1*1a8bc229SAditi Ghag // SPDX-License-Identifier: GPL-2.0
2*1a8bc229SAditi Ghag #include <test_progs.h>
3*1a8bc229SAditi Ghag #include <bpf/bpf_endian.h>
4*1a8bc229SAditi Ghag
5*1a8bc229SAditi Ghag #include "sock_destroy_prog.skel.h"
6*1a8bc229SAditi Ghag #include "sock_destroy_prog_fail.skel.h"
7*1a8bc229SAditi Ghag #include "network_helpers.h"
8*1a8bc229SAditi Ghag
9*1a8bc229SAditi Ghag #define TEST_NS "sock_destroy_netns"
10*1a8bc229SAditi Ghag
start_iter_sockets(struct bpf_program * prog)11*1a8bc229SAditi Ghag static void start_iter_sockets(struct bpf_program *prog)
12*1a8bc229SAditi Ghag {
13*1a8bc229SAditi Ghag struct bpf_link *link;
14*1a8bc229SAditi Ghag char buf[50] = {};
15*1a8bc229SAditi Ghag int iter_fd, len;
16*1a8bc229SAditi Ghag
17*1a8bc229SAditi Ghag link = bpf_program__attach_iter(prog, NULL);
18*1a8bc229SAditi Ghag if (!ASSERT_OK_PTR(link, "attach_iter"))
19*1a8bc229SAditi Ghag return;
20*1a8bc229SAditi Ghag
21*1a8bc229SAditi Ghag iter_fd = bpf_iter_create(bpf_link__fd(link));
22*1a8bc229SAditi Ghag if (!ASSERT_GE(iter_fd, 0, "create_iter"))
23*1a8bc229SAditi Ghag goto free_link;
24*1a8bc229SAditi Ghag
25*1a8bc229SAditi Ghag while ((len = read(iter_fd, buf, sizeof(buf))) > 0)
26*1a8bc229SAditi Ghag ;
27*1a8bc229SAditi Ghag ASSERT_GE(len, 0, "read");
28*1a8bc229SAditi Ghag
29*1a8bc229SAditi Ghag close(iter_fd);
30*1a8bc229SAditi Ghag
31*1a8bc229SAditi Ghag free_link:
32*1a8bc229SAditi Ghag bpf_link__destroy(link);
33*1a8bc229SAditi Ghag }
34*1a8bc229SAditi Ghag
test_tcp_client(struct sock_destroy_prog * skel)35*1a8bc229SAditi Ghag static void test_tcp_client(struct sock_destroy_prog *skel)
36*1a8bc229SAditi Ghag {
37*1a8bc229SAditi Ghag int serv = -1, clien = -1, accept_serv = -1, n;
38*1a8bc229SAditi Ghag
39*1a8bc229SAditi Ghag serv = start_server(AF_INET6, SOCK_STREAM, NULL, 0, 0);
40*1a8bc229SAditi Ghag if (!ASSERT_GE(serv, 0, "start_server"))
41*1a8bc229SAditi Ghag goto cleanup;
42*1a8bc229SAditi Ghag
43*1a8bc229SAditi Ghag clien = connect_to_fd(serv, 0);
44*1a8bc229SAditi Ghag if (!ASSERT_GE(clien, 0, "connect_to_fd"))
45*1a8bc229SAditi Ghag goto cleanup;
46*1a8bc229SAditi Ghag
47*1a8bc229SAditi Ghag accept_serv = accept(serv, NULL, NULL);
48*1a8bc229SAditi Ghag if (!ASSERT_GE(accept_serv, 0, "serv accept"))
49*1a8bc229SAditi Ghag goto cleanup;
50*1a8bc229SAditi Ghag
51*1a8bc229SAditi Ghag n = send(clien, "t", 1, 0);
52*1a8bc229SAditi Ghag if (!ASSERT_EQ(n, 1, "client send"))
53*1a8bc229SAditi Ghag goto cleanup;
54*1a8bc229SAditi Ghag
55*1a8bc229SAditi Ghag /* Run iterator program that destroys connected client sockets. */
56*1a8bc229SAditi Ghag start_iter_sockets(skel->progs.iter_tcp6_client);
57*1a8bc229SAditi Ghag
58*1a8bc229SAditi Ghag n = send(clien, "t", 1, 0);
59*1a8bc229SAditi Ghag if (!ASSERT_LT(n, 0, "client_send on destroyed socket"))
60*1a8bc229SAditi Ghag goto cleanup;
61*1a8bc229SAditi Ghag ASSERT_EQ(errno, ECONNABORTED, "error code on destroyed socket");
62*1a8bc229SAditi Ghag
63*1a8bc229SAditi Ghag cleanup:
64*1a8bc229SAditi Ghag if (clien != -1)
65*1a8bc229SAditi Ghag close(clien);
66*1a8bc229SAditi Ghag if (accept_serv != -1)
67*1a8bc229SAditi Ghag close(accept_serv);
68*1a8bc229SAditi Ghag if (serv != -1)
69*1a8bc229SAditi Ghag close(serv);
70*1a8bc229SAditi Ghag }
71*1a8bc229SAditi Ghag
test_tcp_server(struct sock_destroy_prog * skel)72*1a8bc229SAditi Ghag static void test_tcp_server(struct sock_destroy_prog *skel)
73*1a8bc229SAditi Ghag {
74*1a8bc229SAditi Ghag int serv = -1, clien = -1, accept_serv = -1, n, serv_port;
75*1a8bc229SAditi Ghag
76*1a8bc229SAditi Ghag serv = start_server(AF_INET6, SOCK_STREAM, NULL, 0, 0);
77*1a8bc229SAditi Ghag if (!ASSERT_GE(serv, 0, "start_server"))
78*1a8bc229SAditi Ghag goto cleanup;
79*1a8bc229SAditi Ghag serv_port = get_socket_local_port(serv);
80*1a8bc229SAditi Ghag if (!ASSERT_GE(serv_port, 0, "get_sock_local_port"))
81*1a8bc229SAditi Ghag goto cleanup;
82*1a8bc229SAditi Ghag skel->bss->serv_port = (__be16) serv_port;
83*1a8bc229SAditi Ghag
84*1a8bc229SAditi Ghag clien = connect_to_fd(serv, 0);
85*1a8bc229SAditi Ghag if (!ASSERT_GE(clien, 0, "connect_to_fd"))
86*1a8bc229SAditi Ghag goto cleanup;
87*1a8bc229SAditi Ghag
88*1a8bc229SAditi Ghag accept_serv = accept(serv, NULL, NULL);
89*1a8bc229SAditi Ghag if (!ASSERT_GE(accept_serv, 0, "serv accept"))
90*1a8bc229SAditi Ghag goto cleanup;
91*1a8bc229SAditi Ghag
92*1a8bc229SAditi Ghag n = send(clien, "t", 1, 0);
93*1a8bc229SAditi Ghag if (!ASSERT_EQ(n, 1, "client send"))
94*1a8bc229SAditi Ghag goto cleanup;
95*1a8bc229SAditi Ghag
96*1a8bc229SAditi Ghag /* Run iterator program that destroys server sockets. */
97*1a8bc229SAditi Ghag start_iter_sockets(skel->progs.iter_tcp6_server);
98*1a8bc229SAditi Ghag
99*1a8bc229SAditi Ghag n = send(clien, "t", 1, 0);
100*1a8bc229SAditi Ghag if (!ASSERT_LT(n, 0, "client_send on destroyed socket"))
101*1a8bc229SAditi Ghag goto cleanup;
102*1a8bc229SAditi Ghag ASSERT_EQ(errno, ECONNRESET, "error code on destroyed socket");
103*1a8bc229SAditi Ghag
104*1a8bc229SAditi Ghag cleanup:
105*1a8bc229SAditi Ghag if (clien != -1)
106*1a8bc229SAditi Ghag close(clien);
107*1a8bc229SAditi Ghag if (accept_serv != -1)
108*1a8bc229SAditi Ghag close(accept_serv);
109*1a8bc229SAditi Ghag if (serv != -1)
110*1a8bc229SAditi Ghag close(serv);
111*1a8bc229SAditi Ghag }
112*1a8bc229SAditi Ghag
test_udp_client(struct sock_destroy_prog * skel)113*1a8bc229SAditi Ghag static void test_udp_client(struct sock_destroy_prog *skel)
114*1a8bc229SAditi Ghag {
115*1a8bc229SAditi Ghag int serv = -1, clien = -1, n = 0;
116*1a8bc229SAditi Ghag
117*1a8bc229SAditi Ghag serv = start_server(AF_INET6, SOCK_DGRAM, NULL, 0, 0);
118*1a8bc229SAditi Ghag if (!ASSERT_GE(serv, 0, "start_server"))
119*1a8bc229SAditi Ghag goto cleanup;
120*1a8bc229SAditi Ghag
121*1a8bc229SAditi Ghag clien = connect_to_fd(serv, 0);
122*1a8bc229SAditi Ghag if (!ASSERT_GE(clien, 0, "connect_to_fd"))
123*1a8bc229SAditi Ghag goto cleanup;
124*1a8bc229SAditi Ghag
125*1a8bc229SAditi Ghag n = send(clien, "t", 1, 0);
126*1a8bc229SAditi Ghag if (!ASSERT_EQ(n, 1, "client send"))
127*1a8bc229SAditi Ghag goto cleanup;
128*1a8bc229SAditi Ghag
129*1a8bc229SAditi Ghag /* Run iterator program that destroys sockets. */
130*1a8bc229SAditi Ghag start_iter_sockets(skel->progs.iter_udp6_client);
131*1a8bc229SAditi Ghag
132*1a8bc229SAditi Ghag n = send(clien, "t", 1, 0);
133*1a8bc229SAditi Ghag if (!ASSERT_LT(n, 0, "client_send on destroyed socket"))
134*1a8bc229SAditi Ghag goto cleanup;
135*1a8bc229SAditi Ghag /* UDP sockets have an overriding error code after they are disconnected,
136*1a8bc229SAditi Ghag * so we don't check for ECONNABORTED error code.
137*1a8bc229SAditi Ghag */
138*1a8bc229SAditi Ghag
139*1a8bc229SAditi Ghag cleanup:
140*1a8bc229SAditi Ghag if (clien != -1)
141*1a8bc229SAditi Ghag close(clien);
142*1a8bc229SAditi Ghag if (serv != -1)
143*1a8bc229SAditi Ghag close(serv);
144*1a8bc229SAditi Ghag }
145*1a8bc229SAditi Ghag
test_udp_server(struct sock_destroy_prog * skel)146*1a8bc229SAditi Ghag static void test_udp_server(struct sock_destroy_prog *skel)
147*1a8bc229SAditi Ghag {
148*1a8bc229SAditi Ghag int *listen_fds = NULL, n, i, serv_port;
149*1a8bc229SAditi Ghag unsigned int num_listens = 5;
150*1a8bc229SAditi Ghag char buf[1];
151*1a8bc229SAditi Ghag
152*1a8bc229SAditi Ghag /* Start reuseport servers. */
153*1a8bc229SAditi Ghag listen_fds = start_reuseport_server(AF_INET6, SOCK_DGRAM,
154*1a8bc229SAditi Ghag "::1", 0, 0, num_listens);
155*1a8bc229SAditi Ghag if (!ASSERT_OK_PTR(listen_fds, "start_reuseport_server"))
156*1a8bc229SAditi Ghag goto cleanup;
157*1a8bc229SAditi Ghag serv_port = get_socket_local_port(listen_fds[0]);
158*1a8bc229SAditi Ghag if (!ASSERT_GE(serv_port, 0, "get_sock_local_port"))
159*1a8bc229SAditi Ghag goto cleanup;
160*1a8bc229SAditi Ghag skel->bss->serv_port = (__be16) serv_port;
161*1a8bc229SAditi Ghag
162*1a8bc229SAditi Ghag /* Run iterator program that destroys server sockets. */
163*1a8bc229SAditi Ghag start_iter_sockets(skel->progs.iter_udp6_server);
164*1a8bc229SAditi Ghag
165*1a8bc229SAditi Ghag for (i = 0; i < num_listens; ++i) {
166*1a8bc229SAditi Ghag n = read(listen_fds[i], buf, sizeof(buf));
167*1a8bc229SAditi Ghag if (!ASSERT_EQ(n, -1, "read") ||
168*1a8bc229SAditi Ghag !ASSERT_EQ(errno, ECONNABORTED, "error code on destroyed socket"))
169*1a8bc229SAditi Ghag break;
170*1a8bc229SAditi Ghag }
171*1a8bc229SAditi Ghag ASSERT_EQ(i, num_listens, "server socket");
172*1a8bc229SAditi Ghag
173*1a8bc229SAditi Ghag cleanup:
174*1a8bc229SAditi Ghag free_fds(listen_fds, num_listens);
175*1a8bc229SAditi Ghag }
176*1a8bc229SAditi Ghag
test_sock_destroy(void)177*1a8bc229SAditi Ghag void test_sock_destroy(void)
178*1a8bc229SAditi Ghag {
179*1a8bc229SAditi Ghag struct sock_destroy_prog *skel;
180*1a8bc229SAditi Ghag struct nstoken *nstoken = NULL;
181*1a8bc229SAditi Ghag int cgroup_fd;
182*1a8bc229SAditi Ghag
183*1a8bc229SAditi Ghag skel = sock_destroy_prog__open_and_load();
184*1a8bc229SAditi Ghag if (!ASSERT_OK_PTR(skel, "skel_open"))
185*1a8bc229SAditi Ghag return;
186*1a8bc229SAditi Ghag
187*1a8bc229SAditi Ghag cgroup_fd = test__join_cgroup("/sock_destroy");
188*1a8bc229SAditi Ghag if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup"))
189*1a8bc229SAditi Ghag goto cleanup;
190*1a8bc229SAditi Ghag
191*1a8bc229SAditi Ghag skel->links.sock_connect = bpf_program__attach_cgroup(
192*1a8bc229SAditi Ghag skel->progs.sock_connect, cgroup_fd);
193*1a8bc229SAditi Ghag if (!ASSERT_OK_PTR(skel->links.sock_connect, "prog_attach"))
194*1a8bc229SAditi Ghag goto cleanup;
195*1a8bc229SAditi Ghag
196*1a8bc229SAditi Ghag SYS(cleanup, "ip netns add %s", TEST_NS);
197*1a8bc229SAditi Ghag SYS(cleanup, "ip -net %s link set dev lo up", TEST_NS);
198*1a8bc229SAditi Ghag
199*1a8bc229SAditi Ghag nstoken = open_netns(TEST_NS);
200*1a8bc229SAditi Ghag if (!ASSERT_OK_PTR(nstoken, "open_netns"))
201*1a8bc229SAditi Ghag goto cleanup;
202*1a8bc229SAditi Ghag
203*1a8bc229SAditi Ghag if (test__start_subtest("tcp_client"))
204*1a8bc229SAditi Ghag test_tcp_client(skel);
205*1a8bc229SAditi Ghag if (test__start_subtest("tcp_server"))
206*1a8bc229SAditi Ghag test_tcp_server(skel);
207*1a8bc229SAditi Ghag if (test__start_subtest("udp_client"))
208*1a8bc229SAditi Ghag test_udp_client(skel);
209*1a8bc229SAditi Ghag if (test__start_subtest("udp_server"))
210*1a8bc229SAditi Ghag test_udp_server(skel);
211*1a8bc229SAditi Ghag
212*1a8bc229SAditi Ghag RUN_TESTS(sock_destroy_prog_fail);
213*1a8bc229SAditi Ghag
214*1a8bc229SAditi Ghag cleanup:
215*1a8bc229SAditi Ghag if (nstoken)
216*1a8bc229SAditi Ghag close_netns(nstoken);
217*1a8bc229SAditi Ghag SYS_NOFAIL("ip netns del " TEST_NS " &> /dev/null");
218*1a8bc229SAditi Ghag if (cgroup_fd >= 0)
219*1a8bc229SAditi Ghag close(cgroup_fd);
220*1a8bc229SAditi Ghag sock_destroy_prog__destroy(skel);
221*1a8bc229SAditi Ghag }
222