From: Chia-Yu Chang <[email protected]> Expose tcp_tso_autosize() as a BPF kfunc and register it in the TCP congestion-control kfunc set. This allows BPF congestion controls to reuse the kernel TSO autosizing logic while applying their own minimum TSO segment policy.
To make the kfunc robust against BPF-provided inputs, min_tso_segs is sanitized to at least 1 and mss_now == 0 returns the sanitized minimum value instead of performing autosizing. Signed-off-by: Chia-Yu Chang <[email protected]> -- v8: - Sanitize min_tso_segs in tcp_tso_autosize() - Return sanitized min_tso_segs when mss_now == 0 - Update commit messages --- net/ipv4/bpf_tcp_ca.c | 1 + net/ipv4/tcp_output.c | 14 +++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/net/ipv4/bpf_tcp_ca.c b/net/ipv4/bpf_tcp_ca.c index ed4fea98dfde..9deed2244c2d 100644 --- a/net/ipv4/bpf_tcp_ca.c +++ b/net/ipv4/bpf_tcp_ca.c @@ -194,6 +194,7 @@ BTF_ID_FLAGS(func, tcp_reno_cong_avoid) BTF_ID_FLAGS(func, tcp_reno_undo_cwnd) BTF_ID_FLAGS(func, tcp_slow_start) BTF_ID_FLAGS(func, tcp_cong_avoid_ai) +BTF_ID_FLAGS(func, tcp_tso_autosize) BTF_KFUNCS_END(bpf_tcp_ca_check_kfunc_ids) static const struct btf_kfunc_id_set bpf_tcp_ca_kfunc_set = { diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index b1b493d46b9c..b7f2ee5e7a6b 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2252,13 +2252,21 @@ static bool tcp_nagle_check(bool partial, const struct tcp_sock *tp, * in bigger TSO bursts. We we cut the RTT-based allowance in half * for every 2^9 usec (aka 512 us) of RTT, so that the RTT-based allowance * is below 1500 bytes after 6 * ~500 usec = 3ms. + * + * The min_tso_segs is floored to 1 to avoid surprising conversion. Also, + * BPF callers may pass mss_now == 0. In that case the function returns the + * sanitized min_tso_segs value and skips autosizing. */ -u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now, - int min_tso_segs) +__bpf_kfunc u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now, + int min_tso_segs) { + u32 min_tso = max(min_tso_segs, 1); unsigned long bytes; u32 r; + if (unlikely(!mss_now)) + return min_tso; + bytes = READ_ONCE(sk->sk_pacing_rate) >> READ_ONCE(sk->sk_pacing_shift); r = tcp_min_rtt(tcp_sk(sk)) >> READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_tso_rtt_log); @@ -2267,7 +2275,7 @@ u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now, bytes = min_t(unsigned long, bytes, sk->sk_gso_max_size); - return max_t(u32, bytes / mss_now, min_tso_segs); + return max_t(u32, bytes / mss_now, min_tso); } EXPORT_SYMBOL_GPL(tcp_tso_autosize); -- 2.34.1
