Skip to content

Commit 7ed0a53

Browse files
nealcardwellSasha Levin
authored and
Sasha Levin
committed
tcp: fix to allow timestamp undo if no retransmits were sent
[ Upstream commit e37ab73 ] Fix the TCP loss recovery undo logic in tcp_packet_delayed() so that it can trigger undo even if TSQ prevents a fast recovery episode from reaching tcp_retransmit_skb(). Geumhwan Yu <[email protected]> recently reported that after this commit from 2019: commit bc9f38c ("tcp: avoid unconditional congestion window undo on SYN retransmit") ...and before this fix we could have buggy scenarios like the following: + Due to reordering, a TCP connection receives some SACKs and enters a spurious fast recovery. + TSQ prevents all invocations of tcp_retransmit_skb(), because many skbs are queued in lower layers of the sending machine's network stack; thus tp->retrans_stamp remains 0. + The connection receives a TCP timestamp ECR value echoing a timestamp before the fast recovery, indicating that the fast recovery was spurious. + The connection fails to undo the spurious fast recovery because tp->retrans_stamp is 0, and thus tcp_packet_delayed() returns false, due to the new logic in the 2019 commit: commit bc9f38c ("tcp: avoid unconditional congestion window undo on SYN retransmit") This fix tweaks the logic to be more similar to the tcp_packet_delayed() logic before bc9f38c, except that we take care not to be fooled by the FLAG_SYN_ACKED code path zeroing out tp->retrans_stamp (the bug noted and fixed by Yuchung in bc9f38c). Note that this returns the high-level behavior of tcp_packet_delayed() to again match the comment for the function, which says: "Nothing was retransmitted or returned timestamp is less than timestamp of the first retransmission." Note that this comment is in the original 2005-04-16 Linux git commit, so this is evidently long-standing behavior. Fixes: bc9f38c ("tcp: avoid unconditional congestion window undo on SYN retransmit") Reported-by: Geumhwan Yu <[email protected]> Diagnosed-by: Geumhwan Yu <[email protected]> Signed-off-by: Neal Cardwell <[email protected]> Signed-off-by: Yuchung Cheng <[email protected]> Signed-off-by: Eric Dumazet <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 7c14a4e commit 7ed0a53

File tree

1 file changed

+16
-2
lines changed

1 file changed

+16
-2
lines changed

net/ipv4/tcp_input.c

+16-2
Original file line numberDiff line numberDiff line change
@@ -2433,8 +2433,22 @@ static bool tcp_skb_spurious_retrans(const struct tcp_sock *tp,
24332433
*/
24342434
static inline bool tcp_packet_delayed(const struct tcp_sock *tp)
24352435
{
2436-
return tp->retrans_stamp &&
2437-
tcp_tsopt_ecr_before(tp, tp->retrans_stamp);
2436+
const struct sock *sk = (const struct sock *)tp;
2437+
2438+
if (tp->retrans_stamp &&
2439+
tcp_tsopt_ecr_before(tp, tp->retrans_stamp))
2440+
return true; /* got echoed TS before first retransmission */
2441+
2442+
/* Check if nothing was retransmitted (retrans_stamp==0), which may
2443+
* happen in fast recovery due to TSQ. But we ignore zero retrans_stamp
2444+
* in TCP_SYN_SENT, since when we set FLAG_SYN_ACKED we also clear
2445+
* retrans_stamp even if we had retransmitted the SYN.
2446+
*/
2447+
if (!tp->retrans_stamp && /* no record of a retransmit/SYN? */
2448+
sk->sk_state != TCP_SYN_SENT) /* not the FLAG_SYN_ACKED case? */
2449+
return true; /* nothing was retransmitted */
2450+
2451+
return false;
24382452
}
24392453

24402454
/* Undo procedures. */

0 commit comments

Comments
 (0)