Skip to content

Commit 46c596f

Browse files
authored
Merge pull request #13 from SiyuanSun0736/fix_pin_var_map
fix: correct pinned maps handling and implement missing userspace setup
2 parents f980559 + 1585094 commit 46c596f

3 files changed

Lines changed: 408 additions & 23 deletions

File tree

src/ir_generator.ml

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2825,12 +2825,15 @@ let lower_multi_program ast symbol_table source_name =
28252825
let ir_map = lower_map_declaration symbol_table map_decl in
28262826
((decl, `Map ir_map) :: decls, ir_map :: maps, vars)
28272827
| Ast.GlobalVarDecl var_decl when is_global_var_map var_decl ->
2828+
(* When a global variable has a map type, convert it to a map definition only.
2829+
Do NOT create a corresponding IR global variable, as that causes the map
2830+
to be incorrectly treated as a pinned global variable in userspace codegen. *)
28282831
let ir_map = match convert_global_var_to_map symbol_table var_decl with
28292832
| Some map -> map
28302833
| None -> failwith "Expected map conversion to succeed"
28312834
in
2832-
let ir_var = lower_global_variable_declaration symbol_table var_decl in
2833-
((decl, `MapFromGlobalVar (ir_map, ir_var)) :: decls, ir_map :: maps, ir_var :: vars)
2835+
(* Only track as map, not as global variable *)
2836+
((decl, `MapFromGlobalVar ir_map) :: decls, ir_map :: maps, vars)
28342837
| Ast.GlobalVarDecl var_decl ->
28352838
let ir_var = lower_global_variable_declaration symbol_table var_decl in
28362839
((decl, `GlobalVar ir_var) :: decls, maps, ir_var :: vars)
@@ -3136,10 +3139,11 @@ let lower_multi_program ast symbol_table source_name =
31363139
match processed with
31373140
| `Map ir_map ->
31383141
add_source_declaration (IRDeclMapDef ir_map) pos
3139-
| `MapFromGlobalVar (ir_map, ir_var) ->
3140-
(* For global variables with map types, add both the map and the variable *)
3141-
add_source_declaration (IRDeclMapDef ir_map) pos;
3142-
add_source_declaration (IRDeclGlobalVarDef ir_var) pos
3142+
| `MapFromGlobalVar ir_map ->
3143+
(* For global variables with map types, only add the map definition.
3144+
Do NOT add a global variable declaration, as it would incorrectly be treated
3145+
as a pinned global variable in userspace codegen. *)
3146+
add_source_declaration (IRDeclMapDef ir_map) pos
31433147
| `GlobalVar ir_var ->
31443148
add_source_declaration (IRDeclGlobalVarDef ir_var) pos
31453149
| `Other decl ->

src/userspace_codegen.ml

Lines changed: 78 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -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 *)
29953010
let 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

Comments
 (0)