Add btf_module_names and nr_btf_module_names fields to bpf_object_open_opts to support selective kernel module BTF loading. When btf_module_names is provided, libbpf loads BTFs only for the specified kernel modules and skips other module BTFs. If btf_module_names is NULL, all module BTFs are loaded as before. This avoids unnecessary module BTF loading and reduces BPF object loading time when only a subset of kernel module BTFs is needed. Suggested-by: Andrii Nakryiko Signed-off-by: Fuyu Zhao --- tools/lib/bpf/libbpf.c | 105 +++++++++++++++++++++++++++++++++++++++++ tools/lib/bpf/libbpf.h | 24 +++++++++- 2 files changed, 128 insertions(+), 1 deletion(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 514e4e9daa82..6f5d3213b3e5 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -779,6 +779,9 @@ struct bpf_object { char *token_path; int token_fd; + char **btf_module_names; + size_t nr_btf_module_names; + char path[]; }; @@ -5803,6 +5806,94 @@ int bpf_core_add_cands(struct bpf_core_cand *local_cand, return 0; } +static void bpf_object_free_btf_module_names(struct bpf_object *obj) +{ + size_t i; + + if (!obj->btf_module_names) + return; + + for (i = 0; i < obj->nr_btf_module_names; i++) + zfree(&obj->btf_module_names[i]); + zfree(&obj->btf_module_names); + obj->nr_btf_module_names = 0; +} + +static int bpf_object_init_btf_module_names(struct bpf_object *obj, + const struct bpf_object_open_opts *opts) +{ + const char **names; + size_t i, j, cnt; + int err; + + names = OPTS_GET(opts, btf_module_names, NULL); + if (!names) + return 0; + + cnt = OPTS_GET(opts, nr_btf_module_names, 0); + + /* + * Keep btf_module_names non-NULL to distinguish an empty filter from + * the default behavior of loading all module BTFs. + */ + obj->btf_module_names = calloc(cnt ?: 1, + sizeof(*obj->btf_module_names)); + if (!obj->btf_module_names) + return -ENOMEM; + + for (i = 0; i < cnt; i++) { + if (!names[i] || !names[i][0]) { + pr_warn("invalid kernel module BTF name at index %zu\n", i); + err = -EINVAL; + goto err_out; + } + + for (j = 0; j < i; j++) { + if (strcmp(obj->btf_module_names[j], names[i]) == 0) { + pr_warn("duplicate kernel module BTF name '%s'\n", + names[i]); + err = -EINVAL; + goto err_out; + } + } + + obj->btf_module_names[i] = strdup(names[i]); + if (!obj->btf_module_names[i]) { + err = -ENOMEM; + goto err_out; + } + + obj->nr_btf_module_names++; + } + return 0; + +err_out: + bpf_object_free_btf_module_names(obj); + return err; +} + +static bool is_module_btf_needed(const struct bpf_object *obj, const char *name) +{ + size_t i; + + if (!obj->btf_module_names) + return true; + + for (i = 0; i < obj->nr_btf_module_names; i++) { + if (strcmp(obj->btf_module_names[i], name) == 0) + return true; + } + + pr_debug("skipping module BTF '%s', not in btf_module_names\n", name); + return false; +} + +static bool all_needed_module_btfs_loaded(const struct bpf_object *obj) +{ + return obj->btf_module_names && + obj->nr_btf_module_names == obj->btf_module_cnt; +} + static int load_module_btfs(struct bpf_object *obj) { struct bpf_btf_info info; @@ -5867,6 +5958,11 @@ static int load_module_btfs(struct bpf_object *obj) continue; } + if (!is_module_btf_needed(obj, name)) { + close(fd); + continue; + } + btf = btf_get_from_fd(fd, obj->btf_vmlinux); err = libbpf_get_error(btf); if (err) { @@ -5891,6 +5987,9 @@ static int load_module_btfs(struct bpf_object *obj) break; } obj->btf_module_cnt++; + + if (all_needed_module_btfs_loaded(obj)) + break; } if (err) { @@ -8508,6 +8607,10 @@ static struct bpf_object *bpf_object_open(const char *path, const void *obj_buf, } } + err = bpf_object_init_btf_module_names(obj, opts); + if (err) + goto out; + err = bpf_object__elf_init(obj); err = err ? : bpf_object__elf_collect(obj); err = err ? : bpf_object__collect_externs(obj); @@ -9629,6 +9732,8 @@ void bpf_object__close(struct bpf_object *obj) close(obj->jumptable_maps[i].fd); zfree(&obj->jumptable_maps); + bpf_object_free_btf_module_names(obj); + free(obj); } diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index b965ad571540..838602319da8 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -224,10 +224,32 @@ struct bpf_object_open_opts { * point (/sys/fs/bpf), in case this default behavior is undesirable. */ const char *bpf_token_path; + /* + * Optional list of kernel module names whose BTFs should be loaded. + * nr_btf_module_names specifies the number of entries in + * btf_module_names. + * + * If btf_module_names is NULL, all module BTFs are loaded, + * preserving the default behavior. Otherwise, only the BTFs of + * the listed modules are loaded. A non-NULL btf_module_names + * with nr_btf_module_names equal to zero means that no module + * BTFs are loaded. + * + * The list must not contain duplicate entries; otherwise + * -EINVAL is returned. + * + * This affects: + * - BPF CO-RE relocations against types defined in modules; + * - BTF-based resolution of function attach targets for + * fentry/fexit/fmod_ret/freplace/LSM programs; + * - extern (ksym) resolution for kernel symbols defined in modules. + */ + const char **btf_module_names; + size_t nr_btf_module_names; size_t :0; }; -#define bpf_object_open_opts__last_field bpf_token_path +#define bpf_object_open_opts__last_field nr_btf_module_names /** * @brief **bpf_object__open()** creates a bpf_object by opening -- 2.34.1