git: 32a6df57df3e - main - tcp: calculate ssthresh on RTO according to RFC5681

From: Richard Scheffenegger <rscheff_at_FreeBSD.org>
Date: Thu, 08 Feb 2024 18:55:14 UTC
The branch main has been updated by rscheff:

URL: https://cgit.FreeBSD.org/src/commit/?id=32a6df57df3ef5783bc4bb066cce9c476496e7a9

commit 32a6df57df3ef5783bc4bb066cce9c476496e7a9
Author:     Richard Scheffenegger <rscheff@FreeBSD.org>
AuthorDate: 2024-02-08 18:12:19 +0000
Commit:     Richard Scheffenegger <rscheff@FreeBSD.org>
CommitDate: 2024-02-08 18:18:26 +0000

    tcp: calculate ssthresh on RTO according to RFC5681
    
    per RFC5681, only adjust ssthresh on the initital
    retransmission timeout. Since RTO often happens
    during loss recovery, while cwnd no longer tracks
    all data in flight, calculcate pipe properly.
    
    Reviewed By:           tuexen, #transport
    Sponsored by:          NetApp, Inc.
    Differential Revision: https://reviews.freebsd.org/D43768
---
 sys/netinet/cc/cc.c           | 17 ++++++++++++-----
 sys/netinet/cc/cc_cubic.c     | 14 +++++++++++---
 sys/netinet/cc/cc_dctcp.c     | 16 ++++++++++++----
 sys/netinet/cc/cc_htcp.c      | 16 ++++++++++++----
 sys/netinet/cc/cc_newreno.c   | 19 ++++++++++++++-----
 sys/netinet/tcp_stacks/rack.c |  7 +++++--
 6 files changed, 66 insertions(+), 23 deletions(-)

diff --git a/sys/netinet/cc/cc.c b/sys/netinet/cc/cc.c
index ff25b8368cc4..a3d19e31d438 100644
--- a/sys/netinet/cc/cc.c
+++ b/sys/netinet/cc/cc.c
@@ -454,8 +454,7 @@ newreno_cc_after_idle(struct cc_var *ccv)
 void
 newreno_cc_cong_signal(struct cc_var *ccv, uint32_t type)
 {
-	uint32_t cwin, factor;
-	u_int mss;
+	uint32_t cwin, factor, mss, pipe;
 
 	cwin = CCV(ccv, snd_cwnd);
 	mss = tcp_fixed_maxseg(ccv->ccvc.tcp);
@@ -489,9 +488,17 @@ newreno_cc_cong_signal(struct cc_var *ccv, uint32_t type)
 		}
 		break;
 	case CC_RTO:
-		CCV(ccv, snd_ssthresh) = max(min(CCV(ccv, snd_wnd),
-						 CCV(ccv, snd_cwnd)) / 2 / mss,
-					     2) * mss;
+		if (CCV(ccv, t_rxtshift) == 1) {
+			if (V_tcp_do_newsack) {
+				pipe = tcp_compute_pipe(ccv->ccvc.tcp);
+			} else {
+				pipe = CCV(ccv, snd_nxt) -
+					CCV(ccv, snd_fack) +
+					CCV(ccv, sackhint.sack_bytes_rexmit);
+			}
+			CCV(ccv, snd_ssthresh) = max(2,
+				min(CCV(ccv, snd_wnd), pipe) / 2 / mss) * mss;
+		}
 		CCV(ccv, snd_cwnd) = mss;
 		break;
 	}
