news 2026/9/14 8:32:56

Cilium eBPF 数据面 IP 分片跟踪(Fragment Handling)完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Cilium eBPF 数据面 IP 分片跟踪(Fragment Handling)完整指南

Cilium eBPF 数据面 IP 分片跟踪(Fragment Handling)完整指南

【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium

Cilium 的 eBPF 数据面默认启用 IP 分片跟踪(IP fragment tracking),用于让不支持分段(segmentation)的协议(典型如 UDP)能够透明地传输超过链路 MTU 的大报文。本文以 Cilium 官方文档 fragmentation.rst 为核心,结合仓库内 pkg/option/config.go、bpf/lib/ipv4.h、bpf/lib/ipv6.h 等源码,系统讲解分片跟踪的启用/禁用开关、BPF map 容量参数、底层处理逻辑与配套监控指标,帮助读者在真实集群中完成配置、排障与容量评估。

为什么 Cilium 需要跟踪 IP 分片

当网络报文长度超过路径上某个链路的 MTU(最大传输单元)时,发送方或中间设备会把报文拆分为多个分片(fragment)。TCP 通过 MSS 协商避免这种情况,但 UDP 等无连接协议没有分段机制,只能依赖 IP 层分片来传递大报文。

问题在于:分片报文里,只有第一个分片携带完整的 L4 头(TCP/UDP 端口号),后续分片只有 IP 层信息。而 Cilium 数据面做策略过滤、连接跟踪(conntrack)和负载均衡时,都需要基于「五元组(源/目的 IP、协议、源/目的端口)」进行查找。如果不对分片做跟踪,后续分片将因为查不到 L4 端口信息而无法完成 L4 语义的处理。

为此,Cilium 在 eBPF 数据面实现了分片跟踪机制:

  • 收到第一个带 L4 头的分片时,将「分片标识 → L4 端口对」写入一张 BPF map;
  • 后续到达的不带 L4 头的分片,通过同样的分片标识(源地址、目的地址、IP 标识符、协议)在 map 中查到端口信息,从而复用与首片相同的 L4 语义完成查表。

这样,无论分片以何种顺序到达,数据面都能正确执行策略与连接跟踪。

核心配置项

分片跟踪默认开启,可通过以下cilium-agent命令行选项配置(参数定义见 pkg/option/config.go):

命令行选项作用默认值
--enable-ipv4-fragment-tracking启用/禁用 IPv4 分片跟踪启用(默认开启)
--enable-ipv6-fragment-tracking启用/禁用 IPv6 分片跟踪启用(默认开启)
--bpf-fragments-map-max控制使用 IP 分片的并发连接的最大数量(即分片跟踪 BPF map 容量上限)8k(见下文「容量与边界」)

这三个选项分别映射到源码中的常量EnableIPv4FragmentsTrackingNameEnableIPv6FragmentsTrackingNameFragmentsMapEntriesName,在 pkg/option/config.go 中通过 viper 解析为 Daemon 配置:

c.EnableIPv4FragmentsTracking = vp.GetBool(EnableIPv4FragmentsTrackingName) c.EnableIPv6FragmentsTracking = vp.GetBool(EnableIPv6FragmentsTrackingName) c.FragmentsMapEntries = vp.GetInt(FragmentsMapEntriesName)

配置注意事项

  • 这两个开关是相互独立的:可以只跟踪 IPv4、只跟踪 IPv6,或同时关闭;
  • 关闭跟踪后,不带 L4 头的分片将无法获得端口信息,数据面会以DROP_FRAG_NOSUPPORT处理(对应 BPF 代码ipv4_load_l4_ports/ipv6_load_l4_portsenable_*_fragments配置为 false 的分支);
  • 在 Helm 部署场景下,对应 values 中的 agent 命令行参数可在安装时通过--set覆盖,或直接修改 agent DaemonSet 的启动参数。

底层实现:分片跟踪 BPF map 与处理路径

分片跟踪的核心数据载体是两张 BTF 类型的 BPF map,在 BPF 代码中定义:

  • IPv4:cilium_ipv4_frag_datagrams,定义见 bpf/lib/ipv4.h;
  • IPv6:cilium_ipv6_frag_datagrams,定义见 bpf/lib/ipv6.h。

map 的 key 是分片标识结构(struct ipv4_frag_id/struct ipv6_frag_id),由报文头字段构成:

struct ipv4_frag_id { __be32 daddr; __be32 saddr; __be16 id; /* IP Identification 字段 */ __u8 proto; ... } __packed;

即以「目的地址 + 源地址 + IP 标识符 + 协议号」唯一定位一个原始数据报(datagram),value 则保存该数据报的源端口与目的端口。

