技术博客

eBPF 是什么:从零理解 Linux 内核可编程化

通俗讲解 eBPF 的核心原理、与传统内核模块的区别、安全验证机制,以及 eBPF 在网络观测、安全策略、性能追踪三大场景的实际应用,帮助运维工程师建立正确的 eBPF 认知框架。

eBPFLinux内核网络可观测性

如果你近两年关注 Kubernetes 网络或 Linux 系统监控,一定频繁看到 eBPF 这个词:Cilium 用它替代 iptables、Falco 用它做安全审计、Pixie 用它做零侵入可观测性。eBPF 到底是什么,为什么它让整个云原生圈如此兴奋?本文从零开始讲清楚。

从 BPF 到 eBPF

BPF(Berkeley Packet Filter)诞生于 1992 年,最初只是 tcpdump 底层的一个包过滤机制——在内核里跑一段小程序,决定某个网络包是否应该被捕获,避免把所有包都复制到用户空间再过滤的巨大开销。

eBPF(extended BPF)是 2014 年 Linux 3.18 引入的大幅扩展版本,能做的事情已经远超包过滤:

一句话概括: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。