校验和信息¶
堆栈和网络驱动程序之间的校验和卸载的接口如下...
IP校验和相关功能¶
驱动程序在设备的功能中声明校验和卸载能力。 从堆栈的角度来看,这些是驱动程序提供的功能。 驱动程序通常只声明它能够卸载到其设备的功能。
校验和相关设备功能¶
NETIF_F_HW_CSUM
驱动程序(或其设备)能够为任何协议或协议分层的组合计算一个 IP(一位求反)校验和。 校验和按照 CHECKSUM_PARTIAL 接口在数据包中计算和设置(参见下文)。
NETIF_F_IP_CSUM
驱动程序(设备)只能校验 IPv4 上的纯 TCP 或 UDP 数据包的校验和。 这些是 IPv4|TCP 或 IPv4|UDP 形式的专门的非封装数据包,其中 IPv4 标头中的 Protocol 字段是 TCP 或 UDP。 IPv4 标头可能包含 IP 选项。 如果还设置了 NETIF_F_HW_CSUM,则无法在设备的功能中设置此功能。 此功能已弃用(参见下文)。
NETIF_F_IPV6_CSUM
驱动程序(设备)只能校验 IPv6 上的纯 TCP 或 UDP 数据包的校验和。 这些是 IPv6|TCP 或 IPv6|UDP 形式的专门的非封装数据包,其中 IPv6 标头中的 Next Header 字段是 TCP 或 UDP。 此功能不支持 IPv6 扩展标头。 如果还设置了 NETIF_F_HW_CSUM,则无法在设备的功能中设置此功能。 此功能已弃用(参见下文)。
NETIF_F_RXCSUM
驱动程序(设备)执行接收校验和卸载。 此标志仅用于禁用设备的 RX 校验和功能。 无论是否设置了 NETIF_F_RXCSUM,堆栈都会接受设备上接收的数据包中的接收校验和指示。
设备接收的数据包的校验和¶
校验和验证的指示在 sk_buff.ip_summed 中设置。 可能的值是
CHECKSUM_NONE
设备没有校验此数据包的校验和,例如,由于缺乏能力。 数据包包含完整(但未验证)的校验和,但 skb->csum 中没有。 因此,在这种情况下,skb->csum 是未定义的。
CHECKSUM_UNNECESSARY
您正在处理的硬件不计算完整的校验和(如 CHECKSUM_COMPLETE 中),但它会解析标头并验证特定协议的校验和。 对于此类数据包,如果它们的校验和没问题,则它将设置 CHECKSUM_UNNECESSARY。 在这种情况下,sk_buff.csum 仍然是未定义的。 驱动程序或设备绝不能修改数据包中的校验和字段,即使校验和已验证。
CHECKSUM_UNNECESSARY 适用于以下协议
TCP:IPv6 和 IPv4。
UDP:IPv4 和 IPv6。 设备可以将 CHECKSUM_UNNECESSARY 应用于 IPv4 或 IPv6 的零 UDP 校验和,在这种情况下,网络堆栈可能会执行进一步的验证。
GRE:仅当标头中存在校验和时。
SCTP:指示 SCTP 标头中的 CRC 已验证。
FCOE:指示 FC 帧中的 CRC 已验证。
sk_buff.csum_level 指示在数据包中找到的连续校验和的数量(减 1),这些校验和已验证为 CHECKSUM_UNNECESSARY。 例如,如果设备接收到 IPv6->UDP->GRE->IPv4->TCP 数据包,并且设备能够验证 UDP(可能为零)、GRE(设置了校验和标志)和 TCP 的校验和,则 sk_buff.csum_level 将设置为 2。 如果设备只能验证 UDP 校验和,而不能验证 GRE,可能是因为它不支持 GRE 校验和或因为 GRE 校验和错误,则 skb->csum_level 将设置为 0(在这种情况下不考虑 TCP 校验和)。
CHECKSUM_COMPLETE
这是最通用的方法。 设备提供 netif_rx() 看到的 _整个_ 数据包的校验和,并填写 sk_buff.csum。 这意味着硬件不需要解析 L3/L4 标头来实现此目的。
注意事项
即使设备仅支持某些协议,但能够生成 skb->csum,它也必须使用 CHECKSUM_COMPLETE,而不是 CHECKSUM_UNNECESSARY。
CHECKSUM_COMPLETE 不适用于 SCTP 和 FCoE 协议。
CHECKSUM_PARTIAL
设置校验和以卸载到设备,如 CHECKSUM_PARTIAL 的输出描述中所述。 这可能发生在直接从另一个 Linux OS 接收的数据包上,例如,同一主机上的虚拟化 Linux 内核,或者它可能在 GRO 或远程校验和卸载的输入路径中设置。 为了校验和验证的目的,skb->csum_start + skb->csum_offset 引用的校验和以及数据包中任何前面的校验和都被认为是已验证的。 数据包中位于要卸载的校验和之后的任何校验和都不被认为是已验证的。
非GSO的传输校验和¶
堆栈在数据包的 sk_buff.ip_summed 中请求校验和卸载。 值是
CHECKSUM_PARTIAL
驱动程序需要校验 hard_start_xmit() 从 sk_buff.csum_start 到结尾看到的数据包的校验和,并在偏移量 sk_buff.csum_start + sk_buff.csum_offset 处记录/写入校验和。 驱动程序可能会验证 csum_start 和 csum_offset 值是否是给定数据包的长度和偏移量的有效值,但它不应尝试验证校验和是否引用合法的传输层校验和 - 验证 csum_start 和 csum_offset 是否正确设置是堆栈的职责。
当堆栈请求数据包的校验和卸载时,驱动程序必须确保正确设置校验和。 驱动程序可以将校验和计算卸载到设备,或者调用 skb_checksum_help(如果设备不支持特定校验和的卸载)。
NETIF_F_IP_CSUM 和 NETIF_F_IPV6_CSUM 正被弃用,取而代之的是 NETIF_F_HW_CSUM。 新设备应使用 NETIF_F_HW_CSUM 来指示校验和卸载能力。 可以调用 skb_csum_hwoffload_help() 以基于网络设备校验和能力解析 CHECKSUM_PARTIAL:如果数据包不匹配它们,则调用 skb_checksum_help() 或 skb_crc32c_help()(取决于 sk_buff.csum_not_inet 的值,请参见 非IP校验和 (CRC) 卸载)来解析校验和。
CHECKSUM_NONE
skb 已被协议校验和,或者不需要校验和。
CHECKSUM_UNNECESSARY
这与输出上的校验和卸载的 CHECKSUM_NONE 含义相同。
CHECKSUM_COMPLETE
未用于校验和输出。 如果驱动程序观察到 skbuff 中设置了此值的數據包,则应将数据包视为设置了 CHECKSUM_NONE。
非IP校验和(CRC)卸载¶
NETIF_F_SCTP_CRC
此功能指示设备能够卸载数据包中的 SCTP CRC。 为了执行此卸载,堆栈将相应地设置 csum_start 和 csum_offset,将 ip_summed 设置为 CHECKSUM_PARTIAL,并将 csum_not_inet 设置为 1,以在 skbuff 中指示 CHECKSUM_PARTIAL 引用 CRC32c。 支持 IP 校验和卸载和 SCTP CRC32c 卸载的驱动程序必须通过测试 sk_buff.csum_not_inet 的值来验证为数据包配置了哪个卸载; 提供 skb_crc32c_csum_help() 来解析 csum_not_inet 设置为 1 的 skb 上的 CHECKSUM_PARTIAL。
NETIF_F_FCOE_CRC
此功能指示设备能够卸载数据包中的 FCOE CRC。 为了执行此卸载,堆栈会将 ip_summed 设置为 CHECKSUM_PARTIAL,并相应地设置 csum_start 和 csum_offset。 请注意,skbuff 中没有指示 CHECKSUM_PARTIAL 引用 FCOE 校验和,因此支持 IP 校验和卸载和 FCOE CRC 卸载的驱动程序必须通过检查数据包标头来验证为数据包配置了哪个卸载。
带有GSO的输出校验和¶
在 GSO 数据包的情况下(skb_is_gso() 为真),校验和卸载由 gso_type 中的 SKB_GSO_* 标志暗示。 最明显的是,如果 gso_type 是 SKB_GSO_TCPV4 或 SKB_GSO_TCPV6,则意味着作为 GSO 操作一部分的 TCP 校验和卸载。 如果正在使用 GSO 卸载校验和,则 ip_summed 是 CHECKSUM_PARTIAL,并且 csum_start 和 csum_offset 都设置为引用要卸载的最外层校验和(使用 UDP 封装可以卸载两个校验和)。