3. eBPF基础与Cilium事件源:eBPF程序挂载点与网络事件捕获
eBPF(extended Berkeley Packet Filter)是Cilium实现高性能网络与安全策略的核心基石。理解eBPF的程序挂载点以及Cilium如何利用这些挂载点捕获网络事件,是掌握Cilium事件流还原的第一步。本章将深入剖析XDP、TC、cgroup三类关键挂载点,并展示Cilium如何将原始内核事件转化为可观测的Packet、Trace与Kprobe事件。
3.1 eBPF程序挂载点全景
eBPF程序并非独立运行,而是通过挂载点(Hook Point)附着在内核的特定路径上。不同的挂载点决定了程序能处理的数据类型与触发时机。在容器网络场景中,最核心的挂载点包括:
| 挂载点 | 触发位置 | 数据方向 | 典型用途 |
|---|---|---|---|
| XDP(eXpress Data Path) | 网卡驱动层,最早的数据包处理点 | 入站(Ingress) | DDoS防御、负载均衡、高速包过滤 |
| TC(Traffic Control) | 内核协议栈的ingress/egress钩子 | 入站/出站(Ingress & Egress) | 容器网络策略、带宽管理、包封装/解封装 |
| cgroup(Control Group) | cgroup层级中的进程生命周期事件 | 进程级 | 套接字级策略、进程创建/退出监控、系统调用过滤 |
3.2 挂载点工作机制与Cilium集成
3.2.1 XDP:最早的数据包处理点
XDP程序在网卡驱动收到数据包后、尚未分配sk_buff(套接字缓冲区)之前执行。Cilium利用XDP实现高效的入站包过滤与重定向。XDP程序返回的动作决定了数据包的命运:
- XDP_PASS:允许包进入内核协议栈。
- XDP_DROP:直接丢弃包,性能极高。
- XDP_TX:从接收网卡原路转发出去。
- XDP_REDIRECT:将包重定向到其他网卡或CPU。
3.2.2 TC:协议栈内的双向控制点
TC挂载点位于内核协议栈的ingress(入站)和egress(出站)路径上。Cilium在容器veth对的宿主机端挂载TC程序,实现L3/L4网络策略、封装(VXLAN/Geneve)以及负载均衡。TC程序可以访问完整的sk_buff结构,支持修改包内容。
3.2.3 cgroup:进程级套接字控制
cgroup挂载点允许eBPF程序在进程创建、套接字操作等事件发生时触发。Cilium使用cgroup套接字程序(cgroup/skb、cgroup/sock)来实施基于进程身份的套接字级策略,例如限制特定容器只能绑定到特定端口。
3.3 Cilium如何捕获网络事件
Cilium通过eBPF程序在内核中捕获三类核心事件,这些事件构成了事件流还原的数据基础:
3.3.1 Packet事件:数据包级捕获
Packet事件记录每个经过Cilium管理的数据包的元信息,包括源/目的IP、端口、协议、包长度、方向(ingress/egress)以及对应的安全标识(Security Identity)。Cilium在XDP和TC挂载点中嵌入eBPF程序,在包处理路径上提取这些信息并发送到用户空间的Cilium Agent。
3.3.2 Trace事件:连接跟踪与流级信息
Trace事件基于Cilium的连接跟踪(Conntrack)表,记录流的生命周期信息:流创建、流更新、流关闭。每个Trace事件包含流的五元组、起始时间、持续时间、字节数、包数以及策略决策结果(允许/拒绝)。Trace事件是还原网络连接状态变化的关键。
3.3.3 Kprobe事件:内核函数级探测
Kprobe(Kernel Probe)允许Cilium在内核函数入口或出口动态插入探测点。Cilium使用Kprobe捕获系统调用(如connect、accept、sendmsg)和内核网络函数(如tcp_v4_connect、inet_csk_accept)的执行。Kprobe事件提供最细粒度的内核行为视图,用于诊断连接建立失败、DNS解析异常等深层问题。
| 事件类型 | 捕获粒度 | 数据来源 | 典型应用场景 |
|---|---|---|---|
| Packet | 单个数据包 | XDP/TC挂载点 | 实时流量监控、包丢失诊断、带宽分析 |
| Trace | 网络流(Flow) | 连接跟踪表 | 连接状态还原、策略审计、异常流检测 |
| Kprobe | 内核函数调用 | 动态探测点 | 系统调用级故障定位、应用层协议分析 |
3.4 事件捕获的代码示例
以下是一个简化的Cilium eBPF程序片段,展示如何在TC挂载点捕获Packet事件并提取关键信息:
// 伪代码示例:Cilium TC ingress eBPF程序捕获Packet事件
struct packet_event {
__u32 src_ip;
__u32 dst_ip;
__u16 src_port;
__u16 dst_port;
__u8 protocol;
__u32 security_identity;
__u32 packet_len;
__u8 direction; // 0=ingress, 1=egress
};
struct bpf_map_def SEC("maps") packet_events = {
.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(__u32),
.max_entries = 1024,
};
SEC("tc/ingress")
int cilium_tc_ingress(struct __sk_buff *skb) {
struct packet_event event = {};
// 从skb中提取IP和端口信息
event.src_ip = skb->remote_ip4;
event.dst_ip = skb->local_ip4;
event.protocol = skb->protocol;
event.packet_len = skb->len;
event.direction = 0; // ingress
// 获取安全标识(Cilium特有)
event.security_identity = skb->cb[0];
// 发送事件到用户空间
bpf_perf_event_output(skb, &packet_events, BPF_F_CURRENT_CPU,
&event, sizeof(event));
return TC_ACT_OK;
}
bpf_perf_event_output是eBPF程序将事件传递到用户空间的标准方式。Cilium Agent通过读取Perf Event Ring Buffer来消费这些事件,并进一步加工为Hubble可观测性数据。在实际Cilium代码中,事件结构更复杂,包含更多元数据字段。
3.5 事件源选择与故障场景映射
在蓝绿发布故障时间线还原中,不同事件源适用于不同的故障场景:
- Packet事件:用于检测丢包、延迟抖动、流量突发等数据包级异常。
- Trace事件:用于还原连接建立失败、连接中断、策略拒绝等流级故障。
- Kprobe事件:用于诊断应用层连接超时、DNS解析失败、TLS握手异常等深层问题。