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(&current_test_lock);
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci			if (current_test_idx >= prog_test_cnt) {
120162306a36Sopenharmony_ci				pthread_mutex_unlock(&current_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(&current_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