• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2017 Facebook
3  */
4 #include "test_progs.h"
5 #include "cgroup_helpers.h"
6 #include "bpf_rlimit.h"
7 #include <argp.h>
8 #include <string.h>
9 
10 #define EXIT_NO_TEST		2
11 
12 /* defined in test_progs.h */
13 struct test_env env;
14 
15 struct prog_test_def {
16 	const char *test_name;
17 	int test_num;
18 	void (*run_test)(void);
19 	bool force_log;
20 	int error_cnt;
21 	int skip_cnt;
22 	bool tested;
23 	bool need_cgroup_cleanup;
24 
25 	char *subtest_name;
26 	int subtest_num;
27 
28 	/* store counts before subtest started */
29 	int old_error_cnt;
30 };
31 
should_run(struct test_selector * sel,int num,const char * name)32 static bool should_run(struct test_selector *sel, int num, const char *name)
33 {
34 	if (sel->name && sel->name[0] && !strstr(name, sel->name))
35 		return false;
36 
37 	if (!sel->num_set)
38 		return true;
39 
40 	return num < sel->num_set_len && sel->num_set[num];
41 }
42 
dump_test_log(const struct prog_test_def * test,bool failed)43 static void dump_test_log(const struct prog_test_def *test, bool failed)
44 {
45 	if (stdout == env.stdout)
46 		return;
47 
48 	fflush(stdout); /* exports env.log_buf & env.log_cnt */
49 
50 	if (env.verbose || test->force_log || failed) {
51 		if (env.log_cnt) {
52 			env.log_buf[env.log_cnt] = '\0';
53 			fprintf(env.stdout, "%s", env.log_buf);
54 			if (env.log_buf[env.log_cnt - 1] != '\n')
55 				fprintf(env.stdout, "\n");
56 		}
57 	}
58 
59 	fseeko(stdout, 0, SEEK_SET); /* rewind */
60 }
61 
skip_account(void)62 static void skip_account(void)
63 {
64 	if (env.test->skip_cnt) {
65 		env.skip_cnt++;
66 		env.test->skip_cnt = 0;
67 	}
68 }
69 
test__end_subtest()70 void test__end_subtest()
71 {
72 	struct prog_test_def *test = env.test;
73 	int sub_error_cnt = test->error_cnt - test->old_error_cnt;
74 
75 	if (sub_error_cnt)
76 		env.fail_cnt++;
77 	else
78 		env.sub_succ_cnt++;
79 	skip_account();
80 
81 	dump_test_log(test, sub_error_cnt);
82 
83 	fprintf(env.stdout, "#%d/%d %s:%s\n",
84 	       test->test_num, test->subtest_num,
85 	       test->subtest_name, sub_error_cnt ? "FAIL" : "OK");
86 
87 	free(test->subtest_name);
88 	test->subtest_name = NULL;
89 }
90 
test__start_subtest(const char * name)91 bool test__start_subtest(const char *name)
92 {
93 	struct prog_test_def *test = env.test;
94 
95 	if (test->subtest_name)
96 		test__end_subtest();
97 
98 	test->subtest_num++;
99 
100 	if (!name || !name[0]) {
101 		fprintf(env.stderr,
102 			"Subtest #%d didn't provide sub-test name!\n",
103 			test->subtest_num);
104 		return false;
105 	}
106 
107 	if (!should_run(&env.subtest_selector, test->subtest_num, name))
108 		return false;
109 
110 	test->subtest_name = strdup(name);
111 	if (!test->subtest_name) {
112 		fprintf(env.stderr,
113 			"Subtest #%d: failed to copy subtest name!\n",
114 			test->subtest_num);
115 		return false;
116 	}
117 	env.test->old_error_cnt = env.test->error_cnt;
118 
119 	return true;
120 }
121 
test__force_log()122 void test__force_log() {
123 	env.test->force_log = true;
124 }
125 
test__skip(void)126 void test__skip(void)
127 {
128 	env.test->skip_cnt++;
129 }
130 
test__fail(void)131 void test__fail(void)
132 {
133 	env.test->error_cnt++;
134 }
135 
test__join_cgroup(const char * path)136 int test__join_cgroup(const char *path)
137 {
138 	int fd;
139 
140 	if (!env.test->need_cgroup_cleanup) {
141 		if (setup_cgroup_environment()) {
142 			fprintf(stderr,
143 				"#%d %s: Failed to setup cgroup environment\n",
144 				env.test->test_num, env.test->test_name);
145 			return -1;
146 		}
147 
148 		env.test->need_cgroup_cleanup = true;
149 	}
150 
151 	fd = create_and_get_cgroup(path);
152 	if (fd < 0) {
153 		fprintf(stderr,
154 			"#%d %s: Failed to create cgroup '%s' (errno=%d)\n",
155 			env.test->test_num, env.test->test_name, path, errno);
156 		return fd;
157 	}
158 
159 	if (join_cgroup(path)) {
160 		fprintf(stderr,
161 			"#%d %s: Failed to join cgroup '%s' (errno=%d)\n",
162 			env.test->test_num, env.test->test_name, path, errno);
163 		return -1;
164 	}
165 
166 	return fd;
167 }
168 
169 struct ipv4_packet pkt_v4 = {
170 	.eth.h_proto = __bpf_constant_htons(ETH_P_IP),
171 	.iph.ihl = 5,
172 	.iph.protocol = IPPROTO_TCP,
173 	.iph.tot_len = __bpf_constant_htons(MAGIC_BYTES),
174 	.tcp.urg_ptr = 123,
175 	.tcp.doff = 5,
176 };
177 
178 struct ipv6_packet pkt_v6 = {
179 	.eth.h_proto = __bpf_constant_htons(ETH_P_IPV6),
180 	.iph.nexthdr = IPPROTO_TCP,
181 	.iph.payload_len = __bpf_constant_htons(MAGIC_BYTES),
182 	.tcp.urg_ptr = 123,
183 	.tcp.doff = 5,
184 };
185 
bpf_find_map(const char * test,struct bpf_object * obj,const char * name)186 int bpf_find_map(const char *test, struct bpf_object *obj, const char *name)
187 {
188 	struct bpf_map *map;
189 
190 	map = bpf_object__find_map_by_name(obj, name);
191 	if (!map) {
192 		printf("%s:FAIL:map '%s' not found\n", test, name);
193 		test__fail();
194 		return -1;
195 	}
196 	return bpf_map__fd(map);
197 }
198 
is_jit_enabled(void)199 static bool is_jit_enabled(void)
200 {
201 	const char *jit_sysctl = "/proc/sys/net/core/bpf_jit_enable";
202 	bool enabled = false;
203 	int sysctl_fd;
204 
205 	sysctl_fd = open(jit_sysctl, 0, O_RDONLY);
206 	if (sysctl_fd != -1) {
207 		char tmpc;
208 
209 		if (read(sysctl_fd, &tmpc, sizeof(tmpc)) == 1)
210 			enabled = (tmpc != '0');
211 		close(sysctl_fd);
212 	}
213 
214 	return enabled;
215 }
216 
compare_map_keys(int map1_fd,int map2_fd)217 int compare_map_keys(int map1_fd, int map2_fd)
218 {
219 	__u32 key, next_key;
220 	char val_buf[PERF_MAX_STACK_DEPTH *
221 		     sizeof(struct bpf_stack_build_id)];
222 	int err;
223 
224 	err = bpf_map_get_next_key(map1_fd, NULL, &key);
225 	if (err)
226 		return err;
227 	err = bpf_map_lookup_elem(map2_fd, &key, val_buf);
228 	if (err)
229 		return err;
230 
231 	while (bpf_map_get_next_key(map1_fd, &key, &next_key) == 0) {
232 		err = bpf_map_lookup_elem(map2_fd, &next_key, val_buf);
233 		if (err)
234 			return err;
235 
236 		key = next_key;
237 	}
238 	if (errno != ENOENT)
239 		return -1;
240 
241 	return 0;
242 }
243 
compare_stack_ips(int smap_fd,int amap_fd,int stack_trace_len)244 int compare_stack_ips(int smap_fd, int amap_fd, int stack_trace_len)
245 {
246 	__u32 key, next_key, *cur_key_p, *next_key_p;
247 	char *val_buf1, *val_buf2;
248 	int i, err = 0;
249 
250 	val_buf1 = malloc(stack_trace_len);
251 	val_buf2 = malloc(stack_trace_len);
252 	cur_key_p = NULL;
253 	next_key_p = &key;
254 	while (bpf_map_get_next_key(smap_fd, cur_key_p, next_key_p) == 0) {
255 		err = bpf_map_lookup_elem(smap_fd, next_key_p, val_buf1);
256 		if (err)
257 			goto out;
258 		err = bpf_map_lookup_elem(amap_fd, next_key_p, val_buf2);
259 		if (err)
260 			goto out;
261 		for (i = 0; i < stack_trace_len; i++) {
262 			if (val_buf1[i] != val_buf2[i]) {
263 				err = -1;
264 				goto out;
265 			}
266 		}
267 		key = *next_key_p;
268 		cur_key_p = &key;
269 		next_key_p = &next_key;
270 	}
271 	if (errno != ENOENT)
272 		err = -1;
273 
274 out:
275 	free(val_buf1);
276 	free(val_buf2);
277 	return err;
278 }
279 
extract_build_id(char * build_id,size_t size)280 int extract_build_id(char *build_id, size_t size)
281 {
282 	FILE *fp;
283 	char *line = NULL;
284 	size_t len = 0;
285 
286 	fp = popen("readelf -n ./urandom_read | grep 'Build ID'", "r");
287 	if (fp == NULL)
288 		return -1;
289 
290 	if (getline(&line, &len, fp) == -1)
291 		goto err;
292 	pclose(fp);
293 
294 	if (len > size)
295 		len = size;
296 	memcpy(build_id, line, len);
297 	build_id[len] = '\0';
298 	free(line);
299 	return 0;
300 err:
301 	pclose(fp);
302 	return -1;
303 }
304 
spin_lock_thread(void * arg)305 void *spin_lock_thread(void *arg)
306 {
307 	__u32 duration, retval;
308 	int err, prog_fd = *(u32 *) arg;
309 
310 	err = bpf_prog_test_run(prog_fd, 10000, &pkt_v4, sizeof(pkt_v4),
311 				NULL, NULL, &retval, &duration);
312 	CHECK(err || retval, "",
313 	      "err %d errno %d retval %d duration %d\n",
314 	      err, errno, retval, duration);
315 	pthread_exit(arg);
316 }
317 
318 /* extern declarations for test funcs */
319 #define DEFINE_TEST(name) extern void test_##name();
320 #include <prog_tests/tests.h>
321 #undef DEFINE_TEST
322 
323 static struct prog_test_def prog_test_defs[] = {
324 #define DEFINE_TEST(name) {		\
325 	.test_name = #name,		\
326 	.run_test = &test_##name,	\
327 },
328 #include <prog_tests/tests.h>
329 #undef DEFINE_TEST
330 };
331 const int prog_test_cnt = ARRAY_SIZE(prog_test_defs);
332 
333 const char *argp_program_version = "test_progs 0.1";
334 const char *argp_program_bug_address = "<bpf@vger.kernel.org>";
335 const char argp_program_doc[] = "BPF selftests test runner";
336 
337 enum ARG_KEYS {
338 	ARG_TEST_NUM = 'n',
339 	ARG_TEST_NAME = 't',
340 	ARG_VERIFIER_STATS = 's',
341 	ARG_VERBOSE = 'v',
342 };
343 
344 static const struct argp_option opts[] = {
345 	{ "num", ARG_TEST_NUM, "NUM", 0,
346 	  "Run test number NUM only " },
347 	{ "name", ARG_TEST_NAME, "NAME", 0,
348 	  "Run tests with names containing NAME" },
349 	{ "verifier-stats", ARG_VERIFIER_STATS, NULL, 0,
350 	  "Output verifier statistics", },
351 	{ "verbose", ARG_VERBOSE, "LEVEL", OPTION_ARG_OPTIONAL,
352 	  "Verbose output (use -vv for extra verbose output)" },
353 	{},
354 };
355 
libbpf_print_fn(enum libbpf_print_level level,const char * format,va_list args)356 static int libbpf_print_fn(enum libbpf_print_level level,
357 			   const char *format, va_list args)
358 {
359 	if (!env.very_verbose && level == LIBBPF_DEBUG)
360 		return 0;
361 	vprintf(format, args);
362 	return 0;
363 }
364 
parse_num_list(const char * s,struct test_selector * sel)365 int parse_num_list(const char *s, struct test_selector *sel)
366 {
367 	int i, set_len = 0, num, start = 0, end = -1;
368 	bool *set = NULL, *tmp, parsing_end = false;
369 	char *next;
370 
371 	while (s[0]) {
372 		errno = 0;
373 		num = strtol(s, &next, 10);
374 		if (errno)
375 			return -errno;
376 
377 		if (parsing_end)
378 			end = num;
379 		else
380 			start = num;
381 
382 		if (!parsing_end && *next == '-') {
383 			s = next + 1;
384 			parsing_end = true;
385 			continue;
386 		} else if (*next == ',') {
387 			parsing_end = false;
388 			s = next + 1;
389 			end = num;
390 		} else if (*next == '\0') {
391 			parsing_end = false;
392 			s = next;
393 			end = num;
394 		} else {
395 			return -EINVAL;
396 		}
397 
398 		if (start > end)
399 			return -EINVAL;
400 
401 		if (end + 1 > set_len) {
402 			set_len = end + 1;
403 			tmp = realloc(set, set_len);
404 			if (!tmp) {
405 				free(set);
406 				return -ENOMEM;
407 			}
408 			set = tmp;
409 		}
410 		for (i = start; i <= end; i++) {
411 			set[i] = true;
412 		}
413 
414 	}
415 
416 	if (!set)
417 		return -EINVAL;
418 
419 	sel->num_set = set;
420 	sel->num_set_len = set_len;
421 
422 	return 0;
423 }
424 
parse_arg(int key,char * arg,struct argp_state * state)425 static error_t parse_arg(int key, char *arg, struct argp_state *state)
426 {
427 	struct test_env *env = state->input;
428 
429 	switch (key) {
430 	case ARG_TEST_NUM: {
431 		char *subtest_str = strchr(arg, '/');
432 
433 		if (subtest_str) {
434 			*subtest_str = '\0';
435 			if (parse_num_list(subtest_str + 1,
436 					   &env->subtest_selector)) {
437 				fprintf(stderr,
438 					"Failed to parse subtest numbers.\n");
439 				return -EINVAL;
440 			}
441 		}
442 		if (parse_num_list(arg, &env->test_selector)) {
443 			fprintf(stderr, "Failed to parse test numbers.\n");
444 			return -EINVAL;
445 		}
446 		break;
447 	}
448 	case ARG_TEST_NAME: {
449 		char *subtest_str = strchr(arg, '/');
450 
451 		if (subtest_str) {
452 			*subtest_str = '\0';
453 			env->subtest_selector.name = strdup(subtest_str + 1);
454 			if (!env->subtest_selector.name)
455 				return -ENOMEM;
456 		}
457 		env->test_selector.name = strdup(arg);
458 		if (!env->test_selector.name)
459 			return -ENOMEM;
460 		break;
461 	}
462 	case ARG_VERIFIER_STATS:
463 		env->verifier_stats = true;
464 		break;
465 	case ARG_VERBOSE:
466 		if (arg) {
467 			if (strcmp(arg, "v") == 0) {
468 				env->very_verbose = true;
469 			} else {
470 				fprintf(stderr,
471 					"Unrecognized verbosity setting ('%s'), only -v and -vv are supported\n",
472 					arg);
473 				return -EINVAL;
474 			}
475 		}
476 		env->verbose = true;
477 		break;
478 	case ARGP_KEY_ARG:
479 		argp_usage(state);
480 		break;
481 	case ARGP_KEY_END:
482 		break;
483 	default:
484 		return ARGP_ERR_UNKNOWN;
485 	}
486 	return 0;
487 }
488 
stdio_hijack(void)489 static void stdio_hijack(void)
490 {
491 #ifdef __GLIBC__
492 	env.stdout = stdout;
493 	env.stderr = stderr;
494 
495 	if (env.verbose) {
496 		/* nothing to do, output to stdout by default */
497 		return;
498 	}
499 
500 	/* stdout and stderr -> buffer */
501 	fflush(stdout);
502 
503 	stdout = open_memstream(&env.log_buf, &env.log_cnt);
504 	if (!stdout) {
505 		stdout = env.stdout;
506 		perror("open_memstream");
507 		return;
508 	}
509 
510 	stderr = stdout;
511 #endif
512 }
513 
stdio_restore(void)514 static void stdio_restore(void)
515 {
516 #ifdef __GLIBC__
517 	if (stdout == env.stdout)
518 		return;
519 
520 	fclose(stdout);
521 	free(env.log_buf);
522 
523 	env.log_buf = NULL;
524 	env.log_cnt = 0;
525 
526 	stdout = env.stdout;
527 	stderr = env.stderr;
528 #endif
529 }
530 
main(int argc,char ** argv)531 int main(int argc, char **argv)
532 {
533 	static const struct argp argp = {
534 		.options = opts,
535 		.parser = parse_arg,
536 		.doc = argp_program_doc,
537 	};
538 	int err, i;
539 
540 	err = argp_parse(&argp, argc, argv, 0, NULL, &env);
541 	if (err)
542 		return err;
543 
544 	libbpf_set_print(libbpf_print_fn);
545 
546 	srand(time(NULL));
547 
548 	env.jit_enabled = is_jit_enabled();
549 
550 	stdio_hijack();
551 	for (i = 0; i < prog_test_cnt; i++) {
552 		struct prog_test_def *test = &prog_test_defs[i];
553 
554 		env.test = test;
555 		test->test_num = i + 1;
556 
557 		if (!should_run(&env.test_selector,
558 				test->test_num, test->test_name))
559 			continue;
560 
561 		test->run_test();
562 		/* ensure last sub-test is finalized properly */
563 		if (test->subtest_name)
564 			test__end_subtest();
565 
566 		test->tested = true;
567 		if (test->error_cnt)
568 			env.fail_cnt++;
569 		else
570 			env.succ_cnt++;
571 		skip_account();
572 
573 		dump_test_log(test, test->error_cnt);
574 
575 		fprintf(env.stdout, "#%d %s:%s\n",
576 			test->test_num, test->test_name,
577 			test->error_cnt ? "FAIL" : "OK");
578 
579 		if (test->need_cgroup_cleanup)
580 			cleanup_cgroup_environment();
581 	}
582 	stdio_restore();
583 	printf("Summary: %d/%d PASSED, %d SKIPPED, %d FAILED\n",
584 	       env.succ_cnt, env.sub_succ_cnt, env.skip_cnt, env.fail_cnt);
585 
586 	free(env.test_selector.num_set);
587 	free(env.subtest_selector.num_set);
588 
589 	if (env.succ_cnt + env.fail_cnt + env.skip_cnt == 0)
590 		return EXIT_NO_TEST;
591 
592 	return env.fail_cnt ? EXIT_FAILURE : EXIT_SUCCESS;
593 }
594