Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) 2023 Isovalent */
  3#include <uapi/linux/if_link.h>
  4#include <test_progs.h>
  5
  6#include <netinet/tcp.h>
  7#include <netinet/udp.h>
  8
  9#include "network_helpers.h"
 10#include "test_assign_reuse.skel.h"
 11
 12#define NS_TEST "assign_reuse"
 13#define LOOPBACK 1
 14#define PORT 4443
 15
 16static int attach_reuseport(int sock_fd, int prog_fd)
 17{
 18	return setsockopt(sock_fd, SOL_SOCKET, SO_ATTACH_REUSEPORT_EBPF,
 19			  &prog_fd, sizeof(prog_fd));
 20}
 21
 22static __u64 cookie(int fd)
 23{
 24	__u64 cookie = 0;
 25	socklen_t cookie_len = sizeof(cookie);
 26	int ret;
 27
 28	ret = getsockopt(fd, SOL_SOCKET, SO_COOKIE, &cookie, &cookie_len);
 29	ASSERT_OK(ret, "cookie");
 30	ASSERT_GT(cookie, 0, "cookie_invalid");
 31
 32	return cookie;
 33}
 34
 35static int echo_test_udp(int fd_sv)
 36{
 37	struct sockaddr_storage addr = {};
 38	socklen_t len = sizeof(addr);
 39	char buff[1] = {};
 40	int fd_cl = -1, ret;
 41
 42	fd_cl = connect_to_fd(fd_sv, 100);
 43	ASSERT_GT(fd_cl, 0, "create_client");
 44	ASSERT_EQ(getsockname(fd_cl, (void *)&addr, &len), 0, "getsockname");
 45
 46	ASSERT_EQ(send(fd_cl, buff, sizeof(buff), 0), 1, "send_client");
 47
 48	ret = recv(fd_sv, buff, sizeof(buff), 0);
 49	if (ret < 0) {
 50		close(fd_cl);
 51		return errno;
 52	}
 53
 54	ASSERT_EQ(ret, 1, "recv_server");
 55	ASSERT_EQ(sendto(fd_sv, buff, sizeof(buff), 0, (void *)&addr, len), 1, "send_server");
 56	ASSERT_EQ(recv(fd_cl, buff, sizeof(buff), 0), 1, "recv_client");
 57	close(fd_cl);
 58	return 0;
 59}
 60
 61static int echo_test_tcp(int fd_sv)
 62{
 63	char buff[1] = {};
 64	int fd_cl = -1, fd_sv_cl = -1;
 65
 66	fd_cl = connect_to_fd(fd_sv, 100);
 67	if (fd_cl < 0)
 68		return errno;
 69
 70	fd_sv_cl = accept(fd_sv, NULL, NULL);
 71	ASSERT_GE(fd_sv_cl, 0, "accept_fd");
 72
 73	ASSERT_EQ(send(fd_cl, buff, sizeof(buff), 0), 1, "send_client");
 74	ASSERT_EQ(recv(fd_sv_cl, buff, sizeof(buff), 0), 1, "recv_server");
 75	ASSERT_EQ(send(fd_sv_cl, buff, sizeof(buff), 0), 1, "send_server");
 76	ASSERT_EQ(recv(fd_cl, buff, sizeof(buff), 0), 1, "recv_client");
 77	close(fd_sv_cl);
 78	close(fd_cl);
 79	return 0;
 80}
 81
 82void run_assign_reuse(int family, int sotype, const char *ip, __u16 port)
 83{
 84	DECLARE_LIBBPF_OPTS(bpf_tc_hook, tc_hook,
 85		.ifindex = LOOPBACK,
 86		.attach_point = BPF_TC_INGRESS,
 87	);
 88	DECLARE_LIBBPF_OPTS(bpf_tc_opts, tc_opts,
 89		.handle = 1,
 90		.priority = 1,
 91	);
 92	bool hook_created = false, tc_attached = false;
 93	int ret, fd_tc, fd_accept, fd_drop, fd_map;
 94	int *fd_sv = NULL;
 95	__u64 fd_val;
 96	struct test_assign_reuse *skel;
 97	const int zero = 0;
 98
 99	skel = test_assign_reuse__open();
100	if (!ASSERT_OK_PTR(skel, "skel_open"))
101		goto cleanup;
102
103	skel->rodata->dest_port = port;
104
105	ret = test_assign_reuse__load(skel);
106	if (!ASSERT_OK(ret, "skel_load"))
107		goto cleanup;
108
109	ASSERT_EQ(skel->bss->sk_cookie_seen, 0, "cookie_init");
110
111	fd_tc = bpf_program__fd(skel->progs.tc_main);
112	fd_accept = bpf_program__fd(skel->progs.reuse_accept);
113	fd_drop = bpf_program__fd(skel->progs.reuse_drop);
114	fd_map = bpf_map__fd(skel->maps.sk_map);
115
116	fd_sv = start_reuseport_server(family, sotype, ip, port, 100, 1);
117	if (!ASSERT_NEQ(fd_sv, NULL, "start_reuseport_server"))
118		goto cleanup;
119
120	ret = attach_reuseport(*fd_sv, fd_drop);
121	if (!ASSERT_OK(ret, "attach_reuseport"))
122		goto cleanup;
123
124	fd_val = *fd_sv;
125	ret = bpf_map_update_elem(fd_map, &zero, &fd_val, BPF_NOEXIST);
126	if (!ASSERT_OK(ret, "bpf_sk_map"))
127		goto cleanup;
128
129	ret = bpf_tc_hook_create(&tc_hook);
130	if (ret == 0)
131		hook_created = true;
132	ret = ret == -EEXIST ? 0 : ret;
133	if (!ASSERT_OK(ret, "bpf_tc_hook_create"))
134		goto cleanup;
135
136	tc_opts.prog_fd = fd_tc;
137	ret = bpf_tc_attach(&tc_hook, &tc_opts);
138	if (!ASSERT_OK(ret, "bpf_tc_attach"))
139		goto cleanup;
140	tc_attached = true;
141
142	if (sotype == SOCK_STREAM)
143		ASSERT_EQ(echo_test_tcp(*fd_sv), ECONNREFUSED, "drop_tcp");
144	else
145		ASSERT_EQ(echo_test_udp(*fd_sv), EAGAIN, "drop_udp");
146	ASSERT_EQ(skel->bss->reuseport_executed, 1, "program executed once");
147
148	skel->bss->sk_cookie_seen = 0;
149	skel->bss->reuseport_executed = 0;
150	ASSERT_OK(attach_reuseport(*fd_sv, fd_accept), "attach_reuseport(accept)");
151
152	if (sotype == SOCK_STREAM)
153		ASSERT_EQ(echo_test_tcp(*fd_sv), 0, "echo_tcp");
154	else
155		ASSERT_EQ(echo_test_udp(*fd_sv), 0, "echo_udp");
156
157	ASSERT_EQ(skel->bss->sk_cookie_seen, cookie(*fd_sv),
158		  "cookie_mismatch");
159	ASSERT_EQ(skel->bss->reuseport_executed, 1, "program executed once");
160cleanup:
161	if (tc_attached) {
162		tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;
163		ret = bpf_tc_detach(&tc_hook, &tc_opts);
164		ASSERT_OK(ret, "bpf_tc_detach");
165	}
166	if (hook_created) {
167		tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;
168		bpf_tc_hook_destroy(&tc_hook);
169	}
170	test_assign_reuse__destroy(skel);
171	free_fds(fd_sv, 1);
172}
173
174void test_assign_reuse(void)
175{
176	struct nstoken *tok = NULL;
177
178	SYS(out, "ip netns add %s", NS_TEST);
179	SYS(cleanup, "ip -net %s link set dev lo up", NS_TEST);
180
181	tok = open_netns(NS_TEST);
182	if (!ASSERT_OK_PTR(tok, "netns token"))
183		return;
184
185	if (test__start_subtest("tcpv4"))
186		run_assign_reuse(AF_INET, SOCK_STREAM, "127.0.0.1", PORT);
187	if (test__start_subtest("tcpv6"))
188		run_assign_reuse(AF_INET6, SOCK_STREAM, "::1", PORT);
189	if (test__start_subtest("udpv4"))
190		run_assign_reuse(AF_INET, SOCK_DGRAM, "127.0.0.1", PORT);
191	if (test__start_subtest("udpv6"))
192		run_assign_reuse(AF_INET6, SOCK_DGRAM, "::1", PORT);
193
194cleanup:
195	close_netns(tok);
196	SYS_NOFAIL("ip netns delete %s", NS_TEST);
197out:
198	return;
199}
v6.9.4
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) 2023 Isovalent */
  3#include <uapi/linux/if_link.h>
  4#include <test_progs.h>
  5
  6#include <netinet/tcp.h>
  7#include <netinet/udp.h>
  8
  9#include "network_helpers.h"
 10#include "test_assign_reuse.skel.h"
 11
 12#define NS_TEST "assign_reuse"
 13#define LOOPBACK 1
 14#define PORT 4443
 15
 16static int attach_reuseport(int sock_fd, int prog_fd)
 17{
 18	return setsockopt(sock_fd, SOL_SOCKET, SO_ATTACH_REUSEPORT_EBPF,
 19			  &prog_fd, sizeof(prog_fd));
 20}
 21
 22static __u64 cookie(int fd)
 23{
 24	__u64 cookie = 0;
 25	socklen_t cookie_len = sizeof(cookie);
 26	int ret;
 27
 28	ret = getsockopt(fd, SOL_SOCKET, SO_COOKIE, &cookie, &cookie_len);
 29	ASSERT_OK(ret, "cookie");
 30	ASSERT_GT(cookie, 0, "cookie_invalid");
 31
 32	return cookie;
 33}
 34
 35static int echo_test_udp(int fd_sv)
 36{
 37	struct sockaddr_storage addr = {};
 38	socklen_t len = sizeof(addr);
 39	char buff[1] = {};
 40	int fd_cl = -1, ret;
 41
 42	fd_cl = connect_to_fd(fd_sv, 100);
 43	ASSERT_GT(fd_cl, 0, "create_client");
 44	ASSERT_EQ(getsockname(fd_cl, (void *)&addr, &len), 0, "getsockname");
 45
 46	ASSERT_EQ(send(fd_cl, buff, sizeof(buff), 0), 1, "send_client");
 47
 48	ret = recv(fd_sv, buff, sizeof(buff), 0);
 49	if (ret < 0) {
 50		close(fd_cl);
 51		return errno;
 52	}
 53
 54	ASSERT_EQ(ret, 1, "recv_server");
 55	ASSERT_EQ(sendto(fd_sv, buff, sizeof(buff), 0, (void *)&addr, len), 1, "send_server");
 56	ASSERT_EQ(recv(fd_cl, buff, sizeof(buff), 0), 1, "recv_client");
 57	close(fd_cl);
 58	return 0;
 59}
 60
 61static int echo_test_tcp(int fd_sv)
 62{
 63	char buff[1] = {};
 64	int fd_cl = -1, fd_sv_cl = -1;
 65
 66	fd_cl = connect_to_fd(fd_sv, 100);
 67	if (fd_cl < 0)
 68		return errno;
 69
 70	fd_sv_cl = accept(fd_sv, NULL, NULL);
 71	ASSERT_GE(fd_sv_cl, 0, "accept_fd");
 72
 73	ASSERT_EQ(send(fd_cl, buff, sizeof(buff), 0), 1, "send_client");
 74	ASSERT_EQ(recv(fd_sv_cl, buff, sizeof(buff), 0), 1, "recv_server");
 75	ASSERT_EQ(send(fd_sv_cl, buff, sizeof(buff), 0), 1, "send_server");
 76	ASSERT_EQ(recv(fd_cl, buff, sizeof(buff), 0), 1, "recv_client");
 77	close(fd_sv_cl);
 78	close(fd_cl);
 79	return 0;
 80}
 81
 82void run_assign_reuse(int family, int sotype, const char *ip, __u16 port)
 83{
 84	DECLARE_LIBBPF_OPTS(bpf_tc_hook, tc_hook,
 85		.ifindex = LOOPBACK,
 86		.attach_point = BPF_TC_INGRESS,
 87	);
 88	DECLARE_LIBBPF_OPTS(bpf_tc_opts, tc_opts,
 89		.handle = 1,
 90		.priority = 1,
 91	);
 92	bool hook_created = false, tc_attached = false;
 93	int ret, fd_tc, fd_accept, fd_drop, fd_map;
 94	int *fd_sv = NULL;
 95	__u64 fd_val;
 96	struct test_assign_reuse *skel;
 97	const int zero = 0;
 98
 99	skel = test_assign_reuse__open();
100	if (!ASSERT_OK_PTR(skel, "skel_open"))
101		goto cleanup;
102
103	skel->rodata->dest_port = port;
104
105	ret = test_assign_reuse__load(skel);
106	if (!ASSERT_OK(ret, "skel_load"))
107		goto cleanup;
108
109	ASSERT_EQ(skel->bss->sk_cookie_seen, 0, "cookie_init");
110
111	fd_tc = bpf_program__fd(skel->progs.tc_main);
112	fd_accept = bpf_program__fd(skel->progs.reuse_accept);
113	fd_drop = bpf_program__fd(skel->progs.reuse_drop);
114	fd_map = bpf_map__fd(skel->maps.sk_map);
115
116	fd_sv = start_reuseport_server(family, sotype, ip, port, 100, 1);
117	if (!ASSERT_NEQ(fd_sv, NULL, "start_reuseport_server"))
118		goto cleanup;
119
120	ret = attach_reuseport(*fd_sv, fd_drop);
121	if (!ASSERT_OK(ret, "attach_reuseport"))
122		goto cleanup;
123
124	fd_val = *fd_sv;
125	ret = bpf_map_update_elem(fd_map, &zero, &fd_val, BPF_NOEXIST);
126	if (!ASSERT_OK(ret, "bpf_sk_map"))
127		goto cleanup;
128
129	ret = bpf_tc_hook_create(&tc_hook);
130	if (ret == 0)
131		hook_created = true;
132	ret = ret == -EEXIST ? 0 : ret;
133	if (!ASSERT_OK(ret, "bpf_tc_hook_create"))
134		goto cleanup;
135
136	tc_opts.prog_fd = fd_tc;
137	ret = bpf_tc_attach(&tc_hook, &tc_opts);
138	if (!ASSERT_OK(ret, "bpf_tc_attach"))
139		goto cleanup;
140	tc_attached = true;
141
142	if (sotype == SOCK_STREAM)
143		ASSERT_EQ(echo_test_tcp(*fd_sv), ECONNREFUSED, "drop_tcp");
144	else
145		ASSERT_EQ(echo_test_udp(*fd_sv), EAGAIN, "drop_udp");
146	ASSERT_EQ(skel->bss->reuseport_executed, 1, "program executed once");
147
148	skel->bss->sk_cookie_seen = 0;
149	skel->bss->reuseport_executed = 0;
150	ASSERT_OK(attach_reuseport(*fd_sv, fd_accept), "attach_reuseport(accept)");
151
152	if (sotype == SOCK_STREAM)
153		ASSERT_EQ(echo_test_tcp(*fd_sv), 0, "echo_tcp");
154	else
155		ASSERT_EQ(echo_test_udp(*fd_sv), 0, "echo_udp");
156
157	ASSERT_EQ(skel->bss->sk_cookie_seen, cookie(*fd_sv),
158		  "cookie_mismatch");
159	ASSERT_EQ(skel->bss->reuseport_executed, 1, "program executed once");
160cleanup:
161	if (tc_attached) {
162		tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;
163		ret = bpf_tc_detach(&tc_hook, &tc_opts);
164		ASSERT_OK(ret, "bpf_tc_detach");
165	}
166	if (hook_created) {
167		tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;
168		bpf_tc_hook_destroy(&tc_hook);
169	}
170	test_assign_reuse__destroy(skel);
171	free_fds(fd_sv, 1);
172}
173
174void test_assign_reuse(void)
175{
176	struct nstoken *tok = NULL;
177
178	SYS(out, "ip netns add %s", NS_TEST);
179	SYS(cleanup, "ip -net %s link set dev lo up", NS_TEST);
180
181	tok = open_netns(NS_TEST);
182	if (!ASSERT_OK_PTR(tok, "netns token"))
183		return;
184
185	if (test__start_subtest("tcpv4"))
186		run_assign_reuse(AF_INET, SOCK_STREAM, "127.0.0.1", PORT);
187	if (test__start_subtest("tcpv6"))
188		run_assign_reuse(AF_INET6, SOCK_STREAM, "::1", PORT);
189	if (test__start_subtest("udpv4"))
190		run_assign_reuse(AF_INET, SOCK_DGRAM, "127.0.0.1", PORT);
191	if (test__start_subtest("udpv6"))
192		run_assign_reuse(AF_INET6, SOCK_DGRAM, "::1", PORT);
193
194cleanup:
195	close_netns(tok);
196	SYS_NOFAIL("ip netns delete %s", NS_TEST);
197out:
198	return;
199}