blj28

导航

为何校验和不一致

为何校验和不一致导致通信报错

RFC 1624 主要规定了如何对互联网校验和(Internet Checksum)进行增量更新(Incremental Update)。

简单来说,这份文档提供了一个数学公式和计算方法,允许你在修改数据包的某个字段(例如 IP 头的TTL字段或TCP/UDP的端口号)后,通过直接计算变化量来快速更新校验和,而无需重新计算整个数据包内容。

📝 核心内容与背景

RFC 1624 的发布主要是为了修正并更新其前一个版本 RFC 1141 中的一个边界情况错误。

  • 修正的问题:RFC 1141 提供的方法在特定情况下(即计算结果本应为 +0 0x0000)时,会错误地得出 -0 0xFFFF 的结果。虽然这在某些校验和验证方式下可以接受,但并非在所有场景下都正确。

  • 提供的公式:RFC 1624 给出了一个更精确、更健壮的公式来解决这个问题。

假设你要修改一个16位的字段,从旧值 m 变为新值 m',原始的校验和为 HC,那么新的校验和 HC' 可以通过以下任一公式计算:

  • 方法一(标准公式):

    text
    HC' = ~(~HC + ~m + m')

    这个公式通过 ~HC 恢复出旧的累加和(C),更新后再取反得到新的校验和。

  • 方法二(优化公式):

    text
    HC' = HC - ~m - m'

    这是一个算术运算的等价形式,在某些架构上计算可能更高效。

💡 主要应用场景

这个增量更新技术主要应用于网络设备(如路由器、NAT网关)处理数据包的过程中,用于快速修改以下字段:

  • TTL(生存时间):IP数据包每经过一跳路由器,TTL值就减1。

  • IP分片:修改分片相关的偏移量字段。

  • NAT(网络地址转换):修改源/目的IP地址或端口号。

  • 源路由选项:更新记录路由的地址。

🔧 实际使用示例

假设你在一个NAT设备上,同时修改了TCP报文的目的IP和目的端口:

  1. 原目的IP 192.168.1.1 -> 新目的IP 10.0.0.1

  2. 原目的端口 5000 -> 新目的端口 80

  3. 原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:~$

 

posted on 2026-03-25 16:38  bailinjun  阅读(50)  评论(0)    收藏  举报