Skip to content

Commit 5964a22

Browse files
davemarchevskyborkmann
authored andcommitted
libbpf: Support triple-underscore flavors for kfunc relocation
The function signature of kfuncs can change at any time due to their intentional lack of stability guarantees. As kfuncs become more widely used, BPF program writers will need facilities to support calling different versions of a kfunc from a single BPF object. Consider this simplified example based on a real scenario we ran into at Meta: /* initial kfunc signature */ int some_kfunc(void *ptr) /* Oops, we need to add some flag to modify behavior. No problem, change the kfunc. flags = 0 retains original behavior */ int some_kfunc(void *ptr, long flags) If the initial version of the kfunc is deployed on some portion of the fleet and the new version on the rest, a fleetwide service that uses some_kfunc will currently need to load different BPF programs depending on which some_kfunc is available. Luckily CO-RE provides a facility to solve a very similar problem, struct definition changes, by allowing program writers to declare my_struct___old and my_struct___new, with ___suffix being considered a 'flavor' of the non-suffixed name and being ignored by bpf_core_type_exists and similar calls. This patch extends the 'flavor' facility to the kfunc extern relocation process. BPF program writers can now declare extern int some_kfunc___old(void *ptr) extern int some_kfunc___new(void *ptr, int flags) then test which version of the kfunc exists with bpf_ksym_exists. Relocation and verifier's dead code elimination will work in concert as expected, allowing this pattern: if (bpf_ksym_exists(some_kfunc___old)) some_kfunc___old(ptr); else some_kfunc___new(ptr, 0); Signed-off-by: Dave Marchevsky <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Acked-by: David Vernet <[email protected]> Acked-by: Jiri Olsa <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent b6594a1 commit 5964a22

File tree

1 file changed

+19
-1
lines changed

1 file changed

+19
-1
lines changed

tools/lib/bpf/libbpf.c

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,7 @@ struct extern_desc {
550550
int btf_id;
551551
int sec_btf_id;
552552
const char *name;
553+
char *essent_name;
553554
bool is_set;
554555
bool is_weak;
555556
union {
@@ -3770,6 +3771,7 @@ static int bpf_object__collect_externs(struct bpf_object *obj)
37703771
struct extern_desc *ext;
37713772
int i, n, off, dummy_var_btf_id;
37723773
const char *ext_name, *sec_name;
3774+
size_t ext_essent_len;
37733775
Elf_Scn *scn;
37743776
Elf64_Shdr *sh;
37753777

@@ -3819,6 +3821,14 @@ static int bpf_object__collect_externs(struct bpf_object *obj)
38193821
ext->sym_idx = i;
38203822
ext->is_weak = ELF64_ST_BIND(sym->st_info) == STB_WEAK;
38213823

3824+
ext_essent_len = bpf_core_essential_name_len(ext->name);
3825+
ext->essent_name = NULL;
3826+
if (ext_essent_len != strlen(ext->name)) {
3827+
ext->essent_name = strndup(ext->name, ext_essent_len);
3828+
if (!ext->essent_name)
3829+
return -ENOMEM;
3830+
}
3831+
38223832
ext->sec_btf_id = find_extern_sec_btf_id(obj->btf, ext->btf_id);
38233833
if (ext->sec_btf_id <= 0) {
38243834
pr_warn("failed to find BTF for extern '%s' [%d] section: %d\n",
@@ -7624,7 +7634,8 @@ static int bpf_object__resolve_ksym_func_btf_id(struct bpf_object *obj,
76247634

76257635
local_func_proto_id = ext->ksym.type_id;
76267636

7627-
kfunc_id = find_ksym_btf_id(obj, ext->name, BTF_KIND_FUNC, &kern_btf, &mod_btf);
7637+
kfunc_id = find_ksym_btf_id(obj, ext->essent_name ?: ext->name, BTF_KIND_FUNC, &kern_btf,
7638+
&mod_btf);
76287639
if (kfunc_id < 0) {
76297640
if (kfunc_id == -ESRCH && ext->is_weak)
76307641
return 0;
@@ -7639,6 +7650,9 @@ static int bpf_object__resolve_ksym_func_btf_id(struct bpf_object *obj,
76397650
ret = bpf_core_types_are_compat(obj->btf, local_func_proto_id,
76407651
kern_btf, kfunc_proto_id);
76417652
if (ret <= 0) {
7653+
if (ext->is_weak)
7654+
return 0;
7655+
76427656
pr_warn("extern (func ksym) '%s': func_proto [%d] incompatible with %s [%d]\n",
76437657
ext->name, local_func_proto_id,
76447658
mod_btf ? mod_btf->name : "vmlinux", kfunc_proto_id);
@@ -8370,6 +8384,10 @@ void bpf_object__close(struct bpf_object *obj)
83708384

83718385
zfree(&obj->btf_custom_path);
83728386
zfree(&obj->kconfig);
8387+
8388+
for (i = 0; i < obj->nr_extern; i++)
8389+
zfree(&obj->externs[i].essent_name);
8390+
83738391
zfree(&obj->externs);
83748392
obj->nr_extern = 0;
83758393

0 commit comments

Comments
 (0)