mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
1413 字
4 分钟
eBPF 开发框架
2026-01-18

eBPF 程序的开发涉及两个部分:内核态的 eBPF 程序(C/Rust 编写,编译为字节码)和用户态的加载器(管理程序生命周期、读取 Map 数据)。不同的开发框架提供了不同的抽象层次和开发体验——从 libbpf 的底层控制到 bpftrace 的一行命令,从 C 的性能到 Rust 的安全,从 Go 的生态到 Aya 的纯 Rust。

本章对比四大 eBPF 开发框架,帮你做出正确的技术选型。

一、框架全景对比#

1.1 四大框架#

框架语言内核态用户态CO-RE复杂度
libbpfCCC
cilium/ebpfGoCGo
AyaRustRustRust
bpftraceDSLDSLC++

1.2 选择决策树#

flowchart TD START["选择 eBPF 框架"] --> Q1{"使用场景?"} Q1 -->|"快速诊断"| BPFTRACE["bpftrace<br/>一行命令"] Q1 -->|"生产级开发"| Q2{"团队语言偏好?"} Q2 -->|"C"| LIBBPF["libbpf<br/>CO-RE 基石"] Q2 -->|"Go"| GOEBPF["cilium/ebpf<br/>bpf2go"] Q2 -->|"Rust"| AYA["Aya<br/>纯 Rust"] Q2 -->|"Python"| BCC["BCC<br/>Python 前端"] style BPFTRACE fill:#c8e6c9,stroke:#2e7d32 style LIBBPF fill:#bbdefb,stroke:#1565c0 style GOEBPF fill:#fff9c4,stroke:#f9a825 style AYA fill:#ffccbc,stroke:#d84315

1.3 BCC:Python 前端的 eBPF 工具集#

BCC(BPF Compiler Collection)是决策树中”Python 前端”的选项,在运维场景中广泛使用。它的架构与 libbpf/Aya 有本质区别:

flowchart TB subgraph BCC架构 PY["Python 脚本<br/>用户态控制逻辑"] BPF_C["C 代码片段<br/>嵌入 Python 字符串"] LLVM["LLVM<br/>运行时编译"] end PY -->|"嵌入 C 代码"| BPF_C BPF_C -->|"运行时编译为 BPF"| LLVM LLVM -->|"加载到内核"| KERNEL["内核"] style BCC架构 fill:#e1bee7,stroke:#6a1b9a

BCC 的核心特征是运行时编译——Python 脚本中嵌入的 C 代码在执行时才被 LLVM 编译为 BPF 字节码。这意味着无需预编译,但也意味着每次运行都需要 LLVM,且编译结果依赖当前内核版本(不支持 CO-RE)。

# BCC Python 示例:追踪 openat 系统调用
from bcc import BPF
bpf_text = """
#include <uapi/linux/ptrace.h>
struct data_t { u32 pid; char comm[16]; char filename[256]; };
BPF_PERF_OUTPUT(events);
TRACEPOINT_PROBE(syscalls, sys_enter_openat) {
struct data_t data = {};
data.pid = bpf_get_current_pid_tgid() >> 32;
bpf_get_current_comm(&data.comm, sizeof(data.comm));
bpf_probe_read_user_str(&data.filename, sizeof(data.filename), args->filename);
events.perf_submit(args, &data, sizeof(data));
}
"""
b = BPF(text=bpf_text)
def print_event(cpu, data, size):
event = b["events"].event(data)
print(f"PID={event.pid} COMM={event.comm} FILE={event.filename}")
b["events"].open_perf_buffer(print_event)
while True:
b.perf_buffer_poll()
优点缺点
Python 前端,开发快速运行时编译,依赖 LLVM
丰富的内置工具集不支持 CO-RE,需目标内核头文件
适合运维脚本性能不如编译型方案
社区成熟,工具丰富生产部署需安装 LLVM + kernel headers

二、libbpf:C 语言开发库#

2.1 libbpf 的架构#

libbpf 是 Linux 内核官方的 eBPF 用户态库,是 CO-RE 的基石:

flowchart TB subgraph 用户态程序 APP["应用程序"] SKEL["骨架代码<br/>hello.skel.h"] LIBBPF["libbpf<br/>bpf_object__open/load/attach"] end subgraph eBPF程序 BPF_C["hello.bpf.c"] BPF_O["hello.bpf.o<br/>字节码 + BTF"] end BPF_C -->|"clang 编译"| BPF_O BPF_O -->|"bpftool gen skeleton"| SKEL SKEL --> APP APP --> LIBBPF LIBBPF -->|"bpf() 系统调用"| KERNEL["内核"] style LIBBPF fill:#c8e6c9,stroke:#2e7d32

