BPF-eBPF 实战入门:环境准备、最小实验与排错思路

行动是治愈恐惧的良药,而犹豫、拖延将不断滋养恐惧。——戴尔·卡耐基

写在前面


  • 这一篇不再停留在概念层,而是开始解决怎么把第一个 eBPF 实验真正跑起来
  • 内容会贴近 ebpf.iodocs.ebpf.iolibbpf-bootstrapebpf-go 的官方学习路径
  • 目标不是一次把所有细节学完,而是先建立环境检查 -> 最小实验 -> 定位报错这一套基本节奏

行动是治愈恐惧的良药,而犹豫、拖延将不断滋养恐惧。——戴尔·卡耐基


系列导航

  1. BPF-eBPF 学习总览:从概念、机制到工具链选择
  2. BPF-eBPF 实战入门:环境准备、最小实验与排错思路
  3. BPF-eBPF 开发路线一:BCC 入门、工具使用与自定义脚本
  4. BPF-eBPF 开发路线二:libbpf、CO-RE 与 libbpf-bootstrap 实战
  5. BPF-eBPF 开发路线三:ebpf-go、bpf2go 与 Go 工程集成

做实验前先确认 4 件事

根据 docs.ebpf.io 和主流项目的实践,开始动手前建议先检查这 4 件事:

  1. 内核版本是否足够新
  2. 系统里是否有 clang/llvm
  3. 是否有 bpftool
  4. 是否存在 BTF 信息,或者至少知道当前系统如何提供 vmlinux.h

先看内核和发行版:

1
2
uname -r
cat /etc/os-release

再检查工具链:

1
2
3
clang --version
llc --version
bpftool version

检查 BTF

1
2
ls -l /sys/kernel/btf/vmlinux
file /sys/kernel/btf/vmlinux

如果 /sys/kernel/btf/vmlinux 存在,后续做 CO-RE 会顺很多。

为什么现在大家强调 BTF 和 CO-RE

docs.ebpf.iolibbpf 文档和 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
2
sudo apt-get update
sudo apt-get install -y clang llvm bpftool libbpf-dev build-essential

如果要跑 BCC 工具,再按系统仓库补齐 bcc 或 Python 绑定相关包。

第一个最小实验应该怎么选

初学者不要从 XDP 或复杂网络程序开始,最稳妥的是:

  1. tracepoint
  2. kprobe
  3. uprobe

原因很简单:

  • tracepoint 相对稳定,适合入门
  • kprobe 更灵活,但更贴近内核实现细节
  • uprobe 能帮你理解用户态程序也能被 eBPF 跟踪

最小实验一:先观察,不先写代码

如果你的机器已经有 BCC 工具,先用现成工具建立直觉。

例如观察进程执行:

1
sudo execsnoop

观察打开文件:

1
sudo opensnoop

统计函数调用次数:

1
sudo funccount 'vfs_*'

为什么先跑现成工具?

  • 先知道“观测什么”比先知道“怎么写语法”更重要
  • 你能快速建立 事件 -> 挂点 -> 输出 的直觉
  • 遇到自己写不出来的时候,有现成工具可以反查思路

最小实验二:用 tracepoint 做第一个闭环

如果你开始写自己的最小程序,建议先做 tracepoint/syscalls/sys_enter_execve 一类事件。

你真正要完成的是这三步:

  1. 把 eBPF 程序编译成 .o
  2. 挂到 tracepoint
  3. 把事件送到用户态并打印

无论你最终用 libbpf 还是 ebpf-go,本质都是这个闭环。

最小实验三:用 libbpf-bootstrap 跑官方示例

libbpf-bootstrap 是非常适合初学者的官方参考项目。它把很多琐碎的工程细节都先整理好了。

常见步骤如下:

1
2
3
4
5
git clone https://github.com/libbpf/libbpf-bootstrap.git
cd libbpf-bootstrap
git submodule update --init --recursive
cd examples/c
make

优先建议先跑:

  • minimal
  • bootstrap
  • kprobe
  • uprobe

为什么先看这几个:

  • minimal 最接近“最小可运行对象”
  • bootstrap 展示了用户态到内核态的完整工程骨架
  • kprobe/uprobe 正好覆盖最常见的观测场景

最小实验四:用 ebpf-go 跑 Go 路线示例

如果你的主力语言是 Go,建议尽快把 ebpf-go 的基本链路跑通:

  1. 编写 .c 内核态程序
  2. bpf2go 生成 Go 绑定
  3. 在 Go 代码里加载对象、attach、读事件

典型命令会长这样:

1
2
3
go install github.com/cilium/ebpf/cmd/bpf2go@latest
go generate ./...
go run .

这里的重点不是把命令背下来,而是理解:

  • .o 文件不是最终交付物
  • bpf2go 负责把对象和类型绑定进 Go 工程
  • Go 代码里控制的是对象加载、链接、事件读取和生命周期

遇到 verifier 报错时怎么排

很多初学者真正的第一堵墙不是编译,而是 verifier

遇到这类问题时,建议按下面的顺序查:

  1. 是否越界访问了内核数据
  2. 是否有空指针或未初始化变量
  3. 是否循环和分支过于复杂
  4. 是否对上下文结构理解错了
  5. 当前 hook 允许使用的 helper 是否正确

常用辅助方式:

1
2
3
sudo bpftool prog show
sudo bpftool map show
sudo bpftool link show

如果你的加载器支持输出 verifier log,一定要打开。很多时候问题不在“程序思想错了”,而在“这段写法 verifier 不接受”。

最容易忽略的权限与挂载问题

跑 eBPF 程序时,常见还有这几类问题:

  • 权限不够,尤其是没有 CAP_BPFCAP_SYS_ADMIN 或调试环境不足
  • bpffs 没挂载,导致 pinning 或对象管理异常
  • 内核关闭了某些能力,或者发行版默认策略更严格

可以先检查:

1
mount | grep bpf

如果需要手工挂载:

1
sudo mount -t bpf bpf /sys/fs/bpf

一个适合新手的最小练习顺序

建议你按这个顺序做:

  1. 跑一个 BCC 现成工具
  2. libbpf-bootstrap/minimal
  3. libbpf-bootstrap/bootstrap
  4. 自己改一个字段输出
  5. 再切到 ebpf-go 跑一遍相同思路

这样你会明显感受到三条路线的差别:

  • BCC 更像“先用起来”
  • libbpf 更像“真正学底层机制”
  • ebpf-go 更像“把底层能力接进工程”

我建议的排错节奏

当程序跑不通时,不要一下子改一堆代码,建议固定按这条链路查:

  1. 编译是否成功
  2. 对象是否加载成功
  3. 程序是否 attach 成功
  4. map/ringbuf 是否创建成功
  5. 用户态是否真的在读事件
  6. 当前系统是否真的发生了触发事件

这套方法比盲目搜报错关键词更稳。

最后总结

eBPF 实战入门的关键,不是今天把多少 API 背下来,而是先形成一个稳定的动手习惯:

  • 先检查环境
  • 再跑最小实验
  • 优先选稳定 hook
  • 出错先看 verifier 和 attach
  • 尽早理解 BTFCO-RE

把这套节奏养成之后,你再去看 BCClibbpfebpf-go 各自的细节,学习效率会高很多。

博文部分内容参考

© 文中涉及参考链接内容版权归原作者所有,如有侵权请告知 :)



© 2018-至今 liruilonger@gmail.com, 保持署名-非商用-相同方式共享(CC BY-NC-SA 4.0)

发布于

2026-04-14

更新于

2026-04-14

许可协议

评论
加载中,最新评论有1分钟缓存...
Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×