eBPF 第二章 环境准备与安装部署

版本:2026.07 | 作者:Pozicaiman | 日期:2026-07-24
关键词:eBPF环境、libbpf、BCC、bpftrace、CO-RE、内核配置
适用版本:Linux Kernel 4.18+ / 推荐 5.4+,libbpf 1.0+,BCC 0.28+


2.1 环境要求与前置条件

2.1.1 内核版本要求

eBPF 的能力与 Linux 内核版本强相关,不同版本支持的程序类型、Helper 函数、Map 类型均有差异。下表汇总了各内核版本的关键特性:

内核版本 发布年份 关键 eBPF 特性 推荐度 说明
4.0 - 4.3 2015 eBPF 基础架构引入,支持 kprobe/tracepoint 不推荐 功能极其有限,仅供了解
4.4 - 4.9 2016 XDP 支持、perf_event 程序、BPF Map in Map 最低可用 基础观测可用,无 CO-RE
4.10 - 4.14 2017 bpf 系统调用扩展、cgroup sock 程序、LRU Map 可用 BCC 开发可用
4.15 - 4.19 2018 BTF 引入、bpf_iter、socket filter 增强 推荐(LTS) 4.19 LTS 是长期支持底线
5.0 - 5.4 2019 CO-RE(Compile Once-Run Everywhere)、bpf_link、BTF dedup 强烈推荐(LTS) CO-RE 成熟,libbpf 推荐
5.5 - 5.10 2020 bpf_loop、ring buffer Map、sk_storage、LSM BPF 强烈推荐(LTS) 5.10 LTS 是生产首选
5.11 - 5.15 2021 bpf_iter 增强迭代、bpf_timer、CAP_BPF 强烈推荐(LTS) 无 root 运行成为可能
5.16 - 5.19 2022 bpf_kptr、动态指针、BPF 链接类型扩展 推荐 更多内核子系统可观测
6.0 - 6.6 2023 BPF 验证器增强、bpf_arena、Uprobe 重构 最新推荐(LTS) 6.6 LTS 支持最新特性
6.7+ 2024+ bpf_iter 增强结构体迭代、更多 Helper 函数 前沿 持续演进中

生产环境建议:优先选择 5.10 LTS 或 6.1 LTS 内核,既能获得 CO-RE 支持,又有长期安全更新保障。

2.1.2 内核配置选项检查

eBPF 需要内核在编译时开启相关配置选项。以下配置项必须启用(ym):

配置选项 必需性 说明
CONFIG_BPF 必需 启用 BPF 核心框架
CONFIG_BPF_SYSCALL 必需 启用 bpf() 系统调用,用户空间加载 BPF 程序的入口
CONFIG_BPF_JIT 必需 启用 BPF JIT 编译,将 BPF 字节码转为原生机器码
CONFIG_HAVE_EBPF_JIT 必需 标记架构支持 eBPF JIT(x86_64/ARM64/RISC-V)
CONFIG_BPF_JIT_ALWAYS_ON 推荐 强制开启 JIT,防止字节码解释器被禁用
CONFIG_BPF_UNPRIV_DEFAULT_OFF 推荐 默认禁止非特权用户使用 BPF(安全加固)
CONFIG_DEBUG_INFO_BTF 必需(CO-RE) 编译内核 BTF 调试信息,CO-RE 运行时依赖
CONFIG_DEBUG_INFO_BTF_MODULES 推荐 为内核模块生成 BTF,支持模块相关 eBPF 程序
CONFIG_BPF_LSM 可选 启用 BPF LSM(Linux Security Module),安全策略场景
CONFIG_NET_CLS_BPF 可选 流量分类 BPF,网络场景
CONFIG_NET_ACT_BPF 可选 流量动作 BPF,网络场景
CONFIG_XDP_SOCKETS 可选 AF_XDP 高性能数据包处理
CONFIG_CGROUP_BPF 推荐 cgroup 级别 BPF 程序
CONFIG_LIRC_BPF 可选 红外遥控 BPF

2.1.3 硬件架构要求

架构 eBPF 支持 JIT 支持 状态 说明
x86_64 完整 完整 生产首选 最成熟的 eBPF 架构
ARM64 (aarch64) 完整 完整 生产推荐 云原生主流架构,5.x 起完全成熟
RISC-V (riscv64) 完整 完整(5.18+) 可用 新兴架构,5.18 起支持 JIT
s390x 完整 完整 可用 IBM 大型机
PowerPC (ppc64le) 部分 完整 有限 部分特性受限
MIPS 部分 部分 不推荐 JIT 支持不完整
ARM32 (armv7) 有限 部分 不推荐 受限于寄存器数量,仅基础功能

2.1.4 操作系统发行版支持矩阵

发行版 最低版本 默认内核 BTF 支持 libbpf 包 BCC 包 推荐度
Ubuntu 20.04 LTS 20.04 5.4/5.15 20.10+ 推荐
Ubuntu 22.04 LTS 22.04 5.15/6.8 强烈推荐
Ubuntu 24.04 LTS 24.04 6.8 最新推荐
RHEL 8.x 8.0 4.18 8.2+ 推荐(企业)
RHEL 9.x 9.0 5.14 强烈推荐(企业)
CentOS Stream 8/9 8 4.18/5.14 8+ 推荐
Rocky Linux 8/9 8 4.18/5.14 推荐
AlmaLinux 8/9 8 4.18/5.14 推荐
Debian 11 11 5.10 推荐
Debian 12 12 6.1 强烈推荐
Fedora 36+ 36 5.17+ 前沿测试
Alpine 3.16+ 3.16 5.15+ 3.18+ 是(社区) 否(需编译) 容器场景
openSUSE Tumbleweed - 6.x 可用

2.1.5 eBPF 开发环境组件关系

编译工具链

内核空间 Kernel Space

用户空间 User Space

源码转BPF字节码

BPF .o 文件

重定位数据

调用libbpf API

bpf() syscall

验证指令

通过则JIT编译

原生代码挂载

读写数据

读取Map数据

应用/工具
BCC/bpftrace/bpftool

libbpf
(BPF 加载库)

BPF 加载器
(CO-RE Skeleton)

bpf() 系统调用

BPF 验证器
Verifier

BPF JIT 编译器
(x86_64/ARM64)

内核 Hook 点
kprobe/tracepoint/XDP/...

BPF Maps
(数据存储)

Clang
(前端编译)

LLVM
(后端 BPF 代码生成)

BTF 调试信息
(vmlinux)

上图展示了 eBPF 开发环境的完整组件链路:从源码编译(Clang/LLVM)到 BPF 字节码生成,通过 libbpf 加载器(CO-RE Skeleton 机制)调用 bpf() 系统调用,经验证器安全检查后由 JIT 编译为原生代码挂载到内核 Hook 点。


2.2 工具链安装与配置

2.2.1 LLVM/Clang 编译器安装

LLVM/Clang 是 eBPF 程序的编译器前端,将 C 语言源码编译为 BPF 字节码。Clang 版本直接影响 eBPF 程序的编译能力。

方式一:包管理器安装(推荐快速使用)
# ===== Ubuntu / Debian =====
sudo apt-get update
sudo apt-get install -y clang llvm lld lldb

# 指定版本安装(推荐 clang-15+)
sudo apt-get install -y clang-15 llvm-15 lld-15

# 验证安装
clang --version
llvm-strip --version

# ===== RHEL / CentOS / Rocky / AlmaLinux =====
sudo dnf install -y clang llvm lld
# 或指定模块版本
sudo dnf module install llvm-toolset

# ===== Fedora =====
sudo dnf install -y clang llvm lld

# ===== Alpine =====
sudo apk add clang llvm lld
方式二:源码编译安装(需要特定版本时)
# 安装编译依赖
sudo apt-get install -y build-essential cmake ninja-build python3 git

# 下载 LLVM 源码(以 17.0.6 为例)
git clone --depth 1 --branch llvmorg-17.0.6 https://github.com/llvm/llvm-project.git
cd llvm-project

# 创建构建目录
mkdir -p build && cd build

# 配置 CMake(仅编译 Clang 和 BPF 后端,大幅减少编译时间)
cmake -G Ninja \
    -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_INSTALL_PREFIX=/usr/local/llvm-17 \
    -DLLVM_ENABLE_PROJECTS="clang" \
    -DLLVM_TARGETS_TO_BUILD="BPF;X86" \
    -DLLVM_ENABLE_RTTI=ON \
    -DLLVM_ENABLE_EH=ON \
    -DLLVM_BUILD_TESTS=OFF \
    -DLLVM_BUILD_EXAMPLES=OFF \
    ../llvm

# 编译并安装(根据 CPU 核数调整 -j 参数)
ninja -j$(nproc)
sudo ninja install

# 配置环境变量
echo 'export PATH=/usr/local/llvm-17/bin:$PATH' >> ~/.bashrc
echo 'export LD_LIBRARY_PATH=/usr/local/llvm-17/lib:$LD_LIBRARY_PATH' >> ~/.bashrc
source ~/.bashrc

# 验证
clang --version
版本选择建议
Clang 版本 BPF 目标支持 CO-RE 支持 推荐度 说明
< 7.0 部分 不推荐 BPF 后端不完善
8.0 - 9.0 部分 可用 早期 CO-RE 支持
10.0 - 12.0 推荐 BPF 代码生成稳定
13.0 - 15.0 强烈推荐 支持最新 BPF 特性
16.0+ 最新推荐 完整支持 BPF 语法

兼容性说明:Clang 版本与内核版本无强绑定关系,但较新的 Clang 能更好地编译使用新 BPF 特性的程序。建议 Clang >= 12。


