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.verbose || 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 for extra 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.very_verbose && 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 static error_t parse_arg(int key, char *arg, struct argp_state *state) 423 { 424 struct test_env *env = state->input; 425 426 switch (key) { 427 case ARG_TEST_NUM: { 428 char *subtest_str = strchr(arg, '/'); 429 430 if (subtest_str) { 431 *subtest_str = '\0'; 432 if (parse_num_list(subtest_str + 1, 433 &env->subtest_selector)) { 434 fprintf(stderr, 435 "Failed to parse subtest numbers.\n"); 436 return -EINVAL; 437 } 438 } 439 if (parse_num_list(arg, &env->test_selector)) { 440 fprintf(stderr, "Failed to parse test numbers.\n"); 441 return -EINVAL; 442 } 443 break; 444 } 445 case ARG_TEST_NAME: { 446 char *subtest_str = strchr(arg, '/'); 447 448 if (subtest_str) { 449 *subtest_str = '\0'; 450 env->subtest_selector.name = strdup(subtest_str + 1); 451 if (!env->subtest_selector.name) 452 return -ENOMEM; 453 } 454 env->test_selector.name = strdup(arg); 455 if (!env->test_selector.name) 456 return -ENOMEM; 457 break; 458 } 459 case ARG_VERIFIER_STATS: 460 env->verifier_stats = true; 461 break; 462 case ARG_VERBOSE: 463 if (arg) { 464 if (strcmp(arg, "v") == 0) { 465 env->very_verbose = true; 466 } else { 467 fprintf(stderr, 468 "Unrecognized verbosity setting ('%s'), only -v and -vv are supported\n", 469 arg); 470 return -EINVAL; 471 } 472 } 473 env->verbose = true; 474 break; 475 case ARGP_KEY_ARG: 476 argp_usage(state); 477 break; 478 case ARGP_KEY_END: 479 break; 480 default: 481 return ARGP_ERR_UNKNOWN; 482 } 483 return 0; 484 } 485 486 static void stdio_hijack(void) 487 { 488 #ifdef __GLIBC__ 489 env.stdout = stdout; 490 env.stderr = stderr; 491 492 if (env.verbose) { 493 /* nothing to do, output to stdout by default */ 494 return; 495 } 496 497 /* stdout and stderr -> buffer */ 498 fflush(stdout); 499 500 stdout = open_memstream(&env.log_buf, &env.log_cnt); 501 if (!stdout) { 502 stdout = env.stdout; 503 perror("open_memstream"); 504 return; 505 } 506 507 stderr = stdout; 508 #endif 509 } 510 511 static void stdio_restore(void) 512 { 513 #ifdef __GLIBC__ 514 if (stdout == env.stdout) 515 return; 516 517 fclose(stdout); 518 free(env.log_buf); 519 520 env.log_buf = NULL; 521 env.log_cnt = 0; 522 523 stdout = env.stdout; 524 stderr = env.stderr; 525 #endif 526 } 527 528 /* 529 * Determine if test_progs is running as a "flavored" test runner and switch 530 * into corresponding sub-directory to load correct BPF objects. 531 * 532 * This is done by looking at executable name. If it contains "-flavor" 533 * suffix, then we are running as a flavored test runner. 534 */ 535 int cd_flavor_subdir(const char *exec_name) 536 { 537 /* General form of argv[0] passed here is: 538 * some/path/to/test_progs[-flavor], where -flavor part is optional. 539 * First cut out "test_progs[-flavor]" part, then extract "flavor" 540 * part, if it's there. 541 */ 542 const char *flavor = strrchr(exec_name, '/'); 543 544 if (!flavor) 545 return 0; 546 flavor++; 547 flavor = strrchr(flavor, '-'); 548 if (!flavor) 549 return 0; 550 flavor++; 551 printf("Switching to flavor '%s' subdirectory...\n", flavor); 552 return chdir(flavor); 553 } 554 555 int main(int argc, char **argv) 556 { 557 static const struct argp argp = { 558 .options = opts, 559 .parser = parse_arg, 560 .doc = argp_program_doc, 561 }; 562 int err, i; 563 564 err = argp_parse(&argp, argc, argv, 0, NULL, &env); 565 if (err) 566 return err; 567 568 err = cd_flavor_subdir(argv[0]); 569 if (err) 570 return err; 571 572 libbpf_set_print(libbpf_print_fn); 573 574 srand(time(NULL)); 575 576 env.jit_enabled = is_jit_enabled(); 577 578 stdio_hijack(); 579 for (i = 0; i < prog_test_cnt; i++) { 580 struct prog_test_def *test = &prog_test_defs[i]; 581 582 env.test = test; 583 test->test_num = i + 1; 584 585 if (!should_run(&env.test_selector, 586 test->test_num, test->test_name)) 587 continue; 588 589 test->run_test(); 590 /* ensure last sub-test is finalized properly */ 591 if (test->subtest_name) 592 test__end_subtest(); 593 594 test->tested = true; 595 if (test->error_cnt) 596 env.fail_cnt++; 597 else 598 env.succ_cnt++; 599 skip_account(); 600 601 dump_test_log(test, test->error_cnt); 602 603 fprintf(env.stdout, "#%d %s:%s\n", 604 test->test_num, test->test_name, 605 test->error_cnt ? "FAIL" : "OK"); 606 607 if (test->need_cgroup_cleanup) 608 cleanup_cgroup_environment(); 609 } 610 stdio_restore(); 611 printf("Summary: %d/%d PASSED, %d SKIPPED, %d FAILED\n", 612 env.succ_cnt, env.sub_succ_cnt, env.skip_cnt, env.fail_cnt); 613 614 free(env.test_selector.num_set); 615 free(env.subtest_selector.num_set); 616 617 return env.fail_cnt ? EXIT_FAILURE : EXIT_SUCCESS; 618 } 619