2.2 libbpf 开发流程#

# 1. 编写 eBPF 程序
cat > hello.bpf.c << 'EOF'
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256*1024); } events SEC(".maps");
SEC("tracepoint/syscalls/sys_enter_execve")
int hello(void *ctx) {
bpf_trace_printk("Hello from eBPF!", 18);
return 0;
}
char LICENSE[] SEC("license") = "GPL";
EOF
# 2. 编译
clang -g -O2 -target bpf -D__TARGET_ARCH_x86 -c hello.bpf.c -o hello.bpf.o
# 3. 生成骨架
bpftool gen skeleton hello.bpf.o > hello.skel.h
# 4. 编写用户态程序(包含 hello.skel.h)
# 5. 编译用户态程序
gcc -o hello hello.c -lbpf -lelf -lz
# 6. 运行
sudo ./hello

2.3 libbpf 骨架 API#

// 骨架提供的核心 API
struct hello_bpf *hello_bpf__open(void); // 打开
struct hello_bpf *hello_bpf__open_and_load(void); // 打开+加载
int hello_bpf__load(struct hello_bpf *skel); // 加载
int hello_bpf__attach(struct hello_bpf *skel); // 附加
void hello_bpf__destroy(struct hello_bpf *skel); // 销毁
// 访问 Map 和程序
int fd = bpf_map__fd(skel->maps.my_map);
int prog_fd = bpf_program__fd(skel->progs.my_prog);

2.4 libbpf 的优缺点#

优点缺点
CO-RE 原生支持C 语言开发体验
内核官方维护需要手动管理骨架
最小依赖错误处理不够友好
性能最优缺乏高级抽象

三、cilium/ebpf:Go 语言开发库#

3.1 cilium/ebpf 的架构#

cilium/ebpf 是 Cilium 团队维护的 Go eBPF 库,通过 bpf2go 实现编译时代码生成:

flowchart LR BPF_C["hello.bpf.c"] -->|"clang 编译"| BPF_O["hello.bpf.o"] BPF_O -->|"bpf2go"| GO_GEN["hello_bpfel.go<br/>自动生成"] GO_GEN --> GO_APP["main.go<br/>用户态程序"] GO_APP -->|"cilium/ebpf 库"| KERNEL["内核"] style GO_GEN fill:#c8e6c9,stroke:#2e7d32

3.2 cilium/ebpf 开发流程#

main.go
package main
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target bpfel -type event bpf hello.bpf.c -- -I/usr/include/bpf -D__TARGET_ARCH_x86
import (
"fmt"
"os"
"os/signal"
"github.com/cilium/ebpf/ringbuf"
)
func main() {
// 加载 eBPF 程序(bpf2go 生成的代码)
objs := bpfObjects{}
if err := loadBpfObjects(&objs, nil); err != nil {
panic(err)
}
defer objs.Close()
// 附加到 tracepoint
// ...
// 读取 Ring Buffer
rd, err := ringbuf.NewReader(objs.Events)
if err != nil {
panic(err)
}
defer rd.Close()
fmt.Println("Tracing execve calls...")
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt)
for {
select {
case <-sig:
return
case record := <-rd.Events():
event := (*bpfEvent)(unsafe.Pointer(&record.RawSample[0]))
fmt.Printf("PID=%d COMM=%s\n", event.Pid, event.Comm)
}
}
}

3.3 bpf2go 代码生成#

# 生成 Go 代码
go generate ./...
# bpf2go 会生成以下文件:
# hello_bpfel.go — Go 类型定义和加载函数
# hello_bpfel.o — 编译后的 eBPF 字节码

3.4 cilium/ebpf 的优缺点#

优点缺点
Go 语言生态编译时依赖 clang
类型安全bpf2go 增加构建复杂度
丰富的 Map 操作不支持所有 eBPF 特性
Cilium 团队维护Go GC 可能影响实时性

四、Aya:Rust eBPF 框架#

4.1 Aya 的架构#

Aya 是纯 Rust 的 eBPF 框架,不依赖 libbpf:

