xref: /linux/tools/testing/selftests/bpf/prog_tests/bpftool_metadata.c (revision 6f7e6393d1ce636bb7ec77a7fe7b77458fddf701)
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