4、Cilium数据面原理:基于eBPF的L3/L4网络策略、Service负载均衡(DSR与Tunnel模式)、NAT与封装
Cilium 的数据面完全构建在 eBPF 之上,绕过了传统的 iptables 和内核网络栈的复杂路径。本章深入解析其核心数据面组件:L3/L4 网络策略的 eBPF 实现、Service 负载均衡的两种模式(DSR 与 Tunnel),以及 NAT 与封装的底层机制。
4.1 基于eBPF的L3/L4网络策略
Cilium 的网络策略通过 eBPF 程序直接挂载到网络钩子点(如 XDP、TC ingress/egress)实现,无需修改 iptables 规则。每个节点上的 Cilium Agent 将用户定义的策略(CRD)编译为 eBPF 字节码,并加载到内核。
策略匹配流程如下:
- 身份识别: 数据包到达 Endpoint 时,eBPF 程序提取源/目的 IP,通过全局的 Identity Map 转换为安全标签(Security Identity)。
- 策略查找: 使用源身份、目的身份、目的端口和协议作为 Key,在 eBPF Map 中查找对应的策略决策(Allow / Deny)。
- 动作执行: 若匹配到 Allow 规则,数据包继续处理;若匹配到 Deny 或无匹配,则直接丢弃。
4.2 Service负载均衡:DSR与Tunnel模式
Cilium 为 Kubernetes Service 提供两种负载均衡转发模式:DSR(Direct Server Return) 和 Tunnel(隧道)。两者均通过 eBPF 在节点上完成,无需 kube-proxy。
| 特性 | DSR 模式 | Tunnel 模式 |
|---|---|---|
| 转发路径 | 请求经 LB 节点,响应直接返回客户端 | 请求和响应均经过 LB 节点 |
| 后端可见源 IP | 客户端真实 IP(保留源 IP) | LB 节点 IP(需额外配置保留源 IP) |
| 封装开销 | 无封装,性能最高 | 需要 VXLAN/Geneve 封装,有额外开销 |
| 适用场景 | 对性能要求极高,且网络允许直接路由 | 跨子网、跨集群、网络策略隔离要求高 |
| eBPF 实现 | 在 TC 入口修改目标 MAC 为后端 Pod MAC | 在 TC 入口封装外层隧道头 |
4.2.1 DSR 模式
在 DSR 模式下,Cilium 的 eBPF 程序在负载均衡节点上仅修改数据包的 目标 MAC 地址 为后端 Pod 的 MAC,并转发出去。后端 Pod 处理完请求后,直接以客户端 IP 为目标发送响应,绕过负载均衡节点。
bpf_redirect() 将数据包重定向到后端 Pod 所在的网络设备,同时通过 bpf_skb_store_bytes() 修改 MAC 头。源 IP 和目的 IP(Cluster IP)保持不变。
4.2.2 Tunnel 模式
Tunnel 模式下,Cilium 在源节点将原始数据包封装在 VXLAN 或 Geneve 隧道中,目标节点解封装后转发给后端 Pod。响应数据包同样经过隧道返回源节点,再由源节点解封装后发送给客户端。
4.3 NAT与封装
Cilium 的 NAT 和封装功能同样由 eBPF 程序实现,用于处理 Service 的 DNAT(目标网络地址转换)和 Overlay 网络的隧道封装。
4.3.1 NAT 实现
当数据包匹配到 Service 规则时,eBPF 程序在 TC ingress 点执行 DNAT,将目标 IP 从 Cluster IP 转换为后端 Pod IP。转换信息记录在 NAT Map 中,用于反向转换(SNAT)。
- DNAT: 修改数据包的目标 IP 和端口,通过
bpf_skb_store_bytes()和bpf_l3_csum_replace()更新校验和。 - SNAT: 对于非 DSR 模式,响应数据包经过 LB 节点时,将源 IP 从 Pod IP 转换回 Cluster IP。
- Map 结构: NAT Map 使用
struct ipv4_nat_entry存储原始 IP:端口与转换后 IP:端口的映射,支持并发查找。
4.3.2 封装实现
在 Tunnel 模式下,Cilium 使用 VXLAN 或 Geneve 封装。eBPF 程序在源节点创建外层 UDP 头(VXLAN 端口 8472,Geneve 端口 6081),并将原始数据包作为负载。
// 伪代码示例:VXLAN 封装
1. 计算外层头部长度(ETH + IP + UDP + VXLAN)
2. 通过 bpf_skb_adjust_room() 扩展数据包头部空间
3. 填充外层以太网头(目标 MAC 为隧道端点)
4. 填充外层 IP 头(源 IP 为本节点,目标 IP 为远端节点)
5. 填充 UDP 头(源端口为哈希值,目标端口 8472)
6. 填充 VXLAN 头(VNI 为网络标识)
7. 通过 bpf_redirect() 发送到隧道设备
下表总结了 NAT 与封装在不同模式下的行为差异:
| 功能 | DSR 模式 | Tunnel 模式 |
|---|---|---|
| DNAT | 仅在 LB 节点执行一次 | 在源节点执行 |
| SNAT | 不需要(响应直接返回) | 在源节点执行(响应返回时) |
| 封装 | 无 | VXLAN/Geneve 封装 |
| eBPF Map 使用 | NAT Map(仅 DNAT 条目) | NAT Map + Tunnel Map(端点映射) |