012.实战:将eBPF程序load进Linux内核

简短结论先给你:

bpftool prog load u_ebpf/mem.bpf.o /sys/fs/bpf/test** 的核心意义是:
**把 eBPF 程序真正交给内核做一次“权威体检”。

✔️ 能不能被 verifier 接受
✔️ BTF / 指令 / helper 是否合法
❌ 但不代表程序“逻辑一定正确”或“已经在运行”

下面我分层把这件事讲清楚。


一、这条命令到底做了什么?(逐步拆解)

sudo bpftool prog load u_ebpf/mem.bpf.o /sys/fs/bpf/test

1️⃣ bpftool prog load

  • 调用的是 bpf(BPF_PROG_LOAD, …)
  • .bpf.o 里的 eBPF 指令送进内核
  • 触发 verifier 全流程校验

👉 这是 eBPF 的“上内核考试”


2️⃣ u_ebpf/mem.bpf.o

  • clang 编译出来的 eBPF ELF
  • 包含:
    • 指令
    • maps
    • BTF(如果有)
    • license

3️⃣ /sys/fs/bpf/test

  • pin 位置
  • 表示:

“如果 load 成功,请把这个 eBPF 程序固定在 bpffs 里”

👉 程序 不会自动 attach,但已经存在于内核对象系统中。


二、所以:它是不是在“判断 eBPF 有没有问题”?

✅ 是,但只判断 这一类问题

能检查什么 说明
verifier 是否通过 指令安全、控制流、栈
helper 是否可用 GPL / 非 GPL
BTF 是否匹配 CO-RE / fentry
map 定义是否合法 key/value/size
指令是否合法 边界、指针

👉 这是“内核级正确性”


❌ 它不检查这些问题

检查不到 原因
attach 点是否正确 还没 attach
程序是否真的执行 没有 hook
逻辑是否符合预期 verifier 不管语义
uprobe 路径是否存在 属于 attach 阶段
打印是否有输出 程序未运行

三、一个非常关键的误区(一定要澄清)

load 成功 ≠ 程序在跑

此时状态是:

eBPF 程序
  ✔ 已通过 verifier
  ✔ 已驻留内核
  ✖ 没有挂到任何事件

四、那为什么很多人(包括你)会用这一步?

因为它是最干净的“分界线”

用它可以把问题一刀切开:

如果 load 失败

👉 100% 是 eBPF 程序本身的问题

  • 指令
  • helper
  • BTF
  • license
  • map

如果 load 成功,但 attach 失败

👉 问题在:

  • hook 点
  • 函数名
  • 路径
  • pid
  • 内核支持情况

这是非常重要的调试策略


五、你现在这个命令在工程中的“正确定位”

我给你一个推荐的标准调试流程(你已经走在这条路上了):

clang 编译
   ↓
bpftool prog load        ←【你现在这一步】
   ↓
bpftool prog attach / libbpf attach
   ↓
触发事件
   ↓
bpftool prog tracelog / ringbuf

👉 prog load** 是 verifier 关卡**


六、进一步:怎么把它当成“自动体检”用?

1️⃣ 打开 verifier log(非常建议)

sudo bpftool prog load u_ebpf/mem.bpf.o /sys/fs/bpf/test \
  verbose

或:

sudo bpftool prog load u_ebpf/mem.bpf.o /sys/fs/bpf/test \
  log_level=2

你会看到:

  • 指令逐条分析
  • verifier 判断理由

👉 这是写 eBPF 最值钱的调试信息


七、和 libbpf / skeleton 的关系(帮你对齐认知)

方式 是否走 verifier 是否 attach
bpftool prog load
libbpf load()
bpf_program__attach_* 已 load

👉 本质完全一致,只是入口不同


八、一句“工程级总结”(你可以直接放课里)

bpftool prog load** 的意义不是“程序跑没跑”,
****而是确认:
**“这个 eBPF 程序,内核愿不愿意接受它。”

posted @ 2026-06-02 00:20  BlackSnow  阅读(22)  评论(0)    收藏  举报