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