Message ID | 20240703171246.1739561-1-ncardwell.sw@gmail.com (mailing list archive) |
---|---|
State | Accepted |
Commit | 0ec986ed7bab6801faed1440e8839dcc710331ff |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | [net] tcp: fix incorrect undo caused by DSACK of TLP retransmit | expand |
Hello: This patch was applied to netdev/net.git (main) by Jakub Kicinski <kuba@kernel.org>: On Wed, 3 Jul 2024 13:12:46 -0400 you wrote: > From: Neal Cardwell <ncardwell@google.com> > > 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. > > [...] Here is the summary with links: - [net] tcp: fix incorrect undo caused by DSACK of TLP retransmit https://git.kernel.org/netdev/net/c/0ec986ed7bab You are awesome, thank you!
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index e67cbeeeb95b..3d8f597989e3 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2129,8 +2129,16 @@ void tcp_clear_retrans(struct tcp_sock *tp) static inline void tcp_init_undo(struct tcp_sock *tp) { tp->undo_marker = tp->snd_una; + /* Retransmission still in flight may cause DSACKs later. */ - tp->undo_retrans = tp->retrans_out ? : -1; + /* First, account for regular retransmits in flight: */ + tp->undo_retrans = tp->retrans_out; + /* Next, account for TLP retransmits in flight: */ + if (tp->tlp_high_seq && tp->tlp_retrans) + tp->undo_retrans++; + /* Finally, avoid 0, because undo_retrans==0 means "can undo now": */ + if (!tp->undo_retrans) + tp->undo_retrans = -1; } static bool tcp_is_rack(const struct sock *sk) @@ -2209,6 +2217,7 @@ void tcp_enter_loss(struct sock *sk) tcp_set_ca_state(sk, TCP_CA_Loss); tp->high_seq = tp->snd_nxt; + tp->tlp_high_seq = 0; tcp_ecn_queue_cwr(tp); /* F-RTO RFC5682 sec 3.1 step 1: retransmit SND.UNA if no previous diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 5bfd76a31af6..db9d826560e5 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -536,8 +536,6 @@ void tcp_retransmit_timer(struct sock *sk) if (WARN_ON_ONCE(!skb)) return; - tp->tlp_high_seq = 0; - if (!tp->snd_wnd && !sock_flag(sk, SOCK_DEAD) && !((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV))) { /* Receiver dastardly shrinks window. Our retransmits