---
title: eBPF 程序类型
url: https://doc.liz6.com/linux-kernel/08-ebpf-and-observability/02-ebpf-program-types
locale: zh
area: linux-kernel
tags:
- linux-kernel
- eBPF与可观测性
date: 2026-06-30
modified: 2026-06-30
description: '覆盖: 所有 BPF_PROG_TYPE → 挂载点 → 上下文 → 可用 helpers → 使用场景 → 内核实现要点'
---

# eBPF 程序类型

> 覆盖: 所有 BPF_PROG_TYPE → 挂载点 → 上下文 → 可用 helpers → 使用场景 → 内核实现要点

## 程序类型总览

每种程序类型定义了：attach 到哪里、context 参数类型、可用的 helper 函数白名单。

| 类型 | 挂载点 | Context | 用途 |
|------|--------|---------|------|
| `XDP` | 网卡驱动 NAPI poll | `xdp_md` | DDoS/负载均衡 (最早接触点) |
| `SCHED_CLS` | TC ingress/egress | `__sk_buff` | 防火墙/Cilium |
| `SCHED_ACT` | TC action | `__sk_buff` | 包修改/重定向 |
| `KPROBE` | kprobe (函数入口) | `pt_regs` | 可观测性 |
| `TRACEPOINT` | tracepoint | tracepoint 特定 struct | 事件追踪 |
| `PERF_EVENT` | perf_event_open | `bpf_perf_event_data` | 性能采样 |
| `CGROUP_SKB` | cgroup egress/ingress | `__sk_buff` | 容器网络策略 |
| `CGROUP_SOCK` | socket create/release | `bpf_sock` | socket 选项控制 |
| `SOCK_OPS` | socket 操作 (TCP states) | `bpf_sock_ops` | TCP 调优/BBR 策略 |
| `SK_MSG` | socket message | `sk_msg_md` | socket 重定向 |
| `LSM` | LSM hooks | `bpf_lsm_ctx` | 安全策略 |
| `SK_LOOKUP` | socket lookup | `bpf_sk_lookup` | socket 绑定覆盖 |
| `SYSCALL` | syscall | `bpf_syscall_ctx` | syscall 过滤 |
| `STRUCT_OPS` | 内核函数指针替换 | 操作特定 struct | 替换拥塞控制等 |

---

## 深入关键程序类型

### XDP (eXpress Data Path)

```c
// drivers/net/ 各驱动 → XDP hook → BPF 程序
// 最早处理点: NAPI poll 中, sk_buff 分配之前
// Context: struct xdp_md { data, data_end, data_meta }

// 返回值:
enum xdp_action {
    XDP_DROP,       // 丢弃 (最快!)
    XDP_PASS,       // 放行, 交给协议栈
    XDP_TX,         // 从同一网卡发回 (hairpin)
    XDP_REDIRECT,   // 重定向到其他网卡/CPU
};

// 为何快:
//   - 在 sk_buff 分配之前运行 → 零分配开销
//   - 驱动内联执行 → 无函数调用开销 (某些驱动)
//   - DROP 只需: BPF_JMP XDP_DROP → 驱动释放 DMA buffer → 完成

// 加载:
ip link set dev eth0 xdp obj xdp_drop.o sec xdp
bpftool net attach xdpdrv id <prog_id> dev eth0
```

### kprobe / kretprobe

```c
// 动态探测任意内核函数 (非稳定 API!)
// kprobe: 函数入口 → R0..R5 = 函数参数
// kretprobe: 函数返回 → R0 = 返回值

// 限制:
//   - 函数签名版本间可能变化 → CO-RE 不完全覆盖 (需 BTF)
//   - 内核可以内联函数 → kprobe 挂不上去
//   - 黑名单: 某些函数不能探测 (lock, NMI, ...)
//     → /sys/kernel/debug/kprobes/blacklist

// 用户态探测 (uprobe):
//   挂用户态函数的入口/返回
//   → 适合调试, 不适合生产 (开销大)
```

### Tracepoint

```c
// 内核预定义的稳定探测点 → 不依赖函数签名
// /sys/kernel/debug/tracing/events/ 目录结构
// 每个 tracepoint 有特定的 context struct (通过 BTF 可知)

// 例: sched_switch
//   context: prev_pid, prev_comm, next_pid, next_comm, ...

// 优势:
//   - 稳定 API (比 kprobe 可靠)
//   - BTF 完整覆盖
//   - 开销比 kprobe 低 (少一次函数调用)

// 劣势:
//   - 只有内核预定义的点 → 灵活度不如 kprobe
```

### CGROUP_SKB (容器网络策略)

```
挂载点: cgroup v2 的 egress/ingress
  → 此 cgroup 下所有任务的 socket 流量都经过
  → 容器出口: 挂载点在 cgroup net_cls 上

Cilium 的核心: 用 CGROUP_SKB 实现:
  - 容器间 L3/L4 策略 (无隧道, 无 iptables)
  - 基于 identity 而不是 IP
  - 比 iptables 快 10x (hash lookup vs linear chain)
```

### LSM BPF (5.7+)

```c
// security/ + BPF
// BPF 程序实现 LSM hook → 不修改内核代码就能定制安全策略

// bpf(BPF_PROG_LOAD, BPF_PROG_TYPE_LSM, ...)
// → attach to LSM hook: bpf(BPF_RAW_TRACEPOINT_OPEN, lsm/file_open)

// 适用:
//   - 自定义审计策略
//   - Android: 设备级别的安全策略
//   - 容器安全 (比 seccomp 更灵活)
```

---

## Helper 可用性矩阵

```c
// 不是所有 helper 对所有程序类型都可用
// 规则由内核编译时决定: include/uapi/linux/bpf.h

// 例: bpf_skb_load_bytes() 只对 SKB 类型可用
//     bpf_xdp_adjust_head() 只对 XDP 可用
//     bpf_get_current_pid_tgid() 对所有 tracing 类型可用

// 工具: bpftool feature probe 检查当前内核支持哪些
```

---

## 参考

- **源码**: `include/uapi/linux/bpf.h` (所有类型定义), `kernel/bpf/syscall.c` (加载路径), `net/core/filter.c` (网络相关 helpers)
- **内核文档**: `Documentation/bpf/libbpf/`
- **Cilium BPF 文档**: docs.cilium.io (最好的 BPF 网络实践文档)

---

*关键词: BPF_PROG_TYPE, XDP, kprobe, tracepoint, CGROUP_SKB, LSM BPF, helper 白名单*
