最近我设置了一个新的 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
Run Code Online (Sandbox Code Playgroud)
我正在使用 smcroute 来管理我的多播注册。
b$ smcroute -d
b$ smcroute -j eth1 233.37.54.71
Run Code Online (Sandbox Code Playgroud)
加入组后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
Run Code Online (Sandbox Code Playgroud)
到目前为止一切顺利,我可以看到我正在接收这个多播组的数据。
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
...
Run Code Online (Sandbox Code Playgroud)
我还可以确认接口正在接收 mcast 数据包。
b $ ethtool -S eth1 | grep mcast_pack
rx_mcast_packets: 103998
tx_mcast_packets: 33
Run Code Online (Sandbox Code Playgroud)
现在问题来了。当我尝试使用简单的 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
Run Code Online (Sandbox Code Playgroud)
如果我将用 ruby 制作的 UDP 数据包发送到本地主机,服务器会收到它并打印出前两个字符。所以我知道上面的服务器工作正常。
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)
Run Code Online (Sandbox Code Playgroud)
当我检查协议统计信息时,我发现 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
Run Code Online (Sandbox Code Playgroud)
如果我尝试强制界面进入 promisc 模式,则没有任何变化。
在这一点上,我被困住了。我已经确认内核配置已启用多播。也许我应该检查其他配置选项?
b $ grep CONFIG_IP_MULTICAST /boot/config-2.6.32-23-server
CONFIG_IP_MULTICAST=y
Run Code Online (Sandbox Code Playgroud)
关于从这里去哪里的任何想法?
VxJ*_*nxV 39
在我们的例子中,我们的问题是通过 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我们愉快地奔跑着。
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
Run Code Online (Sandbox Code Playgroud)
strace这里的原因是我实际上无法socat将数据包打印到标准输出,但是在strace输出中您可以清楚地看到是否socat正在从绑定的套接字接收实际数据(否则在几次初始select调用后它会静音)
rp_filtersysctl - 不适用,系统在同一个 IP 网络上(我将它们设置0为相同,1现在似乎是默认设置,至少对于 Ubuntu)。-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
Run Code Online (Sandbox Code Playgroud)
这样,如果为 vlan id 100 的 vlan 流量创建了一个额外的接口。 vlan ip 可能是不必要的。然后为新接口配置多播地址(01:00:5e:01:01:01 是 239.1.1.1 的链路层地址),所有传入的多播流量都绑定到 eth0_100。我还在上面的答案中做了所有可能的步骤(检查 iptables、rp_filter 等)。