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