2. 网络观测基础:网络数据包路径、Linux网络协议栈、eBPF挂载点
网络观测是eBPF最成熟的应用领域之一。要理解eBPF如何观测网络,必须先掌握数据包在Linux系统中的完整旅程、协议栈的分层处理,以及eBPF在各个关键环节的挂载能力。本章将围绕这三个核心主题展开,为后续构建自动化观测制品库打下坚实的理论基础。
2.1 网络数据包路径:从网卡到应用
一个数据包从物理网卡到达用户态应用程序,需要经过一系列内核子系统。理解这条路径是选择eBPF挂载点的前提。下图展示了数据包接收(Rx)路径的核心阶段:
2.2 Linux网络协议栈分层处理
Linux网络协议栈遵循分层设计,每一层负责特定的协议处理。eBPF的挂载点也围绕这些层次分布。下表总结了各层的关键功能与对应的eBPF观测手段:
| 协议栈层次 | 核心功能 | 关键内核函数/子系统 | eBPF挂载方式 |
|---|---|---|---|
| 网络设备层 | 驱动接收/发送、NAPI轮询 | netif_receive_skb、dev_queue_xmit |
XDP、TC、tracepoint:net |
| 网络层 (L3) | IP路由、分片重组、Netfilter钩子 | ip_rcv、ip_output、nf_hook_slow |
kprobe、tracepoint:netfilter |
| 传输层 (L4) | TCP/UDP连接管理、拥塞控制 | tcp_v4_rcv、udp_rcv、tcp_sendmsg |
kprobe、tracepoint:tcp、sockops |
| 套接字层 | Socket抽象、数据拷贝、系统调用 | __sys_recvmsg、sock_read |
tracepoint:syscalls、kprobe |
2.3 eBPF挂载点详解
eBPF程序必须挂载到内核的特定事件上才能执行。在网络观测场景中,最常用的挂载点包括XDP、TC、kprobe和tracepoint。下面逐一分析其特点与适用场景。
2.3.1 XDP (eXpress Data Path)
XDP在网卡驱动层、内核协议栈处理之前执行,是性能最高的eBPF挂载点。它允许程序直接操作原始数据包(DMA缓冲区),实现高速包过滤、负载均衡或DDoS防御。
- 挂载位置:
netif_receive_skb之前,驱动NAPI轮询上下文中。 - 返回动作:
XDP_DROP(丢弃)、XDP_PASS(放行到协议栈)、XDP_TX(从原网卡转发)、XDP_REDIRECT(重定向到其他网卡/CPU)。 - 典型用途: 高性能防火墙、流量采样、数据包元数据提取。
2.3.2 TC (Traffic Control)
TC是Linux内核流量控制子系统,eBPF可以挂载到TC的ingress(入口)和egress(出口)钩子上。TC eBPF在协议栈处理之后、数据包进入Socket队列之前执行,因此可以访问完整的协议头信息。
- 挂载位置:
__dev_queue_xmit(出口)、__netif_receive_skb_core(入口)。 - 返回动作:
TC_ACT_OK(继续)、TC_ACT_SHOT(丢弃)、TC_ACT_REDIRECT(重定向)。 - 典型用途: 流量监控、QoS标记、L3/L4负载均衡。
2.3.3 kprobe (Kernel Probe)
kprobe是一种动态插桩技术,可以在几乎任何内核函数入口(kprobe)或返回(kretprobe)处挂载eBPF程序。它不依赖内核预定义的跟踪点,灵活性极高,但需要开发者了解内核函数签名。
- 挂载方式: 指定函数名,如
kprobe/tcp_v4_rcv。 - 优势: 可以观测未暴露tracepoint的内核路径,如特定驱动函数。
- 风险: 内核函数名可能随版本变化,导致eBPF程序加载失败。
2.3.4 tracepoint (跟踪点)
tracepoint是内核开发者预定义的静态跟踪点,具有稳定的API签名。eBPF程序挂载到tracepoint上比kprobe更安全、更易维护,是生产环境的首选。
- 挂载方式: 指定tracepoint类别/事件,如
tracepoint/net/netif_receive_skb。 - 优势: 参数结构稳定,内核版本升级时不易损坏。
- 典型用途: 网络事件计数、延迟分布统计、连接跟踪。
2.4 挂载点对比与选型
在实际的自动化流水线中,选择哪个挂载点取决于观测目标与性能要求。下表从多个维度对比了四种挂载点:
| 维度 | XDP | TC | kprobe | tracepoint |
|---|---|---|---|---|
| 性能开销 | 极低 | 低 | 中 | 低 |
| 可访问数据 | 原始包(L2-L4) | 完整协议头 | 函数参数/返回值 | 预定义事件字段 |
| API稳定性 | 稳定 | 稳定 | 不稳定(依赖内核版本) | 稳定 |
| 编程复杂度 | 中 | 中 | 高 | 低 |
| 典型场景 | 包过滤、负载均衡 | 流量整形、观测 | 协议栈内部调试 | 生产监控、告警 |
2.5 综合示例:一次HTTP请求的eBPF观测路径
假设我们需要观测一次完整的HTTP请求(从网卡到Nginx进程),eBPF可以在以下挂载点分别采集数据:
- XDP (网卡层): 统计每秒接收的包数,丢弃明显的恶意流量(如SYN Flood)。
- TC ingress (协议栈入口): 提取源IP、目的IP、TCP端口,记录流量五元组。
- tracepoint:tcp/tcp_rcv_established (传输层): 记录TCP连接建立延迟、重传次数。
- kprobe:__sys_recvmsg (系统调用层): 测量应用读取数据的延迟分布。