API 命名约定¶
libbpf API 提供了对一些逻辑上分离的函数和类型组的访问。每个组都有其自己的命名约定,在此处描述。建议在添加新函数或类型时遵循这些约定,以保持 libbpf API 的简洁和一致性。
libbpf API 提供的所有类型和函数都应具有以下前缀之一: bpf_
, btf_
, libbpf_
, btf_dump_
, ring_buffer_
, perf_buffer_
。
系统调用包装器¶
系统调用包装器是 sys_bpf 系统调用支持的命令的简单包装器。这些包装器应放入 bpf.h
头文件中,并与相应的命令一一映射。
例如,bpf_map_lookup_elem
包装 sys_bpf 的 BPF_MAP_LOOKUP_ELEM
命令,bpf_prog_attach
包装 BPF_PROG_ATTACH
,等等。
对象¶
libbpf API 提供的另一种类型和函数是“对象”和用于处理它们的功能。对象是高级抽象,例如 BPF 程序或 BPF 映射。它们由相应的结构表示,例如 struct bpf_object
、struct bpf_program
、struct bpf_map
等。
结构体被前向声明,并且对其字段的访问应该通过相应的 getter 和 setter 提供,而不是直接访问。
这些对象与包含已编译 BPF 程序的 ELF 对象的相应部分相关联。
例如,struct bpf_object
表示从 ELF 文件或缓冲区创建的 ELF 对象本身,struct bpf_program
表示 ELF 对象中的程序,而 struct bpf_map
是一个映射。
使用对象的功能具有从对象名称、双下划线和描述功能目的的部分构建的名称。
例如,bpf_object__open
由相应对象的名称 bpf_object
、双下划线和 open
组成,后者定义了打开 ELF 文件并从中创建 bpf_object
的功能目的。
除 BTF 相关之外的所有对象和相应的功能都应放入 libbpf.h
中。BTF 类型和函数应放入 btf.h
中。
辅助功能¶
不适合上述任何类别的辅助函数和类型应具有 libbpf_
前缀,例如 libbpf_get_error
或 libbpf_prog_type_by_name
。
ABI¶
libbpf 既可以静态链接,也可以用作 DSO。为了避免与应用程序链接的其他库发生可能的冲突,所有非静态 libbpf 符号都应具有上述 API 文档中提到的前缀之一。请参阅 API 命名约定,为新符号选择正确的名称。
符号可见性¶
libbpf 遵循以下模型:默认情况下,所有全局符号都具有“隐藏”可见性,并且要使符号可见,必须使用 LIBBPF_API
宏显式标记。例如:
LIBBPF_API int bpf_prog_get_fd_by_id(__u32 id);
这可以防止意外导出不应成为 ABI 一部分的符号,从而改善 libbpf 开发人员和用户体验。
ABI 版本控制¶
为了使将来的 ABI 扩展成为可能,libbpf ABI 已版本化。版本控制是通过传递给链接器的 libbpf.map
版本脚本来实现的。
版本名称是 LIBBPF_
前缀 + 三组件数字版本,从 0.0.1
开始。
每次 ABI 发生更改时,例如,因为添加了新符号或更改了现有符号的语义,都应增加 ABI 版本。ABI 版本的增加最多在每个内核开发周期发生一次。
例如,如果 libbpf.map
的当前状态为
LIBBPF_0.0.1 {
global:
bpf_func_a;
bpf_func_b;
local:
\*;
};
,并且正在引入新符号 bpf_func_c
,则应像这样更改 libbpf.map
:
LIBBPF_0.0.1 {
global:
bpf_func_a;
bpf_func_b;
local:
\*;
};
LIBBPF_0.0.2 {
global:
bpf_func_c;
} LIBBPF_0.0.1;
,其中新版本 LIBBPF_0.0.2
依赖于先前的 LIBBPF_0.0.1
。
版本脚本的格式以及处理 ABI 更改(包括不兼容的更改)的方法在 [1] 中有详细说明。
独立构建¶
在 https://github.com/libbpf/libbpf 下,有一个(半)自动化的主线版本 libbpf 的镜像,用于独立构建。
但是,对 libbpf 代码库的所有更改都必须通过主线内核树向上游推送。
API 文档约定¶
libbpf API 通过头文件中定义上方的注释进行文档化。这些注释可以由 doxygen 和 sphinx 呈现,以获得组织良好的 html 输出。本节描述了这些注释应采用的格式约定。
以下是 btf.h 中的示例:
/**
* @brief **btf__new()** creates a new instance of a BTF object from the raw
* bytes of an ELF's BTF section
* @param data raw bytes
* @param size number of bytes passed in `data`
* @return new BTF object instance which has to be eventually freed with
* **btf__free()**
*
* On error, error-code-encoded-as-pointer is returned, not a NULL. To extract
* error code from such a pointer `libbpf_get_error()` should be used. If
* `libbpf_set_strict_mode(LIBBPF_STRICT_CLEAN_PTRS)` is enabled, NULL is
* returned on error instead. In both cases thread-local `errno` variable is
* always set to error code as well.
*/
注释必须以 ‘/**’ 形式的块注释开头。
文档始终以 @brief 指令开头。此行是有关此 API 的简短描述。它以 API 的名称开头,并以粗体显示,如下所示: api_name。如果这是一个函数,请包括一个开括号和一个闭括号。紧接着是 API 的简短描述。可以在最后一个指令下方的注释底部添加更长的描述。
参数用 @param 指令表示,每个参数应有一个。如果这是一个具有非 void 返回值的函数,请使用 @return 指令来记录它。
许可¶
libbpf 在 LGPL 2.1 和 BSD 2-Clause 双重许可下获得许可。
链接¶
- [1] https://www.akkadia.org/drepper/dsohowto.pdf
(第 3 章。维护 API 和 ABI)。