Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'selftests-bpf-migrate-a-few-bpftool-testing-scripts'

Alexis Lothoré says:

====================
selftests/bpf: migrate a few bpftool testing scripts

this is the v4 for some bpftool tests conversion. The new tests are
being integrated in test_progs so that they can be executed on each CI
run.

- First commit introduces a few dedicated helpers to execute bpftool
commands, with or without retrieving the generated stdout output
- Second commit integrates test_bpftool_metadata.sh into test_progs
- Third commit integrates test_bpftool_map.sh into test_progs

Signed-off-by: Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>
---
Changes in v4:
- Port missing map access test in bpftool_metadata
- Link to v3: https://lore.kernel.org/r/20260121-bpftool-tests-v3-0-368632f377e5@bootlin.com

Changes in v3:
- Drop commit reordering objects in Makefile
- Rebased series on ci/bpf-next_base to fix conflict
- Link to v2: https://lore.kernel.org/r/20260121-bpftool-tests-v2-0-64edb47e91ae@bootlin.com

Changes in v2:
- drop standalone runner in favor of test_progs
- Link to v1: https://lore.kernel.org/r/20260114-bpftool-tests-v1-0-cfab1cc9beaf@bootlin.com

====================

Link: https://patch.msgid.link/20260123-bpftool-tests-v4-0-a6653a7f28e7@bootlin.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

