结合例子学习eBPF与bcc:kretprobe与Tracepoint

在前面的文章中,我们学习了如何通过追踪kprobe,今天我们来学习更多的追踪机制:

  • kretprobe:类似于kprobe,但是是追踪其返回值或输出值;
  • Tracepoint:静态的追踪点,在内核中已编译好;

vfsreadlat

首先我们借助vfsreadlat来学习kretprobe的使用。kretprobekprobe可以看成是一对兄弟,kprobe在内核函数开始的时候执行,而kretprobe则在内核函数结束的时候执行,例如对于内核函数blk_mq_start_request

我们在kprobe挂载的函数start会在内核函数开始执行前执行,而在kretprobe挂载的函数end则会在内核函数结束后执行。前者可以探测内核函数的输入值,而后者则探测内核函数的返回值或者输出值。

让我们来看看vfsreadlat,首先是vfsreadlat.c

可以看出在do_entry函数中,我们记录了pid和它对应的时间;在do_return函数中,我们基于pid来计算时间的差值。

这是eBPFC代码,我们需要在bcc文件中引入它:

py 复制代码
b = BPF(src_file = "vfsreadlat.c")

如下就是全部的vfsreadlat.py

我们重点关注其中的挂载语句:

正如我们前文所说的,这里的流程是这样的:

小结一下:kprobe在内核函数进入前执行,kretprobe在内核函数返回后执行

urandomread

这一小节我们要学习的是Tracepoint的使用,Tracepointkprobe类似,也可以追踪内核的一些信息,但是Tracepoint是预制好的hook,已经提前在内核中编译好了,我们只需要直接使用就行。

先看代码:

可以看到我们直接在C中用TRACEPOINT_PROBE宏来进行了声明,这个宏指向的目标是内核断点 random:urandom_read,这个断点已经在内核中静态编译好了,如果我们在这里加入了这个宏,那么运行到randon:urandon_read的时候就会运行这个宏的内容。我们可以通过perf list命令来查看Tracepoint的列表:

这里宏的参数做了自动填充,我们可以用args->xxx来访问结构体变量。参数的内容可以通过/sys/kernel/debug/tracing/events/xxx/xxx/format来访问,例如random:urandom_read就是/sys/kernel/debug/tracing/events/random/urandom_read/format

这个程序的流程如下图所示:

Tracepointhook总是存在的,如果我们给它挂载了东西,它就会执行,反之则不会。

disksnoopTracepoint

现在我们尝试用block:block_rq_issueblock:block_rq_complete这两个Tracepoint来改写disksnoop。前者表示的是磁盘请求开始,后者则是结束。我们需要输出请求的大小和延时。

我们首先查看Tracepoint的结构体:

从这两个结构体中我们可以看出,请求的大小只在block_rq_issue的时候记录,所以我们需要有一个地方存储它。此外我们还需要考虑如何计算时间,我们需要记录下请求开始的时间和请求结束的时间,这里的问题在于我们该用什么作为哈希表的key。在这里我们使用args->dev作为keydev表示块设备的设备号。

**这里如果用pid作为key将会出现没有输出的情况。**这是因为在block_rq_issue的时候,我们通过bpf_get_current_pid_tgid获取到的是pid,但是在block_rq_complete的时候,此时运行的进程并不一定是发出请求的那个进程,所以无法保持一致性。

基于args->dev作为key,我们可以快速的编写如下的C代码:

接着通过编写前端代码我们就可以进行数据的输出了,运行结果如下:

小结

今天我们学习了:

  • k[ret]probe是动态追踪,我们可以在内核函数的开头和结尾进行追踪,相对更灵活;但是其开销也更大;
  • Tracepoint则更像是静态的,已经存在于内核中的hook点,不够灵活,但是相对固定,在不同版本的操作系统中变化不大,开销也更小;

disksnoopTracepoint

相关推荐
冰暮流星25 分钟前
flask之定义URL
后端·python·flask
程序员爱钓鱼1 小时前
为什么学习 Rust?Rust 能做什么?
后端·rust
二宝哥2 小时前
创建Gradle多模块SpringBoot项目
java·spring boot·后端
掘金者阿豪2 小时前
Docker命令太多记不住?用Portainer把容器管理变成可视化操作
后端
用户69371750013843 小时前
AI Agent 里的 Loop 到底是什么?
android·前端·后端
Rain的Java大神之路3 小时前
高并发下的抢优惠券如何设计
后端
钟智强3 小时前
AWS CloudGoat 实战:一个 SSRF 如何撬动整个云账户
后端
Ai拆代码的曹操3 小时前
@Transactional 写在 private 方法上,事务根本没生效
后端
云技纵横3 小时前
@Async 默认执行器又炸了:SimpleAsyncTaskExecutor 为什么不是线程池?
后端·面试
程序员Agions3 小时前
Fypro 新手快速上手与实战指南
后端