005.BPF的头文件
在目录/usr/include/bpf
$ ls /usr/include/bpf -l
总计 424
-rw-r--r-- 1 root root 22416 11月 26 2024 bpf_core_read.h
-rw-r--r-- 1 root root 3750 11月 26 2024 bpf_endian.h
-rw-r--r-- 1 root root 25468 11月 26 2024 bpf.h
-rw-r--r-- 1 root root 175686 11月 26 2024 bpf_helper_defs.h
-rw-r--r-- 1 root root 15932 11月 26 2024 bpf_helpers.h
-rw-r--r-- 1 root root 38530 11月 26 2024 bpf_tracing.h
-rw-r--r-- 1 root root 20659 11月 26 2024 btf.h
-rw-r--r-- 1 root root 3437 11月 26 2024 libbpf_common.h
-rw-r--r-- 1 root root 75022 11月 26 2024 libbpf.h
-rw-r--r-- 1 root root 5191 11月 26 2024 libbpf_legacy.h
-rw-r--r-- 1 root root 242 11月 26 2024 libbpf_version.h
-rw-r--r-- 1 root root 9393 11月 26 2024 skel_internal.h
-rw-r--r-- 1 root root 8514 11月 26 2024 usdt.bpf.h
很好,这一组 .h 正好就是 libbpf / eBPF 世界的“标准库全家桶”。
下面我逐个解释每个头文件的真实用途、谁在用、什么时候该 include、什么时候不该碰
一、整体先给你一张「功能分层图」
┌────────────────────────────┐
│ eBPF 程序 (mem.bpf.c) │
│ - bpf_helpers.h │ ← 必需
│ - bpf_tracing.h │ ← kprobe/uprobe
│ - bpf_core_read.h │ ← CO-RE
└──────────────┬─────────────┘
│
┌──────────────▼─────────────┐
│ libbpf 用户态 │
│ - libbpf.h │
│ - libbpf_common.h │
│ - skel_internal.h │
└──────────────┬─────────────┘
│
┌──────────────▼─────────────┐
│ BTF / ABI / 内核接口 │
│ - bpf.h │
│ - btf.h │
│ - bpf_helper_defs.h │
│ - bpf_endian.h │
└────────────────────────────┘
二、逐个 .h 文件详解(工程级)
1️⃣ bpf_helpers.h ⭐⭐⭐(必选)
作用
- 定义 所有 eBPF helper 的调用接口
- 提供
SEC()、__always_inline等核心宏
你写 eBPF 程序 99% 必须 include 的头
#include <bpf/bpf_helpers.h>
里面有什么
bpf_map_lookup_elembpf_printkbpf_get_current_pid_tgidSEC("...")
✅ 任何 mem.bpf.c / sched.bpf.c 都必须有
2️⃣ bpf_tracing.h ⭐⭐⭐(kprobe / uprobe 必需)
作用
- 提供 BPF_KPROBE / BPF_KRETPROBE / BPF_PROG 等参数解析宏
- 解决 寄存器 → C 函数参数 的映射问题
#include <bpf/bpf_tracing.h>
SEC("uprobe/malloc")
int BPF_KPROBE(uprobe_malloc, size_t size) { ... }
❗ 没有它:
- 你得自己从
pt_regs里扒参数(非常痛苦)
✅ 只要你做 kprobe / uprobe / fentry,基本都要
3️⃣ bpf_core_read.h ⭐⭐⭐(CO-RE 专用)
作用
- 提供
BPF_CORE_READ()等 跨内核结构读取宏 - 解决 内核版本不一致 的问题
#include <bpf/bpf_core_read.h>
典型用途
struct task_struct *task = (struct task_struct *)bpf_get_current_task();
pid = BPF_CORE_READ(task, pid);
⚠️ 注意
- uprobe 用户态程序一般不需要
- 只有读 内核结构体 才用
👉 这是你课程里必须强调的一句:
CO-RE 不是 eBPF 必需品,而是“内核结构访问的兼容层”。
4️⃣ bpf.h
作用
- 定义 BPF syscall、cmd、map/prog 类型
- 属于 内核 ABI 层
主要被谁用
- libbpf
- bpftool
- loader
❌ 普通 eBPF 程序基本不用 include
5️⃣ bpf_helper_defs.h
作用
- helper 函数 ID → 函数原型映射表
- verifier / libbpf 内部使用
一句话
这是 eBPF helper 的“身份证字典”
❌ 你不应该手动 include
bpf_helpers.h已经帮你封装好了
6️⃣ bpf_endian.h
作用
- 提供 字节序转换宏
- 解决 eBPF 程序中 大小端问题
__be32 net_ip;
__u32 host_ip = bpf_ntohl(net_ip);
常见场景
- XDP
- tc
- 网络协议解析
❌ 纯 malloc / sched 追踪几乎不用
7️⃣ btf.h
作用
- 定义 BTF(BPF Type Format)结构
- 用于解析 / 构建 BTF
谁在用
- bpftool
- libbpf
- verifier
❌ 业务 eBPF 程序不直接用
8️⃣ libbpf.h ⭐⭐⭐(用户态必选)
作用
- libbpf 用户态 API 总入口
- load / attach / map / link 全在这里
#include <bpf/libbpf.h>
你熟的
bpf_object__openbpf_program__attach_uprobe_opts- skeleton API
✅ loader.c 必须 include
9️⃣ libbpf_common.h
作用
- libbpf 内部公共定义
- enum / util / attribute
❌ 一般不直接 include
🔟 libbpf_legacy.h
作用
- 兼容 老内核 / 老 API
- 逐步被淘汰
⚠️ 新项目不建议用
1️⃣1️⃣ libbpf_version.h
作用
- libbpf 版本宏
LIBBPF_MAJOR_VERSION
LIBBPF_MINOR_VERSION
用途
- 条件编译
- 兼容判断
1️⃣2️⃣ skel_internal.h
作用
- skeleton 生成代码内部使用
- map / prog 描述结构
❌ 你永远不该手写 include
xxx.skel.h会自动处理
1️⃣3️⃣ usdt.bpf.h
作用
- 支持 USDT(User Statically Defined Tracepoint)
- 用户态应用自定义探针
SEC("usdt")
int handle_usdt(...) { ... }
典型用途
- JVM
- PostgreSQL
- 高级性能分析
👉 这是 uprobe 的高级形态
三、给你一张「该不该 include」速查表(非常适合课程)
| 头文件 | eBPF 程序 | loader | 是否常用 |
|---|---|---|---|
| bpf_helpers.h | ✅ | ❌ | ⭐⭐⭐ |
| bpf_tracing.h | ✅ | ❌ | ⭐⭐⭐ |
| bpf_core_read.h | ⚠️ | ❌ | ⭐⭐ |
| bpf_endian.h | ⚠️ | ❌ | ⭐ |
| libbpf.h | ❌ | ✅ | ⭐⭐⭐ |
| skel_internal.h | ❌ | ❌ | ❌ |
| usdt.bpf.h | ⚠️ | ❌ | ⭐ |

浙公网安备 33010602011771号