]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
tcp: address problems caused by EDT misshaps
authorEric Dumazet <edumazet@google.com>
Sat, 24 Nov 2018 17:12:24 +0000 (09:12 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 6 Oct 2021 13:31:19 +0000 (15:31 +0200)
commit 9efdda4e3abed13f0903b7b6e4d4c2102019440a upstream.

When a qdisc setup including pacing FQ is dismantled and recreated,
some TCP packets are sent earlier than instructed by TCP stack.

TCP can be fooled when ACK comes back, because the following
operation can return a negative value.

    tcp_time_stamp(tp) - tp->rx_opt.rcv_tsecr;

Some paths in TCP stack were not dealing properly with this,
this patch addresses four of them.

Fixes: ab408b6dc744 ("tcp: switch tcp and sch_fq to new earliest departure time model")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Qiumiao Zhang <zhangqiumiao1@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
net/ipv4/tcp_input.c
net/ipv4/tcp_timer.c

index 5117e0aeea1afb82f9fef60f426403950e780943..757e1f60e00dbd2ad2dbe61a5348b52fb8804687 100644 (file)
@@ -581,10 +581,12 @@ static inline void tcp_rcv_rtt_measure_ts(struct sock *sk,
                u32 delta = tcp_time_stamp(tp) - tp->rx_opt.rcv_tsecr;
                u32 delta_us;
 
-               if (!delta)
-                       delta = 1;
-               delta_us = delta * (USEC_PER_SEC / TCP_TS_HZ);
-               tcp_rcv_rtt_update(tp, delta_us, 0);
+               if (likely(delta < INT_MAX / (USEC_PER_SEC / TCP_TS_HZ))) {
+                       if (!delta)
+                               delta = 1;
+                       delta_us = delta * (USEC_PER_SEC / TCP_TS_HZ);
+                       tcp_rcv_rtt_update(tp, delta_us, 0);
+               }
        }
 }
 
@@ -2931,9 +2933,11 @@ static bool tcp_ack_update_rtt(struct sock *sk, const int flag,
        if (seq_rtt_us < 0 && tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr &&
            flag & FLAG_ACKED) {
                u32 delta = tcp_time_stamp(tp) - tp->rx_opt.rcv_tsecr;
-               u32 delta_us = delta * (USEC_PER_SEC / TCP_TS_HZ);
 
-               seq_rtt_us = ca_rtt_us = delta_us;
+               if (likely(delta < INT_MAX / (USEC_PER_SEC / TCP_TS_HZ))) {
+                       seq_rtt_us = delta * (USEC_PER_SEC / TCP_TS_HZ);
+                       ca_rtt_us = seq_rtt_us;
+               }
        }
        rs->rtt_us = ca_rtt_us; /* RTT of last (S)ACKed packet (or -1) */
        if (seq_rtt_us < 0)
index 681882a409686743b18e4eac614b66a1c3cdec37..7c7f7e6cd955f68857704eea4bd37b517e4342fc 100644 (file)
@@ -40,15 +40,17 @@ static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk)
 {
        struct inet_connection_sock *icsk = inet_csk(sk);
        u32 elapsed, start_ts;
+       s32 remaining;
 
        start_ts = tcp_retransmit_stamp(sk);
        if (!icsk->icsk_user_timeout || !start_ts)
                return icsk->icsk_rto;
        elapsed = tcp_time_stamp(tcp_sk(sk)) - start_ts;
-       if (elapsed >= icsk->icsk_user_timeout)
+       remaining = icsk->icsk_user_timeout - elapsed;
+       if (remaining <= 0)
                return 1; /* user timeout has passed; fire ASAP */
-       else
-               return min_t(u32, icsk->icsk_rto, msecs_to_jiffies(icsk->icsk_user_timeout - elapsed));
+
+       return min_t(u32, icsk->icsk_rto, msecs_to_jiffies(remaining));
 }
 
 /**
@@ -210,7 +212,7 @@ static bool retransmits_timed_out(struct sock *sk,
                                (boundary - linear_backoff_thresh) * TCP_RTO_MAX;
                timeout = jiffies_to_msecs(timeout);
        }
-       return (tcp_time_stamp(tcp_sk(sk)) - start_ts) >= timeout;
+       return (s32)(tcp_time_stamp(tcp_sk(sk)) - start_ts - timeout) >= 0;
 }
 
 /* A write timeout has occurred. Process the after effects. */