Skip to content

Commit 98e36d4

Browse files
yuchungchengdavem330
authored andcommitted
tcp: check undo conditions before detecting losses
Currently RACK would mark loss before the undo operations in TCP loss recovery. This could incorrectly identify real losses as spurious. For example a sender first experiences a delay spike and then eventually some packets were lost due to buffer overrun. In this case, the sender should perform fast recovery b/c not all the packets were lost. But the sender may first trigger a (spurious) RTO and reset cwnd to 1. The following ACKs may used to mark real losses by tcp_rack_mark_lost. Then in tcp_process_loss this ACK could trigger F-RTO undo condition and unmark real losses and revert the cwnd reduction. If there are no more ACKs coming back, eventually the sender would timeout again instead of performing fast recovery. The patch fixes this incorrect process by always performing the undo checks before detecting losses. Fixes: 4f41b1c ("tcp: use RACK to detect losses") Signed-off-by: Yuchung Cheng <ycheng@google.com> Signed-off-by: Neal Cardwell <ncardwell@google.com> Acked-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 1d0833d commit 98e36d4

File tree

1 file changed

+20
-13
lines changed

1 file changed

+20
-13
lines changed

net/ipv4/tcp_input.c

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2801,6 +2801,21 @@ static bool tcp_try_undo_partial(struct sock *sk, const int acked)
28012801
return false;
28022802
}
28032803

2804+
static void tcp_rack_identify_loss(struct sock *sk, int *ack_flag,
2805+
const struct skb_mstamp *ack_time)
2806+
{
2807+
struct tcp_sock *tp = tcp_sk(sk);
2808+
2809+
/* Use RACK to detect loss */
2810+
if (sysctl_tcp_recovery & TCP_RACK_LOST_RETRANS) {
2811+
u32 prior_retrans = tp->retrans_out;
2812+
2813+
tcp_rack_mark_lost(sk, ack_time);
2814+
if (prior_retrans > tp->retrans_out)
2815+
*ack_flag |= FLAG_LOST_RETRANS;
2816+
}
2817+
}
2818+
28042819
/* Process an event, which can update packets-in-flight not trivially.
28052820
* Main goal of this function is to calculate new estimate for left_out,
28062821
* taking into account both packets sitting in receiver's buffer and
@@ -2866,17 +2881,6 @@ static void tcp_fastretrans_alert(struct sock *sk, const int acked,
28662881
}
28672882
}
28682883

2869-
/* Use RACK to detect loss */
2870-
if (sysctl_tcp_recovery & TCP_RACK_LOST_RETRANS) {
2871-
u32 prior_retrans = tp->retrans_out;
2872-
2873-
tcp_rack_mark_lost(sk, ack_time);
2874-
if (prior_retrans > tp->retrans_out) {
2875-
flag |= FLAG_LOST_RETRANS;
2876-
*ack_flag |= FLAG_LOST_RETRANS;
2877-
}
2878-
}
2879-
28802884
/* E. Process state. */
28812885
switch (icsk->icsk_ca_state) {
28822886
case TCP_CA_Recovery:
@@ -2894,11 +2898,13 @@ static void tcp_fastretrans_alert(struct sock *sk, const int acked,
28942898
tcp_try_keep_open(sk);
28952899
return;
28962900
}
2901+
tcp_rack_identify_loss(sk, ack_flag, ack_time);
28972902
break;
28982903
case TCP_CA_Loss:
28992904
tcp_process_loss(sk, flag, is_dupack, rexmit);
2900-
if (icsk->icsk_ca_state != TCP_CA_Open &&
2901-
!(flag & FLAG_LOST_RETRANS))
2905+
tcp_rack_identify_loss(sk, ack_flag, ack_time);
2906+
if (!(icsk->icsk_ca_state == TCP_CA_Open ||
2907+
(*ack_flag & FLAG_LOST_RETRANS)))
29022908
return;
29032909
/* Change state if cwnd is undone or retransmits are lost */
29042910
default:
@@ -2912,6 +2918,7 @@ static void tcp_fastretrans_alert(struct sock *sk, const int acked,
29122918
if (icsk->icsk_ca_state <= TCP_CA_Disorder)
29132919
tcp_try_undo_dsack(sk);
29142920

2921+
tcp_rack_identify_loss(sk, ack_flag, ack_time);
29152922
if (!tcp_time_to_recover(sk, flag)) {
29162923
tcp_try_to_open(sk, flag);
29172924
return;

0 commit comments

Comments
 (0)