Commit 89fe18e4 authored by Yuchung Cheng's avatar Yuchung Cheng Committed by David S. Miller

tcp: extend F-RTO to catch more spurious timeouts

Current F-RTO reverts cwnd reset whenever a never-retransmitted
packet was (s)acked. The timeout can be declared spurious because
the packets acknoledged with this ACK was transmitted before the
timeout, so clearly not all the packets are lost to reset the cwnd.

This nice detection does not really depend F-RTO internals. This
patch applies the detection universally. On Google servers this
change detected 20% more spurious timeouts.
Suggested-by: default avatarNeal Cardwell <ncardwell@google.com>
Signed-off-by: default avatarYuchung Cheng <ycheng@google.com>
Signed-off-by: default avatarNeal Cardwell <ncardwell@google.com>
Acked-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a0370b3f
...@@ -1939,7 +1939,6 @@ void tcp_enter_loss(struct sock *sk) ...@@ -1939,7 +1939,6 @@ void tcp_enter_loss(struct sock *sk)
struct tcp_sock *tp = tcp_sk(sk); struct tcp_sock *tp = tcp_sk(sk);
struct net *net = sock_net(sk); struct net *net = sock_net(sk);
struct sk_buff *skb; struct sk_buff *skb;
bool new_recovery = icsk->icsk_ca_state < TCP_CA_Recovery;
bool is_reneg; /* is receiver reneging on SACKs? */ bool is_reneg; /* is receiver reneging on SACKs? */
bool mark_lost; bool mark_lost;
...@@ -2000,13 +1999,15 @@ void tcp_enter_loss(struct sock *sk) ...@@ -2000,13 +1999,15 @@ void tcp_enter_loss(struct sock *sk)
tp->high_seq = tp->snd_nxt; tp->high_seq = tp->snd_nxt;
tcp_ecn_queue_cwr(tp); tcp_ecn_queue_cwr(tp);
/* F-RTO RFC5682 sec 3.1 step 1: retransmit SND.UNA if no previous /* F-RTO RFC5682 sec 3.1 step 1 mandates to disable F-RTO
* loss recovery is underway except recurring timeout(s) on * if a previous recovery is underway, otherwise it may incorrectly
* the same SND.UNA (sec 3.2). Disable F-RTO on path MTU probing * call a timeout spurious if some previously retransmitted packets
* are s/acked (sec 3.2). We do not apply that retriction since
* retransmitted skbs are permanently tagged with TCPCB_EVER_RETRANS
* so FLAG_ORIG_SACK_ACKED is always correct. But we do disable F-RTO
* on PTMU discovery to avoid sending new data.
*/ */
tp->frto = sysctl_tcp_frto && tp->frto = sysctl_tcp_frto && !inet_csk(sk)->icsk_mtup.probe_size;
(new_recovery || icsk->icsk_retransmits) &&
!inet_csk(sk)->icsk_mtup.probe_size;
} }
/* If ACK arrived pointing to a remembered SACK, it means that our /* If ACK arrived pointing to a remembered SACK, it means that our
...@@ -2740,14 +2741,18 @@ static void tcp_process_loss(struct sock *sk, int flag, bool is_dupack, ...@@ -2740,14 +2741,18 @@ static void tcp_process_loss(struct sock *sk, int flag, bool is_dupack,
tcp_try_undo_loss(sk, false)) tcp_try_undo_loss(sk, false))
return; return;
if (tp->frto) { /* F-RTO RFC5682 sec 3.1 (sack enhanced version). */ /* The ACK (s)acks some never-retransmitted data meaning not all
/* Step 3.b. A timeout is spurious if not all data are * the data packets before the timeout were lost. Therefore we
* lost, i.e., never-retransmitted data are (s)acked. * undo the congestion window and state. This is essentially
*/ * the operation in F-RTO (RFC5682 section 3.1 step 3.b). Since
if ((flag & FLAG_ORIG_SACK_ACKED) && * a retransmitted skb is permantly marked, we can apply such an
tcp_try_undo_loss(sk, true)) * operation even if F-RTO was not used.
return; */
if ((flag & FLAG_ORIG_SACK_ACKED) &&
tcp_try_undo_loss(sk, tp->undo_marker))
return;
if (tp->frto) { /* F-RTO RFC5682 sec 3.1 (sack enhanced version). */
if (after(tp->snd_nxt, tp->high_seq)) { if (after(tp->snd_nxt, tp->high_seq)) {
if (flag & FLAG_DATA_SACKED || is_dupack) if (flag & FLAG_DATA_SACKED || is_dupack)
tp->frto = 0; /* Step 3.a. loss was real */ tp->frto = 0; /* Step 3.a. loss was real */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment