File Index
Files and directories
Sign in
FILE

setup.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/net/tcp_ao/lib/setup.c C
  1// SPDX-License-Identifier: GPL-2.0
  2#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 which
 10 * 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	else
282		exit(KSFT_PASS);
283}
284
285/* /proc/sys/net/core/optmem_max artifically limits the amount of memory
286 * 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 test
288 * 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 that
290 * 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_max
294 * 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}
~/ Read-only file preview.