2.2.2 libbpf 安装

libbpf 是 Linux 内核官方维护的 BPF 程序加载库,是 CO-RE(Compile Once - Run Everywhere) 的核心组件。

方式一:源码编译安装(推荐,获取最新版本)
# 安装依赖
sudo apt-get install -y pkg-config libelf-dev libzstd-dev

# 克隆 libbpf 仓库
git clone https://github.com/libbpf/libbpf.git
cd libbpf

# 切换到稳定分支(推荐 1.3.0+)
git checkout v1.3.0

# 方式 A:使用 meson 构建(libbpf 1.0+ 推荐)
sudo apt-get install -y meson ninja-build

# 配置并编译
meson setup build -Dprefix=/usr -Dlibdir=lib
ninja -C build
sudo ninja -C build install

# 方式 B:使用传统 Makefile 构建
cd src
make -j$(nproc)
sudo make install
sudo ldconfig

# 验证安装
pkg-config --modversion libbpf
# 预期输出: 1.3.0
方式二:包管理器安装
# Ubuntu / Debian
sudo apt-get install -y libbpf-dev libbpf1

# RHEL / CentOS / Rocky
sudo dnf install -y libbpf-devel libbpf

# Alpine
sudo apk add libbpf-dev

# 验证
pkg-config --cflags --libs libbpf
# 预期输出: -I/usr/include -lbpf
libbpf 与内核版本兼容性
libbpf 版本 最低内核要求 关键特性 说明
0.x (0.8之前) 4.15+ 基础 BPF 加载 旧 API,不推荐
1.0 4.18+ API 稳定,CO-RE 成熟 首个稳定版本
1.1 - 1.3 5.4+ bpf_link 增强,ringbuf 推荐生产使用
1.4+ 5.10+ 最新特性支持 前沿使用

关键原则:libbpf 向后兼容旧内核。使用 libbpf 1.x 可以加载到 4.18+ 的内核上运行(前提是程序未使用新内核独有的特性)。libbpf 会在运行时探测内核能力并优雅降级。


2.2.3 BCC 工具集安装

BCC (BPF Compiler Collection) 是基于 Python/C++ 的高层 eBPF 开发框架,提供丰富的开箱即用工具和 Python 绑定。

BCC 完整安装流程
# ===== Ubuntu 22.04 / 24.04 =====
# 1. 安装构建依赖
sudo apt-get install -y \
    bpfcc-tools linux-headers-$(uname -r) \
    build-essential clang llvm \
    libelf-dev libbpf-dev \
    python3 python3-dev python3-pip \
    cmake git flex bison

# 2. 克隆 BCC 仓库
git clone --recursive https://github.com/iovisor/bcc.git
cd bcc

# 3. 创建构建目录
mkdir -p build && cd build

# 4. CMake 配置
cmake -DCMAKE_INSTALL_PREFIX=/usr \
      -DPYTHON_CMD=python3 \
      ..

# 5. 编译(耗时约 5-10 分钟)
make -j$(nproc)

# 6. 安装
sudo make install

# 7. 安装 Python 绑定
sudo pip3 install bcc
# 或从源码安装
cd ../src/python
sudo python3 setup.py install

# 8. 验证安装
sudo python3 -c "from bcc import BPF; print('BCC installed successfully')"

# 9. 运行自带工具验证
sudo /usr/share/bcc/tools/execsnoop
# 预期:输出系统进程执行事件


# ===== RHEL 9 / Rocky 9 / AlmaLinux 9 =====
sudo dnf install -y \
    bcc bcc-tools \
    python3-bcc \
    kernel-devel-$(uname -r) \
    clang llvm \
    elfutils-libelf-devel libbpf-devel

# 验证
sudo /usr/share/bcc/tools/execsnoop


# ===== Alpine Linux =====
# BCC 在 Alpine 上需要源码编译,依赖较多
sudo apk add --no-cache \
    build-base clang llvm-dev elfutils-dev \
    libbpf-dev python3-dev cmake git flex-dev bison
git clone https://github.com/iovisor/bcc.git
cd bcc && mkdir build && cd build
cmake .. && make -j$(nproc) && sudo make install
BCC Python 绑定验证
#!/usr/bin/env python3
"""BCC Python 绑定验证脚本"""
from bcc import BPF

# 简单的 BPF 程序
bpf_text = """
#include <uapi/linux/ptrace.h>
BPF_HASH(counts, u32, u64);

int hello(void *ctx) {
    u32 pid = bpf_get_current_pid_tgid() >> 32;
    u64 one = 1;
    u64 *existing = counts.lookup(&pid);
    if (existing) {
        (*existing)++;
    } else {
        counts.update(&pid, &one);
    }
    return 0;
}
"""

bpf = BPF(text=bpf_text)
print("BCC version check passed. BPF object created successfully.")
print("Available BPF functions: " + str(list(bpf.functions.keys())))
常见安装问题排查
# 问题1:找不到内核头文件
# 解决:安装对应内核版本头文件
sudo apt-get install -y linux-headers-$(uname -r)

# 问题2:Python 导入错误 ModuleNotFoundError: No module named 'bcc'
# 解决:确认 Python 版本一致,重新安装绑定
python3 -c "import sys; print(sys.path)"
sudo python3 -m pip install --force-reinstall bcc

# 问题3:Clang 编译 BPF 程序报错 "target triple invalid"
# 解决:确认 Clang 版本 >= 7,且支持 BPF 后端
echo 'int main() { return 0; }' | clang -target bpf -c -x c - -o /dev/null && echo "BPF target OK"

# 问题4:运行时报错 "bpf: Operation not permitted"
# 解决:确认以 root 运行或具有 CAP_BPF/CAP_SYS_ADMIN 能力
sudo cat /proc/sys/kernel/unprivileged_bpf_disabled
# 若为 1 或 2,非特权用户无法运行 BPF

2.2.4 bpftrace 安装

bpftrace 是基于 eBPF 的高级追踪语言,提供类似 awk/DTrace 的一行命令和脚本能力,是快速排障利器。

方式一:包管理器安装(最快)
# Ubuntu 22.04+
sudo apt-get install -y bpftrace

# RHEL 9 / Rocky 9
sudo dnf install -y bpftrace

# Fedora
sudo dnf install -y bpftrace

# Debian 12
sudo apt-get install -y bpftrace

# 验证
bpftrace --version
# 预期: bpftrace v0.x.x
方式二:源码编译安装
# 安装依赖
sudo apt-get install -y \
    build-essential cmake ninja-build \
    clang llvm-dev libelf-dev libbpf-dev \
    libbcc-dev bison flex \
    libprotobuf-dev protobuf-compiler \
    libgrpc++-dev libgrpc-dev \
    asciidoctor

# 克隆仓库
git clone https://github.com/bpftrace/bpftrace.git
cd bpftrace
git submodule update --init --recursive

# 构建
mkdir -p build && cd build
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release ..
ninja -j$(nproc)

# 安装
sudo ninja install

# 验证
bpftrace --version
方式三:静态二进制(免安装)
# 下载官方静态编译二进制(无需任何依赖)
wget https://github.com/bpftrace/bpftrace/releases/latest/download/bpftrace-static-amd64.tar.gz
tar xzf bpftrace-static-amd64.tar.gz
sudo cp bpftrace /usr/local/bin/

# 验证
bpftrace --version
bpftrace 语言基础语法
// bpftrace 语法结构
// 探针类型:标识符[/过滤器/] { 动作语句 }

// 1. BEGIN 探针 - 程序启动时执行
BEGIN { printf("Starting bpftrace...\n"); }

// 2. END 探针 - 程序结束时执行
END { printf("Done. Exiting.\n"); }

// 3. kprobe 探针 - 内核函数入口
kprobe:do_sys_open { printf("open() called by %s\n", comm); }

// 4. kretprobe 探针 - 内核函数返回
kretprobe:do_sys_open /retval < 0/ { printf("open() failed: %d\n", retval); }

// 5. tracepoint 探针 - 内核静态追踪点
tracepoint:syscalls:sys_enter_openat { @opens = count(); }

// 6. interval 探针 - 定时器
interval:s:1 { print(@opens); clear(@opens); }

// 7. uprobe 探针 - 用户空间函数
uprobe:/bin/bash:readline { printf("bash readline: %s\n", str(arg0)); }

// 内置变量说明
// pid     - 进程 ID
// tid     - 线程 ID
// uid     - 用户 ID
// comm    - 进程名
// kstack  - 内核调用栈
// ustack  - 用户调用栈
// arg0-9  - 函数参数
// retval  - 返回值(仅 kretprobe/uprobe)

// 内置函数说明
// count() - 计数
// sum()   - 求和
// avg()   - 平均值
// hist()  - 直方图(2的幂次)
// lhist() - 线性直方图
// printf() - 格式化输出
// str()   - 读取字符串指针
// delete() - 删除 Map 元素
// clear() - 清空 Map
// exit()  - 退出 bpftrace

2.2.5 bpftool 安装

bpftool 是内核官方提供的 BPF 管理工具,用于查看、加载、卸载和调试 BPF 程序与 Maps。

# ===== Ubuntu / Debian =====
sudo apt-get install -y linux-tools-common linux-tools-$(uname -r)
# 或安装通用包
sudo apt-get install -y bpftool

# ===== RHEL / CentOS / Rocky / AlmaLinux =====
sudo dnf install -y bpftool

# ===== Fedora =====
sudo dnf install -y bpftool

# ===== 源码编译(从内核源码树) =====
git clone --depth 1 https://github.com/torvalds/linux.git
cd linux/tools/bpf/bpftool
make -j$(nproc)
sudo make install

