引子
本文将要描述一个我在某些linux版本以及libpcap(unix/linux平台下网络数据捕获包)中发现的一个非常险恶的bug。
一个有意思的现象
一位客户向我们报告,在一些安装了Debian Lenny的机器上,处于主动备份模式下的网卡不能检测到发送的数据包,边界流量检测器没有任何图形显示。我在公司里找了几台与客户硬件配置一样的机器,开始对问题展开调查。
首先,我从自己的笔记本ping目标机器。接着,我在目标机器上使用tcpdump嗅探(sniff 窃听网络上流经的数据包)绑定接口收到的ICMP包。
% sudo tcpdump -i bond0 dst 172.16.209.136 and proto 1 12:57:26.275660 IP 172.16.209.1 > 172.16.209.136: ICMP echo request, id 62831, seq 54, length 64 12:57:27.275731 IP 172.16.209.1 > 172.16.209.136: ICMP echo request, id 62831, seq 55, length 64 ^C 2 packets captured 2 packets received by filter 0 packets dropped by kernel |
看来一切正常,是时候开始监听eth0了。eth0绑定的是活跃物理网卡:
% sudo tcpdump -i eth0 dst 172.16.209.136 and proto 1 ^C 0 packets captured 2 packets received by filter 0 packets dropped by kernel |
结果,bond0嗅探的结果显示有ICMP输入,但是eth0绑定的物理网卡没有任何数据包输入。这就难怪我们的监测工具没有输入流量显示,因为测量仪没有检测到数据包!
这是什么原因呢?
设备无关层
为了调试这个问题,我首先开始检查网络协议栈的设备无关层,跟踪pcap负责处理输入数据包的相关代码。设备驱动通过调用设备无关层.netif_receive_skb函数处理从网络捕获的一组数据。
查看位于net/core/dev.c文件中的netif_receive_skb函数(简洁起见这里只摘取重要部分):
1
2
3
4
5
6
7
8
9
10
|
int netif_receive_skb( struct sk_buff *skb) { /* ... */ orig_dev = skb_bond(skb); if (!orig_dev) return NET_RX_DROP; /* ... */ |