]> Git Repo - J-linux.git/blob - tools/testing/selftests/bpf/prog_tests/assign_reuse.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / tools / testing / selftests / bpf / prog_tests / assign_reuse.c
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
16 static 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
22 static __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
35 static 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
61 static 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
82 void 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");
160 cleanup:
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
174 void 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
194 cleanup:
195         close_netns(tok);
196         SYS_NOFAIL("ip netns delete %s", NS_TEST);
197 out:
198         return;
199 }
This page took 0.037378 seconds and 4 git commands to generate.