为何校验和不一致
为何校验和不一致导致通信报错
RFC 1624 主要规定了如何对互联网校验和(Internet Checksum)进行增量更新(Incremental Update)。
简单来说,这份文档提供了一个数学公式和计算方法,允许你在修改数据包的某个字段(例如 IP 头的TTL字段或TCP/UDP的端口号)后,通过直接计算变化量来快速更新校验和,而无需重新计算整个数据包内容。
📝 核心内容与背景
RFC 1624 的发布主要是为了修正并更新其前一个版本 RFC 1141 中的一个边界情况错误。
-
修正的问题:RFC 1141 提供的方法在特定情况下(即计算结果本应为
+00x0000)时,会错误地得出-00xFFFF的结果。虽然这在某些校验和验证方式下可以接受,但并非在所有场景下都正确。 -
提供的公式:RFC 1624 给出了一个更精确、更健壮的公式来解决这个问题。
假设你要修改一个16位的字段,从旧值 m 变为新值 m',原始的校验和为 HC,那么新的校验和 HC' 可以通过以下任一公式计算:
-
方法一(标准公式):
HC' = ~(~HC + ~m + m')
这个公式通过
~HC恢复出旧的累加和(C),更新后再取反得到新的校验和。 -
方法二(优化公式):
HC' = HC - ~m - m'
这是一个算术运算的等价形式,在某些架构上计算可能更高效。
💡 主要应用场景
这个增量更新技术主要应用于网络设备(如路由器、NAT网关)处理数据包的过程中,用于快速修改以下字段:
-
TTL(生存时间):IP数据包每经过一跳路由器,TTL值就减1。
-
IP分片:修改分片相关的偏移量字段。
-
NAT(网络地址转换):修改源/目的IP地址或端口号。
-
源路由选项:更新记录路由的地址。
🔧 实际使用示例
假设你在一个NAT设备上,同时修改了TCP报文的目的IP和目的端口:
-
原目的IP
192.168.1.1-> 新目的IP10.0.0.1 -
原目的端口
5000-> 新目的端口80 -
原TCP校验和
0x1234
使用RFC 1624的方法,你只需要将32位的IP地址拆分为两个16位的值,然后应用公式即可快速计算出新的校验和,而无需扫描和计算整个TCP数据段,极大地提高了处理性能。
📌 总结
-
全称:Computation of the Internet Checksum via Incremental Update。
-
目的:通过增量计算高效地更新校验和,避免全量重算。
-
关键意义:修正了RFC 1141在边界条件下的计算错误,是网络协议栈实现中一个重要的优化基础。
如果你需要在自己的代码中实现这个算法,建议优先参考RFC 1624文档正文中的公式和示例。
简单来说,RFC 1624 修正了 RFC 1141 的一个边界问题。Linux 内核的软件校验和计算很早就采用了这个正确的标准,因此你不用担心软件层面的问题。但对于硬件卸载功能,情况会有所不同。
如何确认你的硬件驱动遵循哪种标准?
你可以使用 ethtool 工具来查看网卡驱动支持的硬件卸载功能,这能间接反映出其行为。
| 观察维度 | 具体操作/命令 | 看到什么可以确认遵循 RFC 1624 | 看到什么可能表示遵循 RFC 1141 或存在兼容问题 |
|---|---|---|---|
| 内核软件算法 | 查看内核源码注释 | 在 net/core/ 等目录下能看到代码注释中明确提及 RFC 1624。内核的软件实现是 RFC 1624 标准。 |
在 2.4.x 等极早期内核版本中可能使用旧标准,但现代所有内核都遵循 RFC 1624。 |
| 硬件卸载能力 | 运行 ethtool -k <接口名> |
看到 tx-checksum-ip-generic: on 或 tx-checksumming: on。这代表硬件能处理各种协议的通用校验和,理论上会按 RFC 1624 的标准实现。 |
仅开启 tx-checksum-ipv4 和 tx-checksum-ipv6,而没有开启 generic 选项。 |
| 硬件实际表现 | 分析驱动源码或已知问题 | 驱动源码中会明确处理校验和为 0x0000 的情况。例如,无线网卡驱动 wil6210 的补丁就专门处理了 Windows 系统违反 RFC 1624 的问题。 |
收到校验和应为 0x0000 的报文时报错并丢弃。部分旧网卡驱动可能不理解 0x0000 是有效值,从而将其判定为错误。 |
AX7x
#include <stdio.h> #include <string.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <linux/ethtool.h> #include <linux/sockios.h> #include <net/if.h> #include <unistd.h>
int main(int argc, char **argv) { struct ifreq ifr; struct ethtool_value edata; int sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { perror("socket"); return 1; } strncpy(ifr.ifr_name, argv[1], IFNAMSIZ); edata.cmd = ETHTOOL_GTXCSUM; // 获取 tx checksum 状态 ifr.ifr_data = (caddr_t)&edata; if (ioctl(sock, SIOCETHTOOL, &ifr) == 0) { printf("tx-checksumming: %s\n", edata.data ? "on" : "off"); } else { perror("ioctl"); } close(sock); return 0; }
执行上述函数打印如下:
root@am335x-evm:~# ./uuu eth1 tx-checksumming: on root@am335x-evm:~#
为什么这里没有 tx-checksumming 的配置? DM9000 网卡特性 DM9000 是一款较早期的 10/100M 以太网控制器(常见于嵌入式平台如 AM335x),其硬件能力较为基础,通常不支持硬件校验和卸载(checksum offload)。因此,即使你运行 ethtool -k eth1,输出中 tx-checksumming 也会显示为 off(不可用)。既然硬件本身不支持,内核驱动也就不会在 sysfs 中创建相关控制文件。 /sys/class/net/eth1/ 中缺少 features 文件 你之前列出的 /sys/class/net/eth1 目录中没有 features 文件,这也佐证了该网卡驱动未实现向 sysfs 导出 offload 特性的功能(可能由于内核配置或驱动自身限制)。 硬件卸载状态的典型暴露方式 对于支持 offload 的网卡,其状态通常通过 /sys/class/net/<iface>/features(位掩码)或通过 ethtool 的 -k 选项展示。DM9000 不支持,因此这些接口不会出现或始终返回 off。
TM741
root@am62xx-evm:~# ethtool -k eth1 Features for eth1: rx-checksumming: on tx-checksumming: on tx-checksum-ipv4: off [fixed] tx-checksum-ip-generic: on tx-checksum-ipv6: off [fixed] 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: off tx-tcp-segmentation: off [fixed] tx-tcp-ecn-segmentation: off [fixed] tx-tcp-mangleid-segmentation: off [fixed] tx-tcp6-segmentation: off [fixed] generic-segmentation-offload: on generic-receive-offload: on large-receive-offload: off [fixed] rx-vlan-offload: off [fixed] tx-vlan-offload: off [fixed] ntuple-filters: off [fixed] receive-hashing: off [fixed] highdma: off [fixed] rx-vlan-filter: on [fixed] vlan-challenged: 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-tunnel-remcsum-segmentation: off [fixed] tx-sctp-segmentation: off [fixed] tx-esp-segmentation: off [fixed] tx-udp-segmentation: off [fixed] tx-gso-list: 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: off [fixed] rx-vlan-stag-filter: off [fixed] l2-fwd-offload: off [fixed] hw-tc-offload: on 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] rx-gro-list: off macsec-hw-offload: off [fixed] rx-udp-gro-forwarding: off hsr-tag-ins-offload: off [fixed] hsr-tag-rm-offload: off [fixed] hsr-fwd-offload: off [fixed] hsr-dup-offload: off [fixed]
TM753
root@am571x-evm:~# ethtool -k eth1 Features for eth1: Cannot get device udp-fragmentation-offload settings: Operation not supported rx-checksumming: off [fixed] tx-checksumming: off tx-checksum-ipv4: off [fixed] tx-checksum-ip-generic: off [fixed] tx-checksum-ipv6: off [fixed] tx-checksum-fcoe-crc: off [fixed] tx-checksum-sctp: off [fixed] scatter-gather: off tx-scatter-gather: off [fixed] tx-scatter-gather-fraglist: off [fixed] tcp-segmentation-offload: off tx-tcp-segmentation: off [fixed] tx-tcp-ecn-segmentation: off [fixed] tx-tcp-mangleid-segmentation: off [fixed] tx-tcp6-segmentation: off [fixed] udp-fragmentation-offload: off generic-segmentation-offload: off [requested on] generic-receive-offload: on large-receive-offload: off [fixed] rx-vlan-offload: off [fixed] tx-vlan-offload: off [fixed] ntuple-filters: off [fixed] receive-hashing: off [fixed] highdma: off [fixed] rx-vlan-filter: on 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-tunnel-remcsum-segmentation: off [fixed] tx-sctp-segmentation: off [fixed] tx-esp-segmentation: off [fixed] tx-udp-segmentation: off [fixed] tx-gso-list: off [fixed] 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: off [fixed] rx-vlan-stag-filter: off [fixed] l2-fwd-offload: off [fixed] hw-tc-offload: on [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] rx-gro-list: off macsec-hw-offload: off [fixed] rx-udp-gro-forwarding: off hsr-tag-ins-offload: off [fixed] hsr-tag-rm-offload: off [fixed] hsr-fwd-offload: off [fixed] hsr-dup-offload: off [fixed] root@am571x-evm:~# uname -a Linux am571x-evm 6.1.119-rt45-00004-gcc4dcbbb0644-dirty #1 PREEMPT_RT Thu Dec 25 17:09:41 CST 2025 armv7l GNU/Linux root@am571x-evm:~#
TP2000
invt@invt:~$ ethtool -k eth0 Features for eth0: rx-checksumming: on tx-checksumming: on tx-checksum-ipv4: off [fixed] tx-checksum-ip-generic: on tx-checksum-ipv6: off [fixed] tx-checksum-fcoe-crc: off [fixed] tx-checksum-sctp: on 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 tx-vlan-offload: on ntuple-filters: off 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: on tx-gre-csum-segmentation: on tx-ipxip4-segmentation: on tx-ipxip6-segmentation: on tx-udp_tnl-segmentation: on tx-udp_tnl-csum-segmentation: on tx-gso-partial: on tx-sctp-segmentation: off [fixed] tx-esp-segmentation: off [fixed] tx-udp-segmentation: off [fixed] fcoe-mtu: off [fixed] tx-nocache-copy: off 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] hw-tc-offload: on 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] invt@invt:~$ uname -a Linux invt 4.19.59-rt24 #61 SMP PREEMPT RT Fri Jun 6 01:26:20 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux invt@invt:~$
浙公网安备 33010602011771号