root/tools/testing/selftests/bpf/test_progs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. should_run
  2. dump_test_log
  3. skip_account
  4. test__end_subtest
  5. test__start_subtest
  6. test__force_log
  7. test__skip
  8. test__fail
  9. test__join_cgroup
  10. bpf_find_map
  11. is_jit_enabled
  12. compare_map_keys
  13. compare_stack_ips
  14. extract_build_id
  15. spin_lock_thread
  16. libbpf_print_fn
  17. parse_num_list
  18. parse_arg
  19. stdio_hijack
  20. stdio_restore
  21. main

   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();
 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 int main(int argc, char **argv)
 529 {
 530         static const struct argp argp = {
 531                 .options = opts,
 532                 .parser = parse_arg,
 533                 .doc = argp_program_doc,
 534         };
 535         int err, i;
 536 
 537         err = argp_parse(&argp, argc, argv, 0, NULL, &env);
 538         if (err)
 539                 return err;
 540 
 541         libbpf_set_print(libbpf_print_fn);
 542 
 543         srand(time(NULL));
 544 
 545         env.jit_enabled = is_jit_enabled();
 546 
 547         stdio_hijack();
 548         for (i = 0; i < prog_test_cnt; i++) {
 549                 struct prog_test_def *test = &prog_test_defs[i];
 550 
 551                 env.test = test;
 552                 test->test_num = i + 1;
 553 
 554                 if (!should_run(&env.test_selector,
 555                                 test->test_num, test->test_name))
 556                         continue;
 557 
 558                 test->run_test();
 559                 /* ensure last sub-test is finalized properly */
 560                 if (test->subtest_name)
 561                         test__end_subtest();
 562 
 563                 test->tested = true;
 564                 if (test->error_cnt)
 565                         env.fail_cnt++;
 566                 else
 567                         env.succ_cnt++;
 568                 skip_account();
 569 
 570                 dump_test_log(test, test->error_cnt);
 571 
 572                 fprintf(env.stdout, "#%d %s:%s\n",
 573                         test->test_num, test->test_name,
 574                         test->error_cnt ? "FAIL" : "OK");
 575 
 576                 if (test->need_cgroup_cleanup)
 577                         cleanup_cgroup_environment();
 578         }
 579         stdio_restore();
 580         printf("Summary: %d/%d PASSED, %d SKIPPED, %d FAILED\n",
 581                env.succ_cnt, env.sub_succ_cnt, env.skip_cnt, env.fail_cnt);
 582 
 583         free(env.test_selector.num_set);
 584         free(env.subtest_selector.num_set);
 585 
 586         return env.fail_cnt ? EXIT_FAILURE : EXIT_SUCCESS;
 587 }

/* [<][>][^][v][top][bottom][index][help] */