]> www.infradead.org Git - users/hch/misc.git/commitdiff
tcp: sack option handling improvements
authorIlpo Järvinen <ij@kernel.org>
Tue, 16 Sep 2025 08:24:29 +0000 (10:24 +0200)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 18 Sep 2025 06:47:52 +0000 (08:47 +0200)
1) Don't early return when sack doesn't fit. AccECN code will be
   placed after this fragment so no early returns please.

2) Make sure opts->num_sack_blocks is not left undefined. E.g.,
   tcp_current_mss() does not memset its opts struct to zero.
   AccECN code checks if SACK option is present and may even
   alter it to make room for AccECN option when many SACK blocks
   are present. Thus, num_sack_blocks needs to be always valid.

Signed-off-by: Ilpo Järvinen <ij@kernel.org>
Signed-off-by: Chia-Yu Chang <chia-yu.chang@nokia-bell-labs.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20250916082434.100722-6-chia-yu.chang@nokia-bell-labs.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
net/ipv4/tcp_output.c

index deb9b085a8a2233983a012f64d16e1e6b83bbcf6..5be2b3eb73d3e30c433d0a3ff253dc20d6c01a3c 100644 (file)
@@ -985,17 +985,20 @@ static unsigned int tcp_established_options(struct sock *sk, struct sk_buff *skb
        eff_sacks = tp->rx_opt.num_sacks + tp->rx_opt.dsack;
        if (unlikely(eff_sacks)) {
                const unsigned int remaining = MAX_TCP_OPTION_SPACE - size;
-               if (unlikely(remaining < TCPOLEN_SACK_BASE_ALIGNED +
-                                        TCPOLEN_SACK_PERBLOCK))
-                       return size;
-
-               opts->num_sack_blocks =
-                       min_t(unsigned int, eff_sacks,
-                             (remaining - TCPOLEN_SACK_BASE_ALIGNED) /
-                             TCPOLEN_SACK_PERBLOCK);
-
-               size += TCPOLEN_SACK_BASE_ALIGNED +
-                       opts->num_sack_blocks * TCPOLEN_SACK_PERBLOCK;
+               if (likely(remaining >= TCPOLEN_SACK_BASE_ALIGNED +
+                                       TCPOLEN_SACK_PERBLOCK)) {
+                       opts->num_sack_blocks =
+                               min_t(unsigned int, eff_sacks,
+                                     (remaining - TCPOLEN_SACK_BASE_ALIGNED) /
+                                     TCPOLEN_SACK_PERBLOCK);
+
+                       size += TCPOLEN_SACK_BASE_ALIGNED +
+                               opts->num_sack_blocks * TCPOLEN_SACK_PERBLOCK;
+               } else {
+                       opts->num_sack_blocks = 0;
+               }
+       } else {
+               opts->num_sack_blocks = 0;
        }
 
        if (unlikely(BPF_SOCK_OPS_TEST_FLAG(tp,