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 */
11 struct test_env env
= {};
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
)
34 for (i
= 0; i
< sel
->blacklist
.cnt
; i
++) {
35 if (strstr(name
, sel
->blacklist
.strs
[i
]))
39 for (i
= 0; i
< sel
->whitelist
.cnt
; i
++) {
40 if (strstr(name
, sel
->whitelist
.strs
[i
]))
44 if (!sel
->whitelist
.cnt
&& !sel
->num_set
)
47 return num
< sel
->num_set_len
&& sel
->num_set
[num
];
50 static void dump_test_log(const struct prog_test_def
*test
, bool failed
)
52 if (stdout
== env
.stdout
)
55 fflush(stdout
); /* exports env.log_buf & env.log_cnt */
57 if (env
.verbosity
> VERBOSE_NONE
|| test
->force_log
|| failed
) {
59 env
.log_buf
[env
.log_cnt
] = '\0';
60 fprintf(env
.stdout
, "%s", env
.log_buf
);
61 if (env
.log_buf
[env
.log_cnt
- 1] != '\n')
62 fprintf(env
.stdout
, "\n");
66 fseeko(stdout
, 0, SEEK_SET
); /* rewind */
69 static void skip_account(void)
71 if (env
.test
->skip_cnt
) {
73 env
.test
->skip_cnt
= 0;
77 void test__end_subtest()
79 struct prog_test_def
*test
= env
.test
;
80 int sub_error_cnt
= test
->error_cnt
- test
->old_error_cnt
;
88 dump_test_log(test
, sub_error_cnt
);
90 fprintf(env
.stdout
, "#%d/%d %s:%s\n",
91 test
->test_num
, test
->subtest_num
,
92 test
->subtest_name
, sub_error_cnt
? "FAIL" : "OK");
94 free(test
->subtest_name
);
95 test
->subtest_name
= NULL
;
98 bool test__start_subtest(const char *name
)
100 struct prog_test_def
*test
= env
.test
;
102 if (test
->subtest_name
)
107 if (!name
|| !name
[0]) {
109 "Subtest #%d didn't provide sub-test name!\n",
114 if (!should_run(&env
.subtest_selector
, test
->subtest_num
, name
))
117 test
->subtest_name
= strdup(name
);
118 if (!test
->subtest_name
) {
120 "Subtest #%d: failed to copy subtest name!\n",
124 env
.test
->old_error_cnt
= env
.test
->error_cnt
;
129 void test__force_log() {
130 env
.test
->force_log
= true;
133 void test__skip(void)
135 env
.test
->skip_cnt
++;
138 void test__fail(void)
140 env
.test
->error_cnt
++;
143 int test__join_cgroup(const char *path
)
147 if (!env
.test
->need_cgroup_cleanup
) {
148 if (setup_cgroup_environment()) {
150 "#%d %s: Failed to setup cgroup environment\n",
151 env
.test
->test_num
, env
.test
->test_name
);
155 env
.test
->need_cgroup_cleanup
= true;
158 fd
= create_and_get_cgroup(path
);
161 "#%d %s: Failed to create cgroup '%s' (errno=%d)\n",
162 env
.test
->test_num
, env
.test
->test_name
, path
, errno
);
166 if (join_cgroup(path
)) {
168 "#%d %s: Failed to join cgroup '%s' (errno=%d)\n",
169 env
.test
->test_num
, env
.test
->test_name
, path
, errno
);
176 struct ipv4_packet pkt_v4
= {
177 .eth
.h_proto
= __bpf_constant_htons(ETH_P_IP
),
179 .iph
.protocol
= IPPROTO_TCP
,
180 .iph
.tot_len
= __bpf_constant_htons(MAGIC_BYTES
),
185 struct ipv6_packet pkt_v6
= {
186 .eth
.h_proto
= __bpf_constant_htons(ETH_P_IPV6
),
187 .iph
.nexthdr
= IPPROTO_TCP
,
188 .iph
.payload_len
= __bpf_constant_htons(MAGIC_BYTES
),
193 int bpf_find_map(const char *test
, struct bpf_object
*obj
, const char *name
)
197 map
= bpf_object__find_map_by_name(obj
, name
);
199 printf("%s:FAIL:map '%s' not found\n", test
, name
);
203 return bpf_map__fd(map
);
206 static bool is_jit_enabled(void)
208 const char *jit_sysctl
= "/proc/sys/net/core/bpf_jit_enable";
209 bool enabled
= false;
212 sysctl_fd
= open(jit_sysctl
, 0, O_RDONLY
);
213 if (sysctl_fd
!= -1) {
216 if (read(sysctl_fd
, &tmpc
, sizeof(tmpc
)) == 1)
217 enabled
= (tmpc
!= '0');
224 int compare_map_keys(int map1_fd
, int map2_fd
)
227 char val_buf
[PERF_MAX_STACK_DEPTH
*
228 sizeof(struct bpf_stack_build_id
)];
231 err
= bpf_map_get_next_key(map1_fd
, NULL
, &key
);
234 err
= bpf_map_lookup_elem(map2_fd
, &key
, val_buf
);
238 while (bpf_map_get_next_key(map1_fd
, &key
, &next_key
) == 0) {
239 err
= bpf_map_lookup_elem(map2_fd
, &next_key
, val_buf
);
251 int compare_stack_ips(int smap_fd
, int amap_fd
, int stack_trace_len
)
253 __u32 key
, next_key
, *cur_key_p
, *next_key_p
;
254 char *val_buf1
, *val_buf2
;
257 val_buf1
= malloc(stack_trace_len
);
258 val_buf2
= malloc(stack_trace_len
);
261 while (bpf_map_get_next_key(smap_fd
, cur_key_p
, next_key_p
) == 0) {
262 err
= bpf_map_lookup_elem(smap_fd
, next_key_p
, val_buf1
);
265 err
= bpf_map_lookup_elem(amap_fd
, next_key_p
, val_buf2
);
268 for (i
= 0; i
< stack_trace_len
; i
++) {
269 if (val_buf1
[i
] != val_buf2
[i
]) {
276 next_key_p
= &next_key
;
287 int extract_build_id(char *build_id
, size_t size
)
293 fp
= popen("readelf -n ./urandom_read | grep 'Build ID'", "r");
297 if (getline(&line
, &len
, fp
) == -1)
303 memcpy(build_id
, line
, len
);
304 build_id
[len
] = '\0';
311 void *spin_lock_thread(void *arg
)
313 __u32 duration
, retval
;
314 int err
, prog_fd
= *(u32
*) arg
;
316 err
= bpf_prog_test_run(prog_fd
, 10000, &pkt_v4
, sizeof(pkt_v4
),
317 NULL
, NULL
, &retval
, &duration
);
318 CHECK(err
|| retval
, "",
319 "err %d errno %d retval %d duration %d\n",
320 err
, errno
, retval
, duration
);
324 /* extern declarations for test funcs */
325 #define DEFINE_TEST(name) extern void test_##name(void);
326 #include <prog_tests/tests.h>
329 static struct prog_test_def prog_test_defs
[] = {
330 #define DEFINE_TEST(name) { \
331 .test_name = #name, \
332 .run_test = &test_##name, \
334 #include <prog_tests/tests.h>
337 const int prog_test_cnt
= ARRAY_SIZE(prog_test_defs
);
339 const char *argp_program_version
= "test_progs 0.1";
340 const char *argp_program_bug_address
= "<bpf@vger.kernel.org>";
341 const char argp_program_doc
[] = "BPF selftests test runner";
346 ARG_TEST_NAME_BLACKLIST
= 'b',
347 ARG_VERIFIER_STATS
= 's',
351 static const struct argp_option opts
[] = {
352 { "num", ARG_TEST_NUM
, "NUM", 0,
353 "Run test number NUM only " },
354 { "name", ARG_TEST_NAME
, "NAMES", 0,
355 "Run tests with names containing any string from NAMES list" },
356 { "name-blacklist", ARG_TEST_NAME_BLACKLIST
, "NAMES", 0,
357 "Don't run tests with names containing any string from NAMES list" },
358 { "verifier-stats", ARG_VERIFIER_STATS
, NULL
, 0,
359 "Output verifier statistics", },
360 { "verbose", ARG_VERBOSE
, "LEVEL", OPTION_ARG_OPTIONAL
,
361 "Verbose output (use -vv or -vvv for progressively verbose output)" },
365 static int libbpf_print_fn(enum libbpf_print_level level
,
366 const char *format
, va_list args
)
368 if (env
.verbosity
< VERBOSE_VERY
&& level
== LIBBPF_DEBUG
)
370 vprintf(format
, args
);
374 static int parse_str_list(const char *s
, struct str_set
*set
)
376 char *input
, *state
= NULL
, *next
, **tmp
, **strs
= NULL
;
386 while ((next
= strtok_r(state
? NULL
: input
, ",", &state
))) {
387 tmp
= realloc(strs
, sizeof(*strs
) * (cnt
+ 1));
392 strs
[cnt
] = strdup(next
);
400 set
->strs
= (const char **)strs
;
409 int parse_num_list(const char *s
, struct test_selector
*sel
)
411 int i
, set_len
= 0, num
, start
= 0, end
= -1;
412 bool *set
= NULL
, *tmp
, parsing_end
= false;
417 num
= strtol(s
, &next
, 10);
426 if (!parsing_end
&& *next
== '-') {
430 } else if (*next
== ',') {
434 } else if (*next
== '\0') {
445 if (end
+ 1 > set_len
) {
447 tmp
= realloc(set
, set_len
);
454 for (i
= start
; i
<= end
; i
++) {
464 sel
->num_set_len
= set_len
;
469 extern int extra_prog_load_log_flags
;
471 static error_t
parse_arg(int key
, char *arg
, struct argp_state
*state
)
473 struct test_env
*env
= state
->input
;
477 char *subtest_str
= strchr(arg
, '/');
481 if (parse_num_list(subtest_str
+ 1,
482 &env
->subtest_selector
)) {
484 "Failed to parse subtest numbers.\n");
488 if (parse_num_list(arg
, &env
->test_selector
)) {
489 fprintf(stderr
, "Failed to parse test numbers.\n");
494 case ARG_TEST_NAME
: {
495 char *subtest_str
= strchr(arg
, '/');
499 if (parse_str_list(subtest_str
+ 1,
500 &env
->subtest_selector
.whitelist
))
503 if (parse_str_list(arg
, &env
->test_selector
.whitelist
))
507 case ARG_TEST_NAME_BLACKLIST
: {
508 char *subtest_str
= strchr(arg
, '/');
512 if (parse_str_list(subtest_str
+ 1,
513 &env
->subtest_selector
.blacklist
))
516 if (parse_str_list(arg
, &env
->test_selector
.blacklist
))
520 case ARG_VERIFIER_STATS
:
521 env
->verifier_stats
= true;
524 env
->verbosity
= VERBOSE_NORMAL
;
526 if (strcmp(arg
, "v") == 0) {
527 env
->verbosity
= VERBOSE_VERY
;
528 extra_prog_load_log_flags
= 1;
529 } else if (strcmp(arg
, "vv") == 0) {
530 env
->verbosity
= VERBOSE_SUPER
;
531 extra_prog_load_log_flags
= 2;
534 "Unrecognized verbosity setting ('%s'), only -v and -vv are supported\n",
546 return ARGP_ERR_UNKNOWN
;
551 static void stdio_hijack(void)
557 if (env
.verbosity
> VERBOSE_NONE
) {
558 /* nothing to do, output to stdout by default */
562 /* stdout and stderr -> buffer */
565 stdout
= open_memstream(&env
.log_buf
, &env
.log_cnt
);
568 perror("open_memstream");
576 static void stdio_restore(void)
579 if (stdout
== env
.stdout
)
594 * Determine if test_progs is running as a "flavored" test runner and switch
595 * into corresponding sub-directory to load correct BPF objects.
597 * This is done by looking at executable name. If it contains "-flavor"
598 * suffix, then we are running as a flavored test runner.
600 int cd_flavor_subdir(const char *exec_name
)
602 /* General form of argv[0] passed here is:
603 * some/path/to/test_progs[-flavor], where -flavor part is optional.
604 * First cut out "test_progs[-flavor]" part, then extract "flavor"
605 * part, if it's there.
607 const char *flavor
= strrchr(exec_name
, '/');
612 flavor
= strrchr(flavor
, '-');
616 printf("Switching to flavor '%s' subdirectory...\n", flavor
);
617 return chdir(flavor
);
620 int main(int argc
, char **argv
)
622 static const struct argp argp
= {
625 .doc
= argp_program_doc
,
629 err
= argp_parse(&argp
, argc
, argv
, 0, NULL
, &env
);
633 err
= cd_flavor_subdir(argv
[0]);
637 libbpf_set_print(libbpf_print_fn
);
641 env
.jit_enabled
= is_jit_enabled();
644 for (i
= 0; i
< prog_test_cnt
; i
++) {
645 struct prog_test_def
*test
= &prog_test_defs
[i
];
648 test
->test_num
= i
+ 1;
650 if (!should_run(&env
.test_selector
,
651 test
->test_num
, test
->test_name
))
655 /* ensure last sub-test is finalized properly */
656 if (test
->subtest_name
)
666 dump_test_log(test
, test
->error_cnt
);
668 fprintf(env
.stdout
, "#%d %s:%s\n",
669 test
->test_num
, test
->test_name
,
670 test
->error_cnt
? "FAIL" : "OK");
672 if (test
->need_cgroup_cleanup
)
673 cleanup_cgroup_environment();
676 printf("Summary: %d/%d PASSED, %d SKIPPED, %d FAILED\n",
677 env
.succ_cnt
, env
.sub_succ_cnt
, env
.skip_cnt
, env
.fail_cnt
);
679 free(env
.test_selector
.blacklist
.strs
);
680 free(env
.test_selector
.whitelist
.strs
);
681 free(env
.test_selector
.num_set
);
682 free(env
.subtest_selector
.blacklist
.strs
);
683 free(env
.subtest_selector
.whitelist
.strs
);
684 free(env
.subtest_selector
.num_set
);
686 return env
.fail_cnt
? EXIT_FAILURE
: EXIT_SUCCESS
;