总述
主要是梳理下一些网卡的一些offload
特性,这些offload
特性主要是提升发送跟接收的性能。以ethtool -k eth0
为切入点,可以看到有这么多的特性。注意在理清一个特性的时候,区分下发送跟接收发送方向。
root@rock-3a:~# 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-tcp-mangleid-segmentation: off
tx-tcp6-segmentation: on
generic-segmentation-offload: on
generic-receive-offload: on
large-receive-offload: off [fixed]
rx-vlan-offload: on [fixed]
tx-vlan-offload: off [fixed]
ntuple-filters: off [fixed]
receive-hashing: off [fixed]
highdma: on [fixed]
rx-vlan-filter: off [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-gre-csum-segmentation: off [fixed]
tx-ipxip4-segmentation: off [fixed]
tx-ipxip6-segmentation: off [fixed]
tx-udp_tnl-segmentation: off [fixed]
tx-udp_tnl-csum-segmentation: off [fixed]
tx-gso-partial: off [fixed]
tx-sctp-segmentation: off [fixed]
tx-esp-segmentation: off [fixed]
tx-udp-segmentation: on
fcoe-mtu: off [fixed]
tx-nocache-copy: off
loopback: off [fixed]
rx-fcs: off [fixed]
rx-all: off [fixed]
tx-vlan-stag-hw-insert: off [fixed]
rx-vlan-stag-hw-parse: on [fixed]
rx-vlan-stag-filter: off [fixed]
l2-fwd-offload: off [fixed]
hw-tc-offload: off [fixed]
esp-hw-offload: off [fixed]
esp-tx-csum-hw-offload: off [fixed]
rx-udp_tunnel-port-offload: off [fixed]
tls-hw-tx-offload: off [fixed]
tls-hw-rx-offload: off [fixed]
rx-gro-hw: off [fixed]
tls-hw-record: off [fixed]
如果要关闭某项特性,比如tso
,就使用命令ethtool -K ethX tso off
。比如接收校验和,ethtool -K ethX rx off
。比如sg
,ethtool -K ethX sg on
发送方向特性
TSO
TSO(TCP Segmentation Offload)
,是一种利用网卡对TCP
数据包分片,减轻CPU
负荷的一种技术,有时也被叫做 LSO (Large segment offload)
。TSO
是针对TCP
的,UFO
是针对UDP
的。如果硬件支持 TSO
功能,同时也需要硬件支持的TCP
校验计算和分散/聚集 (Scatter Gather)
功能。
为什么需要网卡硬件支持TCP
校验计算和分散/聚集 (Scatter Gather)
功能呢?因为大的TCP
包下来,当对该包进行分片后,需要硬件额外的对每个分片附着相关的头部,这就依靠SG
(支持一次性发送多个不连续的数据段)了,然后TCP的校验和也需要硬件自己对每个分片进行独立计算。
注意:在支持TSO
和checksum offload
的网卡上,skb数据在进入驱动层之前是不进行分片处理和完整的checksum
计算的,而tcpdump
抓取的包恰恰是在此处,网卡这时候还没计算出来校验和,自然看到的是错误的数值,而这并不代表实际链路上的包会发生错误。
GSO
GSO(Generic Segmentation Offload)
,它比TSO
更通用,基本思想就是尽可能的推迟数据分片直至发送到网卡驱动之前,此时会检查网卡是否支持分片功能(如TSO、UFO
)。
如果支持直接发送到网卡,如果不支持就进行分片后再发往网卡。这样大数据包只需走一次协议栈,而不是被分割成几个数据包分别走,这就提高了效率。
SG
SG (Scatter Gather)
就是说网卡支持一次发送多个不连续的数据段。
按照我的思路理解,比如开了tso
之后,应用层传来了一个很大的TCP
包,可能这个包被分为了三段。且之前也分析过gmac
驱动,这三段的物理地址可能是不连续的,而网卡有这个SG
特性,他可以一次性把这三个数据发出去,这就有点像离散DMA
的意思了。
其实感觉这个SG
就是支持gmac
支持离散DMA
的意思?
接收方向特性
LRO
LRO(Large Receive Offload)
,通过将接收到的多个TCP
数据聚合成一个大的数据包,然后传递给网络协议栈处理,以减少上层协议栈处理开销,提高系统接收TCP
数据包的能力。LRO
现在已经被GRO
替代了。
GRO
GRO(Generic Receive Offload)
,基本思想跟LRO
类似,克服了LRO
的一些缺点,更通用。后续的驱动都使用GRO
的接口,而不是LRO
。感觉巨型帧Jumbo Frame
是不是需要这个特性?
RSS
RSS(Receive Side Scaling)
,是一项网卡的新特性,俗称多队列。具备多个RSS
队列的网卡,可以将不同的网络流分成不同的队列,再分别将这些队列分配到多个CPU
核心上进行处理,从而将负荷分散,充分利用多核处理器的能力。
怎么分流给CPU
,直接绑定中断即可。
其他概念
MTU
MTU
指的是 IP
报文的大小, 一般MTU
为1500
TCP
模式下,1500(MTU) = 1460(tcp payload) + 20(tcp head) + 20(ip head)
如果这个报文在MAC
网卡上传输,还需打上 MAC
头,1514 = 6(dst mac) + 6(src mac) +2(type) + MTU
校验和
校验和主要提到的有三种。
IP检验和
首先IP
报文的格式如下,前面的20
个字节是固定,最后的四个字节是可选的。这里提到的IP
报文的校验和就是其中的Header Checksum
了。校验和只对头部进行,不包括数据部分。
发送IP
包, 计算checksum
:
- 把
IP
数据报的首部校验和字段设置为0
。 - 把首部看成以
16
位为单位的数字组成,依次进行二进制反码求和。 - 把得到的结果存入校验和字段中。
接收IP
包,验证checksum
:
- 把首部看成以
16
位为单位的数字组成,依次进行二进制反码求和,包括校验和字段。 - 检查计算出的校验和的结果是否为全1。
- 如果全1,校验是和正确。否则,校验和就是错误的,协议栈要抛弃这个数据包。但不生成差错报文,由上层去发现丢失的数据报并进行重传。
UDP校验和
校验和既覆盖头部,也覆盖数据部分。UDP
校验和是可选的。如果校验和字段是0,表示不需要计算校验和。其头部格式如下。
Checksum
也即校验和,UDP
的校验和计算需要引入伪首部 (Pseudo Header)
, 伪首部的结构如下所示:
伪首部中每个字段如下
source address
, 长度为 32 比特, 源 IP 地址destination address
, 长度为 32 比特, 目的 IP 地址zero
, 长度为 8 比特, 全部置为 0protocol
, 长度为 8 比特, UDP 协议的协议编号, 值为 17, 协议编号由 IANA 维护UDP length
, 长度为 16 比特, UDP 长度
发送包, 计算checksum
:
算法和IP头部的校验和计算方法类似:二进制反码求和。但有下面两个区别:
- 总长度如果是奇数,则自动补齐,并自动填充为0. 填充的部分不发送出去。
- 添加12个字节的伪头部。
接收包, 验证checksum
:
验证checksum
是根据udp
头部中的length
字段值所指向的数据长度进行校验,length
字段是包括UDP头部跟数据部分的长度的,如果length
字段值大于实际的数据长度,那么包在校验前会被丢弃。如果length
字段值小于实际的数据长度,则需要裁减数据,并校验。
TCP校验和
TCP
校验和是必须的,过程跟UDP
一样,也需要一个12
字节的伪头部。
各个字段的语义如下:
Source Port
, 长度为 16 比特, 发送端的端口Destination Port
, 长度为 16 比特, 接收端的端口Sequence Number
, 长度为 32 比特, Segment 的序号, 在通常的 TCP 实现中 (如 4.2 BSD) 在进行 TCP 通信时, 都会随机生成一个起始序号 (Initial Sequence Number, 缩写为 ISN), 然后在此基础之上, 每发送一个 Segment, 序号便增加一Acknowledgment Number
, 长度为 32 位, TCP 的确认号, 确认号用于实现对 Segment 的确认机制, 确认号是接收方当前已收到并校验无误的最大序号加一, 即确认号等于 N 代表接收方已经收到了包括 N - 1 在内的所有 Segment, 期望接收序号为 N 的 SegmentData Offset
, 长度为四比特, 该字段以四字节为单位指示 Segment 的 Payload 部分的起始位置相对于 TCP Segment 的起始位置的偏移量, 即若 Data Offset 等于 N 表示 TCP Payload 相对于 TCP Segment 的起始位置的偏移量为 N * 32 比特, 由于该字段的长度为四比特, 因此 TCP Segment 的最大 Header 长度为 60 ByteReserved
, 长度为 6 比特, 保留字段, 使用时应当置 0URG
, 长度为 1 的标志位, 该字段指示紧急指针, 当 URG = 1 时表示当前的 Segment 为高优先级, 应优先发送当前的 SegmentACK
, 长度为 1 的标志位, 当 ACK = 1 时, 确认号 (Acknowledgment Number) 字段有效PSH
, 长度为 1 的标志位, PSH 用来告知接收方此 Segment 应尽快交付给应用层, 因为从 TCP 及其往下的网络协议栈通常都是由内核实现的, TCP 将接收到的数据交付给应用层需要将内核空间的数据拷贝到用户空间, 这是一个比较耗时的操作, 通常 TCP 的实现都会等待数据达到一定数量再交付给应用层, PSH 标志可以通知接收方尽快将 Segment 交付给应用层RST
, 长度为 1 的标志位, 用于释放连接, 当 RST = 1 时通常说明网络发生了严重错误, 此时应立即断开连接并重新连接SYN
, 长度为 1 的标志位, 用于在连接建立的握手阶段来同步序号, 当通信方发起 TCP 握手时, 应设置 SYN = 1 及 ACK = 0, 对方若同意握手请求, 则将响应 Segment 中的 SYN 设置为 1, 并将 ACK 设置为 1FIN
, 长度为 1 的标志位, 用于释放 TCP 连接Window
, 长度为 16 比特, 该字段指示发送方自身的接收窗口, 例如发送方发出的 Segment 的确认号为 N, 窗口为 M, 则表示接收方从 N 算起还可以接收 M 个字节的数据, Window 用来实现 TCP 端到端的流量控制Checksum
, 长度为 16 比特, TCP Segment (Header 及 Payload) 的校验和, 用于接收方校验接收到的数据是否有差错Urgent Pointer
, 长度为 16 比特, 紧急指针, 该字段指示紧急数据的末尾在该 Segment 中的位置, 紧急数据都放在普通的数据之前, 因此该字段也可以理解为普通数据的起始位置Options
, 长度可变, 用于存放 TCP 的选项信息, 由于 Data Offset 的长度为 4 位, 其以 32 比特为单位指示 Payload 相对于 Segment 起始位置的偏移量, 因此 TCP Header 的最大长度为 60 Byte, 其中前 20 Byte 为固定 Header, 因此选项字段的长度上限为 40 Byte (选项字段可以存放的信息比较多, 例如可以存放时间戳, TCP Segment 的序号长度为 32 位, TCP 发送方会随机初始化一个 ISN, 一方面这个 ISN 本身就可能很大, 从而导致序号很快到达最大值而又绕回 0, 另一方面即便 ISN 设置为 0, 由于现在的网络传输速度很快, 可能很快就会把序号用到最大值, 当序号绕回 0 之后, 若此时又收到了此前没有收到的大序号的 Segment, 可能导致无法区分二者的新旧次序, 使用时间戳选项可以实现新旧 Segment 的区分)Padding
, 长度可变, 用于 TCP Segment 是 4 字节对齐的, Options 字段的长度可能不是 4 字节的整数倍, 此时使用 Padding 来填充, Padding 的值应设置为全 0
Jumbo Frames
Jumbo Frames
就是MTU
为9000
字节的Ethernet Frames
。
支持Jumbo Frames
需要相应的硬件支持了。