分片处理主函数

以 IPv4 为例,核心处理函数ipv4_handle_fragmentation位于 bpf/lib/ipv4.h,其逻辑分三种情况:

  1. 分片不带 L4 头(后续分片):调用ipv4_frag_get_l4ports在 map 中查找端口;若查不到返回DROP_FRAG_NOT_FOUND,表示首片尚未到达(bpf/lib/ipv4.h);
  2. 分片带 L4 头且是分片(首片或中间某片):从报文加载源/目的端口,然后map_update_elem将「分片标识 → 端口」写入cilium_ipv4_frag_datagrams。注意源码注释特别说明:即使 map 写入失败也不返回错误,当前报文仍可正常处理,只是后续分片无法复用该记录(bpf/lib/ipv4.h);
  3. 完整未分片报文:直接加载 L4 端口,不涉及 map。

最终由ipv4_load_l4_ports统一入口按配置开关分发:

if (CONFIG(enable_ipv4_fragments)) return ipv4_handle_fragmentation(ctx, ip4, fraginfo, l4_off, dir, (struct ipv4_frag_l4ports *)ports); if (unlikely(!ipfrag_has_l4_header(fraginfo))) return DROP_FRAG_NOSUPPORT;

IPv6 的处理路径与 IPv4 对称:ipv6_handle_fragmentation(bpf/lib/ipv6.h)中有一个实现细节——利用 IPv6 头与ipv6_frag_id中 saddr/daddr 偏移相同的特性,复用栈上空间避免额外的 32 字节拷贝,先清零填充位、写入idproto,处理完毕后再恢复原值。

这些 eBPF 程序通过DECLARE_CONFIG(bool, enable_ipv4_fragments, ...)(bpf/lib/ipv4.h)与 agent 侧参数联动,实现开关与数据面的映射。

容量与边界

分片跟踪 map 的容量不是无上限的,源码在 pkg/option/config.go 定义了硬边界:

FragmentsMapMin = 1 << 8 // 256 FragmentsMapMax = 1 << 16 // 65536

--bpf-fragments-map-max的取值在 pkg/option/config.go 中被校验,超出边界会直接导致 agent 启动失败并返回明确错误信息:

if c.FragmentsMapEntries < FragmentsMapMin { return fmt.Errorf("specified max entries %d for fragment-tracking map must be greater or equal to %d", ...) } if c.FragmentsMapEntries > FragmentsMapMax { return fmt.Errorf("specified max entries %d for fragment-tracking map must not exceed maximum %d", ...) }

即该参数的可配置区间为256 ~ 65536

默认情况下,IPv4 与 IPv6 分片跟踪 map 的节点级容量均为8k(8192),含义是「同一节点上最多同时有 8192 个分片数据报在途」(见 Documentation/network/ebpf/maps.rst 的 BPF map 默认容量表)。当数据报数量超过该上限时,map 插入会失败,意味着超出的数据报将无法获得端口关联,可能影响对应流的 L4 处理。在分片流量密集的节点(例如大量跨网传输大 UDP 报文),应根据监控指标评估是否需要调大该值。

监控指标:确认分片是否发生

1. 分片跟踪 map 压力指标

检查以下两个 Prometheus 指标是否非零,即可确认数据面是否处理过分片报文:

  • cilium_bpf_map_pressure{map_name="cilium_ipv4_frag_datagrams"}
  • cilium_bpf_map_pressure{map_name="cilium_ipv6_frag_datagrams"}

指标非零表示曾经有分片报文进入跟踪流程。同时,cilium_bpf_map_pressure也能反映 map 的填充水位,帮助判断 8k 默认容量是否接近极限、是否需要调大--bpf-fragments-map-max

2. MTU 错误消息指标

分片行为往往由路径 MTU 不足触发,Cilium 数据面会处理相应的 ICMP 报错消息。可通过以下指标观察:

  • mtu_error_message_total:Cilium 数据面处理的 ICMPfragmentation_needed(IPv4)或 ICMPv6packet_too_big消息总数。

该指标的实现位于 pkg/maps/metricsmap/metricsmap.go,定义为:

fragNeededCountDesc: prometheus.NewDesc( prometheus.BuildFQName(metrics.Namespace, "", "mtu_error_message_total"), "Total number of icmp fragmentation-needed or icmpv6 packet-too-big messages processed", []string{metrics.LabelDirection}, nil, ),

这类报文正是**路径 MTU 发现(PMTUD)**的基础:它们的出现说明网络中某段路径上的报文尺寸超出了链路最大 MTU,通常意味着需要排查 MTU 配置(如隧道开销、VXLAN/Geneve 封装尺寸、底层网络巨型帧支持等)。同一文件中还有一个配套指标fragmented_count_total("Total number of fragmented packets processed by datapath"),可直接统计数据面处理的分片报文总数,适合与mtu_error_message_total一起观察。

