LSO/LRO 简介
分别对应到发送和接收两个方向,全称是 Large Segment Offload 和 Large Receive Offload。 首先来看 LSO。我们知道计算机网络上传输的数据基本单位是离散的网包, 既然是网包,就有大小限制,这个限制就是 MTU(Maximum Transmission Unit)的大小,一般是 1518 字节。 比如我们想发送很多数据出去,经过 OS 协议栈的时候,会自动帮你拆分成几个不超过 MTU 的网包。 然而,这个拆分是比较费计算资源的(比如很多时候还要计算分别的 checksum), 由 CPU 来做的话,往往会造成使用率过高。 那可不可以把这些简单重复的操作 offload 到网卡上呢? 于是就有了 LSO,在发送数据超过 MTU 限制的时候(太容易发生了), OS 只需要提交一次传输请求给网卡,网卡会自动的把数据拿过来, 然后进行切,并封包发出,发出的网包不超过 MTU 限制。 接下来看 LRO,当网卡收到很多碎片包的时候,LRO 可以辅助自动组合成一段较大的数据,一次性提交给 OS 处理。 一般的,LSO 和 LRO 主要面向 TCP 报文。
GSO简介
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 层上的切片。
可以通过ethtool -k eth0
命令来查看网卡设备各个选项的当前状态,注意输出中各种 offload 选项的状态。
# ethtool -k eth0 Features for eth0: rx-checksumming: on tx-checksumming: on tx-checksum-ipv4: on tx-checksum-ip-generic: off [fixed] tx-checksum-ipv6: on tx-checksum-fcoe-crc: off [fixed] tx-checksum-sctp: off [fixed] scatter-gather: on tx-scatter-gather: on tx-scatter-gather-fraglist: off [fixed] tcp-segmentation-offload: on tx-tcp-segmentation: on tx-tcp-ecn-segmentation: off [fixed] tx-tcp6-segmentation: on udp-fragmentation-offload: off [fixed] generic-segmentation-offload: on generic-receive-offload: on large-receive-offload: off [fixed] rx-vlan-offload: on tx-vlan-offload: on ntuple-filters: off [fixed] receive-hashing: on highdma: on [fixed] rx-vlan-filter: on [fixed] vlan-challenged: off [fixed] tx-lockless: off [fixed] netns-local: off [fixed] tx-gso-robust: off [fixed] tx-fcoe-segmentation: off [fixed] tx-gre-segmentation: off [fixed] tx-ipip-segmentation: off [fixed] tx-sit-segmentation: off [fixed] tx-udp_tnl-segmentation: off [fixed] tx-mpls-segmentation: off [fixed] fcoe-mtu: off [fixed] tx-nocache-copy: on loopback: off [fixed] rx-fcs: off [fixed] rx-all: off tx-vlan-stag-hw-insert: off [fixed] rx-vlan-stag-hw-parse: off [fixed] rx-vlan-stag-filter: off [fixed] l2-fwd-offload: off [fixed]
通过 ethtool -K eth0 gso off/on 这样的命令来开关。
之前还一点儿也不了解网卡还有一些高级特性,在工作中的一次调试中,发现期望对端发送的一个报文长度居然超过了网络中的mtu(默认1500Bytes),能够达到将近3000Bytes。
一开始就排除了对端协议栈下到网卡上的数据会大于mtu(这一点在之前的工作中我使用libpcap验证过,一旦发送的报文长度大于1个mtu,发送就会失败)。然后查看虚拟网桥上抓到的包,发现网桥捕获的数据包的确大于了1个mtu。当时一直认为出现问题的地方可能是网桥在转发时聚合了数据包,后来经过同事的提醒,才认识到可能是网卡本身存在某种数据聚合的特性,使得上层协议栈所发送的数据包被聚合成了一个大包,然后被发送出去。
查阅了相关资料,这种现象实际上涉及到了网卡的GRO/GSO/LRO等特性,下面简要介绍一下。
##GSO(generic-segmentation-offload)/ TSO(TCP-segmentation-offload)
所谓的GSO,实际上是对TSO的增强。TSO将tcp协议的一些处理下放到网卡完成以减轻协议栈处理占用CPU的负载。通常以太网的MTU是1500Bytes,除去IP头(标准情况下20Bytes)、TCP头(标准情况下20Bytes),TCP的MSS (Max Segment Size)大小是1460Bytes。当应用层下发的数据超过了mss时,协议栈会对这样的payload进行分片,保证生成的报文长度不超过MTU的大小。但是对于支持TSO/GSO的网卡而言,就没这个必要了,可以把最多64K大小的payload直接往下传给协议栈,此时IP层也不会进行分片,一直会传给网卡驱动,支持TSO/GSO的网卡会自己生成TCP/IP包头和帧头,这样可以offload很多协议栈上的内存操作,checksum计算等原本靠CPU来做的工作都移给了网卡。
##GRO(generic-receive-offload)/ LRO(large-receive-offload)
LRO通过将接收到的多个TCP数据聚合成一个大的数据包,然后传递给网络协议栈处理,以减少上层协议栈处理 开销,提高系统接收TCP数据包的能力。
而GRO的基本思想跟LRO类似,克服了LRO的一些缺点,更通用。后续的驱动都使用GRO的接口,而不是LRO。
具体到工作中遇到的那个问题中,我们在关闭了网卡的GSO/TSO功能后,还是能收到大包,这里面实际上还有LRO/GRO的“功劳”在里面,将它们也关闭后,对端协议栈发送什么样的数据包,本端就收到了什么样的数据包了。
##了解网卡是否支持
在linux下,我们可以使用ethtool工具查询网卡是否支持这些特性(以网卡eth0为例):
$ ethtool -k eth0
而我们要关闭某一个特性时,只需要输入(以关闭gso为例):
$ ethtool -K eth0 gso off
上面的命令只能暂时关闭网卡的特性,当重启之后网卡又会启用该特性,为了避免这种情况,我们只需要将上面的命令保存到网卡的配置文件里面即可,对于我的CentOS 6.5来讲,对应于eth0的配置文件在
/etc/sysconfig/network-scripts/ifcfg-eth0
转载请注明:爱开源 » 网卡 LSO/LRO、GSO/GRO、TSO