2. 网络观测基础:网络数据包路径、Linux网络协议栈、eBPF挂载点

网络观测是eBPF最成熟的应用领域之一。要理解eBPF如何观测网络,必须先掌握数据包在Linux系统中的完整旅程、协议栈的分层处理,以及eBPF在各个关键环节的挂载能力。本章将围绕这三个核心主题展开,为后续构建自动化观测制品库打下坚实的理论基础。

2.1 网络数据包路径:从网卡到应用

一个数据包从物理网卡到达用户态应用程序,需要经过一系列内核子系统。理解这条路径是选择eBPF挂载点的前提。下图展示了数据包接收(Rx)路径的核心阶段:

网络数据包接收路径与eBPF挂载点 网络数据包接收路径与eBPF挂载点 网卡 (NIC) 硬件接收 XDP eBPF早期挂载 内核协议栈 TC / Netfilter Socket 内核-用户边界 用户态应用 read/recvmsg kprobe / tracepoint 动态/静态插桩 💡 路径要点 • XDP 在驱动层直接处理,绕过协议栈,性能最高。 • TC 在协议栈入口/出口挂载,适合流量整形与过滤。 • kprobe/tracepoint 可观测协议栈内部函数调用。
路径速记: 网卡 → XDP(可选) → 内核协议栈(TC/Netfilter) → Socket → 用户态应用。eBPF 可以在除“用户态应用”之外的每一个环节插入观测逻辑。

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
观测粒度说明: 越靠近网卡(如XDP),观测开销越低,但可获取的协议信息越少;越靠近应用(如kprobe在tcp_sendmsg),信息越丰富,但性能开销也越大。实际制品库设计需要根据观测目标在“性能”与“信息量”之间做权衡。

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稳定性 稳定 稳定 不稳定(依赖内核版本) 稳定
编程复杂度 中 中 高 低
典型场景 包过滤、负载均衡 流量整形、观测 协议栈内部调试 生产监控、告警
选型建议: 对于自动化制品库,优先使用 tracepoint 和 TC 作为主要挂载点,因为它们API稳定、性能可接受。仅在需要极致性能(如XDP)或调试未覆盖路径(如kprobe)时才引入其他挂载点。制品库应封装挂载点差异,对用户暴露统一的观测语义。

2.5 综合示例:一次HTTP请求的eBPF观测路径

假设我们需要观测一次完整的HTTP请求(从网卡到Nginx进程),eBPF可以在以下挂载点分别采集数据:

  1. XDP (网卡层): 统计每秒接收的包数,丢弃明显的恶意流量(如SYN Flood)。
  2. TC ingress (协议栈入口): 提取源IP、目的IP、TCP端口,记录流量五元组。
  3. tracepoint:tcp/tcp_rcv_established (传输层): 记录TCP连接建立延迟、重传次数。
  4. kprobe:__sys_recvmsg (系统调用层): 测量应用读取数据的延迟分布。