diff --git a/sys/netinet/cc/cc_cubic.c b/sys/netinet/cc/cc_cubic.c
index 3f7ba630db5d..dcb096af6cbf 100644
--- a/sys/netinet/cc/cc_cubic.c
+++ b/sys/netinet/cc/cc_cubic.c
@@ -420,7 +420,7 @@ static void
 cubic_cong_signal(struct cc_var *ccv, uint32_t type)
 {
 	struct cubic *cubic_data;
-	u_int mss;
+	uint32_t mss, pipe;
 
 	cubic_data = ccv->cc_data;
 	mss = tcp_fixed_maxseg(ccv->ccvc.tcp);
@@ -476,12 +476,20 @@ cubic_cong_signal(struct cc_var *ccv, uint32_t type)
 			cubic_data->undo_cwnd_prior = cubic_data->cwnd_prior;
 			cubic_data->undo_W_max = cubic_data->W_max;
 			cubic_data->undo_K = cubic_data->K;
+			if (V_tcp_do_newsack) {
+				pipe = tcp_compute_pipe(ccv->ccvc.tcp);
+			} else {
+				pipe = CCV(ccv, snd_nxt) -
+					CCV(ccv, snd_fack) +
+					CCV(ccv, sackhint.sack_bytes_rexmit);
+			}
+			CCV(ccv, snd_ssthresh) = max(2,
+				(((uint64_t)min(CCV(ccv, snd_wnd), pipe) *
+				CUBIC_BETA) >> CUBIC_SHIFT) / mss) * mss;
 		}
 		cubic_data->flags |= CUBICFLAG_CONG_EVENT | CUBICFLAG_RTO_EVENT;
 		cubic_data->undo_W_max = cubic_data->W_max;
 		cubic_data->num_cong_events++;
-			CCV(ccv, snd_ssthresh) = ((uint64_t)CCV(ccv, snd_cwnd) *
-					  CUBIC_BETA) >> CUBIC_SHIFT;
 		CCV(ccv, snd_cwnd) = mss;
 		break;
 
