type
Post
status
Published
slug
2023/01/06/bpf-example-program-tracepoint
summary
tags
Linux
Python
BPF
eBPF
category
BPF
icon
password
new update day
Property
Oct 22, 2023 01:31 PM
created days
Last edited time
Oct 22, 2023 01:31 PM
跟踪点是内核代码的静态标记,可用于将代码附加在运行的内核中。跟踪点跟 kprobes 的主要区别在于跟踪点由内核开发人员在内核中编写和修改。这就是我们将跟踪点称作静态的原因。由于跟踪点是静态存在的,所以跟踪点的 ABI更稳定。内核保证旧版本上跟踪点将在新版本上存在。但是,考虑到跟踪点添加是由内核开发人员添加的,所以跟踪点可能并不会涵盖到内核的所有子系统。
通过查看 /sys/kernel/debug/tracing/events 目录下的内容可以查看系统中所有可用的跟踪点。例如查看 BPF 可用的所有的跟踪点:
notion image
编写使用跟踪点的 BPF 程序与编写 kprobes 跟踪程序类似。下面的示例是使用 BPF 程序跟踪系统中加载的其他 BPF 程序:

example.py

from bcc import BPF bpf_source = """ int trace_bpf_prog_load(struct pt_regs *ctx) { char comm[16]; bpf_get_current_comm(&comm, sizeof(comm)); bpf_trace_printk("%s is loading a BPF program", comm); return 0; } """ bpf = BPF(text = bpf_source) bpf.attach_tracepoint(tp = "syscalls:sys_enter_bpf", fn_name = "trace_bpf_prog_load") bpf.trace_print()
程序的主要区别是:不是将程序附加到 kprobe 上,而是将其附加到跟踪点上。BCC 遵循追踪点命名约定,首先是指定要跟踪的子系统,这里是 syscalls: ,然后是子系统中的跟踪点 sys_enter_bpf。这意味着每次内核执行 sys_enter_bpf 函数时,该程序将会收到该事件,并打印执行 sys_enter_bpf 指令的应用程序名称。
内核探针和跟踪点提供了对内核的完全访问。由于跟踪点更加安全,我们推荐尽可能使用跟踪点,当然这不是强制的。在某些场景下,我们也需要利用内核探针的动态性质。

运行结果展示

[root@bpfbook bpf_fs]# ./save Failed to create map: -1 (Operation not permitted) [root@bpfbook chapter-3]# ./fetch Value read from the map: '4567' [root@bpfbook chapter-3]# ./update Value update from the map: '4567' [root@bpfbook chapter-3]# ./delete Failed to delete value from the map: -1 (Invalid argument)
python3 ./example.py save-31505 [000] .... 20855.048509: 0: save is loading a BPF program fetch-31508 [000] .... 20869.206237: 0: fetch is loading a BPF program fetch-31508 [000] .... 20869.206448: 0: fetch is loading a BPF program update-31509 [000] .... 20874.848160: 0: update is loading a BPF program update-31509 [000] .... 20874.848219: 0: update is loading a BPF program delete-31510 [000] .... 20886.692936: 0: delete is loading a BPF program delete-31510 [000] .... 20886.693011: 0: delete is loading a BPF program python3-31513 [000] .... 21077.873097: 0: python3 is loading a BPF program python3-31513 [000] .... 21077.873344: 0: python3 is loading a BPF program python3-31513 [000] .... 21077.874825: 0: python3 is loading a BPF program python3-31513 [000] .... 21077.875207: 0: python3 is loading a BPF program python3-31513 [000] .... 21216.596874: 0: python3 is loading a BPF program python3-31517 [000] .... 21220'

结果分析

分析一下 update 程序的源码,可以看到在代码里面首先是加载 bpf 对象(第一次进入 bpf ),然后是更新对应键的值(第二次进入 bpf)与上面的运行结果一致。
#include <errno.h> #include <linux/bpf.h> #include <stdio.h> #include <string.h> #include "bpf.h" static const char *file_path = "/sys/fs/bpf/my_array"; int main(int argc, char **argv) { int fd, key, value, result; fd = bpf_obj_get(file_path); if (fd < 0) { printf("Failed to fetch the map: %d (%s)\n", fd, strerror(errno)); return -1; } key = 1, value = 4567; result = bpf_map_update_elem(fd, &key, &value, BPF_ANY); if (result < 0) { printf("Failed to update map: %d (%s)\n", result, strerror(errno)); return -1; } printf("Value update from the map: '%d'\n", value); return 0; }
 
 
 
欢迎加入喵星计算机技术研究院,原创技术文章第一时间推送。
notion image
 
BPF 学习系列之 - 用户空间探针 - uprobes 与 uretprobes 使用 CoreDNS 对抗 DNS 污染