Hengqi Chen says: ==================== Currently a bunch of (usually pretty specialized) BPF maps do not support specifying BTF types for they key and value. For such maps, specifying their definition like this: struct { __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); __type(key, int); __type(value, int); } my_perf_buf SEC(".maps"); Would actually produce warnings about retrying BPF map creation without BTF. Users are forced to know such nuances and use __uint(key_size, 4) instead. This is non-uniform, annoying, and inconvenient. This patch set teaches libbpf to recognize those specialized maps and removes BTF type IDs when creating BPF map. Also, update existing BPF selftests to exericse this change. ====================
Unified · Split
| @@ -4669,6 +4669,30 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b · 4668 unmodified lines | |||
| 4669 | create_attr.inner_map_fd = map->inner_map_fd; | 4669 | create_attr.inner_map_fd = map->inner_map_fd; |
| 4670 | } | 4670 | } |
| 4671 | 4671 | ||
| 4672 | switch (def->type) { | ||
| 4673 | case BPF_MAP_TYPE_PERF_EVENT_ARRAY: | ||
| 4674 | case BPF_MAP_TYPE_CGROUP_ARRAY: | ||
| 4675 | case BPF_MAP_TYPE_STACK_TRACE: | ||
| 4676 | case BPF_MAP_TYPE_ARRAY_OF_MAPS: | ||
| 4677 | case BPF_MAP_TYPE_HASH_OF_MAPS: | ||
| 4678 | case BPF_MAP_TYPE_DEVMAP: | ||
| 4679 | case BPF_MAP_TYPE_DEVMAP_HASH: | ||
| 4680 | case BPF_MAP_TYPE_CPUMAP: | ||
| 4681 | case BPF_MAP_TYPE_XSKMAP: | ||
| 4682 | case BPF_MAP_TYPE_SOCKMAP: | ||
| 4683 | case BPF_MAP_TYPE_SOCKHASH: | ||
| 4684 | case BPF_MAP_TYPE_QUEUE: | ||
| 4685 | case BPF_MAP_TYPE_STACK: | ||
| 4686 | case BPF_MAP_TYPE_RINGBUF: | ||
| 4687 | create_attr.btf_fd = 0; | ||
| 4688 | create_attr.btf_key_type_id = 0; | ||
| 4689 | create_attr.btf_value_type_id = 0; | ||
| 4690 | map->btf_key_type_id = 0; | ||
| 4691 | map->btf_value_type_id = 0; | ||
| 4692 | default: | ||
| 4693 | break; | ||
| 4694 | } | ||
| 4695 | |||
| 4672 | if (obj->gen_loader) { | 4696 | if (obj->gen_loader) { |
| 4673 | bpf_gen__map_create(obj->gen_loader, &create_attr, is_inner ? -1 : map - obj->maps); | 4697 | bpf_gen__map_create(obj->gen_loader, &create_attr, is_inner ? -1 : map - obj->maps); |
| 4674 | /* Pretend to have valid FD to pass various fd >= 0 checks. | 4698 | /* Pretend to have valid FD to pass various fd >= 0 checks. |
| @@ -9,8 +9,8 @@ · 8 unmodified lines | |||
| 9 | char _license[] SEC("license") = "GPL"; | 9 | char _license[] SEC("license") = "GPL"; |
| 10 | struct { | 10 | struct { |
| 11 | __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); | 11 | __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); |
| 12 | __uint(key_size, sizeof(int)); | 12 | __type(key, int); |
| 13 | __uint(value_size, sizeof(int)); | 13 | __type(value, int); |
| 14 | } perf_buf_map SEC(".maps"); | 14 | } perf_buf_map SEC(".maps"); |
| 15 | 15 | ||
| 16 | #define _(P) (__builtin_preserve_access_index(P)) | 16 | #define _(P) (__builtin_preserve_access_index(P)) |
| @@ -11,8 +11,8 @@ typedef __u64 stack_trace_t[PERF_MAX_STACK_DEPTH]; · 10 unmodified lines | |||
| 11 | struct { | 11 | struct { |
| 12 | __uint(type, BPF_MAP_TYPE_STACK_TRACE); | 12 | __uint(type, BPF_MAP_TYPE_STACK_TRACE); |
| 13 | __uint(max_entries, 16384); | 13 | __uint(max_entries, 16384); |
| 14 | __uint(key_size, sizeof(__u32)); | 14 | __type(key, __u32); |
| 15 | __uint(value_size, sizeof(stack_trace_t)); | 15 | __type(value, stack_trace_t); |
| 16 | } stackmap SEC(".maps"); | 16 | } stackmap SEC(".maps"); |
| 17 | 17 | ||
| 18 | struct { | 18 | struct { |
| @@ -7,22 +7,22 @@ int _version SEC("version") = 1; · 6 unmodified lines | |||
| 7 | struct { | 7 | struct { |
| 8 | __uint(type, BPF_MAP_TYPE_SOCKMAP); | 8 | __uint(type, BPF_MAP_TYPE_SOCKMAP); |
| 9 | __uint(max_entries, 20); | 9 | __uint(max_entries, 20); |
| 10 | __uint(key_size, sizeof(int)); | 10 | __type(key, int); |
| 11 | __uint(value_size, sizeof(int)); | 11 | __type(value, int); |
| 12 | } sock_map_rx SEC(".maps"); | 12 | } sock_map_rx SEC(".maps"); |
| 13 | 13 | ||
| 14 | struct { | 14 | struct { |
| 15 | __uint(type, BPF_MAP_TYPE_SOCKMAP); | 15 | __uint(type, BPF_MAP_TYPE_SOCKMAP); |
| 16 | __uint(max_entries, 20); | 16 | __uint(max_entries, 20); |
| 17 | __uint(key_size, sizeof(int)); | 17 | __type(key, int); |
| 18 | __uint(value_size, sizeof(int)); | 18 | __type(value, int); |
| 19 | } sock_map_tx SEC(".maps"); | 19 | } sock_map_tx SEC(".maps"); |
| 20 | 20 | ||
| 21 | struct { | 21 | struct { |
| 22 | __uint(type, BPF_MAP_TYPE_SOCKMAP); | 22 | __uint(type, BPF_MAP_TYPE_SOCKMAP); |
| 23 | __uint(max_entries, 20); | 23 | __uint(max_entries, 20); |
| 24 | __uint(key_size, sizeof(int)); | 24 | __type(key, int); |
| 25 | __uint(value_size, sizeof(int)); | 25 | __type(value, int); |
| 26 | } sock_map_msg SEC(".maps"); | 26 | } sock_map_msg SEC(".maps"); |
| 27 | 27 | ||
| 28 | struct { | 28 | struct { |
| @@ -21,8 +21,8 @@ struct inner_map_sz2 { · 20 unmodified lines | |||
| 21 | struct outer_arr { | 21 | struct outer_arr { |
| 22 | __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); | 22 | __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); |
| 23 | __uint(max_entries, 3); | 23 | __uint(max_entries, 3); |
| 24 | __uint(key_size, sizeof(int)); | 24 | __type(key, int); |
| 25 | __uint(value_size, sizeof(int)); | 25 | __type(value, int); |
| 26 | /* it's possible to use anonymous struct as inner map definition here */ | 26 | /* it's possible to use anonymous struct as inner map definition here */ |
| 27 | __array(values, struct { | 27 | __array(values, struct { |
| 28 | __uint(type, BPF_MAP_TYPE_ARRAY); | 28 | __uint(type, BPF_MAP_TYPE_ARRAY); |
| @@ -61,8 +61,8 @@ struct inner_map_sz4 { · 32 unmodified lines | |||
| 61 | struct outer_arr_dyn { | 61 | struct outer_arr_dyn { |
| 62 | __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); | 62 | __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); |
| 63 | __uint(max_entries, 3); | 63 | __uint(max_entries, 3); |
| 64 | __uint(key_size, sizeof(int)); | 64 | __type(key, int); |
| 65 | __uint(value_size, sizeof(int)); | 65 | __type(value, int); |
| 66 | __array(values, struct { | 66 | __array(values, struct { |
| 67 | __uint(type, BPF_MAP_TYPE_ARRAY); | 67 | __uint(type, BPF_MAP_TYPE_ARRAY); |
| 68 | __uint(map_flags, BPF_F_INNER_MAP); | 68 | __uint(map_flags, BPF_F_INNER_MAP); |
| @@ -81,7 +81,7 @@ struct outer_arr_dyn { · 12 unmodified lines | |||
| 81 | struct outer_hash { | 81 | struct outer_hash { |
| 82 | __uint(type, BPF_MAP_TYPE_HASH_OF_MAPS); | 82 | __uint(type, BPF_MAP_TYPE_HASH_OF_MAPS); |
| 83 | __uint(max_entries, 5); | 83 | __uint(max_entries, 5); |
| 84 | __uint(key_size, sizeof(int)); | 84 | __type(key, int); |
| 85 | /* Here everything works flawlessly due to reuse of struct inner_map | 85 | /* Here everything works flawlessly due to reuse of struct inner_map |
| 86 | * and compiler will complain at the attempt to use non-inner_map | 86 | * and compiler will complain at the attempt to use non-inner_map |
| 87 | * references below. This is great experience. | 87 | * references below. This is great experience. |
| @@ -111,8 +111,8 @@ struct sockarr_sz2 { · 23 unmodified lines | |||
| 111 | struct outer_sockarr_sz1 { | 111 | struct outer_sockarr_sz1 { |
| 112 | __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); | 112 | __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); |
| 113 | __uint(max_entries, 1); | 113 | __uint(max_entries, 1); |
| 114 | __uint(key_size, sizeof(int)); | 114 | __type(key, int); |
| 115 | __uint(value_size, sizeof(int)); | 115 | __type(value, int); |
| 116 | __array(values, struct sockarr_sz1); | 116 | __array(values, struct sockarr_sz1); |
| 117 | } outer_sockarr SEC(".maps") = { | 117 | } outer_sockarr SEC(".maps") = { |
| 118 | .values = { (void *)&sockarr_sz1 }, | 118 | .values = { (void *)&sockarr_sz1 }, |
| @@ -9,18 +9,16 @@ struct { · 8 unmodified lines | |||
| 9 | __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); | 9 | __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); |
| 10 | __uint(max_entries, 1); | 10 | __uint(max_entries, 1); |
| 11 | __uint(map_flags, 0); | 11 | __uint(map_flags, 0); |
| 12 | __uint(key_size, sizeof(__u32)); | 12 | __type(key, __u32); |
| 13 | /* must be sizeof(__u32) for map in map */ | 13 | __type(value, __u32); |
| 14 | __uint(value_size, sizeof(__u32)); | ||
| 15 | } mim_array SEC(".maps"); | 14 | } mim_array SEC(".maps"); |
| 16 | 15 | ||
| 17 | struct { | 16 | struct { |
| 18 | __uint(type, BPF_MAP_TYPE_HASH_OF_MAPS); | 17 | __uint(type, BPF_MAP_TYPE_HASH_OF_MAPS); |
| 19 | __uint(max_entries, 1); | 18 | __uint(max_entries, 1); |
| 20 | __uint(map_flags, 0); | 19 | __uint(map_flags, 0); |
| 21 | __uint(key_size, sizeof(int)); | 20 | __type(key, int); |
| 22 | /* must be sizeof(__u32) for map in map */ | 21 | __type(value, __u32); |
| 23 | __uint(value_size, sizeof(__u32)); | ||
| 24 | } mim_hash SEC(".maps"); | 22 | } mim_hash SEC(".maps"); |
| 25 | 23 | ||
| 26 | SEC("xdp") | 24 | SEC("xdp") |
| @@ -13,7 +13,7 @@ struct inner { · 12 unmodified lines | |||
| 13 | struct { | 13 | struct { |
| 14 | __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); | 14 | __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); |
| 15 | __uint(max_entries, 0); /* This will make map creation to fail */ | 15 | __uint(max_entries, 0); /* This will make map creation to fail */ |
| 16 | __uint(key_size, sizeof(__u32)); | 16 | __type(key, __u32); |
| 17 | __array(values, struct inner); | 17 | __array(values, struct inner); |
| 18 | } mim SEC(".maps"); | 18 | } mim SEC(".maps"); |
| 19 | 19 | ||
| @@ -7,15 +7,15 @@ · 6 unmodified lines | |||
| 7 | struct { | 7 | struct { |
| 8 | __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); | 8 | __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); |
| 9 | __uint(max_entries, 1); | 9 | __uint(max_entries, 1); |
| 10 | __uint(key_size, sizeof(int)); | 10 | __type(key, int); |
| 11 | __uint(value_size, sizeof(int)); | 11 | __type(value, int); |
| 12 | } array_1 SEC(".maps"); | 12 | } array_1 SEC(".maps"); |
| 13 | 13 | ||
| 14 | struct { | 14 | struct { |
| 15 | __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); | 15 | __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); |
| 16 | __uint(max_entries, 1); | 16 | __uint(max_entries, 1); |
| 17 | __uint(key_size, sizeof(int)); | 17 | __type(key, int); |
| 18 | __uint(value_size, sizeof(int)); | 18 | __type(value, int); |
| 19 | __uint(map_flags, BPF_F_PRESERVE_ELEMS); | 19 | __uint(map_flags, BPF_F_PRESERVE_ELEMS); |
| 20 | } array_2 SEC(".maps"); | 20 | } array_2 SEC(".maps"); |
| 21 | 21 | ||
| @@ -8,8 +8,8 @@ · 7 unmodified lines | |||
| 8 | 8 | ||
| 9 | struct { | 9 | struct { |
| 10 | __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); | 10 | __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); |
| 11 | __uint(key_size, sizeof(int)); | 11 | __type(key, int); |
| 12 | __uint(value_size, sizeof(int)); | 12 | __type(value, int); |
| 13 | } perf_buf_map SEC(".maps"); | 13 | } perf_buf_map SEC(".maps"); |
| 14 | 14 | ||
| 15 | SEC("tp/raw_syscalls/sys_enter") | 15 | SEC("tp/raw_syscalls/sys_enter") |
| @@ -24,8 +24,8 @@ int _version SEC("version") = 1; · 23 unmodified lines | |||
| 24 | struct { | 24 | struct { |
| 25 | __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); | 25 | __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); |
| 26 | __uint(max_entries, 1); | 26 | __uint(max_entries, 1); |
| 27 | __uint(key_size, sizeof(__u32)); | 27 | __type(key, __u32); |
| 28 | __uint(value_size, sizeof(__u32)); | 28 | __type(value, __u32); |
| 29 | } outer_map SEC(".maps"); | 29 | } outer_map SEC(".maps"); |
| 30 | 30 | ||
| 31 | struct { | 31 | struct { |
| @@ -28,8 +28,8 @@ struct { · 27 unmodified lines | |||
| 28 | __uint(type, BPF_MAP_TYPE_STACK_TRACE); | 28 | __uint(type, BPF_MAP_TYPE_STACK_TRACE); |
| 29 | __uint(max_entries, 128); | 29 | __uint(max_entries, 128); |
| 30 | __uint(map_flags, BPF_F_STACK_BUILD_ID); | 30 | __uint(map_flags, BPF_F_STACK_BUILD_ID); |
| 31 | __uint(key_size, sizeof(__u32)); | 31 | __type(key, __u32); |
| 32 | __uint(value_size, sizeof(stack_trace_t)); | 32 | __type(value, stack_trace_t); |
| 33 | } stackmap SEC(".maps"); | 33 | } stackmap SEC(".maps"); |
| 34 | 34 | ||
| 35 | struct { | 35 | struct { |
| @@ -27,8 +27,8 @@ typedef __u64 stack_trace_t[PERF_MAX_STACK_DEPTH]; · 26 unmodified lines | |||
| 27 | struct { | 27 | struct { |
| 28 | __uint(type, BPF_MAP_TYPE_STACK_TRACE); | 28 | __uint(type, BPF_MAP_TYPE_STACK_TRACE); |
| 29 | __uint(max_entries, 16384); | 29 | __uint(max_entries, 16384); |
| 30 | __uint(key_size, sizeof(__u32)); | 30 | __type(key, __u32); |
| 31 | __uint(value_size, sizeof(stack_trace_t)); | 31 | __type(value, stack_trace_t); |
| 32 | } stackmap SEC(".maps"); | 32 | } stackmap SEC(".maps"); |
| 33 | 33 | ||
| 34 | struct { | 34 | struct { |
| @@ -24,8 +24,8 @@ struct { · 23 unmodified lines | |||
| 24 | struct { | 24 | struct { |
| 25 | __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); | 25 | __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); |
| 26 | __uint(max_entries, 2); | 26 | __uint(max_entries, 2); |
| 27 | __uint(key_size, sizeof(int)); | 27 | __type(key, int); |
| 28 | __uint(value_size, sizeof(__u32)); | 28 | __type(value, __u32); |
| 29 | } perf_event_map SEC(".maps"); | 29 | } perf_event_map SEC(".maps"); |
| 30 | 30 | ||
| 31 | int _version SEC("version") = 1; | 31 | int _version SEC("version") = 1; |
| @@ -36,8 +36,8 @@ struct meta { · 35 unmodified lines | |||
| 36 | 36 | ||
| 37 | struct { | 37 | struct { |
| 38 | __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); | 38 | __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); |
| 39 | __uint(key_size, sizeof(int)); | 39 | __type(key, int); |
| 40 | __uint(value_size, sizeof(int)); | 40 | __type(value, int); |
| 41 | } perf_buf_map SEC(".maps"); | 41 | } perf_buf_map SEC(".maps"); |
| 42 | 42 | ||
| 43 | __u64 test_result_fentry = 0; | 43 | __u64 test_result_fentry = 0; |