flowchart TB subgraph Aya架构 RBPF["Rust eBPF 程序<br/>aya-bpf 库"] RUSER["Rust 用户态<br/>aya 库"] end RBPF -->|"编译为 BPF 字节码"| OBJ["hello.o"] RUSER -->|"aya 库加载"| OBJ RUSER -->|"直接 bpf() 系统调用<br/>无需 libbpf"| KERNEL["内核"] style Aya架构 fill:#ffccbc,stroke:#d84315

4.2 Aya eBPF 程序#

// eBPF 程序(Rust)
#![no_std]
#![no_main]
use aya_bpf::{
bindings::xdp_action,
macros::xdp,
programs::XdpContext,
};
use aya_log_ebpf::info;
#[xdp(name="hello_xdp")]
pub fn hello_xdp(ctx: XdpContext) -> u32 {
info!(&ctx, "received a packet");
xdp_action::XDP_PASS
}
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
unsafe { core::hint::unreachable_unchecked() }
}

4.3 Aya 用户态程序#

// 用户态程序(Rust)
use aya::{Bpf, programs::Xdp, BpfLoader};
use std::net::Interface;
fn main() -> Result<(), anyhow::Error> {
// 加载 eBPF 程序
let mut bpf = BpfLoader::new().load_file("hello.o")?;
// 获取 XDP 程序
let program: &mut Xdp = bpf.program_mut("hello_xdp")?.try_into()?;
program.load()?;
// 附加到网卡
let iface = Interface::from_str("eth0")?;
program.attach(&iface, XdpFlags::default())?;
println!("XDP program attached to eth0");
// 事件循环
loop {
std::thread::sleep(std::time::Duration::from_secs(1));
}
}

4.4 Aya 的优缺点#

优点缺点
纯 Rust,无 libbpf 依赖Rust 学习曲线
内存安全生态不如 libbpf 成熟
Cargo 集成编译时间较长
宏简化开发文档相对较少

五、bpftrace:高级追踪语言#

5.1 bpftrace 的定位#

bpftrace 是 eBPF 的高级前端,用类似 awk 的 DSL 编写追踪脚本:

# 一行命令追踪
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s → %s\n", comm, str(args->filename)); }'
# 脚本文件
cat > trace_open.bt << 'EOF'
#!/usr/bin/env bpftrace
tracepoint:syscalls:sys_enter_openat
/comm == "myapp"/
{
printf("PID=%d FILE=%s\n", pid, str(args->filename));
}
tracepoint:syscalls:sys_exit_openat
/comm == "myapp" && args->ret < 0/
{
printf("FAILED: PID=%d RET=%d\n", pid, args->ret);
}
EOF
sudo bpftrace trace_open.bt

5.2 bpftrace 的优缺点#

优点缺点
一行命令即可追踪不适合复杂程序
无需编译性能不如编译型方案
丰富的内置函数不支持 CO-RE
适合快速诊断不适合生产级部署

六、框架选型指南#

6.1 按场景选择#

场景推荐框架原因
快速诊断/临时追踪bpftrace一行命令,无需编译
生产级网络程序libbpf性能最优,CO-RE 支持
K8s/云原生开发cilium/ebpfGo 生态,与 K8s 集成
安全工具开发AyaRust 内存安全
Python 运维脚本BCCPython 前端,快速原型
教学实验bpftrace最低学习门槛

6.2 按团队技能选择#

团队技能推荐框架原因
C 语言熟练libbpf最直接的映射
Go 语言团队cilium/ebpfGo 生态集成
Rust 爱好者Aya纯 Rust 栈
运维工程师bpftrace/BCC脚本化,低门槛
Note

框架选择不是互斥的——你可以在不同场景使用不同框架。用 bpftrace 做快速诊断,用 libbpf/cilium/ebpf 做生产级开发,这是最常见的组合。

七、动手实践#

7.1 使用 libbpf 开发 eBPF 程序#

# 使用 libbpf-bootstrap 快速开始
git clone https://github.com/libbpf/libbpf-bootstrap.git
cd libbpf-bootstrap/c
# 编译
make
# 运行
sudo ./minimal
sudo ./bootstrap

7.2 使用 cilium/ebpf 开发 eBPF 程序#

# 使用 ebpf-go-bootstrap 快速开始
git clone https://github.com/cilium/ebpf-go-bootstrap.git
cd ebpf-go-bootstrap
# 编译
go generate ./...
go build -o app
# 运行
sudo ./app

7.3 使用 Aya 开发 eBPF 程序#

