当前位置: 技术问答>linux和unix
[百度分享]以太网卡TSO技术浅析(二)
来源: 互联网 发布时间:2016-09-07
本文导语: 网卡驱动层对TSO的支持 如果skb_shinfo(skb)->tso_size不为0,则表明网卡需要对这样的skb作特殊的处理(而只有当网卡驱动初始化时声明自己支持TSO,才可能出现这样的skb),以e1000网卡驱动为例: 函数e...
网卡驱动层对TSO的支持
如果skb_shinfo(skb)->tso_size不为0,则表明网卡需要对这样的skb作特殊的处理(而只有当网卡驱动初始化时声明自己支持TSO,才可能出现这样的skb),以e1000网卡驱动为例:
函数e1000_tso,在文件drivers/net/e1000/e1000_main.c,被e1000_xmit_frame (即hard_start_xmit服务函数)调用
if(skb_shinfo(skb)->tso_size) {
…
// 计算头部偏移
ipcss = skb->nh.raw - skb->data;
ipcso = (void *)&(skb->nh.iph->check) - (void *)skb->data;
tucss = skb->h.raw - skb->data;
tucso = (void *)&(skb->h.th->check) - (void *)skb->data;
tucse = 0;
……
//把头部偏移放入context,最终写入寄存器
context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i);
context_desc->lower_setup.ip_fields.ipcss = ipcss;
context_desc->lower_setup.ip_fields.ipcso = ipcso;
context_desc->lower_setup.ip_fields.ipcse = cpu_to_le16(ipcse);
context_desc->upper_setup.tcp_fields.tucss = tucss;
context_desc->upper_setup.tcp_fields.tucso = tucso;
context_desc->upper_setup.tcp_fields.tucse = cpu_to_le16(tucse);
context_desc->tcp_seg_setup.fields.mss = cpu_to_le16(mss);
context_desc->tcp_seg_setup.fields.hdr_len = hdr_len;
context_desc->cmd_and_length = cpu_to_le32(cmd_length);
……
}
……
//设置TSO标志
if (likely(tso))
tx_flags |= E1000_TX_FLAGS_TSO;
……
//发送“大”的skb数据
e1000_tx_queue(adapter,
e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss),
tx_flags);
即驱动需要告诉网卡硬件(设置E1000_TX_FLAGS_TSO标志),让网卡对这个skb重新分块,对每一个分块计算TCP头和IP头校验和,为此需要告诉网卡对应字段的偏移。
TSO对基于RAW_SOCKET的抓包工具的影响
当发送数据包时,skb经过如下路径发向网卡驱动
net_tx_action->dev_queue_xmit()->驱动的hard_start_xmit服务函数
在函数dev_queue_xmit()中,如果有抓包工具开启了RAW_SOCKET,则该函数会在调用hard_start_xmit之前调用 dev_queue_xmit_nit clone一份skb交给抓包工具。如果skb是一个TSO-enable的特殊skb,抓包工具将会看到这个长度大于MTU的“特殊”skb。 而且,由于TCP、IP的校验和与长度字段将由网卡重新计算,一些版本的内核有可能为了优化而不去计算填写这些数值,所以除了会出现大数据包、校验和与长 度错误的现象。
例如:使用tcpdump在支持TSO的网卡抓取外出数据包可能会出现如下3种错误,其中第一种一般出现在使用e1000网卡驱动的2.6.9内核上,第2种出现在使用bnx2网卡驱动的2.6.9内核上,第3种出现在2.6.23+版本后的内核上:
• ip bad len = 0
000001 IP 192.168.13.1.61941 > 192.168.13.223.32879: . ack 4345 win 32768
000145 IP bad-len 0
000229 IP 192.168.13.1.61941 > 192.168.13.223.32879: . ack 8689 win 32768
000011 IP bad-len 0
• bad csum
16:29:32.561407 IP (tos 0x60, ttl 48, id 14116, offset 0, flags [DF], length:
80) 69.42.67.34.2612 > 81.13.94.6.1234: . [bad cksum 0 (->2610)!] ack 93407
win 9821
• “包合并”
在MTU=1500的网卡上抓包,出现了比1500还大的IP包
21:58:36.691026 IP (tos 0x0, ttl 64, id 38181, offset 0, flags [DF], proto 6, length: 52) 10.13.100.34.45043 > 10.1
3.100.102.34476: . [tcp sum ok] 1:1(0) ack 482281 win 16664
21:58:36.691029 IP (tos 0x0, ttl 64, id 10688, offset 0, flags [DF], proto 6, length: 23220) 10.13.100.102.34476 >
10.13.100.34.45043: . 525769:548937(23168) ack 1 win 1448
21:58:36.691031 IP (tos 0x0, ttl 64, id 38183, offset 0, flags [DF], proto 6, length: 52) 10.13.100.34.45043 > 10.1
3.100.102.34476: . [tcp sum ok] 1:1(0) ack 485177 win 16664
21:58:36.691033 IP (tos 0x0, ttl 64, id 38185, offset 0, flags [DF], proto 6, length: 52) 10.13.100.34.45043 > 10.1
3.100.102.34476: . [tcp sum ok] 1:1(0) ack 488073 win 16664
根据上面的分析,可以知道这些现象本质都是TSO造成的假象,即TCPDUMP抓取的*外出*数据包并不能真实反应链路上实际的数据帧, 解决办法有两种:
1. 关闭网卡的TSO选项
[xxx]#ethtool -K eth0 tso off
2. 使用其他的旁路链路层的抓包工具
如果skb_shinfo(skb)->tso_size不为0,则表明网卡需要对这样的skb作特殊的处理(而只有当网卡驱动初始化时声明自己支持TSO,才可能出现这样的skb),以e1000网卡驱动为例:
函数e1000_tso,在文件drivers/net/e1000/e1000_main.c,被e1000_xmit_frame (即hard_start_xmit服务函数)调用
if(skb_shinfo(skb)->tso_size) {
…
// 计算头部偏移
ipcss = skb->nh.raw - skb->data;
ipcso = (void *)&(skb->nh.iph->check) - (void *)skb->data;
tucss = skb->h.raw - skb->data;
tucso = (void *)&(skb->h.th->check) - (void *)skb->data;
tucse = 0;
……
//把头部偏移放入context,最终写入寄存器
context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i);
context_desc->lower_setup.ip_fields.ipcss = ipcss;
context_desc->lower_setup.ip_fields.ipcso = ipcso;
context_desc->lower_setup.ip_fields.ipcse = cpu_to_le16(ipcse);
context_desc->upper_setup.tcp_fields.tucss = tucss;
context_desc->upper_setup.tcp_fields.tucso = tucso;
context_desc->upper_setup.tcp_fields.tucse = cpu_to_le16(tucse);
context_desc->tcp_seg_setup.fields.mss = cpu_to_le16(mss);
context_desc->tcp_seg_setup.fields.hdr_len = hdr_len;
context_desc->cmd_and_length = cpu_to_le32(cmd_length);
……
}
……
//设置TSO标志
if (likely(tso))
tx_flags |= E1000_TX_FLAGS_TSO;
……
//发送“大”的skb数据
e1000_tx_queue(adapter,
e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss),
tx_flags);
即驱动需要告诉网卡硬件(设置E1000_TX_FLAGS_TSO标志),让网卡对这个skb重新分块,对每一个分块计算TCP头和IP头校验和,为此需要告诉网卡对应字段的偏移。
TSO对基于RAW_SOCKET的抓包工具的影响
当发送数据包时,skb经过如下路径发向网卡驱动
net_tx_action->dev_queue_xmit()->驱动的hard_start_xmit服务函数
在函数dev_queue_xmit()中,如果有抓包工具开启了RAW_SOCKET,则该函数会在调用hard_start_xmit之前调用 dev_queue_xmit_nit clone一份skb交给抓包工具。如果skb是一个TSO-enable的特殊skb,抓包工具将会看到这个长度大于MTU的“特殊”skb。 而且,由于TCP、IP的校验和与长度字段将由网卡重新计算,一些版本的内核有可能为了优化而不去计算填写这些数值,所以除了会出现大数据包、校验和与长 度错误的现象。
例如:使用tcpdump在支持TSO的网卡抓取外出数据包可能会出现如下3种错误,其中第一种一般出现在使用e1000网卡驱动的2.6.9内核上,第2种出现在使用bnx2网卡驱动的2.6.9内核上,第3种出现在2.6.23+版本后的内核上:
• ip bad len = 0
000001 IP 192.168.13.1.61941 > 192.168.13.223.32879: . ack 4345 win 32768
000145 IP bad-len 0
000229 IP 192.168.13.1.61941 > 192.168.13.223.32879: . ack 8689 win 32768
000011 IP bad-len 0
• bad csum
16:29:32.561407 IP (tos 0x60, ttl 48, id 14116, offset 0, flags [DF], length:
80) 69.42.67.34.2612 > 81.13.94.6.1234: . [bad cksum 0 (->2610)!] ack 93407
win 9821
• “包合并”
在MTU=1500的网卡上抓包,出现了比1500还大的IP包
21:58:36.691026 IP (tos 0x0, ttl 64, id 38181, offset 0, flags [DF], proto 6, length: 52) 10.13.100.34.45043 > 10.1
3.100.102.34476: . [tcp sum ok] 1:1(0) ack 482281 win 16664
21:58:36.691029 IP (tos 0x0, ttl 64, id 10688, offset 0, flags [DF], proto 6, length: 23220) 10.13.100.102.34476 >
10.13.100.34.45043: . 525769:548937(23168) ack 1 win 1448
21:58:36.691031 IP (tos 0x0, ttl 64, id 38183, offset 0, flags [DF], proto 6, length: 52) 10.13.100.34.45043 > 10.1
3.100.102.34476: . [tcp sum ok] 1:1(0) ack 485177 win 16664
21:58:36.691033 IP (tos 0x0, ttl 64, id 38185, offset 0, flags [DF], proto 6, length: 52) 10.13.100.34.45043 > 10.1
3.100.102.34476: . [tcp sum ok] 1:1(0) ack 488073 win 16664
根据上面的分析,可以知道这些现象本质都是TSO造成的假象,即TCPDUMP抓取的*外出*数据包并不能真实反应链路上实际的数据帧, 解决办法有两种:
1. 关闭网卡的TSO选项
[xxx]#ethtool -K eth0 tso off
2. 使用其他的旁路链路层的抓包工具
|
最好有个知识分享网站
|
不错哈
|
怎麼得積分啊 日啊
|
呵呵,up。
是啊,搞个专题技术。
是啊,搞个专题技术。