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 = TCP_BPF_DELACK_MAX, .new = 30000, .expected = 30000, }, 65 { .opt = TCP_BPF_RTO_MIN, .new = 30000, .expected = 30000, }, 66 { .opt = TCP_RTO_MAX_MS, .new = 2000, .expected = 2000, }, 67 { .opt = 0, }, 68 }; 69 70 static const struct sockopt_test sol_ip_tests[] = { 71 { .opt = IP_TOS, .new = 0xe1, .expected = 0xe1, .tcp_expected = 0xe0, }, 72 { .opt = IP_TRANSPARENT, .flip = 1, }, 73 { .opt = 0, }, 74 }; 75 76 static const struct sockopt_test sol_ipv6_tests[] = { 77 { .opt = IPV6_TCLASS, .new = 0xe1, .expected = 0xe1, .tcp_expected = 0xe0, }, 78 { .opt = IPV6_AUTOFLOWLABEL, .flip = 1, }, 79 { .opt = IPV6_TRANSPARENT, .flip = 1, }, 80 { .opt = 0, }, 81 }; 82 83 struct loop_ctx { 84 void *ctx; 85 struct sock *sk; 86 }; 87 88 static bool sk_is_tcp(struct sock *sk) 89 { 90 return (sk->__sk_common.skc_family == AF_INET || 91 sk->__sk_common.skc_family == AF_INET6) && 92 sk->sk_type == SOCK_STREAM && 93 sk->sk_protocol == IPPROTO_TCP; 94 } 95 96 static int bpf_test_sockopt_flip(void *ctx, struct sock *sk, 97 const struct sockopt_test *t, 98 int level) 99 { 100 int old, tmp, new, opt = t->opt; 101 102 opt = t->opt; 103 104 if (opt == SO_TXREHASH && !sk_is_tcp(sk)) 105 return 0; 106 107 if (bpf_getsockopt(ctx, level, opt, &old, sizeof(old))) 108 return 1; 109 /* kernel initialized txrehash to 255 */ 110 if (level == SOL_SOCKET && opt == SO_TXREHASH && old != 0 && old != 1) 111 old = 1; 112 113 new = !old; 114 if (bpf_setsockopt(ctx, level, opt, &new, sizeof(new))) 115 return 1; 116 if (bpf_getsockopt(ctx, level, opt, &tmp, sizeof(tmp)) || 117 tmp != new) 118 return 1; 119 120 if (bpf_setsockopt(ctx, level, opt, &old, sizeof(old))) 121 return 1; 122 123 return 0; 124 } 125 126 static int bpf_test_sockopt_int(void *ctx, struct sock *sk, 127 const struct sockopt_test *t, 128 int level) 129 { 130 int old, tmp, new, expected, opt; 131 132 opt = t->opt; 133 new = t->new; 134 if (sk->sk_type == SOCK_STREAM && t->tcp_expected) 135 expected = t->tcp_expected; 136 else 137 expected = t->expected; 138 139 if (bpf_getsockopt(ctx, level, opt, &old, sizeof(old)) || 140 old == new) 141 return 1; 142 143 if (bpf_setsockopt(ctx, level, opt, &new, sizeof(new))) 144 return 1; 145 if (bpf_getsockopt(ctx, level, opt, &tmp, sizeof(tmp)) || 146 tmp != expected) 147 return 1; 148 149 if (t->restore) 150 old = t->restore; 151 if (bpf_setsockopt(ctx, level, opt, &old, sizeof(old))) 152 return 1; 153 154 return 0; 155 } 156 157 static int bpf_test_socket_sockopt(__u32 i, struct loop_ctx *lc) 158 { 159 const struct sockopt_test *t; 160 161 if (i >= ARRAY_SIZE(sol_socket_tests)) 162 return 1; 163 164 t = &sol_socket_tests[i]; 165 if (!t->opt) 166 return 1; 167 168 if (t->flip) 169 return bpf_test_sockopt_flip(lc->ctx, lc->sk, t, SOL_SOCKET); 170 171 return bpf_test_sockopt_int(lc->ctx, lc->sk, t, SOL_SOCKET); 172 } 173 174 static int bpf_test_ip_sockopt(__u32 i, struct loop_ctx *lc) 175 { 176 const struct sockopt_test *t; 177 178 if (i >= ARRAY_SIZE(sol_ip_tests)) 179 return 1; 180 181 t = &sol_ip_tests[i]; 182 if (!t->opt) 183 return 1; 184 185 if (t->flip) 186 return bpf_test_sockopt_flip(lc->ctx, lc->sk, t, IPPROTO_IP); 187 188 return bpf_test_sockopt_int(lc->ctx, lc->sk, t, IPPROTO_IP); 189 } 190 191 static int bpf_test_ipv6_sockopt(__u32 i, struct loop_ctx *lc) 192 { 193 const struct sockopt_test *t; 194 195 if (i >= ARRAY_SIZE(sol_ipv6_tests)) 196 return 1; 197 198 t = &sol_ipv6_tests[i]; 199 if (!t->opt) 200 return 1; 201 202 if (t->flip) 203 return bpf_test_sockopt_flip(lc->ctx, lc->sk, t, IPPROTO_IPV6); 204 205 return bpf_test_sockopt_int(lc->ctx, lc->sk, t, IPPROTO_IPV6); 206 } 207 208 static int bpf_test_tcp_sockopt(__u32 i, struct loop_ctx *lc) 209 { 210 const struct sockopt_test *t; 211 struct sock *sk; 212 void *ctx; 213 214 if (i >= ARRAY_SIZE(sol_tcp_tests)) 215 return 1; 216 217 t = &sol_tcp_tests[i]; 218 if (!t->opt) 219 return 1; 220 221 ctx = lc->ctx; 222 sk = lc->sk; 223 224 if (t->opt == TCP_CONGESTION) { 225 char old_cc[16], tmp_cc[16]; 226 const char *new_cc; 227 int new_cc_len; 228 229 if (!bpf_setsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, 230 (void *)not_exist_cc, sizeof(not_exist_cc))) 231 return 1; 232 if (bpf_getsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, old_cc, sizeof(old_cc))) 233 return 1; 234 if (!bpf_strncmp(old_cc, sizeof(old_cc), cubic_cc)) { 235 new_cc = reno_cc; 236 new_cc_len = sizeof(reno_cc); 237 } else { 238 new_cc = cubic_cc; 239 new_cc_len = sizeof(cubic_cc); 240 } 241 if (bpf_setsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, (void *)new_cc, 242 new_cc_len)) 243 return 1; 244 if (bpf_getsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, tmp_cc, sizeof(tmp_cc))) 245 return 1; 246 if (bpf_strncmp(tmp_cc, sizeof(tmp_cc), new_cc)) 247 return 1; 248 if (bpf_setsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, old_cc, sizeof(old_cc))) 249 return 1; 250 return 0; 251 } 252 253 if (t->flip) 254 return bpf_test_sockopt_flip(ctx, sk, t, IPPROTO_TCP); 255 256 return bpf_test_sockopt_int(ctx, sk, t, IPPROTO_TCP); 257 } 258 259 static int bpf_test_sockopt(void *ctx, struct sock *sk) 260 { 261 struct loop_ctx lc = { .ctx = ctx, .sk = sk, }; 262 __u16 family, proto; 263 int n; 264 265 family = sk->sk_family; 266 proto = sk->sk_protocol; 267 268 n = bpf_loop(ARRAY_SIZE(sol_socket_tests), bpf_test_socket_sockopt, &lc, 0); 269 if (n != ARRAY_SIZE(sol_socket_tests)) 270 return -1; 271 272 if (proto == IPPROTO_TCP) { 273 n = bpf_loop(ARRAY_SIZE(sol_tcp_tests), bpf_test_tcp_sockopt, &lc, 0); 274 if (n != ARRAY_SIZE(sol_tcp_tests)) 275 return -1; 276 } 277 278 if (family == AF_INET) { 279 n = bpf_loop(ARRAY_SIZE(sol_ip_tests), bpf_test_ip_sockopt, &lc, 0); 280 if (n != ARRAY_SIZE(sol_ip_tests)) 281 return -1; 282 } else { 283 n = bpf_loop(ARRAY_SIZE(sol_ipv6_tests), bpf_test_ipv6_sockopt, &lc, 0); 284 if (n != ARRAY_SIZE(sol_ipv6_tests)) 285 return -1; 286 } 287 288 return 0; 289 } 290 291 static int binddev_test(void *ctx) 292 { 293 const char empty_ifname[] = ""; 294 int ifindex, zero = 0; 295 296 if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE, 297 (void *)veth, sizeof(veth))) 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_BINDTODEVICE, 305 (void *)empty_ifname, sizeof(empty_ifname))) 306 return -1; 307 if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX, 308 &ifindex, sizeof(int)) || 309 ifindex != 0) 310 return -1; 311 312 if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX, 313 (void *)&veth_ifindex, sizeof(int))) 314 return -1; 315 if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX, 316 &ifindex, sizeof(int)) || 317 ifindex != veth_ifindex) 318 return -1; 319 320 if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX, 321 &zero, sizeof(int))) 322 return -1; 323 if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX, 324 &ifindex, sizeof(int)) || 325 ifindex != 0) 326 return -1; 327 328 return 0; 329 } 330 331 static int test_tcp_maxseg(void *ctx, struct sock *sk) 332 { 333 int val = 1314, tmp; 334 335 if (sk->sk_state != TCP_ESTABLISHED) 336 return bpf_setsockopt(ctx, IPPROTO_TCP, TCP_MAXSEG, 337 &val, sizeof(val)); 338 339 if (bpf_getsockopt(ctx, IPPROTO_TCP, TCP_MAXSEG, &tmp, sizeof(tmp)) || 340 tmp > val) 341 return -1; 342 343 return 0; 344 } 345 346 static int test_tcp_saved_syn(void *ctx, struct sock *sk) 347 { 348 __u8 saved_syn[20]; 349 int one = 1; 350 351 if (sk->sk_state == TCP_LISTEN) 352 return bpf_setsockopt(ctx, IPPROTO_TCP, TCP_SAVE_SYN, 353 &one, sizeof(one)); 354 355 return bpf_getsockopt(ctx, IPPROTO_TCP, TCP_SAVED_SYN, 356 saved_syn, sizeof(saved_syn)); 357 } 358 359 SEC("lsm_cgroup/socket_post_create") 360 int BPF_PROG(socket_post_create, struct socket *sock, int family, 361 int type, int protocol, int kern) 362 { 363 struct sock *sk = sock->sk; 364 365 if (!sk) 366 return 1; 367 368 nr_socket_post_create += !bpf_test_sockopt(sk, sk); 369 nr_binddev += !binddev_test(sk); 370 371 return 1; 372 } 373 374 SEC("cgroup/getsockopt") 375 int _getsockopt(struct bpf_sockopt *ctx) 376 { 377 struct bpf_sock *sk = ctx->sk; 378 int *optval = ctx->optval; 379 struct tcp_sock *tp; 380 381 if (!sk || ctx->level != SOL_TCP || ctx->optname != TCP_BPF_SOCK_OPS_CB_FLAGS) 382 return 1; 383 384 tp = bpf_core_cast(sk, struct tcp_sock); 385 if (ctx->optval + sizeof(int) <= ctx->optval_end) { 386 *optval = tp->bpf_sock_ops_cb_flags; 387 ctx->retval = 0; 388 } 389 return 1; 390 } 391 392 int v4mapped_v6_ip_tos_enable; 393 int v4mapped_v6_ip_tos_ret; 394 int v4mapped_v6_ip_tos_cnt; 395 int v4mapped_v6_ip_tos_val; 396 397 static void test_v4mapped_v6_ip_tos(struct bpf_sock_ops *skops) 398 { 399 int tos = v4mapped_v6_ip_tos_val; 400 401 if (!v4mapped_v6_ip_tos_enable || skops->op != BPF_SOCK_OPS_TCP_CONNECT_CB) 402 return; 403 if (skops->family != AF_INET6) 404 return; 405 406 v4mapped_v6_ip_tos_cnt++; 407 v4mapped_v6_ip_tos_ret = bpf_setsockopt(skops, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); 408 } 409 410 SEC("sockops") 411 int skops_sockopt(struct bpf_sock_ops *skops) 412 { 413 struct bpf_sock *bpf_sk = skops->sk; 414 struct sock *sk; 415 int flags; 416 417 if (!bpf_sk) 418 return 1; 419 420 sk = (struct sock *)bpf_skc_to_tcp_sock(bpf_sk); 421 if (!sk) 422 return 1; 423 424 if (v4mapped_v6_ip_tos_enable) { 425 test_v4mapped_v6_ip_tos(skops); 426 return 1; 427 } 428 429 switch (skops->op) { 430 case BPF_SOCK_OPS_TCP_LISTEN_CB: 431 nr_listen += !(bpf_test_sockopt(skops, sk) || 432 test_tcp_maxseg(skops, sk) || 433 test_tcp_saved_syn(skops, sk)); 434 break; 435 case BPF_SOCK_OPS_TCP_CONNECT_CB: 436 nr_connect += !(bpf_test_sockopt(skops, sk) || 437 test_tcp_maxseg(skops, sk)); 438 break; 439 case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: 440 nr_active += !(bpf_test_sockopt(skops, sk) || 441 test_tcp_maxseg(skops, sk)); 442 break; 443 case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: 444 nr_passive += !(bpf_test_sockopt(skops, sk) || 445 test_tcp_maxseg(skops, sk) || 446 test_tcp_saved_syn(skops, sk)); 447 flags = skops->bpf_sock_ops_cb_flags | BPF_SOCK_OPS_STATE_CB_FLAG; 448 bpf_setsockopt(skops, SOL_TCP, TCP_BPF_SOCK_OPS_CB_FLAGS, &flags, sizeof(flags)); 449 break; 450 case BPF_SOCK_OPS_STATE_CB: 451 if (skops->args[1] == BPF_TCP_CLOSE_WAIT) 452 nr_fin_wait1 += !bpf_test_sockopt(skops, sk); 453 break; 454 } 455 456 return 1; 457 } 458 459 char _license[] SEC("license") = "GPL"; 460