@@ -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
@@ -2957,23 +2963,30 @@ let generate_unified_map_setup_code ?(obj_var="obj->obj") maps =
29572963 else map :: acc
29582964 ) [] maps |> List. rev in
29592965
2960- List. map (fun map ->
2966+ let map_setups = List. map (fun map ->
29612967 (* Always load from eBPF object first, then handle pinning if needed *)
29622968 let pin_logic = match map.pin_path with
29632969 | Some pin_path ->
2970+ (* Extract directory path from pin_path *)
2971+ let dir_path = Filename. dirname pin_path in
2972+ (* Generate unique variable name for each map's existing_fd *)
29642973 Printf. sprintf {|
29652974 // Check if map is already pinned
2966- int existing_fd = bpf_obj_get(" %s" );
2967- if (existing_fd > = 0 ) {
2968- % s_fd = existing_fd ;
2975+ int % s_existing_fd = bpf_obj_get(" %s" );
2976+ if (% s_existing_fd > = 0 ) {
2977+ % s_fd = % s_existing_fd ;
29692978 } else {
2970- // Map not pinned yet, pin it now
2979+ // Map not pinned yet, create directory and pin it
2980+ if (ensure_bpf_dir ("%s" ) < 0 ) {
2981+ fprintf(stderr, "Failed to create directory %s: %%s\n", strerror(errno));
2982+ return 1;
2983+ }
29712984 if (bpf_map__pin (%s_map , "%s" ) < 0 ) {
29722985 fprintf(stderr, "Failed to pin %s map to %s\n");
29732986 return 1;
29742987 }
29752988 %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
2989+ }| } 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
29772990 | None ->
29782991 Printf. sprintf {|
29792992 // Non - pinned map, just get file descriptor
@@ -2989,7 +3002,9 @@ let generate_unified_map_setup_code ?(obj_var="obj->obj") maps =
29893002 fprintf(stderr, " Failed to get fd for %s map\n " );
29903003 return 1 ;
29913004 }| } 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 "
3005+ ) deduplicated_maps in
3006+
3007+ String. concat " \n " map_setups
29933008
29943009(* * Generate config struct definition from config declaration - reusing eBPF logic *)
29953010let generate_config_struct_from_decl (config_decl : Ast.config_declaration ) =
@@ -3446,8 +3461,14 @@ let generate_complete_userspace_program_from_ir ?(config_declarations = []) ?(ta
34463461 maps_for_exec (* Use all global maps directly for exec *)
34473462 else used_global_maps in
34483463
3464+ (* Check if there are any pinned maps - this affects which headers we need *)
3465+ let has_any_pinned_maps = List. exists (fun map -> map.pin_path <> None ) global_maps in
3466+
3467+ (* For header generation, use all global maps if there are pinned maps, otherwise use the filtered list *)
3468+ let maps_for_headers = if has_any_pinned_maps then global_maps else used_global_maps_with_exec in
3469+
34493470 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
3471+ let base_includes = generate_headers_for_maps ~uses_bpf_functions maps_for_headers in
34513472 let additional_includes = {| #include < stdbool.h>
34523473#include < stdint.h>
34533474#include < inttypes.h>
@@ -3520,8 +3541,12 @@ let generate_complete_userspace_program_from_ir ?(config_declarations = []) ?(ta
35203541 else " " in
35213542
35223543 (* 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
3544+ (* Check if there are any pinned maps that need setup *)
3545+ let has_pinned_maps = List. exists (fun map -> map.pin_path <> None ) global_maps in
3546+ let map_setup_code = if all_usage.uses_map_operations || all_usage.uses_exec || has_pinned_maps then
3547+ (* For pinned maps, we need to include all of them in setup, not just used ones *)
3548+ let maps_for_setup = if has_pinned_maps then global_maps else used_global_maps_with_exec in
3549+ generate_unified_map_setup_code maps_for_setup
35253550 else " " in
35263551
35273552 (* Generate pinned globals support *)
@@ -3588,8 +3613,9 @@ let generate_complete_userspace_program_from_ir ?(config_declarations = []) ?(ta
35883613
35893614
35903615
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
3616+ let map_fd_declarations = if all_usage.uses_map_operations || all_usage.uses_exec || has_pinned_maps then
3617+ let maps_for_fd = if has_pinned_maps then global_maps else used_global_maps_with_exec in
3618+ generate_map_fd_declarations maps_for_fd
35933619 else " " in
35943620
35953621 (* Generate config map file descriptors if there are config declarations *)
@@ -3666,6 +3692,9 @@ void cleanup_bpf_maps(void) {
36663692
36673693 (* Only generate BPF helper functions when they're actually used *)
36683694 let bpf_helper_functions =
3695+ (* Check if there are any pinned maps in the global maps *)
3696+ let has_pinned_maps = List. exists (fun map -> map.pin_path <> None ) global_maps in
3697+
36693698 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
36703699
36713700 (* Global attachment storage (generated only when attach/detach are used) *)
@@ -4140,7 +4169,40 @@ static int add_attachment(int prog_fd, const char *target, uint32_t flags,
41404169 ) maps_for_exec |> String.concat "\n")
41414170 else "" in
41424171
4143- let functions_list = List.filter (fun s -> s <> "") [attachment_storage; load_function; attach_function; detach_function; daemon_function; exec_function] in
4172+ (* Generate directory creation helper if there are pinned maps *)
4173+ let mkdir_helper_function = if has_pinned_maps then
4174+ {|// Helper function to create directory recursively
4175+ static int ensure_bpf_dir(const char *path) {
4176+ char tmp[4096];
4177+ char *p = NULL;
4178+ size_t len;
4179+
4180+ if (!path || strlen(path) >= sizeof(tmp)) {
4181+ fprintf(stderr, "ensure_bpf_dir: path too long or NULL\n");
4182+ return -1;
4183+ }
4184+
4185+ snprintf(tmp, sizeof(tmp), "%s", path);
4186+ len = strlen(tmp);
4187+ if (len > 0 && tmp[len - 1] == '/') tmp[len - 1] = 0;
4188+
4189+ for (p = tmp + 1; *p; p++) {
4190+ if (* p == '/') {
4191+ *p = 0;
4192+ if (mkdir(tmp, 0755) != 0 && errno != EEXIST) {
4193+ return -1;
4194+ }
4195+ *p = '/';
4196+ }
4197+ }
4198+ if (mkdir(tmp, 0755) != 0 && errno != EEXIST) {
4199+ return -1;
4200+ }
4201+ return 0;
4202+ }|}
4203+ else "" in
4204+
4205+ let functions_list = List.filter (fun s -> s <> "") [mkdir_helper_function; attachment_storage; load_function; attach_function; detach_function; daemon_function; exec_function] in
41444206 if functions_list = [] && bpf_obj_decl = "" then ""
41454207 else
41464208 sprintf "\n/* BPF Helper Functions (generated only when used) */\n%s\n\n%s"
0 commit comments