# 验证安装
bpftool version
# 预期输出: v7.x.x

# 功能验证
bpftool prog show        # 列出所有已加载的 BPF 程序
bpftool map show         # 列出所有 BPF Maps
bpftool feature probe    # 探测内核 BPF 特性支持
bpftool btf dump file /sys/kernel/btf/vmlinux format c | head -20  # 查看 BTF 信息

2.3 内核配置验证

2.3.1 检查内核 BPF 特性

#!/bin/bash
# ===== 内核 BPF 配置验证命令 =====

# 1. 检查内核版本
echo "=== 内核版本 ==="
uname -r
# 预期: 5.10+ 推荐版本

# 2. 检查关键内核配置选项
echo -e "\n=== 内核 BPF 配置选项 ==="
for config in CONFIG_BPF CONFIG_BPF_SYSCALL CONFIG_BPF_JIT \
              CONFIG_HAVE_EBPF_JIT CONFIG_BPF_JIT_ALWAYS_ON \
              CONFIG_DEBUG_INFO_BTF CONFIG_BPF_UNPRIV_DEFAULT_OFF \
              CONFIG_CGROUP_BPF CONFIG_BPF_LSM; do
    val=$(grep -E "^${config}[= ]" /boot/config-$(uname -r) 2>/dev/null \
          || zcat /proc/config.gz 2>/dev/null | grep -E "^${config}[= ]")
    if [ -n "$val" ]; then
        echo "  $val"
    else
        echo "  $config=未找到(可能未启用)"
    fi
done

# 3. 检查 BTF 是否可用(CO-RE 必需)
echo -e "\n=== BTF 调试信息检查 ==="
ls -lh /sys/kernel/btf/vmlinux && echo "BTF: 可用 (CO-RE 支持)" \
    || echo "BTF: 不可用 (CO-RE 不可用)"

# 4. 检查 bpf() 系统调用是否可用
echo -e "\n=== bpf 系统调用 ==="
grep " T bpf$" /proc/kallsyms | head -5 && echo "bpf syscall: 可用" \
    || echo "bpf syscall: 不可用"

2.3.2 检查 BPF JIT 状态

# 检查 BPF JIT 是否启用(1=启用, 0=禁用)
cat /proc/sys/net/core/bpf_jit_enable
# 输出 1 表示 JIT 已启用

# 检查 BPF JIT 硬件卸载(需要网卡支持)
cat /proc/sys/net/core/bpf_jit_harden
# 0=禁用加固, 1=非特权用户加固, 2=完全加固

# 检查 BPF JIT kallsyms 暴露
cat /proc/sys/net/core/bpf_jit_kallsyms
# 1=JIT 代码符号暴露给 /proc/kallsyms (调试用)

# 启用 JIT(如未启用)
sudo sysctl -w net.core.bpf_jit_enable=1
# 永久生效
echo 'net.core.bpf_jit_enable=1' | sudo tee -a /etc/sysctl.d/99-bpf.conf

2.3.3 检查 BPF Map 大小限制

# 检查 BPF Map 相关限制
echo "=== BPF Map 限制 ==="

# 最大 Map 数量
echo "最大 Map 数量: $(cat /proc/sys/kernel/bpf_map_max_entries 2>/dev/null || echo 'N/A')"

# 单个 Map 最大内存(字节)
echo "单个 Map 最大内存: $(cat /proc/sys/kernel/bpf_map_max_size 2>/dev/null || echo 'N/A')"

# 使用 bpftool 查看当前 Maps
echo -e "\n当前已加载 BPF Maps:"
sudo bpftool map show

2.3.4 检查 RLIMIT_MEMLOCK 设置

BPF 程序加载时需要锁定内存,受 RLIMIT_MEMLOCK 限制。内核 5.11+ 引入了 CAP_BPF,不再依赖 memlock 限制。

# 检查当前 memlock 限制(单位 KB)
ulimit -l
# 输出 8192 表示 8MB,可能不够用

# 临时调整为无限制
ulimit -l unlimited

# 永久调整(编辑 /etc/security/limits.conf)
sudo tee -a /etc/security/limits.conf << 'EOF'
*    soft    memlock    unlimited
*    hard    memlock    unlimited
root soft    memlock    unlimited
root hard    memlock    unlimited
EOF

# 对于 systemd 服务,需要编辑服务单元的 LimitMEMLOCK
sudo sed -i 's/#DefaultLimitMEMLOCK=/DefaultLimitMEMLOCK=infinity/' /etc/systemd/system.conf

# 内核 5.11+ 检查 CAP_BPF 能力
echo -e "\n=== 内核版本与 CAP_BPF 支持 ==="
KV=$(uname -r | awk -F. '{print $1*100+$2}')
if [ "$KV" -ge 511 ]; then
    echo "内核 $(uname -r): 支持 CAP_BPF (5.11+)"
    echo "使用 CAP_BPF 时不需要调整 memlock 限制"
else
    echo "内核 $(uname -r): 不支持 CAP_BPF,需调整 memlock 限制"
fi

2.3.5 系统参数调优建议

#!/bin/bash
# ===== eBPF 系统参数调优脚本 =====
# 运行: sudo bash bpf-sysctl-tune.sh

set -euo pipefail

CONF_FILE="/etc/sysctl.d/99-ebpf.conf"

echo "=== eBPF 系统参数调优 ==="

# 定义调优参数
PARAMS=(
    "net.core.bpf_jit_enable=1"              # 启用 BPF JIT
    "net.core.bpf_jit_harden=1"              # 非特权用户加固(安全)
    "net.core.bpf_jit_kallsyms=0"            # 生产环境关闭符号暴露
    "kernel.unprivileged_bpf_disabled=1"     # 禁止非特权用户使用 BPF
    "kernel.perf_event_paranoid=1"           # 允许观测性能事件
    "kernel.kptr_restrict=1"                 # 限制内核指针暴露
)

# 写入配置文件
echo "# eBPF 系统参数配置 - by Pozicaiman" | sudo tee "$CONF_FILE" > /dev/null

for param in "${PARAMS[@]}"; do
    key="${param%%=*}"
    value="${param##*=}"
    echo "$key = $value" | sudo tee -a "$CONF_FILE" > /dev/null
    sudo sysctl -w "$key=$value" 2>/dev/null || echo "  警告: $key 设置失败(可能内核版本不支持)"
    echo "已设置: $key = $value"
done

echo -e "\n配置已写入 $CONF_FILE"
echo "永久生效需重启或执行: sudo sysctl --system"

2.3.6 完整的内核配置检查脚本

#!/bin/bash
# ===== eBPF 内核环境完整检查脚本 =====
# 运行: sudo bash check-ebpf-kernel.sh
# Author: Pozicaiman
# Date: 2026-07-24

set -euo pipefail

GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m'

pass() { echo -e "${GREEN}[PASS]${NC} $1"; }
fail() { echo -e "${RED}[FAIL]${NC} $1"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }

echo "==============================="
echo " eBPF 内核环境检查"
echo "==============================="
echo "日期: $(date '+%Y-%m-%d %H:%M:%S')"
echo ""

# --- 内核版本 ---
echo "--- 1. 内核版本 ---"
KV=$(uname -r)
KV_MAJOR=$(echo "$KV" | cut -d. -f1)
KV_MINOR=$(echo "$KV" | cut -d. -f2)
KV_NUM=$((KV_MAJOR * 100 + KV_MINOR))
echo "当前内核: $KV"
if [ "$KV_NUM" -ge 510 ]; then
    pass "内核版本 >= 5.10 (推荐版本)"
elif [ "$KV_NUM" -ge 504 ]; then
    warn "内核版本 5.x,建议升级到 5.10+"
elif [ "$KV_NUM" -ge 415 ]; then
    warn "内核版本 4.15+,基本可用,但缺少部分新特性"
else
    fail "内核版本过低 (<4.15),eBPF 支持有限"
fi

# --- 配置文件路径 ---
echo -e "\n--- 2. 内核配置检查 ---"
CONFIG_FILE="/boot/config-$(uname -r)"
if [ ! -f "$CONFIG_FILE" ]; then
    if [ -f "/proc/config.gz" ]; then
        CONFIG_SRC="zcat /proc/config.gz"
    else
        CONFIG_SRC=""
        warn "未找到内核配置文件,无法检查配置选项"
    fi
else
    CONFIG_SRC="cat $CONFIG_FILE"
fi

check_config() {
    local config=$1 required=$2
    if [ -z "$CONFIG_SRC" ]; then return; fi
    val=$(eval "$CONFIG_SRC" 2>/dev/null | grep "^${config}=" | cut -d= -f2)
    if [ "$val" = "y" ] || [ "$val" = "m" ]; then
        pass "$config=$val"
    else
        if [ "$required" = "required" ]; then
            fail "$config 未启用 (必需)"
        else
            warn "$config 未启用 (可选)"
        fi
    fi
}

check_config "CONFIG_BPF" "required"
check_config "CONFIG_BPF_SYSCALL" "required"
check_config "CONFIG_BPF_JIT" "required"
check_config "CONFIG_HAVE_EBPF_JIT" "required"
check_config "CONFIG_BPF_JIT_ALWAYS_ON" "optional"
check_config "CONFIG_DEBUG_INFO_BTF" "required"
check_config "CONFIG_DEBUG_INFO_BTF_MODULES" "optional"
check_config "CONFIG_BPF_UNPRIV_DEFAULT_OFF" "optional"
check_config "CONFIG_CGROUP_BPF" "optional"
check_config "CONFIG_BPF_LSM" "optional"
check_config "CONFIG_NET_CLS_BPF" "optional"
check_config "CONFIG_XDP_SOCKETS" "optional"

