Linux 内核不传递多播 UDP 数据包

Linux 内核不传递多播 UDP 数据包

最近我设置了一个新的 Ubuntu Server 10.04,并注意到我的 UDP 服务器不再能够看到发送到接口的任何多播数据,即使加入多播组也是如此。我在另外两台 Ubuntu 8.04.4 LTS 机器上进行了完全相同的设置,加入同一个多播组后接收数据没有问题。

以太网卡是Broadcom netXtreme II BCM5709,使用的驱动程序是:

b $ ethtool -i eth1
driver: bnx2
version: 2.0.2
firmware-version: 5.0.11 NCSI 2.0.5
bus-info: 0000:01:00.1

我正在使用 smcroute 来管理我的多播注册。

b$ smcroute -d
b$ smcroute -j eth1 233.37.54.71

加入组后ip maddr显示新添加的注册。

b$ ip maddr

    1:  lo
        inet  224.0.0.1
        inet6 ff02::1
    2:  eth0
        link  33:33:ff:40:c6:ad
        link  01:00:5e:00:00:01
        link  33:33:00:00:00:01
        inet  224.0.0.1
        inet6 ff02::1:ff40:c6ad
        inet6 ff02::1
    3:  eth1
        link  01:00:5e:25:36:47
        link  01:00:5e:25:36:3e
        link  01:00:5e:25:36:3d
        link  33:33:ff:40:c6:af
        link  01:00:5e:00:00:01
        link  33:33:00:00:00:01
        inet  233.37.54.71 <------- McastGroup.
        inet  224.0.0.1
        inet6 ff02::1:ff40:c6af
        inet6 ff02::1

到目前为止一切顺利,我可以看到我正在接收该多播组的数据。

b$ sudo tcpdump -i eth1 -s 65534 host 233.37.54.71
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 65534 bytes
09:30:09.924337 IP 192.164.1.120.58848 > 233.37.54.71.15572: UDP, length 212
09:30:09.947547 IP 192.164.1.120.58848 > 233.37.54.71.15572: UDP, length 212
09:30:10.108378 IP 192.164.1.120.58866 > 233.37.54.71.15574: UDP, length 268
09:30:10.196841 IP 192.164.1.120.58848 > 233.37.54.71.15572: UDP, length 212
...

我还可以确认该接口正在接收 mcast 数据包。

b $ ethtool -S eth1 | grep mcast_pack
rx_mcast_packets: 103998
tx_mcast_packets: 33

现在问题来了。当我尝试使用简单的 ruby​​ UDP 服务器捕获流量时,我收到的数据为零!这是一个简单的服务器,它读取端口 15572 上发送的数据并打印前两个字符。这在两个 8.04.4 Ubuntu 服务器上有效,但在 10.04 服务器上无效。

require 'socket'
s = UDPSocket.new
s.bind("", 15572)
5.times do
  text, sender = s.recvfrom(2)
  puts text
end

如果我将用 ruby​​ 编写的 UDP 数据包发送到 localhost,服务器会接收它并打印出前两个字符。所以我知道上面的服务器运行正常。

irb(main):001:0> require 'socket'
=> true
irb(main):002:0> s = UDPSocket.new
=> #<UDPSocket:0x7f3ccd6615f0>
irb(main):003:0> s.send("I2 XXX", 0, 'localhost', 15572)

当我检查协议统计信息时,我发现 InMcastPkts 没有增加。而在同一网络上的其他 8.04 服务器上,10 秒内收到了几千个数据包。

b $ netstat -sgu ; sleep 10 ; netstat -sgu
IcmpMsg:
    InType3: 11
    OutType3: 11
Udp:
    446 packets received
    4 packets to unknown port received.
    0 packet receive errors
    461 packets sent
UdpLite:
IpExt:
    InMcastPkts: 4654 <--------- Same as below
    OutMcastPkts: 3426
    InBcastPkts: 9854
    InOctets: -1691733021
    OutOctets: 51187936
    InMcastOctets: 145207
    OutMcastOctets: 109680
    InBcastOctets: 1246341
IcmpMsg:
    InType3: 11
    OutType3: 11
Udp:
    446 packets received
    4 packets to unknown port received.
    0 packet receive errors
    461 packets sent
UdpLite:
IpExt:
    InMcastPkts: 4656  <-------------- Same as above
    OutMcastPkts: 3427
    InBcastPkts: 9854
    InOctets: -1690886265
    OutOctets: 51188788
    InMcastOctets: 145267
    OutMcastOctets: 109712
    InBcastOctets: 1246341

如果我尝试强制接口进入混杂模式,则什么都不会改变。

这时我卡住了。我已确认内核配置已启用多播。也许我应该检查其他配置选项?

b $ grep CONFIG_IP_MULTICAST /boot/config-2.6.32-23-server
CONFIG_IP_MULTICAST=y

对于接下来要去哪里,您有什么想法吗?

答案1

在我们的实例中,我们的问题通过 sysctl 参数解决,该参数与 Maciej 不同。

请注意,我不是代表 OP(buecking)发言,我写这篇文章是因为问题与基本细节有关(用户空间中没有多播流量)。

我们有一个应用程序,它从通常直接连接到接收服务器接口的设备读取发送到四个多播地址和每个多播地址的唯一端口的数据。

