当我们想要在项目特定版本内核中落地某个 eBPF 特性时,需要确认该版本内核是否支持该 eBPF 特性。

与此同时,也想知道,该 eBPF 特性最低要求哪个版本的内核。

前置条件

学习 eBPF 特性的有效方式是什么?

我觉得最有效的方式是在项目中落地,让代码在生产环境接受严酷的磨砺。

不过,在学习新特性时,有效的方式是编写 demo 代码、并且跑起来。

有效且靠谱的方式是,先学习该特性相关的理论知识、并且深入学习该特性的源代码,再编写 demo 代码、跑起来验证一下。

我现在正朝着有效且靠谱的方向迈进。

阅读内核源代码

我阅读内核源代码的方式比较朴素:

  1. 使用 ag + fzf 搜索代码:快速找到代码位置。
  2. 使用 Sublime Text 阅读代码:满足基本的代码跳转需求。
  3. 使用的内核代码分支是 bpf-next:保障有比较全面的 eBPF 特性。

经常阅读源代码后,可以在 Sublime Text 里使用 Cmd + P 的快捷方式打开对应的源代码文件:

  1. syscall.ckernel/bpf/syscall.c,BPF 系统调用入口。
  2. verifier.ckernel/bpf/verifier.c,BPF 校验器。
  3. arraymap.ckernel/bpf/arraymap.c,ARRAY bpf map、PROG ARRAY bpf map 等。
  4. dev.cnet/core/dev.c,内核协议栈设备层的核心代码,里面包含了 XDP generic 模式的代码。
  5. bpf.hinclude/uapi/linux/bpf.h,BPF 帮助函数的声明及其函数的使用文档。
  6. bpf_types.hinclude/linux/bpf_types.h,BPF 程序类型、map 类型等及其接口的对应关系。

快速打开代码文件后,便可在文件里搜索相关代码,然后就可以阅读相关代码了。

确认特定版本的内核是否支持某 eBPF 特性

首先,需要知道该 eBPF 特性的源代码在什么位置。比如直接搜索 bpf-next 分支的内核代码,找到相关源代码文件路径后,再去特定版本的内核里查看是否有相关的源代码。

不过,这仅限于学习用途。如果想要项目在运行的时候动态探测是否支持某特性,则可以参考 cilium/ebpf/features 进行特性探测。

比如,在网络上了解到较新版本的内核里支持 bpf_loop() 特性,想要确认 5.15 内核是否支持该特性:

  1. bpf_loop() 是一个 BPF 帮助函数,就会在 include/uapi/linux/bpf.h 中有声明。
  2. 到特定版本的内核源代码的 include/uapi/linux/bpf.h 文件里搜索 bpf_loop:搜索到即支持,搜索不到即不支持。

确认某 eBPF 特性最低要求哪个版本的内核

BPF Features by Linux Kernel Version 该文档里整理了不少相关资料,不够全面。而对于文档里没有包含的(特别是较新的)特性,就需要自己去确认了。

这就不好确认了。不过,并非没有办法;下面就是我采用的办法:

下面以 bpf_loop() 为例。

1、在 bpf-next 分支里,确认该特性的源代码文件路径。

2、到 GitHub 的 linux 项目中打开该文件

3、blame 该文件

4、打开 commit

5、确认 kernel version

总结

为什么要那么费劲地阅读内核源代码呢?

因为我信奉 “Try hard to learn little things”。

当克服阅读内核源代码的恐惧后,便会逐步喜欢上阅读源代码的感觉、那种真正掌握知识的感觉。