Skip to content

Commit 3d2af9c

Browse files
nealcardwellkuba-moo
authored andcommitted
tcp: fix indefinite deferral of RTO with SACK reneging
This commit fixes a bug that can cause a TCP data sender to repeatedly defer RTOs when encountering SACK reneging. The bug is that when we're in fast recovery in a scenario with SACK reneging, every time we get an ACK we call tcp_check_sack_reneging() and it can note the apparent SACK reneging and rearm the RTO timer for srtt/2 into the future. In some SACK reneging scenarios that can happen repeatedly until the receive window fills up, at which point the sender can't send any more, the ACKs stop arriving, and the RTO fires at srtt/2 after the last ACK. But that can take far too long (O(10 secs)), since the connection is stuck in fast recovery with a low cwnd that cannot grow beyond ssthresh, even if more bandwidth is available. This fix changes the logic in tcp_check_sack_reneging() to only rearm the RTO timer if data is cumulatively ACKed, indicating forward progress. This avoids this kind of nearly infinite loop of RTO timer re-arming. In addition, this meets the goals of tcp_check_sack_reneging() in handling Windows TCP behavior that looks temporarily like SACK reneging but is not really. Many thanks to Jakub Kicinski and Neil Spring, who reported this issue and provided critical packet traces that enabled root-causing this issue. Also, many thanks to Jakub Kicinski for testing this fix. Fixes: 5ae344c ("tcp: reduce spurious retransmits due to transient SACK reneging") Reported-by: Jakub Kicinski <[email protected]> Reported-by: Neil Spring <[email protected]> Signed-off-by: Neal Cardwell <[email protected]> Reviewed-by: Eric Dumazet <[email protected]> Cc: Yuchung Cheng <[email protected]> Tested-by: Jakub Kicinski <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent e28c444 commit 3d2af9c

File tree

1 file changed

+2
-1
lines changed

1 file changed

+2
-1
lines changed

net/ipv4/tcp_input.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2192,7 +2192,8 @@ void tcp_enter_loss(struct sock *sk)
21922192
*/
21932193
static bool tcp_check_sack_reneging(struct sock *sk, int flag)
21942194
{
2195-
if (flag & FLAG_SACK_RENEGING) {
2195+
if (flag & FLAG_SACK_RENEGING &&
2196+
flag & FLAG_SND_UNA_ADVANCED) {
21962197
struct tcp_sock *tp = tcp_sk(sk);
21972198
unsigned long delay = max(usecs_to_jiffies(tp->srtt_us >> 4),
21982199
msecs_to_jiffies(10));

0 commit comments

Comments
 (0)