1、测试环境
NXP LS1046A平台 + linux4.19
2、问题现象
一般来说,网卡只会接收目的地址是自身的数据包,丢弃其它目的的数据包,但如果网卡开启了混杂模式,该网卡会接收所有来到该网卡的数据包。这也是tcpdump 等一些抓包工具的原理。最近一个客户在使用网卡时,开启了混杂模式,当网卡收到数据包后,并没有被内核统计计数,cat /proc/net/dev 看不到 rx packets 有增加。
在网卡对端,使用 tcpreplay 发包:
# tcpreplay -i eth1 -K -M 100 -l 0 udp.pcap
此时看不到 RX packet 一直增加,说明没有被内核统计,应该是被dropped,但是也没有被 统计到 dropped。(PROMISC 表示已经开启混杂模式,ifconfig eth8 promisc可开启)
# tcprewrite --enet-dmac=5c:d2:0b:10:7e:1b --infile=udp.pcap --outfile=0.pcap
# tcpreplay -i eth1 -K -M 100 -l 0 0.pcap
修改目的MAC地址后,再次发包
说明 混杂模式下的网卡,收到目的地址不是自己的数据包,并没有被内核统计,而是被直接丢弃掉,注意这个丢弃和 ifconfig 显示的RX dropped不一样:
RX dropped: 表示数据包已经进入了 Ring Buffer,但是由于内存不够,上层协议不支持等系统原因,导致在拷贝到内存的过程中被丢弃,netstat -s可以看到更详细的原因。
RX overruns: 表示了 fifo 的 overruns,这是由于 Ring Buffer(aka Driver Queue) 传输的 IO 大于 kernel 能够处理的 IO 导致的,而 Ring Buffer 则是指在发起 IRQ 请求之前的那块 buffer。
3、分析
经过上面的分析,猜测是网卡在混杂模式下,数据包没有被内核统计,直接丢弃掉了。下面就来分析验证一下。先找的网卡 MAC驱动 收包的入口。
可以设备上看下, 寻找一下关键字信息
然后再内核里搜索相关信息,确定MAC驱动
然后 检索 rx_packets 字符串
可以看到 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c 有关 rx_packet的处理,我们打开这个驱动文件看下。
在上图中,发现有两个地方确实会有 drop packet的情况,而且并没有被内核统计计数,我们可以在这个地方可以加入打印,验证一下是否是真的在这里被drop掉了,经过验证是蓝色箭头导致的 unlikely(netif_receive_skb(skb) == NET_RX_DROP) 这个条件满足了,就被drop掉了。
3、解决
经过上面的分析,收取数据包的时候,显示没有考虑混杂模式的情况,而是直接抛弃了,我们只需要将 混杂模式的情况处理下即可。
先看下,内核里,别人都是如何 处理 混杂模式的
看来是net_device 里有 flag可以判定是否是 混杂模式,那么就简单了
搞定,解决!