组播分片报文重组后丢包问题

问题现象

最近业务需要,将一个业务的传送从单播改为组播。修改后测试反馈收包丢包严重,直接影响业务功能。该报文是一个大包,分成多个分片发送到设备eth1口,重组后交给上层应用处理。

问题分析

查看网络错误统计

先是通过netstat查看报文统计,主要关注失败/丢包/错误相关统计。

root@test:~# netstat -s | grep -Ei "err|drop|fail"
    7 dropped because of missing route
    477139 fragments dropped after timeout. //计数持续上涨
    477139 packet reassemblies failed.      //计数持续上涨
    5606 input ICMP message failed
    0 ICMP messages failed
    5613 failed connection attempts
    683469 packet receive errors
    683469 receive buffer errors
    0 send buffer errors
    16 packets pruned from receive queue because of socket buffer overrun
root@test:~# netstat -s | grep -Ei "err|drop|fail"
    7 dropped because of missing route
    477168 fragments dropped after timeout.  //计数持续上涨
    477168 packet reassemblies failed        //计数持续上涨
    5606 input ICMP message failed
    0 ICMP messages failed
    5613 failed connection attempts
    683470 packet receive errors
    683470 receive buffer errors
    0 send buffer errors
    16 packets pruned from receive queue because of socket buffer overrun

首先发现报文重组失败计数持续上涨,进一步发现是重组超时失败导致的重组失败。
看了下重组超时时间设置是30s,这个时间足够收到所有分片。推断是部分分片报文没有在接口上收到,导致超时失败。

抓包分析

在eth1上使用tcpdump抓包,然后使用wireshark进行分析。
发现所有分片完整到达网络接口。协议中的counter值连续。确认接口没有丢包。
在这里插入图片描述

业务代码问题?

为了排除业务代码的嫌疑,手动写了个组播报文接收测试程序,直接接收组播报文并打印报文序号。实际验证结果如下,可以发现序号不连续,存在严重丢包。可以确认非业务代码问题。

root@test:~# ./test 239.0.0.15 1067 10.84.0.42
UDP Server 0.0.0.0: 1067
recv from: 10.84.0.73:1067  898975  db79f
recv from: 10.84.0.73:1067  898976  db7a0
recv from: 10.84.0.73:1067  898978  db7a2
recv from: 10.84.0.73:1067  898980  db7a4
recv from: 10.84.0.73:1067  898982  db7a6
recv from: 10.84.0.73:1067  898984  db7a8
recv from: 10.84.0.73:1067  898986  db7aa
recv from: 10.84.0.73:1067  898988  db7ac
recv from: 10.84.0.73:1067  898989  db7ad
recv from: 10.84.0.73:1067  898990  db7ae
recv from: 10.84.0.73:1067  898991  db7af
recv from: 10.84.0.73:1067  898992  db7b0
recv from: 10.84.0.73:1067  898993  db7b1
recv from: 10.84.0.73:1067  898994  db7b2

eth0和eth1在同一广播域

在分析中发现eth0上通过tcpdump也能收到radar组播报文。也就是说eth0和eth1在同一广播域。组播的每一个分片报文,eth0和eth1都会收到一份。

这是不合理的。因为eth0和eth1是不同网段,正常情况应该在不同的广播域。

在同一个广播域会导致分片报文在eth0和eth1都会收到,怀疑是这个原因导致radar丢帧。为了找到根因,进一步做了以下分析。

ftrace日志分析

为了深入分析协议栈处理情况,我们使用ftrace对特定函数进行了追踪。

分片重组逻辑跟踪

可以看到分片报文在eth0和eth1上都有收到。以下图为例。eth1上收到第一个分片时创建重组队列qp,后续收到的分片(蓝框)放入队列中(arg1=0x0 表示成功)。eth0上收到(红框)的分片因为和eth1上收到(蓝框)的重叠冗余,导致这些报文被丢弃(arg1=0x1 表示失败)。

eth0继续收到分片(黄框),继续放入队列。因为所有分片都收集了,协议栈将其重组为一个完整的大包,并把qp释放。重组后的报文交由上层协议处理。

eth1收到了部分分片(蓝框),此时原有qp已经释放,协议栈将其当作一个新的分片,创建了一个新的qp,并将分片放入队列。

因为该qp等不到其他报文,所以超时候会被丢弃。反映在网络统计中,就是重组超时失败计数持续增长。
在这里插入图片描述
在这里还差点被代码误导,看代码是根据dev进行查找,理论上eth0和eth1是不同的分片队列啊。
再一看红框里的代码实现,对于普通接口,返回值是0,也就是没有区分。😃
在这里插入图片描述

重组后报文的丢弃逻辑跟踪

从上面分析我们可以看到虽然有重组失败计数增长,但仍然有一份重组后的报文送给了协议栈。以上图为例,这个报文重组后对应dev是eth0,而我们的组播是注册在eth1上的,eth0上没有注册。在后续处理中会将其丢弃。

为了验证我们的推断,使用ftrace跟踪协议栈 ip_rcv_finish_core 处理。我们发现确实如此。

以下图为例。可以看到所有从eth0送上的组播报文都被丢弃(ret=0x1)。另外对于序号d700a的报文,遇到了上面分析的冲突(即同一报文的分片交叉到达eth0和eth1),导致只有一份报文重组并且dev是eth0,被协议栈丢弃。导致应用没有收到。
在这里插入图片描述
测试程序打印的日志,可以看到序号为d700a的报文没有收到。
在这里插入图片描述

开启混杂模式?

如果不开启混杂模式的话,组播报文在二层就会被丢弃,不应该收到协议栈。
查看发现确实开了混杂模式,导致报文上到协议栈,引发了重组冲突。

root@test:~# cat /sys/class/net/eth0/flags 
0x1103    //bit8置位,说明在混杂模式
root@test:~# cat /sys/class/net/eth1/flags 
0x1103

在这里插入图片描述

结论

问题原因

业务组播发送的分片报文,在eth0和eth1接口上都会收到(这是因为我们将eth0和eth1放在了同一个广播域中)。报文重组过程中会有冲突,eth1上部分报文重组失败,最终导致上层业务丢帧。

解决方法

关闭接口的混杂模式

相关技术栈链接

Kprobe-based Event Tracing

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浮沉飘摇

码字不易,打赏随意。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值