162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* Copyright (c) 2017 Facebook 362306a36Sopenharmony_ci */ 462306a36Sopenharmony_ci#define _GNU_SOURCE 562306a36Sopenharmony_ci#include "test_progs.h" 662306a36Sopenharmony_ci#include "testing_helpers.h" 762306a36Sopenharmony_ci#include "cgroup_helpers.h" 862306a36Sopenharmony_ci#include <argp.h> 962306a36Sopenharmony_ci#include <pthread.h> 1062306a36Sopenharmony_ci#include <sched.h> 1162306a36Sopenharmony_ci#include <signal.h> 1262306a36Sopenharmony_ci#include <string.h> 1362306a36Sopenharmony_ci#include <execinfo.h> /* backtrace */ 1462306a36Sopenharmony_ci#include <sys/sysinfo.h> /* get_nprocs */ 1562306a36Sopenharmony_ci#include <netinet/in.h> 1662306a36Sopenharmony_ci#include <sys/select.h> 1762306a36Sopenharmony_ci#include <sys/socket.h> 1862306a36Sopenharmony_ci#include <sys/un.h> 1962306a36Sopenharmony_ci#include <bpf/btf.h> 2062306a36Sopenharmony_ci#include "json_writer.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic bool verbose(void) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci return env.verbosity > VERBOSE_NONE; 2562306a36Sopenharmony_ci} 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic void stdio_hijack_init(char **log_buf, size_t *log_cnt) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci#ifdef __GLIBC__ 3062306a36Sopenharmony_ci if (verbose() && env.worker_id == -1) { 3162306a36Sopenharmony_ci /* nothing to do, output to stdout by default */ 3262306a36Sopenharmony_ci return; 3362306a36Sopenharmony_ci } 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci fflush(stdout); 3662306a36Sopenharmony_ci fflush(stderr); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci stdout = open_memstream(log_buf, log_cnt); 3962306a36Sopenharmony_ci if (!stdout) { 4062306a36Sopenharmony_ci stdout = env.stdout; 4162306a36Sopenharmony_ci perror("open_memstream"); 4262306a36Sopenharmony_ci return; 4362306a36Sopenharmony_ci } 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci if (env.subtest_state) 4662306a36Sopenharmony_ci env.subtest_state->stdout = stdout; 4762306a36Sopenharmony_ci else 4862306a36Sopenharmony_ci env.test_state->stdout = stdout; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci stderr = stdout; 5162306a36Sopenharmony_ci#endif 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic void stdio_hijack(char **log_buf, size_t *log_cnt) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci#ifdef __GLIBC__ 5762306a36Sopenharmony_ci if (verbose() && env.worker_id == -1) { 5862306a36Sopenharmony_ci /* nothing to do, output to stdout by default */ 5962306a36Sopenharmony_ci return; 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci env.stdout = stdout; 6362306a36Sopenharmony_ci env.stderr = stderr; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci stdio_hijack_init(log_buf, log_cnt); 6662306a36Sopenharmony_ci#endif 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic void stdio_restore_cleanup(void) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci#ifdef __GLIBC__ 7262306a36Sopenharmony_ci if (verbose() && env.worker_id == -1) { 7362306a36Sopenharmony_ci /* nothing to do, output to stdout by default */ 7462306a36Sopenharmony_ci return; 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci fflush(stdout); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (env.subtest_state) { 8062306a36Sopenharmony_ci fclose(env.subtest_state->stdout); 8162306a36Sopenharmony_ci env.subtest_state->stdout = NULL; 8262306a36Sopenharmony_ci stdout = env.test_state->stdout; 8362306a36Sopenharmony_ci stderr = env.test_state->stdout; 8462306a36Sopenharmony_ci } else { 8562306a36Sopenharmony_ci fclose(env.test_state->stdout); 8662306a36Sopenharmony_ci env.test_state->stdout = NULL; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci#endif 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic void stdio_restore(void) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci#ifdef __GLIBC__ 9462306a36Sopenharmony_ci if (verbose() && env.worker_id == -1) { 9562306a36Sopenharmony_ci /* nothing to do, output to stdout by default */ 9662306a36Sopenharmony_ci return; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (stdout == env.stdout) 10062306a36Sopenharmony_ci return; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci stdio_restore_cleanup(); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci stdout = env.stdout; 10562306a36Sopenharmony_ci stderr = env.stderr; 10662306a36Sopenharmony_ci#endif 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/* Adapted from perf/util/string.c */ 11062306a36Sopenharmony_cistatic bool glob_match(const char *str, const char *pat) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci while (*str && *pat && *pat != '*') { 11362306a36Sopenharmony_ci if (*str != *pat) 11462306a36Sopenharmony_ci return false; 11562306a36Sopenharmony_ci str++; 11662306a36Sopenharmony_ci pat++; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci /* Check wild card */ 11962306a36Sopenharmony_ci if (*pat == '*') { 12062306a36Sopenharmony_ci while (*pat == '*') 12162306a36Sopenharmony_ci pat++; 12262306a36Sopenharmony_ci if (!*pat) /* Tail wild card matches all */ 12362306a36Sopenharmony_ci return true; 12462306a36Sopenharmony_ci while (*str) 12562306a36Sopenharmony_ci if (glob_match(str++, pat)) 12662306a36Sopenharmony_ci return true; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci return !*str && !*pat; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci#define EXIT_NO_TEST 2 13262306a36Sopenharmony_ci#define EXIT_ERR_SETUP_INFRA 3 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci/* defined in test_progs.h */ 13562306a36Sopenharmony_cistruct test_env env = {}; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistruct prog_test_def { 13862306a36Sopenharmony_ci const char *test_name; 13962306a36Sopenharmony_ci int test_num; 14062306a36Sopenharmony_ci void (*run_test)(void); 14162306a36Sopenharmony_ci void (*run_serial_test)(void); 14262306a36Sopenharmony_ci bool should_run; 14362306a36Sopenharmony_ci bool need_cgroup_cleanup; 14462306a36Sopenharmony_ci}; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/* Override C runtime library's usleep() implementation to ensure nanosleep() 14762306a36Sopenharmony_ci * is always called. Usleep is frequently used in selftests as a way to 14862306a36Sopenharmony_ci * trigger kprobe and tracepoints. 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_ciint usleep(useconds_t usec) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci struct timespec ts = { 15362306a36Sopenharmony_ci .tv_sec = usec / 1000000, 15462306a36Sopenharmony_ci .tv_nsec = (usec % 1000000) * 1000, 15562306a36Sopenharmony_ci }; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci return syscall(__NR_nanosleep, &ts, NULL); 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic bool should_run(struct test_selector *sel, int num, const char *name) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci int i; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci for (i = 0; i < sel->blacklist.cnt; i++) { 16562306a36Sopenharmony_ci if (glob_match(name, sel->blacklist.tests[i].name) && 16662306a36Sopenharmony_ci !sel->blacklist.tests[i].subtest_cnt) 16762306a36Sopenharmony_ci return false; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci for (i = 0; i < sel->whitelist.cnt; i++) { 17162306a36Sopenharmony_ci if (glob_match(name, sel->whitelist.tests[i].name)) 17262306a36Sopenharmony_ci return true; 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (!sel->whitelist.cnt && !sel->num_set) 17662306a36Sopenharmony_ci return true; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci return num < sel->num_set_len && sel->num_set[num]; 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic bool should_run_subtest(struct test_selector *sel, 18262306a36Sopenharmony_ci struct test_selector *subtest_sel, 18362306a36Sopenharmony_ci int subtest_num, 18462306a36Sopenharmony_ci const char *test_name, 18562306a36Sopenharmony_ci const char *subtest_name) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci int i, j; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci for (i = 0; i < sel->blacklist.cnt; i++) { 19062306a36Sopenharmony_ci if (glob_match(test_name, sel->blacklist.tests[i].name)) { 19162306a36Sopenharmony_ci if (!sel->blacklist.tests[i].subtest_cnt) 19262306a36Sopenharmony_ci return false; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci for (j = 0; j < sel->blacklist.tests[i].subtest_cnt; j++) { 19562306a36Sopenharmony_ci if (glob_match(subtest_name, 19662306a36Sopenharmony_ci sel->blacklist.tests[i].subtests[j])) 19762306a36Sopenharmony_ci return false; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci for (i = 0; i < sel->whitelist.cnt; i++) { 20362306a36Sopenharmony_ci if (glob_match(test_name, sel->whitelist.tests[i].name)) { 20462306a36Sopenharmony_ci if (!sel->whitelist.tests[i].subtest_cnt) 20562306a36Sopenharmony_ci return true; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci for (j = 0; j < sel->whitelist.tests[i].subtest_cnt; j++) { 20862306a36Sopenharmony_ci if (glob_match(subtest_name, 20962306a36Sopenharmony_ci sel->whitelist.tests[i].subtests[j])) 21062306a36Sopenharmony_ci return true; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (!sel->whitelist.cnt && !subtest_sel->num_set) 21662306a36Sopenharmony_ci return true; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci return subtest_num < subtest_sel->num_set_len && subtest_sel->num_set[subtest_num]; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic char *test_result(bool failed, bool skipped) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci return failed ? "FAIL" : (skipped ? "SKIP" : "OK"); 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci#define TEST_NUM_WIDTH 7 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic void print_test_result(const struct prog_test_def *test, const struct test_state *test_state) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci int skipped_cnt = test_state->skip_cnt; 23162306a36Sopenharmony_ci int subtests_cnt = test_state->subtest_num; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci fprintf(env.stdout, "#%-*d %s:", TEST_NUM_WIDTH, test->test_num, test->test_name); 23462306a36Sopenharmony_ci if (test_state->error_cnt) 23562306a36Sopenharmony_ci fprintf(env.stdout, "FAIL"); 23662306a36Sopenharmony_ci else if (!skipped_cnt) 23762306a36Sopenharmony_ci fprintf(env.stdout, "OK"); 23862306a36Sopenharmony_ci else if (skipped_cnt == subtests_cnt || !subtests_cnt) 23962306a36Sopenharmony_ci fprintf(env.stdout, "SKIP"); 24062306a36Sopenharmony_ci else 24162306a36Sopenharmony_ci fprintf(env.stdout, "OK (SKIP: %d/%d)", skipped_cnt, subtests_cnt); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci fprintf(env.stdout, "\n"); 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic void print_test_log(char *log_buf, size_t log_cnt) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci log_buf[log_cnt] = '\0'; 24962306a36Sopenharmony_ci fprintf(env.stdout, "%s", log_buf); 25062306a36Sopenharmony_ci if (log_buf[log_cnt - 1] != '\n') 25162306a36Sopenharmony_ci fprintf(env.stdout, "\n"); 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic void print_subtest_name(int test_num, int subtest_num, 25562306a36Sopenharmony_ci const char *test_name, char *subtest_name, 25662306a36Sopenharmony_ci char *result) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci char test_num_str[TEST_NUM_WIDTH + 1]; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci snprintf(test_num_str, sizeof(test_num_str), "%d/%d", test_num, subtest_num); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci fprintf(env.stdout, "#%-*s %s/%s", 26362306a36Sopenharmony_ci TEST_NUM_WIDTH, test_num_str, 26462306a36Sopenharmony_ci test_name, subtest_name); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (result) 26762306a36Sopenharmony_ci fprintf(env.stdout, ":%s", result); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci fprintf(env.stdout, "\n"); 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic void jsonw_write_log_message(json_writer_t *w, char *log_buf, size_t log_cnt) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci /* open_memstream (from stdio_hijack_init) ensures that log_bug is terminated by a 27562306a36Sopenharmony_ci * null byte. Yet in parallel mode, log_buf will be NULL if there is no message. 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_ci if (log_cnt) { 27862306a36Sopenharmony_ci jsonw_string_field(w, "message", log_buf); 27962306a36Sopenharmony_ci } else { 28062306a36Sopenharmony_ci jsonw_string_field(w, "message", ""); 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic void dump_test_log(const struct prog_test_def *test, 28562306a36Sopenharmony_ci const struct test_state *test_state, 28662306a36Sopenharmony_ci bool skip_ok_subtests, 28762306a36Sopenharmony_ci bool par_exec_result, 28862306a36Sopenharmony_ci json_writer_t *w) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci bool test_failed = test_state->error_cnt > 0; 29162306a36Sopenharmony_ci bool force_log = test_state->force_log; 29262306a36Sopenharmony_ci bool print_test = verbose() || force_log || test_failed; 29362306a36Sopenharmony_ci int i; 29462306a36Sopenharmony_ci struct subtest_state *subtest_state; 29562306a36Sopenharmony_ci bool subtest_failed; 29662306a36Sopenharmony_ci bool subtest_filtered; 29762306a36Sopenharmony_ci bool print_subtest; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci /* we do not print anything in the worker thread */ 30062306a36Sopenharmony_ci if (env.worker_id != -1) 30162306a36Sopenharmony_ci return; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci /* there is nothing to print when verbose log is used and execution 30462306a36Sopenharmony_ci * is not in parallel mode 30562306a36Sopenharmony_ci */ 30662306a36Sopenharmony_ci if (verbose() && !par_exec_result) 30762306a36Sopenharmony_ci return; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (test_state->log_cnt && print_test) 31062306a36Sopenharmony_ci print_test_log(test_state->log_buf, test_state->log_cnt); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (w && print_test) { 31362306a36Sopenharmony_ci jsonw_start_object(w); 31462306a36Sopenharmony_ci jsonw_string_field(w, "name", test->test_name); 31562306a36Sopenharmony_ci jsonw_uint_field(w, "number", test->test_num); 31662306a36Sopenharmony_ci jsonw_write_log_message(w, test_state->log_buf, test_state->log_cnt); 31762306a36Sopenharmony_ci jsonw_bool_field(w, "failed", test_failed); 31862306a36Sopenharmony_ci jsonw_name(w, "subtests"); 31962306a36Sopenharmony_ci jsonw_start_array(w); 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci for (i = 0; i < test_state->subtest_num; i++) { 32362306a36Sopenharmony_ci subtest_state = &test_state->subtest_states[i]; 32462306a36Sopenharmony_ci subtest_failed = subtest_state->error_cnt; 32562306a36Sopenharmony_ci subtest_filtered = subtest_state->filtered; 32662306a36Sopenharmony_ci print_subtest = verbose() || force_log || subtest_failed; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci if ((skip_ok_subtests && !subtest_failed) || subtest_filtered) 32962306a36Sopenharmony_ci continue; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (subtest_state->log_cnt && print_subtest) { 33262306a36Sopenharmony_ci print_test_log(subtest_state->log_buf, 33362306a36Sopenharmony_ci subtest_state->log_cnt); 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci print_subtest_name(test->test_num, i + 1, 33762306a36Sopenharmony_ci test->test_name, subtest_state->name, 33862306a36Sopenharmony_ci test_result(subtest_state->error_cnt, 33962306a36Sopenharmony_ci subtest_state->skipped)); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (w && print_subtest) { 34262306a36Sopenharmony_ci jsonw_start_object(w); 34362306a36Sopenharmony_ci jsonw_string_field(w, "name", subtest_state->name); 34462306a36Sopenharmony_ci jsonw_uint_field(w, "number", i+1); 34562306a36Sopenharmony_ci jsonw_write_log_message(w, subtest_state->log_buf, subtest_state->log_cnt); 34662306a36Sopenharmony_ci jsonw_bool_field(w, "failed", subtest_failed); 34762306a36Sopenharmony_ci jsonw_end_object(w); 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci if (w && print_test) { 35262306a36Sopenharmony_ci jsonw_end_array(w); 35362306a36Sopenharmony_ci jsonw_end_object(w); 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci print_test_result(test, test_state); 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_cistatic void stdio_restore(void); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci/* A bunch of tests set custom affinity per-thread and/or per-process. Reset 36262306a36Sopenharmony_ci * it after each test/sub-test. 36362306a36Sopenharmony_ci */ 36462306a36Sopenharmony_cistatic void reset_affinity(void) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci cpu_set_t cpuset; 36762306a36Sopenharmony_ci int i, err; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci CPU_ZERO(&cpuset); 37062306a36Sopenharmony_ci for (i = 0; i < env.nr_cpus; i++) 37162306a36Sopenharmony_ci CPU_SET(i, &cpuset); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci err = sched_setaffinity(0, sizeof(cpuset), &cpuset); 37462306a36Sopenharmony_ci if (err < 0) { 37562306a36Sopenharmony_ci stdio_restore(); 37662306a36Sopenharmony_ci fprintf(stderr, "Failed to reset process affinity: %d!\n", err); 37762306a36Sopenharmony_ci exit(EXIT_ERR_SETUP_INFRA); 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci err = pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset); 38062306a36Sopenharmony_ci if (err < 0) { 38162306a36Sopenharmony_ci stdio_restore(); 38262306a36Sopenharmony_ci fprintf(stderr, "Failed to reset thread affinity: %d!\n", err); 38362306a36Sopenharmony_ci exit(EXIT_ERR_SETUP_INFRA); 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic void save_netns(void) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci env.saved_netns_fd = open("/proc/self/ns/net", O_RDONLY); 39062306a36Sopenharmony_ci if (env.saved_netns_fd == -1) { 39162306a36Sopenharmony_ci perror("open(/proc/self/ns/net)"); 39262306a36Sopenharmony_ci exit(EXIT_ERR_SETUP_INFRA); 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic void restore_netns(void) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci if (setns(env.saved_netns_fd, CLONE_NEWNET) == -1) { 39962306a36Sopenharmony_ci stdio_restore(); 40062306a36Sopenharmony_ci perror("setns(CLONE_NEWNS)"); 40162306a36Sopenharmony_ci exit(EXIT_ERR_SETUP_INFRA); 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_civoid test__end_subtest(void) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct prog_test_def *test = env.test; 40862306a36Sopenharmony_ci struct test_state *test_state = env.test_state; 40962306a36Sopenharmony_ci struct subtest_state *subtest_state = env.subtest_state; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (subtest_state->error_cnt) { 41262306a36Sopenharmony_ci test_state->error_cnt++; 41362306a36Sopenharmony_ci } else { 41462306a36Sopenharmony_ci if (!subtest_state->skipped) 41562306a36Sopenharmony_ci test_state->sub_succ_cnt++; 41662306a36Sopenharmony_ci else 41762306a36Sopenharmony_ci test_state->skip_cnt++; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci if (verbose() && !env.workers) 42162306a36Sopenharmony_ci print_subtest_name(test->test_num, test_state->subtest_num, 42262306a36Sopenharmony_ci test->test_name, subtest_state->name, 42362306a36Sopenharmony_ci test_result(subtest_state->error_cnt, 42462306a36Sopenharmony_ci subtest_state->skipped)); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci stdio_restore_cleanup(); 42762306a36Sopenharmony_ci env.subtest_state = NULL; 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cibool test__start_subtest(const char *subtest_name) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci struct prog_test_def *test = env.test; 43362306a36Sopenharmony_ci struct test_state *state = env.test_state; 43462306a36Sopenharmony_ci struct subtest_state *subtest_state; 43562306a36Sopenharmony_ci size_t sub_state_size = sizeof(*subtest_state); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci if (env.subtest_state) 43862306a36Sopenharmony_ci test__end_subtest(); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci state->subtest_num++; 44162306a36Sopenharmony_ci state->subtest_states = 44262306a36Sopenharmony_ci realloc(state->subtest_states, 44362306a36Sopenharmony_ci state->subtest_num * sub_state_size); 44462306a36Sopenharmony_ci if (!state->subtest_states) { 44562306a36Sopenharmony_ci fprintf(stderr, "Not enough memory to allocate subtest result\n"); 44662306a36Sopenharmony_ci return false; 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci subtest_state = &state->subtest_states[state->subtest_num - 1]; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci memset(subtest_state, 0, sub_state_size); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if (!subtest_name || !subtest_name[0]) { 45462306a36Sopenharmony_ci fprintf(env.stderr, 45562306a36Sopenharmony_ci "Subtest #%d didn't provide sub-test name!\n", 45662306a36Sopenharmony_ci state->subtest_num); 45762306a36Sopenharmony_ci return false; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci subtest_state->name = strdup(subtest_name); 46162306a36Sopenharmony_ci if (!subtest_state->name) { 46262306a36Sopenharmony_ci fprintf(env.stderr, 46362306a36Sopenharmony_ci "Subtest #%d: failed to copy subtest name!\n", 46462306a36Sopenharmony_ci state->subtest_num); 46562306a36Sopenharmony_ci return false; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci if (!should_run_subtest(&env.test_selector, 46962306a36Sopenharmony_ci &env.subtest_selector, 47062306a36Sopenharmony_ci state->subtest_num, 47162306a36Sopenharmony_ci test->test_name, 47262306a36Sopenharmony_ci subtest_name)) { 47362306a36Sopenharmony_ci subtest_state->filtered = true; 47462306a36Sopenharmony_ci return false; 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci env.subtest_state = subtest_state; 47862306a36Sopenharmony_ci stdio_hijack_init(&subtest_state->log_buf, &subtest_state->log_cnt); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci return true; 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_civoid test__force_log(void) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci env.test_state->force_log = true; 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_civoid test__skip(void) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci if (env.subtest_state) 49162306a36Sopenharmony_ci env.subtest_state->skipped = true; 49262306a36Sopenharmony_ci else 49362306a36Sopenharmony_ci env.test_state->skip_cnt++; 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_civoid test__fail(void) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci if (env.subtest_state) 49962306a36Sopenharmony_ci env.subtest_state->error_cnt++; 50062306a36Sopenharmony_ci else 50162306a36Sopenharmony_ci env.test_state->error_cnt++; 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ciint test__join_cgroup(const char *path) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci int fd; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (!env.test->need_cgroup_cleanup) { 50962306a36Sopenharmony_ci if (setup_cgroup_environment()) { 51062306a36Sopenharmony_ci fprintf(stderr, 51162306a36Sopenharmony_ci "#%d %s: Failed to setup cgroup environment\n", 51262306a36Sopenharmony_ci env.test->test_num, env.test->test_name); 51362306a36Sopenharmony_ci return -1; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci env.test->need_cgroup_cleanup = true; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci fd = create_and_get_cgroup(path); 52062306a36Sopenharmony_ci if (fd < 0) { 52162306a36Sopenharmony_ci fprintf(stderr, 52262306a36Sopenharmony_ci "#%d %s: Failed to create cgroup '%s' (errno=%d)\n", 52362306a36Sopenharmony_ci env.test->test_num, env.test->test_name, path, errno); 52462306a36Sopenharmony_ci return fd; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci if (join_cgroup(path)) { 52862306a36Sopenharmony_ci fprintf(stderr, 52962306a36Sopenharmony_ci "#%d %s: Failed to join cgroup '%s' (errno=%d)\n", 53062306a36Sopenharmony_ci env.test->test_num, env.test->test_name, path, errno); 53162306a36Sopenharmony_ci return -1; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci return fd; 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ciint bpf_find_map(const char *test, struct bpf_object *obj, const char *name) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci struct bpf_map *map; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci map = bpf_object__find_map_by_name(obj, name); 54262306a36Sopenharmony_ci if (!map) { 54362306a36Sopenharmony_ci fprintf(stdout, "%s:FAIL:map '%s' not found\n", test, name); 54462306a36Sopenharmony_ci test__fail(); 54562306a36Sopenharmony_ci return -1; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci return bpf_map__fd(map); 54862306a36Sopenharmony_ci} 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_cistatic bool is_jit_enabled(void) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci const char *jit_sysctl = "/proc/sys/net/core/bpf_jit_enable"; 55362306a36Sopenharmony_ci bool enabled = false; 55462306a36Sopenharmony_ci int sysctl_fd; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci sysctl_fd = open(jit_sysctl, 0, O_RDONLY); 55762306a36Sopenharmony_ci if (sysctl_fd != -1) { 55862306a36Sopenharmony_ci char tmpc; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci if (read(sysctl_fd, &tmpc, sizeof(tmpc)) == 1) 56162306a36Sopenharmony_ci enabled = (tmpc != '0'); 56262306a36Sopenharmony_ci close(sysctl_fd); 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci return enabled; 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ciint compare_map_keys(int map1_fd, int map2_fd) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci __u32 key, next_key; 57162306a36Sopenharmony_ci char val_buf[PERF_MAX_STACK_DEPTH * 57262306a36Sopenharmony_ci sizeof(struct bpf_stack_build_id)]; 57362306a36Sopenharmony_ci int err; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci err = bpf_map_get_next_key(map1_fd, NULL, &key); 57662306a36Sopenharmony_ci if (err) 57762306a36Sopenharmony_ci return err; 57862306a36Sopenharmony_ci err = bpf_map_lookup_elem(map2_fd, &key, val_buf); 57962306a36Sopenharmony_ci if (err) 58062306a36Sopenharmony_ci return err; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci while (bpf_map_get_next_key(map1_fd, &key, &next_key) == 0) { 58362306a36Sopenharmony_ci err = bpf_map_lookup_elem(map2_fd, &next_key, val_buf); 58462306a36Sopenharmony_ci if (err) 58562306a36Sopenharmony_ci return err; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci key = next_key; 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci if (errno != ENOENT) 59062306a36Sopenharmony_ci return -1; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci return 0; 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ciint compare_stack_ips(int smap_fd, int amap_fd, int stack_trace_len) 59662306a36Sopenharmony_ci{ 59762306a36Sopenharmony_ci __u32 key, next_key, *cur_key_p, *next_key_p; 59862306a36Sopenharmony_ci char *val_buf1, *val_buf2; 59962306a36Sopenharmony_ci int i, err = 0; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci val_buf1 = malloc(stack_trace_len); 60262306a36Sopenharmony_ci val_buf2 = malloc(stack_trace_len); 60362306a36Sopenharmony_ci cur_key_p = NULL; 60462306a36Sopenharmony_ci next_key_p = &key; 60562306a36Sopenharmony_ci while (bpf_map_get_next_key(smap_fd, cur_key_p, next_key_p) == 0) { 60662306a36Sopenharmony_ci err = bpf_map_lookup_elem(smap_fd, next_key_p, val_buf1); 60762306a36Sopenharmony_ci if (err) 60862306a36Sopenharmony_ci goto out; 60962306a36Sopenharmony_ci err = bpf_map_lookup_elem(amap_fd, next_key_p, val_buf2); 61062306a36Sopenharmony_ci if (err) 61162306a36Sopenharmony_ci goto out; 61262306a36Sopenharmony_ci for (i = 0; i < stack_trace_len; i++) { 61362306a36Sopenharmony_ci if (val_buf1[i] != val_buf2[i]) { 61462306a36Sopenharmony_ci err = -1; 61562306a36Sopenharmony_ci goto out; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci key = *next_key_p; 61962306a36Sopenharmony_ci cur_key_p = &key; 62062306a36Sopenharmony_ci next_key_p = &next_key; 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci if (errno != ENOENT) 62362306a36Sopenharmony_ci err = -1; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ciout: 62662306a36Sopenharmony_ci free(val_buf1); 62762306a36Sopenharmony_ci free(val_buf2); 62862306a36Sopenharmony_ci return err; 62962306a36Sopenharmony_ci} 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci/* extern declarations for test funcs */ 63262306a36Sopenharmony_ci#define DEFINE_TEST(name) \ 63362306a36Sopenharmony_ci extern void test_##name(void) __weak; \ 63462306a36Sopenharmony_ci extern void serial_test_##name(void) __weak; 63562306a36Sopenharmony_ci#include <prog_tests/tests.h> 63662306a36Sopenharmony_ci#undef DEFINE_TEST 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cistatic struct prog_test_def prog_test_defs[] = { 63962306a36Sopenharmony_ci#define DEFINE_TEST(name) { \ 64062306a36Sopenharmony_ci .test_name = #name, \ 64162306a36Sopenharmony_ci .run_test = &test_##name, \ 64262306a36Sopenharmony_ci .run_serial_test = &serial_test_##name, \ 64362306a36Sopenharmony_ci}, 64462306a36Sopenharmony_ci#include <prog_tests/tests.h> 64562306a36Sopenharmony_ci#undef DEFINE_TEST 64662306a36Sopenharmony_ci}; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cistatic const int prog_test_cnt = ARRAY_SIZE(prog_test_defs); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_cistatic struct test_state test_states[ARRAY_SIZE(prog_test_defs)]; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ciconst char *argp_program_version = "test_progs 0.1"; 65362306a36Sopenharmony_ciconst char *argp_program_bug_address = "<bpf@vger.kernel.org>"; 65462306a36Sopenharmony_cistatic const char argp_program_doc[] = 65562306a36Sopenharmony_ci"BPF selftests test runner\v" 65662306a36Sopenharmony_ci"Options accepting the NAMES parameter take either a comma-separated list\n" 65762306a36Sopenharmony_ci"of test names, or a filename prefixed with @. The file contains one name\n" 65862306a36Sopenharmony_ci"(or wildcard pattern) per line, and comments beginning with # are ignored.\n" 65962306a36Sopenharmony_ci"\n" 66062306a36Sopenharmony_ci"These options can be passed repeatedly to read multiple files.\n"; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_cienum ARG_KEYS { 66362306a36Sopenharmony_ci ARG_TEST_NUM = 'n', 66462306a36Sopenharmony_ci ARG_TEST_NAME = 't', 66562306a36Sopenharmony_ci ARG_TEST_NAME_BLACKLIST = 'b', 66662306a36Sopenharmony_ci ARG_VERIFIER_STATS = 's', 66762306a36Sopenharmony_ci ARG_VERBOSE = 'v', 66862306a36Sopenharmony_ci ARG_GET_TEST_CNT = 'c', 66962306a36Sopenharmony_ci ARG_LIST_TEST_NAMES = 'l', 67062306a36Sopenharmony_ci ARG_TEST_NAME_GLOB_ALLOWLIST = 'a', 67162306a36Sopenharmony_ci ARG_TEST_NAME_GLOB_DENYLIST = 'd', 67262306a36Sopenharmony_ci ARG_NUM_WORKERS = 'j', 67362306a36Sopenharmony_ci ARG_DEBUG = -1, 67462306a36Sopenharmony_ci ARG_JSON_SUMMARY = 'J' 67562306a36Sopenharmony_ci}; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_cistatic const struct argp_option opts[] = { 67862306a36Sopenharmony_ci { "num", ARG_TEST_NUM, "NUM", 0, 67962306a36Sopenharmony_ci "Run test number NUM only " }, 68062306a36Sopenharmony_ci { "name", ARG_TEST_NAME, "NAMES", 0, 68162306a36Sopenharmony_ci "Run tests with names containing any string from NAMES list" }, 68262306a36Sopenharmony_ci { "name-blacklist", ARG_TEST_NAME_BLACKLIST, "NAMES", 0, 68362306a36Sopenharmony_ci "Don't run tests with names containing any string from NAMES list" }, 68462306a36Sopenharmony_ci { "verifier-stats", ARG_VERIFIER_STATS, NULL, 0, 68562306a36Sopenharmony_ci "Output verifier statistics", }, 68662306a36Sopenharmony_ci { "verbose", ARG_VERBOSE, "LEVEL", OPTION_ARG_OPTIONAL, 68762306a36Sopenharmony_ci "Verbose output (use -vv or -vvv for progressively verbose output)" }, 68862306a36Sopenharmony_ci { "count", ARG_GET_TEST_CNT, NULL, 0, 68962306a36Sopenharmony_ci "Get number of selected top-level tests " }, 69062306a36Sopenharmony_ci { "list", ARG_LIST_TEST_NAMES, NULL, 0, 69162306a36Sopenharmony_ci "List test names that would run (without running them) " }, 69262306a36Sopenharmony_ci { "allow", ARG_TEST_NAME_GLOB_ALLOWLIST, "NAMES", 0, 69362306a36Sopenharmony_ci "Run tests with name matching the pattern (supports '*' wildcard)." }, 69462306a36Sopenharmony_ci { "deny", ARG_TEST_NAME_GLOB_DENYLIST, "NAMES", 0, 69562306a36Sopenharmony_ci "Don't run tests with name matching the pattern (supports '*' wildcard)." }, 69662306a36Sopenharmony_ci { "workers", ARG_NUM_WORKERS, "WORKERS", OPTION_ARG_OPTIONAL, 69762306a36Sopenharmony_ci "Number of workers to run in parallel, default to number of cpus." }, 69862306a36Sopenharmony_ci { "debug", ARG_DEBUG, NULL, 0, 69962306a36Sopenharmony_ci "print extra debug information for test_progs." }, 70062306a36Sopenharmony_ci { "json-summary", ARG_JSON_SUMMARY, "FILE", 0, "Write report in json format to this file."}, 70162306a36Sopenharmony_ci {}, 70262306a36Sopenharmony_ci}; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistatic int libbpf_print_fn(enum libbpf_print_level level, 70562306a36Sopenharmony_ci const char *format, va_list args) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci if (env.verbosity < VERBOSE_VERY && level == LIBBPF_DEBUG) 70862306a36Sopenharmony_ci return 0; 70962306a36Sopenharmony_ci vfprintf(stdout, format, args); 71062306a36Sopenharmony_ci return 0; 71162306a36Sopenharmony_ci} 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_cistatic void free_test_filter_set(const struct test_filter_set *set) 71462306a36Sopenharmony_ci{ 71562306a36Sopenharmony_ci int i, j; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci if (!set) 71862306a36Sopenharmony_ci return; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci for (i = 0; i < set->cnt; i++) { 72162306a36Sopenharmony_ci free((void *)set->tests[i].name); 72262306a36Sopenharmony_ci for (j = 0; j < set->tests[i].subtest_cnt; j++) 72362306a36Sopenharmony_ci free((void *)set->tests[i].subtests[j]); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci free((void *)set->tests[i].subtests); 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci free((void *)set->tests); 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic void free_test_selector(struct test_selector *test_selector) 73262306a36Sopenharmony_ci{ 73362306a36Sopenharmony_ci free_test_filter_set(&test_selector->blacklist); 73462306a36Sopenharmony_ci free_test_filter_set(&test_selector->whitelist); 73562306a36Sopenharmony_ci free(test_selector->num_set); 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ciextern int extra_prog_load_log_flags; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_cistatic error_t parse_arg(int key, char *arg, struct argp_state *state) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci struct test_env *env = state->input; 74362306a36Sopenharmony_ci int err = 0; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci switch (key) { 74662306a36Sopenharmony_ci case ARG_TEST_NUM: { 74762306a36Sopenharmony_ci char *subtest_str = strchr(arg, '/'); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci if (subtest_str) { 75062306a36Sopenharmony_ci *subtest_str = '\0'; 75162306a36Sopenharmony_ci if (parse_num_list(subtest_str + 1, 75262306a36Sopenharmony_ci &env->subtest_selector.num_set, 75362306a36Sopenharmony_ci &env->subtest_selector.num_set_len)) { 75462306a36Sopenharmony_ci fprintf(stderr, 75562306a36Sopenharmony_ci "Failed to parse subtest numbers.\n"); 75662306a36Sopenharmony_ci return -EINVAL; 75762306a36Sopenharmony_ci } 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci if (parse_num_list(arg, &env->test_selector.num_set, 76062306a36Sopenharmony_ci &env->test_selector.num_set_len)) { 76162306a36Sopenharmony_ci fprintf(stderr, "Failed to parse test numbers.\n"); 76262306a36Sopenharmony_ci return -EINVAL; 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci break; 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci case ARG_TEST_NAME_GLOB_ALLOWLIST: 76762306a36Sopenharmony_ci case ARG_TEST_NAME: { 76862306a36Sopenharmony_ci if (arg[0] == '@') 76962306a36Sopenharmony_ci err = parse_test_list_file(arg + 1, 77062306a36Sopenharmony_ci &env->test_selector.whitelist, 77162306a36Sopenharmony_ci key == ARG_TEST_NAME_GLOB_ALLOWLIST); 77262306a36Sopenharmony_ci else 77362306a36Sopenharmony_ci err = parse_test_list(arg, 77462306a36Sopenharmony_ci &env->test_selector.whitelist, 77562306a36Sopenharmony_ci key == ARG_TEST_NAME_GLOB_ALLOWLIST); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci break; 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci case ARG_TEST_NAME_GLOB_DENYLIST: 78062306a36Sopenharmony_ci case ARG_TEST_NAME_BLACKLIST: { 78162306a36Sopenharmony_ci if (arg[0] == '@') 78262306a36Sopenharmony_ci err = parse_test_list_file(arg + 1, 78362306a36Sopenharmony_ci &env->test_selector.blacklist, 78462306a36Sopenharmony_ci key == ARG_TEST_NAME_GLOB_DENYLIST); 78562306a36Sopenharmony_ci else 78662306a36Sopenharmony_ci err = parse_test_list(arg, 78762306a36Sopenharmony_ci &env->test_selector.blacklist, 78862306a36Sopenharmony_ci key == ARG_TEST_NAME_GLOB_DENYLIST); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci break; 79162306a36Sopenharmony_ci } 79262306a36Sopenharmony_ci case ARG_VERIFIER_STATS: 79362306a36Sopenharmony_ci env->verifier_stats = true; 79462306a36Sopenharmony_ci break; 79562306a36Sopenharmony_ci case ARG_VERBOSE: 79662306a36Sopenharmony_ci env->verbosity = VERBOSE_NORMAL; 79762306a36Sopenharmony_ci if (arg) { 79862306a36Sopenharmony_ci if (strcmp(arg, "v") == 0) { 79962306a36Sopenharmony_ci env->verbosity = VERBOSE_VERY; 80062306a36Sopenharmony_ci extra_prog_load_log_flags = 1; 80162306a36Sopenharmony_ci } else if (strcmp(arg, "vv") == 0) { 80262306a36Sopenharmony_ci env->verbosity = VERBOSE_SUPER; 80362306a36Sopenharmony_ci extra_prog_load_log_flags = 2; 80462306a36Sopenharmony_ci } else { 80562306a36Sopenharmony_ci fprintf(stderr, 80662306a36Sopenharmony_ci "Unrecognized verbosity setting ('%s'), only -v and -vv are supported\n", 80762306a36Sopenharmony_ci arg); 80862306a36Sopenharmony_ci return -EINVAL; 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci if (verbose()) { 81362306a36Sopenharmony_ci if (setenv("SELFTESTS_VERBOSE", "1", 1) == -1) { 81462306a36Sopenharmony_ci fprintf(stderr, 81562306a36Sopenharmony_ci "Unable to setenv SELFTESTS_VERBOSE=1 (errno=%d)", 81662306a36Sopenharmony_ci errno); 81762306a36Sopenharmony_ci return -EINVAL; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci break; 82262306a36Sopenharmony_ci case ARG_GET_TEST_CNT: 82362306a36Sopenharmony_ci env->get_test_cnt = true; 82462306a36Sopenharmony_ci break; 82562306a36Sopenharmony_ci case ARG_LIST_TEST_NAMES: 82662306a36Sopenharmony_ci env->list_test_names = true; 82762306a36Sopenharmony_ci break; 82862306a36Sopenharmony_ci case ARG_NUM_WORKERS: 82962306a36Sopenharmony_ci if (arg) { 83062306a36Sopenharmony_ci env->workers = atoi(arg); 83162306a36Sopenharmony_ci if (!env->workers) { 83262306a36Sopenharmony_ci fprintf(stderr, "Invalid number of worker: %s.", arg); 83362306a36Sopenharmony_ci return -EINVAL; 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci } else { 83662306a36Sopenharmony_ci env->workers = get_nprocs(); 83762306a36Sopenharmony_ci } 83862306a36Sopenharmony_ci break; 83962306a36Sopenharmony_ci case ARG_DEBUG: 84062306a36Sopenharmony_ci env->debug = true; 84162306a36Sopenharmony_ci break; 84262306a36Sopenharmony_ci case ARG_JSON_SUMMARY: 84362306a36Sopenharmony_ci env->json = fopen(arg, "w"); 84462306a36Sopenharmony_ci if (env->json == NULL) { 84562306a36Sopenharmony_ci perror("Failed to open json summary file"); 84662306a36Sopenharmony_ci return -errno; 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci break; 84962306a36Sopenharmony_ci case ARGP_KEY_ARG: 85062306a36Sopenharmony_ci argp_usage(state); 85162306a36Sopenharmony_ci break; 85262306a36Sopenharmony_ci case ARGP_KEY_END: 85362306a36Sopenharmony_ci break; 85462306a36Sopenharmony_ci default: 85562306a36Sopenharmony_ci return ARGP_ERR_UNKNOWN; 85662306a36Sopenharmony_ci } 85762306a36Sopenharmony_ci return err; 85862306a36Sopenharmony_ci} 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci/* 86162306a36Sopenharmony_ci * Determine if test_progs is running as a "flavored" test runner and switch 86262306a36Sopenharmony_ci * into corresponding sub-directory to load correct BPF objects. 86362306a36Sopenharmony_ci * 86462306a36Sopenharmony_ci * This is done by looking at executable name. If it contains "-flavor" 86562306a36Sopenharmony_ci * suffix, then we are running as a flavored test runner. 86662306a36Sopenharmony_ci */ 86762306a36Sopenharmony_ciint cd_flavor_subdir(const char *exec_name) 86862306a36Sopenharmony_ci{ 86962306a36Sopenharmony_ci /* General form of argv[0] passed here is: 87062306a36Sopenharmony_ci * some/path/to/test_progs[-flavor], where -flavor part is optional. 87162306a36Sopenharmony_ci * First cut out "test_progs[-flavor]" part, then extract "flavor" 87262306a36Sopenharmony_ci * part, if it's there. 87362306a36Sopenharmony_ci */ 87462306a36Sopenharmony_ci const char *flavor = strrchr(exec_name, '/'); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci if (!flavor) 87762306a36Sopenharmony_ci flavor = exec_name; 87862306a36Sopenharmony_ci else 87962306a36Sopenharmony_ci flavor++; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci flavor = strrchr(flavor, '-'); 88262306a36Sopenharmony_ci if (!flavor) 88362306a36Sopenharmony_ci return 0; 88462306a36Sopenharmony_ci flavor++; 88562306a36Sopenharmony_ci if (verbose()) 88662306a36Sopenharmony_ci fprintf(stdout, "Switching to flavor '%s' subdirectory...\n", flavor); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci return chdir(flavor); 88962306a36Sopenharmony_ci} 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ciint trigger_module_test_read(int read_sz) 89262306a36Sopenharmony_ci{ 89362306a36Sopenharmony_ci int fd, err; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci fd = open(BPF_TESTMOD_TEST_FILE, O_RDONLY); 89662306a36Sopenharmony_ci err = -errno; 89762306a36Sopenharmony_ci if (!ASSERT_GE(fd, 0, "testmod_file_open")) 89862306a36Sopenharmony_ci return err; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci read(fd, NULL, read_sz); 90162306a36Sopenharmony_ci close(fd); 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci return 0; 90462306a36Sopenharmony_ci} 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ciint trigger_module_test_write(int write_sz) 90762306a36Sopenharmony_ci{ 90862306a36Sopenharmony_ci int fd, err; 90962306a36Sopenharmony_ci char *buf = malloc(write_sz); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci if (!buf) 91262306a36Sopenharmony_ci return -ENOMEM; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci memset(buf, 'a', write_sz); 91562306a36Sopenharmony_ci buf[write_sz-1] = '\0'; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci fd = open(BPF_TESTMOD_TEST_FILE, O_WRONLY); 91862306a36Sopenharmony_ci err = -errno; 91962306a36Sopenharmony_ci if (!ASSERT_GE(fd, 0, "testmod_file_open")) { 92062306a36Sopenharmony_ci free(buf); 92162306a36Sopenharmony_ci return err; 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci write(fd, buf, write_sz); 92562306a36Sopenharmony_ci close(fd); 92662306a36Sopenharmony_ci free(buf); 92762306a36Sopenharmony_ci return 0; 92862306a36Sopenharmony_ci} 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ciint write_sysctl(const char *sysctl, const char *value) 93162306a36Sopenharmony_ci{ 93262306a36Sopenharmony_ci int fd, err, len; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci fd = open(sysctl, O_WRONLY); 93562306a36Sopenharmony_ci if (!ASSERT_NEQ(fd, -1, "open sysctl")) 93662306a36Sopenharmony_ci return -1; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci len = strlen(value); 93962306a36Sopenharmony_ci err = write(fd, value, len); 94062306a36Sopenharmony_ci close(fd); 94162306a36Sopenharmony_ci if (!ASSERT_EQ(err, len, "write sysctl")) 94262306a36Sopenharmony_ci return -1; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci return 0; 94562306a36Sopenharmony_ci} 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ciint get_bpf_max_tramp_links_from(struct btf *btf) 94862306a36Sopenharmony_ci{ 94962306a36Sopenharmony_ci const struct btf_enum *e; 95062306a36Sopenharmony_ci const struct btf_type *t; 95162306a36Sopenharmony_ci __u32 i, type_cnt; 95262306a36Sopenharmony_ci const char *name; 95362306a36Sopenharmony_ci __u16 j, vlen; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci for (i = 1, type_cnt = btf__type_cnt(btf); i < type_cnt; i++) { 95662306a36Sopenharmony_ci t = btf__type_by_id(btf, i); 95762306a36Sopenharmony_ci if (!t || !btf_is_enum(t) || t->name_off) 95862306a36Sopenharmony_ci continue; 95962306a36Sopenharmony_ci e = btf_enum(t); 96062306a36Sopenharmony_ci for (j = 0, vlen = btf_vlen(t); j < vlen; j++, e++) { 96162306a36Sopenharmony_ci name = btf__str_by_offset(btf, e->name_off); 96262306a36Sopenharmony_ci if (name && !strcmp(name, "BPF_MAX_TRAMP_LINKS")) 96362306a36Sopenharmony_ci return e->val; 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci } 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci return -1; 96862306a36Sopenharmony_ci} 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ciint get_bpf_max_tramp_links(void) 97162306a36Sopenharmony_ci{ 97262306a36Sopenharmony_ci struct btf *vmlinux_btf; 97362306a36Sopenharmony_ci int ret; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci vmlinux_btf = btf__load_vmlinux_btf(); 97662306a36Sopenharmony_ci if (!ASSERT_OK_PTR(vmlinux_btf, "vmlinux btf")) 97762306a36Sopenharmony_ci return -1; 97862306a36Sopenharmony_ci ret = get_bpf_max_tramp_links_from(vmlinux_btf); 97962306a36Sopenharmony_ci btf__free(vmlinux_btf); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci return ret; 98262306a36Sopenharmony_ci} 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci#define MAX_BACKTRACE_SZ 128 98562306a36Sopenharmony_civoid crash_handler(int signum) 98662306a36Sopenharmony_ci{ 98762306a36Sopenharmony_ci void *bt[MAX_BACKTRACE_SZ]; 98862306a36Sopenharmony_ci size_t sz; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci sz = backtrace(bt, ARRAY_SIZE(bt)); 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci if (env.stdout) 99362306a36Sopenharmony_ci stdio_restore(); 99462306a36Sopenharmony_ci if (env.test) { 99562306a36Sopenharmony_ci env.test_state->error_cnt++; 99662306a36Sopenharmony_ci dump_test_log(env.test, env.test_state, true, false, NULL); 99762306a36Sopenharmony_ci } 99862306a36Sopenharmony_ci if (env.worker_id != -1) 99962306a36Sopenharmony_ci fprintf(stderr, "[%d]: ", env.worker_id); 100062306a36Sopenharmony_ci fprintf(stderr, "Caught signal #%d!\nStack trace:\n", signum); 100162306a36Sopenharmony_ci backtrace_symbols_fd(bt, sz, STDERR_FILENO); 100262306a36Sopenharmony_ci} 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_cistatic void sigint_handler(int signum) 100562306a36Sopenharmony_ci{ 100662306a36Sopenharmony_ci int i; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci for (i = 0; i < env.workers; i++) 100962306a36Sopenharmony_ci if (env.worker_socks[i] > 0) 101062306a36Sopenharmony_ci close(env.worker_socks[i]); 101162306a36Sopenharmony_ci} 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_cistatic int current_test_idx; 101462306a36Sopenharmony_cistatic pthread_mutex_t current_test_lock; 101562306a36Sopenharmony_cistatic pthread_mutex_t stdout_output_lock; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_cistatic inline const char *str_msg(const struct msg *msg, char *buf) 101862306a36Sopenharmony_ci{ 101962306a36Sopenharmony_ci switch (msg->type) { 102062306a36Sopenharmony_ci case MSG_DO_TEST: 102162306a36Sopenharmony_ci sprintf(buf, "MSG_DO_TEST %d", msg->do_test.num); 102262306a36Sopenharmony_ci break; 102362306a36Sopenharmony_ci case MSG_TEST_DONE: 102462306a36Sopenharmony_ci sprintf(buf, "MSG_TEST_DONE %d (log: %d)", 102562306a36Sopenharmony_ci msg->test_done.num, 102662306a36Sopenharmony_ci msg->test_done.have_log); 102762306a36Sopenharmony_ci break; 102862306a36Sopenharmony_ci case MSG_SUBTEST_DONE: 102962306a36Sopenharmony_ci sprintf(buf, "MSG_SUBTEST_DONE %d (log: %d)", 103062306a36Sopenharmony_ci msg->subtest_done.num, 103162306a36Sopenharmony_ci msg->subtest_done.have_log); 103262306a36Sopenharmony_ci break; 103362306a36Sopenharmony_ci case MSG_TEST_LOG: 103462306a36Sopenharmony_ci sprintf(buf, "MSG_TEST_LOG (cnt: %zu, last: %d)", 103562306a36Sopenharmony_ci strlen(msg->test_log.log_buf), 103662306a36Sopenharmony_ci msg->test_log.is_last); 103762306a36Sopenharmony_ci break; 103862306a36Sopenharmony_ci case MSG_EXIT: 103962306a36Sopenharmony_ci sprintf(buf, "MSG_EXIT"); 104062306a36Sopenharmony_ci break; 104162306a36Sopenharmony_ci default: 104262306a36Sopenharmony_ci sprintf(buf, "UNKNOWN"); 104362306a36Sopenharmony_ci break; 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci return buf; 104762306a36Sopenharmony_ci} 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_cistatic int send_message(int sock, const struct msg *msg) 105062306a36Sopenharmony_ci{ 105162306a36Sopenharmony_ci char buf[256]; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci if (env.debug) 105462306a36Sopenharmony_ci fprintf(stderr, "Sending msg: %s\n", str_msg(msg, buf)); 105562306a36Sopenharmony_ci return send(sock, msg, sizeof(*msg), 0); 105662306a36Sopenharmony_ci} 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_cistatic int recv_message(int sock, struct msg *msg) 105962306a36Sopenharmony_ci{ 106062306a36Sopenharmony_ci int ret; 106162306a36Sopenharmony_ci char buf[256]; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci memset(msg, 0, sizeof(*msg)); 106462306a36Sopenharmony_ci ret = recv(sock, msg, sizeof(*msg), 0); 106562306a36Sopenharmony_ci if (ret >= 0) { 106662306a36Sopenharmony_ci if (env.debug) 106762306a36Sopenharmony_ci fprintf(stderr, "Received msg: %s\n", str_msg(msg, buf)); 106862306a36Sopenharmony_ci } 106962306a36Sopenharmony_ci return ret; 107062306a36Sopenharmony_ci} 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_cistatic void run_one_test(int test_num) 107362306a36Sopenharmony_ci{ 107462306a36Sopenharmony_ci struct prog_test_def *test = &prog_test_defs[test_num]; 107562306a36Sopenharmony_ci struct test_state *state = &test_states[test_num]; 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci env.test = test; 107862306a36Sopenharmony_ci env.test_state = state; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci stdio_hijack(&state->log_buf, &state->log_cnt); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci if (test->run_test) 108362306a36Sopenharmony_ci test->run_test(); 108462306a36Sopenharmony_ci else if (test->run_serial_test) 108562306a36Sopenharmony_ci test->run_serial_test(); 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci /* ensure last sub-test is finalized properly */ 108862306a36Sopenharmony_ci if (env.subtest_state) 108962306a36Sopenharmony_ci test__end_subtest(); 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci state->tested = true; 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci if (verbose() && env.worker_id == -1) 109462306a36Sopenharmony_ci print_test_result(test, state); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci reset_affinity(); 109762306a36Sopenharmony_ci restore_netns(); 109862306a36Sopenharmony_ci if (test->need_cgroup_cleanup) 109962306a36Sopenharmony_ci cleanup_cgroup_environment(); 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci stdio_restore(); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci dump_test_log(test, state, false, false, NULL); 110462306a36Sopenharmony_ci} 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_cistruct dispatch_data { 110762306a36Sopenharmony_ci int worker_id; 110862306a36Sopenharmony_ci int sock_fd; 110962306a36Sopenharmony_ci}; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_cistatic int read_prog_test_msg(int sock_fd, struct msg *msg, enum msg_type type) 111262306a36Sopenharmony_ci{ 111362306a36Sopenharmony_ci if (recv_message(sock_fd, msg) < 0) 111462306a36Sopenharmony_ci return 1; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci if (msg->type != type) { 111762306a36Sopenharmony_ci printf("%s: unexpected message type %d. expected %d\n", __func__, msg->type, type); 111862306a36Sopenharmony_ci return 1; 111962306a36Sopenharmony_ci } 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci return 0; 112262306a36Sopenharmony_ci} 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_cistatic int dispatch_thread_read_log(int sock_fd, char **log_buf, size_t *log_cnt) 112562306a36Sopenharmony_ci{ 112662306a36Sopenharmony_ci FILE *log_fp = NULL; 112762306a36Sopenharmony_ci int result = 0; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci log_fp = open_memstream(log_buf, log_cnt); 113062306a36Sopenharmony_ci if (!log_fp) 113162306a36Sopenharmony_ci return 1; 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci while (true) { 113462306a36Sopenharmony_ci struct msg msg; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci if (read_prog_test_msg(sock_fd, &msg, MSG_TEST_LOG)) { 113762306a36Sopenharmony_ci result = 1; 113862306a36Sopenharmony_ci goto out; 113962306a36Sopenharmony_ci } 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci fprintf(log_fp, "%s", msg.test_log.log_buf); 114262306a36Sopenharmony_ci if (msg.test_log.is_last) 114362306a36Sopenharmony_ci break; 114462306a36Sopenharmony_ci } 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ciout: 114762306a36Sopenharmony_ci fclose(log_fp); 114862306a36Sopenharmony_ci log_fp = NULL; 114962306a36Sopenharmony_ci return result; 115062306a36Sopenharmony_ci} 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_cistatic int dispatch_thread_send_subtests(int sock_fd, struct test_state *state) 115362306a36Sopenharmony_ci{ 115462306a36Sopenharmony_ci struct msg msg; 115562306a36Sopenharmony_ci struct subtest_state *subtest_state; 115662306a36Sopenharmony_ci int subtest_num = state->subtest_num; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci state->subtest_states = malloc(subtest_num * sizeof(*subtest_state)); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci for (int i = 0; i < subtest_num; i++) { 116162306a36Sopenharmony_ci subtest_state = &state->subtest_states[i]; 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci memset(subtest_state, 0, sizeof(*subtest_state)); 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci if (read_prog_test_msg(sock_fd, &msg, MSG_SUBTEST_DONE)) 116662306a36Sopenharmony_ci return 1; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci subtest_state->name = strdup(msg.subtest_done.name); 116962306a36Sopenharmony_ci subtest_state->error_cnt = msg.subtest_done.error_cnt; 117062306a36Sopenharmony_ci subtest_state->skipped = msg.subtest_done.skipped; 117162306a36Sopenharmony_ci subtest_state->filtered = msg.subtest_done.filtered; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci /* collect all logs */ 117462306a36Sopenharmony_ci if (msg.subtest_done.have_log) 117562306a36Sopenharmony_ci if (dispatch_thread_read_log(sock_fd, 117662306a36Sopenharmony_ci &subtest_state->log_buf, 117762306a36Sopenharmony_ci &subtest_state->log_cnt)) 117862306a36Sopenharmony_ci return 1; 117962306a36Sopenharmony_ci } 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci return 0; 118262306a36Sopenharmony_ci} 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_cistatic void *dispatch_thread(void *ctx) 118562306a36Sopenharmony_ci{ 118662306a36Sopenharmony_ci struct dispatch_data *data = ctx; 118762306a36Sopenharmony_ci int sock_fd; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci sock_fd = data->sock_fd; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci while (true) { 119262306a36Sopenharmony_ci int test_to_run = -1; 119362306a36Sopenharmony_ci struct prog_test_def *test; 119462306a36Sopenharmony_ci struct test_state *state; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci /* grab a test */ 119762306a36Sopenharmony_ci { 119862306a36Sopenharmony_ci pthread_mutex_lock(¤t_test_lock); 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci if (current_test_idx >= prog_test_cnt) { 120162306a36Sopenharmony_ci pthread_mutex_unlock(¤t_test_lock); 120262306a36Sopenharmony_ci goto done; 120362306a36Sopenharmony_ci } 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci test = &prog_test_defs[current_test_idx]; 120662306a36Sopenharmony_ci test_to_run = current_test_idx; 120762306a36Sopenharmony_ci current_test_idx++; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci pthread_mutex_unlock(¤t_test_lock); 121062306a36Sopenharmony_ci } 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci if (!test->should_run || test->run_serial_test) 121362306a36Sopenharmony_ci continue; 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci /* run test through worker */ 121662306a36Sopenharmony_ci { 121762306a36Sopenharmony_ci struct msg msg_do_test; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci memset(&msg_do_test, 0, sizeof(msg_do_test)); 122062306a36Sopenharmony_ci msg_do_test.type = MSG_DO_TEST; 122162306a36Sopenharmony_ci msg_do_test.do_test.num = test_to_run; 122262306a36Sopenharmony_ci if (send_message(sock_fd, &msg_do_test) < 0) { 122362306a36Sopenharmony_ci perror("Fail to send command"); 122462306a36Sopenharmony_ci goto done; 122562306a36Sopenharmony_ci } 122662306a36Sopenharmony_ci env.worker_current_test[data->worker_id] = test_to_run; 122762306a36Sopenharmony_ci } 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci /* wait for test done */ 123062306a36Sopenharmony_ci do { 123162306a36Sopenharmony_ci struct msg msg; 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci if (read_prog_test_msg(sock_fd, &msg, MSG_TEST_DONE)) 123462306a36Sopenharmony_ci goto error; 123562306a36Sopenharmony_ci if (test_to_run != msg.test_done.num) 123662306a36Sopenharmony_ci goto error; 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci state = &test_states[test_to_run]; 123962306a36Sopenharmony_ci state->tested = true; 124062306a36Sopenharmony_ci state->error_cnt = msg.test_done.error_cnt; 124162306a36Sopenharmony_ci state->skip_cnt = msg.test_done.skip_cnt; 124262306a36Sopenharmony_ci state->sub_succ_cnt = msg.test_done.sub_succ_cnt; 124362306a36Sopenharmony_ci state->subtest_num = msg.test_done.subtest_num; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci /* collect all logs */ 124662306a36Sopenharmony_ci if (msg.test_done.have_log) { 124762306a36Sopenharmony_ci if (dispatch_thread_read_log(sock_fd, 124862306a36Sopenharmony_ci &state->log_buf, 124962306a36Sopenharmony_ci &state->log_cnt)) 125062306a36Sopenharmony_ci goto error; 125162306a36Sopenharmony_ci } 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci /* collect all subtests and subtest logs */ 125462306a36Sopenharmony_ci if (!state->subtest_num) 125562306a36Sopenharmony_ci break; 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci if (dispatch_thread_send_subtests(sock_fd, state)) 125862306a36Sopenharmony_ci goto error; 125962306a36Sopenharmony_ci } while (false); 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci pthread_mutex_lock(&stdout_output_lock); 126262306a36Sopenharmony_ci dump_test_log(test, state, false, true, NULL); 126362306a36Sopenharmony_ci pthread_mutex_unlock(&stdout_output_lock); 126462306a36Sopenharmony_ci } /* while (true) */ 126562306a36Sopenharmony_cierror: 126662306a36Sopenharmony_ci if (env.debug) 126762306a36Sopenharmony_ci fprintf(stderr, "[%d]: Protocol/IO error: %s.\n", data->worker_id, strerror(errno)); 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_cidone: 127062306a36Sopenharmony_ci { 127162306a36Sopenharmony_ci struct msg msg_exit; 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci msg_exit.type = MSG_EXIT; 127462306a36Sopenharmony_ci if (send_message(sock_fd, &msg_exit) < 0) { 127562306a36Sopenharmony_ci if (env.debug) 127662306a36Sopenharmony_ci fprintf(stderr, "[%d]: send_message msg_exit: %s.\n", 127762306a36Sopenharmony_ci data->worker_id, strerror(errno)); 127862306a36Sopenharmony_ci } 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci return NULL; 128162306a36Sopenharmony_ci} 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_cistatic void calculate_summary_and_print_errors(struct test_env *env) 128462306a36Sopenharmony_ci{ 128562306a36Sopenharmony_ci int i; 128662306a36Sopenharmony_ci int succ_cnt = 0, fail_cnt = 0, sub_succ_cnt = 0, skip_cnt = 0; 128762306a36Sopenharmony_ci json_writer_t *w = NULL; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci for (i = 0; i < prog_test_cnt; i++) { 129062306a36Sopenharmony_ci struct test_state *state = &test_states[i]; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci if (!state->tested) 129362306a36Sopenharmony_ci continue; 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci sub_succ_cnt += state->sub_succ_cnt; 129662306a36Sopenharmony_ci skip_cnt += state->skip_cnt; 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci if (state->error_cnt) 129962306a36Sopenharmony_ci fail_cnt++; 130062306a36Sopenharmony_ci else 130162306a36Sopenharmony_ci succ_cnt++; 130262306a36Sopenharmony_ci } 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci if (env->json) { 130562306a36Sopenharmony_ci w = jsonw_new(env->json); 130662306a36Sopenharmony_ci if (!w) 130762306a36Sopenharmony_ci fprintf(env->stderr, "Failed to create new JSON stream."); 130862306a36Sopenharmony_ci } 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci if (w) { 131162306a36Sopenharmony_ci jsonw_start_object(w); 131262306a36Sopenharmony_ci jsonw_uint_field(w, "success", succ_cnt); 131362306a36Sopenharmony_ci jsonw_uint_field(w, "success_subtest", sub_succ_cnt); 131462306a36Sopenharmony_ci jsonw_uint_field(w, "skipped", skip_cnt); 131562306a36Sopenharmony_ci jsonw_uint_field(w, "failed", fail_cnt); 131662306a36Sopenharmony_ci jsonw_name(w, "results"); 131762306a36Sopenharmony_ci jsonw_start_array(w); 131862306a36Sopenharmony_ci } 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci /* 132162306a36Sopenharmony_ci * We only print error logs summary when there are failed tests and 132262306a36Sopenharmony_ci * verbose mode is not enabled. Otherwise, results may be incosistent. 132362306a36Sopenharmony_ci * 132462306a36Sopenharmony_ci */ 132562306a36Sopenharmony_ci if (!verbose() && fail_cnt) { 132662306a36Sopenharmony_ci printf("\nAll error logs:\n"); 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci /* print error logs again */ 132962306a36Sopenharmony_ci for (i = 0; i < prog_test_cnt; i++) { 133062306a36Sopenharmony_ci struct prog_test_def *test = &prog_test_defs[i]; 133162306a36Sopenharmony_ci struct test_state *state = &test_states[i]; 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci if (!state->tested || !state->error_cnt) 133462306a36Sopenharmony_ci continue; 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci dump_test_log(test, state, true, true, w); 133762306a36Sopenharmony_ci } 133862306a36Sopenharmony_ci } 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci if (w) { 134162306a36Sopenharmony_ci jsonw_end_array(w); 134262306a36Sopenharmony_ci jsonw_end_object(w); 134362306a36Sopenharmony_ci jsonw_destroy(&w); 134462306a36Sopenharmony_ci } 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci if (env->json) 134762306a36Sopenharmony_ci fclose(env->json); 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci printf("Summary: %d/%d PASSED, %d SKIPPED, %d FAILED\n", 135062306a36Sopenharmony_ci succ_cnt, sub_succ_cnt, skip_cnt, fail_cnt); 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci env->succ_cnt = succ_cnt; 135362306a36Sopenharmony_ci env->sub_succ_cnt = sub_succ_cnt; 135462306a36Sopenharmony_ci env->fail_cnt = fail_cnt; 135562306a36Sopenharmony_ci env->skip_cnt = skip_cnt; 135662306a36Sopenharmony_ci} 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_cistatic void server_main(void) 135962306a36Sopenharmony_ci{ 136062306a36Sopenharmony_ci pthread_t *dispatcher_threads; 136162306a36Sopenharmony_ci struct dispatch_data *data; 136262306a36Sopenharmony_ci struct sigaction sigact_int = { 136362306a36Sopenharmony_ci .sa_handler = sigint_handler, 136462306a36Sopenharmony_ci .sa_flags = SA_RESETHAND, 136562306a36Sopenharmony_ci }; 136662306a36Sopenharmony_ci int i; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci sigaction(SIGINT, &sigact_int, NULL); 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci dispatcher_threads = calloc(sizeof(pthread_t), env.workers); 137162306a36Sopenharmony_ci data = calloc(sizeof(struct dispatch_data), env.workers); 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci env.worker_current_test = calloc(sizeof(int), env.workers); 137462306a36Sopenharmony_ci for (i = 0; i < env.workers; i++) { 137562306a36Sopenharmony_ci int rc; 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci data[i].worker_id = i; 137862306a36Sopenharmony_ci data[i].sock_fd = env.worker_socks[i]; 137962306a36Sopenharmony_ci rc = pthread_create(&dispatcher_threads[i], NULL, dispatch_thread, &data[i]); 138062306a36Sopenharmony_ci if (rc < 0) { 138162306a36Sopenharmony_ci perror("Failed to launch dispatcher thread"); 138262306a36Sopenharmony_ci exit(EXIT_ERR_SETUP_INFRA); 138362306a36Sopenharmony_ci } 138462306a36Sopenharmony_ci } 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci /* wait for all dispatcher to finish */ 138762306a36Sopenharmony_ci for (i = 0; i < env.workers; i++) { 138862306a36Sopenharmony_ci while (true) { 138962306a36Sopenharmony_ci int ret = pthread_tryjoin_np(dispatcher_threads[i], NULL); 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci if (!ret) { 139262306a36Sopenharmony_ci break; 139362306a36Sopenharmony_ci } else if (ret == EBUSY) { 139462306a36Sopenharmony_ci if (env.debug) 139562306a36Sopenharmony_ci fprintf(stderr, "Still waiting for thread %d (test %d).\n", 139662306a36Sopenharmony_ci i, env.worker_current_test[i] + 1); 139762306a36Sopenharmony_ci usleep(1000 * 1000); 139862306a36Sopenharmony_ci continue; 139962306a36Sopenharmony_ci } else { 140062306a36Sopenharmony_ci fprintf(stderr, "Unexpected error joining dispatcher thread: %d", ret); 140162306a36Sopenharmony_ci break; 140262306a36Sopenharmony_ci } 140362306a36Sopenharmony_ci } 140462306a36Sopenharmony_ci } 140562306a36Sopenharmony_ci free(dispatcher_threads); 140662306a36Sopenharmony_ci free(env.worker_current_test); 140762306a36Sopenharmony_ci free(data); 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci /* run serial tests */ 141062306a36Sopenharmony_ci save_netns(); 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci for (int i = 0; i < prog_test_cnt; i++) { 141362306a36Sopenharmony_ci struct prog_test_def *test = &prog_test_defs[i]; 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci if (!test->should_run || !test->run_serial_test) 141662306a36Sopenharmony_ci continue; 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci run_one_test(i); 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci /* generate summary */ 142262306a36Sopenharmony_ci fflush(stderr); 142362306a36Sopenharmony_ci fflush(stdout); 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci calculate_summary_and_print_errors(&env); 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci /* reap all workers */ 142862306a36Sopenharmony_ci for (i = 0; i < env.workers; i++) { 142962306a36Sopenharmony_ci int wstatus, pid; 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci pid = waitpid(env.worker_pids[i], &wstatus, 0); 143262306a36Sopenharmony_ci if (pid != env.worker_pids[i]) 143362306a36Sopenharmony_ci perror("Unable to reap worker"); 143462306a36Sopenharmony_ci } 143562306a36Sopenharmony_ci} 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_cistatic void worker_main_send_log(int sock, char *log_buf, size_t log_cnt) 143862306a36Sopenharmony_ci{ 143962306a36Sopenharmony_ci char *src; 144062306a36Sopenharmony_ci size_t slen; 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci src = log_buf; 144362306a36Sopenharmony_ci slen = log_cnt; 144462306a36Sopenharmony_ci while (slen) { 144562306a36Sopenharmony_ci struct msg msg_log; 144662306a36Sopenharmony_ci char *dest; 144762306a36Sopenharmony_ci size_t len; 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci memset(&msg_log, 0, sizeof(msg_log)); 145062306a36Sopenharmony_ci msg_log.type = MSG_TEST_LOG; 145162306a36Sopenharmony_ci dest = msg_log.test_log.log_buf; 145262306a36Sopenharmony_ci len = slen >= MAX_LOG_TRUNK_SIZE ? MAX_LOG_TRUNK_SIZE : slen; 145362306a36Sopenharmony_ci memcpy(dest, src, len); 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci src += len; 145662306a36Sopenharmony_ci slen -= len; 145762306a36Sopenharmony_ci if (!slen) 145862306a36Sopenharmony_ci msg_log.test_log.is_last = true; 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci assert(send_message(sock, &msg_log) >= 0); 146162306a36Sopenharmony_ci } 146262306a36Sopenharmony_ci} 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_cistatic void free_subtest_state(struct subtest_state *state) 146562306a36Sopenharmony_ci{ 146662306a36Sopenharmony_ci if (state->log_buf) { 146762306a36Sopenharmony_ci free(state->log_buf); 146862306a36Sopenharmony_ci state->log_buf = NULL; 146962306a36Sopenharmony_ci state->log_cnt = 0; 147062306a36Sopenharmony_ci } 147162306a36Sopenharmony_ci free(state->name); 147262306a36Sopenharmony_ci state->name = NULL; 147362306a36Sopenharmony_ci} 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_cistatic int worker_main_send_subtests(int sock, struct test_state *state) 147662306a36Sopenharmony_ci{ 147762306a36Sopenharmony_ci int i, result = 0; 147862306a36Sopenharmony_ci struct msg msg; 147962306a36Sopenharmony_ci struct subtest_state *subtest_state; 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci memset(&msg, 0, sizeof(msg)); 148262306a36Sopenharmony_ci msg.type = MSG_SUBTEST_DONE; 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci for (i = 0; i < state->subtest_num; i++) { 148562306a36Sopenharmony_ci subtest_state = &state->subtest_states[i]; 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci msg.subtest_done.num = i; 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci strncpy(msg.subtest_done.name, subtest_state->name, MAX_SUBTEST_NAME); 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci msg.subtest_done.error_cnt = subtest_state->error_cnt; 149262306a36Sopenharmony_ci msg.subtest_done.skipped = subtest_state->skipped; 149362306a36Sopenharmony_ci msg.subtest_done.filtered = subtest_state->filtered; 149462306a36Sopenharmony_ci msg.subtest_done.have_log = false; 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci if (verbose() || state->force_log || subtest_state->error_cnt) { 149762306a36Sopenharmony_ci if (subtest_state->log_cnt) 149862306a36Sopenharmony_ci msg.subtest_done.have_log = true; 149962306a36Sopenharmony_ci } 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci if (send_message(sock, &msg) < 0) { 150262306a36Sopenharmony_ci perror("Fail to send message done"); 150362306a36Sopenharmony_ci result = 1; 150462306a36Sopenharmony_ci goto out; 150562306a36Sopenharmony_ci } 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci /* send logs */ 150862306a36Sopenharmony_ci if (msg.subtest_done.have_log) 150962306a36Sopenharmony_ci worker_main_send_log(sock, subtest_state->log_buf, subtest_state->log_cnt); 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci free_subtest_state(subtest_state); 151262306a36Sopenharmony_ci free(subtest_state->name); 151362306a36Sopenharmony_ci } 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ciout: 151662306a36Sopenharmony_ci for (; i < state->subtest_num; i++) 151762306a36Sopenharmony_ci free_subtest_state(&state->subtest_states[i]); 151862306a36Sopenharmony_ci free(state->subtest_states); 151962306a36Sopenharmony_ci return result; 152062306a36Sopenharmony_ci} 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_cistatic int worker_main(int sock) 152362306a36Sopenharmony_ci{ 152462306a36Sopenharmony_ci save_netns(); 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci while (true) { 152762306a36Sopenharmony_ci /* receive command */ 152862306a36Sopenharmony_ci struct msg msg; 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci if (recv_message(sock, &msg) < 0) 153162306a36Sopenharmony_ci goto out; 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci switch (msg.type) { 153462306a36Sopenharmony_ci case MSG_EXIT: 153562306a36Sopenharmony_ci if (env.debug) 153662306a36Sopenharmony_ci fprintf(stderr, "[%d]: worker exit.\n", 153762306a36Sopenharmony_ci env.worker_id); 153862306a36Sopenharmony_ci goto out; 153962306a36Sopenharmony_ci case MSG_DO_TEST: { 154062306a36Sopenharmony_ci int test_to_run = msg.do_test.num; 154162306a36Sopenharmony_ci struct prog_test_def *test = &prog_test_defs[test_to_run]; 154262306a36Sopenharmony_ci struct test_state *state = &test_states[test_to_run]; 154362306a36Sopenharmony_ci struct msg msg; 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci if (env.debug) 154662306a36Sopenharmony_ci fprintf(stderr, "[%d]: #%d:%s running.\n", 154762306a36Sopenharmony_ci env.worker_id, 154862306a36Sopenharmony_ci test_to_run + 1, 154962306a36Sopenharmony_ci test->test_name); 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci run_one_test(test_to_run); 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci memset(&msg, 0, sizeof(msg)); 155462306a36Sopenharmony_ci msg.type = MSG_TEST_DONE; 155562306a36Sopenharmony_ci msg.test_done.num = test_to_run; 155662306a36Sopenharmony_ci msg.test_done.error_cnt = state->error_cnt; 155762306a36Sopenharmony_ci msg.test_done.skip_cnt = state->skip_cnt; 155862306a36Sopenharmony_ci msg.test_done.sub_succ_cnt = state->sub_succ_cnt; 155962306a36Sopenharmony_ci msg.test_done.subtest_num = state->subtest_num; 156062306a36Sopenharmony_ci msg.test_done.have_log = false; 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci if (verbose() || state->force_log || state->error_cnt) { 156362306a36Sopenharmony_ci if (state->log_cnt) 156462306a36Sopenharmony_ci msg.test_done.have_log = true; 156562306a36Sopenharmony_ci } 156662306a36Sopenharmony_ci if (send_message(sock, &msg) < 0) { 156762306a36Sopenharmony_ci perror("Fail to send message done"); 156862306a36Sopenharmony_ci goto out; 156962306a36Sopenharmony_ci } 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci /* send logs */ 157262306a36Sopenharmony_ci if (msg.test_done.have_log) 157362306a36Sopenharmony_ci worker_main_send_log(sock, state->log_buf, state->log_cnt); 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci if (state->log_buf) { 157662306a36Sopenharmony_ci free(state->log_buf); 157762306a36Sopenharmony_ci state->log_buf = NULL; 157862306a36Sopenharmony_ci state->log_cnt = 0; 157962306a36Sopenharmony_ci } 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci if (state->subtest_num) 158262306a36Sopenharmony_ci if (worker_main_send_subtests(sock, state)) 158362306a36Sopenharmony_ci goto out; 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci if (env.debug) 158662306a36Sopenharmony_ci fprintf(stderr, "[%d]: #%d:%s done.\n", 158762306a36Sopenharmony_ci env.worker_id, 158862306a36Sopenharmony_ci test_to_run + 1, 158962306a36Sopenharmony_ci test->test_name); 159062306a36Sopenharmony_ci break; 159162306a36Sopenharmony_ci } /* case MSG_DO_TEST */ 159262306a36Sopenharmony_ci default: 159362306a36Sopenharmony_ci if (env.debug) 159462306a36Sopenharmony_ci fprintf(stderr, "[%d]: unknown message.\n", env.worker_id); 159562306a36Sopenharmony_ci return -1; 159662306a36Sopenharmony_ci } 159762306a36Sopenharmony_ci } 159862306a36Sopenharmony_ciout: 159962306a36Sopenharmony_ci return 0; 160062306a36Sopenharmony_ci} 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_cistatic void free_test_states(void) 160362306a36Sopenharmony_ci{ 160462306a36Sopenharmony_ci int i, j; 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(prog_test_defs); i++) { 160762306a36Sopenharmony_ci struct test_state *test_state = &test_states[i]; 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci for (j = 0; j < test_state->subtest_num; j++) 161062306a36Sopenharmony_ci free_subtest_state(&test_state->subtest_states[j]); 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci free(test_state->subtest_states); 161362306a36Sopenharmony_ci free(test_state->log_buf); 161462306a36Sopenharmony_ci test_state->subtest_states = NULL; 161562306a36Sopenharmony_ci test_state->log_buf = NULL; 161662306a36Sopenharmony_ci } 161762306a36Sopenharmony_ci} 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ciint main(int argc, char **argv) 162062306a36Sopenharmony_ci{ 162162306a36Sopenharmony_ci static const struct argp argp = { 162262306a36Sopenharmony_ci .options = opts, 162362306a36Sopenharmony_ci .parser = parse_arg, 162462306a36Sopenharmony_ci .doc = argp_program_doc, 162562306a36Sopenharmony_ci }; 162662306a36Sopenharmony_ci struct sigaction sigact = { 162762306a36Sopenharmony_ci .sa_handler = crash_handler, 162862306a36Sopenharmony_ci .sa_flags = SA_RESETHAND, 162962306a36Sopenharmony_ci }; 163062306a36Sopenharmony_ci int err, i; 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci sigaction(SIGSEGV, &sigact, NULL); 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci err = argp_parse(&argp, argc, argv, 0, NULL, &env); 163562306a36Sopenharmony_ci if (err) 163662306a36Sopenharmony_ci return err; 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci err = cd_flavor_subdir(argv[0]); 163962306a36Sopenharmony_ci if (err) 164062306a36Sopenharmony_ci return err; 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci /* Use libbpf 1.0 API mode */ 164362306a36Sopenharmony_ci libbpf_set_strict_mode(LIBBPF_STRICT_ALL); 164462306a36Sopenharmony_ci libbpf_set_print(libbpf_print_fn); 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci srand(time(NULL)); 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci env.jit_enabled = is_jit_enabled(); 164962306a36Sopenharmony_ci env.nr_cpus = libbpf_num_possible_cpus(); 165062306a36Sopenharmony_ci if (env.nr_cpus < 0) { 165162306a36Sopenharmony_ci fprintf(stderr, "Failed to get number of CPUs: %d!\n", 165262306a36Sopenharmony_ci env.nr_cpus); 165362306a36Sopenharmony_ci return -1; 165462306a36Sopenharmony_ci } 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci env.stdout = stdout; 165762306a36Sopenharmony_ci env.stderr = stderr; 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci env.has_testmod = true; 166062306a36Sopenharmony_ci if (!env.list_test_names) { 166162306a36Sopenharmony_ci /* ensure previous instance of the module is unloaded */ 166262306a36Sopenharmony_ci unload_bpf_testmod(verbose()); 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci if (load_bpf_testmod(verbose())) { 166562306a36Sopenharmony_ci fprintf(env.stderr, "WARNING! Selftests relying on bpf_testmod.ko will be skipped.\n"); 166662306a36Sopenharmony_ci env.has_testmod = false; 166762306a36Sopenharmony_ci } 166862306a36Sopenharmony_ci } 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci /* initializing tests */ 167162306a36Sopenharmony_ci for (i = 0; i < prog_test_cnt; i++) { 167262306a36Sopenharmony_ci struct prog_test_def *test = &prog_test_defs[i]; 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci test->test_num = i + 1; 167562306a36Sopenharmony_ci test->should_run = should_run(&env.test_selector, 167662306a36Sopenharmony_ci test->test_num, test->test_name); 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci if ((test->run_test == NULL && test->run_serial_test == NULL) || 167962306a36Sopenharmony_ci (test->run_test != NULL && test->run_serial_test != NULL)) { 168062306a36Sopenharmony_ci fprintf(stderr, "Test %d:%s must have either test_%s() or serial_test_%sl() defined.\n", 168162306a36Sopenharmony_ci test->test_num, test->test_name, test->test_name, test->test_name); 168262306a36Sopenharmony_ci exit(EXIT_ERR_SETUP_INFRA); 168362306a36Sopenharmony_ci } 168462306a36Sopenharmony_ci } 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci /* ignore workers if we are just listing */ 168762306a36Sopenharmony_ci if (env.get_test_cnt || env.list_test_names) 168862306a36Sopenharmony_ci env.workers = 0; 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci /* launch workers if requested */ 169162306a36Sopenharmony_ci env.worker_id = -1; /* main process */ 169262306a36Sopenharmony_ci if (env.workers) { 169362306a36Sopenharmony_ci env.worker_pids = calloc(sizeof(__pid_t), env.workers); 169462306a36Sopenharmony_ci env.worker_socks = calloc(sizeof(int), env.workers); 169562306a36Sopenharmony_ci if (env.debug) 169662306a36Sopenharmony_ci fprintf(stdout, "Launching %d workers.\n", env.workers); 169762306a36Sopenharmony_ci for (i = 0; i < env.workers; i++) { 169862306a36Sopenharmony_ci int sv[2]; 169962306a36Sopenharmony_ci pid_t pid; 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv) < 0) { 170262306a36Sopenharmony_ci perror("Fail to create worker socket"); 170362306a36Sopenharmony_ci return -1; 170462306a36Sopenharmony_ci } 170562306a36Sopenharmony_ci pid = fork(); 170662306a36Sopenharmony_ci if (pid < 0) { 170762306a36Sopenharmony_ci perror("Failed to fork worker"); 170862306a36Sopenharmony_ci return -1; 170962306a36Sopenharmony_ci } else if (pid != 0) { /* main process */ 171062306a36Sopenharmony_ci close(sv[1]); 171162306a36Sopenharmony_ci env.worker_pids[i] = pid; 171262306a36Sopenharmony_ci env.worker_socks[i] = sv[0]; 171362306a36Sopenharmony_ci } else { /* inside each worker process */ 171462306a36Sopenharmony_ci close(sv[0]); 171562306a36Sopenharmony_ci env.worker_id = i; 171662306a36Sopenharmony_ci return worker_main(sv[1]); 171762306a36Sopenharmony_ci } 171862306a36Sopenharmony_ci } 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci if (env.worker_id == -1) { 172162306a36Sopenharmony_ci server_main(); 172262306a36Sopenharmony_ci goto out; 172362306a36Sopenharmony_ci } 172462306a36Sopenharmony_ci } 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci /* The rest of the main process */ 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci /* on single mode */ 172962306a36Sopenharmony_ci save_netns(); 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci for (i = 0; i < prog_test_cnt; i++) { 173262306a36Sopenharmony_ci struct prog_test_def *test = &prog_test_defs[i]; 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_ci if (!test->should_run) 173562306a36Sopenharmony_ci continue; 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci if (env.get_test_cnt) { 173862306a36Sopenharmony_ci env.succ_cnt++; 173962306a36Sopenharmony_ci continue; 174062306a36Sopenharmony_ci } 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci if (env.list_test_names) { 174362306a36Sopenharmony_ci fprintf(env.stdout, "%s\n", test->test_name); 174462306a36Sopenharmony_ci env.succ_cnt++; 174562306a36Sopenharmony_ci continue; 174662306a36Sopenharmony_ci } 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci run_one_test(i); 174962306a36Sopenharmony_ci } 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci if (env.get_test_cnt) { 175262306a36Sopenharmony_ci printf("%d\n", env.succ_cnt); 175362306a36Sopenharmony_ci goto out; 175462306a36Sopenharmony_ci } 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_ci if (env.list_test_names) 175762306a36Sopenharmony_ci goto out; 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci calculate_summary_and_print_errors(&env); 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci close(env.saved_netns_fd); 176262306a36Sopenharmony_ciout: 176362306a36Sopenharmony_ci if (!env.list_test_names && env.has_testmod) 176462306a36Sopenharmony_ci unload_bpf_testmod(verbose()); 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_ci free_test_selector(&env.test_selector); 176762306a36Sopenharmony_ci free_test_selector(&env.subtest_selector); 176862306a36Sopenharmony_ci free_test_states(); 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci if (env.succ_cnt + env.fail_cnt + env.skip_cnt == 0) 177162306a36Sopenharmony_ci return EXIT_NO_TEST; 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci return env.fail_cnt ? EXIT_FAILURE : EXIT_SUCCESS; 177462306a36Sopenharmony_ci} 1775