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