eBPF学习笔记(二)——Hello World
(英文书看嘛了,我好像在翻译?)
Hello World
Code
#!/usr/bin/python
from bcc import BPF
program = r"""
int hello(void *ctx) {
bpf_trace_printk("Hello World!");
return 0;
}
"""
b = BPF(text=program)
syscall = b.get_syscall_fnname("execve")
b.attach_kprobe(event=syscall, fn_name="hello")
b.trace_print()
解读

hello()是将要在内核中运行的程序, 但这个python程序是运行在用户空间的
而hello()中只是使用了helper function: bpf_trace_printk("Hello World!")去输出一个消息
帮助程序函数是将“extend”BPF 与其“classic”前身区分开来的另一个特性。它们是 eBPF 程序可以调用的一组函数,用于与系统交互
但是这个C代码需要先编译成二进制文件才能运行
b = BPF(text=program)
此时将返回一个BPF对象(这里都是使用python进行学习,仅仅是方便演示.但最终生产环境还是应该脱离python,手动编译)
syscall = b.get_syscall_fnname("execve")
此处我们选择将eBPF程序附加到system call execve()上.虽然 “execve()” 是 Linux 中的标准接口,但在内核中实现它的函数名称取决于芯片架构. 好在BCC 为我们提供了一种方便的方法来查找我们正在运行的机器的函数名称,在此处用syscall储存返回的函数名称
使用kprobe可以将可以将hello附加到该事件中:
b.attach_kprobe(event=syscall, fn_name="hello")
此时,eBPF 程序被加载到内核中并附加到一个事件中,因此每当在机器上启动新的可执行文件时,都会触发该程序。在 Python 代码中剩下要做的就是读取内核输出的跟踪并将其写入屏幕上:
b.trace_print()//将会无限循环

这是书中所给示意图. 很显然可以看到每当有execve调用时,都回触发hello()的执行调用,并且将一行trace写入 pseudofile(伪文件) 中. python程序再从pseudofile中读取trace消息并显示.
伪文件位置:/sys/kernel/debug/tracing/trace_pipe
此实例中只支持字符串的输出,对于传递 structure作用甚微.尤其是当多个eBPF程序同时运行时,对同一跟踪管道进行写入------会导致一些紊乱.
因此使用 eBPF map是必要的
[eBPF Map]

浙公网安备 33010602011771号