BPF-eBPF 实战入门:环境准备、最小实验与排错思路
行动是治愈恐惧的良药,而犹豫、拖延将不断滋养恐惧。——戴尔·卡耐基
写在前面
- 这一篇不再停留在概念层,而是开始解决
怎么把第一个 eBPF 实验真正跑起来 - 内容会贴近
ebpf.io、docs.ebpf.io、libbpf-bootstrap、ebpf-go的官方学习路径 - 目标不是一次把所有细节学完,而是先建立
环境检查 -> 最小实验 -> 定位报错这一套基本节奏
行动是治愈恐惧的良药,而犹豫、拖延将不断滋养恐惧。——戴尔·卡耐基
系列导航
BPF-eBPF 学习总览:从概念、机制到工具链选择BPF-eBPF 实战入门:环境准备、最小实验与排错思路BPF-eBPF 开发路线一:BCC 入门、工具使用与自定义脚本BPF-eBPF 开发路线二:libbpf、CO-RE 与 libbpf-bootstrap 实战BPF-eBPF 开发路线三:ebpf-go、bpf2go 与 Go 工程集成
做实验前先确认 4 件事
根据 docs.ebpf.io 和主流项目的实践,开始动手前建议先检查这 4 件事:
内核版本是否足够新- 系统里是否有
clang/llvm - 是否有
bpftool - 是否存在
BTF信息,或者至少知道当前系统如何提供vmlinux.h
先看内核和发行版:
1 | uname -r |
再检查工具链:
1 | clang --version |
检查 BTF:
1 | ls -l /sys/kernel/btf/vmlinux |
如果 /sys/kernel/btf/vmlinux 存在,后续做 CO-RE 会顺很多。
为什么现在大家强调 BTF 和 CO-RE
docs.ebpf.io、libbpf 文档和 ebpf-go 文档都会反复提到这两个词:
BTF:BPF Type Format,给内核类型信息做结构化描述CO-RE:Compile Once, Run Everywhere,让同一个 eBPF 对象在不同内核版本上更容易复用
这背后的现实问题是:
- 内核结构体会变
- 不同发行版内核布局会变
- 你本机能跑,不代表别的机器也能跑
所以现在更主流的路线已经不是“对着当前机器硬编码偏移量”,而是:
- 尽量依赖
BTF - 优先用
CO-RE - 用
bpftool生成vmlinux.h
常见命令:
1 | bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h |
建议准备的环境
Fedora / RHEL 系
常见会准备这些包:
1 | sudo dnf install -y clang llvm bpftool libbpf libbpf-devel gcc make |
如果要学 BCC,还需要准备 bcc 相关包;不同发行版包名可能不同,要以仓库实际名称为准。
Ubuntu / Debian 系
常见会准备这些包:
1 | sudo apt-get update |
如果要跑 BCC 工具,再按系统仓库补齐 bcc 或 Python 绑定相关包。
第一个最小实验应该怎么选
初学者不要从 XDP 或复杂网络程序开始,最稳妥的是:
tracepointkprobeuprobe
原因很简单:
tracepoint相对稳定,适合入门kprobe更灵活,但更贴近内核实现细节uprobe能帮你理解用户态程序也能被 eBPF 跟踪
最小实验一:先观察,不先写代码
如果你的机器已经有 BCC 工具,先用现成工具建立直觉。
例如观察进程执行:
1 | sudo execsnoop |
观察打开文件:
1 | sudo opensnoop |
统计函数调用次数:
1 | sudo funccount 'vfs_*' |
为什么先跑现成工具?
- 先知道“观测什么”比先知道“怎么写语法”更重要
- 你能快速建立
事件 -> 挂点 -> 输出的直觉 - 遇到自己写不出来的时候,有现成工具可以反查思路
最小实验二:用 tracepoint 做第一个闭环
如果你开始写自己的最小程序,建议先做 tracepoint/syscalls/sys_enter_execve 一类事件。
你真正要完成的是这三步:
- 把 eBPF 程序编译成
.o - 挂到
tracepoint - 把事件送到用户态并打印
无论你最终用 libbpf 还是 ebpf-go,本质都是这个闭环。
最小实验三:用 libbpf-bootstrap 跑官方示例
libbpf-bootstrap 是非常适合初学者的官方参考项目。它把很多琐碎的工程细节都先整理好了。
常见步骤如下:
1 | git clone https://github.com/libbpf/libbpf-bootstrap.git |
优先建议先跑:
minimalbootstrapkprobeuprobe
为什么先看这几个:
minimal最接近“最小可运行对象”bootstrap展示了用户态到内核态的完整工程骨架kprobe/uprobe正好覆盖最常见的观测场景
最小实验四:用 ebpf-go 跑 Go 路线示例
如果你的主力语言是 Go,建议尽快把 ebpf-go 的基本链路跑通:
- 编写
.c内核态程序 - 用
bpf2go生成 Go 绑定 - 在 Go 代码里加载对象、attach、读事件
典型命令会长这样:
1 | go install github.com/cilium/ebpf/cmd/bpf2go@latest |
这里的重点不是把命令背下来,而是理解:
.o文件不是最终交付物bpf2go负责把对象和类型绑定进 Go 工程- Go 代码里控制的是对象加载、链接、事件读取和生命周期
遇到 verifier 报错时怎么排
很多初学者真正的第一堵墙不是编译,而是 verifier。
遇到这类问题时,建议按下面的顺序查:
- 是否越界访问了内核数据
- 是否有空指针或未初始化变量
- 是否循环和分支过于复杂
- 是否对上下文结构理解错了
- 当前 hook 允许使用的 helper 是否正确
常用辅助方式:
1 | sudo bpftool prog show |
如果你的加载器支持输出 verifier log,一定要打开。很多时候问题不在“程序思想错了”,而在“这段写法 verifier 不接受”。
最容易忽略的权限与挂载问题
跑 eBPF 程序时,常见还有这几类问题:
- 权限不够,尤其是没有
CAP_BPF、CAP_SYS_ADMIN或调试环境不足 bpffs没挂载,导致 pinning 或对象管理异常- 内核关闭了某些能力,或者发行版默认策略更严格
可以先检查:
1 | mount | grep bpf |
如果需要手工挂载:
1 | sudo mount -t bpf bpf /sys/fs/bpf |
一个适合新手的最小练习顺序
建议你按这个顺序做:
- 跑一个
BCC现成工具 - 跑
libbpf-bootstrap/minimal - 跑
libbpf-bootstrap/bootstrap - 自己改一个字段输出
- 再切到
ebpf-go跑一遍相同思路
这样你会明显感受到三条路线的差别:
BCC更像“先用起来”libbpf更像“真正学底层机制”ebpf-go更像“把底层能力接进工程”
我建议的排错节奏
当程序跑不通时,不要一下子改一堆代码,建议固定按这条链路查:
- 编译是否成功
- 对象是否加载成功
- 程序是否 attach 成功
- map/ringbuf 是否创建成功
- 用户态是否真的在读事件
- 当前系统是否真的发生了触发事件
这套方法比盲目搜报错关键词更稳。
最后总结
eBPF 实战入门的关键,不是今天把多少 API 背下来,而是先形成一个稳定的动手习惯:
- 先检查环境
- 再跑最小实验
- 优先选稳定 hook
- 出错先看 verifier 和 attach
- 尽早理解
BTF与CO-RE
把这套节奏养成之后,你再去看 BCC、libbpf、ebpf-go 各自的细节,学习效率会高很多。
博文部分内容参考
© 文中涉及参考链接内容版权归原作者所有,如有侵权请告知 :)
© 2018-至今 liruilonger@gmail.com, 保持署名-非商用-相同方式共享(CC BY-NC-SA 4.0)
BPF-eBPF 实战入门:环境准备、最小实验与排错思路
https://liruilongs.github.io/2026/04/14/rhca/RH442_BPF/BPF/eBPF学习路线/BPF-eBPF 实战入门:环境准备、最小实验与排错思路/
1.BPF-eBPF 开发路线三:ebpf-go、bpf2go 与 Go 工程集成
2.BPF-eBPF 开发路线二:libbpf、CO-RE 与 libbpf-bootstrap 实战
3.BPF-eBPF 开发路线一:BCC 入门、工具使用与自定义脚本
4.BPF-eBPF 学习总览:从概念、机制到工具链选择
5.Linux性能调优之使用BPF工具观测CPU性能指标
6.认识 Linux 内存构成:Linux 内存调优之内存分配机制和换页行为认知
7.BPF:BCC工具 funccount 统计内核函数调用(内核函数、跟踪点USDT探针)认知
8.BPF:BCC(BPF Compiler Collection)工具集认知