+602 -486
+2 -3
tools/testing/selftests/bpf/Makefile
··· 108 108 test_xdping.sh \ 109 109 test_bpftool_build.sh \ 110 110 test_bpftool.sh \ 111 - test_bpftool_map.sh \ 112 - test_bpftool_metadata.sh \ 113 111 test_doc_build.sh \ 114 112 test_xsk.sh \ 115 113 test_xdp_features.sh ··· 745 747 json_writer.c \ 746 748 $(VERIFY_SIG_HDR) \ 747 749 flow_dissector_load.h \ 748 - ip_check_defrag_frags.h 750 + ip_check_defrag_frags.h \ 751 + bpftool_helpers.c 749 752 TRUNNER_LIB_SOURCES := find_bit.c 750 753 TRUNNER_EXTRA_FILES := $(OUTPUT)/urandom_read \ 751 754 $(OUTPUT)/liburandom_read.so \
+74
tools/testing/selftests/bpf/bpftool_helpers.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + #include "bpftool_helpers.h" 3 + #include <unistd.h> 4 + #include <string.h> 5 + #include <stdbool.h> 6 + 7 + #define BPFTOOL_PATH_MAX_LEN 64 8 + #define BPFTOOL_FULL_CMD_MAX_LEN 512 9 + 10 + #define BPFTOOL_DEFAULT_PATH "tools/sbin/bpftool" 11 + 12 + static int detect_bpftool_path(char *buffer) 13 + { 14 + char tmp[BPFTOOL_PATH_MAX_LEN]; 15 + 16 + /* Check default bpftool location (will work if we are running the 17 + * default flavor of test_progs) 18 + */ 19 + snprintf(tmp, BPFTOOL_PATH_MAX_LEN, "./%s", BPFTOOL_DEFAULT_PATH); 20 + if (access(tmp, X_OK) == 0) { 21 + strncpy(buffer, tmp, BPFTOOL_PATH_MAX_LEN); 22 + return 0; 23 + } 24 + 25 + /* Check alternate bpftool location (will work if we are running a 26 + * specific flavor of test_progs, e.g. cpuv4 or no_alu32) 27 + */ 28 + snprintf(tmp, BPFTOOL_PATH_MAX_LEN, "../%s", BPFTOOL_DEFAULT_PATH); 29 + if (access(tmp, X_OK) == 0) { 30 + strncpy(buffer, tmp, BPFTOOL_PATH_MAX_LEN); 31 + return 0; 32 + } 33 + 34 + /* Failed to find bpftool binary */ 35 + return 1; 36 + } 37 + 38 + static int run_command(char *args, char *output_buf, size_t output_max_len) 39 + { 40 + static char bpftool_path[BPFTOOL_PATH_MAX_LEN] = {0}; 41 + bool suppress_output = !(output_buf && output_max_len); 42 + char command[BPFTOOL_FULL_CMD_MAX_LEN]; 43 + FILE *f; 44 + int ret; 45 + 46 + /* Detect and cache bpftool binary location */ 47 + if (bpftool_path[0] == 0 && detect_bpftool_path(bpftool_path)) 48 + return 1; 49 + 50 + ret = snprintf(command, BPFTOOL_FULL_CMD_MAX_LEN, "%s %s%s", 51 + bpftool_path, args, 52 + suppress_output ? " > /dev/null 2>&1" : ""); 53 + 54 + f = popen(command, "r"); 55 + if (!f) 56 + return 1; 57 + 58 + if (!suppress_output) 59 + fread(output_buf, 1, output_max_len, f); 60 + ret = pclose(f); 61 + 62 + return ret; 63 + } 64 + 65 + int run_bpftool_command(char *args) 66 + { 67 + return run_command(args, NULL, 0); 68 + } 69 + 70 + int get_bpftool_command_output(char *args, char *output_buf, size_t output_max_len) 71 + { 72 + return run_command(args, output_buf, output_max_len); 73 + } 74 +
+11
tools/testing/selftests/bpf/bpftool_helpers.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + #pragma once 3 + 4 + #include <stdlib.h> 5 + #include <stdio.h> 6 + #include <stdbool.h> 7 + 8 + #define MAX_BPFTOOL_CMD_LEN (256) 9 + 10 + int run_bpftool_command(char *args); 11 + int get_bpftool_command_output(char *args, char *output_buf, size_t output_max_len);
+371
tools/testing/selftests/bpf/prog_tests/bpftool_maps_access.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + #include <stdlib.h> 4 + #include <unistd.h> 5 + #include <fcntl.h> 6 + #include <stdint.h> 7 + #include <sys/stat.h> 8 + #include <stdbool.h> 9 + #include <linux/bpf.h> 10 + #include <bpf/libbpf.h> 11 + #include <bpftool_helpers.h> 12 + #include <test_progs.h> 13 + #include <bpf/bpf.h> 14 + #include "security_bpf_map.skel.h" 15 + 16 + #define PROTECTED_MAP_NAME "prot_map" 17 + #define UNPROTECTED_MAP_NAME "not_prot_map" 18 + #define BPF_ITER_FILE "bpf_iter_map_elem.bpf.o" 19 + #define BPFFS_PIN_DIR "/sys/fs/bpf/test_bpftool_map" 20 + #define INNER_MAP_NAME "inner_map_tt" 21 + #define OUTER_MAP_NAME "outer_map_tt" 22 + 23 + #define MAP_NAME_MAX_LEN 64 24 + #define PATH_MAX_LEN 128 25 + 26 + enum map_protection { 27 + PROTECTED, 28 + UNPROTECTED 29 + }; 30 + 31 + struct test_desc { 32 + char *name; 33 + enum map_protection protection; 34 + struct bpf_map *map; 35 + char *map_name; 36 + bool pinned; 37 + char pin_path[PATH_MAX_LEN]; 38 + bool write_must_fail; 39 + }; 40 + 41 + static struct security_bpf_map *general_setup(void) 42 + { 43 + struct security_bpf_map *skel; 44 + uint32_t key, value; 45 + int ret, i; 46 + 47 + skel = security_bpf_map__open_and_load(); 48 + if (!ASSERT_OK_PTR(skel, "open and load skeleton")) 49 + goto end; 50 + 51 + struct bpf_map *maps[] = {skel->maps.prot_map, skel->maps.not_prot_map}; 52 + 53 + ret = security_bpf_map__attach(skel); 54 + if (!ASSERT_OK(ret, "attach maps security programs")) 55 + goto end_destroy; 56 + 57 + for (i = 0; i < sizeof(maps)/sizeof(struct bpf_map *); i++) { 58 + for (key = 0; key < 2; key++) { 59 + int ret = bpf_map__update_elem(maps[i], &key, 60 + sizeof(key), &key, sizeof(key), 61 + 0); 62 + if (!ASSERT_OK(ret, "set initial map value")) 63 + goto end_destroy; 64 + } 65 + } 66 + 67 + key = 0; 68 + value = 1; 69 + ret = bpf_map__update_elem(skel->maps.prot_status_map, &key, 70 + sizeof(key), &value, sizeof(value), 0); 71 + if (!ASSERT_OK(ret, "configure map protection")) 72 + goto end_destroy; 73 + 74 + if (!ASSERT_OK(mkdir(BPFFS_PIN_DIR, S_IFDIR), "create bpffs pin dir")) 75 + goto end_destroy; 76 + 77 + return skel; 78 + end_destroy: 79 + security_bpf_map__destroy(skel); 80 + end: 81 + return NULL; 82 + } 83 + 84 + static void general_cleanup(struct security_bpf_map *skel) 85 + { 86 + rmdir(BPFFS_PIN_DIR); 87 + security_bpf_map__destroy(skel); 88 + } 89 + 90 + static void update_test_desc(struct security_bpf_map *skel, 91 + struct test_desc *test) 92 + { 93 + /* Now that the skeleton is loaded, update all missing fields to 94 + * have the subtest properly configured 95 + */ 96 + if (test->protection == PROTECTED) { 97 + test->map = skel->maps.prot_map; 98 + test->map_name = PROTECTED_MAP_NAME; 99 + } else { 100 + test->map = skel->maps.not_prot_map; 101 + test->map_name = UNPROTECTED_MAP_NAME; 102 + } 103 + } 104 + 105 + static int test_setup(struct security_bpf_map *skel, struct test_desc *desc) 106 + { 107 + int ret; 108 + 109 + update_test_desc(skel, desc); 110 + 111 + if (desc->pinned) { 112 + ret = snprintf(desc->pin_path, PATH_MAX_LEN, "%s/%s", BPFFS_PIN_DIR, 113 + desc->name); 114 + if (!ASSERT_GT(ret, 0, "format pin path")) 115 + return 1; 116 + ret = bpf_map__pin(desc->map, desc->pin_path); 117 + if (!ASSERT_OK(ret, "pin map")) 118 + return 1; 119 + } 120 + 121 + return 0; 122 + } 123 + 124 + static void test_cleanup(struct test_desc *desc) 125 + { 126 + if (desc->pinned) 127 + bpf_map__unpin(desc->map, NULL); 128 + } 129 + 130 + static int lookup_map_value(char *map_handle) 131 + { 132 + char cmd[MAX_BPFTOOL_CMD_LEN]; 133 + int ret = 0; 134 + 135 + ret = snprintf(cmd, MAX_BPFTOOL_CMD_LEN, "map lookup %s key 0 0 0 0", 136 + map_handle); 137 + if (!ASSERT_GT(ret, 0, "format map lookup cmd")) 138 + return 1; 139 + return run_bpftool_command(cmd); 140 + } 141 + 142 + static int read_map_btf_data(char *map_handle) 143 + { 144 + char cmd[MAX_BPFTOOL_CMD_LEN]; 145 + int ret = 0; 146 + 147 + ret = snprintf(cmd, MAX_BPFTOOL_CMD_LEN, "btf dump map %s", 148 + map_handle); 149 + if (!ASSERT_GT(ret, 0, "format map btf dump cmd")) 150 + return 1; 151 + return run_bpftool_command(cmd); 152 + } 153 + 154 + static int write_map_value(char *map_handle) 155 + { 156 + char cmd[MAX_BPFTOOL_CMD_LEN]; 157 + int ret = 0; 158 + 159 + ret = snprintf(cmd, MAX_BPFTOOL_CMD_LEN, 160 + "map update %s key 0 0 0 0 value 1 1 1 1", map_handle); 161 + if (!ASSERT_GT(ret, 0, "format value write cmd")) 162 + return 1; 163 + return run_bpftool_command(cmd); 164 + } 165 + 166 + static int delete_map_value(char *map_handle) 167 + { 168 + char cmd[MAX_BPFTOOL_CMD_LEN]; 169 + int ret = 0; 170 + 171 + ret = snprintf(cmd, MAX_BPFTOOL_CMD_LEN, 172 + "map delete %s key 0 0 0 0", map_handle); 173 + if (!ASSERT_GT(ret, 0, "format value deletion cmd")) 174 + return 1; 175 + return run_bpftool_command(cmd); 176 + } 177 + 178 + static int iterate_on_map_values(char *map_handle, char *iter_pin_path) 179 + { 180 + char cmd[MAX_BPFTOOL_CMD_LEN]; 181 + int ret = 0; 182 + 183 + 184 + ret = snprintf(cmd, MAX_BPFTOOL_CMD_LEN, "iter pin %s %s map %s", 185 + BPF_ITER_FILE, iter_pin_path, map_handle); 186 + if (!ASSERT_GT(ret, 0, "format iterator creation cmd")) 187 + return 1; 188 + ret = run_bpftool_command(cmd); 189 + if (ret) 190 + return ret; 191 + ret = snprintf(cmd, MAP_NAME_MAX_LEN, "cat %s", iter_pin_path); 192 + if (ret < 0) 193 + goto cleanup; 194 + ret = system(cmd); 195 + 196 + cleanup: 197 + unlink(iter_pin_path); 198 + return ret; 199 + } 200 + 201 + static int create_inner_map(void) 202 + { 203 + char cmd[MAX_BPFTOOL_CMD_LEN]; 204 + int ret = 0; 205 + 206 + ret = snprintf( 207 + cmd, MAX_BPFTOOL_CMD_LEN, 208 + "map create %s/%s type array key 4 value 4 entries 4 name %s", 209 + BPFFS_PIN_DIR, INNER_MAP_NAME, INNER_MAP_NAME); 210 + if (!ASSERT_GT(ret, 0, "format inner map create cmd")) 211 + return 1; 212 + return run_bpftool_command(cmd); 213 + } 214 + 215 + static int create_outer_map(void) 216 + { 217 + char cmd[MAX_BPFTOOL_CMD_LEN]; 218 + int ret = 0; 219 + 220 + ret = snprintf( 221 + cmd, MAX_BPFTOOL_CMD_LEN, 222 + "map create %s/%s type hash_of_maps key 4 value 4 entries 2 name %s inner_map name %s", 223 + BPFFS_PIN_DIR, OUTER_MAP_NAME, OUTER_MAP_NAME, INNER_MAP_NAME); 224 + if (!ASSERT_GT(ret, 0, "format outer map create cmd")) 225 + return 1; 226 + return run_bpftool_command(cmd); 227 + } 228 + 229 + static void delete_pinned_map(char *map_name) 230 + { 231 + char pin_path[PATH_MAX_LEN]; 232 + int ret; 233 + 234 + ret = snprintf(pin_path, PATH_MAX_LEN, "%s/%s", BPFFS_PIN_DIR, 235 + map_name); 236 + if (ret >= 0) 237 + unlink(pin_path); 238 + } 239 + 240 + static int add_outer_map_entry(int key) 241 + { 242 + char cmd[MAX_BPFTOOL_CMD_LEN]; 243 + int ret = 0; 244 + 245 + ret = snprintf( 246 + cmd, MAX_BPFTOOL_CMD_LEN, 247 + "map update pinned %s/%s key %d 0 0 0 value name %s", 248 + BPFFS_PIN_DIR, OUTER_MAP_NAME, key, INNER_MAP_NAME); 249 + if (!ASSERT_GT(ret, 0, "format outer map value addition cmd")) 250 + return 1; 251 + return run_bpftool_command(cmd); 252 + } 253 + 254 + static void test_basic_access(struct test_desc *desc) 255 + { 256 + char map_handle[MAP_NAME_MAX_LEN]; 257 + char iter_pin_path[PATH_MAX_LEN]; 258 + int ret; 259 + 260 + if (desc->pinned) 261 + ret = snprintf(map_handle, MAP_NAME_MAX_LEN, "pinned %s", 262 + desc->pin_path); 263 + else 264 + ret = snprintf(map_handle, MAP_NAME_MAX_LEN, "name %s", 265 + desc->map_name); 266 + if (!ASSERT_GT(ret, 0, "format map handle")) 267 + return; 268 + 269 + ret = lookup_map_value(map_handle); 270 + ASSERT_OK(ret, "read map value"); 271 + 272 + ret = read_map_btf_data(map_handle); 273 + ASSERT_OK(ret, "read map btf data"); 274 + 275 + ret = write_map_value(map_handle); 276 + ASSERT_OK(desc->write_must_fail ? !ret : ret, "write map value"); 277 + 278 + ret = delete_map_value(map_handle); 279 + ASSERT_OK(desc->write_must_fail ? !ret : ret, "delete map value"); 280 + /* Restore deleted value */ 281 + if (!ret) 282 + write_map_value(map_handle); 283 + 284 + ret = snprintf(iter_pin_path, PATH_MAX_LEN, "%s/iter", BPFFS_PIN_DIR); 285 + if (ASSERT_GT(ret, 0, "format iter pin path")) { 286 + ret = iterate_on_map_values(map_handle, iter_pin_path); 287 + ASSERT_OK(ret, "iterate on map values"); 288 + } 289 + } 290 + 291 + static void test_create_nested_maps(void) 292 + { 293 + if (!ASSERT_OK(create_inner_map(), "create inner map")) 294 + return; 295 + if (!ASSERT_OK(create_outer_map(), "create outer map")) 296 + goto end_cleanup_inner; 297 + ASSERT_OK(add_outer_map_entry(0), "add a first entry in outer map"); 298 + ASSERT_OK(add_outer_map_entry(1), "add a second entry in outer map"); 299 + ASSERT_NEQ(add_outer_map_entry(2), 0, "add a third entry in outer map"); 300 + 301 + delete_pinned_map(OUTER_MAP_NAME); 302 + end_cleanup_inner: 303 + delete_pinned_map(INNER_MAP_NAME); 304 + } 305 + 306 + static void test_btf_list(void) 307 + { 308 + ASSERT_OK(run_bpftool_command("btf list"), "list btf data"); 309 + } 310 + 311 + static struct test_desc tests[] = { 312 + { 313 + .name = "unprotected_unpinned", 314 + .protection = UNPROTECTED, 315 + .map_name = UNPROTECTED_MAP_NAME, 316 + .pinned = false, 317 + .write_must_fail = false, 318 + }, 319 + { 320 + .name = "unprotected_pinned", 321 + .protection = UNPROTECTED, 322 + .map_name = UNPROTECTED_MAP_NAME, 323 + .pinned = true, 324 + .write_must_fail = false, 325 + }, 326 + { 327 + .name = "protected_unpinned", 328 + .protection = PROTECTED, 329 + .map_name = UNPROTECTED_MAP_NAME, 330 + .pinned = false, 331 + .write_must_fail = true, 332 + }, 333 + { 334 + .name = "protected_pinned", 335 + .protection = PROTECTED, 336 + .map_name = UNPROTECTED_MAP_NAME, 337 + .pinned = true, 338 + .write_must_fail = true, 339 + } 340 + }; 341 + 342 + static const size_t tests_count = ARRAY_SIZE(tests); 343 + 344 + void test_bpftool_maps_access(void) 345 + { 346 + struct security_bpf_map *skel; 347 + struct test_desc *current; 348 + int i; 349 + 350 + skel = general_setup(); 351 + if (!ASSERT_OK_PTR(skel, "prepare programs")) 352 + goto cleanup; 353 + 354 + for (i = 0; i < tests_count; i++) { 355 + current = &tests[i]; 356 + if (!test__start_subtest(current->name)) 357 + continue; 358 + if (ASSERT_OK(test_setup(skel, current), "subtest setup")) { 359 + test_basic_access(current); 360 + test_cleanup(current); 361 + } 362 + } 363 + if (test__start_subtest("nested_maps")) 364 + test_create_nested_maps(); 365 + if (test__start_subtest("btf_list")) 366 + test_btf_list(); 367 + 368 + cleanup: 369 + general_cleanup(skel); 370 + } 371 +
+144
tools/testing/selftests/bpf/prog_tests/bpftool_metadata.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + #include <bpftool_helpers.h> 3 + #include <test_progs.h> 4 + #include <linux/bpf.h> 5 + #include <string.h> 6 + #include <unistd.h> 7 + #include <fcntl.h> 8 + #include <sys/stat.h> 9 + #include <stdbool.h> 10 + 11 + #define BPFFS_DIR "/sys/fs/bpf/test_metadata" 12 + #define BPFFS_USED BPFFS_DIR "/used" 13 + #define BPFFS_UNUSED BPFFS_DIR "/unused" 14 + 15 + #define BPF_FILE_USED "metadata_used.bpf.o" 16 + #define BPF_FILE_UNUSED "metadata_unused.bpf.o" 17 + #define METADATA_MAP_NAME "metadata.rodata" 18 + 19 + #define MAX_BPFTOOL_OUTPUT_LEN (64*1024) 20 + 21 + #define MAX_TOKENS_TO_CHECK 3 22 + static char output[MAX_BPFTOOL_OUTPUT_LEN]; 23 + 24 + struct test_desc { 25 + char *name; 26 + char *bpf_prog; 27 + char *bpffs_path; 28 + char *expected_output[MAX_TOKENS_TO_CHECK]; 29 + char *expected_output_json[MAX_TOKENS_TO_CHECK]; 30 + char *metadata_map_name; 31 + }; 32 + 33 + static int setup(struct test_desc *test) 34 + { 35 + return mkdir(BPFFS_DIR, 0700); 36 + } 37 + 38 + static void cleanup(struct test_desc *test) 39 + { 40 + unlink(test->bpffs_path); 41 + rmdir(BPFFS_DIR); 42 + } 43 + 44 + static int check_metadata(char *buf, char * const *tokens, int count) 45 + { 46 + int i; 47 + 48 + for (i = 0; i < count && tokens[i]; i++) 49 + if (!strstr(buf, tokens[i])) 50 + return 1; 51 + 52 + return 0; 53 + } 54 + 55 + static void run_test(struct test_desc *test) 56 + { 57 + int ret; 58 + char cmd[MAX_BPFTOOL_CMD_LEN]; 59 + 60 + ret = snprintf(cmd, MAX_BPFTOOL_CMD_LEN, "prog load %s %s", 61 + test->bpf_prog, test->bpffs_path); 62 + if (!ASSERT_GT(ret, 0, "format prog insert command")) 63 + return; 64 + ret = run_bpftool_command(cmd); 65 + if (!ASSERT_OK(ret, "load program")) 66 + return; 67 + 68 + /* Check output with default format */ 69 + ret = snprintf(cmd, MAX_BPFTOOL_CMD_LEN, "prog show pinned %s", 70 + test->bpffs_path); 71 + if (!ASSERT_GT(ret, 0, "format pinned prog check command")) 72 + return; 73 + ret = get_bpftool_command_output(cmd, output, 74 + MAX_BPFTOOL_OUTPUT_LEN); 75 + if (ASSERT_OK(ret, "get program info")) { 76 + ret = check_metadata(output, test->expected_output, 77 + ARRAY_SIZE(test->expected_output)); 78 + ASSERT_OK(ret, "find metadata"); 79 + } 80 + 81 + /* Check output with json format */ 82 + ret = snprintf(cmd, MAX_BPFTOOL_CMD_LEN, "prog -j show pinned %s", 83 + test->bpffs_path); 84 + if (!ASSERT_GT(ret, 0, "format pinned prog check command in json")) 85 + return; 86 + ret = get_bpftool_command_output(cmd, output, 87 + MAX_BPFTOOL_OUTPUT_LEN); 88 + if (ASSERT_OK(ret, "get program info in json")) { 89 + ret = check_metadata(output, test->expected_output_json, 90 + ARRAY_SIZE(test->expected_output_json)); 91 + ASSERT_OK(ret, "find metadata in json"); 92 + } 93 + 94 + /* Check that the corresponding map can be found and accessed */ 95 + ret = snprintf(cmd, MAX_BPFTOOL_CMD_LEN, "map show name %s", 96 + test->metadata_map_name); 97 + if (!ASSERT_GT(ret, 0, "format map check command")) 98 + return; 99 + ASSERT_OK(run_bpftool_command(cmd), "access metadata map"); 100 + } 101 + 102 + static struct test_desc tests[] = { 103 + { 104 + .name = "metadata_unused", 105 + .bpf_prog = BPF_FILE_UNUSED, 106 + .bpffs_path = BPFFS_UNUSED, 107 + .expected_output = { 108 + "a = \"foo\"", 109 + "b = 1" 110 + }, 111 + .expected_output_json = { 112 + "\"metadata\":{\"a\":\"foo\",\"b\":1}" 113 + }, 114 + .metadata_map_name = METADATA_MAP_NAME 115 + }, 116 + { 117 + .name = "metadata_used", 118 + .bpf_prog = BPF_FILE_USED, 119 + .bpffs_path = BPFFS_USED, 120 + .expected_output = { 121 + "a = \"bar\"", 122 + "b = 2" 123 + }, 124 + .expected_output_json = { 125 + "\"metadata\":{\"a\":\"bar\",\"b\":2}" 126 + }, 127 + .metadata_map_name = METADATA_MAP_NAME 128 + } 129 + }; 130 + static const int tests_count = ARRAY_SIZE(tests); 131 + 132 + void test_bpftool_metadata(void) 133 + { 134 + int i; 135 + 136 + for (i = 0; i < tests_count; i++) { 137 + if (!test__start_subtest(tests[i].name)) 138 + continue; 139 + if (ASSERT_OK(setup(&tests[i]), "setup bpffs pin dir")) { 140 + run_test(&tests[i]); 141 + cleanup(&tests[i]); 142 + } 143 + } 144 + }
-398
tools/testing/selftests/bpf/test_bpftool_map.sh
··· 1 - #!/bin/sh 2 - # SPDX-License-Identifier: GPL-2.0 3 - 4 - # Kselftest framework requirement - SKIP code is 4. 5 - ksft_skip=4 6 - 7 - TESTNAME="bpftool_map" 8 - BPF_FILE="security_bpf_map.bpf.o" 9 - BPF_ITER_FILE="bpf_iter_map_elem.bpf.o" 10 - PROTECTED_MAP_NAME="prot_map" 11 - NOT_PROTECTED_MAP_NAME="not_prot_map" 12 - BPF_FS_TMP_PARENT="/tmp" 13 - BPF_FS_PARENT=$(awk '$3 == "bpf" {print $2; exit}' /proc/mounts) 14 - BPF_FS_PARENT=${BPF_FS_PARENT:-$BPF_FS_TMP_PARENT} 15 - # bpftool will mount bpf file system under BPF_DIR if it is not mounted 16 - # under BPF_FS_PARENT. 17 - BPF_DIR="$BPF_FS_PARENT/test_$TESTNAME" 18 - SCRIPT_DIR=$(dirname $(realpath "$0")) 19 - BPF_FILE_PATH="$SCRIPT_DIR/$BPF_FILE" 20 - BPF_ITER_FILE_PATH="$SCRIPT_DIR/$BPF_ITER_FILE" 21 - BPFTOOL_PATH="bpftool" 22 - # Assume the script is located under tools/testing/selftests/bpf/ 23 - KDIR_ROOT_DIR=$(realpath "$SCRIPT_DIR"/../../../../) 24 - 25 - _cleanup() 26 - { 27 - set +eu 28 - 29 - # If BPF_DIR is a mount point this will not remove the mount point itself. 30 - [ -d "$BPF_DIR" ] && rm -rf "$BPF_DIR" 2> /dev/null 31 - 32 - # Unmount if BPF filesystem was temporarily created. 33 - if [ "$BPF_FS_PARENT" = "$BPF_FS_TMP_PARENT" ]; then 34 - # A loop and recursive unmount are required as bpftool might 35 - # create multiple mounts. For example, a bind mount of the directory 36 - # to itself. The bind mount is created to change mount propagation 37 - # flags on an actual mount point. 38 - max_attempts=3 39 - attempt=0 40 - while mountpoint -q "$BPF_DIR" && [ $attempt -lt $max_attempts ]; do 41 - umount -R "$BPF_DIR" 2>/dev/null 42 - attempt=$((attempt+1)) 43 - done 44 - 45 - # The directory still exists. Remove it now. 46 - [ -d "$BPF_DIR" ] && rm -rf "$BPF_DIR" 2>/dev/null 47 - fi 48 - } 49 - 50 - cleanup_skip() 51 - { 52 - echo "selftests: $TESTNAME [SKIP]" 53 - _cleanup 54 - 55 - exit $ksft_skip 56 - } 57 - 58 - cleanup() 59 - { 60 - if [ "$?" = 0 ]; then 61 - echo "selftests: $TESTNAME [PASS]" 62 - else 63 - echo "selftests: $TESTNAME [FAILED]" 64 - fi 65 - _cleanup 66 - } 67 - 68 - check_root_privileges() { 69 - if [ $(id -u) -ne 0 ]; then 70 - echo "Need root privileges" 71 - exit $ksft_skip 72 - fi 73 - } 74 - 75 - # Function to verify bpftool path. 76 - # Parameters: 77 - # $1: bpftool path 78 - verify_bpftool_path() { 79 - local bpftool_path="$1" 80 - if ! "$bpftool_path" version > /dev/null 2>&1; then 81 - echo "Could not run test without bpftool" 82 - exit $ksft_skip 83 - fi 84 - } 85 - 86 - # Function to verify BTF support. 87 - # The test requires BTF support for fmod_ret programs. 88 - verify_btf_support() { 89 - if [ ! -f /sys/kernel/btf/vmlinux ]; then 90 - echo "Could not run test without BTF support" 91 - exit $ksft_skip 92 - fi 93 - } 94 - 95 - # Function to initialize map entries with keys [0..2] and values set to 0. 96 - # Parameters: 97 - # $1: Map name 98 - # $2: bpftool path 99 - initialize_map_entries() { 100 - local map_name="$1" 101 - local bpftool_path="$2" 102 - 103 - for key in 0 1 2; do 104 - "$bpftool_path" map update name "$map_name" key $key 0 0 0 value 0 0 0 $key 105 - done 106 - } 107 - 108 - # Test read access to the map. 109 - # Parameters: 110 - # $1: Name command (name/pinned) 111 - # $2: Map name 112 - # $3: bpftool path 113 - # $4: key 114 - access_for_read() { 115 - local name_cmd="$1" 116 - local map_name="$2" 117 - local bpftool_path="$3" 118 - local key="$4" 119 - 120 - # Test read access to the map. 121 - if ! "$bpftool_path" map lookup "$name_cmd" "$map_name" key $key 1>/dev/null; then 122 - echo " Read access to $key in $map_name failed" 123 - exit 1 124 - fi 125 - 126 - # Test read access to map's BTF data. 127 - if ! "$bpftool_path" btf dump map "$name_cmd" "$map_name" 1>/dev/null; then 128 - echo " Read access to $map_name for BTF data failed" 129 - exit 1 130 - fi 131 - } 132 - 133 - # Test write access to the map. 134 - # Parameters: 135 - # $1: Name command (name/pinned) 136 - # $2: Map name 137 - # $3: bpftool path 138 - # $4: key 139 - # $5: Whether write should succeed (true/false) 140 - access_for_write() { 141 - local name_cmd="$1" 142 - local map_name="$2" 143 - local bpftool_path="$3" 144 - local key="$4" 145 - local write_should_succeed="$5" 146 - local value="1 1 1 1" 147 - 148 - if "$bpftool_path" map update "$name_cmd" "$map_name" key $key value \ 149 - $value 2>/dev/null; then 150 - if [ "$write_should_succeed" = "false" ]; then 151 - echo " Write access to $key in $map_name succeeded but should have failed" 152 - exit 1 153 - fi 154 - else 155 - if [ "$write_should_succeed" = "true" ]; then 156 - echo " Write access to $key in $map_name failed but should have succeeded" 157 - exit 1 158 - fi 159 - fi 160 - } 161 - 162 - # Test entry deletion for the map. 163 - # Parameters: 164 - # $1: Name command (name/pinned) 165 - # $2: Map name 166 - # $3: bpftool path 167 - # $4: key 168 - # $5: Whether write should succeed (true/false) 169 - access_for_deletion() { 170 - local name_cmd="$1" 171 - local map_name="$2" 172 - local bpftool_path="$3" 173 - local key="$4" 174 - local write_should_succeed="$5" 175 - local value="1 1 1 1" 176 - 177 - # Test deletion by key for the map. 178 - # Before deleting, check the key exists. 179 - if ! "$bpftool_path" map lookup "$name_cmd" "$map_name" key $key 1>/dev/null; then 180 - echo " Key $key does not exist in $map_name" 181 - exit 1 182 - fi 183 - 184 - # Delete by key. 185 - if "$bpftool_path" map delete "$name_cmd" "$map_name" key $key 2>/dev/null; then 186 - if [ "$write_should_succeed" = "false" ]; then 187 - echo " Deletion for $key in $map_name succeeded but should have failed" 188 - exit 1 189 - fi 190 - else 191 - if [ "$write_should_succeed" = "true" ]; then 192 - echo " Deletion for $key in $map_name failed but should have succeeded" 193 - exit 1 194 - fi 195 - fi 196 - 197 - # After deleting, check the entry existence according to the expected status. 198 - if "$bpftool_path" map lookup "$name_cmd" "$map_name" key $key 1>/dev/null; then 199 - if [ "$write_should_succeed" = "true" ]; then 200 - echo " Key $key for $map_name was not deleted but should have been deleted" 201 - exit 1 202 - fi 203 - else 204 - if [ "$write_should_succeed" = "false" ]; then 205 - echo "Key $key for $map_name was deleted but should have not been deleted" 206 - exit 1 207 - fi 208 - fi 209 - 210 - # Test creation of map's deleted entry, if deletion was successful. 211 - # Otherwise, the entry exists. 212 - if "$bpftool_path" map update "$name_cmd" "$map_name" key $key value \ 213 - $value 2>/dev/null; then 214 - if [ "$write_should_succeed" = "false" ]; then 215 - echo " Write access to $key in $map_name succeeded after deletion attempt but should have failed" 216 - exit 1 217 - fi 218 - else 219 - if [ "$write_should_succeed" = "true" ]; then 220 - echo " Write access to $key in $map_name failed after deletion attempt but should have succeeded" 221 - exit 1 222 - fi 223 - fi 224 - } 225 - 226 - # Test map elements iterator. 227 - # Parameters: 228 - # $1: Name command (name/pinned) 229 - # $2: Map name 230 - # $3: bpftool path 231 - # $4: BPF_DIR 232 - # $5: bpf iterator object file path 233 - iterate_map_elem() { 234 - local name_cmd="$1" 235 - local map_name="$2" 236 - local bpftool_path="$3" 237 - local bpf_dir="$4" 238 - local bpf_file="$5" 239 - local pin_path="$bpf_dir/map_iterator" 240 - 241 - "$bpftool_path" iter pin "$bpf_file" "$pin_path" map "$name_cmd" "$map_name" 242 - if [ ! -f "$pin_path" ]; then 243 - echo " Failed to pin iterator to $pin_path" 244 - exit 1 245 - fi 246 - 247 - cat "$pin_path" 1>/dev/null 248 - rm "$pin_path" 2>/dev/null 249 - } 250 - 251 - # Function to test map access with configurable write expectations 252 - # Parameters: 253 - # $1: Name command (name/pinned) 254 - # $2: Map name 255 - # $3: bpftool path 256 - # $4: key for rw 257 - # $5: key to delete 258 - # $6: Whether write should succeed (true/false) 259 - # $7: BPF_DIR 260 - # $8: bpf iterator object file path 261 - access_map() { 262 - local name_cmd="$1" 263 - local map_name="$2" 264 - local bpftool_path="$3" 265 - local key_for_rw="$4" 266 - local key_to_del="$5" 267 - local write_should_succeed="$6" 268 - local bpf_dir="$7" 269 - local bpf_iter_file_path="$8" 270 - 271 - access_for_read "$name_cmd" "$map_name" "$bpftool_path" "$key_for_rw" 272 - access_for_write "$name_cmd" "$map_name" "$bpftool_path" "$key_for_rw" \ 273 - "$write_should_succeed" 274 - access_for_deletion "$name_cmd" "$map_name" "$bpftool_path" "$key_to_del" \ 275 - "$write_should_succeed" 276 - iterate_map_elem "$name_cmd" "$map_name" "$bpftool_path" "$bpf_dir" \ 277 - "$bpf_iter_file_path" 278 - } 279 - 280 - # Function to test map access with configurable write expectations 281 - # Parameters: 282 - # $1: Map name 283 - # $2: bpftool path 284 - # $3: BPF_DIR 285 - # $4: Whether write should succeed (true/false) 286 - # $5: bpf iterator object file path 287 - test_map_access() { 288 - local map_name="$1" 289 - local bpftool_path="$2" 290 - local bpf_dir="$3" 291 - local pin_path="$bpf_dir/${map_name}_pinned" 292 - local write_should_succeed="$4" 293 - local bpf_iter_file_path="$5" 294 - 295 - # Test access to the map by name. 296 - access_map "name" "$map_name" "$bpftool_path" "0 0 0 0" "1 0 0 0" \ 297 - "$write_should_succeed" "$bpf_dir" "$bpf_iter_file_path" 298 - 299 - # Pin the map to the BPF filesystem 300 - "$bpftool_path" map pin name "$map_name" "$pin_path" 301 - if [ ! -e "$pin_path" ]; then 302 - echo " Failed to pin $map_name" 303 - exit 1 304 - fi 305 - 306 - # Test access to the pinned map. 307 - access_map "pinned" "$pin_path" "$bpftool_path" "0 0 0 0" "2 0 0 0" \ 308 - "$write_should_succeed" "$bpf_dir" "$bpf_iter_file_path" 309 - } 310 - 311 - # Function to test map creation and map-of-maps 312 - # Parameters: 313 - # $1: bpftool path 314 - # $2: BPF_DIR 315 - test_map_creation_and_map_of_maps() { 316 - local bpftool_path="$1" 317 - local bpf_dir="$2" 318 - local outer_map_name="outer_map_tt" 319 - local inner_map_name="inner_map_tt" 320 - 321 - "$bpftool_path" map create "$bpf_dir/$inner_map_name" type array key 4 \ 322 - value 4 entries 4 name "$inner_map_name" 323 - if [ ! -f "$bpf_dir/$inner_map_name" ]; then 324 - echo " Failed to create inner map file at $bpf_dir/$outer_map_name" 325 - return 1 326 - fi 327 - 328 - "$bpftool_path" map create "$bpf_dir/$outer_map_name" type hash_of_maps \ 329 - key 4 value 4 entries 2 name "$outer_map_name" inner_map name "$inner_map_name" 330 - if [ ! -f "$bpf_dir/$outer_map_name" ]; then 331 - echo " Failed to create outer map file at $bpf_dir/$outer_map_name" 332 - return 1 333 - fi 334 - 335 - # Add entries to the outer map by name and by pinned path. 336 - "$bpftool_path" map update pinned "$bpf_dir/$outer_map_name" key 0 0 0 0 \ 337 - value pinned "$bpf_dir/$inner_map_name" 338 - "$bpftool_path" map update name "$outer_map_name" key 1 0 0 0 value \ 339 - name "$inner_map_name" 340 - 341 - # The outer map should be full by now. 342 - # The following map update command is expected to fail. 343 - if "$bpftool_path" map update name "$outer_map_name" key 2 0 0 0 value name \ 344 - "$inner_map_name" 2>/dev/null; then 345 - echo " Update for $outer_map_name succeeded but should have failed" 346 - exit 1 347 - fi 348 - } 349 - 350 - # Function to test map access with the btf list command 351 - # Parameters: 352 - # $1: bpftool path 353 - test_map_access_with_btf_list() { 354 - local bpftool_path="$1" 355 - 356 - # The btf list command iterates over maps for 357 - # loaded BPF programs. 358 - if ! "$bpftool_path" btf list 1>/dev/null; then 359 - echo " Failed to access btf data" 360 - exit 1 361 - fi 362 - } 363 - 364 - set -eu 365 - 366 - trap cleanup_skip EXIT 367 - 368 - check_root_privileges 369 - 370 - verify_bpftool_path "$BPFTOOL_PATH" 371 - 372 - verify_btf_support 373 - 374 - trap cleanup EXIT 375 - 376 - # Load and attach the BPF programs to control maps access. 377 - "$BPFTOOL_PATH" prog loadall "$BPF_FILE_PATH" "$BPF_DIR" autoattach 378 - 379 - initialize_map_entries "$PROTECTED_MAP_NAME" "$BPFTOOL_PATH" 380 - initialize_map_entries "$NOT_PROTECTED_MAP_NAME" "$BPFTOOL_PATH" 381 - 382 - # Activate the map protection mechanism. Protection status is controlled 383 - # by a value stored in the prot_status_map at index 0. 384 - "$BPFTOOL_PATH" map update name prot_status_map key 0 0 0 0 value 1 0 0 0 385 - 386 - # Test protected map (write should fail). 387 - test_map_access "$PROTECTED_MAP_NAME" "$BPFTOOL_PATH" "$BPF_DIR" "false" \ 388 - "$BPF_ITER_FILE_PATH" 389 - 390 - # Test not protected map (write should succeed). 391 - test_map_access "$NOT_PROTECTED_MAP_NAME" "$BPFTOOL_PATH" "$BPF_DIR" "true" \ 392 - "$BPF_ITER_FILE_PATH" 393 - 394 - test_map_creation_and_map_of_maps "$BPFTOOL_PATH" "$BPF_DIR" 395 - 396 - test_map_access_with_btf_list "$BPFTOOL_PATH" 397 - 398 - exit 0
-85
tools/testing/selftests/bpf/test_bpftool_metadata.sh
··· 1 - #!/bin/sh 2 - # SPDX-License-Identifier: GPL-2.0 3 - 4 - # Kselftest framework requirement - SKIP code is 4. 5 - ksft_skip=4 6 - 7 - BPF_FILE_USED="metadata_used.bpf.o" 8 - BPF_FILE_UNUSED="metadata_unused.bpf.o" 9 - 10 - TESTNAME=bpftool_metadata 11 - BPF_FS=$(awk '$3 == "bpf" {print $2; exit}' /proc/mounts) 12 - BPF_DIR=$BPF_FS/test_$TESTNAME 13 - 14 - _cleanup() 15 - { 16 - set +e 17 - rm -rf $BPF_DIR 2> /dev/null 18 - } 19 - 20 - cleanup_skip() 21 - { 22 - echo "selftests: $TESTNAME [SKIP]" 23 - _cleanup 24 - 25 - exit $ksft_skip 26 - } 27 - 28 - cleanup() 29 - { 30 - if [ "$?" = 0 ]; then 31 - echo "selftests: $TESTNAME [PASS]" 32 - else 33 - echo "selftests: $TESTNAME [FAILED]" 34 - fi 35 - _cleanup 36 - } 37 - 38 - if [ $(id -u) -ne 0 ]; then 39 - echo "selftests: $TESTNAME [SKIP] Need root privileges" 40 - exit $ksft_skip 41 - fi 42 - 43 - if [ -z "$BPF_FS" ]; then 44 - echo "selftests: $TESTNAME [SKIP] Could not run test without bpffs mounted" 45 - exit $ksft_skip 46 - fi 47 - 48 - if ! bpftool version > /dev/null 2>&1; then 49 - echo "selftests: $TESTNAME [SKIP] Could not run test without bpftool" 50 - exit $ksft_skip 51 - fi 52 - 53 - set -e 54 - 55 - trap cleanup_skip EXIT 56 - 57 - mkdir $BPF_DIR 58 - 59 - trap cleanup EXIT 60 - 61 - bpftool prog load $BPF_FILE_UNUSED $BPF_DIR/unused 62 - 63 - METADATA_PLAIN="$(bpftool prog)" 64 - echo "$METADATA_PLAIN" | grep 'a = "foo"' > /dev/null 65 - echo "$METADATA_PLAIN" | grep 'b = 1' > /dev/null 66 - 67 - bpftool prog --json | grep '"metadata":{"a":"foo","b":1}' > /dev/null 68 - 69 - bpftool map | grep 'metadata.rodata' > /dev/null 70 - 71 - rm $BPF_DIR/unused 72 - 73 - bpftool prog load $BPF_FILE_USED $BPF_DIR/used 74 - 75 - METADATA_PLAIN="$(bpftool prog)" 76 - echo "$METADATA_PLAIN" | grep 'a = "bar"' > /dev/null 77 - echo "$METADATA_PLAIN" | grep 'b = 2' > /dev/null 78 - 79 - bpftool prog --json | grep '"metadata":{"a":"bar","b":2}' > /dev/null 80 - 81 - bpftool map | grep 'metadata.rodata' > /dev/null 82 - 83 - rm $BPF_DIR/used 84 - 85 - exit 0