1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) Meta Platforms, Inc. and affiliates. */ 3 4 #define _GNU_SOURCE 5 #include <sched.h> 6 #include <linux/socket.h> 7 #include <linux/tls.h> 8 #include <net/if.h> 9 10 #include "test_progs.h" 11 #include "cgroup_helpers.h" 12 #include "network_helpers.h" 13 14 #include "setget_sockopt.skel.h" 15 16 #define CG_NAME "/setget-sockopt-test" 17 18 static const char addr4_str[] = "127.0.0.1"; 19 static const char addr6_str[] = "::1"; 20 static struct setget_sockopt *skel; 21 static int cg_fd; 22 23 static int create_netns(void) 24 { 25 if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns")) 26 return -1; 27 28 if (!ASSERT_OK(system("ip link set dev lo up"), "set lo up")) 29 return -1; 30 31 if (!ASSERT_OK(system("ip link add dev binddevtest1 type veth peer name binddevtest2"), 32 "add veth")) 33 return -1; 34 35 if (!ASSERT_OK(system("ip link set dev binddevtest1 up"), 36 "bring veth up")) 37 return -1; 38 39 return 0; 40 } 41 42 static void test_tcp(int family) 43 { 44 struct setget_sockopt__bss *bss = skel->bss; 45 int sfd, cfd; 46 47 memset(bss, 0, sizeof(*bss)); 48 49 sfd = start_server(family, SOCK_STREAM, 50 family == AF_INET6 ? addr6_str : addr4_str, 0, 0); 51 if (!ASSERT_GE(sfd, 0, "start_server")) 52 return; 53 54 cfd = connect_to_fd(sfd, 0); 55 if (!ASSERT_GE(cfd, 0, "connect_to_fd_server")) { 56 close(sfd); 57 return; 58 } 59 close(sfd); 60 close(cfd); 61 62 ASSERT_EQ(bss->nr_listen, 1, "nr_listen"); 63 ASSERT_EQ(bss->nr_connect, 1, "nr_connect"); 64 ASSERT_EQ(bss->nr_active, 1, "nr_active"); 65 ASSERT_EQ(bss->nr_passive, 1, "nr_passive"); 66 ASSERT_EQ(bss->nr_socket_post_create, 2, "nr_socket_post_create"); 67 ASSERT_EQ(bss->nr_binddev, 2, "nr_bind"); 68 } 69 70 static void test_udp(int family) 71 { 72 struct setget_sockopt__bss *bss = skel->bss; 73 int sfd; 74 75 memset(bss, 0, sizeof(*bss)); 76 77 sfd = start_server(family, SOCK_DGRAM, 78 family == AF_INET6 ? addr6_str : addr4_str, 0, 0); 79 if (!ASSERT_GE(sfd, 0, "start_server")) 80 return; 81 close(sfd); 82 83 ASSERT_GE(bss->nr_socket_post_create, 1, "nr_socket_post_create"); 84 ASSERT_EQ(bss->nr_binddev, 1, "nr_bind"); 85 } 86 87 static void test_ktls(int family) 88 { 89 struct tls12_crypto_info_aes_gcm_128 aes128; 90 struct setget_sockopt__bss *bss = skel->bss; 91 int cfd = -1, sfd = -1, fd = -1, ret; 92 char buf; 93 94 memset(bss, 0, sizeof(*bss)); 95 96 sfd = start_server(family, SOCK_STREAM, 97 family == AF_INET6 ? addr6_str : addr4_str, 0, 0); 98 if (!ASSERT_GE(sfd, 0, "start_server")) 99 return; 100 fd = connect_to_fd(sfd, 0); 101 if (!ASSERT_GE(fd, 0, "connect_to_fd")) 102 goto err_out; 103 104 cfd = accept(sfd, NULL, 0); 105 if (!ASSERT_GE(cfd, 0, "accept")) 106 goto err_out; 107 108 close(sfd); 109 sfd = -1; 110 111 /* Setup KTLS */ 112 ret = setsockopt(fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls")); 113 if (!ASSERT_OK(ret, "setsockopt")) 114 goto err_out; 115 ret = setsockopt(cfd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls")); 116 if (!ASSERT_OK(ret, "setsockopt")) 117 goto err_out; 118 119 memset(&aes128, 0, sizeof(aes128)); 120 aes128.info.version = TLS_1_2_VERSION; 121 aes128.info.cipher_type = TLS_CIPHER_AES_GCM_128; 122 123 ret = setsockopt(fd, SOL_TLS, TLS_TX, &aes128, sizeof(aes128)); 124 if (!ASSERT_OK(ret, "setsockopt")) 125 goto err_out; 126 127 ret = setsockopt(cfd, SOL_TLS, TLS_RX, &aes128, sizeof(aes128)); 128 if (!ASSERT_OK(ret, "setsockopt")) 129 goto err_out; 130 131 /* KTLS is enabled */ 132 133 close(fd); 134 /* At this point, the cfd socket is at the CLOSE_WAIT state 135 * and still run TLS protocol. The test for 136 * BPF_TCP_CLOSE_WAIT should be run at this point. 137 */ 138 ret = read(cfd, &buf, sizeof(buf)); 139 ASSERT_EQ(ret, 0, "read"); 140 close(cfd); 141 142 ASSERT_EQ(bss->nr_listen, 1, "nr_listen"); 143 ASSERT_EQ(bss->nr_connect, 1, "nr_connect"); 144 ASSERT_EQ(bss->nr_active, 1, "nr_active"); 145 ASSERT_EQ(bss->nr_passive, 1, "nr_passive"); 146 ASSERT_EQ(bss->nr_socket_post_create, 2, "nr_socket_post_create"); 147 ASSERT_EQ(bss->nr_binddev, 2, "nr_bind"); 148 ASSERT_EQ(bss->nr_fin_wait1, 1, "nr_fin_wait1"); 149 return; 150 151 err_out: 152 close(fd); 153 close(cfd); 154 close(sfd); 155 } 156 157 static void test_nonstandard_opt(int family) 158 { 159 struct setget_sockopt__bss *bss = skel->bss; 160 struct bpf_link *getsockopt_link = NULL; 161 int sfd = -1, fd = -1, cfd = -1, flags; 162 socklen_t flagslen = sizeof(flags); 163 164 memset(bss, 0, sizeof(*bss)); 165 166 sfd = start_server(family, SOCK_STREAM, 167 family == AF_INET6 ? addr6_str : addr4_str, 0, 0); 168 if (!ASSERT_GE(sfd, 0, "start_server")) 169 return; 170 171 fd = connect_to_fd(sfd, 0); 172 if (!ASSERT_GE(fd, 0, "connect_to_fd_server")) 173 goto err_out; 174 175 /* cgroup/getsockopt prog will intercept getsockopt() below and 176 * retrieve the tcp socket bpf_sock_ops_cb_flags value for the 177 * accept()ed socket; this was set earlier in the passive established 178 * callback for the accept()ed socket via bpf_setsockopt(). 179 */ 180 getsockopt_link = bpf_program__attach_cgroup(skel->progs._getsockopt, cg_fd); 181 if (!ASSERT_OK_PTR(getsockopt_link, "getsockopt prog")) 182 goto err_out; 183 184 cfd = accept(sfd, NULL, 0); 185 if (!ASSERT_GE(cfd, 0, "accept")) 186 goto err_out; 187 188 if (!ASSERT_OK(getsockopt(cfd, SOL_TCP, TCP_BPF_SOCK_OPS_CB_FLAGS, &flags, &flagslen), 189 "getsockopt_flags")) 190 goto err_out; 191 ASSERT_EQ(flags & BPF_SOCK_OPS_STATE_CB_FLAG, BPF_SOCK_OPS_STATE_CB_FLAG, 192 "cb_flags_set"); 193 err_out: 194 close(sfd); 195 if (fd != -1) 196 close(fd); 197 if (cfd != -1) 198 close(cfd); 199 bpf_link__destroy(getsockopt_link); 200 } 201 202 void test_setget_sockopt(void) 203 { 204 cg_fd = test__join_cgroup(CG_NAME); 205 if (cg_fd < 0) 206 return; 207 208 if (create_netns()) 209 goto done; 210 211 skel = setget_sockopt__open(); 212 if (!ASSERT_OK_PTR(skel, "open skel")) 213 goto done; 214 215 strcpy(skel->rodata->veth, "binddevtest1"); 216 skel->rodata->veth_ifindex = if_nametoindex("binddevtest1"); 217 if (!ASSERT_GT(skel->rodata->veth_ifindex, 0, "if_nametoindex")) 218 goto done; 219 220 if (!ASSERT_OK(setget_sockopt__load(skel), "load skel")) 221 goto done; 222 223 skel->links.skops_sockopt = 224 bpf_program__attach_cgroup(skel->progs.skops_sockopt, cg_fd); 225 if (!ASSERT_OK_PTR(skel->links.skops_sockopt, "attach cgroup")) 226 goto done; 227 228 skel->links.socket_post_create = 229 bpf_program__attach_cgroup(skel->progs.socket_post_create, cg_fd); 230 if (!ASSERT_OK_PTR(skel->links.socket_post_create, "attach_cgroup")) 231 goto done; 232 233 test_tcp(AF_INET6); 234 test_tcp(AF_INET); 235 test_udp(AF_INET6); 236 test_udp(AF_INET); 237 test_ktls(AF_INET6); 238 test_ktls(AF_INET); 239 test_nonstandard_opt(AF_INET); 240 test_nonstandard_opt(AF_INET6); 241 242 done: 243 setget_sockopt__destroy(skel); 244 close(cg_fd); 245 } 246