fentry – 记 Linux 内核观测的冰山一角

1. eBPF 常用的 hook / probe 方式

  • krobe/kretprobe
  • uprobe/uretprobe
  • fentry/fexit
  • tracepoints
  • socket filter
  • cgroups / cgroups skb
  • perf events
  • TC
  • XDP
  • LSM

2. fentry 与 ftrace 与 fprobe 与 kprobe

2.1 kprobe

首先是古老的 kprobe, 它通过替换指令的方式来实现任意内核函数的 hook。具体替换的方式又历经了好多年的迭代,最早是 “int3 中断 + 单步调试中断” 的方案,后来的 “int3 中断 + 指令模拟” 则规避了 “单步调试中断” 带来的多一个中断的性能影响。再后来又引入了 “int3 中断 + detour buffer 跳板” 的方案,具体可以参考: eBPF 动态观测之指令跳板

2.2 ftrace 与 fprobe

再来谈谈 ftrace, ftrace 的核心是 event,监控内核里的各类 event, 随后通过 debugfs 暴露出来,因此早期的 ftrace 基本可以理解成一个静态的探针 + 消息传递途径。不过情况很快发生了变化, 一个 patch kprobe-based event tracer 进入了内核,让 ftrace 能够利用 kprobe 实现动态探针/追踪的能力。于是出现了下面这样的依赖关系:
kprobe => kprobe-based event tracer => ftrace dynamic tracing, fprobe

2.3 fentry

现在我们来讲先进的 fentry. 实际上很早的时候,ftrace 就依赖内核的 CONFIG_HAVE_FENTRY 选项来实现各类 profiling 功能。内核在配置了该选项之后,gcc 编译时会打开 -pg -mfentry 等参数,在每个内核函数的入口处埋点,以便于未来的 profiling 操作。eBPF 这边也看到了 fentry 的潜力,使用 fentry + BPF trampoline 实现了等同 kprobe 的内核 hook 能力,并且性能更好,不过这需要内核 5.5 及以上版本。

最后还有一个 kprobe multi link,本来 eBPF kprobe 的过程是不能一次性 attach 到多个函数上的,只能一个一个来。而一个新的 patch bpf: Add kprobe multi link 利用了 fprobe 的能力来实现一次性 attach 多个内核函数,这个新的 link 类型被命名为 BPF_TRACE_KPROBE_MULTI

补充一下,BPF trampolines 一般又分为两类:

  • 内核调用 eBPF, 如上文 fentry + BPF trampoline 的实现
  • eBPF 调用内核函数, 如 BPF Kernel Functions (kfuncs)

3. kfunc 概念的说明

TODO

4. 参考资料

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注


The reCAPTCHA verification period has expired. Please reload the page.