指标使用小结

指标含义典型用途
cilium_bpf_map_pressure{map_name="cilium_ipv4_frag_datagrams"}IPv4 分片跟踪 map 压力/水位确认 IPv4 分片是否发生、评估 map 容量
cilium_bpf_map_pressure{map_name="cilium_ipv6_frag_datagrams"}IPv6 分片跟踪 map 压力/水位确认 IPv6 分片是否发生、评估 map 容量
mtu_error_message_totalICMP fragmentation_needed / ICMPv6 packet_too_big 处理数判断路径 MTU 是否不足、定位大报文被丢弃的根因
fragmented_count_total数据面处理的分片报文总数量化分片流量规模

测试验证:NodePort 场景下的分片处理

仓库的 BPF 测试套件为分片跟踪提供了端到端用例,见 bpf/tests/tc_nodeport_lb_fragments.h。该测试:

  • 通过ASSIGN_CONFIG(bool, enable_ipv4_fragments, true)ASSIGN_CONFIG(bool, enable_ipv6_fragments, true)显式开启 IPv4/IPv6 分片跟踪(bpf/tests/tc_nodeport_lb_fragments.h);
  • 构造外部访问 NodePort 服务的 IPv4/IPv6 分片报文(lb4_ns_nodeport_fragment1/2lb6_ns_nodeport_fragment1/2等),覆盖首片与后续分片;
  • 校验分片经 DNAT 后仍能正确匹配 conntrack,并检查分片相关指标键。

这说明分片跟踪与负载均衡(NodePort/LB)路径紧密耦合——只有正确关联分片端口,DNAT 后连接跟踪才能对同一条流的所有分片生效。读者在启用/调大分片跟踪配置后,可参考该测试理解预期行为。

运维建议与常见问题

  1. 确认分片是否真的发生:先查cilium_bpf_map_pressure{map_name="cilium_ipv4_frag_datagrams"}等指标;全部为 0 说明当前网络路径没有分片流量,无需调整任何参数。
  2. 出现大量mtu_error_message_total:优先排查链路 MTU,而不是盲目调大 map。大报文被丢弃、重传、性能劣化通常根因是 MTU 不匹配(例如 Pod 网络接口 MTU 与底层网络不一致,或隧道封装未考虑开销)。
  3. map 容量接近上限时:结合cilium_bpf_map_pressure的水位,将--bpf-fragments-map-max在 256~65536 的合法区间内调大,并重启 agent 生效。
  4. 安全/合规考虑:分片本身可能被用于绕过策略(fragment evasion),若业务明确不需要分片传输大 UDP 报文,可在确认无分片流量后通过--enable-ipv4-fragment-tracking=false/--enable-ipv6-fragment-tracking=false关闭,关闭后无 L4 头的分片会被DROP_FRAG_NOSUPPORT丢弃,行为更严格。
  5. 改动重启影响:调整--bpf-fragments-map-max会导致分片跟踪 map 重建,涉及存量分片流的短暂重学习,建议在维护窗口执行。

小结

Cilium 的 IP 分片跟踪是保证 UDP 等协议大报文在 eBPF 数据面「透明穿越」的关键机制:默认开启的 IPv4/IPv6 跟踪通过cilium_ipv4_frag_datagrams/cilium_ipv6_frag_datagrams两张 BPF map 将分片标识映射到 L4 端口,使连接跟踪、策略与负载均衡对分片流保持完整语义。运维时可借助--enable-ipv4-fragment-tracking--enable-ipv6-fragment-tracking--bpf-fragments-map-max三个参数灵活控制,并通过cilium_bpf_map_pressuremtu_error_message_total等指标精准定位分片与 MTU 问题,实现数据面的精细化调优。

【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 8:32:36

AI语言引擎:破解游戏出海本地化与买量增长脱节的钥匙

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/14 8:32:02

MATLAB实现OFDM信道编码:卷积码、Turbo与LDPC完整链路

简介&#xff1a;面向通信工程学生与研究人员的OFDM完整MATLAB仿真资源&#xff0c;聚焦信道估计、调制与信道编码三大核心模块&#xff0c;覆盖正交频分复用系统的关键知识点&#xff0c;帮助理解OFDM从发射到接收的完整链路以及不同传输策略对系统性能的影响。压缩包共21个文…

作者头像 李华
网站建设 2026/9/14 8:29:16

WPS JSA实现Excel多Sheet数据合并与自动化处理

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华