xref: /openbmc/linux/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c (revision 36db6e8484ed455bbb320d89a119378897ae991c)
15d3919a9SJakub Sitnicki // SPDX-License-Identifier: GPL-2.0
25d3919a9SJakub Sitnicki // Copyright (c) 2020 Cloudflare
31d9c037aSJohn Fastabend #include <error.h>
49cacf81fSStanislav Fomichev #include <netinet/tcp.h>
51fa1fe8fSJohn Fastabend #include <sys/epoll.h>
65d3919a9SJakub Sitnicki 
75d3919a9SJakub Sitnicki #include "test_progs.h"
81d9c037aSJohn Fastabend #include "test_skmsg_load_helpers.skel.h"
9bb23c0e1SLorenz Bauer #include "test_sockmap_update.skel.h"
10bb23c0e1SLorenz Bauer #include "test_sockmap_invalid_update.skel.h"
118d7cb74fSCong Wang #include "test_sockmap_skb_verdict_attach.skel.h"
12820e6e22SDi Zhu #include "test_sockmap_progs_query.skel.h"
131fa1fe8fSJohn Fastabend #include "test_sockmap_pass_prog.skel.h"
1480e24d22SJohn Fastabend #include "test_sockmap_drop_prog.skel.h"
152f7de986SLorenz Bauer #include "bpf_iter_sockmap.skel.h"
162f7de986SLorenz Bauer 
171fa1fe8fSJohn Fastabend #include "sockmap_helpers.h"
181fa1fe8fSJohn Fastabend 
19f2e97dc1SJohn Fastabend #define TCP_REPAIR		19	/* TCP sock is under repair right now */
20f2e97dc1SJohn Fastabend 
21f2e97dc1SJohn Fastabend #define TCP_REPAIR_ON		1
22f2e97dc1SJohn Fastabend #define TCP_REPAIR_OFF_NO_WP	-1	/* Turn off without window probes */
23f2e97dc1SJohn Fastabend 
connected_socket_v4(void)245d3919a9SJakub Sitnicki static int connected_socket_v4(void)
255d3919a9SJakub Sitnicki {
265d3919a9SJakub Sitnicki 	struct sockaddr_in addr = {
275d3919a9SJakub Sitnicki 		.sin_family = AF_INET,
285d3919a9SJakub Sitnicki 		.sin_port = htons(80),
295d3919a9SJakub Sitnicki 		.sin_addr = { inet_addr("127.0.0.1") },
305d3919a9SJakub Sitnicki 	};
315d3919a9SJakub Sitnicki 	socklen_t len = sizeof(addr);
325d3919a9SJakub Sitnicki 	int s, repair, err;
335d3919a9SJakub Sitnicki 
345d3919a9SJakub Sitnicki 	s = socket(AF_INET, SOCK_STREAM, 0);
3538e35e1dSWang Yufen 	if (!ASSERT_GE(s, 0, "socket"))
365d3919a9SJakub Sitnicki 		goto error;
375d3919a9SJakub Sitnicki 
385d3919a9SJakub Sitnicki 	repair = TCP_REPAIR_ON;
395d3919a9SJakub Sitnicki 	err = setsockopt(s, SOL_TCP, TCP_REPAIR, &repair, sizeof(repair));
4038e35e1dSWang Yufen 	if (!ASSERT_OK(err, "setsockopt(TCP_REPAIR)"))
415d3919a9SJakub Sitnicki 		goto error;
425d3919a9SJakub Sitnicki 
435d3919a9SJakub Sitnicki 	err = connect(s, (struct sockaddr *)&addr, len);
4438e35e1dSWang Yufen 	if (!ASSERT_OK(err, "connect"))
455d3919a9SJakub Sitnicki 		goto error;
465d3919a9SJakub Sitnicki 
475d3919a9SJakub Sitnicki 	repair = TCP_REPAIR_OFF_NO_WP;
485d3919a9SJakub Sitnicki 	err = setsockopt(s, SOL_TCP, TCP_REPAIR, &repair, sizeof(repair));
4938e35e1dSWang Yufen 	if (!ASSERT_OK(err, "setsockopt(TCP_REPAIR)"))
505d3919a9SJakub Sitnicki 		goto error;
515d3919a9SJakub Sitnicki 
525d3919a9SJakub Sitnicki 	return s;
535d3919a9SJakub Sitnicki error:
545d3919a9SJakub Sitnicki 	perror(__func__);
555d3919a9SJakub Sitnicki 	close(s);
565d3919a9SJakub Sitnicki 	return -1;
575d3919a9SJakub Sitnicki }
585d3919a9SJakub Sitnicki 
compare_cookies(struct bpf_map * src,struct bpf_map * dst)5926c3270dSLorenz Bauer static void compare_cookies(struct bpf_map *src, struct bpf_map *dst)
6026c3270dSLorenz Bauer {
6126c3270dSLorenz Bauer 	__u32 i, max_entries = bpf_map__max_entries(src);
6238e35e1dSWang Yufen 	int err, src_fd, dst_fd;
6326c3270dSLorenz Bauer 
6426c3270dSLorenz Bauer 	src_fd = bpf_map__fd(src);
6526c3270dSLorenz Bauer 	dst_fd = bpf_map__fd(dst);
6626c3270dSLorenz Bauer 
6726c3270dSLorenz Bauer 	for (i = 0; i < max_entries; i++) {
6826c3270dSLorenz Bauer 		__u64 src_cookie, dst_cookie;
6926c3270dSLorenz Bauer 
7026c3270dSLorenz Bauer 		err = bpf_map_lookup_elem(src_fd, &i, &src_cookie);
7126c3270dSLorenz Bauer 		if (err && errno == ENOENT) {
7226c3270dSLorenz Bauer 			err = bpf_map_lookup_elem(dst_fd, &i, &dst_cookie);
7338e35e1dSWang Yufen 			ASSERT_ERR(err, "map_lookup_elem(dst)");
7438e35e1dSWang Yufen 			ASSERT_EQ(errno, ENOENT, "map_lookup_elem(dst)");
7526c3270dSLorenz Bauer 			continue;
7626c3270dSLorenz Bauer 		}
7738e35e1dSWang Yufen 		if (!ASSERT_OK(err, "lookup_elem(src)"))
7826c3270dSLorenz Bauer 			continue;
7926c3270dSLorenz Bauer 
8026c3270dSLorenz Bauer 		err = bpf_map_lookup_elem(dst_fd, &i, &dst_cookie);
8138e35e1dSWang Yufen 		if (!ASSERT_OK(err, "lookup_elem(dst)"))
8226c3270dSLorenz Bauer 			continue;
8326c3270dSLorenz Bauer 
8438e35e1dSWang Yufen 		ASSERT_EQ(dst_cookie, src_cookie, "cookie mismatch");
8526c3270dSLorenz Bauer 	}
8626c3270dSLorenz Bauer }
8726c3270dSLorenz Bauer 
885d3919a9SJakub Sitnicki /* Create a map, populate it with one socket, and free the map. */
test_sockmap_create_update_free(enum bpf_map_type map_type)895d3919a9SJakub Sitnicki static void test_sockmap_create_update_free(enum bpf_map_type map_type)
905d3919a9SJakub Sitnicki {
915d3919a9SJakub Sitnicki 	const int zero = 0;
925d3919a9SJakub Sitnicki 	int s, map, err;
935d3919a9SJakub Sitnicki 
945d3919a9SJakub Sitnicki 	s = connected_socket_v4();
9538e35e1dSWang Yufen 	if (!ASSERT_GE(s, 0, "connected_socket_v4"))
965d3919a9SJakub Sitnicki 		return;
975d3919a9SJakub Sitnicki 
982fe256a4SAndrii Nakryiko 	map = bpf_map_create(map_type, NULL, sizeof(int), sizeof(int), 1, NULL);
9938e35e1dSWang Yufen 	if (!ASSERT_GE(map, 0, "bpf_map_create"))
1005d3919a9SJakub Sitnicki 		goto out;
1015d3919a9SJakub Sitnicki 
1025d3919a9SJakub Sitnicki 	err = bpf_map_update_elem(map, &zero, &s, BPF_NOEXIST);
10338e35e1dSWang Yufen 	if (!ASSERT_OK(err, "bpf_map_update"))
1045d3919a9SJakub Sitnicki 		goto out;
1055d3919a9SJakub Sitnicki 
1065d3919a9SJakub Sitnicki out:
1075d3919a9SJakub Sitnicki 	close(map);
1085d3919a9SJakub Sitnicki 	close(s);
1095d3919a9SJakub Sitnicki }
1105d3919a9SJakub Sitnicki 
test_skmsg_helpers(enum bpf_map_type map_type)1111d9c037aSJohn Fastabend static void test_skmsg_helpers(enum bpf_map_type map_type)
1121d9c037aSJohn Fastabend {
1131d9c037aSJohn Fastabend 	struct test_skmsg_load_helpers *skel;
1141d9c037aSJohn Fastabend 	int err, map, verdict;
1151d9c037aSJohn Fastabend 
1161d9c037aSJohn Fastabend 	skel = test_skmsg_load_helpers__open_and_load();
11738e35e1dSWang Yufen 	if (!ASSERT_OK_PTR(skel, "test_skmsg_load_helpers__open_and_load"))
1181d9c037aSJohn Fastabend 		return;
1191d9c037aSJohn Fastabend 
1201d9c037aSJohn Fastabend 	verdict = bpf_program__fd(skel->progs.prog_msg_verdict);
1211d9c037aSJohn Fastabend 	map = bpf_map__fd(skel->maps.sock_map);
1221d9c037aSJohn Fastabend 
1231d9c037aSJohn Fastabend 	err = bpf_prog_attach(verdict, map, BPF_SK_MSG_VERDICT, 0);
12438e35e1dSWang Yufen 	if (!ASSERT_OK(err, "bpf_prog_attach"))
1251d9c037aSJohn Fastabend 		goto out;
1261d9c037aSJohn Fastabend 
1271d9c037aSJohn Fastabend 	err = bpf_prog_detach2(verdict, map, BPF_SK_MSG_VERDICT);
12838e35e1dSWang Yufen 	if (!ASSERT_OK(err, "bpf_prog_detach2"))
1291d9c037aSJohn Fastabend 		goto out;
1301d9c037aSJohn Fastabend out:
1311d9c037aSJohn Fastabend 	test_skmsg_load_helpers__destroy(skel);
1321d9c037aSJohn Fastabend }
1331d9c037aSJohn Fastabend 
test_sockmap_update(enum bpf_map_type map_type)134bb23c0e1SLorenz Bauer static void test_sockmap_update(enum bpf_map_type map_type)
135bb23c0e1SLorenz Bauer {
13638e35e1dSWang Yufen 	int err, prog, src;
137bb23c0e1SLorenz Bauer 	struct test_sockmap_update *skel;
13826c3270dSLorenz Bauer 	struct bpf_map *dst_map;
139bb23c0e1SLorenz Bauer 	const __u32 zero = 0;
140bb23c0e1SLorenz Bauer 	char dummy[14] = {0};
14139316183SDelyan Kratunov 	LIBBPF_OPTS(bpf_test_run_opts, topts,
14239316183SDelyan Kratunov 		.data_in = dummy,
14339316183SDelyan Kratunov 		.data_size_in = sizeof(dummy),
14439316183SDelyan Kratunov 		.repeat = 1,
14539316183SDelyan Kratunov 	);
146bb23c0e1SLorenz Bauer 	__s64 sk;
147bb23c0e1SLorenz Bauer 
148bb23c0e1SLorenz Bauer 	sk = connected_socket_v4();
14938e35e1dSWang Yufen 	if (!ASSERT_NEQ(sk, -1, "connected_socket_v4"))
150bb23c0e1SLorenz Bauer 		return;
151bb23c0e1SLorenz Bauer 
152bb23c0e1SLorenz Bauer 	skel = test_sockmap_update__open_and_load();
15338e35e1dSWang Yufen 	if (!ASSERT_OK_PTR(skel, "open_and_load"))
1548c3b3d97SLorenz Bauer 		goto close_sk;
155bb23c0e1SLorenz Bauer 
156bb23c0e1SLorenz Bauer 	prog = bpf_program__fd(skel->progs.copy_sock_map);
157bb23c0e1SLorenz Bauer 	src = bpf_map__fd(skel->maps.src);
158bb23c0e1SLorenz Bauer 	if (map_type == BPF_MAP_TYPE_SOCKMAP)
15926c3270dSLorenz Bauer 		dst_map = skel->maps.dst_sock_map;
160bb23c0e1SLorenz Bauer 	else
16126c3270dSLorenz Bauer 		dst_map = skel->maps.dst_sock_hash;
162bb23c0e1SLorenz Bauer 
163bb23c0e1SLorenz Bauer 	err = bpf_map_update_elem(src, &zero, &sk, BPF_NOEXIST);
16438e35e1dSWang Yufen 	if (!ASSERT_OK(err, "update_elem(src)"))
165bb23c0e1SLorenz Bauer 		goto out;
166bb23c0e1SLorenz Bauer 
16739316183SDelyan Kratunov 	err = bpf_prog_test_run_opts(prog, &topts);
16839316183SDelyan Kratunov 	if (!ASSERT_OK(err, "test_run"))
16939316183SDelyan Kratunov 		goto out;
17039316183SDelyan Kratunov 	if (!ASSERT_NEQ(topts.retval, 0, "test_run retval"))
171bb23c0e1SLorenz Bauer 		goto out;
172bb23c0e1SLorenz Bauer 
17326c3270dSLorenz Bauer 	compare_cookies(skel->maps.src, dst_map);
174bb23c0e1SLorenz Bauer 
175bb23c0e1SLorenz Bauer out:
176bb23c0e1SLorenz Bauer 	test_sockmap_update__destroy(skel);
1778c3b3d97SLorenz Bauer close_sk:
1788c3b3d97SLorenz Bauer 	close(sk);
179bb23c0e1SLorenz Bauer }
180bb23c0e1SLorenz Bauer 
test_sockmap_invalid_update(void)181bb23c0e1SLorenz Bauer static void test_sockmap_invalid_update(void)
182bb23c0e1SLorenz Bauer {
183bb23c0e1SLorenz Bauer 	struct test_sockmap_invalid_update *skel;
184bb23c0e1SLorenz Bauer 
185bb23c0e1SLorenz Bauer 	skel = test_sockmap_invalid_update__open_and_load();
18638e35e1dSWang Yufen 	if (!ASSERT_NULL(skel, "open_and_load"))
187bb23c0e1SLorenz Bauer 		test_sockmap_invalid_update__destroy(skel);
188bb23c0e1SLorenz Bauer }
189bb23c0e1SLorenz Bauer 
test_sockmap_copy(enum bpf_map_type map_type)1905b87adc3SLorenz Bauer static void test_sockmap_copy(enum bpf_map_type map_type)
1912f7de986SLorenz Bauer {
1922f7de986SLorenz Bauer 	DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
19338e35e1dSWang Yufen 	int err, len, src_fd, iter_fd;
19448ca6243SStanislav Fomichev 	union bpf_iter_link_info linfo = {};
19527870317SLorenz Bauer 	__u32 i, num_sockets, num_elems;
1962f7de986SLorenz Bauer 	struct bpf_iter_sockmap *skel;
19727870317SLorenz Bauer 	__s64 *sock_fd = NULL;
1982f7de986SLorenz Bauer 	struct bpf_link *link;
1992f7de986SLorenz Bauer 	struct bpf_map *src;
2002f7de986SLorenz Bauer 	char buf[64];
2012f7de986SLorenz Bauer 
2022f7de986SLorenz Bauer 	skel = bpf_iter_sockmap__open_and_load();
20338e35e1dSWang Yufen 	if (!ASSERT_OK_PTR(skel, "bpf_iter_sockmap__open_and_load"))
2042f7de986SLorenz Bauer 		return;
2052f7de986SLorenz Bauer 
2062f7de986SLorenz Bauer 	if (map_type == BPF_MAP_TYPE_SOCKMAP) {
2072f7de986SLorenz Bauer 		src = skel->maps.sockmap;
20827870317SLorenz Bauer 		num_elems = bpf_map__max_entries(src);
20927870317SLorenz Bauer 		num_sockets = num_elems - 1;
2102f7de986SLorenz Bauer 	} else {
2112f7de986SLorenz Bauer 		src = skel->maps.sockhash;
21227870317SLorenz Bauer 		num_elems = bpf_map__max_entries(src) - 1;
21327870317SLorenz Bauer 		num_sockets = num_elems;
2142f7de986SLorenz Bauer 	}
2152f7de986SLorenz Bauer 
21627870317SLorenz Bauer 	sock_fd = calloc(num_sockets, sizeof(*sock_fd));
21738e35e1dSWang Yufen 	if (!ASSERT_OK_PTR(sock_fd, "calloc(sock_fd)"))
21827870317SLorenz Bauer 		goto out;
21927870317SLorenz Bauer 
22027870317SLorenz Bauer 	for (i = 0; i < num_sockets; i++)
22127870317SLorenz Bauer 		sock_fd[i] = -1;
22227870317SLorenz Bauer 
2232f7de986SLorenz Bauer 	src_fd = bpf_map__fd(src);
2242f7de986SLorenz Bauer 
2252f7de986SLorenz Bauer 	for (i = 0; i < num_sockets; i++) {
2262f7de986SLorenz Bauer 		sock_fd[i] = connected_socket_v4();
22738e35e1dSWang Yufen 		if (!ASSERT_NEQ(sock_fd[i], -1, "connected_socket_v4"))
2282f7de986SLorenz Bauer 			goto out;
2292f7de986SLorenz Bauer 
2302f7de986SLorenz Bauer 		err = bpf_map_update_elem(src_fd, &i, &sock_fd[i], BPF_NOEXIST);
23138e35e1dSWang Yufen 		if (!ASSERT_OK(err, "map_update"))
2322f7de986SLorenz Bauer 			goto out;
2332f7de986SLorenz Bauer 	}
2342f7de986SLorenz Bauer 
2352f7de986SLorenz Bauer 	linfo.map.map_fd = src_fd;
2362f7de986SLorenz Bauer 	opts.link_info = &linfo;
2372f7de986SLorenz Bauer 	opts.link_info_len = sizeof(linfo);
2385b87adc3SLorenz Bauer 	link = bpf_program__attach_iter(skel->progs.copy, &opts);
239bad2e478SAndrii Nakryiko 	if (!ASSERT_OK_PTR(link, "attach_iter"))
2402f7de986SLorenz Bauer 		goto out;
2412f7de986SLorenz Bauer 
2422f7de986SLorenz Bauer 	iter_fd = bpf_iter_create(bpf_link__fd(link));
24338e35e1dSWang Yufen 	if (!ASSERT_GE(iter_fd, 0, "create_iter"))
2442f7de986SLorenz Bauer 		goto free_link;
2452f7de986SLorenz Bauer 
2462f7de986SLorenz Bauer 	/* do some tests */
2472f7de986SLorenz Bauer 	while ((len = read(iter_fd, buf, sizeof(buf))) > 0)
2482f7de986SLorenz Bauer 		;
24938e35e1dSWang Yufen 	if (!ASSERT_GE(len, 0, "read"))
2502f7de986SLorenz Bauer 		goto close_iter;
2512f7de986SLorenz Bauer 
2522f7de986SLorenz Bauer 	/* test results */
25338e35e1dSWang Yufen 	if (!ASSERT_EQ(skel->bss->elems, num_elems, "elems"))
2542f7de986SLorenz Bauer 		goto close_iter;
2552f7de986SLorenz Bauer 
25638e35e1dSWang Yufen 	if (!ASSERT_EQ(skel->bss->socks, num_sockets, "socks"))
2572f7de986SLorenz Bauer 		goto close_iter;
2582f7de986SLorenz Bauer 
2595b87adc3SLorenz Bauer 	compare_cookies(src, skel->maps.dst);
2605b87adc3SLorenz Bauer 
2612f7de986SLorenz Bauer close_iter:
2622f7de986SLorenz Bauer 	close(iter_fd);
2632f7de986SLorenz Bauer free_link:
2642f7de986SLorenz Bauer 	bpf_link__destroy(link);
2652f7de986SLorenz Bauer out:
26627870317SLorenz Bauer 	for (i = 0; sock_fd && i < num_sockets; i++)
2672f7de986SLorenz Bauer 		if (sock_fd[i] >= 0)
2682f7de986SLorenz Bauer 			close(sock_fd[i]);
26927870317SLorenz Bauer 	if (sock_fd)
27027870317SLorenz Bauer 		free(sock_fd);
2712f7de986SLorenz Bauer 	bpf_iter_sockmap__destroy(skel);
2722f7de986SLorenz Bauer }
2732f7de986SLorenz Bauer 
test_sockmap_skb_verdict_attach(enum bpf_attach_type first,enum bpf_attach_type second)2748d7cb74fSCong Wang static void test_sockmap_skb_verdict_attach(enum bpf_attach_type first,
2758d7cb74fSCong Wang 					    enum bpf_attach_type second)
2768d7cb74fSCong Wang {
2778d7cb74fSCong Wang 	struct test_sockmap_skb_verdict_attach *skel;
2788d7cb74fSCong Wang 	int err, map, verdict;
2798d7cb74fSCong Wang 
2808d7cb74fSCong Wang 	skel = test_sockmap_skb_verdict_attach__open_and_load();
28138e35e1dSWang Yufen 	if (!ASSERT_OK_PTR(skel, "open_and_load"))
2828d7cb74fSCong Wang 		return;
2838d7cb74fSCong Wang 
2848d7cb74fSCong Wang 	verdict = bpf_program__fd(skel->progs.prog_skb_verdict);
2858d7cb74fSCong Wang 	map = bpf_map__fd(skel->maps.sock_map);
2868d7cb74fSCong Wang 
2878d7cb74fSCong Wang 	err = bpf_prog_attach(verdict, map, first, 0);
28838e35e1dSWang Yufen 	if (!ASSERT_OK(err, "bpf_prog_attach"))
2898d7cb74fSCong Wang 		goto out;
2908d7cb74fSCong Wang 
2918d7cb74fSCong Wang 	err = bpf_prog_attach(verdict, map, second, 0);
292bad2e478SAndrii Nakryiko 	ASSERT_EQ(err, -EBUSY, "prog_attach_fail");
2938d7cb74fSCong Wang 
2948d7cb74fSCong Wang 	err = bpf_prog_detach2(verdict, map, first);
29538e35e1dSWang Yufen 	if (!ASSERT_OK(err, "bpf_prog_detach2"))
2968d7cb74fSCong Wang 		goto out;
2978d7cb74fSCong Wang out:
2988d7cb74fSCong Wang 	test_sockmap_skb_verdict_attach__destroy(skel);
2998d7cb74fSCong Wang }
3008d7cb74fSCong Wang 
query_prog_id(int prog_fd)301820e6e22SDi Zhu static __u32 query_prog_id(int prog_fd)
302820e6e22SDi Zhu {
303820e6e22SDi Zhu 	struct bpf_prog_info info = {};
304820e6e22SDi Zhu 	__u32 info_len = sizeof(info);
305820e6e22SDi Zhu 	int err;
306820e6e22SDi Zhu 
307c5a237a4SIlya Leoshkevich 	err = bpf_prog_get_info_by_fd(prog_fd, &info, &info_len);
308c5a237a4SIlya Leoshkevich 	if (!ASSERT_OK(err, "bpf_prog_get_info_by_fd") ||
309c5a237a4SIlya Leoshkevich 	    !ASSERT_EQ(info_len, sizeof(info), "bpf_prog_get_info_by_fd"))
310820e6e22SDi Zhu 		return 0;
311820e6e22SDi Zhu 
312820e6e22SDi Zhu 	return info.id;
313820e6e22SDi Zhu }
314820e6e22SDi Zhu 
test_sockmap_progs_query(enum bpf_attach_type attach_type)315820e6e22SDi Zhu static void test_sockmap_progs_query(enum bpf_attach_type attach_type)
316820e6e22SDi Zhu {
317820e6e22SDi Zhu 	struct test_sockmap_progs_query *skel;
318820e6e22SDi Zhu 	int err, map_fd, verdict_fd;
319820e6e22SDi Zhu 	__u32 attach_flags = 0;
320820e6e22SDi Zhu 	__u32 prog_ids[3] = {};
321820e6e22SDi Zhu 	__u32 prog_cnt = 3;
322820e6e22SDi Zhu 
323820e6e22SDi Zhu 	skel = test_sockmap_progs_query__open_and_load();
324820e6e22SDi Zhu 	if (!ASSERT_OK_PTR(skel, "test_sockmap_progs_query__open_and_load"))
325820e6e22SDi Zhu 		return;
326820e6e22SDi Zhu 
327820e6e22SDi Zhu 	map_fd = bpf_map__fd(skel->maps.sock_map);
328820e6e22SDi Zhu 
329820e6e22SDi Zhu 	if (attach_type == BPF_SK_MSG_VERDICT)
330820e6e22SDi Zhu 		verdict_fd = bpf_program__fd(skel->progs.prog_skmsg_verdict);
331820e6e22SDi Zhu 	else
332820e6e22SDi Zhu 		verdict_fd = bpf_program__fd(skel->progs.prog_skb_verdict);
333820e6e22SDi Zhu 
334820e6e22SDi Zhu 	err = bpf_prog_query(map_fd, attach_type, 0 /* query flags */,
335820e6e22SDi Zhu 			     &attach_flags, prog_ids, &prog_cnt);
336820e6e22SDi Zhu 	ASSERT_OK(err, "bpf_prog_query failed");
337820e6e22SDi Zhu 	ASSERT_EQ(attach_flags,  0, "wrong attach_flags on query");
338820e6e22SDi Zhu 	ASSERT_EQ(prog_cnt, 0, "wrong program count on query");
339820e6e22SDi Zhu 
340820e6e22SDi Zhu 	err = bpf_prog_attach(verdict_fd, map_fd, attach_type, 0);
341820e6e22SDi Zhu 	if (!ASSERT_OK(err, "bpf_prog_attach failed"))
342820e6e22SDi Zhu 		goto out;
343820e6e22SDi Zhu 
344820e6e22SDi Zhu 	prog_cnt = 1;
345820e6e22SDi Zhu 	err = bpf_prog_query(map_fd, attach_type, 0 /* query flags */,
346820e6e22SDi Zhu 			     &attach_flags, prog_ids, &prog_cnt);
347820e6e22SDi Zhu 	ASSERT_OK(err, "bpf_prog_query failed");
348820e6e22SDi Zhu 	ASSERT_EQ(attach_flags, 0, "wrong attach_flags on query");
349820e6e22SDi Zhu 	ASSERT_EQ(prog_cnt, 1, "wrong program count on query");
350820e6e22SDi Zhu 	ASSERT_EQ(prog_ids[0], query_prog_id(verdict_fd),
351820e6e22SDi Zhu 		  "wrong prog_ids on query");
352820e6e22SDi Zhu 
353820e6e22SDi Zhu 	bpf_prog_detach2(verdict_fd, map_fd, attach_type);
354820e6e22SDi Zhu out:
355820e6e22SDi Zhu 	test_sockmap_progs_query__destroy(skel);
356820e6e22SDi Zhu }
357820e6e22SDi Zhu 
3581fa1fe8fSJohn Fastabend #define MAX_EVENTS 10
test_sockmap_skb_verdict_shutdown(void)3591fa1fe8fSJohn Fastabend static void test_sockmap_skb_verdict_shutdown(void)
3601fa1fe8fSJohn Fastabend {
3611fa1fe8fSJohn Fastabend 	struct epoll_event ev, events[MAX_EVENTS];
3621fa1fe8fSJohn Fastabend 	int n, err, map, verdict, s, c1, p1;
3631fa1fe8fSJohn Fastabend 	struct test_sockmap_pass_prog *skel;
3641fa1fe8fSJohn Fastabend 	int epollfd;
3651fa1fe8fSJohn Fastabend 	int zero = 0;
3661fa1fe8fSJohn Fastabend 	char b;
3671fa1fe8fSJohn Fastabend 
3681fa1fe8fSJohn Fastabend 	skel = test_sockmap_pass_prog__open_and_load();
3691fa1fe8fSJohn Fastabend 	if (!ASSERT_OK_PTR(skel, "open_and_load"))
3701fa1fe8fSJohn Fastabend 		return;
3711fa1fe8fSJohn Fastabend 
3721fa1fe8fSJohn Fastabend 	verdict = bpf_program__fd(skel->progs.prog_skb_verdict);
3731fa1fe8fSJohn Fastabend 	map = bpf_map__fd(skel->maps.sock_map_rx);
3741fa1fe8fSJohn Fastabend 
3751fa1fe8fSJohn Fastabend 	err = bpf_prog_attach(verdict, map, BPF_SK_SKB_STREAM_VERDICT, 0);
3761fa1fe8fSJohn Fastabend 	if (!ASSERT_OK(err, "bpf_prog_attach"))
3771fa1fe8fSJohn Fastabend 		goto out;
3781fa1fe8fSJohn Fastabend 
3791fa1fe8fSJohn Fastabend 	s = socket_loopback(AF_INET, SOCK_STREAM);
3801fa1fe8fSJohn Fastabend 	if (s < 0)
3811fa1fe8fSJohn Fastabend 		goto out;
3821fa1fe8fSJohn Fastabend 	err = create_pair(s, AF_INET, SOCK_STREAM, &c1, &p1);
3831fa1fe8fSJohn Fastabend 	if (err < 0)
3841fa1fe8fSJohn Fastabend 		goto out;
3851fa1fe8fSJohn Fastabend 
3861fa1fe8fSJohn Fastabend 	err = bpf_map_update_elem(map, &zero, &c1, BPF_NOEXIST);
3871fa1fe8fSJohn Fastabend 	if (err < 0)
3881fa1fe8fSJohn Fastabend 		goto out_close;
3891fa1fe8fSJohn Fastabend 
3901fa1fe8fSJohn Fastabend 	shutdown(p1, SHUT_WR);
3911fa1fe8fSJohn Fastabend 
3921fa1fe8fSJohn Fastabend 	ev.events = EPOLLIN;
3931fa1fe8fSJohn Fastabend 	ev.data.fd = c1;
3941fa1fe8fSJohn Fastabend 
3951fa1fe8fSJohn Fastabend 	epollfd = epoll_create1(0);
3961fa1fe8fSJohn Fastabend 	if (!ASSERT_GT(epollfd, -1, "epoll_create(0)"))
3971fa1fe8fSJohn Fastabend 		goto out_close;
3981fa1fe8fSJohn Fastabend 	err = epoll_ctl(epollfd, EPOLL_CTL_ADD, c1, &ev);
3991fa1fe8fSJohn Fastabend 	if (!ASSERT_OK(err, "epoll_ctl(EPOLL_CTL_ADD)"))
4001fa1fe8fSJohn Fastabend 		goto out_close;
4011fa1fe8fSJohn Fastabend 	err = epoll_wait(epollfd, events, MAX_EVENTS, -1);
4021fa1fe8fSJohn Fastabend 	if (!ASSERT_EQ(err, 1, "epoll_wait(fd)"))
4031fa1fe8fSJohn Fastabend 		goto out_close;
4041fa1fe8fSJohn Fastabend 
405*dfbaf8a6SJiayuan Chen 	n = recv(c1, &b, 1, MSG_DONTWAIT);
406*dfbaf8a6SJiayuan Chen 	ASSERT_EQ(n, 0, "recv(fin)");
4071fa1fe8fSJohn Fastabend out_close:
4081fa1fe8fSJohn Fastabend 	close(c1);
4091fa1fe8fSJohn Fastabend 	close(p1);
4101fa1fe8fSJohn Fastabend out:
4111fa1fe8fSJohn Fastabend 	test_sockmap_pass_prog__destroy(skel);
4121fa1fe8fSJohn Fastabend }
4131fa1fe8fSJohn Fastabend 
test_sockmap_skb_verdict_fionread(bool pass_prog)41480e24d22SJohn Fastabend static void test_sockmap_skb_verdict_fionread(bool pass_prog)
415bb516f98SJohn Fastabend {
41680e24d22SJohn Fastabend 	int expected, zero = 0, sent, recvd, avail;
417bb516f98SJohn Fastabend 	int err, map, verdict, s, c0, c1, p0, p1;
41880e24d22SJohn Fastabend 	struct test_sockmap_pass_prog *pass;
41980e24d22SJohn Fastabend 	struct test_sockmap_drop_prog *drop;
420bb516f98SJohn Fastabend 	char buf[256] = "0123456789";
421bb516f98SJohn Fastabend 
42280e24d22SJohn Fastabend 	if (pass_prog) {
42380e24d22SJohn Fastabend 		pass = test_sockmap_pass_prog__open_and_load();
42480e24d22SJohn Fastabend 		if (!ASSERT_OK_PTR(pass, "open_and_load"))
425bb516f98SJohn Fastabend 			return;
42680e24d22SJohn Fastabend 		verdict = bpf_program__fd(pass->progs.prog_skb_verdict);
42780e24d22SJohn Fastabend 		map = bpf_map__fd(pass->maps.sock_map_rx);
42880e24d22SJohn Fastabend 		expected = sizeof(buf);
42980e24d22SJohn Fastabend 	} else {
43080e24d22SJohn Fastabend 		drop = test_sockmap_drop_prog__open_and_load();
43180e24d22SJohn Fastabend 		if (!ASSERT_OK_PTR(drop, "open_and_load"))
43280e24d22SJohn Fastabend 			return;
43380e24d22SJohn Fastabend 		verdict = bpf_program__fd(drop->progs.prog_skb_verdict);
43480e24d22SJohn Fastabend 		map = bpf_map__fd(drop->maps.sock_map_rx);
43580e24d22SJohn Fastabend 		/* On drop data is consumed immediately and copied_seq inc'd */
43680e24d22SJohn Fastabend 		expected = 0;
43780e24d22SJohn Fastabend 	}
438bb516f98SJohn Fastabend 
439bb516f98SJohn Fastabend 
440bb516f98SJohn Fastabend 	err = bpf_prog_attach(verdict, map, BPF_SK_SKB_STREAM_VERDICT, 0);
441bb516f98SJohn Fastabend 	if (!ASSERT_OK(err, "bpf_prog_attach"))
442bb516f98SJohn Fastabend 		goto out;
443bb516f98SJohn Fastabend 
444bb516f98SJohn Fastabend 	s = socket_loopback(AF_INET, SOCK_STREAM);
445bb516f98SJohn Fastabend 	if (!ASSERT_GT(s, -1, "socket_loopback(s)"))
446bb516f98SJohn Fastabend 		goto out;
447bb516f98SJohn Fastabend 	err = create_socket_pairs(s, AF_INET, SOCK_STREAM, &c0, &c1, &p0, &p1);
448bb516f98SJohn Fastabend 	if (!ASSERT_OK(err, "create_socket_pairs(s)"))
449bb516f98SJohn Fastabend 		goto out;
450bb516f98SJohn Fastabend 
451bb516f98SJohn Fastabend 	err = bpf_map_update_elem(map, &zero, &c1, BPF_NOEXIST);
452bb516f98SJohn Fastabend 	if (!ASSERT_OK(err, "bpf_map_update_elem(c1)"))
453bb516f98SJohn Fastabend 		goto out_close;
454bb516f98SJohn Fastabend 
455bb516f98SJohn Fastabend 	sent = xsend(p1, &buf, sizeof(buf), 0);
456bb516f98SJohn Fastabend 	ASSERT_EQ(sent, sizeof(buf), "xsend(p0)");
457bb516f98SJohn Fastabend 	err = ioctl(c1, FIONREAD, &avail);
458bb516f98SJohn Fastabend 	ASSERT_OK(err, "ioctl(FIONREAD) error");
45980e24d22SJohn Fastabend 	ASSERT_EQ(avail, expected, "ioctl(FIONREAD)");
46080e24d22SJohn Fastabend 	/* On DROP test there will be no data to read */
46180e24d22SJohn Fastabend 	if (pass_prog) {
462*dfbaf8a6SJiayuan Chen 		recvd = recv_timeout(c1, &buf, sizeof(buf), MSG_DONTWAIT, IO_TIMEOUT_SEC);
463bb516f98SJohn Fastabend 		ASSERT_EQ(recvd, sizeof(buf), "recv_timeout(c0)");
46480e24d22SJohn Fastabend 	}
465bb516f98SJohn Fastabend 
466bb516f98SJohn Fastabend out_close:
467bb516f98SJohn Fastabend 	close(c0);
468bb516f98SJohn Fastabend 	close(p0);
469bb516f98SJohn Fastabend 	close(c1);
470bb516f98SJohn Fastabend 	close(p1);
471bb516f98SJohn Fastabend out:
47280e24d22SJohn Fastabend 	if (pass_prog)
47380e24d22SJohn Fastabend 		test_sockmap_pass_prog__destroy(pass);
47480e24d22SJohn Fastabend 	else
47580e24d22SJohn Fastabend 		test_sockmap_drop_prog__destroy(drop);
476bb516f98SJohn Fastabend }
477bb516f98SJohn Fastabend 
test_sockmap_skb_verdict_peek(void)4785f405c0cSJohn Fastabend static void test_sockmap_skb_verdict_peek(void)
4795f405c0cSJohn Fastabend {
4805f405c0cSJohn Fastabend 	int err, map, verdict, s, c1, p1, zero = 0, sent, recvd, avail;
4815f405c0cSJohn Fastabend 	struct test_sockmap_pass_prog *pass;
4825f405c0cSJohn Fastabend 	char snd[256] = "0123456789";
4835f405c0cSJohn Fastabend 	char rcv[256] = "0";
4845f405c0cSJohn Fastabend 
4855f405c0cSJohn Fastabend 	pass = test_sockmap_pass_prog__open_and_load();
4865f405c0cSJohn Fastabend 	if (!ASSERT_OK_PTR(pass, "open_and_load"))
4875f405c0cSJohn Fastabend 		return;
4885f405c0cSJohn Fastabend 	verdict = bpf_program__fd(pass->progs.prog_skb_verdict);
4895f405c0cSJohn Fastabend 	map = bpf_map__fd(pass->maps.sock_map_rx);
4905f405c0cSJohn Fastabend 
4915f405c0cSJohn Fastabend 	err = bpf_prog_attach(verdict, map, BPF_SK_SKB_STREAM_VERDICT, 0);
4925f405c0cSJohn Fastabend 	if (!ASSERT_OK(err, "bpf_prog_attach"))
4935f405c0cSJohn Fastabend 		goto out;
4945f405c0cSJohn Fastabend 
4955f405c0cSJohn Fastabend 	s = socket_loopback(AF_INET, SOCK_STREAM);
4965f405c0cSJohn Fastabend 	if (!ASSERT_GT(s, -1, "socket_loopback(s)"))
4975f405c0cSJohn Fastabend 		goto out;
4985f405c0cSJohn Fastabend 
4995f405c0cSJohn Fastabend 	err = create_pair(s, AF_INET, SOCK_STREAM, &c1, &p1);
5005f405c0cSJohn Fastabend 	if (!ASSERT_OK(err, "create_pairs(s)"))
5015f405c0cSJohn Fastabend 		goto out;
5025f405c0cSJohn Fastabend 
5035f405c0cSJohn Fastabend 	err = bpf_map_update_elem(map, &zero, &c1, BPF_NOEXIST);
5045f405c0cSJohn Fastabend 	if (!ASSERT_OK(err, "bpf_map_update_elem(c1)"))
5055f405c0cSJohn Fastabend 		goto out_close;
5065f405c0cSJohn Fastabend 
5075f405c0cSJohn Fastabend 	sent = xsend(p1, snd, sizeof(snd), 0);
5085f405c0cSJohn Fastabend 	ASSERT_EQ(sent, sizeof(snd), "xsend(p1)");
5095f405c0cSJohn Fastabend 	recvd = recv(c1, rcv, sizeof(rcv), MSG_PEEK);
5105f405c0cSJohn Fastabend 	ASSERT_EQ(recvd, sizeof(rcv), "recv(c1)");
5115f405c0cSJohn Fastabend 	err = ioctl(c1, FIONREAD, &avail);
5125f405c0cSJohn Fastabend 	ASSERT_OK(err, "ioctl(FIONREAD) error");
5135f405c0cSJohn Fastabend 	ASSERT_EQ(avail, sizeof(snd), "after peek ioctl(FIONREAD)");
5145f405c0cSJohn Fastabend 	recvd = recv(c1, rcv, sizeof(rcv), 0);
5155f405c0cSJohn Fastabend 	ASSERT_EQ(recvd, sizeof(rcv), "recv(p0)");
5165f405c0cSJohn Fastabend 	err = ioctl(c1, FIONREAD, &avail);
5175f405c0cSJohn Fastabend 	ASSERT_OK(err, "ioctl(FIONREAD) error");
5185f405c0cSJohn Fastabend 	ASSERT_EQ(avail, 0, "after read ioctl(FIONREAD)");
5195f405c0cSJohn Fastabend 
5205f405c0cSJohn Fastabend out_close:
5215f405c0cSJohn Fastabend 	close(c1);
5225f405c0cSJohn Fastabend 	close(p1);
5235f405c0cSJohn Fastabend out:
5245f405c0cSJohn Fastabend 	test_sockmap_pass_prog__destroy(pass);
5255f405c0cSJohn Fastabend }
5265f405c0cSJohn Fastabend 
test_sockmap_basic(void)5275d3919a9SJakub Sitnicki void test_sockmap_basic(void)
5285d3919a9SJakub Sitnicki {
5295d3919a9SJakub Sitnicki 	if (test__start_subtest("sockmap create_update_free"))
5305d3919a9SJakub Sitnicki 		test_sockmap_create_update_free(BPF_MAP_TYPE_SOCKMAP);
5315d3919a9SJakub Sitnicki 	if (test__start_subtest("sockhash create_update_free"))
5325d3919a9SJakub Sitnicki 		test_sockmap_create_update_free(BPF_MAP_TYPE_SOCKHASH);
5331d9c037aSJohn Fastabend 	if (test__start_subtest("sockmap sk_msg load helpers"))
5341d9c037aSJohn Fastabend 		test_skmsg_helpers(BPF_MAP_TYPE_SOCKMAP);
5351d9c037aSJohn Fastabend 	if (test__start_subtest("sockhash sk_msg load helpers"))
5361d9c037aSJohn Fastabend 		test_skmsg_helpers(BPF_MAP_TYPE_SOCKHASH);
537bb23c0e1SLorenz Bauer 	if (test__start_subtest("sockmap update"))
538bb23c0e1SLorenz Bauer 		test_sockmap_update(BPF_MAP_TYPE_SOCKMAP);
539bb23c0e1SLorenz Bauer 	if (test__start_subtest("sockhash update"))
540bb23c0e1SLorenz Bauer 		test_sockmap_update(BPF_MAP_TYPE_SOCKHASH);
541bb23c0e1SLorenz Bauer 	if (test__start_subtest("sockmap update in unsafe context"))
542bb23c0e1SLorenz Bauer 		test_sockmap_invalid_update();
5435b87adc3SLorenz Bauer 	if (test__start_subtest("sockmap copy"))
5445b87adc3SLorenz Bauer 		test_sockmap_copy(BPF_MAP_TYPE_SOCKMAP);
5455b87adc3SLorenz Bauer 	if (test__start_subtest("sockhash copy"))
5465b87adc3SLorenz Bauer 		test_sockmap_copy(BPF_MAP_TYPE_SOCKHASH);
5478d7cb74fSCong Wang 	if (test__start_subtest("sockmap skb_verdict attach")) {
5488d7cb74fSCong Wang 		test_sockmap_skb_verdict_attach(BPF_SK_SKB_VERDICT,
5498d7cb74fSCong Wang 						BPF_SK_SKB_STREAM_VERDICT);
5508d7cb74fSCong Wang 		test_sockmap_skb_verdict_attach(BPF_SK_SKB_STREAM_VERDICT,
5518d7cb74fSCong Wang 						BPF_SK_SKB_VERDICT);
5528d7cb74fSCong Wang 	}
553820e6e22SDi Zhu 	if (test__start_subtest("sockmap msg_verdict progs query"))
554820e6e22SDi Zhu 		test_sockmap_progs_query(BPF_SK_MSG_VERDICT);
555820e6e22SDi Zhu 	if (test__start_subtest("sockmap stream_parser progs query"))
556820e6e22SDi Zhu 		test_sockmap_progs_query(BPF_SK_SKB_STREAM_PARSER);
557820e6e22SDi Zhu 	if (test__start_subtest("sockmap stream_verdict progs query"))
558820e6e22SDi Zhu 		test_sockmap_progs_query(BPF_SK_SKB_STREAM_VERDICT);
559820e6e22SDi Zhu 	if (test__start_subtest("sockmap skb_verdict progs query"))
560820e6e22SDi Zhu 		test_sockmap_progs_query(BPF_SK_SKB_VERDICT);
5611fa1fe8fSJohn Fastabend 	if (test__start_subtest("sockmap skb_verdict shutdown"))
5621fa1fe8fSJohn Fastabend 		test_sockmap_skb_verdict_shutdown();
563bb516f98SJohn Fastabend 	if (test__start_subtest("sockmap skb_verdict fionread"))
56480e24d22SJohn Fastabend 		test_sockmap_skb_verdict_fionread(true);
56580e24d22SJohn Fastabend 	if (test__start_subtest("sockmap skb_verdict fionread on drop"))
56680e24d22SJohn Fastabend 		test_sockmap_skb_verdict_fionread(false);
5675f405c0cSJohn Fastabend 	if (test__start_subtest("sockmap skb_verdict msg_f_peek"))
5685f405c0cSJohn Fastabend 		test_sockmap_skb_verdict_peek();
5695d3919a9SJakub Sitnicki }
570