在当今的系统性能优化领域, 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 程序: