eunomia-bpf 项目教程:eBPF 开发入门之 Hello World
2025-07-10 02:02:15作者:江焘钦
前言
eBPF(Extended Berkeley Packet Filter)是 Linux 内核中一项革命性的技术,它允许开发者在不修改内核源代码的情况下,动态地向内核注入自定义代码。这种能力为系统观测、性能分析、安全防护等领域带来了前所未有的可能性。本文将基于 eunomia-bpf 项目,带领读者从零开始编写并运行第一个 eBPF 程序。
eBPF 开发环境准备
在开始 eBPF 开发前,我们需要配置合适的开发环境:
- 内核要求:建议使用 Linux 5.15 或 6.2 以上版本的内核,最低要求为 4.8 版本
- 工具链安装:
- LLVM 和 Clang:用于编译 eBPF 程序
- 在 Ubuntu/Debian 上可通过以下命令安装:
sudo apt install clang llvm
eunomia-bpf 工具安装
eunomia-bpf 是一个开源的 eBPF 动态加载运行时和开发工具链,它简化了 eBPF 程序的开发、构建和运行流程。我们需要安装两个核心工具:
-
ecli:用于运行 eBPF 程序
wget https://aka.pw/bpf-ecli -O ecli && chmod +x ./ecli
-
ecc:eBPF 编译器工具链
wget https://github.com/eunomia-bpf/eunomia-bpf/releases/latest/download/ecc && chmod +x ./ecc
第一个 eBPF 程序:Hello World
下面是一个最简单的 eBPF 程序示例,它会在每次系统调用 write
时打印一条日志:
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
#define BPF_NO_GLOBAL_DATA
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
typedef unsigned int u32;
typedef int pid_t;
const pid_t pid_filter = 0;
char LICENSE[] SEC("license") = "Dual BSD/GPL";
SEC("tp/syscalls/sys_enter_write")
int handle_tp(void *ctx)
{
pid_t pid = bpf_get_current_pid_tgid() >> 32;
if (pid_filter && pid != pid_filter)
return 0;
bpf_printk("BPF triggered sys_enter_write from PID %d.\n", pid);
return 0;
}
代码解析
- 头文件:包含了必要的 eBPF 开发头文件
- 许可证声明:eBPF 程序必须声明许可证
- SEC 宏:定义了程序挂载点(这里是
sys_enter_write
系统调用入口) - 核心函数:
bpf_get_current_pid_tgid()
:获取当前进程 IDbpf_printk()
:内核打印函数(有参数限制)
编译与运行
-
编译 eBPF 程序:
./ecc minimal.bpf.c
或使用 Docker:
docker run -it -v `pwd`/:/src/ ghcr.io/eunomia-bpf/ecc-`uname -m`:latest
-
运行程序:
sudo ./ecli run package.json
-
查看输出:
sudo cat /sys/kernel/debug/tracing/trace_pipe | grep "BPF triggered"
eBPF 程序基本框架
一个完整的 eBPF 程序通常包含以下要素:
- 头文件:
linux/bpf.h
和bpf/bpf_helpers.h
等 - 许可证声明:通常是 "Dual BSD/GPL"
- BPF 函数:
- 使用
SEC()
宏定义挂载点 - 返回值通常为整型
- 使用
- 辅助函数:如
bpf_printk()
等
跟踪点(Tracepoint)简介
Tracepoint 是内核中的静态插桩技术:
- 在内核源代码中预置的探测点
- 稳定的 API 接口
- 常见于系统调用、调度器事件等关键路径
- 本例中使用的
sys_enter_write
就是一个典型的 tracepoint
项目模板推荐
为了简化 eBPF 项目初始化,eunomia-bpf 提供了多种语言的项目模板:
- C + libbpf:传统开发方式
- Go + cilium/ebpf:Go 语言开发
- Rust + libbpf-rs:Rust 语言开发
- C + eunomia-bpf:简化开发流程
这些模板都包含:
- 一键构建的 Makefile
- Docker 支持
- GitHub Actions 集成
- 完整的依赖配置
总结
通过本文,我们学习了:
- eBPF 开发环境的搭建
- 使用 eunomia-bpf 工具链开发简单程序
- eBPF 程序的基本结构和原理
- 如何编译和运行 eBPF 程序
eBPF 技术的强大之处在于它能够在运行时动态修改内核行为,而不需要重新编译或加载内核模块。随着对 eBPF 的深入学习,开发者可以实现更复杂的功能,如系统观测、性能分析等。
建议读者在掌握这个简单示例后,继续探索 eBPF 的更多高级特性,如 perf buffer、map 数据结构等,以充分发挥这项技术的潜力。