3. 开发环境搭建:Linux内核版本要求、编译工具链安装、libbpf库安装、bpftool工具安装、第一个Hello World程序
搭建一个稳定、可复现的开发环境是学习 eBPF 的第一步。本章将引导你完成从内核版本选择到工具链安装,再到运行第一个 eBPF 程序的完整流程。请严格按照以下步骤操作,避免因环境差异导致的编译或运行时错误。
3.1 Linux 内核版本要求
eBPF 功能随内核版本演进不断扩展。不同版本的 eBPF 特性对内核有最低版本要求。下表列出了关键特性与推荐的内核版本:
| eBPF 特性 | 最低内核版本 | 推荐内核版本 | 说明 |
|---|---|---|---|
| 基础 eBPF (cgroup/socket) | 4.4 | 5.4+ | 支持基本的 BPF 程序类型和 map |
| BPF 跟踪 (kprobe/uprobe) | 4.15 | 5.10+ | 支持动态内核/用户态探针 |
| BPF CO-RE (Compile Once – Run Everywhere) | 5.2 | 5.15+ | 支持 BTF 和 libbpf 的 CO-RE 功能 |
| BPF 调度器 (sched_ext) | 6.6 | 6.8+ | 可编程内核调度器扩展 |
推荐选择: 对于本课程的学习,建议使用 Linux 5.15 LTS 或更高版本的内核。该版本对 CO-RE 支持成熟,且兼容大多数主流发行版。如果你使用的是 Ubuntu 20.04+ 或 CentOS 8+,通常可以满足要求。
3.2 编译工具链安装
编译 eBPF 程序需要完整的 C 编译工具链和内核头文件。以下是主流发行版的安装命令:
Ubuntu / Debian
sudo apt update
sudo apt install -y build-essential git clang llvm libelf-dev linux-headers-$(uname -r)
CentOS / RHEL / Fedora
sudo dnf groupinstall -y "Development Tools"
sudo dnf install -y clang llvm elfutils-libelf-devel kernel-devel
关键组件说明:
- clang / LLVM: eBPF 程序必须使用 clang 编译,因为 gcc 对 BPF 后端的支持不完整。建议版本 >= 11。
- libelf-dev / elfutils-libelf-devel: 用于处理 ELF 文件,libbpf 依赖此库。
- linux-headers / kernel-devel: 提供内核头文件,用于编译与内核交互的 BPF 程序。
3.3 libbpf 库安装
libbpf 是 eBPF 程序开发的核心用户态库,负责加载、验证和附加 BPF 程序。推荐从源码编译安装最新稳定版:
# 克隆 libbpf 仓库
git clone https://github.com/libbpf/libbpf.git
cd libbpf/src
# 编译并安装到系统目录
make
sudo make install
# 更新动态链接库缓存
sudo ldconfig
安装完成后,头文件位于 /usr/include/bpf/,库文件位于 /usr/lib64/ 或 /usr/lib/x86_64-linux-gnu/。
注意: 某些发行版(如 Ubuntu)的包管理器提供的 libbpf 版本可能较旧,不支持 CO-RE 特性。强烈建议从 GitHub 源码编译,以确保获得最新功能和修复。
3.4 bpftool 工具安装
bpftool 是 eBPF 开发和调试的瑞士军刀,用于查看 BPF 程序、map、以及内核 BTF 信息。安装方式如下:
# 方法一:从内核源码编译(推荐)
git clone --depth 1 https://github.com/torvalds/linux.git
cd linux/tools/bpf/bpftool
make
sudo make install
# 方法二:使用发行版包管理器(版本可能较旧)
# Ubuntu
sudo apt install -y linux-tools-common linux-tools-$(uname -r)
# CentOS
sudo dnf install -y bpftool
验证安装:
bpftool --version
bpftool feature list
如果 bpftool feature list 输出显示 BTF 和 CO-RE 支持为 yes,则环境准备就绪。
3.5 第一个 Hello World 程序
下面我们编写一个经典的 eBPF Hello World 程序。它会在每次系统调用 execve 执行时打印一条消息。
步骤 1:编写 BPF 内核态程序 (hello.bpf.c)
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
char LICENSE[] SEC("license") = "GPL";
SEC("kprobe/sys_execve")
int hello_world(struct pt_regs *ctx)
{
bpf_printk("Hello, eBPF World!\n");
return 0;
}
步骤 2:编写用户态加载程序 (hello.c)
#include <stdio.h>
#include <unistd.h>
#include <bpf/libbpf.h>
#include "hello.skel.h"
int main()
{
struct hello_bpf *skel;
// 打开并加载 BPF 骨架
skel = hello_bpf__open_and_load();
if (!skel) {
fprintf(stderr, "Failed to open and load BPF skeleton\n");
return 1;
}
// 附加 BPF 程序到 kprobe
if (hello_bpf__attach(skel)) {
fprintf(stderr, "Failed to attach BPF skeleton\n");
goto cleanup;
}
printf("eBPF program loaded and attached! Check /sys/kernel/debug/tracing/trace_pipe\n");
printf("Press Ctrl+C to exit...\n");
// 等待用户中断
while (1) {
sleep(1);
}
cleanup:
hello_bpf__destroy(skel);
return 0;
}
步骤 3:编译与运行
# 生成 BPF 骨架头文件
clang -O2 -target bpf -c hello.bpf.c -o hello.bpf.o
bpftool gen skeleton hello.bpf.o > hello.skel.h
# 编译用户态程序
gcc -O2 -o hello hello.c -lbpf -lelf -lz
# 运行(需要 root 权限)
sudo ./hello
在另一个终端查看输出:
sudo cat /sys/kernel/debug/tracing/trace_pipe
# 每次执行新程序时,会看到类似输出:
# bash-12345 [000] .... 123456.789012: 0: Hello, eBPF World!
调试提示: 如果
trace_pipe 没有输出,请检查:1) 内核是否开启了 CONFIG_BPF 和 CONFIG_BPF_KPROBE_OVERRIDE;2) 是否以 root 权限运行;3) 使用 bpftool prog list 确认程序已加载。
3.6 开发环境架构总览
下图展示了 eBPF 开发环境的完整软件栈与数据流:
3.7 常见问题与排查
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
clang: error: unknown target CPU 'bpf' |
clang 版本过低,不支持 BPF 后端 | 升级 clang 到 11+ 或从源码编译 LLVM |
fatal error: 'bpf/bpf_helpers.h' file not found |
libbpf 头文件未安装或路径错误 | 确认 make install 成功,检查 /usr/include/bpf/ 目录 |
libbpf: failed to find valid kernel BTF |
内核未开启 BTF 支持 | 重新编译内核,开启 CONFIG_DEBUG_INFO_BTF=y |
Operation not permitted |
缺少 root 权限或内核安全策略限制 | 使用 sudo 运行,或检查 SELinux/AppArmor 配置 |
环境验证清单:
- ✅ 内核版本 >= 5.15(推荐)
- ✅ clang 版本 >= 11
- ✅ libbpf 已从源码编译安装
- ✅ bpftool 可用且支持 BTF
- ✅ 内核开启了
CONFIG_BPF、CONFIG_BPF_KPROBE_OVERRIDE、CONFIG_DEBUG_INFO_BTF