现在大多数网卡都支持offload功能,这种机制可以提升网络的收发性能,但是对于需要抓包进行网络通信研究的技术人员来说,在不注意的情况下,可能会出现抓取的报文大小大于MTU限制的情况,最近又有同事在工作中掉到了这个坑里。所以把之前写的关于网卡offload特性的总结翻出来整理一下


网络分片技术

MTU

最大传输单元,指一种通信协议的某一层上面所能通过的最大数据包大小(以字节为单位)。

在以太网通信中,MTU规定了经过网络层封装的数据包的最大长度。例如,若某个接口的MTU值为1500,则通过此接口传送的IP数据包的最大长度为1500字节。

MSS

最大分段长度,TCP数据包每次能够传输的最大数据分段长度,在TCP协议的实际实现中,MSS往往用MTU-(IP Header Length + TCP Header Length)来代替。

IP分片

当IP层需要传送的数据包长度超过MTU值时,则IP层需要对该数据包进行分片,使每一片的长度小于或等于MTU值。在分片过程中,除了对payload进行分片外,数据包的IP首部也需要进行相应的更改:

  • 将identifier字段的值复制给每个分片;
  • 将分片数据包的Flags中的DF位置为0;
  • 除最后一个分片之外的其他分片,将MF位置为1;
  • 将Fragment Offset字段设置正确的值。

TCP分段

在TCP通信建立连接时,取两端提供的MSS的最小值作为会话的MSS值。当一次传输的payload数据长度大于MSS限制时,会将payload分割为多个数据段,分别封装在tcp报文中,按顺序进行传输。

由于MSS的限制,TCP通信在传输较长数据时会先进行TCP分段,所以其IP层报文长度会小于等于MTU值,因此TCP报文不会进行IP分片。而UDP通信由于没有类似机制,因此传输较长数据时,会在IP层根据MTU的限制,进行IP分片。简单概括起来就是:TCP协议进行TCP分段,UDP协议进行IP分片

网卡的offload机制

在互联网的早期,这种分片和分段的机制,很大程度上减轻了解决低速网络传输的不可靠性问题。但是随着网络技术的发展和传输速度的提升,现在数据的传输量越来越大,因此,无论是IP分片还是TCP分段机制,对大量分片/分段包进行拆分/重组的工作,都带来了大量的计算需求,即面临着越来越多的CPU消耗。

在这种情况下,就产生了将这些计算工作转移到专用硬件上的技术,即网卡的offload机制。

网卡的offload机制包含多种实现,目前在网卡驱动上常用的机制,按照接收和发送模式,主要可以分为以下几种:

发送模式

  • TSO(tcp-segmentation-offload)

​ 将TCP分段的过程从协议栈下移到网卡中进行。对于支持TSO机制的网卡,可以直接把不超过滑动窗口大小 的payload下传给协议栈,即使数据长度大于MSS,也不会在TCP层进行分段,同样也不会进行IP分片,而是直接传送给网卡驱动,由网卡驱动进行tcp分段操作,并执行checksum计算和包头、帧头的生成工作。

  • UFO(udp-fragmentation-offload)

    ​ 是一种专门针对udp协议的特性,主要机制就是将IP分片的过程转移到网卡中进行,用户层可以发送任意大小的udp数据包(udp数据包总长度最大不超过64k),而不需要协议栈进行任何分片操作。主要应用在虚拟化设备上,实际支持UFO机制的网卡非常少见。

  • GSO(generic-segmentation-offload)

    ​ 可以理解为是TSO/UFO的合并升级,是针对所有协议设计的发送模式,更为通用。同时,GSO机制并不完全依赖于网卡硬件层面的支持。GSO机制首先通过软件实现的方式,将IP分片/TCP分段的操作,尽可能的向底层推迟,直到数据发送给网卡驱动之前。再对网卡的硬件特性进行判断,如果支持TSO/UFO机制,就直接把数据发送给网卡,由网卡进行IP分片/TCP分段操作。若网卡不支持上述机制,则在数据发送给网卡之前再去进行IP分片/TCP分段操作,这样即使不依靠网卡硬件,也最大幅度的减少了协议栈处理的次数,提高数据处理和传输的效率。

目前在实际的网卡应用上,主要是TSO和GSO机制组合使用,除了GSO单独作用于UDP报文以外,TSO和GSO都作用于TCP报文,其组合关系如下:

  • GSO开启, TSO开启: 协议栈推迟分段,并直接传递大数据包到网卡,让网卡自动分段

  • GSO开启, TSO关闭: 协议栈推迟分段,在最后发送到网卡前才执行分段

  • GSO关闭, TSO开启: 同GSO开启, TSO开启

  • GSO关闭, TSO关闭: 不推迟分段,在tcp_sendmsg中直接发送MSS大小的数据包

接收模式

  • LRO(large-receive-offload)

    ​ 在网卡驱动层面上将接受到的多个TCP分段聚合成一个大的数据包,然后上传给协议栈处理。这样可以减少协议栈处理的开销,提高系统接收TCP数据的能力和效率。

  • GRO(generic-receive-offload)

    ​ 基本思想和LRO类似,改进了LRO的一些缺点,并增加了对UDP通信IP分片包的聚合功能,更加通用。目前的网卡都是应用了GRO机制,不再使用GRO机制。


offload机制对抓包分析的影响

由于TSO、GSO、GRO等offload机制将报文IP分片和TCP分段的操作下移到了网卡或数据发送给网卡之前,而我们在对网络通信进行分析时,用tcpdump、wireshark等工具进行抓包时,是处在用户态进行的,因此在offload机制开启的情况下,我们抓到的数据包,并不能完全真实的反应实际链路中传输的数据帧。

开启和关闭TSO/GSO机制的抓包对比:

​ 关闭TSO/GSO/GRO:

关闭TSO/GSO/GRO

​ 开启TSO/GSO/GRO:

开启TSO/GSO/GRO

如上所示,当在开启offload功能的情况下进行抓包,可能会导致IP分片/TCP分段的相关细节丢失,对流量和数据的分析造成干扰。


offload功能的开关设置

这里主要以常用的Ubuntu和Windows7系统作为示例

ubuntu

在Ubuntu等linux系统下,可以通过ethtool查看各模式的状态并进行设置:

  1. 查看状态:

    ethtool -k 设备名 例:ethtool -k eth0

    ethtoolk

  2. 修改开关设置:

    ethtool -K 设备名 模式 on|off 例: ethtool -K eth0 tso on

    ethtoolK

windows

对于Windows系统来说,可以在设备管理器中选择网卡设备的属性对offload功能的状态进行调整,以Intel 82579LM和Intel I217-LM网卡为例

82579

I217