1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ 3 #include <errno.h> 4 #include <sys/syscall.h> 5 #include <unistd.h> 6 #include "test_global_map_resize.skel.h" 7 #include "test_progs.h" 8 9 static void run_prog_bss_array_sum(void) 10 { 11 (void)syscall(__NR_getpid); 12 } 13 14 static void run_prog_data_array_sum(void) 15 { 16 (void)syscall(__NR_getuid); 17 } 18 19 static void global_map_resize_bss_subtest(void) 20 { 21 int err; 22 struct test_global_map_resize *skel; 23 struct bpf_map *map; 24 const __u32 desired_sz = sizeof(skel->bss->sum) + sysconf(_SC_PAGE_SIZE) * 2; 25 size_t array_len, actual_sz, new_sz; 26 27 skel = test_global_map_resize__open(); 28 if (!ASSERT_OK_PTR(skel, "test_global_map_resize__open")) 29 goto teardown; 30 31 /* set some initial value before resizing. 32 * it is expected this non-zero value will be preserved 33 * while resizing. 34 */ 35 skel->bss->array[0] = 1; 36 37 /* resize map value and verify the new size */ 38 map = skel->maps.bss; 39 err = bpf_map__set_value_size(map, desired_sz); 40 if (!ASSERT_OK(err, "bpf_map__set_value_size")) 41 goto teardown; 42 if (!ASSERT_EQ(bpf_map__value_size(map), desired_sz, "resize")) 43 goto teardown; 44 45 new_sz = sizeof(skel->data_percpu_arr->percpu_arr[0]) * libbpf_num_possible_cpus(); 46 err = bpf_map__set_value_size(skel->maps.data_percpu_arr, new_sz); 47 ASSERT_OK(err, "percpu_arr_resize"); 48 49 /* set the expected number of elements based on the resized array */ 50 array_len = (desired_sz - sizeof(skel->bss->sum)) / sizeof(skel->bss->array[0]); 51 if (!ASSERT_GT(array_len, 1, "array_len")) 52 goto teardown; 53 54 skel->bss = bpf_map__initial_value(skel->maps.bss, &actual_sz); 55 if (!ASSERT_OK_PTR(skel->bss, "bpf_map__initial_value (ptr)")) 56 goto teardown; 57 if (!ASSERT_EQ(actual_sz, desired_sz, "bpf_map__initial_value (size)")) 58 goto teardown; 59 60 /* fill the newly resized array with ones, 61 * skipping the first element which was previously set 62 */ 63 for (int i = 1; i < array_len; i++) 64 skel->bss->array[i] = 1; 65 66 /* set global const values before loading */ 67 skel->rodata->pid = getpid(); 68 skel->rodata->bss_array_len = array_len; 69 skel->rodata->data_array_len = 1; 70 71 err = test_global_map_resize__load(skel); 72 if (!ASSERT_OK(err, "test_global_map_resize__load")) 73 goto teardown; 74 err = test_global_map_resize__attach(skel); 75 if (!ASSERT_OK(err, "test_global_map_resize__attach")) 76 goto teardown; 77 78 /* run the bpf program which will sum the contents of the array. 79 * since the array was filled with ones,verify the sum equals array_len 80 */ 81 run_prog_bss_array_sum(); 82 if (!ASSERT_EQ(skel->bss->sum, array_len, "sum")) 83 goto teardown; 84 85 teardown: 86 test_global_map_resize__destroy(skel); 87 } 88 89 static void global_map_resize_data_subtest(void) 90 { 91 struct test_global_map_resize *skel; 92 struct bpf_map *map; 93 const __u32 desired_sz = sysconf(_SC_PAGE_SIZE) * 2; 94 size_t array_len, actual_sz, new_sz; 95 int err; 96 97 skel = test_global_map_resize__open(); 98 if (!ASSERT_OK_PTR(skel, "test_global_map_resize__open")) 99 goto teardown; 100 101 /* set some initial value before resizing. 102 * it is expected this non-zero value will be preserved 103 * while resizing. 104 */ 105 skel->data_custom->my_array[0] = 1; 106 107 /* resize map value and verify the new size */ 108 map = skel->maps.data_custom; 109 err = bpf_map__set_value_size(map, desired_sz); 110 if (!ASSERT_OK(err, "bpf_map__set_value_size")) 111 goto teardown; 112 if (!ASSERT_EQ(bpf_map__value_size(map), desired_sz, "resize")) 113 goto teardown; 114 115 new_sz = sizeof(skel->data_percpu_arr->percpu_arr[0]) * libbpf_num_possible_cpus(); 116 err = bpf_map__set_value_size(skel->maps.data_percpu_arr, new_sz); 117 ASSERT_OK(err, "percpu_arr_resize"); 118 119 /* set the expected number of elements based on the resized array */ 120 array_len = (desired_sz - sizeof(skel->bss->sum)) / sizeof(skel->data_custom->my_array[0]); 121 if (!ASSERT_GT(array_len, 1, "array_len")) 122 goto teardown; 123 124 skel->data_custom = bpf_map__initial_value(skel->maps.data_custom, &actual_sz); 125 if (!ASSERT_OK_PTR(skel->data_custom, "bpf_map__initial_value (ptr)")) 126 goto teardown; 127 if (!ASSERT_EQ(actual_sz, desired_sz, "bpf_map__initial_value (size)")) 128 goto teardown; 129 130 /* fill the newly resized array with ones, 131 * skipping the first element which was previously set 132 */ 133 for (int i = 1; i < array_len; i++) 134 skel->data_custom->my_array[i] = 1; 135 136 /* set global const values before loading */ 137 skel->rodata->pid = getpid(); 138 skel->rodata->bss_array_len = 1; 139 skel->rodata->data_array_len = array_len; 140 141 err = test_global_map_resize__load(skel); 142 if (!ASSERT_OK(err, "test_global_map_resize__load")) 143 goto teardown; 144 err = test_global_map_resize__attach(skel); 145 if (!ASSERT_OK(err, "test_global_map_resize__attach")) 146 goto teardown; 147 148 /* run the bpf program which will sum the contents of the array. 149 * since the array was filled with ones,verify the sum equals array_len 150 */ 151 run_prog_data_array_sum(); 152 if (!ASSERT_EQ(skel->bss->sum, array_len, "sum")) 153 goto teardown; 154 155 teardown: 156 test_global_map_resize__destroy(skel); 157 } 158 159 static void global_map_resize_invalid_subtest(void) 160 { 161 int err; 162 struct test_global_map_resize *skel; 163 struct bpf_map *map; 164 __u32 element_sz, desired_sz; 165 166 skel = test_global_map_resize__open(); 167 if (!ASSERT_OK_PTR(skel, "test_global_map_resize__open")) 168 return; 169 170 /* attempt to resize a global datasec map to size 171 * which does NOT align with array 172 */ 173 map = skel->maps.data_custom; 174 if (!ASSERT_NEQ(bpf_map__btf_value_type_id(map), 0, ".data.custom initial btf")) 175 goto teardown; 176 /* set desired size a fraction of element size beyond an aligned size */ 177 element_sz = sizeof(skel->data_custom->my_array[0]); 178 desired_sz = element_sz + element_sz / 2; 179 /* confirm desired size does NOT align with array */ 180 if (!ASSERT_NEQ(desired_sz % element_sz, 0, "my_array alignment")) 181 goto teardown; 182 err = bpf_map__set_value_size(map, desired_sz); 183 /* confirm resize is OK but BTF info is cleared */ 184 if (!ASSERT_OK(err, ".data.custom bpf_map__set_value_size") || 185 !ASSERT_EQ(bpf_map__btf_key_type_id(map), 0, ".data.custom clear btf key") || 186 !ASSERT_EQ(bpf_map__btf_value_type_id(map), 0, ".data.custom clear btf val")) 187 goto teardown; 188 189 /* attempt to resize a global datasec map whose only var is NOT an array */ 190 map = skel->maps.data_non_array; 191 if (!ASSERT_NEQ(bpf_map__btf_value_type_id(map), 0, ".data.non_array initial btf")) 192 goto teardown; 193 /* set desired size to arbitrary value */ 194 desired_sz = 1024; 195 err = bpf_map__set_value_size(map, desired_sz); 196 /* confirm resize is OK but BTF info is cleared */ 197 if (!ASSERT_OK(err, ".data.non_array bpf_map__set_value_size") || 198 !ASSERT_EQ(bpf_map__btf_key_type_id(map), 0, ".data.non_array clear btf key") || 199 !ASSERT_EQ(bpf_map__btf_value_type_id(map), 0, ".data.non_array clear btf val")) 200 goto teardown; 201 202 /* attempt to resize a global datasec map 203 * whose last var is NOT an array 204 */ 205 map = skel->maps.data_array_not_last; 206 if (!ASSERT_NEQ(bpf_map__btf_value_type_id(map), 0, ".data.array_not_last initial btf")) 207 goto teardown; 208 /* set desired size to a multiple of element size */ 209 element_sz = sizeof(skel->data_array_not_last->my_array_first[0]); 210 desired_sz = element_sz * 8; 211 /* confirm desired size aligns with array */ 212 if (!ASSERT_EQ(desired_sz % element_sz, 0, "my_array_first alignment")) 213 goto teardown; 214 err = bpf_map__set_value_size(map, desired_sz); 215 /* confirm resize is OK but BTF info is cleared */ 216 if (!ASSERT_OK(err, ".data.array_not_last bpf_map__set_value_size") || 217 !ASSERT_EQ(bpf_map__btf_key_type_id(map), 0, ".data.array_not_last clear btf key") || 218 !ASSERT_EQ(bpf_map__btf_value_type_id(map), 0, ".data.array_not_last clear btf val")) 219 goto teardown; 220 221 teardown: 222 test_global_map_resize__destroy(skel); 223 } 224 225 void test_global_map_resize(void) 226 { 227 if (test__start_subtest("global_map_resize_bss")) 228 global_map_resize_bss_subtest(); 229 230 if (test__start_subtest("global_map_resize_data")) 231 global_map_resize_data_subtest(); 232 233 if (test__start_subtest("global_map_resize_invalid")) 234 global_map_resize_invalid_subtest(); 235 } 236