# --- BTF 检查 ---
echo -e "\n--- 3. BTF 调试信息 (CO-RE 依赖) ---"
if [ -f "/sys/kernel/btf/vmlinux" ]; then
    BTF_SIZE=$(stat -c%s /sys/kernel/btf/vmlinux 2>/dev/null || stat -f%z /sys/kernel/btf/vmlinux)
    pass "BTF 可用 (vmlinux BTF: $BTF_SIZE bytes)"
else
    fail "BTF 不可用 - CO-RE 程序将无法运行"
    echo "  解决方案:"
    echo "  1. 升级到 CONFIG_DEBUG_INFO_BTF=y 的内核"
    echo "  2. 或安装 pahole 工具重新编译内核"
fi

# --- JIT 状态 ---
echo -e "\n--- 4. BPF JIT 状态 ---"
JIT=$(cat /proc/sys/net/core/bpf_jit_enable 2>/dev/null || echo "N/A")
if [ "$JIT" = "1" ]; then
    pass "BPF JIT 已启用"
else
    fail "BPF JIT 未启用 (当前: $JIT)"
    echo "  解决: sudo sysctl -w net.core.bpf_jit_enable=1"
fi

# --- memlock 限制 ---
echo -e "\n--- 5. 内存锁定限制 ---"
MEMLOCK=$(ulimit -l)
if [ "$MEMLOCK" = "unlimited" ] || [ "$MEMLOCK" -ge 1048576 ]; then
    pass "memlock 限制充足 ($MEMLOCK KB)"
else
    warn "memlock 限制较低 ($MEMLOCK KB),可能影响 BPF 程序加载"
    echo "  解决: ulimit -l unlimited 或配置 CAP_BPF"
fi

# --- 工具链检查 ---
echo -e "\n--- 6. 工具链检查 ---"
check_tool() {
    if command -v "$1" &> /dev/null; then
        ver=$("$1" --version 2>&1 | head -1)
        pass "$1: $ver"
    else
        fail "$1: 未安装"
    fi
}
check_tool clang
check_tool llvm-strip
check_tool bpftool
check_tool bpftrace

# libbpf 检查
if pkg-config --exists libbpf 2>/dev/null; then
    pass "libbpf: $(pkg-config --modversion libbpf)"
else
    fail "libbpf: 未安装 (pkg-config 未找到)"
fi

echo -e "\n==============================="
echo " 检查完成"
echo "==============================="

2.4 开发环境搭建

2.4.1 VS Code eBPF 开发环境配置

推荐插件列表
插件名称 功能 必要性
ms-vscode.cpptools C/C++ 智能提示、调试 必需
llvm-vs-code-extensions.vscode-clangd Clangd 代码分析(替代 C/C++ 插件) 推荐
BPF ( Marketplace 搜索 ) BPF 语法高亮、代码片段 推荐
vadimcn.vscode-lldb LLDB 调试器集成 推荐
ms-python.python Python 开发(BCC 用) BCC 必需
xaver.clang-format 代码格式化 可选
GitHub.copilot AI 辅助编码 可选
VS Code 配置(.vscode/settings.json)
{
    "C_Cpp.default.includePath": [
        "${workspaceFolder}/**",
        "/usr/include/**",
        "/usr/include/x86_64-linux-gnu/**",
        "${workspaceFolder}/vmlinux.h"
    ],
    "C_Cpp.default.defines": [
        "__BPF_TRACING__",
        "__TARGET_ARCH_x86"
    ],
    "clangd.arguments": [
        "--clang-tidy",
        "--header-insertion=iwyu",
        "--completion-style=detailed"
    ],
    "files.associations": {
        "*.bpf.c": "c",
        "*.h": "c",
        "vmlinux.h": "c"
    },
    "[c]": {
        "editor.formatOnSave": true,
        "editor.defaultFormatter": "xaver.clang-format"
    }
}
调试配置(.vscode/launch.json)
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Debug eBPF Loader (LLDB)",
            "type": "lldb",
            "request": "launch",
            "program": "${workspaceFolder}/build/ebpf-loader",
            "args": [],
            "cwd": "${workspaceFolder}",
            "env": {
                "RUST_LOG": "debug"
            },
            "preLaunchTask": "build"
        },
        {
            "name": "Debug BCC Python",
            "type": "python",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal",
            "sudo": true
        }
    ]
}
构建任务(.vscode/tasks.json)
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build",
            "type": "shell",
            "command": "make",
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "problemMatcher": ["$gcc"]
        },
        {
            "label": "clean",
            "type": "shell",
            "command": "make clean"
        },
        {
            "label": "generate vmlinux.h",
            "type": "shell",
            "command": "bpftool btf dump file /sys/kernel/btf/vmlinux format c > ${workspaceFolder}/vmlinux.h",
            "problemMatcher": []
        }
    ]
}

2.4.2 Docker 容器化开发环境

Dockerfile 示例
# ===== eBPF 开发环境 Dockerfile =====
# 构建: docker build -t ebpf-dev:latest .
# 运行: docker run --rm -it --privileged -v $(pwd):/src ebpf-dev:latest

FROM ubuntu:22.04

LABEL maintainer="Pozicaiman"
LABEL description="eBPF Development Environment"

ENV DEBIAN_FRONTEND=noninteractive
ENV LLVM_VERSION=15

