1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2023 Facebook */
3 #include <test_progs.h>
5 #include <sys/socket.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"
14 #define CGROUP_TCP_SKB_PATH "/test_cgroup_tcp_skb"
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)
24 skel->bss->g_sock_state = 0;
25 skel->bss->g_unexpected = 0;
27 bpf_program__attach_cgroup(egress_prog,
29 if (!ASSERT_OK_PTR(egress_link, "egress_link"))
32 bpf_program__attach_cgroup(ingress_prog,
34 if (!ASSERT_OK_PTR(ingress_link, "ingress_link"))
40 static void uninstall_filters(struct bpf_link **egress_link,
41 struct bpf_link **ingress_link)
43 bpf_link__destroy(*egress_link);
45 bpf_link__destroy(*ingress_link);
49 static int create_client_sock_v6(void)
53 fd = socket(AF_INET6, SOCK_STREAM, 0);
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)
70 /* Create client & server socket */
71 err = join_root_cgroup();
72 if (!ASSERT_OK(err, "join_root_cgroup"))
74 *client_fd = create_client_sock_v6();
75 if (!ASSERT_GE(*client_fd, 0, "client_fd"))
77 err = join_cgroup(CGROUP_TCP_SKB_PATH);
78 if (!ASSERT_OK(err, "join_cgroup"))
80 *listen_fd = start_server(AF_INET6, SOCK_STREAM, NULL, 0, 0);
81 if (!ASSERT_GE(*listen_fd, 0, "listen_fd"))
83 port = get_socket_local_port(*listen_fd);
84 if (!ASSERT_GE(port, 0, "get_socket_local_port"))
86 skel->bss->g_sock_port = ntohs(port);
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"))
92 *service_fd = accept(*listen_fd, NULL, NULL);
93 if (!ASSERT_GE(*service_fd, 0, "service_fd"))
95 err = join_root_cgroup();
96 if (!ASSERT_OK(err, "join_root_cgroup"))
98 cp = write(*client_fd, "hello", 5);
99 if (!ASSERT_EQ(cp, 5, "write"))
101 cp = read(*service_fd, buf, 5);
102 if (!ASSERT_EQ(cp, 5, "read"))
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)
117 /* Create client & server socket */
118 err = join_root_cgroup();
119 if (!ASSERT_OK(err, "join_root_cgroup"))
121 *listen_fd = start_server(AF_INET6, SOCK_STREAM, NULL, 0, 0);
122 if (!ASSERT_GE(*listen_fd, 0, "listen_fd"))
124 err = join_cgroup(CGROUP_TCP_SKB_PATH);
125 if (!ASSERT_OK(err, "join_cgroup"))
127 *client_fd = create_client_sock_v6();
128 if (!ASSERT_GE(*client_fd, 0, "client_fd"))
130 err = join_root_cgroup();
131 if (!ASSERT_OK(err, "join_root_cgroup"))
133 port = get_socket_local_port(*listen_fd);
134 if (!ASSERT_GE(port, 0, "get_socket_local_port"))
136 skel->bss->g_sock_port = ntohs(port);
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"))
142 *service_fd = accept(*listen_fd, NULL, NULL);
143 if (!ASSERT_GE(*service_fd, 0, "service_fd"))
145 cp = write(*client_fd, "hello", 5);
146 if (!ASSERT_EQ(cp, 5, "write"))
148 cp = read(*service_fd, buf, 5);
149 if (!ASSERT_EQ(cp, 5, "read"))
155 static int close_connection(int *closing_fd, int *peer_fd, int *listen_fd,
156 struct cgroup_tcp_skb *skel)
158 __u32 saved_packet_count = 0;
162 /* Wait for ACKs to be sent */
163 saved_packet_count = skel->bss->g_packet_count;
164 usleep(100000); /* 0.1s */
166 skel->bss->g_packet_count != saved_packet_count && i < 10;
168 saved_packet_count = skel->bss->g_packet_count;
169 usleep(100000); /* 0.1s */
171 if (!ASSERT_EQ(skel->bss->g_packet_count, saved_packet_count,
175 skel->bss->g_packet_count = 0;
176 saved_packet_count = 0;
178 /* Half shutdown to make sure the closing socket having a chance to
179 * receive a FIN from the peer.
181 err = shutdown(*closing_fd, SHUT_WR);
182 if (!ASSERT_OK(err, "shutdown closing_fd"))
185 /* Wait for FIN and the ACK of the FIN to be observed */
187 skel->bss->g_packet_count < saved_packet_count + 2 && i < 10;
189 usleep(100000); /* 0.1s */
190 if (!ASSERT_GE(skel->bss->g_packet_count, saved_packet_count + 2,
194 saved_packet_count = skel->bss->g_packet_count;
196 /* Fully shutdown the connection */
197 err = close(*peer_fd);
198 if (!ASSERT_OK(err, "close peer_fd"))
202 /* Wait for FIN and the ACK of the FIN to be observed */
204 skel->bss->g_packet_count < saved_packet_count + 2 && i < 10;
206 usleep(100000); /* 0.1s */
207 if (!ASSERT_GE(skel->bss->g_packet_count, saved_packet_count + 2,
211 err = close(*closing_fd);
212 if (!ASSERT_OK(err, "close closing_fd"))
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.
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.
235 void test_cgroup_tcp_skb(void)
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;
245 skel = cgroup_tcp_skb__open_and_load();
246 if (!ASSERT_OK(!skel, "skel_open_load"))
249 err = setup_cgroup_environment();
250 if (!ASSERT_OK(err, "setup_cgroup_environment"))
253 cgroup_fd = create_and_get_cgroup(CGROUP_TCP_SKB_PATH);
254 if (!ASSERT_GE(cgroup_fd, 0, "cgroup_fd"))
258 err = install_filters(cgroup_fd, &egress_link, &ingress_link,
259 skel->progs.server_egress,
260 skel->progs.server_ingress,
262 if (!ASSERT_OK(err, "install_filters"))
265 err = talk_to_cgroup(&client_fd, &listen_fd, &service_fd, skel);
266 if (!ASSERT_OK(err, "talk_to_cgroup"))
269 err = close_connection(&client_fd, &service_fd, &listen_fd, skel);
270 if (!ASSERT_OK(err, "close_connection"))
273 ASSERT_EQ(skel->bss->g_unexpected, 0, "g_unexpected");
274 ASSERT_EQ(skel->bss->g_sock_state, CLOSED, "g_sock_state");
276 uninstall_filters(&egress_link, &ingress_link);
279 err = install_filters(cgroup_fd, &egress_link, &ingress_link,
280 skel->progs.server_egress_srv,
281 skel->progs.server_ingress_srv,
284 err = talk_to_cgroup(&client_fd, &listen_fd, &service_fd, skel);
285 if (!ASSERT_OK(err, "talk_to_cgroup"))
288 err = close_connection(&service_fd, &client_fd, &listen_fd, skel);
289 if (!ASSERT_OK(err, "close_connection"))
292 ASSERT_EQ(skel->bss->g_unexpected, 0, "g_unexpected");
293 ASSERT_EQ(skel->bss->g_sock_state, TIME_WAIT, "g_sock_state");
295 uninstall_filters(&egress_link, &ingress_link);
298 err = install_filters(cgroup_fd, &egress_link, &ingress_link,
299 skel->progs.client_egress_srv,
300 skel->progs.client_ingress_srv,
303 err = talk_to_outside(&client_fd, &listen_fd, &service_fd, skel);
304 if (!ASSERT_OK(err, "talk_to_outside"))
307 err = close_connection(&service_fd, &client_fd, &listen_fd, skel);
308 if (!ASSERT_OK(err, "close_connection"))
311 ASSERT_EQ(skel->bss->g_unexpected, 0, "g_unexpected");
312 ASSERT_EQ(skel->bss->g_sock_state, CLOSED, "g_sock_state");
314 uninstall_filters(&egress_link, &ingress_link);
317 err = install_filters(cgroup_fd, &egress_link, &ingress_link,
318 skel->progs.client_egress,
319 skel->progs.client_ingress,
322 err = talk_to_outside(&client_fd, &listen_fd, &service_fd, skel);
323 if (!ASSERT_OK(err, "talk_to_outside"))
326 err = close_connection(&client_fd, &service_fd, &listen_fd, skel);
327 if (!ASSERT_OK(err, "close_connection"))
330 ASSERT_EQ(skel->bss->g_unexpected, 0, "g_unexpected");
331 ASSERT_EQ(skel->bss->g_sock_state, TIME_WAIT, "g_sock_state");
333 uninstall_filters(&egress_link, &ingress_link);
340 bpf_link__destroy(egress_link);
341 bpf_link__destroy(ingress_link);
342 cleanup_cgroup_environment();
343 cgroup_tcp_skb__destroy(skel);