1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2017 Facebook
4 #include "test_progs.h"
5 #include "cgroup_helpers.h"
6 #include "bpf_rlimit.h"
10 /* defined in test_progs.h */
13 struct prog_test_def {
14 const char *test_name;
16 void (*run_test)(void);
21 bool need_cgroup_cleanup;
26 /* store counts before subtest started */
30 static bool should_run(struct test_selector *sel, int num, const char *name)
32 if (sel->name && sel->name[0] && !strstr(name, sel->name))
38 return num < sel->num_set_len && sel->num_set[num];
41 static void dump_test_log(const struct prog_test_def *test, bool failed)
43 if (stdout == env.stdout)
46 fflush(stdout); /* exports env.log_buf & env.log_cnt */
48 if (env.verbosity > VERBOSE_NONE || test->force_log || failed) {
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");
57 fseeko(stdout, 0, SEEK_SET); /* rewind */
60 static void skip_account(void)
62 if (env.test->skip_cnt) {
64 env.test->skip_cnt = 0;
68 void test__end_subtest()
70 struct prog_test_def *test = env.test;
71 int sub_error_cnt = test->error_cnt - test->old_error_cnt;
79 dump_test_log(test, sub_error_cnt);
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");
85 free(test->subtest_name);
86 test->subtest_name = NULL;
89 bool test__start_subtest(const char *name)
91 struct prog_test_def *test = env.test;
93 if (test->subtest_name)
98 if (!name || !name[0]) {
100 "Subtest #%d didn't provide sub-test name!\n",
105 if (!should_run(&env.subtest_selector, test->subtest_num, name))
108 test->subtest_name = strdup(name);
109 if (!test->subtest_name) {
111 "Subtest #%d: failed to copy subtest name!\n",
115 env.test->old_error_cnt = env.test->error_cnt;
120 void test__force_log() {
121 env.test->force_log = true;
124 void test__skip(void)
126 env.test->skip_cnt++;
129 void test__fail(void)
131 env.test->error_cnt++;
134 int test__join_cgroup(const char *path)
138 if (!env.test->need_cgroup_cleanup) {
139 if (setup_cgroup_environment()) {
141 "#%d %s: Failed to setup cgroup environment\n",
142 env.test->test_num, env.test->test_name);
146 env.test->need_cgroup_cleanup = true;
149 fd = create_and_get_cgroup(path);
152 "#%d %s: Failed to create cgroup '%s' (errno=%d)\n",
153 env.test->test_num, env.test->test_name, path, errno);
157 if (join_cgroup(path)) {
159 "#%d %s: Failed to join cgroup '%s' (errno=%d)\n",
160 env.test->test_num, env.test->test_name, path, errno);
167 struct ipv4_packet pkt_v4 = {
168 .eth.h_proto = __bpf_constant_htons(ETH_P_IP),
170 .iph.protocol = IPPROTO_TCP,
171 .iph.tot_len = __bpf_constant_htons(MAGIC_BYTES),
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),
184 int bpf_find_map(const char *test, struct bpf_object *obj, const char *name)
188 map = bpf_object__find_map_by_name(obj, name);
190 printf("%s:FAIL:map '%s' not found\n", test, name);
194 return bpf_map__fd(map);
197 static bool is_jit_enabled(void)
199 const char *jit_sysctl = "/proc/sys/net/core/bpf_jit_enable";
200 bool enabled = false;
203 sysctl_fd = open(jit_sysctl, 0, O_RDONLY);
204 if (sysctl_fd != -1) {
207 if (read(sysctl_fd, &tmpc, sizeof(tmpc)) == 1)
208 enabled = (tmpc != '0');
215 int compare_map_keys(int map1_fd, int map2_fd)
218 char val_buf[PERF_MAX_STACK_DEPTH *
219 sizeof(struct bpf_stack_build_id)];
222 err = bpf_map_get_next_key(map1_fd, NULL, &key);
225 err = bpf_map_lookup_elem(map2_fd, &key, val_buf);
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);
242 int compare_stack_ips(int smap_fd, int amap_fd, int stack_trace_len)
244 __u32 key, next_key, *cur_key_p, *next_key_p;
245 char *val_buf1, *val_buf2;
248 val_buf1 = malloc(stack_trace_len);
249 val_buf2 = malloc(stack_trace_len);
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);
256 err = bpf_map_lookup_elem(amap_fd, next_key_p, val_buf2);
259 for (i = 0; i < stack_trace_len; i++) {
260 if (val_buf1[i] != val_buf2[i]) {
267 next_key_p = &next_key;
278 int extract_build_id(char *build_id, size_t size)
284 fp = popen("readelf -n ./urandom_read | grep 'Build ID'", "r");
288 if (getline(&line, &len, fp) == -1)
294 memcpy(build_id, line, len);
295 build_id[len] = '\0';
302 void *spin_lock_thread(void *arg)
304 __u32 duration, retval;
305 int err, prog_fd = *(u32 *) arg;
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);
315 /* extern declarations for test funcs */
316 #define DEFINE_TEST(name) extern void test_##name(void);
317 #include <prog_tests/tests.h>
320 static struct prog_test_def prog_test_defs[] = {
321 #define DEFINE_TEST(name) { \
322 .test_name = #name, \
323 .run_test = &test_##name, \
325 #include <prog_tests/tests.h>
328 const int prog_test_cnt = ARRAY_SIZE(prog_test_defs);
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";
337 ARG_VERIFIER_STATS = 's',
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)" },
353 static int libbpf_print_fn(enum libbpf_print_level level,
354 const char *format, va_list args)
356 if (env.verbosity < VERBOSE_VERY && level == LIBBPF_DEBUG)
358 vprintf(format, args);
362 int parse_num_list(const char *s, struct test_selector *sel)
364 int i, set_len = 0, num, start = 0, end = -1;
365 bool *set = NULL, *tmp, parsing_end = false;
370 num = strtol(s, &next, 10);
379 if (!parsing_end && *next == '-') {
383 } else if (*next == ',') {
387 } else if (*next == '\0') {
398 if (end + 1 > set_len) {
400 tmp = realloc(set, set_len);
407 for (i = start; i <= end; i++) {
417 sel->num_set_len = set_len;
422 extern int extra_prog_load_log_flags;
424 static error_t parse_arg(int key, char *arg, struct argp_state *state)
426 struct test_env *env = state->input;
430 char *subtest_str = strchr(arg, '/');
434 if (parse_num_list(subtest_str + 1,
435 &env->subtest_selector)) {
437 "Failed to parse subtest numbers.\n");
441 if (parse_num_list(arg, &env->test_selector)) {
442 fprintf(stderr, "Failed to parse test numbers.\n");
447 case ARG_TEST_NAME: {
448 char *subtest_str = strchr(arg, '/');
452 env->subtest_selector.name = strdup(subtest_str + 1);
453 if (!env->subtest_selector.name)
456 env->test_selector.name = strdup(arg);
457 if (!env->test_selector.name)
461 case ARG_VERIFIER_STATS:
462 env->verifier_stats = true;
465 env->verbosity = VERBOSE_NORMAL;
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;
475 "Unrecognized verbosity setting ('%s'), only -v and -vv are supported\n",
487 return ARGP_ERR_UNKNOWN;
492 static void stdio_hijack(void)
498 if (env.verbosity > VERBOSE_NONE) {
499 /* nothing to do, output to stdout by default */
503 /* stdout and stderr -> buffer */
506 stdout = open_memstream(&env.log_buf, &env.log_cnt);
509 perror("open_memstream");
517 static void stdio_restore(void)
520 if (stdout == env.stdout)
535 * Determine if test_progs is running as a "flavored" test runner and switch
536 * into corresponding sub-directory to load correct BPF objects.
538 * This is done by looking at executable name. If it contains "-flavor"
539 * suffix, then we are running as a flavored test runner.
541 int cd_flavor_subdir(const char *exec_name)
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.
548 const char *flavor = strrchr(exec_name, '/');
553 flavor = strrchr(flavor, '-');
557 printf("Switching to flavor '%s' subdirectory...\n", flavor);
558 return chdir(flavor);
561 int main(int argc, char **argv)
563 static const struct argp argp = {
566 .doc = argp_program_doc,
570 err = argp_parse(&argp, argc, argv, 0, NULL, &env);
574 err = cd_flavor_subdir(argv[0]);
578 libbpf_set_print(libbpf_print_fn);
582 env.jit_enabled = is_jit_enabled();
585 for (i = 0; i < prog_test_cnt; i++) {
586 struct prog_test_def *test = &prog_test_defs[i];
589 test->test_num = i + 1;
591 if (!should_run(&env.test_selector,
592 test->test_num, test->test_name))
596 /* ensure last sub-test is finalized properly */
597 if (test->subtest_name)
607 dump_test_log(test, test->error_cnt);
609 fprintf(env.stdout, "#%d %s:%s\n",
610 test->test_num, test->test_name,
611 test->error_cnt ? "FAIL" : "OK");
613 if (test->need_cgroup_cleanup)
614 cleanup_cgroup_environment();
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);
620 free(env.test_selector.num_set);
621 free(env.subtest_selector.num_set);
623 return env.fail_cnt ? EXIT_FAILURE : EXIT_SUCCESS;