xref: /linux/tools/testing/selftests/bpf/test_loader.c (revision c9d23f9657cabfd2836a096bf6eddf8df2cf1434)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
3 #include <stdlib.h>
4 #include <test_progs.h>
5 #include <bpf/btf.h>
6 
7 #define str_has_pfx(str, pfx) \
8 	(strncmp(str, pfx, __builtin_constant_p(pfx) ? sizeof(pfx) - 1 : strlen(pfx)) == 0)
9 
10 #define TEST_LOADER_LOG_BUF_SZ 1048576
11 
12 #define TEST_TAG_EXPECT_FAILURE "comment:test_expect_failure"
13 #define TEST_TAG_EXPECT_SUCCESS "comment:test_expect_success"
14 #define TEST_TAG_EXPECT_MSG_PFX "comment:test_expect_msg="
15 #define TEST_TAG_LOG_LEVEL_PFX "comment:test_log_level="
16 #define TEST_TAG_PROG_FLAGS_PFX "comment:test_prog_flags="
17 
18 struct test_spec {
19 	const char *name;
20 	bool expect_failure;
21 	const char **expect_msgs;
22 	size_t expect_msg_cnt;
23 	int log_level;
24 	int prog_flags;
25 };
26 
27 static int tester_init(struct test_loader *tester)
28 {
29 	if (!tester->log_buf) {
30 		tester->log_buf_sz = TEST_LOADER_LOG_BUF_SZ;
31 		tester->log_buf = malloc(tester->log_buf_sz);
32 		if (!ASSERT_OK_PTR(tester->log_buf, "tester_log_buf"))
33 			return -ENOMEM;
34 	}
35 
36 	return 0;
37 }
38 
39 void test_loader_fini(struct test_loader *tester)
40 {
41 	if (!tester)
42 		return;
43 
44 	free(tester->log_buf);
45 }
46 
47 static int parse_test_spec(struct test_loader *tester,
48 			   struct bpf_object *obj,
49 			   struct bpf_program *prog,
50 			   struct test_spec *spec)
51 {
52 	struct btf *btf;
53 	int func_id, i;
54 
55 	memset(spec, 0, sizeof(*spec));
56 
57 	spec->name = bpf_program__name(prog);
58 
59 	btf = bpf_object__btf(obj);
60 	if (!btf) {
61 		ASSERT_FAIL("BPF object has no BTF");
62 		return -EINVAL;
63 	}
64 
65 	func_id = btf__find_by_name_kind(btf, spec->name, BTF_KIND_FUNC);
66 	if (func_id < 0) {
67 		ASSERT_FAIL("failed to find FUNC BTF type for '%s'", spec->name);
68 		return -EINVAL;
69 	}
70 
71 	for (i = 1; i < btf__type_cnt(btf); i++) {
72 		const struct btf_type *t;
73 		const char *s, *val;
74 		char *e;
75 
76 		t = btf__type_by_id(btf, i);
77 		if (!btf_is_decl_tag(t))
78 			continue;
79 
80 		if (t->type != func_id || btf_decl_tag(t)->component_idx != -1)
81 			continue;
82 
83 		s = btf__str_by_offset(btf, t->name_off);
84 		if (strcmp(s, TEST_TAG_EXPECT_FAILURE) == 0) {
85 			spec->expect_failure = true;
86 		} else if (strcmp(s, TEST_TAG_EXPECT_SUCCESS) == 0) {
87 			spec->expect_failure = false;
88 		} else if (str_has_pfx(s, TEST_TAG_EXPECT_MSG_PFX)) {
89 			void *tmp;
90 			const char **msg;
91 
92 			tmp = realloc(spec->expect_msgs,
93 				      (1 + spec->expect_msg_cnt) * sizeof(void *));
94 			if (!tmp) {
95 				ASSERT_FAIL("failed to realloc memory for messages\n");
96 				return -ENOMEM;
97 			}
98 			spec->expect_msgs = tmp;
99 			msg = &spec->expect_msgs[spec->expect_msg_cnt++];
100 			*msg = s + sizeof(TEST_TAG_EXPECT_MSG_PFX) - 1;
101 		} else if (str_has_pfx(s, TEST_TAG_LOG_LEVEL_PFX)) {
102 			val = s + sizeof(TEST_TAG_LOG_LEVEL_PFX) - 1;
103 			errno = 0;
104 			spec->log_level = strtol(val, &e, 0);
105 			if (errno || e[0] != '\0') {
106 				ASSERT_FAIL("failed to parse test log level from '%s'", s);
107 				return -EINVAL;
108 			}
109 		} else if (str_has_pfx(s, TEST_TAG_PROG_FLAGS_PFX)) {
110 			val = s + sizeof(TEST_TAG_PROG_FLAGS_PFX) - 1;
111 			if (strcmp(val, "BPF_F_STRICT_ALIGNMENT") == 0) {
112 				spec->prog_flags |= BPF_F_STRICT_ALIGNMENT;
113 			} else if (strcmp(val, "BPF_F_ANY_ALIGNMENT") == 0) {
114 				spec->prog_flags |= BPF_F_ANY_ALIGNMENT;
115 			} else if (strcmp(val, "BPF_F_TEST_RND_HI32") == 0) {
116 				spec->prog_flags |= BPF_F_TEST_RND_HI32;
117 			} else if (strcmp(val, "BPF_F_TEST_STATE_FREQ") == 0) {
118 				spec->prog_flags |= BPF_F_TEST_STATE_FREQ;
119 			} else if (strcmp(val, "BPF_F_SLEEPABLE") == 0) {
120 				spec->prog_flags |= BPF_F_SLEEPABLE;
121 			} else if (strcmp(val, "BPF_F_XDP_HAS_FRAGS") == 0) {
122 				spec->prog_flags |= BPF_F_XDP_HAS_FRAGS;
123 			} else /* assume numeric value */ {
124 				errno = 0;
125 				spec->prog_flags |= strtol(val, &e, 0);
126 				if (errno || e[0] != '\0') {
127 					ASSERT_FAIL("failed to parse test prog flags from '%s'", s);
128 					return -EINVAL;
129 				}
130 			}
131 		}
132 	}
133 
134 	return 0;
135 }
136 
137 static void prepare_case(struct test_loader *tester,
138 			 struct test_spec *spec,
139 			 struct bpf_object *obj,
140 			 struct bpf_program *prog)
141 {
142 	int min_log_level = 0, prog_flags;
143 
144 	if (env.verbosity > VERBOSE_NONE)
145 		min_log_level = 1;
146 	if (env.verbosity > VERBOSE_VERY)
147 		min_log_level = 2;
148 
149 	bpf_program__set_log_buf(prog, tester->log_buf, tester->log_buf_sz);
150 
151 	/* Make sure we set at least minimal log level, unless test requirest
152 	 * even higher level already. Make sure to preserve independent log
153 	 * level 4 (verifier stats), though.
154 	 */
155 	if ((spec->log_level & 3) < min_log_level)
156 		bpf_program__set_log_level(prog, (spec->log_level & 4) | min_log_level);
157 	else
158 		bpf_program__set_log_level(prog, spec->log_level);
159 
160 	prog_flags = bpf_program__flags(prog);
161 	bpf_program__set_flags(prog, prog_flags | spec->prog_flags);
162 
163 	tester->log_buf[0] = '\0';
164 	tester->next_match_pos = 0;
165 }
166 
167 static void emit_verifier_log(const char *log_buf, bool force)
168 {
169 	if (!force && env.verbosity == VERBOSE_NONE)
170 		return;
171 	fprintf(stdout, "VERIFIER LOG:\n=============\n%s=============\n", log_buf);
172 }
173 
174 static void validate_case(struct test_loader *tester,
175 			  struct test_spec *spec,
176 			  struct bpf_object *obj,
177 			  struct bpf_program *prog,
178 			  int load_err)
179 {
180 	int i, j;
181 
182 	for (i = 0; i < spec->expect_msg_cnt; i++) {
183 		char *match;
184 		const char *expect_msg;
185 
186 		expect_msg = spec->expect_msgs[i];
187 
188 		match = strstr(tester->log_buf + tester->next_match_pos, expect_msg);
189 		if (!ASSERT_OK_PTR(match, "expect_msg")) {
190 			/* if we are in verbose mode, we've already emitted log */
191 			if (env.verbosity == VERBOSE_NONE)
192 				emit_verifier_log(tester->log_buf, true /*force*/);
193 			for (j = 0; j < i; j++)
194 				fprintf(stderr, "MATCHED  MSG: '%s'\n", spec->expect_msgs[j]);
195 			fprintf(stderr, "EXPECTED MSG: '%s'\n", expect_msg);
196 			return;
197 		}
198 
199 		tester->next_match_pos = match - tester->log_buf + strlen(expect_msg);
200 	}
201 }
202 
203 /* this function is forced noinline and has short generic name to look better
204  * in test_progs output (in case of a failure)
205  */
206 static noinline
207 void run_subtest(struct test_loader *tester,
208 		 const char *skel_name,
209 		 skel_elf_bytes_fn elf_bytes_factory)
210 {
211 	LIBBPF_OPTS(bpf_object_open_opts, open_opts, .object_name = skel_name);
212 	struct bpf_object *obj = NULL, *tobj;
213 	struct bpf_program *prog, *tprog;
214 	const void *obj_bytes;
215 	size_t obj_byte_cnt;
216 	int err;
217 
218 	if (tester_init(tester) < 0)
219 		return; /* failed to initialize tester */
220 
221 	obj_bytes = elf_bytes_factory(&obj_byte_cnt);
222 	obj = bpf_object__open_mem(obj_bytes, obj_byte_cnt, &open_opts);
223 	if (!ASSERT_OK_PTR(obj, "obj_open_mem"))
224 		return;
225 
226 	bpf_object__for_each_program(prog, obj) {
227 		const char *prog_name = bpf_program__name(prog);
228 		struct test_spec spec;
229 
230 		if (!test__start_subtest(prog_name))
231 			continue;
232 
233 		/* if we can't derive test specification, go to the next test */
234 		err = parse_test_spec(tester, obj, prog, &spec);
235 		if (!ASSERT_OK(err, "parse_test_spec"))
236 			continue;
237 
238 		tobj = bpf_object__open_mem(obj_bytes, obj_byte_cnt, &open_opts);
239 		if (!ASSERT_OK_PTR(tobj, "obj_open_mem")) /* shouldn't happen */
240 			continue;
241 
242 		bpf_object__for_each_program(tprog, tobj)
243 			bpf_program__set_autoload(tprog, false);
244 
245 		bpf_object__for_each_program(tprog, tobj) {
246 			/* only load specified program */
247 			if (strcmp(bpf_program__name(tprog), prog_name) == 0) {
248 				bpf_program__set_autoload(tprog, true);
249 				break;
250 			}
251 		}
252 
253 		prepare_case(tester, &spec, tobj, tprog);
254 
255 		err = bpf_object__load(tobj);
256 		if (spec.expect_failure) {
257 			if (!ASSERT_ERR(err, "unexpected_load_success")) {
258 				emit_verifier_log(tester->log_buf, false /*force*/);
259 				goto tobj_cleanup;
260 			}
261 		} else {
262 			if (!ASSERT_OK(err, "unexpected_load_failure")) {
263 				emit_verifier_log(tester->log_buf, true /*force*/);
264 				goto tobj_cleanup;
265 			}
266 		}
267 
268 		emit_verifier_log(tester->log_buf, false /*force*/);
269 		validate_case(tester, &spec, tobj, tprog, err);
270 
271 tobj_cleanup:
272 		bpf_object__close(tobj);
273 	}
274 
275 	bpf_object__close(obj);
276 }
277 
278 void test_loader__run_subtests(struct test_loader *tester,
279 			       const char *skel_name,
280 			       skel_elf_bytes_fn elf_bytes_factory)
281 {
282 	/* see comment in run_subtest() for why we do this function nesting */
283 	run_subtest(tester, skel_name, elf_bytes_factory);
284 }
285