eBPF入门教程(Ubuntu 24.04)

发布于:2025-02-11 ⋅ 阅读:(12) ⋅ 点赞:(0)

在当今的系统性能优化领域, eBPF(Extended Berkeley Packet Filter)正发挥着越来越重要的作用. 它不仅能够深入系统底层, 实现精准的性能跟踪, 还拥有内置的高性能网络功能, 甚至可以有效地检测系统中的恶意行为. 这些优势使得 eBPF 成为了系统开发和运维人员手中的一把利器.

环境准备

需要明确的是, eBPF 并非普通的应用层软件, 它与内核紧密相关. 因此, 确保系统内核版本的一致性至关重要. 以下是本文所使用的演示环境:

操作系统

  • Ubuntu 24.04
    • 内核版本: 6.8.0-52-generic
    • 处理器架构: x86_64

依赖软件安装

在开始使用 eBPF 之前, 需要安装一些必要的依赖软件. 打开终端, 依次执行以下命令:

sudo apt update
sudo apt install libelf-dev libbpf-dev python3-bpfcc bpfcc-tools libbpfcc-dev
sudo apt install linux-headers-$(uname -r)

虚拟机环境(可选)

如果你希望在一个独立的虚拟机环境中进行实验, 以避免对现有系统造成影响, vagrant 是一个不错的选择. 本文使用的基础镜像是: bento/ubuntu-24.04.

eBPF Hello World

编写 eBPF 程序有多种方法, 为了帮助新手快速入门, 这里我们选择使用 BCC Python 框架. 下面将展示一个简单的示例, 该示例会挂载(hook)在系统调用 execve 上, 每当这个系统调用被触发时, 程序会打印一句 "Hello eBPF!".

步骤 1: 创建 Python 脚本

创建一个名为 hello.py 的文件, 并将以下代码复制到该文件中:

from bcc import BPF

# 定义 eBPF 程序, 使用 C 语言编写
program = r"""
int hello(void *ctx) {
    // 打印输出信息
    bpf_trace_printk("Hello eBPF!");
    return 0;
}
"""

# 初始化 BPF 对象, 将 C 语言程序交给 bcc 处理
b = BPF(text=program)

# 获取 execve 系统调用的函数名
syscall = b.get_syscall_fnname("execve")

# 将 eBPF 程序挂载到 execve 系统调用上
b.attach_kprobe(event=syscall, fn_name="hello")

# 输出日志信息
b.trace_print()

步骤 2: 执行脚本

由于 eBPF 程序需要在内核中运行, 因此需要使用 sudo 权限来执行脚本:

sudo python3 hello.py

步骤 3: 观察输出

执行脚本后, 你会看到类似如下的输出:

b'            sshd-2548    [000] ...21   963.948685: bpf_trace_printk: Hello eBPF!'
b'              sh-2549    [000] ...21   963.950330: bpf_trace_printk: Hello eBPF!'
b'             env-2549    [000] ...21   963.951490: bpf_trace_printk: Hello eBPF!'
b'             env-2549    [000] ...21   963.951551: bpf_trace_printk: Hello eBPF!'
b'             env-2549    [000] ...21   963.951557: bpf_trace_printk: Hello eBPF!'
b'             env-2549    [000] ...21   963.951562: bpf_trace_printk: Hello eBPF!'
b'       run-parts-2550    [001] ...21   963.953146: bpf_trace_printk: Hello eBPF!'
b'           <...>-2551    [000] ...21   963.955544: bpf_trace_printk: Hello eBPF!'
b'           <...>-2552    [000] ...21   963.957097: bpf_trace_printk: Hello eBPF!'
b'           <...>-2553    [000] ...21   963.958475: bpf_trace_printk: Hello eBPF!'
b'           <...>-2554    [001] ...21   963.959866: bpf_trace_printk: Hello eBPF!'
...

需要注意的是, 输出结果会根据当时机器上正在执行的程序而有所不同.

样例解析

1. eBPF 程序的定义

在上述示例中, program 变量存储的是一段 C 语言编写的 eBPF 程序: