udp cksum

来源:互联网 发布:安卓字体软件 编辑:程序博客网 时间:2024/06/05 20:39

    目前碰到一个奇怪的现象,某台机器(就叫hostA吧)上面tx-checksumming是开启状态下,所有本地发出去的UDP报文用tcpdump -vvv udp抓出来,凡是从这台主机发出去的包所有包全部显示bad udp cksum,收到的UDP包则没有一个是bad udp cksum的。

    而在另外一台机器(就叫hostB吧)上面,则没有一个bad udp cksum的包,抓包不多,1000个左右,对比环境差异:

hostA的ethtool -i信息:

driver: bnx2
version: 1.6.9
firmware-version: 4.0.3 ipms 1.6.0
bus-info: 0000:04:00.0

hostB的ethtool -i信息:

driver: bnx2
version: 1.6.9
firmware-version: 1.9.6
bus-info: 0000:04:00.0

hostA uname -a:

Linux hostA 2.6.18-92.el5xen #1 SMP Tue Apr 29 13:31:30 EDT 2008 x86_64 x86_64 x86_64 GNU/Linux

hostB uname -a:

Linux hostB 2.6.18-92.el5xen #1 SMP Tue Apr 29 13:31:30 EDT 2008 x86_64 x86_64 x86_64 GNU/Linux

hostA and hostB tcpdump --version:

tcpdump version 3.9.4
libpcap version 0.9.4

下面验证使用的kernel源码版本为:2.6.32.60


    物理上两台一样的服务器,tcpdump版本一致,除了网卡固件有所差异外,没别的区别,按照我的分析,会对udp send包 cksum有所影响的只应该有2个层面,一个是内核,也就是系统调用入sendto生产udp报文的时候udp层面的cksum计算,而另外一个就是网卡来计算cksum,二选一。

   这两天和雷风讨论了下,没啥结果,现在应该说是昨天下午,和燕飞请教了下,让我关掉tx-checksumming,他的理解是开启这个功能相当于用网卡硬件来计算cksum,而关闭则由内核来计算cksum。


    燕飞推荐的《understanding_linux_network_internals》的85页,引用下该图:


    可以看到tcpdump 的原理是创建一个PF_PACKET类型套接字,直接插到网络层和数据链路层中间的dev_queue_xmit函数中截取,按照燕飞的说法,开启了tx-checksumming,内核就不会计算cksum,而是在这个包交给数据链路层后再计算cksum,所以tcpdump 的时候,抓回来的包,全是错误的cksum,而关闭该功能后,也就是说让网络层去做cksum的计算后抓回来的包是没问题的,在hostA上我验证与燕飞的猜想一致。

   但是,我在hostB上面,看到checksumming也是开启的,实时抓取1000+ udp报文是没有一个cksum错误的,这就是我疑惑的地方,难道说在网络层已经完成了cksum计算?

    假设tcpdump拿到的包都是dev_queue_xmit处理完之后的包。这个以后验证,以下逻辑建立在此之上:

    看dev_queue_xmit函数(1908~1916行):

    /* If packet is not checksummed and device does not support
     * checksumming for this protocol, complete checksumming here.
     */
    if (skb->ip_summed == CHECKSUM_PARTIAL) {
        skb_set_transport_header(skb, skb->csum_start -
                          skb_headroom(skb));
        if (!dev_can_checksum(dev, skb) && skb_checksum_help(skb))
            goto out_kfree_skb;
    }

    解释的很清楚,只有当硬件不支持和包还未cksum的时候才会计算cksum,调用的是skb_checksum_help函数来计算,具体cksum实现在该函数里。

    如果硬件支持cksum,就不计算cksum直接发出去。

实验数据:

 tx-checksumming ontx-checksumming offhostAbad udp cksumnormalhostBnormalnormal

    显然这里面有台机器是不正常的,个人更倾向于hostB不正常,因为hostA可以用代码来解释为什么开启了tx checksumming抓到的全是错误的cksum包。

    而对于hostB,暂时我无法理解该行为!

    有点晚了,明天开启tx checksumming 的情况下,验证一下从hostA发一个UDP报文给hostB,分别在A和B上抓包看下cksum是否变化过。

    接上次的,28号验证表明,在网卡开启tx checksumming的情况下,hostA发出UDP报文,在hostA上抓取显示UDPcksum是错误的,而在目标主机上抓取hostA发送的UDP报文,则没问题,也就是说,开启tx checksumming的情况下,是网卡来计算了cksum。

    最后一个疑问,目前还无法解释hostB上的情况,无论起开或者关闭tx checksumming,hostB发生的UDP报文在hostB上抓取,UDP cksum均是没问题的。



参考资料:

1、其他博主写的dev_queue_xmit函数分析http://blog.csdn.net/peimichael/article/details/4699609.

2、《understanding_linux_network_internals》一书的第85页.

3、《TCP/IP详解卷2: 实现》的UDP部分615页