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层级中的进程生命周期事件 进程级 套接字级策略、进程创建/退出监控、系统调用过滤
关键认知:XDP在驱动层处理包,性能最高但只能处理入站流量;TC在协议栈内处理,支持双向流量且可修改包内容;cgroup则聚焦于进程与套接字级别的控制,三者互补构成Cilium的完整数据面。

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)来实施基于进程身份的套接字级策略,例如限制特定容器只能绑定到特定端口。

挂载点选择策略:在Cilium中,XDP优先用于高性能入站过滤;TC用于需要修改包或处理出站流量的场景;cgroup用于进程级套接字策略。实际部署中,Cilium会根据节点能力和配置自动选择最优挂载点。
eBPF挂载点与数据流路径 网卡(NIC) XDP 内核协议栈 TC Ingress TC Egress cgroup 容器进程 数据包从网卡进入,依次经过XDP、协议栈、TC Ingress到达容器;出站时反向经过TC Egress和协议栈

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 内核函数调用 动态探测点 系统调用级故障定位、应用层协议分析
性能注意事项:Kprobe事件捕获会引入额外的内核上下文切换开销。在生产环境中,建议仅在故障排查期间临时启用Kprobe事件,避免长期开启影响整体性能。Packet和Trace事件的开销相对较低,可默认开启。
Cilium事件捕获架构 内核空间(Kernel Space) XDP eBPF程序 TC eBPF程序 Kprobe探测点 连接跟踪表 eBPF Map / Perf Event Ring Buffer → 事件生成 用户空间(User Space) Cilium Agent Hubble(事件消费) Packet / Trace / Kprobe eBPF程序通过Perf Event Ring Buffer或eBPF Map将事件传递到用户空间

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握手异常等深层问题。