Skip to content

Commit 0ec986e

Browse files
nealcardwellkuba-moo
authored andcommitted
tcp: fix incorrect undo caused by DSACK of TLP retransmit
Loss recovery undo_retrans bookkeeping had a long-standing bug where a DSACK from a spurious TLP retransmit packet could cause an erroneous undo of a fast recovery or RTO recovery that repaired a single really-lost packet (in a sequence range outside that of the TLP retransmit). Basically, because the loss recovery state machine didn't account for the fact that it sent a TLP retransmit, the DSACK for the TLP retransmit could erroneously be implicitly be interpreted as corresponding to the normal fast recovery or RTO recovery retransmit that plugged a real hole, thus resulting in an improper undo. For example, consider the following buggy scenario where there is a real packet loss but the congestion control response is improperly undone because of this bug: + send packets P1, P2, P3, P4 + P1 is really lost + send TLP retransmit of P4 + receive SACK for original P2, P3, P4 + enter fast recovery, fast-retransmit P1, increment undo_retrans to 1 + receive DSACK for TLP P4, decrement undo_retrans to 0, undo (bug!) + receive cumulative ACK for P1-P4 (fast retransmit plugged real hole) The fix: when we initialize undo machinery in tcp_init_undo(), if there is a TLP retransmit in flight, then increment tp->undo_retrans so that we make sure that we receive a DSACK corresponding to the TLP retransmit, as well as DSACKs for all later normal retransmits, before triggering a loss recovery undo. Note that we also have to move the line that clears tp->tlp_high_seq for RTO recovery, so that upon RTO we remember the tp->tlp_high_seq value until tcp_init_undo() and clear it only afterward. Also note that the bug dates back to the original 2013 TLP implementation, commit 6ba8a3b ("tcp: Tail loss probe (TLP)"). However, this patch will only compile and work correctly with kernels that have tp->tlp_retrans, which was added only in v5.8 in 2020 in commit 76be93f ("tcp: allow at most one TLP probe per flight"). So we associate this fix with that later commit. Fixes: 76be93f ("tcp: allow at most one TLP probe per flight") Signed-off-by: Neal Cardwell <[email protected]> Reviewed-by: Eric Dumazet <[email protected]> Cc: Yuchung Cheng <[email protected]> Cc: Kevin Yang <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 842c361 commit 0ec986e

File tree

2 files changed

+10
-3
lines changed

2 files changed

+10
-3
lines changed

net/ipv4/tcp_input.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2129,8 +2129,16 @@ void tcp_clear_retrans(struct tcp_sock *tp)
21292129
static inline void tcp_init_undo(struct tcp_sock *tp)
21302130
{
21312131
tp->undo_marker = tp->snd_una;
2132+
21322133
/* Retransmission still in flight may cause DSACKs later. */
2133-
tp->undo_retrans = tp->retrans_out ? : -1;
2134+
/* First, account for regular retransmits in flight: */
2135+
tp->undo_retrans = tp->retrans_out;
2136+
/* Next, account for TLP retransmits in flight: */
2137+
if (tp->tlp_high_seq && tp->tlp_retrans)
2138+
tp->undo_retrans++;
2139+
/* Finally, avoid 0, because undo_retrans==0 means "can undo now": */
2140+
if (!tp->undo_retrans)
2141+
tp->undo_retrans = -1;
21342142
}
21352143

21362144
static bool tcp_is_rack(const struct sock *sk)
@@ -2209,6 +2217,7 @@ void tcp_enter_loss(struct sock *sk)
22092217

22102218
tcp_set_ca_state(sk, TCP_CA_Loss);
22112219
tp->high_seq = tp->snd_nxt;
2220+
tp->tlp_high_seq = 0;
22122221
tcp_ecn_queue_cwr(tp);
22132222

22142223
/* F-RTO RFC5682 sec 3.1 step 1: retransmit SND.UNA if no previous

net/ipv4/tcp_timer.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -536,8 +536,6 @@ void tcp_retransmit_timer(struct sock *sk)
536536
if (WARN_ON_ONCE(!skb))
537537
return;
538538

539-
tp->tlp_high_seq = 0;
540-
541539
if (!tp->snd_wnd && !sock_flag(sk, SOCK_DEAD) &&
542540
!((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV))) {
543541
/* Receiver dastardly shrinks window. Our retransmits

0 commit comments

Comments
 (0)