@@ -2610,7 +2610,13 @@ let generate_c_function_from_ir ?(global_variables = []) ?(base_name = "") ?(con
26102610 let pinned_globals_vars = List. filter (fun gv -> gv.is_pinned) global_variables in
26112611 let has_pinned_globals = List. length pinned_globals_vars > 0 in
26122612
2613- let setup_call = if needs_object_loading && (List. length config_declarations > 0 || func_usage.uses_map_operations || func_usage.uses_exec || has_pinned_globals) then
2613+ (* Check if there are any pinned maps that need setup *)
2614+ let has_pinned_maps = match ir_multi_prog with
2615+ | Some multi_prog -> List. exists (fun map -> map.pin_path <> None ) (Ir. get_global_maps multi_prog)
2616+ | None -> false
2617+ in
2618+
2619+ let setup_call = if needs_object_loading && (List. length config_declarations > 0 || func_usage.uses_map_operations || func_usage.uses_exec || has_pinned_globals || has_pinned_maps) then
26142620 let all_setup_parts = List. filter (fun s -> s <> " " ) [
26152621 (if has_pinned_globals then
26162622 let project_name = base_name in
@@ -2637,8 +2643,8 @@ let generate_c_function_from_ir ?(global_variables = []) ?(base_name = "") ?(con
26372643 }
26382644 }| } pin_path pin_path
26392645 else " " );
2640- (* Include all_setup_code only once for maps, config, struct_ops, and ringbuf *)
2641- (if func_usage.uses_map_operations || func_usage.uses_exec || List. length config_declarations > 0 then all_setup_code else " " );
2646+ (* Include all_setup_code for maps (including pinned maps) , config, struct_ops, and ringbuf *)
2647+ (if func_usage.uses_map_operations || func_usage.uses_exec || List. length config_declarations > 0 || has_pinned_maps then all_setup_code else " " );
26422648 ] in
26432649 if all_setup_parts <> [] then " \n " ^ String. concat " \n " all_setup_parts else " "
26442650 else " " in
@@ -2811,6 +2817,19 @@ let generate_pinned_globals_support _project_name global_variables =
28112817
28122818(* * Generate ring buffer event handler functions *)
28132819let generate_ringbuf_handlers_from_registry (registry : Ir.ir_ring_buffer_registry ) ~dispatch_used =
2820+ (* Generate forward declarations for callback functions *)
2821+ let forward_declarations = List. map (fun rb_decl ->
2822+ let ringbuf_name = rb_decl.rb_name in
2823+ let value_type = c_type_from_ir_type rb_decl.rb_value_type in
2824+ let handler_name = match List. assoc_opt ringbuf_name registry.event_handler_registrations with
2825+ | Some handler -> handler
2826+ | None ->
2827+ (* Try callback function naming convention: {ringbuf_name}_callback *)
2828+ ringbuf_name ^ " _callback"
2829+ in
2830+ sprintf " int %s(%s *event);" handler_name value_type
2831+ ) registry.ring_buffer_declarations |> String. concat " \n " in
2832+
28142833 let event_handlers = List. map (fun rb_decl ->
28152834 let ringbuf_name = rb_decl.rb_name in
28162835 let value_type = c_type_from_ir_type rb_decl.rb_value_type in
@@ -2836,7 +2855,11 @@ static int %s_event_handler(void *ctx, void *data, size_t data_sz) {
28362855 else " " in
28372856
28382857 (* Only generate event handlers if dispatch is actually used *)
2839- let final_event_handlers = if dispatch_used then event_handlers else " " in
2858+ let final_event_handlers = if dispatch_used then
2859+ if List. length registry.ring_buffer_declarations > 0 then
2860+ sprintf " \n // Forward declarations for ring buffer callbacks\n %s\n %s" forward_declarations event_handlers
2861+ else " "
2862+ else " " in
28402863
28412864 final_event_handlers ^ combined_rb_declaration
28422865
@@ -2957,23 +2980,30 @@ let generate_unified_map_setup_code ?(obj_var="obj->obj") maps =
29572980 else map :: acc
29582981 ) [] maps |> List. rev in
29592982
2960- List. map (fun map ->
2983+ let map_setups = List. map (fun map ->
29612984 (* Always load from eBPF object first, then handle pinning if needed *)
29622985 let pin_logic = match map.pin_path with
29632986 | Some pin_path ->
2987+ (* Extract directory path from pin_path *)
2988+ let dir_path = Filename. dirname pin_path in
2989+ (* Generate unique variable name for each map's existing_fd *)
29642990 Printf. sprintf {|
29652991 // Check if map is already pinned
2966- int existing_fd = bpf_obj_get(" %s" );
2967- if (existing_fd > = 0 ) {
2968- % s_fd = existing_fd ;
2992+ int % s_existing_fd = bpf_obj_get(" %s" );
2993+ if (% s_existing_fd > = 0 ) {
2994+ % s_fd = % s_existing_fd ;
29692995 } else {
2970- // Map not pinned yet, pin it now
2996+ // Map not pinned yet, create directory and pin it
2997+ if (ensure_bpf_dir ("%s" ) < 0 ) {
2998+ fprintf(stderr, "Failed to create directory %s: %%s\n", strerror(errno));
2999+ return 1;
3000+ }
29713001 if (bpf_map__pin (%s_map , "%s" ) < 0 ) {
29723002 fprintf(stderr, "Failed to pin %s map to %s\n");
29733003 return 1;
29743004 }
29753005 %s_fd = bpf_map__fd(% s_map);
2976- }| } pin_path map.map_name map.map_name pin_path map.map_name pin_path map.map_name map.map_name
3006+ }| } map.map_name pin_path map.map_name map.map_name map.map_name dir_path dir_path map.map_name pin_path map.map_name pin_path map.map_name map.map_name
29773007 | None ->
29783008 Printf. sprintf {|
29793009 // Non - pinned map, just get file descriptor
@@ -2989,7 +3019,9 @@ let generate_unified_map_setup_code ?(obj_var="obj->obj") maps =
29893019 fprintf(stderr, " Failed to get fd for %s map\n " );
29903020 return 1 ;
29913021 }| } map.map_name map.map_name obj_var map.map_name map.map_name map.map_name pin_logic map.map_name map.map_name
2992- ) deduplicated_maps |> String. concat " \n "
3022+ ) deduplicated_maps in
3023+
3024+ String. concat " \n " map_setups
29933025
29943026(* * Generate config struct definition from config declaration - reusing eBPF logic *)
29953027let generate_config_struct_from_decl (config_decl : Ast.config_declaration ) =
@@ -3446,8 +3478,14 @@ let generate_complete_userspace_program_from_ir ?(config_declarations = []) ?(ta
34463478 maps_for_exec (* Use all global maps directly for exec *)
34473479 else used_global_maps in
34483480
3481+ (* Check if there are any pinned maps - this affects which headers we need *)
3482+ let has_any_pinned_maps = List. exists (fun map -> map.pin_path <> None ) global_maps in
3483+
3484+ (* For header generation, use all global maps if there are pinned maps, otherwise use the filtered list *)
3485+ let maps_for_headers = if has_any_pinned_maps then global_maps else used_global_maps_with_exec in
3486+
34493487 let uses_bpf_functions = all_usage.uses_load || all_usage.uses_attach || all_usage.uses_detach in
3450- let base_includes = generate_headers_for_maps ~uses_bpf_functions used_global_maps_with_exec in
3488+ let base_includes = generate_headers_for_maps ~uses_bpf_functions maps_for_headers in
34513489 let additional_includes = {| #include < stdbool.h>
34523490#include < stdint.h>
34533491#include < inttypes.h>
@@ -3520,8 +3558,12 @@ let generate_complete_userspace_program_from_ir ?(config_declarations = []) ?(ta
35203558 else " " in
35213559
35223560 (* Generate setup code first for use in main function *)
3523- let map_setup_code = if all_usage.uses_map_operations || all_usage.uses_exec then
3524- generate_unified_map_setup_code used_global_maps_with_exec
3561+ (* Check if there are any pinned maps that need setup *)
3562+ let has_pinned_maps = List. exists (fun map -> map.pin_path <> None ) global_maps in
3563+ let map_setup_code = if all_usage.uses_map_operations || all_usage.uses_exec || has_pinned_maps then
3564+ (* For pinned maps, we need to include all of them in setup, not just used ones *)
3565+ let maps_for_setup = if has_pinned_maps then global_maps else used_global_maps_with_exec in
3566+ generate_unified_map_setup_code maps_for_setup
35253567 else " " in
35263568
35273569 (* Generate pinned globals support *)
@@ -3588,8 +3630,9 @@ let generate_complete_userspace_program_from_ir ?(config_declarations = []) ?(ta
35883630
35893631
35903632
3591- let map_fd_declarations = if all_usage.uses_map_operations || all_usage.uses_exec then
3592- generate_map_fd_declarations used_global_maps_with_exec
3633+ let map_fd_declarations = if all_usage.uses_map_operations || all_usage.uses_exec || has_pinned_maps then
3634+ let maps_for_fd = if has_pinned_maps then global_maps else used_global_maps_with_exec in
3635+ generate_map_fd_declarations maps_for_fd
35933636 else " " in
35943637
35953638 (* Generate config map file descriptors if there are config declarations *)
@@ -3666,6 +3709,9 @@ void cleanup_bpf_maps(void) {
36663709
36673710 (* Only generate BPF helper functions when they're actually used *)
36683711 let bpf_helper_functions =
3712+ (* Check if there are any pinned maps in the global maps *)
3713+ let has_pinned_maps = List. exists (fun map -> map.pin_path <> None ) global_maps in
3714+
36693715 let load_function = generate_load_function_with_tail_calls base_name all_usage tail_call_analysis all_setup_code kfunc_dependencies (Ir. get_global_variables ir_multi_prog) in
36703716
36713717 (* Global attachment storage (generated only when attach/detach are used) *)
@@ -4140,7 +4186,40 @@ static int add_attachment(int prog_fd, const char *target, uint32_t flags,
41404186 ) maps_for_exec |> String.concat "\n")
41414187 else "" in
41424188
4143- let functions_list = List.filter (fun s -> s <> "") [attachment_storage; load_function; attach_function; detach_function; daemon_function; exec_function] in
4189+ (* Generate directory creation helper if there are pinned maps *)
4190+ let mkdir_helper_function = if has_pinned_maps then
4191+ {|// Helper function to create directory recursively
4192+ static int ensure_bpf_dir(const char *path) {
4193+ char tmp[4096];
4194+ char *p = NULL;
4195+ size_t len;
4196+
4197+ if (!path || strlen(path) >= sizeof(tmp)) {
4198+ fprintf(stderr, "ensure_bpf_dir: path too long or NULL\n");
4199+ return -1;
4200+ }
4201+
4202+ snprintf(tmp, sizeof(tmp), "%s", path);
4203+ len = strlen(tmp);
4204+ if (len > 0 && tmp[len - 1] == '/') tmp[len - 1] = 0;
4205+
4206+ for (p = tmp + 1; *p; p++) {
4207+ if (* p == '/') {
4208+ *p = 0;
4209+ if (mkdir(tmp, 0755) != 0 && errno != EEXIST) {
4210+ return -1;
4211+ }
4212+ *p = '/';
4213+ }
4214+ }
4215+ if (mkdir(tmp, 0755) != 0 && errno != EEXIST) {
4216+ return -1;
4217+ }
4218+ return 0;
4219+ }|}
4220+ else "" in
4221+
4222+ let functions_list = List.filter (fun s -> s <> "") [mkdir_helper_function; attachment_storage; load_function; attach_function; detach_function; daemon_function; exec_function] in
41444223 if functions_list = [] && bpf_obj_decl = "" then ""
41454224 else
41464225 sprintf "\n/* BPF Helper Functions (generated only when used) */\n%s\n\n%s"
0 commit comments