1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2021 Facebook */ 3 #include "bpf_iter.h" 4 #include "bpf_tracing_net.h" 5 #include <bpf/bpf_helpers.h> 6 #include <bpf/bpf_endian.h> 7 8 #define bpf_tcp_sk(skc) ({ \ 9 struct sock_common *_skc = skc; \ 10 sk = NULL; \ 11 tp = NULL; \ 12 if (_skc) { \ 13 tp = bpf_skc_to_tcp_sock(_skc); \ 14 sk = (struct sock *)tp; \ 15 } \ 16 tp; \ 17 }) 18 19 unsigned short reuse_listen_hport = 0; 20 unsigned short listen_hport = 0; 21 char cubic_cc[TCP_CA_NAME_MAX] = "bpf_cubic"; 22 char dctcp_cc[TCP_CA_NAME_MAX] = "bpf_dctcp"; 23 bool random_retry = false; 24 25 static bool tcp_cc_eq(const char *a, const char *b) 26 { 27 int i; 28 29 for (i = 0; i < TCP_CA_NAME_MAX; i++) { 30 if (a[i] != b[i]) 31 return false; 32 if (!a[i]) 33 break; 34 } 35 36 return true; 37 } 38 39 SEC("iter/tcp") 40 int change_tcp_cc(struct bpf_iter__tcp *ctx) 41 { 42 char cur_cc[TCP_CA_NAME_MAX]; 43 struct tcp_sock *tp; 44 struct sock *sk; 45 int ret; 46 47 if (!bpf_tcp_sk(ctx->sk_common)) 48 return 0; 49 50 if (sk->sk_family != AF_INET6 || 51 (sk->sk_state != TCP_LISTEN && 52 sk->sk_state != TCP_ESTABLISHED) || 53 (sk->sk_num != reuse_listen_hport && 54 sk->sk_num != listen_hport && 55 bpf_ntohs(sk->sk_dport) != listen_hport)) 56 return 0; 57 58 if (bpf_getsockopt(tp, SOL_TCP, TCP_CONGESTION, 59 cur_cc, sizeof(cur_cc))) 60 return 0; 61 62 if (!tcp_cc_eq(cur_cc, cubic_cc)) 63 return 0; 64 65 if (random_retry && bpf_get_prandom_u32() % 4 == 1) 66 return 1; 67 68 bpf_setsockopt(tp, SOL_TCP, TCP_CONGESTION, dctcp_cc, sizeof(dctcp_cc)); 69 return 0; 70 } 71 72 char _license[] SEC("license") = "GPL"; 73