diff --git a/sys/netinet/cc/cc_dctcp.c b/sys/netinet/cc/cc_dctcp.c
index efb8913ec36c..41db7e0811aa 100644
--- a/sys/netinet/cc/cc_dctcp.c
+++ b/sys/netinet/cc/cc_dctcp.c
@@ -240,7 +240,7 @@ static void
 dctcp_cong_signal(struct cc_var *ccv, uint32_t type)
 {
 	struct dctcp *dctcp_data;
-	u_int cwin, mss;
+	uint32_t cwin, mss, pipe;
 
 	if (CCV(ccv, t_flags2) & TF2_ECN_PERMIT) {
 		dctcp_data = ccv->cc_data;
@@ -292,9 +292,17 @@ dctcp_cong_signal(struct cc_var *ccv, uint32_t type)
 			dctcp_data->ece_curr = 1;
 			break;
 		case CC_RTO:
-			CCV(ccv, snd_ssthresh) = max(min(CCV(ccv, snd_wnd),
-							 CCV(ccv, snd_cwnd)) / 2 / mss,
-						     2) * mss;
+			if (CCV(ccv, t_rxtshift) == 1) {
+				if (V_tcp_do_newsack) {
+					pipe = tcp_compute_pipe(ccv->ccvc.tcp);
+				} else {
+					pipe = CCV(ccv, snd_nxt) -
+						CCV(ccv, snd_fack) +
+						CCV(ccv, sackhint.sack_bytes_rexmit);
+				}
+				CCV(ccv, snd_ssthresh) = max(2,
+					min(CCV(ccv, snd_wnd), pipe) / 2 / mss) * mss;
+			}
 			CCV(ccv, snd_cwnd) = mss;
 			dctcp_update_alpha(ccv);
 			dctcp_data->save_sndnxt += CCV(ccv, t_maxseg);
diff --git a/sys/netinet/cc/cc_htcp.c b/sys/netinet/cc/cc_htcp.c
index c9304fcfc8e5..7500446d3051 100644
--- a/sys/netinet/cc/cc_htcp.c
+++ b/sys/netinet/cc/cc_htcp.c
@@ -281,7 +281,7 @@ static void
 htcp_cong_signal(struct cc_var *ccv, uint32_t type)
 {
 	struct htcp *htcp_data;
-	u_int mss;
+	uint32_t mss, pipe;
 
 	htcp_data = ccv->cc_data;
 	mss = tcp_fixed_maxseg(ccv->ccvc.tcp);
@@ -323,9 +323,17 @@ htcp_cong_signal(struct cc_var *ccv, uint32_t type)
 		break;
 
 	case CC_RTO:
-		CCV(ccv, snd_ssthresh) = max(min(CCV(ccv, snd_wnd),
-						 CCV(ccv, snd_cwnd)) / 2 / mss,
-					     2) * mss;
+		if (CCV(ccv, t_rxtshift) == 1) {
+			if (V_tcp_do_newsack) {
+				pipe = tcp_compute_pipe(ccv->ccvc.tcp);
+			} else {
+				pipe = CCV(ccv, snd_nxt) -
+					CCV(ccv, snd_fack) +
+					CCV(ccv, sackhint.sack_bytes_rexmit);
+			}
+			CCV(ccv, snd_ssthresh) = max(2,
+				min(CCV(ccv, snd_wnd), pipe) / 2 / mss) * mss;
+		}
 		CCV(ccv, snd_cwnd) = mss;
 		/*
 		 * Grab the current time and record it so we know when the
diff --git a/sys/netinet/cc/cc_newreno.c b/sys/netinet/cc/cc_newreno.c
index 53d066682a7d..4f55fb7e0f7a 100644
--- a/sys/netinet/cc/cc_newreno.c
+++ b/sys/netinet/cc/cc_newreno.c
@@ -366,8 +366,7 @@ static void
 newreno_cong_signal(struct cc_var *ccv, uint32_t type)
 {
 	struct newreno *nreno;
-	uint32_t beta, beta_ecn, cwin, factor;
-	u_int mss;
+	uint32_t beta, beta_ecn, cwin, factor, mss, pipe;
 
 	cwin = CCV(ccv, snd_cwnd);
 	mss = tcp_fixed_maxseg(ccv->ccvc.tcp);
@@ -428,9 +427,19 @@ newreno_cong_signal(struct cc_var *ccv, uint32_t type)
 		}
 		break;
 	case CC_RTO:
-		CCV(ccv, snd_ssthresh) = max(min(CCV(ccv, snd_wnd),
-						 CCV(ccv, snd_cwnd)) / 2 / mss,
-					     2) * mss;
+		if (CCV(ccv, t_rxtshift) == 1) {
+			if (V_tcp_do_newsack) {
+				pipe = tcp_compute_pipe(ccv->ccvc.tcp);
+			} else {
+				pipe = CCV(ccv, snd_nxt) -
+					CCV(ccv, snd_fack) +
+					CCV(ccv, sackhint.sack_bytes_rexmit);
+			}
+			CCV(ccv, snd_ssthresh) = max(2,
+				((uint64_t)min(CCV(ccv, snd_wnd), pipe) *
+				    (uint64_t)factor) /
+				    (100ULL * (uint64_t)mss)) * mss;
+		}
 		CCV(ccv, snd_cwnd) = mss;
 		break;
 	}
diff --git a/sys/netinet/tcp_stacks/rack.c b/sys/netinet/tcp_stacks/rack.c
index 10ab20f00e26..0ec50bb5e5c5 100644
--- a/sys/netinet/tcp_stacks/rack.c
+++ b/sys/netinet/tcp_stacks/rack.c
@@ -5948,8 +5948,11 @@ rack_cong_signal(struct tcpcb *tp, uint32_t type, uint32_t ack, int line)
 		tp->t_bytes_acked = 0;
 		rack->r_fast_output = 0;
 		EXIT_RECOVERY(tp->t_flags);
-		tp->snd_ssthresh = max(2, min(tp->snd_wnd, rack->r_ctl.cwnd_to_use) / 2 /
-		    ctf_fixed_maxseg(tp)) * ctf_fixed_maxseg(tp);
+		if (tp->t_rxtshift == 1) {
+			tp->snd_ssthresh = max(2,
+			    min(tp->snd_wnd, rack->r_ctl.cwnd_to_use) / 2 /
+			    ctf_fixed_maxseg(tp)) * ctf_fixed_maxseg(tp);
+		}
 		orig_cwnd = tp->snd_cwnd;
 		tp->snd_cwnd = ctf_fixed_maxseg(tp);
 		rack_log_to_prr(rack, 16, orig_cwnd, line);