tcp: consider using standard rtx logic in tcp_rcv_fastopen_synack()

Jakub reported Data included in a Fastopen SYN that had to be
retransmit would have to wait for an RTO if TX completions are slow,
even with prior fix.

This is because tcp_rcv_fastopen_synack() does not use standard
rtx logic, meaning TSQ handler exits early in tcp_tsq_write()
because tp->lost_out == tp->retrans_out

Lets make tcp_rcv_fastopen_synack() use standard rtx logic,
by using tcp_mark_skb_lost() on the skb thats needs to be
sent again.

Not this raised a warning in tcp_fastretrans_alert() during my tests
since we consider the data not being aknowledged
by the receiver does not mean packet was lost on the network.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: Jakub Kicinski <kuba@kernel.org>
Cc: Neal Cardwell <ncardwell@google.com>
Cc: Yuchung Cheng <ycheng@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Eric Dumazet 2021-03-11 12:35:05 -08:00 committed by David S. Miller
parent f4dae54e48
commit a7abf3cd76
1 changed files with 4 additions and 6 deletions

View File

@ -2914,7 +2914,7 @@ static void tcp_fastretrans_alert(struct sock *sk, const u32 prior_snd_una,
/* D. Check state exit conditions. State can be terminated /* D. Check state exit conditions. State can be terminated
* when high_seq is ACKed. */ * when high_seq is ACKed. */
if (icsk->icsk_ca_state == TCP_CA_Open) { if (icsk->icsk_ca_state == TCP_CA_Open) {
WARN_ON(tp->retrans_out != 0); WARN_ON(tp->retrans_out != 0 && !tp->syn_data);
tp->retrans_stamp = 0; tp->retrans_stamp = 0;
} else if (!before(tp->snd_una, tp->high_seq)) { } else if (!before(tp->snd_una, tp->high_seq)) {
switch (icsk->icsk_ca_state) { switch (icsk->icsk_ca_state) {
@ -5994,11 +5994,9 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack,
tp->fastopen_client_fail = TFO_SYN_RETRANSMITTED; tp->fastopen_client_fail = TFO_SYN_RETRANSMITTED;
else else
tp->fastopen_client_fail = TFO_DATA_NOT_ACKED; tp->fastopen_client_fail = TFO_DATA_NOT_ACKED;
skb_rbtree_walk_from(data) { skb_rbtree_walk_from(data)
if (__tcp_retransmit_skb(sk, data, 1)) tcp_mark_skb_lost(sk, data);
break; tcp_xmit_retransmit_queue(sk);
}
tcp_rearm_rto(sk);
NET_INC_STATS(sock_net(sk), NET_INC_STATS(sock_net(sk),
LINUX_MIB_TCPFASTOPENACTIVEFAIL); LINUX_MIB_TCPFASTOPENACTIVEFAIL);
return true; return true;