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)。