# 安装系统依赖和开发工具链
RUN apt-get update && apt-get install -y \
    build-essential cmake ninja-build git curl wget vim \
    pkg-config flex bison \
    clang-${LLVM_VERSION} llvm-${LLVM_VERSION} lld-${LLVM_VERSION} \
    llvm-${LLVM_VERSION}-dev libclang-${LLVM_VERSION}-dev \
    libelf-dev libzstd-dev \
    python3 python3-dev python3-pip \
    bison flex \
    gdb strace ltrace \
    iproute2 iputils-ping tcpdump net-tools \
    linux-tools-common kmod \
    && rm -rf /var/lib/apt/lists/*

# 创建 clang 符号链接
RUN ln -sf /usr/bin/clang-${LLVM_VERSION} /usr/bin/clang \
    && ln -sf /usr/bin/llvm-strip-${LLVM_VERSION} /usr/bin/llvm-strip \
    && ln -sf /usr/bin/llc-${LLVM_VERSION} /usr/bin/llc

# 编译安装 libbpf (1.3.0)
RUN git clone --depth 1 --branch v1.3.0 https://github.com/libbpf/libbpf.git /tmp/libbpf \
    && cd /tmp/libbpf/src \
    && make -j$(nproc) \
    && make install \
    && ldconfig \
    && rm -rf /tmp/libbpf

# 编译安装 bpftool
RUN git clone --depth 1 https://github.com/libbpf/bpftool.git /tmp/bpftool \
    && cd /tmp/bpftool/src \
    && make -j$(nproc) \
    && make install \
    && rm -rf /tmp/bpftool

# 安装 bpftrace(静态二进制)
RUN wget -qO /tmp/bpftrace.tar.gz \
    https://github.com/bpftrace/bpftrace/releases/latest/download/bpftrace-static-amd64.tar.gz \
    && tar xzf /tmp/bpftrace.tar.gz -C /usr/local/bin/ \
    && chmod +x /usr/local/bin/bpftrace \
    && rm /tmp/bpftrace.tar.gz

# 安装 BCC Python 绑定
RUN pip3 install bcc

# 设置工作目录
WORKDIR /src

# 默认命令
CMD ["/bin/bash"]
docker-compose 配置
# ===== docker-compose.yml =====
# 启动: docker compose run --rm ebpf-dev
version: '3.8'

services:
  ebpf-dev:
    build:
      context: .
      dockerfile: Dockerfile
    image: ebpf-dev:latest
    container_name: ebpf-dev
    privileged: true
    volumes:
      - ./src:/src
      - /sys/kernel/btf:/sys/kernel/btf:ro
      - /sys/kernel/tracing:/sys/kernel/tracing
      - /sys/kernel/debug:/sys/kernel/debug
      - /proc:/proc:rw
    network_mode: host
    mem_limit: 4g
    cap_add:
      - SYS_ADMIN
      - SYS_PTRACE
      - NET_ADMIN
      - BPF
    security_opt:
      - apparmor:unconfined
    environment:
      - KERNEL_VERSION=host
容器化开发环境拓扑

Volume 挂载

Docker 容器 ebpf-dev

宿主机 Host Machine

调试与工具

开发工具链

编译

BPF字节码

挂载卷访问内核

读取 BTF

CO-RE 重定位

bpf() syscall

JIT+挂载Hook

数据读取

事件读取

Linux Kernel
5.10+ with BPF

BTF: /sys/kernel/btf/vmlinux

BPF FS: /sys/fs/bpf

Tracing: /sys/kernel/tracing

Clang 15

LLVM 15

libbpf 1.3.0

bpftool

bpftrace

BCC Python

GDB

源码目录
/src

/sys/kernel/btf:ro

/sys/kernel/tracing

/sys/kernel/debug

/proc


2.4.3 Kubernetes 环境部署

eBPF 在 K8s 中的运行要求

在 Kubernetes 中运行 eBPF 程序需要注意以下要求:

  1. 特权模式:eBPF 加载需要 CAP_BPFCAP_SYS_ADMIN
  2. 文件系统挂载:需要访问 /sys/fs/bpf/sys/kernel/tracing/sys/kernel/debug
  3. 主机网络:网络观测类程序通常需要 hostNetwork: true
  4. 内核版本一致性:DaemonSet 模式下每个节点的内核版本应一致(或使用 CO-RE)
Pod Security 配置(DaemonSet 部署模式)
# ===== eBPF DaemonSet 部署清单 =====
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: ebpf-agent
  namespace: kube-system
  labels:
    app: ebpf-agent
spec:
  selector:
    matchLabels:
      app: ebpf-agent
  template:
    metadata:
      labels:
        app: ebpf-agent
    spec:
      hostNetwork: true
      hostPID: true
      hostIPC: false
      securityContext:
        privileged: true
        runAsUser: 0
        runAsGroup: 0
        seccompProfile:
          type: Unconfined
      tolerations:
        - operator: Exists
      containers:
        - name: ebpf-agent
          image: ebpf-agent:latest
          imagePullPolicy: IfNotPresent
          securityContext:
            privileged: true
            capabilities:
              add:
                - SYS_ADMIN
                - SYS_PTRACE
                - NET_ADMIN
                - BPF
                - PERFMON
                - SYS_RESOURCE
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 512Mi
          volumeMounts:
            - name: bpf-fs
              mountPath: /sys/fs/bpf
            - name: tracing-fs
              mountPath: /sys/kernel/tracing
            - name: debug-fs
              mountPath: /sys/kernel/debug
            - name: btf
              mountPath: /sys/kernel/btf
              readOnly: true
            - name: lib-modules
              mountPath: /lib/modules
              readOnly: true
            - name: proc
              mountPath: /proc
      volumes:
        - name: bpf-fs
          hostPath:
            path: /sys/fs/bpf
            type: DirectoryOrCreate
        - name: tracing-fs
          hostPath:
            path: /sys/kernel/tracing
            type: Directory
        - name: debug-fs
          hostPath:
            path: /sys/kernel/debug
            type: Directory
        - name: btf
          hostPath:
            path: /sys/kernel/btf
            type: Directory
        - name: lib-modules
          hostPath:
            path: /lib/modules
            type: Directory
        - name: proc
          hostPath:
            path: /proc
            type: Directory
      nodeSelector:
        kubernetes.io/os: linux
K8s 中 eBPF 部署架构

Kubernetes 集群

Node-3 内核 6.1

Node-2 内核 5.10

Node-1 内核 5.10

Control Plane

调度 DaemonSet

部署到每个节点

部署到每个节点

部署到每个节点

启动特权容器

启动特权容器

启动特权容器

bpf syscall
加载BPF程序

bpf syscall

bpf syscall

挂载卷

读取BTF(CO-RE)

重定位

挂载卷

读取BTF(CO-RE)

重定位

挂载卷

读取BTF(CO-RE)

重定位

观测数据/事件

观测数据/事件

观测数据/事件

kubelet

kube-apiserver

kube-scheduler

kubelet

kubelet

ebpf-agent Pod
(privileged)

ebpf-agent Pod
(privileged)

ebpf-agent Pod
(privileged)

BPF 程序
(内核空间)

BPF 程序
(内核空间)

BPF 程序
(内核空间)

/sys/fs/bpf

BTF: vmlinux

/sys/fs/bpf

BTF: vmlinux

/sys/fs/bpf

BTF: vmlinux

上图展示了 Kubernetes 中 eBPF Agent 的 DaemonSet 部署模式:每个节点运行一个特权 Pod,通过 CO-RE 机制读取节点本地的 BTF 信息进行重定位,加载 BPF 程序到各自节点的内核中。不同节点可以运行不同内核版本,CO-RE 保证了 BPF 程序的跨版本兼容性。


2.5 第一个 eBPF 程序

2.5.1 使用 BCC 编写 Hello World

BCC 提供了最简单的 eBPF 开发方式,通过 Python 定义和加载 BPF C 代码。

完整 Python+BCC 代码示例
#!/usr/bin/env python3
"""
第一个 eBPF 程序 - BCC Hello World
功能:追踪系统中的 execve() 系统调用,打印新进程信息
运行:sudo python3 hello_bcc.py
"""

from bcc import BPF
import time

# BPF C 程序代码
bpf_program = """
#include <uapi/linux/ptrace.h>
#include <linux/sched.h>

// 定义事件数据结构
struct event_t {
    u32 pid;
    u32 ppid;
    u64 timestamp;
    char comm[16];
    char filename[256];
};

// 定义 perf 事件 Map(用于内核到用户空间通信)
BPF_PERF_OUTPUT(events);

// 挂载到 execve 系统调用入口
int trace_execve(struct pt_regs *ctx,
                 const char __user *filename,
                 const char __user *const __user *__argv,
                 const char __user *const __user *__envp)
{
    struct event_t event = {};

    // 获取进程信息
    event.pid = bpf_get_current_pid_tgid() >> 32;
    event.ppid = bpf_get_current_task()->real_parent->tgid;
    event.timestamp = bpf_ktime_get_ns();
    bpf_get_current_comm(&event.comm, sizeof(event.comm));

    // 从用户空间安全读取文件名
    bpf_probe_read_user_str(&event.filename, sizeof(event.filename), filename);

    // 提交事件到 perf buffer
    events.perf_submit(ctx, &event, sizeof(event));

    return 0;
}
"""

def format_event(cpu, data, size):
    """处理来自内核的事件"""
    import ctypes as ct

    class Event(ct.Structure):
        _fields_ = [
            ("pid", ct.c_uint32),
            ("ppid", ct.c_uint32),
            ("timestamp", ct.c_uint64),
            ("comm", ct.c_char * 16),
            ("filename", ct.c_char * 256),
        ]

    event = ct.cast(data, ct.POINTER(Event)).contents
    ts = time.strftime("%H:%M:%S", time.localtime())
    print(f"[{ts}] PID={event.pid:6d} PPID={event.ppid:6d} "
          f"COMM={event.comm.decode():16s} FILE={event.filename.decode()}")


def main():
    print("eBPF Hello World - 追踪进程创建 (execve)")
    print("=" * 80)
    print(f"{'时间':>10s} {'PID':>8s} {'PPID':>8s} {'进程名':>18s} {'可执行文件'}")
    print("-" * 80)

    # 编译并加载 BPF 程序
    bpf = BPF(text=bpf_program)

    # 挂载到 execve 系统调用
    bpf.attach_kprobe(event="do_sys_openat2", fn_name="trace_execve")

    # 注册 perf 事件回调
    bpf["events"].open_perf_buffer(format_event)

    print("\n等待进程创建事件... (Ctrl+C 退出)\n")

    # 事件循环
    try:
        while True:
            bpf.perf_buffer_poll(timeout=100)
    except KeyboardInterrupt:
        print("\n\n退出追踪。")


if __name__ == "__main__":
    main()
运行和验证步骤
# 1. 确认 BCC 已安装
python3 -c "from bcc import BPF; print('BCC OK')"

# 2. 运行程序
sudo python3 hello_bcc.py

# 3. 在另一个终端触发 execve(执行命令)
ls
echo "hello"
cat /etc/hostname

# 4. 预期输出
# [14:30:01] PID= 12345 PPID= 12344 COMM=ls                FILE=/bin/ls
# [14:30:02] PID= 12346 PPID= 12344 COMM=echo               FILE=/bin/echo
# [14:30:03] PID= 12347 PPID= 12344 COMM=cat                FILE=/bin/cat
代码逐行解析
代码片段 说明
BPF_PERF_OUTPUT(events) 定义 perf 事件 Map,用于内核向用户空间推送事件
bpf_get_current_pid_tgid() >> 32 获取当前进程 PID(高 32 位为 tgid 即 PID)
bpf_get_current_task() 获取当前 task_struct 指针
bpf_probe_read_user_str() 安全地从用户空间读取字符串
events.perf_submit() 将事件数据提交到 perf buffer
bpf.attach_kprobe() 将 BPF 函数挂载到内核探针点
bpf["events"].open_perf_buffer() 在用户空间打开 perf buffer 接收数据
bpf.perf_buffer_poll() 轮询 perf buffer,触发回调函数

2.5.2 使用 libbpf+CO-RE 编写 Hello World

libbpf + CO-RE 是当前推荐的 eBPF 开发范式,具有编译一次到处运行的优势。

完整 C 代码示例

1. BPF 程序(hello.bpf.c)

/* hello.bpf.c - BPF 程序(运行在内核空间) */
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>

char LICENSE[] SEC("license") = "Dual BSD/GPL";

/* 定义事件数据结构 */
struct event {
    u32 pid;
    u32 ppid;
    u64 ts_ns;
    char comm[16];
};

/* 定义 Ring Buffer Map(高性能内核到用户空间通信) */
struct {
    __uint(type, BPF_MAP_TYPE_RINGBUF);
    __uint(max_entries, 256 * 1024);  /* 256KB */
} events SEC(".maps");

/* 挂载到 execve 系统调用(使用 tracepoint) */
SEC("tp/syscalls/sys_enter_execve")
int handle_execve(struct trace_event_raw_sys_enter *ctx)
{
    struct event *e;

    /* 从 ring buffer 预留空间 */
    e = bpf_ringbuf_reserve(&events, sizeof(*e), 0);
    if (!e)
        return 0;

    /* 填充事件数据 */
    e->pid = bpf_get_current_pid_tgid() >> 32;
    e->ppid = bpf_get_current_task()->real_parent->tgid;
    e->ts_ns = bpf_ktime_get_ns();
    bpf_get_current_comm(&e->comm, sizeof(e->comm));

    /* 提交事件 */
    bpf_ringbuf_submit(e, 0);

    return 0;
}

2. 用户空间加载器(hello.c)

/* hello.c - 用户空间加载器 */
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <sys/resource.h>
#include <bpf/libbpf.h>
#include <bpf/bpf.h>
#include "hello.skel.h"  /* CO-RE Skeleton 头文件 */