我们试图在客户站点部署此软件时,它莫名其妙地失败了,原因不明。调试此软件的尝试导致检查每个系统调用,最终它们都告诉我们同一件事:

我们的软件要求提供数据,但操作系统从不提供任何数据。

多播数据包计数器递增,tcpdump 显示流量到达了盒子/特定接口,但我们无法对此采取任何措施。SELinux 已禁用,iptables 正在运行,但任何表中均无规则。

我们很困惑。

在随机搜索时,我们开始思考 sysctl 处理的内核参数,但记录的功能都不是特别相关,或者如果它们与多播流量有关,则它们被启用。哦,ifconfig 确实在功能行中列出了“MULTICAST”(启动、广播、运行、多播)。出于好奇,我们查看了/etc/sysctl.conf。瞧,这位客户的基础映像底部多了几行。

在我们的案例中,客户已设置net.ipv4.all.rp_filter = 1。rp_filter 是路由路径过滤器,它(据我理解)拒绝所有不可能到达此框的流量。网络子网跳跃,认为源 IP 被欺骗了。

好吧,该服务器位于 192.168.1/24 子网中,而设备用于多播流量的源 IP 地址位于 10.* 网络中的某个位置。因此,过滤器阻止服务器对流量进行任何有意义的操作。

net.ipv4.eth0.rp_filter = 1经过客户同意的几项调整,net.ipv4.eth1.rp_filter = 0我们运行起来很愉快。

答案2

TL/DR还要确保您的多播不是来自 vlan。tcpdump -e这将有助于确定它们是否来自。

平心而论,有人应该建立一个页面,列出可以阻止多播到达用户空间的事项清单。我已经为此苦苦挣扎了几天,当然,我在网上找不到任何有用的信息。

我不仅可以看到 中的数据包tcpdump,实际上还可以接收其他生产者的其他多播数据包,只是在不同的接口上。​​我最终用来测试是否可以接收多播的命令是:

$ GRP=224.x.x.x # set me to the group
$ PORT=yyyy # set me to the receiving port
$ IFACE=mmmm # set me to the name or IP address of the interface
$ strace -f socat -  UDP4-DATAGRAM:$GRP:$PORT,ip-add-membership=$GRP:$IFACE,bind=0.0.0.0:$PORT,multicast-loop=0

原因strace是我实际上无法将socat数据包打印到标准输出,但在strace输出中您可以清楚地看到是否socat从绑定套接字接收实际数据(否则在几次初始select调用后它将处于静音状态)

  • rp_filtersysctl - 不适用,系统在同一个 IP 网络上(我将它们设置为0全部相同,似乎1现在这是默认设置,至少对于 Ubuntu 而言)。
  • 防火墙/等 - 接收系统没有防火墙(我认为如果有防火墙,数据包就不会出现在 tcpdump 中,但如果防火墙很有趣,我想这是可能的)
  • IP/多播路由和多个接口 - 我明确地在正确的接口上加入了组
  • 古怪的网络硬件 - 这是我最后的办法,但将一些笔记本电脑换成 Intel NUC 也无济于事。这就是我开始咬紧牙关并坚持将这篇文章发布到 SE 的原因。
  • 在我的案例中,问题在于生成这些多播数据包的专用硬件使用了 VLAN。要查看这是否是您的问题,请确保将-e标志添加到tcpdump,并检查 vlan 标签。在​​用户空间能够获取这些数据包之前,需要将接口配置到正确的 vlan 中。对我来说,实际上,多播生产者不会 ping,甚至不会进入 ARP 缓存,尽管我可以清楚地看到 ARP 回复。

要使用 VLAN 运行它此链接可能有助于配置多播路由。(遗憾的是,我是这方面的新手,因此声誉不允许我添加答案。因此进行了此编辑。)

这是我所做的(如果需要,请使用 sudo):

ip link add link eth0 name eth0_100 type vlan id 100
ip addr add 192.168.100.2/24 brd 192.168.100.255 dev eth0_100
ip link set dev eth0_100 up
ip maddr add 01:00:5e:01:01:01 dev eth0_100
route -n add -net 224.0.0.0 netmask 240.0.0.0 dev eth0_100

这样,如果为具有 vlan id 100 的 vlan 流量创建了一个附加接口。vlan ip 可能没有必要。然后为新接口配置一个多播地址(01:00:5e:01:01:01 是 239.1.1.1 的链路层地址),并且所有传入的多播流量都绑定到 eth0_100。我还执行了上述答案中的所有可能步骤(检查 iptables、rp_filter 等)。

答案3

您可能想尝试查看以下设置:

进程

echo "0" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts

系统配置参数

sed -i -e 's|^net.ipv4.icmp_echo_ignore_broadcasts =.*|net.ipv4.icmp_echo_ignore_broadcasts = 0|g' /etc/sysctl.conf

这些已用于在 RHEL 中启用多播。

您可能需要确保您的防火墙允许多播流量;再次使用 RHEL,我启用了以下内容:

# allow anything in on multicast addresses
-A INPUT -s 224.0.0.0/4 -j ACCEPT
-A INPUT -p igmp -d 224.0.0.0/4 -j ACCEPT
# needed for multicast ping responses
-A INPUT -p icmp --icmp-type 0 -j ACCEPT

答案4

s.bind("", 15572)

确定“”吗?为什么不使用多播 IP 地址进行绑定?

相关内容