# 安装 Aya 工具
cargo install aya-tool
# 创建新项目
cargo generate --name my-ebpf https://github.com/aya-rs/aya-template
cd my-ebpf
cargo build --release
sudo ./target/release/my-ebpf

八、开发工具链与调试#

8.1 核心开发工具#

工具用途安装方式
bpftool gen skeleton从 .o 文件生成骨架头文件apt install bpftool
pahole生成 BTF 类型信息apt install dwarves
llvm-objdump反汇编 eBPF 字节码随 clang 安装
bpftool btf dump查看内核 BTF 信息apt install bpftool

骨架头文件是 libbpf 开发的核心——它将 Map 定义和程序入口自动包装为结构体,避免手动管理文件描述符:

# 生成骨架头文件
bpftool gen skeleton example.bpf.o > example.skel.h
# 在 C 代码中使用
# #include "example.skel.h"
# struct example_bpf *obj = example_bpf__open();
# example_bpf__load(obj);
# example_bpf__attach(obj);

8.2 BCC Python 快速示例#

BCC 的优势在于快速原型——几行 Python 就能实现内核追踪:

#!/usr/bin/env python3
from bcc import BPF
prog = """
#include <uapi/linux/ptrace.h>
int trace_open(struct pt_regs *ctx, const char __user *filename) {
bpf_trace_printk("open: %s\\n", filename);
return 0;
}
"""
b = BPF(text=prog)
b.attach_kprobe(event="do_sys_openat2", fn_name="trace_open")
b.trace_print()
Note

CO-RE 是 libbpf 和 cilium/ebpf 的基础能力。如果你的目标内核不支持 BTF(5.2 以下),只能使用 BCC 的运行时编译模式。生产环境建议内核 5.15+ 以获得完整的 CO-RE 支持。

九、本章小结#

上一章剖析了Cilium 架构深入。 本章对比了四大 eBPF 开发框架:

主题核心要点关键词
libbpfC 语言,CO-RE 基石,性能最优,适合底层开发libbpf
cilium/ebpfGo 语言,bpf2go 代码生成,适合云原生开发cilium/ebpf
AyaRust,纯 Rust 无 libbpf 依赖,内存安全Aya
bpftraceDSL,一行命令追踪,适合快速诊断bpftrace

选择框架的核心原则:快速诊断用 bpftrace,生产开发用 libbpf 或 cilium/ebpf,追求安全用 Aya

支持与分享

如果这篇文章对你有帮助,欢迎支持作者或分享给更多人

eBPF 开发框架
https://blog.souloss.com/posts/ebpf/ebpf-development-framework/
作者
Souloss
发布于
2026-01-18
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

相关文章 智能推荐
1
eBPF 可观测性
eBPF eBPF 最大的应用场景是可观测性——零侵入、低开销、内核级的全链路追踪。本章详解三大可观测性工具链——bpftrace(一行命令追踪内核)、BCC(Python 前端 + 丰富工具集)、Beyla(零侵入应用性能监控),并通过实战展示性能分析、分布式追踪、应用性能监控的完整工作流。
2
eBPF 网络全景
eBPF eBPF 正在重新定义 Linux 网络栈——从连接跟踪、NAT 到 kube-proxy 替代,从 Socket Filter 到 Sk_msg 重定向,eBPF 提供了比 iptables/netfilter 更高性能、更灵活的网络方案。本章从宏观视角展示 eBPF 网络的全景,详解连接跟踪、NAT、kube-proxy 替代、Socket 层 eBPF,并对比 eBPF 与传统网络方案的架构差异。
3
eBPF 生产部署
eBPF eBPF 生产部署实践——性能开销分析、调试技巧、版本兼容、内核版本要求与升级策略。
4
eBPF 与 WebAssembly
eBPF eBPF 提供内核可编程能力,WebAssembly 提供跨平台可移植性——两者的融合会带来什么?本章详解 Wasm-eBPF 项目、用户态 eBPF 运行时、eBPF 程序的 Wasm 封装,以及 eBPF + Wasm 在边缘计算、插件系统、跨平台可观测性中的应用前景。
5
eBPF 与内存管理
eBPF eBPF 程序的内存使用是生产部署中的关键考量——Map 占用多少内存?eBPF 程序的栈空间有多大?容器环境中的 eBPF 内存如何计费?本章详解 eBPF 的内存模型、Map 内存开销计算、容器内存追踪、eBPF-mm 子系统,以及内存限制下的优化策略。