目前碰到一个奇怪的现象,某台机器(就叫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 on
tx-checksumming off
hostA
bad udp cksum |
normal |
hostB
normal |
normal |
显然这里面有台机器是不正常的,个人更倾向于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页
分享到:
相关推荐
网络编程从大的方面说就是对信息的发送到接收,中间传输为物理线路的作用。网络编程最主要的工作就是在发送端把信息通过规定好的协议进行组装包,在接收端按照规定好的协议把包进行解析,从而提取出对应的信息,达到...
cksum = (cksum >> 16) + (cksum & 0xffff); cksum += (cksum >>16); return (USHORT)(~cksum); } // // Function: InitIpv4Header // // Description: // Initialize the IPv4 header with the version, ...
cksum = (cksum >> 16) + (cksum & 0xffff); cksum += (cksum >>16); return (USHORT)(~cksum); } int main(int argc, char **argv) { WSADATA wsd; SOCKET s; BOOL bOpt; struct ...
// protocol (TCP, UDP etc) unsigned short checksum; // IP checksum unsigned int sourceIP; unsigned int destIP; }IpHeader; // // ICMP header // typedef struct icmphdr { BYTE i_type; ...
8.7 Internet检验和:in_cksum函数 186 8.8 setsockopt和getsockopt系统调用 190 8.8.1 PRCO_SETOPT的处理 192 8.8.2 PRCO_GETOPT的处理 193 8.9 ip_sysctl函数 193 8.10 小结 194 第9章 IP选项处理 196 9.1 引言 ...
8.7 Internet检验和:in_cksum函数 186 8.8 setsockopt和getsockopt系统调用 190 8.8.1 PRCO_SETOPT的处理 192 8.8.2 PRCO_GETOPT的处理 193 8.9 ip_sysctl函数 193 8.10 小结 194 第9章 IP选项处理 196 9.1 引言 ...
8.7 Internet检验和:in_cksum函数 186 8.8 setsockopt和getsockopt系统调用 190 8.8.1 PRCO_SETOPT的处理 192 8.8.2 PRCO_GETOPT的处理 193 8.9 ip_sysctl函数 193 8.10 小结 194 第9章 IP选项处理 196 9.1 ...
8.7 Internet检验和:in_cksum函数 186 8.8 setsockopt和getsockopt系统调用 190 8.8.1 PRCO_SETOPT的处理 192 8.8.2 PRCO_GETOPT的处理 193 8.9 ip_sysctl函数 193 8.10 小结 194 第9章 IP选项处理 196 9.1 ...
8.7 Internet检验和:in_cksum函数 186 8.8 setsockopt和getsockopt系统调用 190 8.8.1 PRCO_SETOPT的处理 192 8.8.2 PRCO_GETOPT的处理 193 8.9 ip_sysctl函数 193 8.10 小结 194 第9章 IP选项处理 196 9.1 ...
8.7 Internet检验和:in_cksum函数 186 8.8 setsockopt和getsockopt系统调用 190 8.8.1 PRCO_SETOPT的处理 192 8.8.2 PRCO_GETOPT的处理 193 8.9 ip_sysctl函数 193 8.10 小结 194 第9章 IP选项处理 196 9.1 引言 ...
8.7 Internet检验和:in_cksum函数 186 8.8 setsockopt和getsockopt系统调用 190 8.8.1 PRCO_SETOPT的处理 192 8.8.2 PRCO_GETOPT的处理 193 8.9 ip_sysctl函数 193 8.10 小结 194 第9章 IP选项处理 196 9.1 ...
8.7 Internet检验和:in_cksum函数 186 8.8 setsockopt和getsockopt系统调用 190 8.8.1 PRCO_SETOPT的处理 192 8.8.2 PRCO_GETOPT的处理 193 8.9 ip_sysctl函数 193 8.10 小结 194 第9章 IP选项处理 196 9.1 引言 ...
8.7 Internet检验和:in_cksum函数 186 8.8 setsockopt和getsockopt系统调用 190 8.8.1 PRCO_SETOPT的处理 192 8.8.2 PRCO_GETOPT的处理 193 8.9 ip_sysctl函数 193 8.10 小结 194 第9章 IP选项处理 196 9.1 引言 ...
8.7 Internet检验和:in_cksum函数 186 8.8 setsockopt和getsockopt系统调用 190 8.8.1 PRCO_SETOPT的处理 192 8.8.2 PRCO_GETOPT的处理 193 8.9 ip_sysctl函数 193 8.10 小结 194 第9章 IP选项处理 196 9.1 引言 ...
8.7 Internet检验和:in_cksum函数 186 8.8 setsockopt和getsockopt系统调用 190 8.8.1 PRCO_SETOPT的处理 192 8.8.2 PRCO_GETOPT的处理 193 8.9 ip_sysctl函数 193 8.10 小结 194 第9章 IP选项处理 196 9.1 引言 ...
8.7 Internet检验和:in_cksum函数 186 8.8 setsockopt和getsockopt系统调用 190 8.8.1 PRCO_SETOPT的处理 192 8.8.2 PRCO_GETOPT的处理 193 8.9 ip_sysctl函数 193 8.10 小结 194 第9章 IP选项处理 196 9.1 引言 ...
8.7 Internet检验和:in_cksum函数 186 8.8 setsockopt和getsockopt系统调用 190 8.8.1 PRCO_SETOPT的处理 192 8.8.2 PRCO_GETOPT的处理 193 8.9 ip_sysctl函数 193 8.10 小结 194 第9章 IP选项处理 196 9.1 引言 ...
8.7 Internet检验和:in_cksum函数 186 8.8 setsockopt和getsockopt系统调用 190 8.8.1 PRCO_SETOPT的处理 192 8.8.2 PRCO_GETOPT的处理 193 8.9 ip_sysctl函数 193 8.10 小结 194 第9章 IP选项处理 196 9.1 引言 ...
8.7 Internet检验和:in_cksum函数 186 8.8 setsockopt和getsockopt系统调用 190 8.8.1 PRCO_SETOPT的处理 192 8.8.2 PRCO_GETOPT的处理 193 8.9 ip_sysctl函数 193 8.10 小结 194 第9章 IP选项处理 196 9.1 引言 ...
8.7 Internet检验和:in_cksum函数 186 8.8 setsockopt和getsockopt系统调用 190 8.8.1 PRCO_SETOPT的处理 192 8.8.2 PRCO_GETOPT的处理 193 8.9 ip_sysctl函数 193 8.10 小结 194 第9章 IP选项处理 196 9.1 引言 ...