如果覺得文章對你有所啟發,可以考慮用 🌟 支持 Gthulhu 專案,短期目標是集齊 300 個 🌟 藉此被 CNCF Landscape 採納 [ref]。
libbpf 支援 skeleton 功能,讓開發者能夠透過 bpftool 產生對應的 skeleton file,相關指令如下:
$ bpftool gen skeleton main.bpf.o > main.skeleton.h
main.bpf.o
為可載入的 BPF program 的 object file。main.skeleton.h
為 bpftool 輸出的檔案,包含了許多高度封裝的 API。讓我們觀察一下 main.skeleton.h
的檔案內容:
static void
main_bpf__destroy(struct main_bpf *obj)
{
if (!obj)
return;
if (obj->skeleton)
bpf_object__destroy_skeleton(obj->skeleton);
free(obj);
}
static inline int
main_bpf__create_skeleton(struct main_bpf *obj);
static inline struct main_bpf *
main_bpf__open_opts(const struct bpf_object_open_opts *opts)
{
struct main_bpf *obj;
int err;
obj = (struct main_bpf *)calloc(1, sizeof(*obj));
if (!obj) {
errno = ENOMEM;
return NULL;
}
err = main_bpf__create_skeleton(obj);
if (err)
goto err_out;
err = bpf_object__open_skeleton(obj->skeleton, opts);
if (err)
goto err_out;
obj->struct_ops.goland = (__typeof__(obj->struct_ops.goland))
bpf_map__initial_value(obj->maps.goland, NULL);
return obj;
err_out:
main_bpf__destroy(obj);
errno = -err;
return NULL;
}
我們會發現檔案包含了很多用來操作 struct main_bpf
指標的函式,這些函式封裝了 libbpf 提供的 APIs,讓使用者可以快速的在 user space 載入、更新給定的 eBPF program。
若我們細看 struct main_bpf
會發現,它封裝了 eBPF object 以及 rodata
、data
、bss
等 section。
若在 eBPF program 宣告全域變數,會根據不同的宣告方式將這些變數歸類在不同的 section:
int counter; // -> .bss
int init_value = 10; // -> .data
const int max = 100; // -> .rodata
若不使用 eBPF skeleton,當 eBPF program 載入後,我們可以用 BPF map 操作的方式來讀取這些 section 的資料。
反之,有了 skeleton file,讀取這些 section 都變的簡單不少:
#include "main.skeleton.h"
struct main_bpf *global_obj;
void *open_skel() {
struct main_bpf *obj = NULL;
obj = main_bpf__open();
main_bpf__create_skeleton(obj);
global_obj = obj;
return obj->obj;
}
u32 get_usersched_pid() {
return global_obj->bss->usersched_pid;
}
skeleton 簡化了 User Space Program 和 BPF program 互動的方式,讓我們更輕易的存取 global variable。這對我們日後移植 scx_rustland 的實作有非常大的幫助,至於實際的用途我們將在接下來的文章向各位說明。