2. eBPF 技术基础:架构、验证器、Map与Program、与传统iptables对比

eBPF(extended Berkeley Packet Filter)是 Cilium 实现高性能网络与安全策略的核心技术。理解 eBPF 的架构、验证机制、数据交互方式,以及与 iptables 的本质差异,是掌握 Cilium 数据面优化的前提。

2.1 eBPF 整体架构

eBPF 允许用户在 Linux 内核中安全地运行沙箱化程序,而无需修改内核源码或加载内核模块。其架构分为用户空间、内核辅助层和钩子点三层。

核心思想: eBPF 程序通过事件驱动的方式挂载到内核的特定钩子点(如网络包接收、系统调用、函数入口/出口),在内核态执行自定义逻辑,仅将必要的结果或统计信息传递回用户空间。
eBPF 三层架构与数据流 eBPF 三层架构与数据流 用户空间 (User Space) Cilium Agent / bpftool / 应用程序 加载 eBPF 程序 | 读取 Map 数据 | 配置策略 内核空间 (Kernel Space) eBPF 验证器 安全校验 · 循环检测 JIT 编译器 字节码 → 机器码 内核钩子点 XDP · TC · Tracepoint 内核辅助函数 (Helper Functions) 硬件层 (NIC · CPU · Memory)

2.2 内核验证器:安全第一道防线

eBPF 验证器是内核中一个关键的安全组件。在 eBPF 程序加载到内核并执行之前,验证器会对其进行严格的静态分析,确保程序不会导致内核崩溃、死锁或安全漏洞。

验证维度 检查内容 违规后果
控制流完整性 确保程序有明确的结束点,不存在不可达指令或无限循环 程序加载被拒绝
栈边界检查 验证所有内存访问(读/写)都在栈或 Map 的合法范围内 程序加载被拒绝
指针类型安全 禁止指针算术运算,禁止将整数强制转换为指针 程序加载被拒绝
辅助函数白名单 只允许调用内核预定义的、安全的辅助函数 程序加载被拒绝
最大指令数限制 程序指令数不得超过 BPF_MAXINSNS(默认 4096) 程序加载被拒绝
实践要点: 在编写 eBPF 程序时,应避免复杂的循环结构(除非使用有界循环且能被验证器展开),并确保所有内存访问都经过边界检查。Cilium 的代码生成层已经内置了这些安全约束。

2.3 eBPF Map 与 Program:数据交互的桥梁

eBPF 程序本身是无状态的,但通过 Map 实现状态存储和用户空间通信。Map 是内核中的键值存储结构,可以被多个 eBPF 程序以及用户空间程序通过文件描述符访问。

2.3.1 常见 Map 类型

Map 类型 用途 典型场景
BPF_MAP_TYPE_HASH 通用哈希表,键值对查找 存储连接跟踪表、策略规则
BPF_MAP_TYPE_ARRAY 固定大小的数组,索引访问 全局计数器、per-CPU 统计
BPF_MAP_TYPE_LRU_HASH 带 LRU 淘汰机制的哈希表 限制大小的连接缓存
BPF_MAP_TYPE_PERCPU_ARRAY per-CPU 数组,避免锁竞争 高性能包计数
BPF_MAP_TYPE_RINGBUF 高效的数据流传输(内核→用户) 事件日志、监控数据导出

2.3.2 Program 与 Map 的协作流程

  1. 加载阶段: 用户空间(如 Cilium Agent)通过 bpf() 系统调用创建 Map 并加载 eBPF 程序。
  2. 挂载阶段: 将 eBPF 程序附加到指定的内核钩子点(如 XDP、TC ingress/egress)。
  3. 运行阶段: 每当事件触发(如网络包到达),eBPF 程序执行,通过辅助函数 bpf_map_lookup_elem() / bpf_map_update_elem() 读写 Map。
  4. 通信阶段: 用户空间程序通过 bpf() 系统调用或 bpftool map dump 读取 Map 数据,实现监控和动态配置。
eBPF Program 与 Map 交互流程 eBPF Program 与 Map 交互流程 用户空间程序 Cilium Agent / bpftool eBPF Map 键值存储 / 统计 / 配置 内核钩子点 XDP / TC / Tracepoint eBPF Program 包处理 / 策略执行 bpf() 系统调用 挂载 事件触发 读写 Map

2.4 eBPF 与 iptables 对比:从规则匹配到内核编程

iptables 基于 Netfilter 框架,采用链式规则遍历匹配;eBPF 则允许用户在内核中执行自定义程序。两者在性能、灵活性和可编程性上存在本质差异。

对比维度 iptables (Netfilter) eBPF
执行模型 线性规则遍历,匹配即停止(或继续) 事件驱动,执行自定义字节码
性能开销 高,尤其规则数量多时,CPU 消耗线性增长 低,JIT 编译为机器码,无上下文切换
灵活性 固定表(filter/nat/mangle)和固定匹配条件 可编程,支持任意协议解析和自定义逻辑
状态跟踪 依赖 conntrack 模块,有性能瓶颈 通过 Map 实现自定义状态机,更高效
可观测性 通过日志和计数器,粒度粗 通过 Map 和 Perf Event,可导出任意指标
安全模型 内核模块或规则配置,无沙箱 验证器 + 沙箱执行,安全性更高
更新方式 规则变更需逐个修改,可能中断连接 原子替换程序或 Map 内容,无中断
迁移注意事项: 从 iptables 迁移到 eBPF(如使用 Cilium)并非简单的规则翻译。需要重新设计网络策略模型,利用 eBPF 的 Map 和 Program 实现更细粒度的控制。对于简单的 DNAT/SNAT 场景,Cilium 的 eBPF 实现通常能提供 2-5 倍的性能提升。

2.5 小结