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