tcp: always set retrans_stamp on recovery
Previously TCP socket's retrans_stamp is not set if the retransmission has failed to send. As a result if a socket is experiencing local issues to retransmit packets, determining when to abort a socket is complicated w/o knowning the starting time of the recovery since retrans_stamp may remain zero. This complication causes sub-optimal behavior that TCP may use the latest, instead of the first, retransmission time to compute the elapsed time of a stalling connection due to local issues. Then TCP may disrecard TCP retries settings and keep retrying until it finally succeed: not a good idea when the local host is already strained. The simple fix is to always timestamp the start of a recovery. It's worth noting that retrans_stamp is also used to compare echo timestamp values to detect spurious recovery. This patch does not break that because retrans_stamp is still later than when the original packet was sent. Signed-off-by: Yuchung Cheng <ycheng@google.com> Signed-off-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Neal Cardwell <ncardwell@google.com> Reviewed-by: Soheil Hassas Yeganeh <soheil@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
7f12422c48
commit
7ae189759c
|
@ -2963,13 +2963,12 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs)
|
|||
#endif
|
||||
TCP_SKB_CB(skb)->sacked |= TCPCB_RETRANS;
|
||||
tp->retrans_out += tcp_skb_pcount(skb);
|
||||
|
||||
/* Save stamp of the first retransmit. */
|
||||
if (!tp->retrans_stamp)
|
||||
tp->retrans_stamp = tcp_skb_timestamp(skb);
|
||||
|
||||
}
|
||||
|
||||
/* Save stamp of the first (attempted) retransmit. */
|
||||
if (!tp->retrans_stamp)
|
||||
tp->retrans_stamp = tcp_skb_timestamp(skb);
|
||||
|
||||
if (tp->undo_retrans < 0)
|
||||
tp->undo_retrans = 0;
|
||||
tp->undo_retrans += tcp_skb_pcount(skb);
|
||||
|
|
|
@ -22,28 +22,14 @@
|
|||
#include <linux/gfp.h>
|
||||
#include <net/tcp.h>
|
||||
|
||||
static u32 tcp_retransmit_stamp(const struct sock *sk)
|
||||
{
|
||||
u32 start_ts = tcp_sk(sk)->retrans_stamp;
|
||||
|
||||
if (unlikely(!start_ts)) {
|
||||
struct sk_buff *head = tcp_rtx_queue_head(sk);
|
||||
|
||||
if (!head)
|
||||
return 0;
|
||||
start_ts = tcp_skb_timestamp(head);
|
||||
}
|
||||
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;
|
||||
s32 remaining;
|
||||
|
||||
start_ts = tcp_retransmit_stamp(sk);
|
||||
if (!icsk->icsk_user_timeout || !start_ts)
|
||||
start_ts = tcp_sk(sk)->retrans_stamp;
|
||||
if (!icsk->icsk_user_timeout)
|
||||
return icsk->icsk_rto;
|
||||
elapsed = tcp_time_stamp(tcp_sk(sk)) - start_ts;
|
||||
remaining = icsk->icsk_user_timeout - elapsed;
|
||||
|
@ -197,10 +183,7 @@ static bool retransmits_timed_out(struct sock *sk,
|
|||
if (!inet_csk(sk)->icsk_retransmits)
|
||||
return false;
|
||||
|
||||
start_ts = tcp_retransmit_stamp(sk);
|
||||
if (!start_ts)
|
||||
return false;
|
||||
|
||||
start_ts = tcp_sk(sk)->retrans_stamp;
|
||||
if (likely(timeout == 0)) {
|
||||
linear_backoff_thresh = ilog2(TCP_RTO_MAX/rto_base);
|
||||
|
||||
|
|
Loading…
Reference in New Issue