libbpf failed to load 的根本原因是内核版本、配置、bpftrace 版本或内核头文件不匹配,而非权限问题;需检查 CONFIG_BPF_SYSCALL=y、CONFIG_BPF_JIT=y 等内核选项,并用 bpftrace -v 查看具体 libbpf 错误码。

libbpf failed to load 是内核模块加载失败,不是权限问题本身
这个错误看起来像权限不足,但实际多数情况是 bpftrace 尝试用 libbpf 加载 BPF 程序时,内核拒绝了——原因可能是内核版本太旧、缺少必要配置、或 eBPF 字节码不兼容。运行 bpftrace -v 可看到具体 libbpf 错误码(如 LIBBPF_ERRNO__KVERSION 或 LIBBPF_ERRNO__BAD_INSN),比单纯看 “failed to load” 有用得多。
检查内核是否启用 CONFIG_BPF_SYSCALL 和 CONFIG_BPF_JIT
libbpf 加载失败最常见原因是内核没开关键配置。在目标机器上执行:
zcat /proc/config.gz | grep -E 'CONFIG_BPF_(SYSCALL|JIT)'
或检查 /boot/config-$(uname -r)。必须同时满足:
-
CONFIG_BPF_SYSCALL=y(必需) -
CONFIG_BPF_JIT=y(非必需但强烈建议,否则部分程序因指令数超限被拒) -
CONFIG_BPF_EVENTS=y(若用 tracepoint/kprobe)
Ubuntu/Debian 默认内核通常已启用;CentOS/RHEL 8+ 也基本满足,但 RHEL 7 内核(3.10)原生不支持现代 libbpf 加载流程,会直接报错。
bpftrace 版本和内核头文件必须匹配
bpftrace 编译时依赖内核头(linux/bpf.h 等),运行时又依赖内核实际 ABI。常见坑:
- 用 Ubuntu 22.04 的包装的
bpftrace(对应 kernel 5.15)跑在 6.1 内核上 → 可能因新 helper 函数缺失或结构体变更失败 - 手动编译 bpftrace 但未指定
-DCMAKE_KERNEL_INCLUDES=/lib/modules/$(uname -r)/build/include→ 头文件版本错配,生成的 BPF 字节码含未知指令 - 容器中运行 bpftrace,宿主机内核是 6.5,但容器内
/usr/src/linux-headers-*是 5.4 → 编译期头文件和运行时内核不一致
验证方式:运行 bpftrace -e 'kprobe:do_sys_open { printf("ok\n"); }'。如果失败,加 -v 看 libbpf 日志里是否出现 cannot find symbol 或 invalid insn。
绕过 libbpf 加载(仅调试用):改用 -I 模式或降级 bpftrace
某些场景下,你只是想快速验证逻辑,不强求用最新 libbpf 流程:
- 加
-I参数强制走旧的bpf_prog_load()系统调用路径(绕过 libbpf 的校验和重写):bpftrace -I -e 'tracepoint:syscalls:sys_enter_openat { printf("hit\n"); }' - 换用
bpftrace 0.12.0(libbpf 集成前的最后稳定版),它不依赖 libbpf 加载器,对老内核更宽容 - 确认是否真需要 bpftrace:简单需求可用
bpftool prog load+ 手写 C 加载,排除 bpftrace 自身解析层干扰
注意:-I 模式在 6.0+ 内核可能被彻底禁用(取决于 /proc/sys/net/core/bpf_jit_harden 和内核编译选项),不是长期解法。
真正卡住的地方往往不是“没权限”,而是内核版本、bpftrace 版本、头文件、加载路径四者之间有一处没对齐。盯住 libbpf 日志里的具体 errno,比反复加 sudo 有效得多。










