1. 参考资料
在eBPF的学习过程中,主要是跟着Linux内核之旅开源社区进行学习,在此非常感谢Linux内核之旅开源社区让我少走了很多的弯路,这种乐于分享的精神值得敬佩与学习。
2. BCC简介
目前可以在kernel用 C 来实现 eBPF程序,但编译出来的却仍然是 ELF 文件,无法直接注入内核,需要另外编译一个C用户空间程序进行注入,而BCC实现了一步到位生成出 eBPF 代码并注入到内核。
BCC(BPF Compiler Collection) 是一个 python 库,其中有很大一部分的实现是基于 C 和 C++的,python 是实现对 BCC 应用层接口的封装。使用 BCC 进行 eBPF 的开发仍然需要我们自行利用 C 来设计 BPF 程序,但编译、解析 ELF、加载 BPF 代码块以及创建 map 等可以由 BCC框架实现。
3. 安装BCC
sudo apt-get install bpfcc-tools linux-headers-$(uname -r)
4. hello_world示例
下面介绍一个简单的例子,创建一个文件hello_world.py,代码如下:
from bcc import BPF
BPF(text='int kprobe__sys_clone(void *ctx) { bpf_trace_printk("Hello, World!\\n"); return 0; }').trace_print()
可以看到,这段代码是在 python 中内嵌 C 语言程序的,请注意六点:
text='...'这里定义了一个内联的、C 语言写的 BPF 程序。kprobe__sys_clone()这是一个通过内核探针(kprobe)进行内核动态跟踪的快捷方式。如果一个 C 函数名开头为 kprobe__ ,则后面的部分实际为设备的内核函数名,这里是 sys_clone() 。- void *ctx 这里的 ctx 实际上有一些参数,不过这里我们用不到,暂时转为 void * 。
bpf_trace_printk()这是一个简单的内核工具,用于 printf() 到 trace_pipe(译者注:可以理解为 BPF C 代码中的 printf())。它一般来快速调试一些东西,不过有一些限制:最多有三个参数,一个%s ,并且 trace_pipe 是全局共享的,所以会导致并发程序的输出冲突,因而 BPF_PERF_OUTPUT() 是一个更棒的方案,我们后面会提到。- return 0 这是一个必须的部分。
trace_print()一个 bcc 实例会通过这个读取 trace_pipe 并打印出来。
使用如下命令运行此示例:
sudo python3 hello_world.py
可以看到有新进程被创建,程序打印出“Hello, World!”。