static volatile sig_atomic_t exiting = 0;

static void sig_handler(int sig)
{
    exiting = 1;
}

/* 事件结构(与 BPF 程序中定义一致) */
struct event {
    unsigned int pid;
    unsigned int ppid;
    unsigned long long ts_ns;
    char comm[16];
};

/* Ring Buffer 事件处理回调 */
static int handle_event(void *ctx, void *data, size_t data_sz)
{
    const struct event *e = data;
    struct tm *tm;
    char ts[32];
    time_t t;

    time(&t);
    tm = localtime(&t);
    strftime(ts, sizeof(ts), "%H:%M:%S", tm);

    printf("%-8s PID=%-7d PPID=%-7d COMM=%-16s\n",
           ts, e->pid, e->ppid, e->comm);

    return 0;
}

int main(int argc, char **argv)
{
    struct ring_buffer *rb = NULL;
    struct hello_bpf *skel;
    int err;

    /* 设置信号处理 */
    signal(SIGINT, sig_handler);
    signal(SIGTERM, sig_handler);

    /* 设置 memlock 限制(内核 < 5.11 需要) */
    struct rlimit rlim = {
        .rlim_cur = RLIM_INFINITY,
        .rlim_max = RLIM_INFINITY,
    };
    setrlimit(RLIMIT_MEMLOCK, &rlim);

    /* 打开 BPF 程序(Skeleton 加载) */
    skel = hello_bpf__open();
    if (!skel) {
        fprintf(stderr, "Failed to open BPF skeleton\n");
        return 1;
    }

    /* 加载 BPF 程序到内核 */
    err = hello_bpf__load(skel);
    if (err) {
        fprintf(stderr, "Failed to load BPF skeleton: %d\n", err);
        goto cleanup;
    }

    /* 挂载 BPF 程序到 tracepoint */
    err = hello_bpf__attach(skel);
    if (err) {
        fprintf(stderr, "Failed to attach BPF skeleton: %d\n", err);
        goto cleanup;
    }

    printf("Successfully started! Tracing execve... (Ctrl+C to exit)\n");
    printf("%-8s %-7s %-7s %s\n", "TIME", "PID", "PPID", "COMM");

    /* 设置 Ring Buffer */
    rb = ring_buffer__new(bpf_map__fd(skel->maps.events),
                          handle_event, NULL, NULL);
    if (!rb) {
        fprintf(stderr, "Failed to create ring buffer\n");
        goto cleanup;
    }

    /* 事件循环 */
    while (!exiting) {
        err = ring_buffer__poll(rb, 100);
        if (err == -EINTR) {
            err = 0;
            break;
        }
        if (err < 0) {
            fprintf(stderr, "Error polling ring buffer: %d\n", err);
            break;
        }
    }

cleanup:
    ring_buffer__free(rb);
    hello_bpf__destroy(skel);
    return err != 0;
}
Makefile 构建脚本
# ===== Makefile for libbpf + CO-RE eBPF 程序 =====
# 使用: make            # 编译
#       make run        # 编译并运行
#       make clean      # 清理
#       make vmlinux.h  # 生成 vmlinux.h

# 工具链
CLANG ?= clang
LLVM_STRIP ?= llvm-strip
BPFTOOL ?= bpftool
CC ?= gcc

# 目录
BUILD_DIR := build

# 编译参数
CFLAGS := -g -Wall -O2
BPF_CFLAGS := -O2 -g -target bpf -D__TARGET_ARCH_x86 \
              -I/usr/include/$(shell uname -m)-linux-gnu \
              -I.

# 目标文件
BPF_SRC := hello.bpf.c
BPF_OBJ := $(BUILD_DIR)/hello.bpf.o
BPF_SKEL := hello.skel.h
LOADER_SRC := hello.c
LOADER_OBJ := $(BUILD_DIR)/hello

# 默认目标
all: $(LOADER_OBJ)

# 生成 vmlinux.h
vmlinux.h:
	$(BPFTOOL) btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h

# 编译 BPF 程序为字节码
$(BPF_OBJ): $(BPF_SRC) vmlinux.h
	mkdir -p $(BUILD_DIR)
	$(CLANG) $(BPF_CFLAGS) -c $< -o $@
	$(LLVM_STRIP) -g $@

# 生成 Skeleton 头文件
$(BPF_SKEL): $(BPF_OBJ)
	$(BPFTOOL) gen skeleton $< > $@

# 编译用户空间加载器
$(LOADER_OBJ): $(LOADER_SRC) $(BPF_SKEL)
	mkdir -p $(BUILD_DIR)
	$(CC) $(CFLAGS) $< -o $@ -lbpf -lelf -lz

# 编译并运行
run: $(LOADER_OBJ)
	sudo ./$(LOADER_OBJ)

# 清理
clean:
	rm -rf $(BUILD_DIR) $(BPF_SKEL) vmlinux.h

.PHONY: all clean run vmlinux.h
编译加载运行完整流程
# 1. 生成 vmlinux.h(CO-RE 依赖,仅需一次)
bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h

# 2. 编译 BPF 程序为字节码
clang -O2 -g -target bpf -D__TARGET_ARCH_x86 \
    -I/usr/include/x86_64-linux-gnu -I. \
    -c hello.bpf.c -o build/hello.bpf.o

# 3. 剥离调试信息(减小体积)
llvm-strip -g build/hello.bpf.o

# 4. 生成 Skeleton 头文件
bpftool gen skeleton build/hello.bpf.o > hello.skel.h

# 5. 编译用户空间加载器
gcc -g -Wall -O2 hello.c -o build/hello -lbpf -lelf -lz

# 6. 运行(需要 root 或 CAP_BPF)
sudo ./build/hello

# 一键编译运行(使用 Makefile)
make run
编译加载流程图

clang -target bpf

llvm-strip -g

bpftool gen skeleton

bpftool btf dump

包含在编译中

gcc 编译

包含在编译中

libbpf API

运行时: 1. open skeleton

2. load 到内核

3. attach 到Hook

4. poll ringbuf

5. 事件回调

打印输出

hello.bpf.c
(BPF源码)

hello.bpf.o
(BPF字节码)

hello.bpf.o
(精简字节码)

hello.skel.h
(Skeleton头文件)

/sys/kernel/btf/vmlinux

vmlinux.h
(内核类型定义)

hello.c
(用户空间加载器)

hello
(可执行文件)

libbpf.so

hello_bpf__open()

hello_bpf__load()

hello_bpf__attach()

ring_buffer__poll()

handle_event()

控制台输出

上图展示了 libbpf + CO-RE 的完整编译加载流程:编译阶段将 BPF C 源码通过 Clang 编译为 BPF 字节码,再用 bpftool 生成 Skeleton 头文件;运行阶段通过 Skeleton API 依次完成 open、load、attach 三步加载 BPF 程序到内核,最后通过 ring buffer 轮询接收内核事件。


2.5.3 使用 bpftrace 一行命令

bpftrace 提供了极其简洁的一行命令语法,无需编写完整程序即可快速追踪系统行为。

bpftrace 快速示例
# 1. 统计各进程的 read() 调用次数(按 Ctrl+C 结束查看结果)
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_read { @[comm] = count(); }'

# 2. 追踪进程创建,打印进程名和 PID
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_execve { printf("%s -> %s\n", comm, str(args->filename)); }'

# 3. 统计系统调用延迟分布(直方图)
sudo bpftrace -e 'kprobe:vfs_read { @start[tid] = nsecs; } kretprobe:vfs_read /@start[tid]/ { @latency = hist(nsecs - @start[tid]); delete(@start[tid]); }'

# 4. 追踪文件打开事件
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s %s %s\n", comm, str(args->filename), str(args->mode)); }'

# 5. 按进程统计 TCP 连接
sudo bpftrace -e 'kprobe:tcp_v4_connect { @[comm] = count(); }'
常用 bpftrace 探针示例
# --- 进程相关 ---
# 追踪所有进程创建和退出
sudo bpftrace -e 'tracepoint:sched:sched_process_exec { printf("EXEC: %s pid=%d\n", comm, pid); } tracepoint:sched:sched_process_exit { printf("EXIT: %s pid=%d\n", comm, pid); }'

# --- 文件 I/O ---
# 追踪文件写入大小分布
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_write { @bytes[comm] = hist(args->count); }'

# --- 网络 ---
# 统计 TCP 连接目标 IP
sudo bpftrace -e 'kprobe:tcp_v4_connect { $daddr = (struct sockaddr_in *)arg1; @conns[ntop($daddr->sin_addr.s_addr)] = count(); }'

# --- 内存 ---
# 统计缺页中断
sudo bpftrace -e 'tracepoint:exceptions:page_fault_user { @[comm] = count(); }'

# --- 信号 ---
# 追踪信号发送
sudo bpftrace -e 'tracepoint:signal:signal_generate { printf("Signal %d -> %s (pid=%d)\n", args->sig, str(args->comm), args->pid); }'

# --- 定时统计 ---
# 每 5 秒打印一次系统调用统计
sudo bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[args->id] = count(); } interval:s:5 { print(@); clear(@); }'

# --- 运行 bpftrace 自带工具 ---
# 列出所有可用工具
ls /usr/share/bpftrace/tools/
# 运行工具(例如 biosnoop 追踪块设备 I/O)
sudo bpftrace /usr/share/bpftrace/tools/biosnoop.bt

2.6 验证环境完整性

2.6.1 完整环境验证脚本

以下脚本一次性检查所有 eBPF 组件是否正确安装和配置:

#!/bin/bash
# ===== eBPF 环境完整性验证脚本 =====
# 运行: sudo bash verify-ebpf-env.sh
# Author: Pozicaiman
# Date: 2026-07-24

set -euo pipefail

GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

PASS_COUNT=0
FAIL_COUNT=0
WARN_COUNT=0

pass() { echo -e "${GREEN}[PASS]${NC} $1"; ((PASS_COUNT++)); }
fail() { echo -e "${RED}[FAIL]${NC} $1"; ((FAIL_COUNT++)); }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; ((WARN_COUNT++)); }
info() { echo -e "${BLUE}[INFO]${NC} $1"; }

echo "=========================================="
echo " eBPF 环境完整性验证"
echo " $(date '+%Y-%m-%d %H:%M:%S')"
echo "=========================================="
echo ""

# --- 1. 内核版本 ---
echo "--- 1. 内核版本检查 ---"
KV=$(uname -r)
info "内核版本: $KV"
KV_NUM=$(echo "$KV" | awk -F. '{print $1*100+$2}')
if [ "$KV_NUM" -ge 510 ]; then
    pass "内核版本满足推荐要求 (>=5.10)"
else
    warn "内核版本 $KV,建议升级到 5.10+"
fi

# --- 2. BTF 检查 ---
echo -e "\n--- 2. BTF 调试信息 ---"
if [ -f /sys/kernel/btf/vmlinux ]; then
    pass "BTF 可用 (/sys/kernel/btf/vmlinux)"
else
    fail "BTF 不可用,CO-RE 程序无法运行"
fi

# --- 3. JIT 检查 ---
echo -e "\n--- 3. BPF JIT ---"
JIT=$(cat /proc/sys/net/core/bpf_jit_enable 2>/dev/null || echo "0")
if [ "$JIT" = "1" ]; then
    pass "BPF JIT 已启用"
else
    fail "BPF JIT 未启用 (当前: $JIT)"
fi

# --- 4. 工具链检查 ---
echo -e "\n--- 4. 工具链检查 ---"

# Clang
if command -v clang &> /dev/null; then
    CLANG_VER=$(clang --version | head -1)
    pass "Clang: $CLANG_VER"
else
    fail "Clang: 未安装"
fi

# LLVM
if command -v llc &> /dev/null; then
    pass "LLVM: $(llc --version | head -1)"
else
    fail "LLVM (llc): 未安装"
fi

# llvm-strip
if command -v llvm-strip &> /dev/null; then
    pass "llvm-strip: 已安装"
else
    fail "llvm-strip: 未安装"
fi

# libbpf
if pkg-config --exists libbpf 2>/dev/null; then
    pass "libbpf: $(pkg-config --modversion libbpf)"
else
    fail "libbpf: 未安装"
fi

# bpftool
if command -v bpftool &> /dev/null; then
    pass "bpftool: $(bpftool version 2>&1 | head -1)"
else
    fail "bpftool: 未安装"
fi

# bpftrace
if command -v bpftrace &> /dev/null; then
    pass "bpftrace: $(bpftrace --version)"
else
    warn "bpftrace: 未安装 (可选)"
fi

# BCC
if python3 -c "from bcc import BPF" 2>/dev/null; then
    pass "BCC Python 绑定: 已安装"
else
    warn "BCC Python 绑定: 未安装 (可选)"
fi

# --- 5. 内核配置检查 ---
echo -e "\n--- 5. 关键内核配置 ---"
CONFIG_SRC=""
if [ -f "/boot/config-$(uname -r)" ]; then
    CONFIG_SRC="cat /boot/config-$(uname -r)"
elif [ -f "/proc/config.gz" ]; then
    CONFIG_SRC="zcat /proc/config.gz"
fi

if [ -n "$CONFIG_SRC" ]; then
    for cfg in CONFIG_BPF CONFIG_BPF_SYSCALL CONFIG_BPF_JIT CONFIG_DEBUG_INFO_BTF; do
        val=$(eval "$CONFIG_SRC" 2>/dev/null | grep "^${cfg}=" | cut -d= -f2)
        if [ "$val" = "y" ] || [ "$val" = "m" ]; then
            pass "$cfg=$val"
        else
            fail "$cfg 未启用"
        fi
    done
else
    warn "无法读取内核配置文件"
fi

# --- 6. memlock 限制 ---
echo -e "\n--- 6. 内存锁定限制 ---"
MEMLOCK=$(ulimit -l)
if [ "$MEMLOCK" = "unlimited" ] || [ "$MEMLOCK" -ge 1048576 ]; then
    pass "memlock 限制充足 ($MEMLOCK)"
else
    warn "memlock 限制较低 ($MEMLOCK KB)"
fi

# --- 7. 权限检查 ---
echo -e "\n--- 7. 权限检查 ---"
if [ "$(id -u)" = "0" ]; then
    pass "当前为 root 用户"
else
    if [ "$KV_NUM" -ge 511 ]; then
        info "内核 5.11+ 支持 CAP_BPF,非 root 用户可使用能力运行"
    else
        warn "非 root 用户,且内核 < 5.11,需 root 运行 BPF 程序"
    fi
fi

# --- 汇总 ---
echo -e "\n=========================================="
echo " 验证结果汇总"
echo "=========================================="
echo -e "  ${GREEN}通过: $PASS_COUNT${NC}"
echo -e "  ${RED}失败: $FAIL_COUNT${NC}"
echo -e "  ${YELLOW}警告: $WARN_COUNT${NC}"
echo "=========================================="

if [ "$FAIL_COUNT" -gt 0 ]; then
    echo -e "\n${RED}存在失败项,请根据上述提示修复后重新验证。${NC}"
    exit 1
else
    echo -e "\n${GREEN}环境验证通过!可以开始 eBPF 开发。${NC}"
    exit 0
fi

2.6.2 运行测试 BPF 程序验证功能

使用一个最小化的 BPF 程序验证加载和运行功能:

#!/bin/bash
# ===== 测试 BPF 程序加载与运行 =====

echo "=== 测试 1: bpftool 探测内核特性 ==="
sudo bpftool feature probe | head -20
echo ""

echo "=== 测试 2: bpftrace 最小程序 ==="
# 运行一个简单的 bpftrace 程序,5秒后自动退出
sudo timeout 5 bpftrace -e 'BEGIN { printf("Hello eBPF! bpftrace works.\n"); exit(); }'
if [ $? -eq 0 ]; then
    echo "[OK] bpftrace 运行正常"
else
    echo "[FAIL] bpftrace 运行失败"
fi
echo ""

echo "=== 测试 3: BCC 最小程序 ==="
sudo python3 -c "
from bcc import BPF
bpf = BPF(text='int kprobe__sys_clone(void *ctx) { bpf_trace_printk(\"Hello from BCC!\\n\"); return 0; }')
print('[OK] BCC 程序加载成功')
import time; time.sleep(1)
" 2>&1 && echo "[OK] BCC 运行正常" || echo "[FAIL] BCC 运行失败"
echo ""

echo "=== 测试 4: 检查 BPF 程序是否在内核中 ==="
sudo bpftool prog show 2>/dev/null | head -10
echo ""

echo "=== 测试 5: Ring Buffer / Perf Buffer ==="
# 验证 ringbuf map 类型支持
sudo bpftool feature probe map_types 2>/dev/null | grep -i ringbuf
echo ""

2.6.3 性能基准测试

使用以下脚本测试 BPF 程序的执行延迟和事件吞吐量:

#!/bin/bash
# ===== eBPF 性能基准测试 =====
# 测量 BPF 程序的事件处理延迟和吞吐量

echo "=== eBPF 性能基准测试 ==="
echo "日期: $(date)"
echo "内核: $(uname -r)"
echo "CPU: $(grep 'model name' /proc/cpuinfo | head -1 | cut -d: -f2 | xargs)"
echo ""

# 测试 1: bpftrace 事件吞吐量(10秒内捕获的 syscall 数量)
echo "--- 测试 1: 系统调用吞吐量 (10秒) ---"
sudo timeout 10 bpftrace -e '
BEGIN { printf("开始统计系统调用...\n"); }
tracepoint:raw_syscalls:sys_enter { @count++; }
END { printf("10秒内系统调用总数: %d\n", @count); printf("平均每秒: %d\n", @count/10); clear(@count); }
' 2>&1

echo ""

# 测试 2: BPF 程序执行延迟(使用 kprobe 测量 nanoseconds)
echo -e "\n--- 测试 2: BPF 程序执行延迟 ---"
sudo timeout 5 bpftrace -e '
kprobe:vfs_read { @start[tid] = nsecs; }
kretprobe:vfs_read /@start[tid]/ {
    @latency_ns = nsecs - @start[tid];
    delete(@start[tid]);
}
END {
    printf("vfs_read 延迟分布 (nanoseconds):\n");
    print(@latency_ns);
    clear(@latency_ns);
}
' 2>&1

echo ""

# 测试 3: BPF JIT 编译验证
echo -e "\n--- 测试 3: JIT 编译状态 ---"
echo "BPF JIT 启用状态: $(cat /proc/sys/net/core/bpf_jit_enable)"
echo "JIT 硬件卸载: $(cat /proc/sys/net/core/bpf_jit_harden)"
echo ""
echo "已加载 BPF 程序的 JIT 状态:"
sudo bpftool prog show 2>/dev/null | grep -E "id|name|xlated|jited" | head -20

echo ""
echo "=== 基准测试完成 ==="

性能参考值:在典型 x86_64 服务器上,单个 BPF 程序的执行延迟通常在 50-200 纳秒范围内。JIT 编译后的 BPF 程序性能接近原生代码,比解释执行快 2-4 倍。


2.7 常见安装问题与解决方案

2.7.1 内核版本不兼容问题

