git: c7c325d01de4 - main - tcp: pass maxseg around instead of calculating locally

From: Richard Scheffenegger <rscheff_at_FreeBSD.org>
Date: Wed, 24 Jan 2024 16:41:17 UTC
The branch main has been updated by rscheff:

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

commit c7c325d01de4a1509e0a978f28275279de692130
Author:     Richard Scheffenegger <rscheff@FreeBSD.org>
AuthorDate: 2024-01-24 15:42:29 +0000
Commit:     Richard Scheffenegger <rscheff@FreeBSD.org>
CommitDate: 2024-01-24 15:43:29 +0000

    tcp: pass maxseg around instead of calculating locally
    
    Improve slowpath processing (reordering, retransmissions)
    slightly by calculating maxseg only once. This typically
    saves one of two calls to tcp_maxseg().
    
    Reviewed By:           glebius, tuexen, cc, #transport
    Sponsored by:          NetApp, Inc.
    Differential Revision: https://reviews.freebsd.org/D43536
---
 sys/netinet/tcp_input.c | 37 +++++++++++++++++++++++++------------
 sys/netinet/tcp_sack.c  |  9 +++++++--
 sys/netinet/tcp_var.h   |  8 +++++---
 3 files changed, 37 insertions(+), 17 deletions(-)

diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index ed5f28490852..02b042fd3273 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -1529,7 +1529,7 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
 	struct mbuf *mfree;
 	struct tcpopt to;
 	int tfo_syn;
-	u_int maxseg;
+	u_int maxseg = 0;
 
 	thflags = tcp_get_flags(th);
 	tp->sackhint.last_sack_ack = 0;
@@ -2596,7 +2596,8 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
 					if (V_tcp_do_prr &&
 					    IN_FASTRECOVERY(tp->t_flags) &&
 					    (tp->t_flags & TF_SACK_PERMIT)) {
-						tcp_do_prr_ack(tp, th, &to, sack_changed);
+						tcp_do_prr_ack(tp, th, &to,
+						    sack_changed, &maxseg);
 					} else if (tcp_is_sack_recovery(tp, &to) &&
 					    IN_FASTRECOVERY(tp->t_flags)) {
 						int awnd;
@@ -2801,19 +2802,24 @@ resume_partialack:
 		 */
 		if (IN_FASTRECOVERY(tp->t_flags)) {
 			if (SEQ_LT(th->th_ack, tp->snd_recover)) {
-				if (tp->t_flags & TF_SACK_PERMIT)
+				if (tp->t_flags & TF_SACK_PERMIT) {
 					if (V_tcp_do_prr && to.to_flags & TOF_SACK) {
 						tcp_timer_activate(tp, TT_REXMT, 0);
 						tp->t_rtttime = 0;
-						tcp_do_prr_ack(tp, th, &to, sack_changed);
+						tcp_do_prr_ack(tp, th, &to,
+						    sack_changed, &maxseg);
 						tp->t_flags |= TF_ACKNOW;
 						(void) tcp_output(tp);
-					} else
-						tcp_sack_partialack(tp, th);
-				else
+					} else {
+						tcp_sack_partialack(tp, th,
+						    &maxseg);
+					}
+				} else {
 					tcp_newreno_partial_ack(tp, th);
-			} else
+				}
+			} else {
 				cc_post_recovery(tp, th);
+			}
 		} else if (IN_CONGRECOVERY(tp->t_flags)) {
 			if (SEQ_LT(th->th_ack, tp->snd_recover)) {
 				if (V_tcp_do_prr) {
@@ -2823,11 +2829,13 @@ resume_partialack:
 					 * During ECN cwnd reduction
 					 * always use PRR-SSRB
 					 */
-					tcp_do_prr_ack(tp, th, &to, SACK_CHANGE);
+					tcp_do_prr_ack(tp, th, &to, SACK_CHANGE,
+					    &maxseg);
 					(void) tcp_output(tp);
 				}
-			} else
+			} else {
 				cc_post_recovery(tp, th);
+			}
 		}
 		/*
 		 * If we reach this point, ACK is not a duplicate,
@@ -3946,13 +3954,18 @@ tcp_mssopt(struct in_conninfo *inc)
 }
 
 void
-tcp_do_prr_ack(struct tcpcb *tp, struct tcphdr *th, struct tcpopt *to, sackstatus_t sack_changed)
+tcp_do_prr_ack(struct tcpcb *tp, struct tcphdr *th, struct tcpopt *to,
+    sackstatus_t sack_changed, u_int *maxsegp)
 {
 	int snd_cnt = 0, limit = 0, del_data = 0, pipe = 0;
-	int maxseg = tcp_maxseg(tp);
+	u_int maxseg;
 
 	INP_WLOCK_ASSERT(tptoinpcb(tp));
 
+	if (*maxsegp == 0) {
+		*maxsegp = tcp_maxseg(tp);
+	}
+	maxseg = *maxsegp;
 	/*
 	 * Compute the amount of data that this ACK is indicating
 	 * (del_data) and an estimate of how many bytes are in the
diff --git a/sys/netinet/tcp_sack.c b/sys/netinet/tcp_sack.c
index f9ca83850c09..f517bb9fcdb7 100644
--- a/sys/netinet/tcp_sack.c
+++ b/sys/netinet/tcp_sack.c
@@ -936,13 +936,18 @@ tcp_resend_sackholes(struct tcpcb *tp)
  * the midst of sack recovery.
  */
 void
-tcp_sack_partialack(struct tcpcb *tp, struct tcphdr *th)
+tcp_sack_partialack(struct tcpcb *tp, struct tcphdr *th, u_int *maxsegp)
 {
 	struct sackhole *temp;
 	int num_segs = 1;
-	u_int maxseg = tcp_maxseg(tp);
+	u_int maxseg;
 
 	INP_WLOCK_ASSERT(tptoinpcb(tp));
+
+	if (*maxsegp == 0) {
+		*maxsegp = tcp_maxseg(tp);
+	}
+	maxseg = *maxsegp;
 	tcp_timer_activate(tp, TT_REXMT, 0);
 	tp->t_rtttime = 0;
 	/* Send one or 2 segments based on how much new data was acked. */
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index f9b3d1a5c3ee..cbe8de7988c7 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -1481,14 +1481,16 @@ sackstatus_t
 	 tcp_sack_doack(struct tcpcb *, struct tcpopt *, tcp_seq);
 int	 tcp_dsack_block_exists(struct tcpcb *);
 void	 tcp_update_dsack_list(struct tcpcb *, tcp_seq, tcp_seq);
-void	 tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_laststart, tcp_seq rcv_lastend);
+void	 tcp_update_sack_list(struct tcpcb *tp, tcp_seq rcv_laststart,
+	    tcp_seq rcv_lastend);
 void	 tcp_clean_dsack_blocks(struct tcpcb *tp);
 void	 tcp_clean_sackreport(struct tcpcb *tp);
 void	 tcp_sack_adjust(struct tcpcb *tp);
 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_do_prr_ack(struct tcpcb *, struct tcphdr *, struct tcpopt *,
+	    sackstatus_t, u_int *);
 void	 tcp_lost_retransmission(struct tcpcb *, struct tcphdr *);
-void	 tcp_sack_partialack(struct tcpcb *, struct tcphdr *);
+void	 tcp_sack_partialack(struct tcpcb *, struct tcphdr *, u_int *);
 void	 tcp_resend_sackholes(struct tcpcb *tp);
 void	 tcp_free_sackholes(struct tcpcb *tp);
 void	 tcp_sack_lost_retransmission(struct tcpcb *, struct tcphdr *);