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_bpfBPF_MAP_LOOKUP_ELEM 命令,bpf_prog_attach 封裝了 BPF_PROG_ATTACH,等等。

物件

libbpf API 提供的另一類型別和函式是“物件”以及處理這些物件的函式。物件是高階抽象,例如 BPF 程式或 BPF 對映。它們由相應的結構體表示,例如 struct bpf_objectstruct bpf_programstruct 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_errorlibbpf_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 雙重許可下發布。