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 } 145