brintos

brintos / linux-shallow public Read only

0
0
Text · 8.2 KiB · a27cc03 Raw
369 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <fcntl.h>3#include <pthread.h>4#include <sched.h>5#include <signal.h>6#include "aolib.h"7 8/*9 * Can't be included in the header: it defines static variables which10 * will be unique to every object. Let's include it only once here.11 */12#include "../../../kselftest.h"13 14/* Prevent overriding of one thread's output by another */15static pthread_mutex_t ksft_print_lock = PTHREAD_MUTEX_INITIALIZER;16 17void __test_msg(const char *buf)18{19	pthread_mutex_lock(&ksft_print_lock);20	ksft_print_msg("%s", buf);21	pthread_mutex_unlock(&ksft_print_lock);22}23void __test_ok(const char *buf)24{25	pthread_mutex_lock(&ksft_print_lock);26	ksft_test_result_pass("%s", buf);27	pthread_mutex_unlock(&ksft_print_lock);28}29void __test_fail(const char *buf)30{31	pthread_mutex_lock(&ksft_print_lock);32	ksft_test_result_fail("%s", buf);33	pthread_mutex_unlock(&ksft_print_lock);34}35void __test_xfail(const char *buf)36{37	pthread_mutex_lock(&ksft_print_lock);38	ksft_test_result_xfail("%s", buf);39	pthread_mutex_unlock(&ksft_print_lock);40}41void __test_error(const char *buf)42{43	pthread_mutex_lock(&ksft_print_lock);44	ksft_test_result_error("%s", buf);45	pthread_mutex_unlock(&ksft_print_lock);46}47void __test_skip(const char *buf)48{49	pthread_mutex_lock(&ksft_print_lock);50	ksft_test_result_skip("%s", buf);51	pthread_mutex_unlock(&ksft_print_lock);52}53 54static volatile int failed;55static volatile int skipped;56 57void test_failed(void)58{59	failed = 1;60}61 62static void test_exit(void)63{64	if (failed) {65		ksft_exit_fail();66	} else if (skipped) {67		/* ksft_exit_skip() is different from ksft_exit_*() */68		ksft_print_cnts();69		exit(KSFT_SKIP);70	} else {71		ksft_exit_pass();72	}73}74 75struct dlist_t {76	void (*destruct)(void);77	struct dlist_t *next;78};79static struct dlist_t *destructors_list;80 81void test_add_destructor(void (*d)(void))82{83	struct dlist_t *p;84 85	p = malloc(sizeof(struct dlist_t));86	if (p == NULL)87		test_error("malloc() failed");88 89	p->next = destructors_list;90	p->destruct = d;91	destructors_list = p;92}93 94static void test_destructor(void) __attribute__((destructor));95static void test_destructor(void)96{97	while (destructors_list) {98		struct dlist_t *p = destructors_list->next;99 100		destructors_list->destruct();101		free(destructors_list);102		destructors_list = p;103	}104	test_exit();105}106 107static void sig_int(int signo)108{109	test_error("Caught SIGINT - exiting");110}111 112int open_netns(void)113{114	const char *netns_path = "/proc/thread-self/ns/net";115	int fd;116 117	fd = open(netns_path, O_RDONLY);118	if (fd < 0)119		test_error("open(%s)", netns_path);120	return fd;121}122 123int unshare_open_netns(void)124{125	if (unshare(CLONE_NEWNET) != 0)126		test_error("unshare()");127 128	return open_netns();129}130 131void switch_ns(int fd)132{133	if (setns(fd, CLONE_NEWNET))134		test_error("setns()");135}136 137int switch_save_ns(int new_ns)138{139	int ret = open_netns();140 141	switch_ns(new_ns);142	return ret;143}144 145void switch_close_ns(int fd)146{147	if (setns(fd, CLONE_NEWNET))148		test_error("setns()");149	close(fd);150}151 152static int nsfd_outside	= -1;153static int nsfd_parent	= -1;154static int nsfd_child	= -1;155const char veth_name[]	= "ktst-veth";156 157static void init_namespaces(void)158{159	nsfd_outside = open_netns();160	nsfd_parent = unshare_open_netns();161	nsfd_child = unshare_open_netns();162}163 164static void link_init(const char *veth, int family, uint8_t prefix,165		      union tcp_addr addr, union tcp_addr dest)166{167	if (link_set_up(veth))168		test_error("Failed to set link up");169	if (ip_addr_add(veth, family, addr, prefix))170		test_error("Failed to add ip address");171	if (ip_route_add(veth, family, addr, dest))172		test_error("Failed to add route");173}174 175static unsigned int nr_threads = 1;176 177static pthread_mutex_t sync_lock = PTHREAD_MUTEX_INITIALIZER;178static pthread_cond_t sync_cond = PTHREAD_COND_INITIALIZER;179static volatile unsigned int stage_threads[2];180static volatile unsigned int stage_nr;181 182/* synchronize all threads in the same stage */183void synchronize_threads(void)184{185	unsigned int q = stage_nr;186 187	pthread_mutex_lock(&sync_lock);188	stage_threads[q]++;189	if (stage_threads[q] == nr_threads) {190		stage_nr ^= 1;191		stage_threads[stage_nr] = 0;192		pthread_cond_signal(&sync_cond);193	}194	while (stage_threads[q] < nr_threads)195		pthread_cond_wait(&sync_cond, &sync_lock);196	pthread_mutex_unlock(&sync_lock);197}198 199__thread union tcp_addr this_ip_addr;200__thread union tcp_addr this_ip_dest;201int test_family;202 203struct new_pthread_arg {204	thread_fn	func;205	union tcp_addr	my_ip;206	union tcp_addr	dest_ip;207};208static void *new_pthread_entry(void *arg)209{210	struct new_pthread_arg *p = arg;211 212	this_ip_addr = p->my_ip;213	this_ip_dest = p->dest_ip;214	p->func(NULL); /* shouldn't return */215	exit(KSFT_FAIL);216}217 218static void __test_skip_all(const char *msg)219{220	ksft_set_plan(1);221	ksft_print_header();222	skipped = 1;223	test_skip("%s", msg);224	exit(KSFT_SKIP);225}226 227void __test_init(unsigned int ntests, int family, unsigned int prefix,228		 union tcp_addr addr1, union tcp_addr addr2,229		 thread_fn peer1, thread_fn peer2)230{231	struct sigaction sa = {232		.sa_handler = sig_int,233		.sa_flags = SA_RESTART,234	};235	time_t seed = time(NULL);236 237	sigemptyset(&sa.sa_mask);238	if (sigaction(SIGINT, &sa, NULL))239		test_error("Can't set SIGINT handler");240 241	test_family = family;242	if (!kernel_config_has(KCONFIG_NET_NS))243		__test_skip_all(tests_skip_reason[KCONFIG_NET_NS]);244	if (!kernel_config_has(KCONFIG_VETH))245		__test_skip_all(tests_skip_reason[KCONFIG_VETH]);246	if (!kernel_config_has(KCONFIG_TCP_AO))247		__test_skip_all(tests_skip_reason[KCONFIG_TCP_AO]);248 249	ksft_set_plan(ntests);250	test_print("rand seed %u", (unsigned int)seed);251	srand(seed);252 253	ksft_print_header();254	init_namespaces();255	test_init_ftrace(nsfd_parent, nsfd_child);256 257	if (add_veth(veth_name, nsfd_parent, nsfd_child))258		test_error("Failed to add veth");259 260	switch_ns(nsfd_child);261	link_init(veth_name, family, prefix, addr2, addr1);262	if (peer2) {263		struct new_pthread_arg targ;264		pthread_t t;265 266		targ.my_ip = addr2;267		targ.dest_ip = addr1;268		targ.func = peer2;269		nr_threads++;270		if (pthread_create(&t, NULL, new_pthread_entry, &targ))271			test_error("Failed to create pthread");272	}273	switch_ns(nsfd_parent);274	link_init(veth_name, family, prefix, addr1, addr2);275 276	this_ip_addr = addr1;277	this_ip_dest = addr2;278	peer1(NULL);279	if (failed)280		exit(KSFT_FAIL);281	else282		exit(KSFT_PASS);283}284 285/* /proc/sys/net/core/optmem_max artifically limits the amount of memory286 * that can be allocated with sock_kmalloc() on each socket in the system.287 * It is not virtualized in v6.7, so it has to written outside test288 * namespaces. To be nice a test will revert optmem back to the old value.289 * Keeping it simple without any file lock, which means the tests that290 * need to set/increase optmem value shouldn't run in parallel.291 * Also, not re-entrant.292 * Since commit f5769faeec36 ("net: Namespace-ify sysctl_optmem_max")293 * it is per-namespace, keeping logic for non-virtualized optmem_max294 * for v6.7, which supports TCP-AO.295 */296static const char *optmem_file = "/proc/sys/net/core/optmem_max";297static size_t saved_optmem;298static int optmem_ns = -1;299 300static bool is_optmem_namespaced(void)301{302	if (optmem_ns == -1) {303		int old_ns = switch_save_ns(nsfd_child);304 305		optmem_ns = !access(optmem_file, F_OK);306		switch_close_ns(old_ns);307	}308	return !!optmem_ns;309}310 311size_t test_get_optmem(void)312{313	int old_ns = 0;314	FILE *foptmem;315	size_t ret;316 317	if (!is_optmem_namespaced())318		old_ns = switch_save_ns(nsfd_outside);319	foptmem = fopen(optmem_file, "r");320	if (!foptmem)321		test_error("failed to open %s", optmem_file);322 323	if (fscanf(foptmem, "%zu", &ret) != 1)324		test_error("can't read from %s", optmem_file);325	fclose(foptmem);326	if (!is_optmem_namespaced())327		switch_close_ns(old_ns);328	return ret;329}330 331static void __test_set_optmem(size_t new, size_t *old)332{333	int old_ns = 0;334	FILE *foptmem;335 336	if (old != NULL)337		*old = test_get_optmem();338 339	if (!is_optmem_namespaced())340		old_ns = switch_save_ns(nsfd_outside);341	foptmem = fopen(optmem_file, "w");342	if (!foptmem)343		test_error("failed to open %s", optmem_file);344 345	if (fprintf(foptmem, "%zu", new) <= 0)346		test_error("can't write %zu to %s", new, optmem_file);347	fclose(foptmem);348	if (!is_optmem_namespaced())349		switch_close_ns(old_ns);350}351 352static void test_revert_optmem(void)353{354	if (saved_optmem == 0)355		return;356 357	__test_set_optmem(saved_optmem, NULL);358}359 360void test_set_optmem(size_t value)361{362	if (saved_optmem == 0) {363		__test_set_optmem(value, &saved_optmem);364		test_add_destructor(test_revert_optmem);365	} else {366		__test_set_optmem(value, NULL);367	}368}369