1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) Meta Platforms, Inc. and affiliates. */ 3 4 #include "vmlinux.h" 5 #include "bpf_tracing_net.h" 6 #include <bpf/bpf_core_read.h> 7 #include <bpf/bpf_helpers.h> 8 #include <bpf/bpf_tracing.h> 9 #include "bpf_misc.h" 10 11 extern unsigned long CONFIG_HZ __kconfig; 12 13 const volatile char veth[IFNAMSIZ]; 14 const volatile int veth_ifindex; 15 16 int nr_listen; 17 int nr_passive; 18 int nr_active; 19 int nr_connect; 20 int nr_binddev; 21 int nr_socket_post_create; 22 int nr_fin_wait1; 23 24 struct sockopt_test { 25 int opt; 26 int new; 27 int restore; 28 int expected; 29 int tcp_expected; 30 unsigned int flip:1; 31 }; 32 33 static const char not_exist_cc[] = "not_exist"; 34 static const char cubic_cc[] = "cubic"; 35 static const char reno_cc[] = "reno"; 36 37 static const struct sockopt_test sol_socket_tests[] = { 38 { .opt = SO_REUSEADDR, .flip = 1, }, 39 { .opt = SO_SNDBUF, .new = 8123, .expected = 8123 * 2, }, 40 { .opt = SO_RCVBUF, .new = 8123, .expected = 8123 * 2, }, 41 { .opt = SO_KEEPALIVE, .flip = 1, }, 42 { .opt = SO_PRIORITY, .new = 0xeb9f, .expected = 0xeb9f, }, 43 { .opt = SO_REUSEPORT, .flip = 1, }, 44 { .opt = SO_RCVLOWAT, .new = 8123, .expected = 8123, }, 45 { .opt = SO_MARK, .new = 0xeb9f, .expected = 0xeb9f, }, 46 { .opt = SO_MAX_PACING_RATE, .new = 0xeb9f, .expected = 0xeb9f, }, 47 { .opt = SO_TXREHASH, .flip = 1, }, 48 { .opt = 0, }, 49 }; 50 51 static const struct sockopt_test sol_tcp_tests[] = { 52 { .opt = TCP_NODELAY, .flip = 1, }, 53 { .opt = TCP_KEEPIDLE, .new = 123, .expected = 123, .restore = 321, }, 54 { .opt = TCP_KEEPINTVL, .new = 123, .expected = 123, .restore = 321, }, 55 { .opt = TCP_KEEPCNT, .new = 123, .expected = 123, .restore = 124, }, 56 { .opt = TCP_SYNCNT, .new = 123, .expected = 123, .restore = 124, }, 57 { .opt = TCP_WINDOW_CLAMP, .new = 8123, .expected = 8123, .restore = 8124, }, 58 { .opt = TCP_CONGESTION, }, 59 { .opt = TCP_THIN_LINEAR_TIMEOUTS, .flip = 1, }, 60 { .opt = TCP_USER_TIMEOUT, .new = 123400, .expected = 123400, }, 61 { .opt = TCP_NOTSENT_LOWAT, .new = 1314, .expected = 1314, }, 62 { .opt = TCP_BPF_SOCK_OPS_CB_FLAGS, .new = BPF_SOCK_OPS_ALL_CB_FLAGS, 63 .expected = BPF_SOCK_OPS_ALL_CB_FLAGS, }, 64 { .opt = 0, }, 65 }; 66 67 static const struct sockopt_test sol_ip_tests[] = { 68 { .opt = IP_TOS, .new = 0xe1, .expected = 0xe1, .tcp_expected = 0xe0, }, 69 { .opt = 0, }, 70 }; 71 72 static const struct sockopt_test sol_ipv6_tests[] = { 73 { .opt = IPV6_TCLASS, .new = 0xe1, .expected = 0xe1, .tcp_expected = 0xe0, }, 74 { .opt = IPV6_AUTOFLOWLABEL, .flip = 1, }, 75 { .opt = 0, }, 76 }; 77 78 struct loop_ctx { 79 void *ctx; 80 struct sock *sk; 81 }; 82 83 static int bpf_test_sockopt_flip(void *ctx, struct sock *sk, 84 const struct sockopt_test *t, 85 int level) 86 { 87 int old, tmp, new, opt = t->opt; 88 89 opt = t->opt; 90 91 if (bpf_getsockopt(ctx, level, opt, &old, sizeof(old))) 92 return 1; 93 /* kernel initialized txrehash to 255 */ 94 if (level == SOL_SOCKET && opt == SO_TXREHASH && old != 0 && old != 1) 95 old = 1; 96 97 new = !old; 98 if (bpf_setsockopt(ctx, level, opt, &new, sizeof(new))) 99 return 1; 100 if (bpf_getsockopt(ctx, level, opt, &tmp, sizeof(tmp)) || 101 tmp != new) 102 return 1; 103 104 if (bpf_setsockopt(ctx, level, opt, &old, sizeof(old))) 105 return 1; 106 107 return 0; 108 } 109 110 static int bpf_test_sockopt_int(void *ctx, struct sock *sk, 111 const struct sockopt_test *t, 112 int level) 113 { 114 int old, tmp, new, expected, opt; 115 116 opt = t->opt; 117 new = t->new; 118 if (sk->sk_type == SOCK_STREAM && t->tcp_expected) 119 expected = t->tcp_expected; 120 else 121 expected = t->expected; 122 123 if (bpf_getsockopt(ctx, level, opt, &old, sizeof(old)) || 124 old == new) 125 return 1; 126 127 if (bpf_setsockopt(ctx, level, opt, &new, sizeof(new))) 128 return 1; 129 if (bpf_getsockopt(ctx, level, opt, &tmp, sizeof(tmp)) || 130 tmp != expected) 131 return 1; 132 133 if (t->restore) 134 old = t->restore; 135 if (bpf_setsockopt(ctx, level, opt, &old, sizeof(old))) 136 return 1; 137 138 return 0; 139 } 140 141 static int bpf_test_socket_sockopt(__u32 i, struct loop_ctx *lc) 142 { 143 const struct sockopt_test *t; 144 145 if (i >= ARRAY_SIZE(sol_socket_tests)) 146 return 1; 147 148 t = &sol_socket_tests[i]; 149 if (!t->opt) 150 return 1; 151 152 if (t->flip) 153 return bpf_test_sockopt_flip(lc->ctx, lc->sk, t, SOL_SOCKET); 154 155 return bpf_test_sockopt_int(lc->ctx, lc->sk, t, SOL_SOCKET); 156 } 157 158 static int bpf_test_ip_sockopt(__u32 i, struct loop_ctx *lc) 159 { 160 const struct sockopt_test *t; 161 162 if (i >= ARRAY_SIZE(sol_ip_tests)) 163 return 1; 164 165 t = &sol_ip_tests[i]; 166 if (!t->opt) 167 return 1; 168 169 if (t->flip) 170 return bpf_test_sockopt_flip(lc->ctx, lc->sk, t, IPPROTO_IP); 171 172 return bpf_test_sockopt_int(lc->ctx, lc->sk, t, IPPROTO_IP); 173 } 174 175 static int bpf_test_ipv6_sockopt(__u32 i, struct loop_ctx *lc) 176 { 177 const struct sockopt_test *t; 178 179 if (i >= ARRAY_SIZE(sol_ipv6_tests)) 180 return 1; 181 182 t = &sol_ipv6_tests[i]; 183 if (!t->opt) 184 return 1; 185 186 if (t->flip) 187 return bpf_test_sockopt_flip(lc->ctx, lc->sk, t, IPPROTO_IPV6); 188 189 return bpf_test_sockopt_int(lc->ctx, lc->sk, t, IPPROTO_IPV6); 190 } 191 192 static int bpf_test_tcp_sockopt(__u32 i, struct loop_ctx *lc) 193 { 194 const struct sockopt_test *t; 195 struct sock *sk; 196 void *ctx; 197 198 if (i >= ARRAY_SIZE(sol_tcp_tests)) 199 return 1; 200 201 t = &sol_tcp_tests[i]; 202 if (!t->opt) 203 return 1; 204 205 ctx = lc->ctx; 206 sk = lc->sk; 207 208 if (t->opt == TCP_CONGESTION) { 209 char old_cc[16], tmp_cc[16]; 210 const char *new_cc; 211 int new_cc_len; 212 213 if (!bpf_setsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, 214 (void *)not_exist_cc, sizeof(not_exist_cc))) 215 return 1; 216 if (bpf_getsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, old_cc, sizeof(old_cc))) 217 return 1; 218 if (!bpf_strncmp(old_cc, sizeof(old_cc), cubic_cc)) { 219 new_cc = reno_cc; 220 new_cc_len = sizeof(reno_cc); 221 } else { 222 new_cc = cubic_cc; 223 new_cc_len = sizeof(cubic_cc); 224 } 225 if (bpf_setsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, (void *)new_cc, 226 new_cc_len)) 227 return 1; 228 if (bpf_getsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, tmp_cc, sizeof(tmp_cc))) 229 return 1; 230 if (bpf_strncmp(tmp_cc, sizeof(tmp_cc), new_cc)) 231 return 1; 232 if (bpf_setsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, old_cc, sizeof(old_cc))) 233 return 1; 234 return 0; 235 } 236 237 if (t->flip) 238 return bpf_test_sockopt_flip(ctx, sk, t, IPPROTO_TCP); 239 240 return bpf_test_sockopt_int(ctx, sk, t, IPPROTO_TCP); 241 } 242 243 static int bpf_test_sockopt(void *ctx, struct sock *sk) 244 { 245 struct loop_ctx lc = { .ctx = ctx, .sk = sk, }; 246 __u16 family, proto; 247 int n; 248 249 family = sk->sk_family; 250 proto = sk->sk_protocol; 251 252 n = bpf_loop(ARRAY_SIZE(sol_socket_tests), bpf_test_socket_sockopt, &lc, 0); 253 if (n != ARRAY_SIZE(sol_socket_tests)) 254 return -1; 255 256 if (proto == IPPROTO_TCP) { 257 n = bpf_loop(ARRAY_SIZE(sol_tcp_tests), bpf_test_tcp_sockopt, &lc, 0); 258 if (n != ARRAY_SIZE(sol_tcp_tests)) 259 return -1; 260 } 261 262 if (family == AF_INET) { 263 n = bpf_loop(ARRAY_SIZE(sol_ip_tests), bpf_test_ip_sockopt, &lc, 0); 264 if (n != ARRAY_SIZE(sol_ip_tests)) 265 return -1; 266 } else { 267 n = bpf_loop(ARRAY_SIZE(sol_ipv6_tests), bpf_test_ipv6_sockopt, &lc, 0); 268 if (n != ARRAY_SIZE(sol_ipv6_tests)) 269 return -1; 270 } 271 272 return 0; 273 } 274 275 static int binddev_test(void *ctx) 276 { 277 const char empty_ifname[] = ""; 278 int ifindex, zero = 0; 279 280 if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE, 281 (void *)veth, sizeof(veth))) 282 return -1; 283 if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX, 284 &ifindex, sizeof(int)) || 285 ifindex != veth_ifindex) 286 return -1; 287 288 if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE, 289 (void *)empty_ifname, sizeof(empty_ifname))) 290 return -1; 291 if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX, 292 &ifindex, sizeof(int)) || 293 ifindex != 0) 294 return -1; 295 296 if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX, 297 (void *)&veth_ifindex, sizeof(int))) 298 return -1; 299 if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX, 300 &ifindex, sizeof(int)) || 301 ifindex != veth_ifindex) 302 return -1; 303 304 if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX, 305 &zero, sizeof(int))) 306 return -1; 307 if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX, 308 &ifindex, sizeof(int)) || 309 ifindex != 0) 310 return -1; 311 312 return 0; 313 } 314 315 static int test_tcp_maxseg(void *ctx, struct sock *sk) 316 { 317 int val = 1314, tmp; 318 319 if (sk->sk_state != TCP_ESTABLISHED) 320 return bpf_setsockopt(ctx, IPPROTO_TCP, TCP_MAXSEG, 321 &val, sizeof(val)); 322 323 if (bpf_getsockopt(ctx, IPPROTO_TCP, TCP_MAXSEG, &tmp, sizeof(tmp)) || 324 tmp > val) 325 return -1; 326 327 return 0; 328 } 329 330 static int test_tcp_saved_syn(void *ctx, struct sock *sk) 331 { 332 __u8 saved_syn[20]; 333 int one = 1; 334 335 if (sk->sk_state == TCP_LISTEN) 336 return bpf_setsockopt(ctx, IPPROTO_TCP, TCP_SAVE_SYN, 337 &one, sizeof(one)); 338 339 return bpf_getsockopt(ctx, IPPROTO_TCP, TCP_SAVED_SYN, 340 saved_syn, sizeof(saved_syn)); 341 } 342 343 SEC("lsm_cgroup/socket_post_create") 344 int BPF_PROG(socket_post_create, struct socket *sock, int family, 345 int type, int protocol, int kern) 346 { 347 struct sock *sk = sock->sk; 348 349 if (!sk) 350 return 1; 351 352 nr_socket_post_create += !bpf_test_sockopt(sk, sk); 353 nr_binddev += !binddev_test(sk); 354 355 return 1; 356 } 357 358 SEC("cgroup/getsockopt") 359 int _getsockopt(struct bpf_sockopt *ctx) 360 { 361 struct bpf_sock *sk = ctx->sk; 362 int *optval = ctx->optval; 363 struct tcp_sock *tp; 364 365 if (!sk || ctx->level != SOL_TCP || ctx->optname != TCP_BPF_SOCK_OPS_CB_FLAGS) 366 return 1; 367 368 tp = bpf_core_cast(sk, struct tcp_sock); 369 if (ctx->optval + sizeof(int) <= ctx->optval_end) { 370 *optval = tp->bpf_sock_ops_cb_flags; 371 ctx->retval = 0; 372 } 373 return 1; 374 } 375 376 SEC("sockops") 377 int skops_sockopt(struct bpf_sock_ops *skops) 378 { 379 struct bpf_sock *bpf_sk = skops->sk; 380 struct sock *sk; 381 int flags; 382 383 if (!bpf_sk) 384 return 1; 385 386 sk = (struct sock *)bpf_skc_to_tcp_sock(bpf_sk); 387 if (!sk) 388 return 1; 389 390 switch (skops->op) { 391 case BPF_SOCK_OPS_TCP_LISTEN_CB: 392 nr_listen += !(bpf_test_sockopt(skops, sk) || 393 test_tcp_maxseg(skops, sk) || 394 test_tcp_saved_syn(skops, sk)); 395 break; 396 case BPF_SOCK_OPS_TCP_CONNECT_CB: 397 nr_connect += !(bpf_test_sockopt(skops, sk) || 398 test_tcp_maxseg(skops, sk)); 399 break; 400 case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: 401 nr_active += !(bpf_test_sockopt(skops, sk) || 402 test_tcp_maxseg(skops, sk)); 403 break; 404 case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: 405 nr_passive += !(bpf_test_sockopt(skops, sk) || 406 test_tcp_maxseg(skops, sk) || 407 test_tcp_saved_syn(skops, sk)); 408 flags = skops->bpf_sock_ops_cb_flags | BPF_SOCK_OPS_STATE_CB_FLAG; 409 bpf_setsockopt(skops, SOL_TCP, TCP_BPF_SOCK_OPS_CB_FLAGS, &flags, sizeof(flags)); 410 break; 411 case BPF_SOCK_OPS_STATE_CB: 412 if (skops->args[1] == BPF_TCP_CLOSE_WAIT) 413 nr_fin_wait1 += !bpf_test_sockopt(skops, sk); 414 break; 415 } 416 417 return 1; 418 } 419 420 char _license[] SEC("license") = "GPL"; 421