eBPF 是什么:从零理解 Linux 内核可编程化
通俗讲解 eBPF 的核心原理、与传统内核模块的区别、安全验证机制,以及 eBPF 在网络观测、安全策略、性能追踪三大场景的实际应用,帮助运维工程师建立正确的 eBPF 认知框架。
如果你近两年关注 Kubernetes 网络或 Linux 系统监控,一定频繁看到 eBPF 这个词:Cilium 用它替代 iptables、Falco 用它做安全审计、Pixie 用它做零侵入可观测性。eBPF 到底是什么,为什么它让整个云原生圈如此兴奋?本文从零开始讲清楚。
从 BPF 到 eBPF
BPF(Berkeley Packet Filter)诞生于 1992 年,最初只是 tcpdump 底层的一个包过滤机制——在内核里跑一段小程序,决定某个网络包是否应该被捕获,避免把所有包都复制到用户空间再过滤的巨大开销。
eBPF(extended BPF)是 2014 年 Linux 3.18 引入的大幅扩展版本,能做的事情已经远超包过滤:
- 挂载点扩展:不再局限于网络包,可以挂载到系统调用、内核函数、用户态函数、硬件性能计数器等上百个挂载点
- 数据结构:支持 HashMap、数组、队列、环形缓冲区等丰富数据结构(BPF Maps)
- 程序类型:网络过滤、XDP(eXpress Data Path)、TracePoint、kprobe、uprobe、LSM 等十余种程序类型
- 指令集:64 位寄存器,指令更接近原生机器码,JIT 编译后性能接近原生 C
一句话概括:eBPF 让你在内核里安全地运行自己写的代码,无需修改内核源码,无需重启系统。
关键问题:为什么安全?
传统内核模块(.ko 文件)一旦加载,可以做任何事——读写任意内存、挂死内核、甚至开后门。一个 Bug 就能导致整机崩溃。
eBPF 程序在加载前必须通过内核 Verifier(验证器) 的严格审查:
用户编写 eBPF 程序(C 或其他语言)
↓
LLVM/Clang 编译为 eBPF 字节码
↓
系统调用 bpf() 加载字节码
↓
内核 Verifier 静态分析
├── 程序必须在有限步骤内终止(不允许无界循环)
├── 所有内存访问必须在边界内(不允许越界读写)
├── 不允许调用任意内核函数(只能调用白名单 BPF helper)
└── 指针运算必须可静态追踪
↓
通过 → JIT 编译为原生机器码,加载到内核
失败 → 返回错误,程序不被执行
这个验证机制保证了 eBPF 程序:不会崩溃内核、不会死循环、不会越界访问。
eBPF 程序结构
一个最简单的 eBPF 程序(使用 libbpf + C):
// trace_open.bpf.c
// 追踪所有 openat 系统调用,打印文件名
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
// 定义输出事件结构
struct event {
__u32 pid;
char filename[256];
};
// Ring Buffer Map,用于向用户态传递数据
struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 256 * 1024);
} rb SEC(".maps");
// 挂载到 openat 系统调用入口
SEC("tracepoint/syscalls/sys_enter_openat")
int trace_openat(struct trace_event_raw_sys_enter *ctx)
{
struct event *e;
__u32 pid = bpf_get_current_pid_tgid() >> 32;
// 从 Ring Buffer 申请空间
e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0);
if (!e) return 0;
e->pid = pid;
// 从用户空间读取文件名(BPF helper,安全读取)
bpf_probe_read_user_str(e->filename, sizeof(e->filename),
(void *)ctx->args[1]);
bpf_ringbuf_submit(e, 0);
return 0;
}
char LICENSE[] SEC("license") = "GPL";
# 编译
clang -O2 -target bpf -c trace_open.bpf.c -o trace_open.bpf.o
# 加载并运行(配合用户态程序)
sudo ./trace_open
# 输出示例:
# PID=1234 FILE=/etc/passwd
# PID=5678 FILE=/var/log/syslog
eBPF 三大核心应用场景
1. 网络观测与加速(XDP)
XDP(eXpress Data Path)是 eBPF 最高性能的网络挂载点,程序在网卡驱动层就能处理数据包,比 iptables 早得多,延迟可低至几微秒:
网卡收到数据包
↓
XDP eBPF 程序(可以在这里丢包/转发/修改)← 最早处理
↓
内核网络协议栈(TCP/IP)
↓
iptables/nftables
↓
应用程序
Cilium 正是用 XDP + eBPF 替代了 kube-proxy 的 iptables 规则,在大规模集群(Service 数量 > 1000)时性能提升极为显著。
2. 安全审计与运行时防护
eBPF LSM(Linux Security Module)钩子让安全工具可以在内核层拦截并审计任意系统行为:
# Falco:基于 eBPF 的云原生运行时安全
# 检测规则示例:容器内出现 shell 进程
- rule: Terminal Shell in Container
desc: 容器内有人打开了交互式 shell(可能是入侵)
condition: >
spawned_process and container
and shell_procs and proc.tty != 0
and not user_expected_terminal_shell_in_container_conditions
output: >
A shell was spawned in a container
(user=%user.name container=%container.name
shell=%proc.name parent=%proc.pname)
priority: NOTICE
3. 性能追踪与分析
无需修改代码、无需重启进程,动态追踪任意函数的延迟、调用栈、参数:
# bpftrace:类 awk 的 eBPF 追踪语言
# 追踪所有进程的 read() 调用延迟(直方图)
sudo bpftrace -e '
kprobe:vfs_read { @start[tid] = nsecs; }
kretprobe:vfs_read /@start[tid]/ {
@latency_us = hist((nsecs - @start[tid]) / 1000);
delete(@start[tid]);
}'
# 追踪某个进程的所有系统调用
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_* /pid == 1234/ { @[probe] = count(); }'
# 实时查看 CPU 上运行的函数火焰图(配合 profile 探针)
sudo bpftrace -e 'profile:hz:99 { @[kstack] = count(); }' > /tmp/out.txt
常用 eBPF 工具速查
| 工具 | 用途 | 上手难度 |
|---|---|---|
bpftrace |
单行追踪脚本,类 awk 语法 | ★★☆☆☆ |
BCC tools |
现成工具集(tcptop、opensnoop 等) | ★☆☆☆☆ |
libbpf |
编写 CO-RE 可移植 eBPF 程序 | ★★★★☆ |
| Cilium | Kubernetes 网络 + 安全 | ★★★☆☆(Helm 安装) |
| Falco | 运行时安全审计 | ★★☆☆☆ |
| Pixie | 零侵入可观测平台 | ★★☆☆☆ |
| Tetragon | Cilium 出品,安全可观测 | ★★☆☆☆ |
快速体验:BCC opensnoop
不想写代码,先用现成工具感受 eBPF:
# Ubuntu 安装 BCC 工具集
sudo apt install -y bpfcc-tools linux-headers-$(uname -r)
# 实时追踪所有文件打开操作
sudo opensnoop-bpfcc
# PID COMM FD ERR PATH
# 1234 nginx 5 0 /etc/nginx/nginx.conf
# 5678 sshd 12 0 /var/log/auth.log
# 追踪 TCP 连接建立
sudo tcpconnect-bpfcc
# PID COMM IP SADDR DADDR DPORT
# 9012 curl 4 192.168.1.10 93.184.216.34 443
# 追踪进程执行(可以发现隐藏进程)
sudo execsnoop-bpfcc
内核版本要求
| 功能 | 最低内核版本 |
|---|---|
| 基础 eBPF | 3.18 |
| BPF Maps | 3.19 |
| kprobe | 4.1 |
| tracepoint | 4.7 |
| XDP | 4.8 |
| BTF(CO-RE 基础) | 5.2 |
| Ring Buffer | 5.8 |
| eBPF LSM | 5.7 |
| 生产推荐 | 5.15 LTS+ |
Ubuntu 22.04 LTS 默认内核 5.15,完整支持上述所有特性,是 eBPF 生产环境的推荐起点。
小结
eBPF 的价值在于打破了“要么修改内核、要么忍受用户态开销”的两难困境。通过 Verifier 保证安全、通过 JIT 保证性能、通过 BPF Maps 实现内核态与用户态的数据交换,eBPF 已经成为 2026 年云原生基础设施最重要的底层技术之一。下一篇将讲解基于 eBPF 的 Cilium 如何在 Kubernetes 中替代 Calico/Flannel。
