使用网卡在接收数据包时不会自动组包

在一次进行测试总发现client端发送一次发送2048哥byte的数据给server端,server端接收数据发现有时候会自动组包,有时候不会自动组包(自动组包:一次接收一帧2048, 不自动组包:分两次接收两帧一共2048)

现在大多数网卡都具有LRO/GRO功能。即,网卡收包时将同一流的小包合并成大包 (tcpdump抓包可以看到>MTU 1500bytes的数据包)交给内核协议栈。

打开LRO/GRO功能是由网卡进行分包组包,关闭LRO/GRO是由内核进行分包组包


解决方法,关闭LRO/GRO功能,命令:

1 $ethtool -k eth0 #查看LRO/GRO当前是否打开
2 $ethtool -K eth0 lro off #关闭LRO
3 $ethtool -K eth0 gro off #关闭GRO

在内核代码中gro_receive中不做flush效果更好

LSO/LRO

分别对应到发送和接收两个方向,是 Large Segment Offload 和 Large Receive Offload。

首先来看 LSO。我们知道计算机网络上传输的数据基本单位是离散的网包,既然是网包,就有大小限制,这个限制就是 MTU(Maximum Transmission Unit)的大小,一般是1518字节。比如我们想发送很多数据出去,经过os协议栈的时候,会自动帮你拆分成几个不超过MTU的网包。然而,这个拆分是 比较费计算资源的(比如很多时候还要计算分别的checksum),由 CPU 来做的话,往往会造成使用率过高。那可不可以把这些简单重复的操作 offload 到网卡上呢?

于是就有了 LSO,在发送数据超过 MTU 限制的时候(太容易发生了),OS 只需要提交一次传输请求给网卡,网卡会自动的把数据拿过来,然后进行切,并封包发出,发出的网包不超过 MTU 限制。

接下来看 LSO,当网卡收到很多碎片包的时候,LRO 可以辅助自动组合成一段较大的数据,一次性提交给 OS处理。

一般的,LSO 和 LRO 主要面向 TCP 报文。

GSO/GRO

Generic Segmentation Offload 和 Generic Receive Offload,分别比 LSO 和 LRO 更通用,自动检测网卡支持特性,支持分包则直接发给网卡,否则先分包后发给网卡。新的驱动一般用 GSO/GRO。

TSO/UFO

TCP Segmentation Offload 和 UDP fragmentation offload,分别对应 TCP 报文和 UDP 报文。

很典型的,TCP 协议中就考虑了分片存在的情况,往往是切分 TCP 的数据包,叫做 TSO。而一般的情况,则称为 LSO 或者 GSO。

对于其他不支持切片的协议例如 UDP,则只能进行 IP 层上的切片。

原文地址:https://www.cnblogs.com/zongfanstudy/p/14804320.html