Skip to content

Commit 64ad7b4

Browse files
committed
Emit __ksym extern for local @KFunC declarations
Signed-off-by: Cong Wang <cwang@multikernel.io>
1 parent 151de26 commit 64ad7b4

2 files changed

Lines changed: 22 additions & 18 deletions

File tree

src/ebpf_c_codegen.ml

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3048,11 +3048,14 @@ let generate_declarations_in_source_order_unified ctx ir_multi_prog ~_btf_path _
30483048
emit_blank_line ctx
30493049

30503050
| Ir.IRDeclKfuncDecl kfunc_decl ->
3051-
(* Emit a function-signature declaration so eBPF programs can call the kfunc.
3052-
Kernel-provided kfuncs need `extern ... __ksym;`; locally-defined @kfunc
3053-
functions just need a forward prototype. Standard BPF helpers are skipped
3054-
entirely - libbpf's bpf_helpers.h already declares them, and a __ksym
3055-
extern would clash with that declaration. *)
3051+
(* Emit `extern ... __ksym;` so libbpf resolves the symbol against the
3052+
kernel's BTF at load time. Both kinds of kfunc are external to the
3053+
eBPF object: kernel-provided ones live in vmlinux, and locally-defined
3054+
@kfunc bodies live in the sibling kernel module compiled alongside the
3055+
eBPF program. Without __ksym, bpftool's skeleton generator looks for
3056+
BTF inside the .o and fails. Standard BPF helpers are skipped entirely
3057+
- libbpf's bpf_helpers.h already declares them, and a __ksym extern
3058+
would clash with that declaration. *)
30563059
let name = kfunc_decl.Ir.ikfunc_name in
30573060
if kfunc_decl.Ir.ikfunc_is_extern && Bpf_helpers.is_bpf_helper name then
30583061
()
@@ -3064,13 +3067,8 @@ let generate_declarations_in_source_order_unified ctx ir_multi_prog ~_btf_path _
30643067
) params)
30653068
in
30663069
let return_type_str = kfunc_signature_type_to_c kfunc_decl.Ir.ikfunc_return_type in
3067-
if kfunc_decl.Ir.ikfunc_is_extern then
3068-
emit_line ctx (sprintf "extern %s %s(%s) __ksym;"
3069-
return_type_str name params_str)
3070-
else (
3071-
emit_line ctx "/* kfunc declaration */";
3072-
emit_line ctx (sprintf "%s %s(%s);" return_type_str name params_str)
3073-
);
3070+
emit_line ctx (sprintf "extern %s %s(%s) __ksym;"
3071+
return_type_str name params_str);
30743072
emit_blank_line ctx
30753073
)
30763074
) ir_multi_prog.Ir.source_declarations;

tests/test_kfunc_attribute.ml

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -151,12 +151,18 @@ let test_ebpf_kfunc_declarations () =
151151

152152
(* @kfunc declarations are lowered into the IR; codegen needs no side-channel *)
153153
let (generated_code, _) = Ebpf_c_codegen.compile_multi_to_c_with_analysis ir in
154-
155-
(* Check that kfunc declarations are generated *)
156-
check bool "Contains kfunc declaration" true
157-
(try ignore (Str.search_forward (Str.regexp "bool security_check") generated_code 0); true with Not_found -> false);
158-
check bool "Contains kfunc call" true
159-
(try ignore (Str.search_forward (Str.regexp "security_check(") generated_code 0); true with Not_found -> false)
154+
155+
let contains substr =
156+
try ignore (Str.search_forward (Str.regexp_string substr) generated_code 0); true
157+
with Not_found -> false
158+
in
159+
(* Local @kfuncs are external to the eBPF object - they live in the sibling
160+
kernel module - so they must be declared with __ksym, like vmlinux kfuncs.
161+
Without __ksym, bpftool gen skeleton fails with "failed to find BTF for
162+
extern" because libbpf looks for the symbol's BTF inside the .o file. *)
163+
check bool "Local @kfunc declared as __ksym extern" true
164+
(contains "extern bool security_check(__u64 addr) __ksym;");
165+
check bool "Contains kfunc call" true (contains "security_check(")
160166

161167
(** Test kernel module print function translation *)
162168
let test_kernel_print_translation () =

0 commit comments

Comments
 (0)