151a0e301SMartin KaFai Lau // SPDX-License-Identifier: GPL-2.0
251a0e301SMartin KaFai Lau /* Copyright (c) 2019 Facebook  */
351a0e301SMartin KaFai Lau #include <linux/compiler.h>
451a0e301SMartin KaFai Lau #include <linux/err.h>
551a0e301SMartin KaFai Lau 
651a0e301SMartin KaFai Lau #include <sys/resource.h>
751a0e301SMartin KaFai Lau #include <sys/socket.h>
851a0e301SMartin KaFai Lau #include <sys/types.h>
951a0e301SMartin KaFai Lau #include <linux/btf.h>
1051a0e301SMartin KaFai Lau #include <unistd.h>
1151a0e301SMartin KaFai Lau #include <signal.h>
1251a0e301SMartin KaFai Lau #include <errno.h>
1351a0e301SMartin KaFai Lau #include <string.h>
1451a0e301SMartin KaFai Lau #include <pthread.h>
1551a0e301SMartin KaFai Lau 
1651a0e301SMartin KaFai Lau #include <bpf/bpf.h>
1751a0e301SMartin KaFai Lau #include <bpf/libbpf.h>
1851a0e301SMartin KaFai Lau 
1951a0e301SMartin KaFai Lau #include <test_btf.h>
2051a0e301SMartin KaFai Lau #include <test_maps.h>
2151a0e301SMartin KaFai Lau 
2251a0e301SMartin KaFai Lau static struct bpf_create_map_attr xattr = {
2351a0e301SMartin KaFai Lau 	.name = "sk_storage_map",
2451a0e301SMartin KaFai Lau 	.map_type = BPF_MAP_TYPE_SK_STORAGE,
2551a0e301SMartin KaFai Lau 	.map_flags = BPF_F_NO_PREALLOC,
2651a0e301SMartin KaFai Lau 	.max_entries = 0,
2751a0e301SMartin KaFai Lau 	.key_size = 4,
2851a0e301SMartin KaFai Lau 	.value_size = 8,
2951a0e301SMartin KaFai Lau 	.btf_key_type_id = 1,
3051a0e301SMartin KaFai Lau 	.btf_value_type_id = 3,
3151a0e301SMartin KaFai Lau 	.btf_fd = -1,
3251a0e301SMartin KaFai Lau };
3351a0e301SMartin KaFai Lau 
3451a0e301SMartin KaFai Lau static unsigned int nr_sk_threads_done;
3551a0e301SMartin KaFai Lau static unsigned int nr_sk_threads_err;
3651a0e301SMartin KaFai Lau static unsigned int nr_sk_per_thread = 4096;
3751a0e301SMartin KaFai Lau static unsigned int nr_sk_threads = 4;
3851a0e301SMartin KaFai Lau static int sk_storage_map = -1;
3951a0e301SMartin KaFai Lau static unsigned int stop;
4051a0e301SMartin KaFai Lau static int runtime_s = 5;
4151a0e301SMartin KaFai Lau 
4251a0e301SMartin KaFai Lau static bool is_stopped(void)
4351a0e301SMartin KaFai Lau {
4451a0e301SMartin KaFai Lau 	return READ_ONCE(stop);
4551a0e301SMartin KaFai Lau }
4651a0e301SMartin KaFai Lau 
4751a0e301SMartin KaFai Lau static unsigned int threads_err(void)
4851a0e301SMartin KaFai Lau {
4951a0e301SMartin KaFai Lau 	return READ_ONCE(nr_sk_threads_err);
5051a0e301SMartin KaFai Lau }
5151a0e301SMartin KaFai Lau 
5251a0e301SMartin KaFai Lau static void notify_thread_err(void)
5351a0e301SMartin KaFai Lau {
5451a0e301SMartin KaFai Lau 	__sync_add_and_fetch(&nr_sk_threads_err, 1);
5551a0e301SMartin KaFai Lau }
5651a0e301SMartin KaFai Lau 
5751a0e301SMartin KaFai Lau static bool wait_for_threads_err(void)
5851a0e301SMartin KaFai Lau {
5951a0e301SMartin KaFai Lau 	while (!is_stopped() && !threads_err())
6051a0e301SMartin KaFai Lau 		usleep(500);
6151a0e301SMartin KaFai Lau 
6251a0e301SMartin KaFai Lau 	return !is_stopped();
6351a0e301SMartin KaFai Lau }
6451a0e301SMartin KaFai Lau 
6551a0e301SMartin KaFai Lau static unsigned int threads_done(void)
6651a0e301SMartin KaFai Lau {
6751a0e301SMartin KaFai Lau 	return READ_ONCE(nr_sk_threads_done);
6851a0e301SMartin KaFai Lau }
6951a0e301SMartin KaFai Lau 
7051a0e301SMartin KaFai Lau static void notify_thread_done(void)
7151a0e301SMartin KaFai Lau {
7251a0e301SMartin KaFai Lau 	__sync_add_and_fetch(&nr_sk_threads_done, 1);
7351a0e301SMartin KaFai Lau }
7451a0e301SMartin KaFai Lau 
7551a0e301SMartin KaFai Lau static void notify_thread_redo(void)
7651a0e301SMartin KaFai Lau {
7751a0e301SMartin KaFai Lau 	__sync_sub_and_fetch(&nr_sk_threads_done, 1);
7851a0e301SMartin KaFai Lau }
7951a0e301SMartin KaFai Lau 
8051a0e301SMartin KaFai Lau static bool wait_for_threads_done(void)
8151a0e301SMartin KaFai Lau {
8251a0e301SMartin KaFai Lau 	while (threads_done() != nr_sk_threads && !is_stopped() &&
8351a0e301SMartin KaFai Lau 	       !threads_err())
8451a0e301SMartin KaFai Lau 		usleep(50);
8551a0e301SMartin KaFai Lau 
8651a0e301SMartin KaFai Lau 	return !is_stopped() && !threads_err();
8751a0e301SMartin KaFai Lau }
8851a0e301SMartin KaFai Lau 
8951a0e301SMartin KaFai Lau static bool wait_for_threads_redo(void)
9051a0e301SMartin KaFai Lau {
9151a0e301SMartin KaFai Lau 	while (threads_done() && !is_stopped() && !threads_err())
9251a0e301SMartin KaFai Lau 		usleep(50);
9351a0e301SMartin KaFai Lau 
9451a0e301SMartin KaFai Lau 	return !is_stopped() && !threads_err();
9551a0e301SMartin KaFai Lau }
9651a0e301SMartin KaFai Lau 
9751a0e301SMartin KaFai Lau static bool wait_for_map(void)
9851a0e301SMartin KaFai Lau {
9951a0e301SMartin KaFai Lau 	while (READ_ONCE(sk_storage_map) == -1 && !is_stopped())
10051a0e301SMartin KaFai Lau 		usleep(50);
10151a0e301SMartin KaFai Lau 
10251a0e301SMartin KaFai Lau 	return !is_stopped();
10351a0e301SMartin KaFai Lau }
10451a0e301SMartin KaFai Lau 
10551a0e301SMartin KaFai Lau static bool wait_for_map_close(void)
10651a0e301SMartin KaFai Lau {
10751a0e301SMartin KaFai Lau 	while (READ_ONCE(sk_storage_map) != -1 && !is_stopped())
10851a0e301SMartin KaFai Lau 		;
10951a0e301SMartin KaFai Lau 
11051a0e301SMartin KaFai Lau 	return !is_stopped();
11151a0e301SMartin KaFai Lau }
11251a0e301SMartin KaFai Lau 
11351a0e301SMartin KaFai Lau static int load_btf(void)
11451a0e301SMartin KaFai Lau {
11551a0e301SMartin KaFai Lau 	const char btf_str_sec[] = "\0bpf_spin_lock\0val\0cnt\0l";
11651a0e301SMartin KaFai Lau 	__u32 btf_raw_types[] = {
11751a0e301SMartin KaFai Lau 		/* int */
11851a0e301SMartin KaFai Lau 		BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),  /* [1] */
11951a0e301SMartin KaFai Lau 		/* struct bpf_spin_lock */                      /* [2] */
12051a0e301SMartin KaFai Lau 		BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 1), 4),
12151a0e301SMartin KaFai Lau 		BTF_MEMBER_ENC(15, 1, 0), /* int val; */
12251a0e301SMartin KaFai Lau 		/* struct val */                                /* [3] */
12351a0e301SMartin KaFai Lau 		BTF_TYPE_ENC(15, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 2), 8),
12451a0e301SMartin KaFai Lau 		BTF_MEMBER_ENC(19, 1, 0), /* int cnt; */
12551a0e301SMartin KaFai Lau 		BTF_MEMBER_ENC(23, 2, 32),/* struct bpf_spin_lock l; */
12651a0e301SMartin KaFai Lau 	};
12751a0e301SMartin KaFai Lau 	struct btf_header btf_hdr = {
12851a0e301SMartin KaFai Lau 		.magic = BTF_MAGIC,
12951a0e301SMartin KaFai Lau 		.version = BTF_VERSION,
13051a0e301SMartin KaFai Lau 		.hdr_len = sizeof(struct btf_header),
13151a0e301SMartin KaFai Lau 		.type_len = sizeof(btf_raw_types),
13251a0e301SMartin KaFai Lau 		.str_off = sizeof(btf_raw_types),
13351a0e301SMartin KaFai Lau 		.str_len = sizeof(btf_str_sec),
13451a0e301SMartin KaFai Lau 	};
13551a0e301SMartin KaFai Lau 	__u8 raw_btf[sizeof(struct btf_header) + sizeof(btf_raw_types) +
13651a0e301SMartin KaFai Lau 		     sizeof(btf_str_sec)];
13751a0e301SMartin KaFai Lau 
13851a0e301SMartin KaFai Lau 	memcpy(raw_btf, &btf_hdr, sizeof(btf_hdr));
13951a0e301SMartin KaFai Lau 	memcpy(raw_btf + sizeof(btf_hdr), btf_raw_types, sizeof(btf_raw_types));
14051a0e301SMartin KaFai Lau 	memcpy(raw_btf + sizeof(btf_hdr) + sizeof(btf_raw_types),
14151a0e301SMartin KaFai Lau 	       btf_str_sec, sizeof(btf_str_sec));
14251a0e301SMartin KaFai Lau 
14351a0e301SMartin KaFai Lau 	return bpf_load_btf(raw_btf, sizeof(raw_btf), 0, 0, 0);
14451a0e301SMartin KaFai Lau }
14551a0e301SMartin KaFai Lau 
14651a0e301SMartin KaFai Lau static int create_sk_storage_map(void)
14751a0e301SMartin KaFai Lau {
14851a0e301SMartin KaFai Lau 	int btf_fd, map_fd;
14951a0e301SMartin KaFai Lau 
15051a0e301SMartin KaFai Lau 	btf_fd = load_btf();
15151a0e301SMartin KaFai Lau 	CHECK(btf_fd == -1, "bpf_load_btf", "btf_fd:%d errno:%d\n",
15251a0e301SMartin KaFai Lau 	      btf_fd, errno);
15351a0e301SMartin KaFai Lau 	xattr.btf_fd = btf_fd;
15451a0e301SMartin KaFai Lau 
15551a0e301SMartin KaFai Lau 	map_fd = bpf_create_map_xattr(&xattr);
15651a0e301SMartin KaFai Lau 	xattr.btf_fd = -1;
15751a0e301SMartin KaFai Lau 	close(btf_fd);
15851a0e301SMartin KaFai Lau 	CHECK(map_fd == -1,
15951a0e301SMartin KaFai Lau 	      "bpf_create_map_xattr()", "errno:%d\n", errno);
16051a0e301SMartin KaFai Lau 
16151a0e301SMartin KaFai Lau 	return map_fd;
16251a0e301SMartin KaFai Lau }
16351a0e301SMartin KaFai Lau 
16451a0e301SMartin KaFai Lau static void *insert_close_thread(void *arg)
16551a0e301SMartin KaFai Lau {
16651a0e301SMartin KaFai Lau 	struct {
16751a0e301SMartin KaFai Lau 		int cnt;
16851a0e301SMartin KaFai Lau 		int lock;
16951a0e301SMartin KaFai Lau 	} value = { .cnt = 0xeB9F, .lock = 0, };
17051a0e301SMartin KaFai Lau 	int i, map_fd, err, *sk_fds;
17151a0e301SMartin KaFai Lau 
17251a0e301SMartin KaFai Lau 	sk_fds = malloc(sizeof(*sk_fds) * nr_sk_per_thread);
17351a0e301SMartin KaFai Lau 	if (!sk_fds) {
17451a0e301SMartin KaFai Lau 		notify_thread_err();
17551a0e301SMartin KaFai Lau 		return ERR_PTR(-ENOMEM);
17651a0e301SMartin KaFai Lau 	}
17751a0e301SMartin KaFai Lau 
17851a0e301SMartin KaFai Lau 	for (i = 0; i < nr_sk_per_thread; i++)
17951a0e301SMartin KaFai Lau 		sk_fds[i] = -1;
18051a0e301SMartin KaFai Lau 
18151a0e301SMartin KaFai Lau 	while (!is_stopped()) {
18251a0e301SMartin KaFai Lau 		if (!wait_for_map())
18351a0e301SMartin KaFai Lau 			goto close_all;
18451a0e301SMartin KaFai Lau 
18551a0e301SMartin KaFai Lau 		map_fd = READ_ONCE(sk_storage_map);
18651a0e301SMartin KaFai Lau 		for (i = 0; i < nr_sk_per_thread && !is_stopped(); i++) {
18751a0e301SMartin KaFai Lau 			sk_fds[i] = socket(AF_INET6, SOCK_STREAM, 0);
18851a0e301SMartin KaFai Lau 			if (sk_fds[i] == -1) {
18951a0e301SMartin KaFai Lau 				err = -errno;
19051a0e301SMartin KaFai Lau 				fprintf(stderr, "socket(): errno:%d\n", errno);
19151a0e301SMartin KaFai Lau 				goto errout;
19251a0e301SMartin KaFai Lau 			}
19351a0e301SMartin KaFai Lau 			err = bpf_map_update_elem(map_fd, &sk_fds[i], &value,
19451a0e301SMartin KaFai Lau 						  BPF_NOEXIST);
19551a0e301SMartin KaFai Lau 			if (err) {
19651a0e301SMartin KaFai Lau 				err = -errno;
19751a0e301SMartin KaFai Lau 				fprintf(stderr,
19851a0e301SMartin KaFai Lau 					"bpf_map_update_elem(): errno:%d\n",
19951a0e301SMartin KaFai Lau 					errno);
20051a0e301SMartin KaFai Lau 				goto errout;
20151a0e301SMartin KaFai Lau 			}
20251a0e301SMartin KaFai Lau 		}
20351a0e301SMartin KaFai Lau 
20451a0e301SMartin KaFai Lau 		notify_thread_done();
20551a0e301SMartin KaFai Lau 		wait_for_map_close();
20651a0e301SMartin KaFai Lau 
20751a0e301SMartin KaFai Lau close_all:
20851a0e301SMartin KaFai Lau 		for (i = 0; i < nr_sk_per_thread; i++) {
20951a0e301SMartin KaFai Lau 			close(sk_fds[i]);
21051a0e301SMartin KaFai Lau 			sk_fds[i] = -1;
21151a0e301SMartin KaFai Lau 		}
21251a0e301SMartin KaFai Lau 
21351a0e301SMartin KaFai Lau 		notify_thread_redo();
21451a0e301SMartin KaFai Lau 	}
21551a0e301SMartin KaFai Lau 
21651a0e301SMartin KaFai Lau 	free(sk_fds);
21751a0e301SMartin KaFai Lau 	return NULL;
21851a0e301SMartin KaFai Lau 
21951a0e301SMartin KaFai Lau errout:
22051a0e301SMartin KaFai Lau 	for (i = 0; i < nr_sk_per_thread && sk_fds[i] != -1; i++)
22151a0e301SMartin KaFai Lau 		close(sk_fds[i]);
22251a0e301SMartin KaFai Lau 	free(sk_fds);
22351a0e301SMartin KaFai Lau 	notify_thread_err();
22451a0e301SMartin KaFai Lau 	return ERR_PTR(err);
22551a0e301SMartin KaFai Lau }
22651a0e301SMartin KaFai Lau 
22751a0e301SMartin KaFai Lau static int do_sk_storage_map_stress_free(void)
22851a0e301SMartin KaFai Lau {
22951a0e301SMartin KaFai Lau 	int i, map_fd = -1, err = 0, nr_threads_created = 0;
23051a0e301SMartin KaFai Lau 	pthread_t *sk_thread_ids;
23151a0e301SMartin KaFai Lau 	void *thread_ret;
23251a0e301SMartin KaFai Lau 
23351a0e301SMartin KaFai Lau 	sk_thread_ids = malloc(sizeof(pthread_t) * nr_sk_threads);
23451a0e301SMartin KaFai Lau 	if (!sk_thread_ids) {
23551a0e301SMartin KaFai Lau 		fprintf(stderr, "malloc(sk_threads): NULL\n");
23651a0e301SMartin KaFai Lau 		return -ENOMEM;
23751a0e301SMartin KaFai Lau 	}
23851a0e301SMartin KaFai Lau 
23951a0e301SMartin KaFai Lau 	for (i = 0; i < nr_sk_threads; i++) {
24051a0e301SMartin KaFai Lau 		err = pthread_create(&sk_thread_ids[i], NULL,
24151a0e301SMartin KaFai Lau 				     insert_close_thread, NULL);
24251a0e301SMartin KaFai Lau 		if (err) {
24351a0e301SMartin KaFai Lau 			err = -errno;
24451a0e301SMartin KaFai Lau 			goto done;
24551a0e301SMartin KaFai Lau 		}
24651a0e301SMartin KaFai Lau 		nr_threads_created++;
24751a0e301SMartin KaFai Lau 	}
24851a0e301SMartin KaFai Lau 
24951a0e301SMartin KaFai Lau 	while (!is_stopped()) {
25051a0e301SMartin KaFai Lau 		map_fd = create_sk_storage_map();
25151a0e301SMartin KaFai Lau 		WRITE_ONCE(sk_storage_map, map_fd);
25251a0e301SMartin KaFai Lau 
25351a0e301SMartin KaFai Lau 		if (!wait_for_threads_done())
25451a0e301SMartin KaFai Lau 			break;
25551a0e301SMartin KaFai Lau 
25651a0e301SMartin KaFai Lau 		WRITE_ONCE(sk_storage_map, -1);
25751a0e301SMartin KaFai Lau 		close(map_fd);
25851a0e301SMartin KaFai Lau 		map_fd = -1;
25951a0e301SMartin KaFai Lau 
26051a0e301SMartin KaFai Lau 		if (!wait_for_threads_redo())
26151a0e301SMartin KaFai Lau 			break;
26251a0e301SMartin KaFai Lau 	}
26351a0e301SMartin KaFai Lau 
26451a0e301SMartin KaFai Lau done:
26551a0e301SMartin KaFai Lau 	WRITE_ONCE(stop, 1);
26651a0e301SMartin KaFai Lau 	for (i = 0; i < nr_threads_created; i++) {
26751a0e301SMartin KaFai Lau 		pthread_join(sk_thread_ids[i], &thread_ret);
26851a0e301SMartin KaFai Lau 		if (IS_ERR(thread_ret) && !err) {
26951a0e301SMartin KaFai Lau 			err = PTR_ERR(thread_ret);
27051a0e301SMartin KaFai Lau 			fprintf(stderr, "threads#%u: err:%d\n", i, err);
27151a0e301SMartin KaFai Lau 		}
27251a0e301SMartin KaFai Lau 	}
27351a0e301SMartin KaFai Lau 	free(sk_thread_ids);
27451a0e301SMartin KaFai Lau 
27551a0e301SMartin KaFai Lau 	if (map_fd != -1)
27651a0e301SMartin KaFai Lau 		close(map_fd);
27751a0e301SMartin KaFai Lau 
27851a0e301SMartin KaFai Lau 	return err;
27951a0e301SMartin KaFai Lau }
28051a0e301SMartin KaFai Lau 
28151a0e301SMartin KaFai Lau static void *update_thread(void *arg)
28251a0e301SMartin KaFai Lau {
28351a0e301SMartin KaFai Lau 	struct {
28451a0e301SMartin KaFai Lau 		int cnt;
28551a0e301SMartin KaFai Lau 		int lock;
28651a0e301SMartin KaFai Lau 	} value = { .cnt = 0xeB9F, .lock = 0, };
28751a0e301SMartin KaFai Lau 	int map_fd = READ_ONCE(sk_storage_map);
28851a0e301SMartin KaFai Lau 	int sk_fd = *(int *)arg;
28951a0e301SMartin KaFai Lau 	int err = 0; /* Suppress compiler false alarm */
29051a0e301SMartin KaFai Lau 
29151a0e301SMartin KaFai Lau 	while (!is_stopped()) {
29251a0e301SMartin KaFai Lau 		err = bpf_map_update_elem(map_fd, &sk_fd, &value, 0);
29351a0e301SMartin KaFai Lau 		if (err && errno != EAGAIN) {
29451a0e301SMartin KaFai Lau 			err = -errno;
29551a0e301SMartin KaFai Lau 			fprintf(stderr, "bpf_map_update_elem: %d %d\n",
29651a0e301SMartin KaFai Lau 				err, errno);
29751a0e301SMartin KaFai Lau 			break;
29851a0e301SMartin KaFai Lau 		}
29951a0e301SMartin KaFai Lau 	}
30051a0e301SMartin KaFai Lau 
30151a0e301SMartin KaFai Lau 	if (!is_stopped()) {
30251a0e301SMartin KaFai Lau 		notify_thread_err();
30351a0e301SMartin KaFai Lau 		return ERR_PTR(err);
30451a0e301SMartin KaFai Lau 	}
30551a0e301SMartin KaFai Lau 
30651a0e301SMartin KaFai Lau 	return NULL;
30751a0e301SMartin KaFai Lau }
30851a0e301SMartin KaFai Lau 
30951a0e301SMartin KaFai Lau static void *delete_thread(void *arg)
31051a0e301SMartin KaFai Lau {
31151a0e301SMartin KaFai Lau 	int map_fd = READ_ONCE(sk_storage_map);
31251a0e301SMartin KaFai Lau 	int sk_fd = *(int *)arg;
31351a0e301SMartin KaFai Lau 	int err = 0; /* Suppress compiler false alarm */
31451a0e301SMartin KaFai Lau 
31551a0e301SMartin KaFai Lau 	while (!is_stopped()) {
31651a0e301SMartin KaFai Lau 		err = bpf_map_delete_elem(map_fd, &sk_fd);
31751a0e301SMartin KaFai Lau 		if (err && errno != ENOENT) {
31851a0e301SMartin KaFai Lau 			err = -errno;
31951a0e301SMartin KaFai Lau 			fprintf(stderr, "bpf_map_delete_elem: %d %d\n",
32051a0e301SMartin KaFai Lau 				err, errno);
32151a0e301SMartin KaFai Lau 			break;
32251a0e301SMartin KaFai Lau 		}
32351a0e301SMartin KaFai Lau 	}
32451a0e301SMartin KaFai Lau 
32551a0e301SMartin KaFai Lau 	if (!is_stopped()) {
32651a0e301SMartin KaFai Lau 		notify_thread_err();
32751a0e301SMartin KaFai Lau 		return ERR_PTR(err);
32851a0e301SMartin KaFai Lau 	}
32951a0e301SMartin KaFai Lau 
33051a0e301SMartin KaFai Lau 	return NULL;
33151a0e301SMartin KaFai Lau }
33251a0e301SMartin KaFai Lau 
33351a0e301SMartin KaFai Lau static int do_sk_storage_map_stress_change(void)
33451a0e301SMartin KaFai Lau {
33551a0e301SMartin KaFai Lau 	int i, sk_fd, map_fd = -1, err = 0, nr_threads_created = 0;
33651a0e301SMartin KaFai Lau 	pthread_t *sk_thread_ids;
33751a0e301SMartin KaFai Lau 	void *thread_ret;
33851a0e301SMartin KaFai Lau 
33951a0e301SMartin KaFai Lau 	sk_thread_ids = malloc(sizeof(pthread_t) * nr_sk_threads);
34051a0e301SMartin KaFai Lau 	if (!sk_thread_ids) {
34151a0e301SMartin KaFai Lau 		fprintf(stderr, "malloc(sk_threads): NULL\n");
34251a0e301SMartin KaFai Lau 		return -ENOMEM;
34351a0e301SMartin KaFai Lau 	}
34451a0e301SMartin KaFai Lau 
34551a0e301SMartin KaFai Lau 	sk_fd = socket(AF_INET6, SOCK_STREAM, 0);
34651a0e301SMartin KaFai Lau 	if (sk_fd == -1) {
34751a0e301SMartin KaFai Lau 		err = -errno;
34851a0e301SMartin KaFai Lau 		goto done;
34951a0e301SMartin KaFai Lau 	}
35051a0e301SMartin KaFai Lau 
35151a0e301SMartin KaFai Lau 	map_fd = create_sk_storage_map();
35251a0e301SMartin KaFai Lau 	WRITE_ONCE(sk_storage_map, map_fd);
35351a0e301SMartin KaFai Lau 
35451a0e301SMartin KaFai Lau 	for (i = 0; i < nr_sk_threads; i++) {
35551a0e301SMartin KaFai Lau 		if (i & 0x1)
35651a0e301SMartin KaFai Lau 			err = pthread_create(&sk_thread_ids[i], NULL,
35751a0e301SMartin KaFai Lau 					     update_thread, &sk_fd);
35851a0e301SMartin KaFai Lau 		else
35951a0e301SMartin KaFai Lau 			err = pthread_create(&sk_thread_ids[i], NULL,
36051a0e301SMartin KaFai Lau 					     delete_thread, &sk_fd);
36151a0e301SMartin KaFai Lau 		if (err) {
36251a0e301SMartin KaFai Lau 			err = -errno;
36351a0e301SMartin KaFai Lau 			goto done;
36451a0e301SMartin KaFai Lau 		}
36551a0e301SMartin KaFai Lau 		nr_threads_created++;
36651a0e301SMartin KaFai Lau 	}
36751a0e301SMartin KaFai Lau 
36851a0e301SMartin KaFai Lau 	wait_for_threads_err();
36951a0e301SMartin KaFai Lau 
37051a0e301SMartin KaFai Lau done:
37151a0e301SMartin KaFai Lau 	WRITE_ONCE(stop, 1);
37251a0e301SMartin KaFai Lau 	for (i = 0; i < nr_threads_created; i++) {
37351a0e301SMartin KaFai Lau 		pthread_join(sk_thread_ids[i], &thread_ret);
37451a0e301SMartin KaFai Lau 		if (IS_ERR(thread_ret) && !err) {
37551a0e301SMartin KaFai Lau 			err = PTR_ERR(thread_ret);
37651a0e301SMartin KaFai Lau 			fprintf(stderr, "threads#%u: err:%d\n", i, err);
37751a0e301SMartin KaFai Lau 		}
37851a0e301SMartin KaFai Lau 	}
37951a0e301SMartin KaFai Lau 	free(sk_thread_ids);
38051a0e301SMartin KaFai Lau 
38151a0e301SMartin KaFai Lau 	if (sk_fd != -1)
38251a0e301SMartin KaFai Lau 		close(sk_fd);
38351a0e301SMartin KaFai Lau 	close(map_fd);
38451a0e301SMartin KaFai Lau 
38551a0e301SMartin KaFai Lau 	return err;
38651a0e301SMartin KaFai Lau }
38751a0e301SMartin KaFai Lau 
38851a0e301SMartin KaFai Lau static void stop_handler(int signum)
38951a0e301SMartin KaFai Lau {
39051a0e301SMartin KaFai Lau 	if (signum != SIGALRM)
39151a0e301SMartin KaFai Lau 		printf("stopping...\n");
39251a0e301SMartin KaFai Lau 	WRITE_ONCE(stop, 1);
39351a0e301SMartin KaFai Lau }
39451a0e301SMartin KaFai Lau 
39551a0e301SMartin KaFai Lau #define BPF_SK_STORAGE_MAP_TEST_NR_THREADS "BPF_SK_STORAGE_MAP_TEST_NR_THREADS"
39651a0e301SMartin KaFai Lau #define BPF_SK_STORAGE_MAP_TEST_SK_PER_THREAD "BPF_SK_STORAGE_MAP_TEST_SK_PER_THREAD"
39751a0e301SMartin KaFai Lau #define BPF_SK_STORAGE_MAP_TEST_RUNTIME_S "BPF_SK_STORAGE_MAP_TEST_RUNTIME_S"
39851a0e301SMartin KaFai Lau #define BPF_SK_STORAGE_MAP_TEST_NAME "BPF_SK_STORAGE_MAP_TEST_NAME"
39951a0e301SMartin KaFai Lau 
40051a0e301SMartin KaFai Lau static void test_sk_storage_map_stress_free(void)
40151a0e301SMartin KaFai Lau {
40251a0e301SMartin KaFai Lau 	struct rlimit rlim_old, rlim_new = {};
40351a0e301SMartin KaFai Lau 	int err;
40451a0e301SMartin KaFai Lau 
40551a0e301SMartin KaFai Lau 	getrlimit(RLIMIT_NOFILE, &rlim_old);
40651a0e301SMartin KaFai Lau 
40751a0e301SMartin KaFai Lau 	signal(SIGTERM, stop_handler);
40851a0e301SMartin KaFai Lau 	signal(SIGINT, stop_handler);
40951a0e301SMartin KaFai Lau 	if (runtime_s > 0) {
41051a0e301SMartin KaFai Lau 		signal(SIGALRM, stop_handler);
41151a0e301SMartin KaFai Lau 		alarm(runtime_s);
41251a0e301SMartin KaFai Lau 	}
41351a0e301SMartin KaFai Lau 
41451a0e301SMartin KaFai Lau 	if (rlim_old.rlim_cur < nr_sk_threads * nr_sk_per_thread) {
41551a0e301SMartin KaFai Lau 		rlim_new.rlim_cur = nr_sk_threads * nr_sk_per_thread + 128;
41651a0e301SMartin KaFai Lau 		rlim_new.rlim_max = rlim_new.rlim_cur + 128;
41751a0e301SMartin KaFai Lau 		err = setrlimit(RLIMIT_NOFILE, &rlim_new);
41851a0e301SMartin KaFai Lau 		CHECK(err, "setrlimit(RLIMIT_NOFILE)", "rlim_new:%lu errno:%d",
41951a0e301SMartin KaFai Lau 		      rlim_new.rlim_cur, errno);
42051a0e301SMartin KaFai Lau 	}
42151a0e301SMartin KaFai Lau 
42251a0e301SMartin KaFai Lau 	err = do_sk_storage_map_stress_free();
42351a0e301SMartin KaFai Lau 
42451a0e301SMartin KaFai Lau 	signal(SIGTERM, SIG_DFL);
42551a0e301SMartin KaFai Lau 	signal(SIGINT, SIG_DFL);
42651a0e301SMartin KaFai Lau 	if (runtime_s > 0) {
42751a0e301SMartin KaFai Lau 		signal(SIGALRM, SIG_DFL);
42851a0e301SMartin KaFai Lau 		alarm(0);
42951a0e301SMartin KaFai Lau 	}
43051a0e301SMartin KaFai Lau 
43151a0e301SMartin KaFai Lau 	if (rlim_new.rlim_cur)
43251a0e301SMartin KaFai Lau 		setrlimit(RLIMIT_NOFILE, &rlim_old);
43351a0e301SMartin KaFai Lau 
43451a0e301SMartin KaFai Lau 	CHECK(err, "test_sk_storage_map_stress_free", "err:%d\n", err);
43551a0e301SMartin KaFai Lau }
43651a0e301SMartin KaFai Lau 
43751a0e301SMartin KaFai Lau static void test_sk_storage_map_stress_change(void)
43851a0e301SMartin KaFai Lau {
43951a0e301SMartin KaFai Lau 	int err;
44051a0e301SMartin KaFai Lau 
44151a0e301SMartin KaFai Lau 	signal(SIGTERM, stop_handler);
44251a0e301SMartin KaFai Lau 	signal(SIGINT, stop_handler);
44351a0e301SMartin KaFai Lau 	if (runtime_s > 0) {
44451a0e301SMartin KaFai Lau 		signal(SIGALRM, stop_handler);
44551a0e301SMartin KaFai Lau 		alarm(runtime_s);
44651a0e301SMartin KaFai Lau 	}
44751a0e301SMartin KaFai Lau 
44851a0e301SMartin KaFai Lau 	err = do_sk_storage_map_stress_change();
44951a0e301SMartin KaFai Lau 
45051a0e301SMartin KaFai Lau 	signal(SIGTERM, SIG_DFL);
45151a0e301SMartin KaFai Lau 	signal(SIGINT, SIG_DFL);
45251a0e301SMartin KaFai Lau 	if (runtime_s > 0) {
45351a0e301SMartin KaFai Lau 		signal(SIGALRM, SIG_DFL);
45451a0e301SMartin KaFai Lau 		alarm(0);
45551a0e301SMartin KaFai Lau 	}
45651a0e301SMartin KaFai Lau 
45751a0e301SMartin KaFai Lau 	CHECK(err, "test_sk_storage_map_stress_change", "err:%d\n", err);
45851a0e301SMartin KaFai Lau }
45951a0e301SMartin KaFai Lau 
46051a0e301SMartin KaFai Lau static void test_sk_storage_map_basic(void)
46151a0e301SMartin KaFai Lau {
46251a0e301SMartin KaFai Lau 	struct {
46351a0e301SMartin KaFai Lau 		int cnt;
46451a0e301SMartin KaFai Lau 		int lock;
46551a0e301SMartin KaFai Lau 	} value = { .cnt = 0xeB9f, .lock = 0, }, lookup_value;
46651a0e301SMartin KaFai Lau 	struct bpf_create_map_attr bad_xattr;
46751a0e301SMartin KaFai Lau 	int btf_fd, map_fd, sk_fd, err;
46851a0e301SMartin KaFai Lau 
46951a0e301SMartin KaFai Lau 	btf_fd = load_btf();
47051a0e301SMartin KaFai Lau 	CHECK(btf_fd == -1, "bpf_load_btf", "btf_fd:%d errno:%d\n",
47151a0e301SMartin KaFai Lau 	      btf_fd, errno);
47251a0e301SMartin KaFai Lau 	xattr.btf_fd = btf_fd;
47351a0e301SMartin KaFai Lau 
47451a0e301SMartin KaFai Lau 	sk_fd = socket(AF_INET6, SOCK_STREAM, 0);
47551a0e301SMartin KaFai Lau 	CHECK(sk_fd == -1, "socket()", "sk_fd:%d errno:%d\n",
47651a0e301SMartin KaFai Lau 	      sk_fd, errno);
47751a0e301SMartin KaFai Lau 
47851a0e301SMartin KaFai Lau 	map_fd = bpf_create_map_xattr(&xattr);
47951a0e301SMartin KaFai Lau 	CHECK(map_fd == -1, "bpf_create_map_xattr(good_xattr)",
48051a0e301SMartin KaFai Lau 	      "map_fd:%d errno:%d\n", map_fd, errno);
48151a0e301SMartin KaFai Lau 
48251a0e301SMartin KaFai Lau 	/* Add new elem */
48351a0e301SMartin KaFai Lau 	memcpy(&lookup_value, &value, sizeof(value));
48451a0e301SMartin KaFai Lau 	err = bpf_map_update_elem(map_fd, &sk_fd, &value,
48551a0e301SMartin KaFai Lau 				  BPF_NOEXIST | BPF_F_LOCK);
48651a0e301SMartin KaFai Lau 	CHECK(err, "bpf_map_update_elem(BPF_NOEXIST|BPF_F_LOCK)",
48751a0e301SMartin KaFai Lau 	      "err:%d errno:%d\n", err, errno);
48851a0e301SMartin KaFai Lau 	err = bpf_map_lookup_elem_flags(map_fd, &sk_fd, &lookup_value,
48951a0e301SMartin KaFai Lau 					BPF_F_LOCK);
49051a0e301SMartin KaFai Lau 	CHECK(err || lookup_value.cnt != value.cnt,
49151a0e301SMartin KaFai Lau 	      "bpf_map_lookup_elem_flags(BPF_F_LOCK)",
49251a0e301SMartin KaFai Lau 	      "err:%d errno:%d cnt:%x(%x)\n",
49351a0e301SMartin KaFai Lau 	      err, errno, lookup_value.cnt, value.cnt);
49451a0e301SMartin KaFai Lau 
49551a0e301SMartin KaFai Lau 	/* Bump the cnt and update with BPF_EXIST | BPF_F_LOCK */
49651a0e301SMartin KaFai Lau 	value.cnt += 1;
49751a0e301SMartin KaFai Lau 	err = bpf_map_update_elem(map_fd, &sk_fd, &value,
49851a0e301SMartin KaFai Lau 				  BPF_EXIST | BPF_F_LOCK);
49951a0e301SMartin KaFai Lau 	CHECK(err, "bpf_map_update_elem(BPF_EXIST|BPF_F_LOCK)",
50051a0e301SMartin KaFai Lau 	      "err:%d errno:%d\n", err, errno);
50151a0e301SMartin KaFai Lau 	err = bpf_map_lookup_elem_flags(map_fd, &sk_fd, &lookup_value,
50251a0e301SMartin KaFai Lau 					BPF_F_LOCK);
50351a0e301SMartin KaFai Lau 	CHECK(err || lookup_value.cnt != value.cnt,
50451a0e301SMartin KaFai Lau 	      "bpf_map_lookup_elem_flags(BPF_F_LOCK)",
50551a0e301SMartin KaFai Lau 	      "err:%d errno:%d cnt:%x(%x)\n",
50651a0e301SMartin KaFai Lau 	      err, errno, lookup_value.cnt, value.cnt);
50751a0e301SMartin KaFai Lau 
50851a0e301SMartin KaFai Lau 	/* Bump the cnt and update with BPF_EXIST */
50951a0e301SMartin KaFai Lau 	value.cnt += 1;
51051a0e301SMartin KaFai Lau 	err = bpf_map_update_elem(map_fd, &sk_fd, &value, BPF_EXIST);
51151a0e301SMartin KaFai Lau 	CHECK(err, "bpf_map_update_elem(BPF_EXIST)",
51251a0e301SMartin KaFai Lau 	      "err:%d errno:%d\n", err, errno);
51351a0e301SMartin KaFai Lau 	err = bpf_map_lookup_elem_flags(map_fd, &sk_fd, &lookup_value,
51451a0e301SMartin KaFai Lau 					BPF_F_LOCK);
51551a0e301SMartin KaFai Lau 	CHECK(err || lookup_value.cnt != value.cnt,
51651a0e301SMartin KaFai Lau 	      "bpf_map_lookup_elem_flags(BPF_F_LOCK)",
51751a0e301SMartin KaFai Lau 	      "err:%d errno:%d cnt:%x(%x)\n",
51851a0e301SMartin KaFai Lau 	      err, errno, lookup_value.cnt, value.cnt);
51951a0e301SMartin KaFai Lau 
52051a0e301SMartin KaFai Lau 	/* Update with BPF_NOEXIST */
52151a0e301SMartin KaFai Lau 	value.cnt += 1;
52251a0e301SMartin KaFai Lau 	err = bpf_map_update_elem(map_fd, &sk_fd, &value,
52351a0e301SMartin KaFai Lau 				  BPF_NOEXIST | BPF_F_LOCK);
52451a0e301SMartin KaFai Lau 	CHECK(!err || errno != EEXIST,
52551a0e301SMartin KaFai Lau 	      "bpf_map_update_elem(BPF_NOEXIST|BPF_F_LOCK)",
52651a0e301SMartin KaFai Lau 	      "err:%d errno:%d\n", err, errno);
52751a0e301SMartin KaFai Lau 	err = bpf_map_update_elem(map_fd, &sk_fd, &value, BPF_NOEXIST);
52851a0e301SMartin KaFai Lau 	CHECK(!err || errno != EEXIST, "bpf_map_update_elem(BPF_NOEXIST)",
52951a0e301SMartin KaFai Lau 	      "err:%d errno:%d\n", err, errno);
53051a0e301SMartin KaFai Lau 	value.cnt -= 1;
53151a0e301SMartin KaFai Lau 	err = bpf_map_lookup_elem_flags(map_fd, &sk_fd, &lookup_value,
53251a0e301SMartin KaFai Lau 					BPF_F_LOCK);
53351a0e301SMartin KaFai Lau 	CHECK(err || lookup_value.cnt != value.cnt,
53451a0e301SMartin KaFai Lau 	      "bpf_map_lookup_elem_flags(BPF_F_LOCK)",
53551a0e301SMartin KaFai Lau 	      "err:%d errno:%d cnt:%x(%x)\n",
53651a0e301SMartin KaFai Lau 	      err, errno, lookup_value.cnt, value.cnt);
53751a0e301SMartin KaFai Lau 
53851a0e301SMartin KaFai Lau 	/* Bump the cnt again and update with map_flags == 0 */
53951a0e301SMartin KaFai Lau 	value.cnt += 1;
54051a0e301SMartin KaFai Lau 	err = bpf_map_update_elem(map_fd, &sk_fd, &value, 0);
54151a0e301SMartin KaFai Lau 	CHECK(err, "bpf_map_update_elem()", "err:%d errno:%d\n",
54251a0e301SMartin KaFai Lau 	      err, errno);
54351a0e301SMartin KaFai Lau 	err = bpf_map_lookup_elem_flags(map_fd, &sk_fd, &lookup_value,
54451a0e301SMartin KaFai Lau 					BPF_F_LOCK);
54551a0e301SMartin KaFai Lau 	CHECK(err || lookup_value.cnt != value.cnt,
54651a0e301SMartin KaFai Lau 	      "bpf_map_lookup_elem_flags(BPF_F_LOCK)",
54751a0e301SMartin KaFai Lau 	      "err:%d errno:%d cnt:%x(%x)\n",
54851a0e301SMartin KaFai Lau 	      err, errno, lookup_value.cnt, value.cnt);
54951a0e301SMartin KaFai Lau 
55051a0e301SMartin KaFai Lau 	/* Test delete elem */
55151a0e301SMartin KaFai Lau 	err = bpf_map_delete_elem(map_fd, &sk_fd);
55251a0e301SMartin KaFai Lau 	CHECK(err, "bpf_map_delete_elem()", "err:%d errno:%d\n",
55351a0e301SMartin KaFai Lau 	      err, errno);
55451a0e301SMartin KaFai Lau 	err = bpf_map_lookup_elem_flags(map_fd, &sk_fd, &lookup_value,
55551a0e301SMartin KaFai Lau 					BPF_F_LOCK);
55651a0e301SMartin KaFai Lau 	CHECK(!err || errno != ENOENT,
55751a0e301SMartin KaFai Lau 	      "bpf_map_lookup_elem_flags(BPF_F_LOCK)",
55851a0e301SMartin KaFai Lau 	      "err:%d errno:%d\n", err, errno);
55951a0e301SMartin KaFai Lau 	err = bpf_map_delete_elem(map_fd, &sk_fd);
56051a0e301SMartin KaFai Lau 	CHECK(!err || errno != ENOENT, "bpf_map_delete_elem()",
56151a0e301SMartin KaFai Lau 	      "err:%d errno:%d\n", err, errno);
56251a0e301SMartin KaFai Lau 
56351a0e301SMartin KaFai Lau 	memcpy(&bad_xattr, &xattr, sizeof(xattr));
56451a0e301SMartin KaFai Lau 	bad_xattr.btf_key_type_id = 0;
56551a0e301SMartin KaFai Lau 	err = bpf_create_map_xattr(&bad_xattr);
56651a0e301SMartin KaFai Lau 	CHECK(!err || errno != EINVAL, "bap_create_map_xattr(bad_xattr)",
56751a0e301SMartin KaFai Lau 	      "err:%d errno:%d\n", err, errno);
56851a0e301SMartin KaFai Lau 
56951a0e301SMartin KaFai Lau 	memcpy(&bad_xattr, &xattr, sizeof(xattr));
57051a0e301SMartin KaFai Lau 	bad_xattr.btf_key_type_id = 3;
57151a0e301SMartin KaFai Lau 	err = bpf_create_map_xattr(&bad_xattr);
57251a0e301SMartin KaFai Lau 	CHECK(!err || errno != EINVAL, "bap_create_map_xattr(bad_xattr)",
57351a0e301SMartin KaFai Lau 	      "err:%d errno:%d\n", err, errno);
57451a0e301SMartin KaFai Lau 
57551a0e301SMartin KaFai Lau 	memcpy(&bad_xattr, &xattr, sizeof(xattr));
57651a0e301SMartin KaFai Lau 	bad_xattr.max_entries = 1;
57751a0e301SMartin KaFai Lau 	err = bpf_create_map_xattr(&bad_xattr);
57851a0e301SMartin KaFai Lau 	CHECK(!err || errno != EINVAL, "bap_create_map_xattr(bad_xattr)",
57951a0e301SMartin KaFai Lau 	      "err:%d errno:%d\n", err, errno);
58051a0e301SMartin KaFai Lau 
58151a0e301SMartin KaFai Lau 	memcpy(&bad_xattr, &xattr, sizeof(xattr));
58251a0e301SMartin KaFai Lau 	bad_xattr.map_flags = 0;
58351a0e301SMartin KaFai Lau 	err = bpf_create_map_xattr(&bad_xattr);
58451a0e301SMartin KaFai Lau 	CHECK(!err || errno != EINVAL, "bap_create_map_xattr(bad_xattr)",
58551a0e301SMartin KaFai Lau 	      "err:%d errno:%d\n", err, errno);
58651a0e301SMartin KaFai Lau 
58751a0e301SMartin KaFai Lau 	xattr.btf_fd = -1;
58851a0e301SMartin KaFai Lau 	close(btf_fd);
58951a0e301SMartin KaFai Lau 	close(map_fd);
59051a0e301SMartin KaFai Lau 	close(sk_fd);
59151a0e301SMartin KaFai Lau }
59251a0e301SMartin KaFai Lau 
59351a0e301SMartin KaFai Lau void test_sk_storage_map(void)
59451a0e301SMartin KaFai Lau {
59551a0e301SMartin KaFai Lau 	const char *test_name, *env_opt;
59651a0e301SMartin KaFai Lau 	bool test_ran = false;
59751a0e301SMartin KaFai Lau 
59851a0e301SMartin KaFai Lau 	test_name = getenv(BPF_SK_STORAGE_MAP_TEST_NAME);
59951a0e301SMartin KaFai Lau 
60051a0e301SMartin KaFai Lau 	env_opt = getenv(BPF_SK_STORAGE_MAP_TEST_NR_THREADS);
60151a0e301SMartin KaFai Lau 	if (env_opt)
60251a0e301SMartin KaFai Lau 		nr_sk_threads = atoi(env_opt);
60351a0e301SMartin KaFai Lau 
60451a0e301SMartin KaFai Lau 	env_opt = getenv(BPF_SK_STORAGE_MAP_TEST_SK_PER_THREAD);
60551a0e301SMartin KaFai Lau 	if (env_opt)
60651a0e301SMartin KaFai Lau 		nr_sk_per_thread = atoi(env_opt);
60751a0e301SMartin KaFai Lau 
60851a0e301SMartin KaFai Lau 	env_opt = getenv(BPF_SK_STORAGE_MAP_TEST_RUNTIME_S);
60951a0e301SMartin KaFai Lau 	if (env_opt)
61051a0e301SMartin KaFai Lau 		runtime_s = atoi(env_opt);
61151a0e301SMartin KaFai Lau 
61251a0e301SMartin KaFai Lau 	if (!test_name || !strcmp(test_name, "basic")) {
61351a0e301SMartin KaFai Lau 		test_sk_storage_map_basic();
61451a0e301SMartin KaFai Lau 		test_ran = true;
61551a0e301SMartin KaFai Lau 	}
61651a0e301SMartin KaFai Lau 	if (!test_name || !strcmp(test_name, "stress_free")) {
61751a0e301SMartin KaFai Lau 		test_sk_storage_map_stress_free();
61851a0e301SMartin KaFai Lau 		test_ran = true;
61951a0e301SMartin KaFai Lau 	}
62051a0e301SMartin KaFai Lau 	if (!test_name || !strcmp(test_name, "stress_change")) {
62151a0e301SMartin KaFai Lau 		test_sk_storage_map_stress_change();
62251a0e301SMartin KaFai Lau 		test_ran = true;
62351a0e301SMartin KaFai Lau 	}
62451a0e301SMartin KaFai Lau 
62551a0e301SMartin KaFai Lau 	if (test_ran)
62651a0e301SMartin KaFai Lau 		printf("%s:PASS\n", __func__);
62751a0e301SMartin KaFai Lau 	else
62851a0e301SMartin KaFai Lau 		CHECK(1, "Invalid test_name", "%s\n", test_name);
62951a0e301SMartin KaFai Lau }
630