]> www.infradead.org Git - users/hch/misc.git/commitdiff
tcp: adjust rcvq_space after updating scaling ratio
authorJakub Kicinski <kuba@kernel.org>
Mon, 17 Feb 2025 23:29:05 +0000 (15:29 -0800)
committerJakub Kicinski <kuba@kernel.org>
Wed, 19 Feb 2025 00:02:18 +0000 (16:02 -0800)
Since commit under Fixes we set the window clamp in accordance
to newly measured rcvbuf scaling_ratio. If the scaling_ratio
decreased significantly we may put ourselves in a situation
where windows become smaller than rcvq_space, preventing
tcp_rcv_space_adjust() from increasing rcvbuf.

The significant decrease of scaling_ratio is far more likely
since commit 697a6c8cec03 ("tcp: increase the default TCP scaling ratio"),
which increased the "default" scaling ratio from ~30% to 50%.

Hitting the bad condition depends a lot on TCP tuning, and
drivers at play. One of Meta's workloads hits it reliably
under following conditions:
 - default rcvbuf of 125k
 - sender MTU 1500, receiver MTU 5000
 - driver settles on scaling_ratio of 78 for the config above.
Initial rcvq_space gets calculated as TCP_INIT_CWND * tp->advmss
(10 * 5k = 50k). Once we find out the true scaling ratio and
MSS we clamp the windows to 38k. Triggering the condition also
depends on the message sequence of this workload. I can't repro
the problem with simple iperf or TCP_RR-style tests.

Fixes: a2cbb1603943 ("tcp: Update window clamping condition")
Reviewed-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Neal Cardwell <ncardwell@google.com>
Link: https://patch.msgid.link/20250217232905.3162187-1-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/ipv4/tcp_input.c

index eb82e01da911048b41ca380f913ef55566be79a7..98b8cc7403920331aa7d413421635b78d1afb0da 100644 (file)
@@ -243,9 +243,15 @@ static void tcp_measure_rcv_mss(struct sock *sk, const struct sk_buff *skb)
                        do_div(val, skb->truesize);
                        tcp_sk(sk)->scaling_ratio = val ? val : 1;
 
-                       if (old_ratio != tcp_sk(sk)->scaling_ratio)
-                               WRITE_ONCE(tcp_sk(sk)->window_clamp,
-                                          tcp_win_from_space(sk, sk->sk_rcvbuf));
+                       if (old_ratio != tcp_sk(sk)->scaling_ratio) {
+                               struct tcp_sock *tp = tcp_sk(sk);
+
+                               val = tcp_win_from_space(sk, sk->sk_rcvbuf);
+                               tcp_set_window_clamp(sk, val);
+
+                               if (tp->window_clamp < tp->rcvq_space.space)
+                                       tp->rcvq_space.space = tp->window_clamp;
+                       }
                }
                icsk->icsk_ack.rcv_mss = min_t(unsigned int, len,
                                               tcp_sk(sk)->advmss);