]> Git Repo - J-linux.git/blob - tools/testing/selftests/bpf/prog_tests/ip_check_defrag.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 / ip_check_defrag.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include <test_progs.h>
3 #include <net/if.h>
4 #include <linux/netfilter.h>
5 #include <network_helpers.h>
6 #include "ip_check_defrag.skel.h"
7 #include "ip_check_defrag_frags.h"
8
9 /*
10  * This selftest spins up a client and an echo server, each in their own
11  * network namespace. The client will send a fragmented message to the server.
12  * The prog attached to the server will shoot down any fragments. Thus, if
13  * the server is able to correctly echo back the message to the client, we will
14  * have verified that netfilter is reassembling packets for us.
15  *
16  * Topology:
17  * =========
18  *           NS0         |         NS1
19  *                       |
20  *         client        |       server
21  *       ----------      |     ----------
22  *       |  veth0  | --------- |  veth1  |
23  *       ----------    peer    ----------
24  *                       |
25  *                       |       with bpf
26  */
27
28 #define NS0             "defrag_ns0"
29 #define NS1             "defrag_ns1"
30 #define VETH0           "veth0"
31 #define VETH1           "veth1"
32 #define VETH0_ADDR      "172.16.1.100"
33 #define VETH0_ADDR6     "fc00::100"
34 /* The following constants must stay in sync with `generate_udp_fragments.py` */
35 #define VETH1_ADDR      "172.16.1.200"
36 #define VETH1_ADDR6     "fc00::200"
37 #define CLIENT_PORT     48878
38 #define SERVER_PORT     48879
39 #define MAGIC_MESSAGE   "THIS IS THE ORIGINAL MESSAGE, PLEASE REASSEMBLE ME"
40
41 static int setup_topology(bool ipv6)
42 {
43         bool up;
44         int i;
45
46         SYS(fail, "ip netns add " NS0);
47         SYS(fail, "ip netns add " NS1);
48         SYS(fail, "ip link add " VETH0 " netns " NS0 " type veth peer name " VETH1 " netns " NS1);
49         if (ipv6) {
50                 SYS(fail, "ip -6 -net " NS0 " addr add " VETH0_ADDR6 "/64 dev " VETH0 " nodad");
51                 SYS(fail, "ip -6 -net " NS1 " addr add " VETH1_ADDR6 "/64 dev " VETH1 " nodad");
52         } else {
53                 SYS(fail, "ip -net " NS0 " addr add " VETH0_ADDR "/24 dev " VETH0);
54                 SYS(fail, "ip -net " NS1 " addr add " VETH1_ADDR "/24 dev " VETH1);
55         }
56         SYS(fail, "ip -net " NS0 " link set dev " VETH0 " up");
57         SYS(fail, "ip -net " NS1 " link set dev " VETH1 " up");
58
59         /* Wait for up to 5s for links to come up */
60         for (i = 0; i < 5; ++i) {
61                 if (ipv6)
62                         up = !SYS_NOFAIL("ip netns exec " NS0 " ping -6 -c 1 -W 1 " VETH1_ADDR6);
63                 else
64                         up = !SYS_NOFAIL("ip netns exec " NS0 " ping -c 1 -W 1 " VETH1_ADDR);
65
66                 if (up)
67                         break;
68         }
69
70         return 0;
71 fail:
72         return -1;
73 }
74
75 static void cleanup_topology(void)
76 {
77         SYS_NOFAIL("test -f /var/run/netns/" NS0 " && ip netns delete " NS0);
78         SYS_NOFAIL("test -f /var/run/netns/" NS1 " && ip netns delete " NS1);
79 }
80
81 static int attach(struct ip_check_defrag *skel, bool ipv6)
82 {
83         LIBBPF_OPTS(bpf_netfilter_opts, opts,
84                     .pf = ipv6 ? NFPROTO_IPV6 : NFPROTO_IPV4,
85                     .priority = 42,
86                     .flags = BPF_F_NETFILTER_IP_DEFRAG);
87         struct nstoken *nstoken;
88         int err = -1;
89
90         nstoken = open_netns(NS1);
91         if (!ASSERT_OK_PTR(nstoken, "setns"))
92                 goto out;
93
94         skel->links.defrag = bpf_program__attach_netfilter(skel->progs.defrag, &opts);
95         if (!ASSERT_OK_PTR(skel->links.defrag, "program attach"))
96                 goto out;
97
98         err = 0;
99 out:
100         close_netns(nstoken);
101         return err;
102 }
103
104 static int send_frags(int client)
105 {
106         struct sockaddr_storage saddr;
107         struct sockaddr *saddr_p;
108         socklen_t saddr_len;
109         int err;
110
111         saddr_p = (struct sockaddr *)&saddr;
112         err = make_sockaddr(AF_INET, VETH1_ADDR, SERVER_PORT, &saddr, &saddr_len);
113         if (!ASSERT_OK(err, "make_sockaddr"))
114                 return -1;
115
116         err = sendto(client, frag_0, sizeof(frag_0), 0, saddr_p, saddr_len);
117         if (!ASSERT_GE(err, 0, "sendto frag_0"))
118                 return -1;
119
120         err = sendto(client, frag_1, sizeof(frag_1), 0, saddr_p, saddr_len);
121         if (!ASSERT_GE(err, 0, "sendto frag_1"))
122                 return -1;
123
124         err = sendto(client, frag_2, sizeof(frag_2), 0, saddr_p, saddr_len);
125         if (!ASSERT_GE(err, 0, "sendto frag_2"))
126                 return -1;
127
128         return 0;
129 }
130
131 static int send_frags6(int client)
132 {
133         struct sockaddr_storage saddr;
134         struct sockaddr *saddr_p;
135         socklen_t saddr_len;
136         int err;
137
138         saddr_p = (struct sockaddr *)&saddr;
139         /* Port needs to be set to 0 for raw ipv6 socket for some reason */
140         err = make_sockaddr(AF_INET6, VETH1_ADDR6, 0, &saddr, &saddr_len);
141         if (!ASSERT_OK(err, "make_sockaddr"))
142                 return -1;
143
144         err = sendto(client, frag6_0, sizeof(frag6_0), 0, saddr_p, saddr_len);
145         if (!ASSERT_GE(err, 0, "sendto frag6_0"))
146                 return -1;
147
148         err = sendto(client, frag6_1, sizeof(frag6_1), 0, saddr_p, saddr_len);
149         if (!ASSERT_GE(err, 0, "sendto frag6_1"))
150                 return -1;
151
152         err = sendto(client, frag6_2, sizeof(frag6_2), 0, saddr_p, saddr_len);
153         if (!ASSERT_GE(err, 0, "sendto frag6_2"))
154                 return -1;
155
156         return 0;
157 }
158
159 void test_bpf_ip_check_defrag_ok(bool ipv6)
160 {
161         int family = ipv6 ? AF_INET6 : AF_INET;
162         struct network_helper_opts rx_opts = {
163                 .timeout_ms = 1000,
164         };
165         struct network_helper_opts tx_ops = {
166                 .timeout_ms = 1000,
167                 .proto = IPPROTO_RAW,
168         };
169         struct sockaddr_storage caddr;
170         struct ip_check_defrag *skel;
171         struct nstoken *nstoken;
172         int client_tx_fd = -1;
173         int client_rx_fd = -1;
174         socklen_t caddr_len;
175         int srv_fd = -1;
176         char buf[1024];
177         int len, err;
178
179         skel = ip_check_defrag__open_and_load();
180         if (!ASSERT_OK_PTR(skel, "skel_open"))
181                 return;
182
183         if (!ASSERT_OK(setup_topology(ipv6), "setup_topology"))
184                 goto out;
185
186         if (!ASSERT_OK(attach(skel, ipv6), "attach"))
187                 goto out;
188
189         /* Start server in ns1 */
190         nstoken = open_netns(NS1);
191         if (!ASSERT_OK_PTR(nstoken, "setns ns1"))
192                 goto out;
193         srv_fd = start_server(family, SOCK_DGRAM, NULL, SERVER_PORT, 0);
194         close_netns(nstoken);
195         if (!ASSERT_GE(srv_fd, 0, "start_server"))
196                 goto out;
197
198         /* Open tx raw socket in ns0 */
199         nstoken = open_netns(NS0);
200         if (!ASSERT_OK_PTR(nstoken, "setns ns0"))
201                 goto out;
202         client_tx_fd = client_socket(family, SOCK_RAW, &tx_ops);
203         close_netns(nstoken);
204         if (!ASSERT_GE(client_tx_fd, 0, "client_socket"))
205                 goto out;
206
207         /* Open rx socket in ns0 */
208         nstoken = open_netns(NS0);
209         if (!ASSERT_OK_PTR(nstoken, "setns ns0"))
210                 goto out;
211         client_rx_fd = client_socket(family, SOCK_DGRAM, &rx_opts);
212         close_netns(nstoken);
213         if (!ASSERT_GE(client_rx_fd, 0, "client_socket"))
214                 goto out;
215
216         /* Bind rx socket to a premeditated port */
217         memset(&caddr, 0, sizeof(caddr));
218         nstoken = open_netns(NS0);
219         if (!ASSERT_OK_PTR(nstoken, "setns ns0"))
220                 goto out;
221         if (ipv6) {
222                 struct sockaddr_in6 *c = (struct sockaddr_in6 *)&caddr;
223
224                 c->sin6_family = AF_INET6;
225                 inet_pton(AF_INET6, VETH0_ADDR6, &c->sin6_addr);
226                 c->sin6_port = htons(CLIENT_PORT);
227                 err = bind(client_rx_fd, (struct sockaddr *)c, sizeof(*c));
228         } else {
229                 struct sockaddr_in *c = (struct sockaddr_in *)&caddr;
230
231                 c->sin_family = AF_INET;
232                 inet_pton(AF_INET, VETH0_ADDR, &c->sin_addr);
233                 c->sin_port = htons(CLIENT_PORT);
234                 err = bind(client_rx_fd, (struct sockaddr *)c, sizeof(*c));
235         }
236         close_netns(nstoken);
237         if (!ASSERT_OK(err, "bind"))
238                 goto out;
239
240         /* Send message in fragments */
241         if (ipv6) {
242                 if (!ASSERT_OK(send_frags6(client_tx_fd), "send_frags6"))
243                         goto out;
244         } else {
245                 if (!ASSERT_OK(send_frags(client_tx_fd), "send_frags"))
246                         goto out;
247         }
248
249         if (!ASSERT_EQ(skel->bss->shootdowns, 0, "shootdowns"))
250                 goto out;
251
252         /* Receive reassembled msg on server and echo back to client */
253         caddr_len = sizeof(caddr);
254         len = recvfrom(srv_fd, buf, sizeof(buf), 0, (struct sockaddr *)&caddr, &caddr_len);
255         if (!ASSERT_GE(len, 0, "server recvfrom"))
256                 goto out;
257         len = sendto(srv_fd, buf, len, 0, (struct sockaddr *)&caddr, caddr_len);
258         if (!ASSERT_GE(len, 0, "server sendto"))
259                 goto out;
260
261         /* Expect reassembed message to be echoed back */
262         len = recvfrom(client_rx_fd, buf, sizeof(buf), 0, NULL, NULL);
263         if (!ASSERT_EQ(len, sizeof(MAGIC_MESSAGE) - 1, "client short read"))
264                 goto out;
265
266 out:
267         if (client_rx_fd != -1)
268                 close(client_rx_fd);
269         if (client_tx_fd != -1)
270                 close(client_tx_fd);
271         if (srv_fd != -1)
272                 close(srv_fd);
273         cleanup_topology();
274         ip_check_defrag__destroy(skel);
275 }
276
277 void test_bpf_ip_check_defrag(void)
278 {
279         if (test__start_subtest("v4"))
280                 test_bpf_ip_check_defrag_ok(false);
281         if (test__start_subtest("v6"))
282                 test_bpf_ip_check_defrag_ok(true);
283 }
This page took 0.043703 seconds and 4 git commands to generate.