You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用bpf_skb_store_bytes带BPF_F_RECOMPUTE_CSUM未更新校验及虚拟机自动修正问题

问题解答

1. 为何BPF_F_RECOMPUTE_CSUM标记未更新校验和?

BPF_F_RECOMPUTE_CSUM的作用仅局限于重算被修改数据直接关联的校验和,你的场景里修改的是IPv6扩展头,不属于TCP/UDP校验和的覆盖范围:

  • TCP/UDP的校验和基于自身载荷+IPv6伪首部(源/目的地址、协议号、上层协议长度),扩展头的插入并未改变这些内容,内核判定原有校验和依然有效,不会触发重算。
  • 该标记仅在修改了校验和覆盖范围内的数据时生效,比如修改TCP头部字段或载荷时,才会触发对应校验和的重新计算。

2. 代码是否存在错误?

你的代码存在几个潜在问题:

  • payload_len计算时机易混淆:你在调用bpf_skb_adjust_room前就计算了payload_len,虽然逻辑结果正确,但此时skb->len还是调整前的长度,建议调整skb长度后再计算,避免误解:
    // 先调整skb长度
    if (bpf_skb_adjust_room(skb, bytes_len, BPF_ADJ_ROOM_NET, 0)) { ... }
    // 再计算payload_len(调整后skb->len已包含扩展头长度)
    ip6->payload_len = bpf_htons(skb->len - sizeof(struct ethhdr) - sizeof(struct ipv6hdr));
    
  • 未处理skb校验和状态:如果原包的校验和是硬件卸载模式(skb->ip_summed = CHECKSUM_UNNECESSARY),插入扩展头后,mt7621的网卡无法正确处理这种状态,需要强制内核重新计算校验和。eBPF中可通过bpf_skb_set_checksum辅助函数标记需要重算的校验和字段,比如TCP校验和:
    // 假设tcp_hdr是调整后的TCP头指针
    bpf_skb_set_checksum(skb, (char*)tcp_hdr - (char*)skb->data + offsetof(struct tcphdr, check), BPF_F_CSUM_MANGLE_0);
    
  • 扩展头插入后的指针处理:你在插入扩展头后重新获取ip6指针的逻辑是正确的,但要确保off变量通过ipv6_header重新计算,避免指针偏移错误。

3. 为何Ubuntu 22.04 x86虚拟机自动修正校验和?

这是x86平台网卡的**TCP/UDP IPv6校验和卸载(Checksum Offload)**功能导致的:

  • Ubuntu虚拟机的网卡默认开启该功能,当内核将skb标记为CHECKSUM_UNNECESSARY时,网卡硬件会自动计算并填充正确的TCP/UDP校验和,无论eBPF程序中的校验和是否正确,最终发送的包都会被网卡修正。
  • OpenWrt的mt7621平台(MIPS架构)网卡驱动通常不支持IPv6校验和卸载,或默认未开启,因此必须由内核/eBPF程序确保校验和正确,否则包会因校验和错误被接收方丢弃。

解决建议

  1. 手动触发校验和重算:通过bpf_skb_set_checksum或bpf_l4_csum_replace辅助函数,强制内核重新计算TCP/UDP的校验和。
  2. 验证payload_len正确性:确保IPv6的payload_len字段准确对应扩展头+上层数据的总长度,避免接收方因解析长度错误导致校验和验证失败。
  3. 关闭硬件卸载(临时测试):在OpenWrt上临时关闭网卡的校验和卸载功能(ethtool -K eth0 tx-checksum-ipv6 off),排查是否为硬件卸载逻辑冲突导致的问题。

内容的提问来源于stack exchange,提问作者user24700654

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 12:55:56