现象:加载 BPF 程序时报错 Invalid argumentOperation not supported,程序中使用了较新内核才支持的特性。

排查步骤

# 1. 检查当前内核版本
uname -r

# 2. 使用 bpftool 探测内核支持的 BPF 特性
sudo bpftool feature probe

# 3. 检查 BPF 程序使用的 helper 函数是否被内核支持
sudo bpftool feature probe | grep "bpf_probe_read"

# 4. 查看 dmesg 中 BPF 相关错误
sudo dmesg | grep -i bpf | tail -20

根因:BPF 程序使用了当前内核版本不支持的特性(如 ring buffer 需要 5.8+,bpf_timer 需要 5.15+)。

解决方案

问题场景 解决方案
内核版本过低 升级到 5.10+ LTS 内核(推荐 HWE 内核)
缺少特定 helper 函数 降级使用旧 API(如 perf_buffer 替代 ringbuf)
Ubuntu 使用 HWE 内核 sudo apt install linux-generic-hwe-22.04
RHEL 激活新内核 dnf install kernel-rt 或使用 ELRepo
无法升级内核 使用 BCC(运行时编译,非 CO-RE)替代 libbpf
# Ubuntu 升级 HWE 内核示例
sudo apt update
sudo apt install --install-recommends linux-generic-hwe-22.04
sudo reboot

# 重启后验证
uname -r

2.7.2 缺少 BTF 信息问题

现象:CO-RE 程序加载失败,报错 Error loading .BTF: No such file or directoryfailed to find kernel BTF

排查步骤

# 1. 检查 BTF 文件是否存在
ls -la /sys/kernel/btf/vmlinux

# 2. 检查内核配置
grep CONFIG_DEBUG_INFO_BTF /boot/config-$(uname -r)

# 3. 尝试用 bpftool 读取 BTF
bpftool btf dump file /sys/kernel/btf/vmlinux format c | head -10

根因:内核编译时未启用 CONFIG_DEBUG_INFO_BTF=y,或 BTF 文件缺失。

解决方案

# 方案 1:安装 BTF 信息包(部分发行版提供独立包)
# Ubuntu/Debian
sudo apt install linux-modules-extra-$(uname -r)
# 检查是否生成 BTF
ls /sys/kernel/btf/vmlinux

# 方案 2:使用 BTFHub 获取 BTF 信息(适用于无 BTF 的发行版)
git clone https://github.com/aquasecurity/btfhub.git
cd btfhub
# 生成当前内核的 BTF 文件
./btfhub.sh

# 方案 3:重新编译内核(启用 BTF)
# 需要安装 pahole (dwarves 包)
sudo apt install dwarves
# 在内核配置中启用
# CONFIG_DEBUG_INFO_BTF=y
# CONFIG_DEBUG_INFO=y

2.7.3 权限问题(CAP_BPF 配置)

现象:非 root 用户运行 BPF 程序报错 Operation not permitted

排查步骤

# 1. 检查非特权 BPF 是否被禁用
cat /proc/sys/kernel/unprivileged_bpf_disabled
# 0=允许非特权, 1=禁止(可改), 2=禁止(不可改)

# 2. 检查当前用户能力
capsh --print | grep bpf

# 3. 检查内核版本是否支持 CAP_BPF
uname -r  # 需要 5.8+

解决方案

# 方案 1:为可执行文件设置能力(内核 5.8+)
sudo setcap cap_bpf,cap_perfmon,cap_net_admin+ep ./hello

# 方案 2:使用 sudo 运行
sudo ./hello

# 方案 3:临时允许非特权 BPF(不推荐,安全风险)
sudo sysctl -w kernel.unprivileged_bpf_disabled=0

# 方案 4:将用户加入 bpf 组并配置 udev 规则
sudo groupadd bpf
sudo usermod -aG bpf $USER
# 配置 /etc/security/limits.conf 允许 bpf 组使用 memlock

2.7.4 内存锁定限制问题

现象:加载 BPF 程序报错 Unable to lock memory: Cannot allocate memory 或 RLIMIT_MEMLOCK 相关错误。

排查步骤

# 检查当前 memlock 限制
ulimit -l
# 默认通常为 64KB 或 8MB

# 检查 BPF 程序使用的锁定内存
grep -i bpf /proc/meminfo

解决方案

# 方案 1:临时调整(当前会话生效)
ulimit -l unlimited

# 方案 2:永久调整(limits.conf)
sudo tee -a /etc/security/limits.conf << 'EOF'
*    soft    memlock    unlimited
*    hard    memlock    unlimited
EOF
# 注销重新登录生效

# 方案 3:使用 CAP_BPF(内核 5.11+,不需要 memlock)
sudo setcap cap_bpf+ep ./hello

# 方案 4:systemd 服务配置
# 在 service 文件中添加:
# [Service]
# LimitMEMLOCK=infinity

2.7.5 编译错误排查

现象:编译 BPF 程序时出现各种编译错误。

常见编译错误与解决方案

错误信息 原因 解决方案
error: unknown type name 'u32' 缺少 vmlinux.h 或类型定义 #include "vmlinux.h"
error: 'BPF_MAP_TYPE_RINGBUF' undeclared 内核版本过低或 libbpf 版本过低 升级 libbpf 到 1.0+ 或使用 perf_buffer
clang: error: unknown target triple 'bpf' Clang 未编译 BPF 后端 安装支持 BPF 的 clang 版本
error: cannot find -lbpf libbpf 未安装或路径不对 sudo apt install libbpf-dev
error: 'bpf_ringbuf_reserve' undeclared libbpf 版本过低 升级 libbpf 到 0.6+
error: 'SEC' undeclared 缺少 bpf_helpers.h #include <bpf/bpf_helpers.h>
BPF_VERIFY: invalid bpf_context access 访问了错误的上下文字段 检查探针类型与上下文结构匹配

调试编译问题

# 1. 检查 clang 是否支持 BPF target
echo 'int x = 0;' | clang -target bpf -c -x c - -o /dev/null && echo "BPF target OK"

# 2. 查看编译详细输出
clang -v -target bpf -c hello.bpf.c -o hello.bpf.o 2>&1

# 3. 检查生成的 BPF 对象文件
llvm-objdump -d hello.bpf.o | head -30

# 4. 使用 bpftool 检查 BPF 对象
bpftool prog loadall hello.bpf.o /sys/fs/bpf/hello type tracepoint 2>&1

# 5. 查看验证器日志(加载时加 -v 参数)
sudo ./hello -v  # 或设置环境变量

验证器错误排查

# 当 BPF 程序被验证器拒绝时,查看详细日志
# 在用户空间代码中设置调试输出:
# libbpf_set_print(bpf_printf);

# 或使用 bpftool 直接加载查看验证器日志
sudo bpftool prog load hello.bpf.o /sys/fs/bpf/test \
    type tracepoint 2>&1

# 常见验证器错误:
# - "invalid bpf_context access" → 上下文字段访问错误
# - "back-edge in cfg" → 循环不受限(需要 #pragma unroll)
# - "0-size record" → 结构体大小为 0
# - "reached insn limit" -> 程序指令数超限(默认 100 万条)

2.8 本章小结

本章全面介绍了 eBPF 开发环境的搭建过程,涵盖从内核要求到工具链安装、从开发环境配置到第一个程序运行的完整流程。

核心要点回顾

知识点 关键内容
内核版本 推荐 5.10+ LTS,最低 4.18+;CO-RE 需要 5.0+
内核配置 必须启用 CONFIG_BPF、CONFIG_BPF_SYSCALL、CONFIG_BPF_JIT、CONFIG_DEBUG_INFO_BTF
BTF 信息 CO-RE 的基础依赖,通过 /sys/kernel/btf/vmlinux 检查可用性
Clang/LLVM 推荐 12+,用于将 C 源码编译为 BPF 字节码
libbpf 推荐 1.0+,CO-RE 程序加载库,向后兼容旧内核
BCC 高层开发框架,Python 绑定,适合快速原型和运维工具
bpftrace 一行命令式追踪语言,适合快速排障和临时分析
bpftool 内核官方 BPF 管理工具,用于查看/加载/调试 BPF 程序
CO-RE Compile Once - Run Everywhere,基于 BTF 实现跨内核版本兼容
CAP_BPF 内核 5.8+ 引入,5.11+ 允许非特权用户运行 BPF 程序
容器化 Docker 需要特权模式或 CAP_BPF;K8s 使用 DaemonSet 部署

环境搭建快速路径

根据不同需求,推荐以下环境搭建路径:

快速试用/排障

BCC 开发

CO-RE 生产开发

容器化开发

K8s 集群部署

环境需求

开发场景?

安装 bpftrace
+ bpftool

安装 BCC
+ Python 绑定

libbpf + Clang
+ bpftool

Docker 镜像
ebpf-dev

DaemonSet
+ CO-RE

验证环境
verify-ebpf-env.sh

第一个程序
Hello World

环境就绪

下章预告

本章完成了 eBPF 开发环境的搭建和验证。第三章将深入 eBPF 的核心概念,包括:

  • eBPF 架构详解:验证器、JIT 编译器、BPF 虚拟机的工作原理
  • BPF 程序类型:kprobe、tracepoint、XDP、tc、cgroup 等各类型详解
  • BPF Map 类型:Hash、Array、Ring Buffer、PerCPU 等数据结构
  • BPF Helper 函数:内核提供的辅助函数库
  • CO-RE 机制深入:BTF、重定位、Skeleton 的底层原理

实践建议:在进入第三章前,建议读者完整运行本章的验证脚本和 Hello World 程序,确保开发环境完全就绪。后续章节的代码示例均基于本章搭建的环境。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