~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/bpf/prog_tests/cgroup_tcp_skb.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /* Copyright (c) 2023 Facebook */
  3 #include <test_progs.h>
  4 #include <linux/in6.h>
  5 #include <sys/socket.h>
  6 #include <sched.h>
  7 #include <unistd.h>
  8 #include "cgroup_helpers.h"
  9 #include "testing_helpers.h"
 10 #include "cgroup_tcp_skb.skel.h"
 11 #include "cgroup_tcp_skb.h"
 12 #include "network_helpers.h"
 13 
 14 #define CGROUP_TCP_SKB_PATH "/test_cgroup_tcp_skb"
 15 
 16 static int install_filters(int cgroup_fd,
 17                            struct bpf_link **egress_link,
 18                            struct bpf_link **ingress_link,
 19                            struct bpf_program *egress_prog,
 20                            struct bpf_program *ingress_prog,
 21                            struct cgroup_tcp_skb *skel)
 22 {
 23         /* Prepare filters */
 24         skel->bss->g_sock_state = 0;
 25         skel->bss->g_unexpected = 0;
 26         *egress_link =
 27                 bpf_program__attach_cgroup(egress_prog,
 28                                            cgroup_fd);
 29         if (!ASSERT_OK_PTR(egress_link, "egress_link"))
 30                 return -1;
 31         *ingress_link =
 32                 bpf_program__attach_cgroup(ingress_prog,
 33                                            cgroup_fd);
 34         if (!ASSERT_OK_PTR(ingress_link, "ingress_link"))
 35                 return -1;
 36 
 37         return 0;
 38 }
 39 
 40 static void uninstall_filters(struct bpf_link **egress_link,
 41                               struct bpf_link **ingress_link)
 42 {
 43         bpf_link__destroy(*egress_link);
 44         *egress_link = NULL;
 45         bpf_link__destroy(*ingress_link);
 46         *ingress_link = NULL;
 47 }
 48 
 49 static int create_client_sock_v6(void)
 50 {
 51         int fd;
 52 
 53         fd = socket(AF_INET6, SOCK_STREAM, 0);
 54         if (fd < 0) {
 55                 perror("socket");
 56                 return -1;
 57         }
 58 
 59         return fd;
 60 }
 61 
 62 /* Connect to the server in a cgroup from the outside of the cgroup. */
 63 static int talk_to_cgroup(int *client_fd, int *listen_fd, int *service_fd,
 64                           struct cgroup_tcp_skb *skel)
 65 {
 66         int err, cp;
 67         char buf[5];
 68         int port;
 69 
 70         /* Create client & server socket */
 71         err = join_root_cgroup();
 72         if (!ASSERT_OK(err, "join_root_cgroup"))
 73                 return -1;
 74         *client_fd = create_client_sock_v6();
 75         if (!ASSERT_GE(*client_fd, 0, "client_fd"))
 76                 return -1;
 77         err = join_cgroup(CGROUP_TCP_SKB_PATH);
 78         if (!ASSERT_OK(err, "join_cgroup"))
 79                 return -1;
 80         *listen_fd = start_server(AF_INET6, SOCK_STREAM, NULL, 0, 0);
 81         if (!ASSERT_GE(*listen_fd, 0, "listen_fd"))
 82                 return -1;
 83         port = get_socket_local_port(*listen_fd);
 84         if (!ASSERT_GE(port, 0, "get_socket_local_port"))
 85                 return -1;
 86         skel->bss->g_sock_port = ntohs(port);
 87 
 88         /* Connect client to server */
 89         err = connect_fd_to_fd(*client_fd, *listen_fd, 0);
 90         if (!ASSERT_OK(err, "connect_fd_to_fd"))
 91                 return -1;
 92         *service_fd = accept(*listen_fd, NULL, NULL);
 93         if (!ASSERT_GE(*service_fd, 0, "service_fd"))
 94                 return -1;
 95         err = join_root_cgroup();
 96         if (!ASSERT_OK(err, "join_root_cgroup"))
 97                 return -1;
 98         cp = write(*client_fd, "hello", 5);
 99         if (!ASSERT_EQ(cp, 5, "write"))
100                 return -1;
101         cp = read(*service_fd, buf, 5);
102         if (!ASSERT_EQ(cp, 5, "read"))
103                 return -1;
104 
105         return 0;
106 }
107 
108 /* Connect to the server out of a cgroup from inside the cgroup. */
109 static int talk_to_outside(int *client_fd, int *listen_fd, int *service_fd,
110                            struct cgroup_tcp_skb *skel)
111 
112 {
113         int err, cp;
114         char buf[5];
115         int port;
116 
117         /* Create client & server socket */
118         err = join_root_cgroup();
119         if (!ASSERT_OK(err, "join_root_cgroup"))
120                 return -1;
121         *listen_fd = start_server(AF_INET6, SOCK_STREAM, NULL, 0, 0);
122         if (!ASSERT_GE(*listen_fd, 0, "listen_fd"))
123                 return -1;
124         err = join_cgroup(CGROUP_TCP_SKB_PATH);
125         if (!ASSERT_OK(err, "join_cgroup"))
126                 return -1;
127         *client_fd = create_client_sock_v6();
128         if (!ASSERT_GE(*client_fd, 0, "client_fd"))
129                 return -1;
130         err = join_root_cgroup();
131         if (!ASSERT_OK(err, "join_root_cgroup"))
132                 return -1;
133         port = get_socket_local_port(*listen_fd);
134         if (!ASSERT_GE(port, 0, "get_socket_local_port"))
135                 return -1;
136         skel->bss->g_sock_port = ntohs(port);
137 
138         /* Connect client to server */
139         err = connect_fd_to_fd(*client_fd, *listen_fd, 0);
140         if (!ASSERT_OK(err, "connect_fd_to_fd"))
141                 return -1;
142         *service_fd = accept(*listen_fd, NULL, NULL);
143         if (!ASSERT_GE(*service_fd, 0, "service_fd"))
144                 return -1;
145         cp = write(*client_fd, "hello", 5);
146         if (!ASSERT_EQ(cp, 5, "write"))
147                 return -1;
148         cp = read(*service_fd, buf, 5);
149         if (!ASSERT_EQ(cp, 5, "read"))
150                 return -1;
151 
152         return 0;
153 }
154 
155 static int close_connection(int *closing_fd, int *peer_fd, int *listen_fd,
156                             struct cgroup_tcp_skb *skel)
157 {
158         __u32 saved_packet_count = 0;
159         int err;
160         int i;
161 
162         /* Wait for ACKs to be sent */
163         saved_packet_count = skel->bss->g_packet_count;
164         usleep(100000);         /* 0.1s */
165         for (i = 0;
166              skel->bss->g_packet_count != saved_packet_count && i < 10;
167              i++) {
168                 saved_packet_count = skel->bss->g_packet_count;
169                 usleep(100000); /* 0.1s */
170         }
171         if (!ASSERT_EQ(skel->bss->g_packet_count, saved_packet_count,
172                        "packet_count"))
173                 return -1;
174 
175         skel->bss->g_packet_count = 0;
176         saved_packet_count = 0;
177 
178         /* Half shutdown to make sure the closing socket having a chance to
179          * receive a FIN from the peer.
180          */
181         err = shutdown(*closing_fd, SHUT_WR);
182         if (!ASSERT_OK(err, "shutdown closing_fd"))
183                 return -1;
184 
185         /* Wait for FIN and the ACK of the FIN to be observed */
186         for (i = 0;
187              skel->bss->g_packet_count < saved_packet_count + 2 && i < 10;
188              i++)
189                 usleep(100000); /* 0.1s */
190         if (!ASSERT_GE(skel->bss->g_packet_count, saved_packet_count + 2,
191                        "packet_count"))
192                 return -1;
193 
194         saved_packet_count = skel->bss->g_packet_count;
195 
196         /* Fully shutdown the connection */
197         err = close(*peer_fd);
198         if (!ASSERT_OK(err, "close peer_fd"))
199                 return -1;
200         *peer_fd = -1;
201 
202         /* Wait for FIN and the ACK of the FIN to be observed */
203         for (i = 0;
204              skel->bss->g_packet_count < saved_packet_count + 2 && i < 10;
205              i++)
206                 usleep(100000); /* 0.1s */
207         if (!ASSERT_GE(skel->bss->g_packet_count, saved_packet_count + 2,
208                        "packet_count"))
209                 return -1;
210 
211         err = close(*closing_fd);
212         if (!ASSERT_OK(err, "close closing_fd"))
213                 return -1;
214         *closing_fd = -1;
215 
216         close(*listen_fd);
217         *listen_fd = -1;
218 
219         return 0;
220 }
221 
222 /* This test case includes four scenarios:
223  * 1. Connect to the server from outside the cgroup and close the connection
224  *    from outside the cgroup.
225  * 2. Connect to the server from outside the cgroup and close the connection
226  *    from inside the cgroup.
227  * 3. Connect to the server from inside the cgroup and close the connection
228  *    from outside the cgroup.
229  * 4. Connect to the server from inside the cgroup and close the connection
230  *    from inside the cgroup.
231  *
232  * The test case is to verify that cgroup_skb/{egress,ingress} filters
233  * receive expected packets including SYN, SYN/ACK, ACK, FIN, and FIN/ACK.
234  */
235 void test_cgroup_tcp_skb(void)
236 {
237         struct bpf_link *ingress_link = NULL;
238         struct bpf_link *egress_link = NULL;
239         int client_fd = -1, listen_fd = -1;
240         struct cgroup_tcp_skb *skel;
241         int service_fd = -1;
242         int cgroup_fd = -1;
243         int err;
244 
245         skel = cgroup_tcp_skb__open_and_load();
246         if (!ASSERT_OK(!skel, "skel_open_load"))
247                 return;
248 
249         err = setup_cgroup_environment();
250         if (!ASSERT_OK(err, "setup_cgroup_environment"))
251                 goto cleanup;
252 
253         cgroup_fd = create_and_get_cgroup(CGROUP_TCP_SKB_PATH);
254         if (!ASSERT_GE(cgroup_fd, 0, "cgroup_fd"))
255                 goto cleanup;
256 
257         /* Scenario 1 */
258         err = install_filters(cgroup_fd, &egress_link, &ingress_link,
259                               skel->progs.server_egress,
260                               skel->progs.server_ingress,
261                               skel);
262         if (!ASSERT_OK(err, "install_filters"))
263                 goto cleanup;
264 
265         err = talk_to_cgroup(&client_fd, &listen_fd, &service_fd, skel);
266         if (!ASSERT_OK(err, "talk_to_cgroup"))
267                 goto cleanup;
268 
269         err = close_connection(&client_fd, &service_fd, &listen_fd, skel);
270         if (!ASSERT_OK(err, "close_connection"))
271                 goto cleanup;
272 
273         ASSERT_EQ(skel->bss->g_unexpected, 0, "g_unexpected");
274         ASSERT_EQ(skel->bss->g_sock_state, CLOSED, "g_sock_state");
275 
276         uninstall_filters(&egress_link, &ingress_link);
277 
278         /* Scenario 2 */
279         err = install_filters(cgroup_fd, &egress_link, &ingress_link,
280                               skel->progs.server_egress_srv,
281                               skel->progs.server_ingress_srv,
282                               skel);
283 
284         err = talk_to_cgroup(&client_fd, &listen_fd, &service_fd, skel);
285         if (!ASSERT_OK(err, "talk_to_cgroup"))
286                 goto cleanup;
287 
288         err = close_connection(&service_fd, &client_fd, &listen_fd, skel);
289         if (!ASSERT_OK(err, "close_connection"))
290                 goto cleanup;
291 
292         ASSERT_EQ(skel->bss->g_unexpected, 0, "g_unexpected");
293         ASSERT_EQ(skel->bss->g_sock_state, TIME_WAIT, "g_sock_state");
294 
295         uninstall_filters(&egress_link, &ingress_link);
296 
297         /* Scenario 3 */
298         err = install_filters(cgroup_fd, &egress_link, &ingress_link,
299                               skel->progs.client_egress_srv,
300                               skel->progs.client_ingress_srv,
301                               skel);
302 
303         err = talk_to_outside(&client_fd, &listen_fd, &service_fd, skel);
304         if (!ASSERT_OK(err, "talk_to_outside"))
305                 goto cleanup;
306 
307         err = close_connection(&service_fd, &client_fd, &listen_fd, skel);
308         if (!ASSERT_OK(err, "close_connection"))
309                 goto cleanup;
310 
311         ASSERT_EQ(skel->bss->g_unexpected, 0, "g_unexpected");
312         ASSERT_EQ(skel->bss->g_sock_state, CLOSED, "g_sock_state");
313 
314         uninstall_filters(&egress_link, &ingress_link);
315 
316         /* Scenario 4 */
317         err = install_filters(cgroup_fd, &egress_link, &ingress_link,
318                               skel->progs.client_egress,
319                               skel->progs.client_ingress,
320                               skel);
321 
322         err = talk_to_outside(&client_fd, &listen_fd, &service_fd, skel);
323         if (!ASSERT_OK(err, "talk_to_outside"))
324                 goto cleanup;
325 
326         err = close_connection(&client_fd, &service_fd, &listen_fd, skel);
327         if (!ASSERT_OK(err, "close_connection"))
328                 goto cleanup;
329 
330         ASSERT_EQ(skel->bss->g_unexpected, 0, "g_unexpected");
331         ASSERT_EQ(skel->bss->g_sock_state, TIME_WAIT, "g_sock_state");
332 
333         uninstall_filters(&egress_link, &ingress_link);
334 
335 cleanup:
336         close(client_fd);
337         close(listen_fd);
338         close(service_fd);
339         close(cgroup_fd);
340         bpf_link__destroy(egress_link);
341         bpf_link__destroy(ingress_link);
342         cleanup_cgroup_environment();
343         cgroup_tcp_skb__destroy(skel);
344 }
345 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php