git: 30409ecdb648 - main - tcp: do not purge SACK scoreboard on first RTO
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 06 Jan 2024 19:44:06 UTC
The branch main has been updated by rscheff: URL: https://cgit.FreeBSD.org/src/commit/?id=30409ecdb648901223f4e02e4a575d79c447acab commit 30409ecdb648901223f4e02e4a575d79c447acab Author: Richard Scheffenegger <rscheff@FreeBSD.org> AuthorDate: 2024-01-06 19:25:17 +0000 Commit: Richard Scheffenegger <rscheff@FreeBSD.org> CommitDate: 2024-01-06 19:25:38 +0000 tcp: do not purge SACK scoreboard on first RTO Keeping the SACK scoreboard intact after the first RTO and retransmitting all data anew only on subsequent RTOs allows a more timely and efficient loss recovery under many adverse cirumstances. Reviewed By: tuexen, #transport MFC after: 10 weeks Sponsored by: NetApp, Inc. Differential Revision: https://reviews.freebsd.org/D42906 --- sys/netinet/tcp_input.c | 5 ++++- sys/netinet/tcp_sack.c | 19 +++++++++++++++++++ sys/netinet/tcp_timer.c | 6 ++++-- sys/netinet/tcp_var.h | 1 + 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 1d6430f6ef20..4a6100fc969b 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -439,7 +439,10 @@ cc_cong_signal(struct tcpcb *tp, struct tcphdr *th, uint32_t type) case CC_RTO: tp->t_dupacks = 0; tp->t_bytes_acked = 0; - EXIT_RECOVERY(tp->t_flags); + if ((tp->t_rxtshift > 1) || + !((tp->t_flags & TF_SACK_PERMIT) && + (!TAILQ_EMPTY(&tp->snd_holes)))) + EXIT_RECOVERY(tp->t_flags); if (tp->t_flags2 & TF2_ECN_PERMIT) tp->t_flags2 |= TF2_ECN_SND_CWR; break; diff --git a/sys/netinet/tcp_sack.c b/sys/netinet/tcp_sack.c index e8ed3c52fd67..48efe855f689 100644 --- a/sys/netinet/tcp_sack.c +++ b/sys/netinet/tcp_sack.c @@ -908,6 +908,25 @@ tcp_free_sackholes(struct tcpcb *tp) ("tp->sackhint.nexthole == NULL")); } +/* + * Resend all the currently existing SACK holes of + * the scoreboard. This is in line with the Errata to + * RFC 2018, which allows the use of SACK data past + * an RTO to good effect typically. + */ +void +tcp_resend_sackholes(struct tcpcb *tp) +{ + struct sackhole *p; + + INP_WLOCK_ASSERT(tptoinpcb(tp)); + TAILQ_FOREACH(p, &tp->snd_holes, scblink) { + p->rxmit = p->start; + } + tp->sackhint.nexthole = TAILQ_FIRST(&tp->snd_holes); + tp->sackhint.sack_bytes_rexmit = 0; +} + /* * Partial ack handling within a sack recovery episode. Keeping this very * simple for now. When a partial ack is received, force snd_cwnd to a value diff --git a/sys/netinet/tcp_timer.c b/sys/netinet/tcp_timer.c index 952fa53e0275..125e28134c01 100644 --- a/sys/netinet/tcp_timer.c +++ b/sys/netinet/tcp_timer.c @@ -559,7 +559,6 @@ tcp_timer_rexmt(struct tcpcb *tp) TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); CURVNET_SET(inp->inp_vnet); - tcp_free_sackholes(tp); if (tp->t_fb->tfb_tcp_rexmit_tmr) { /* The stack has a timer action too. */ (*tp->t_fb->tfb_tcp_rexmit_tmr)(tp); @@ -619,8 +618,11 @@ tcp_timer_rexmt(struct tcpcb *tp) * the retransmitted packet's to_tsval to by tcp_output */ tp->t_flags |= TF_PREVVALID; - } else + tcp_resend_sackholes(tp); + } else { tp->t_flags &= ~TF_PREVVALID; + tcp_free_sackholes(tp); + } TCPSTAT_INC(tcps_rexmttimeo); if ((tp->t_state == TCPS_SYN_SENT) || (tp->t_state == TCPS_SYN_RECEIVED)) diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index c2b15526c15b..5f064ead7f64 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -1499,6 +1499,7 @@ struct sackhole *tcp_sack_output(struct tcpcb *tp, int *sack_bytes_rexmt); void tcp_do_prr_ack(struct tcpcb *, struct tcphdr *, struct tcpopt *, sackstatus_t); void tcp_lost_retransmission(struct tcpcb *, struct tcphdr *); void tcp_sack_partialack(struct tcpcb *, struct tcphdr *); +void tcp_resend_sackholes(struct tcpcb *tp); void tcp_free_sackholes(struct tcpcb *tp); void tcp_sack_lost_retransmission(struct tcpcb *, struct tcphdr *); int tcp_newreno(struct tcpcb *, struct tcphdr *);