【BPF入门系列-8】文件打开记录跟踪之 perf_event 篇
1. ebpf_perf_output 介绍
在上一篇 ”使用 ebpf 实时持续跟踪进程文件记录“ 中,我们简单介绍了使用 eBPF 跟踪文件打开记录的跟踪。为了简单演示功能,我们直接使用了 bpf_trace_printk
进行演示,正如上文所述,bpf_trace_printk
存在一些限制:
- 最大只支持 3 个参数,而且只运行一个 %s 的参数;
- 程序共享输出共享
/sys/kernel/debug/tracing/trace_pipe
文件,可能导致文件输出错乱; - 该实现方式在数据量大的时候,性能也存在一定的问题;
本文中我们将使用更加高效且提供隔离功能的 BPF_PERF_OUTPUT
机制来实现数据的传递,而且由于数据通过结构体定义的方式,也不存在参数数量和数据大小等限制。
为了使用 BPF_PERF_OUTPUT
机制,需要约定 Probe 程序和用户空间程序的通信协议。相比简单使用 bpf_trace_printk
,在内核中的 Probe 程序需要以下操作:
-
定义一个通信的结构体,用于 Probe 程序与用户空间通信程序的数据传输约定;
-
定一个用于通信的 perf_event 对象,BCC 提供了宏
BPF_PERF_OUTPUT
实现; -
内核中的 Probe 程序捕获事件,将数据按照第一步定义好的结构体填充,并将
event
事件发布;
在用户空间程序,在本文中为基于 BCC 的 Python代码:
- 定义和声明通信的结构体;(基于 BCC 的程序已经自动生成,无需再定义)
- 定义消费
event
事件的函数; - 持续消费事件程序;
2. 代码实现
原始代码如下:
|
|
按照上述的步骤,调整后的 Probe 的程序如下:
|
|
这里将详细介绍我们进行的相关调整:
- 定义了内核 Probe 程序与用户空间程序通信的结构体
event_data_t
,包含pid
和filename
两个字段; - 使用 BCC 提供的宏
BPF_PERF_OUTPUT(open_events)
完成内核中open_events
变量的定义; - 在
trace_syscall_open
函数中,增加变量的定义struct event_data_t evt = {};
,需要注意的是结构体变量evt.fname
的赋值,需要使用 eBPF 提供的辅助函数bpf_probe_read
来帮助,这是因为内核对于非简单类型的赋值需要进行安全边界的检查,避免在内核中进行越界访问,破坏内核稳定性和安全性的保障; - 最后,使用
open_events.perf_submit
将event
数据发送至用户空间;
上述代码,完成了我们在内核 Probe 程序中的所有工作。用户空间 Python 程序则需要定义 event
消费函数,并使用 perf_buffer_poll
函数轮训消费即可。
|
|
在用户空间的 Python 代码中,当前我们只需要定义事件处理函数,将事件与函数进行关联,然后持续轮询数据即可。
-
我们定义了事件处理函数
print_event
,然后读取出对应的数据并生成结构数据 ,event = b["open_events"].event(data)
,此处不用再声明 Python 中的结构体变量,BCC 已经协助处理,否则需要我们显示定义,在一些早期的 BCC 代码中还可以看到手工转换的场景。1 2 3 4 5 6 7 8 9
import ctypes class OpenEvt(ctypes.Structure): _fields_ = [ ("pid", ctypes.c_uint), ("fname", ctypes.c_char * MAX_STR_LEN), ] # event 处理函数中强制 cast 使用 # event = ct.cast(data, ct.POINTER(OpenEvt)).contents
-
然后在主体函数中使用
b.perf_buffer_poll()
持续轮询即可;
运行结果如下:
|
|
完整样例可以参考 open_perf_output.py。
3. 总结
通过我们上述代码样例,相信你已经非常熟悉了如何使用 BPF_PERF_OUTPUT 方式,在直接编写的各种跟踪程序中,优先推荐使用这种方式进行高效的数据通信。
- 原文作者:DavidDi
- 原文链接:https://www.ebpf.top/post/ebpf_trace_file_open_perf_output/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. 进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。
- 最后更新时间:2022-11-05 21:36:52.023111886 +0800 CST