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
组成,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)。