tcp: Add tcp_clamp_rto_to_user_timeout() helper to improve accuracy
authorJon Maxwell <jmaxwell37@gmail.com>
Thu, 19 Jul 2018 01:14:44 +0000 (11:14 +1000)
committerDavid S. Miller <davem@davemloft.net>
Sat, 21 Jul 2018 17:28:55 +0000 (10:28 -0700)
Create the tcp_clamp_rto_to_user_timeout() helper routine. To calculate
the correct rto, so that the TCP_USER_TIMEOUT socket option is more
accurate. Taking suggestions and feedback into account from
Eric Dumazet, Neal Cardwell and David Laight. Due to the 1st commit we
can avoid the msecs_to_jiffies() and jiffies_to_msecs() dance.

Signed-off-by: Jon Maxwell <jmaxwell37@gmail.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/tcp_timer.c

index d212f183dd2d99b9184e1ca40dbb395f90e3d1d7..a242f88746296e65418f236ac488b0de2dd20d4a 100644 (file)
@@ -36,6 +36,21 @@ u32 tcp_retransmit_stamp(const struct sock *sk)
        return start_ts;
 }
 
+static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk)
+{
+       struct inet_connection_sock *icsk = inet_csk(sk);
+       u32 elapsed, start_ts;
+
+       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)
+               return 1; /* user timeout has passed; fire ASAP */
+       else
+               return min_t(u32, icsk->icsk_rto, msecs_to_jiffies(icsk->icsk_user_timeout - elapsed));
+}
+
 /**
  *  tcp_write_err() - close socket and save error info
  *  @sk:  The socket the error has appeared on.
@@ -544,7 +559,8 @@ out_reset_timer:
                /* Use normal (exponential) backoff */
                icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX);
        }
-       inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, TCP_RTO_MAX);
+       inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
+                                 tcp_clamp_rto_to_user_timeout(sk), TCP_RTO_MAX);
        if (retransmits_timed_out(sk, net->ipv4.sysctl_tcp_retries1 + 1, 0))
                __sk_dst_reset(sk);