git: 04cd9bca4dab - main - tcp: refactor tcp_autorcvbuf() and associated sysctls

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Thu, 22 Oct 2026 03:31:24 UTC
The branch main has been updated by glebius:

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

commit 04cd9bca4dab67c45292c59bbf6d78ce66fc5628
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2026-10-22 03:27:36 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2026-10-22 03:27:36 +0000

    tcp: refactor tcp_autorcvbuf() and associated sysctls
    
    Run the entire function under the socket buffer lock.  Make it responsible
    to set the new limit or clear SB_AUTOSIZE in case of a failure.  Use
    unsigned type for newsize, that matches both the sb_hiwat type and min()
    argument types.  Make byte counter in the tcpcb unsigned, too.  Make the
    sizing tunables unsigned, and make the switching tunable a boolean.  Don't
    execute Dtrace probe in case of a failure.  Simplify the Dtrace probe to
    report only relevant information, the previous probe looked more like a
    leftover from a debugging session.
    
    Reviewed by:            tuexen
    Differential Revision:  https://reviews.freebsd.org/D60731
---
 sys/netinet/in_kdtrace.c      |  8 ++-----
 sys/netinet/tcp_input.c       | 50 ++++++++++++++++++++-----------------------
 sys/netinet/tcp_stacks/bbr.c  | 11 +---------
 sys/netinet/tcp_stacks/rack.c | 20 +++--------------
 sys/netinet/tcp_usrreq.c      |  2 +-
 sys/netinet/tcp_var.h         | 11 +++++-----
 6 files changed, 35 insertions(+), 67 deletions(-)

diff --git a/sys/netinet/in_kdtrace.c b/sys/netinet/in_kdtrace.c
index 917e6b8be137..a44b4c8ed476 100644
--- a/sys/netinet/in_kdtrace.c
+++ b/sys/netinet/in_kdtrace.c
@@ -539,13 +539,9 @@ SDT_PROBE_DEFINE6_XLATE(tcp, , , state__change,
     "void *", "void *",
     "int", "tcplsinfo_t *");
 
-SDT_PROBE_DEFINE6_XLATE(tcp, , , receive__autoresize,
-    "void *", "void *",
-    "struct tcpcb *", "csinfo_t *",
-    "struct mbuf *", "ipinfo_t *",
+SDT_PROBE_DEFINE2_XLATE(tcp, , , receive__autoresize,
     "struct tcpcb *", "tcpsinfo_t *" ,
-    "struct tcphdr *", "tcpinfoh_t *",
-    "int", "int");
+    "u_int", "u_int");
 
 SDT_PROBE_DEFINE5_XLATE(udp, , , receive,
     "void *", "pktinfo_t *",
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 202438632238..5ebcad5eae43 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -208,18 +208,19 @@ SYSCTL_INT(_net_inet_tcp, OID_AUTO, insecure_ack, CTLFLAG_VNET | CTLFLAG_RW,
     &VNET_NAME(tcp_insecure_ack), 0,
     "Follow RFC793 criteria for validating SEG.ACK");
 
-VNET_DEFINE(int, tcp_recvspace) = 1024*64;
+VNET_DEFINE(u_int, tcp_recvspace) = 1024*64;
 #define	V_tcp_recvspace	VNET(tcp_recvspace)
-SYSCTL_INT(_net_inet_tcp, TCPCTL_RECVSPACE, recvspace, CTLFLAG_VNET | CTLFLAG_RW,
-    &VNET_NAME(tcp_recvspace), 0, "Initial receive socket buffer size");
+SYSCTL_UINT(_net_inet_tcp, TCPCTL_RECVSPACE, recvspace,
+    CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(tcp_recvspace), 0,
+    "Initial receive socket buffer size");
 
-VNET_DEFINE(int, tcp_do_autorcvbuf) = 1;
-SYSCTL_INT(_net_inet_tcp, OID_AUTO, recvbuf_auto, CTLFLAG_VNET | CTLFLAG_RW,
+VNET_DEFINE(bool, tcp_do_autorcvbuf) = true;
+SYSCTL_BOOL(_net_inet_tcp, OID_AUTO, recvbuf_auto, CTLFLAG_VNET | CTLFLAG_RW,
     &VNET_NAME(tcp_do_autorcvbuf), 0,
     "Enable automatic receive buffer sizing");
 
-VNET_DEFINE(int, tcp_autorcvbuf_max) = 8*1024*1024;
-SYSCTL_INT(_net_inet_tcp, OID_AUTO, recvbuf_max, CTLFLAG_VNET | CTLFLAG_RW,
+VNET_DEFINE(u_int, tcp_autorcvbuf_max) = 8*1024*1024;
+SYSCTL_UINT(_net_inet_tcp, OID_AUTO, recvbuf_max, CTLFLAG_VNET | CTLFLAG_RW,
     &VNET_NAME(tcp_autorcvbuf_max), 0,
     "Max size of automatic receive buffer");
 
@@ -1415,11 +1416,12 @@ drop:
  * TODO: Only step up if the application is actually serving
  * the buffer to better manage the socket buffer resources.
  */
-int
-tcp_autorcvbuf(struct mbuf *m, struct tcphdr *th, struct socket *so,
-    struct tcpcb *tp, int tlen)
+void
+tcp_autorcvbuf(struct tcpcb *tp, u_int tlen)
 {
-	int newsize = 0;
+	struct socket *so = tptosocket(tp);
+
+	SOCK_RECVBUF_LOCK_ASSERT(so);
 
 	if (V_tcp_do_autorcvbuf && (so->so_rcv.sb_flags & SB_AUTOSIZE) &&
 	    tp->t_srtt != 0 && tp->rfbuf_ts != 0 &&
@@ -1427,17 +1429,22 @@ tcp_autorcvbuf(struct mbuf *m, struct tcphdr *th, struct socket *so,
 	    ((tp->t_srtt >> TCP_RTT_SHIFT)/2)) {
 		if (tp->rfbuf_cnt > ((so->so_rcv.sb_hiwat / 2)/ 4 * 3) &&
 		    so->so_rcv.sb_hiwat < V_tcp_autorcvbuf_max) {
-			newsize = min((so->so_rcv.sb_hiwat + (so->so_rcv.sb_hiwat/2)), V_tcp_autorcvbuf_max);
-		}
-		TCP_PROBE6(receive__autoresize, NULL, tp, m, tp, th, newsize);
+			u_int newsize;
 
+			newsize = min((so->so_rcv.sb_hiwat +
+			    (so->so_rcv.sb_hiwat / 2)), V_tcp_autorcvbuf_max);
+			if (sbreserve_locked(so, SO_RCV, newsize, NULL)) {
+				TCP_PROBE2(receive__autoresize, tp, newsize);
+			} else {
+				so->so_rcv.sb_flags &= ~SB_AUTOSIZE;
+			}
+		}
 		/* Start over with next RTT. */
 		tp->rfbuf_ts = 0;
 		tp->rfbuf_cnt = 0;
 	} else {
 		tp->rfbuf_cnt += tlen;	/* add up */
 	}
-	return (newsize);
 }
 
 int
@@ -1838,8 +1845,6 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
 			}
 		} else if (th->th_ack == tp->snd_una &&
 		    tlen <= sbspace(&so->so_rcv)) {
-			int newsize = 0;	/* automatic sockbuf scaling */
-
 			/*
 			 * This is a pure, in-sequence data packet with
 			 * nothing on the reassembly queue and we have enough
@@ -1873,21 +1878,12 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
 			TCPSTAT_ADD(tcps_rcvbyte, tlen);
 			TCP_PROBE3(debug__input, tp, th, m);
 
-			newsize = tcp_autorcvbuf(m, th, so, tp, tlen);
-
 			/* Add data to socket buffer. */
 			SOCK_RECVBUF_LOCK(so);
 			if (so->so_rcv.sb_state & SBS_CANTRCVMORE) {
 				m_freem(m);
 			} else {
-				/*
-				 * Set new socket buffer size.
-				 * Give up when limit is reached.
-				 */
-				if (newsize)
-					if (!sbreserve_locked(so, SO_RCV,
-					    newsize, NULL))
-						so->so_rcv.sb_flags &= ~SB_AUTOSIZE;
+				tcp_autorcvbuf(tp, tlen);
 				m_adj(m, drop_hdrlen);	/* delayed header drop */
 				sbappendstream_locked(&so->so_rcv, m, 0);
 			}
diff --git a/sys/netinet/tcp_stacks/bbr.c b/sys/netinet/tcp_stacks/bbr.c
index 13cbc885c80a..a055f6d756ac 100644
--- a/sys/netinet/tcp_stacks/bbr.c
+++ b/sys/netinet/tcp_stacks/bbr.c
@@ -8419,7 +8419,6 @@ bbr_do_fastnewdata(struct mbuf *m, struct tcphdr *th, struct socket *so,
     uint32_t tiwin, int32_t nxt_pkt)
 {
 	uint16_t nsegs;
-	int32_t newsize = 0;	/* automatic sockbuf scaling */
 	struct tcp_bbr *bbr;
 #ifdef NETFLIX_SB_LIMITS
 	u_int mcnt, appended;
@@ -8499,22 +8498,14 @@ bbr_do_fastnewdata(struct mbuf *m, struct tcphdr *th, struct socket *so,
 	tp->rcv_up = tp->rcv_nxt;
 	KMOD_TCPSTAT_ADD(tcps_rcvpack, (int)nsegs);
 	KMOD_TCPSTAT_ADD(tcps_rcvbyte, tlen);
-	newsize = tcp_autorcvbuf(m, th, so, tp, tlen);
 
 	/* Add data to socket buffer. */
 	SOCK_RECVBUF_LOCK(so);
 	if (so->so_rcv.sb_state & SBS_CANTRCVMORE) {
 		m_freem(m);
 	} else {
-		/*
-		 * Set new socket buffer size. Give up when limit is
-		 * reached.
-		 */
-		if (newsize)
-			if (!sbreserve_locked(so, SO_RCV, newsize, NULL))
-				so->so_rcv.sb_flags &= ~SB_AUTOSIZE;
+		tcp_autorcvbuf(tp, tlen);
 		m_adj(m, drop_hdrlen);	/* delayed header drop */
-
 #ifdef NETFLIX_SB_LIMITS
 		appended =
 #endif
diff --git a/sys/netinet/tcp_stacks/rack.c b/sys/netinet/tcp_stacks/rack.c
index c1f89a6286b4..227c765b1cee 100644
--- a/sys/netinet/tcp_stacks/rack.c
+++ b/sys/netinet/tcp_stacks/rack.c
@@ -12250,14 +12250,8 @@ rack_process_data(struct mbuf *m, struct tcphdr *th, struct socket *so,
 			if (so->so_rcv.sb_state & SBS_CANTRCVMORE) {
 				m_freem(m);
 			} else {
-				int32_t newsize;
-
-				if (tlen > 0) {
-					newsize = tcp_autorcvbuf(m, th, so, tp, tlen);
-					if (newsize)
-						if (!sbreserve_locked(so, SO_RCV, newsize, NULL))
-							so->so_rcv.sb_flags &= ~SB_AUTOSIZE;
-				}
+				if (tlen > 0)
+					tcp_autorcvbuf(tp, tlen);
 #ifdef NETFLIX_SB_LIMITS
 				appended =
 #endif
@@ -12407,7 +12401,6 @@ rack_do_fastnewdata(struct mbuf *m, struct tcphdr *th, struct socket *so,
     uint32_t tiwin, int32_t nxt_pkt, uint8_t iptos)
 {
 	int32_t nsegs;
-	int32_t newsize = 0;	/* automatic sockbuf scaling */
 	struct tcp_rack *rack;
 #ifdef NETFLIX_SB_LIMITS
 	u_int mcnt, appended;
@@ -12485,20 +12478,13 @@ rack_do_fastnewdata(struct mbuf *m, struct tcphdr *th, struct socket *so,
 	tp->rcv_up = tp->rcv_nxt;
 	KMOD_TCPSTAT_ADD(tcps_rcvpack, nsegs);
 	KMOD_TCPSTAT_ADD(tcps_rcvbyte, tlen);
-	newsize = tcp_autorcvbuf(m, th, so, tp, tlen);
 
 	/* Add data to socket buffer. */
 	SOCK_RECVBUF_LOCK(so);
 	if (so->so_rcv.sb_state & SBS_CANTRCVMORE) {
 		m_freem(m);
 	} else {
-		/*
-		 * Set new socket buffer size. Give up when limit is
-		 * reached.
-		 */
-		if (newsize)
-			if (!sbreserve_locked(so, SO_RCV, newsize, NULL))
-				so->so_rcv.sb_flags &= ~SB_AUTOSIZE;
+		tcp_autorcvbuf(tp, tlen);
 		m_adj(m, drop_hdrlen);	/* delayed header drop */
 #ifdef NETFLIX_SB_LIMITS
 		appended =
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index ac0c11a2233e..60b16fafdbb0 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -2884,7 +2884,7 @@ db_print_tcpcb(struct tcpcb *tp, const char *name, int indent, bool show_bblog,
 	/* Skip sackblks, sackhint. */
 
 	db_print_indent(indent);
-	db_printf("t_rttlow: %d   rfbuf_ts: %u   rfbuf_cnt: %d\n",
+	db_printf("t_rttlow: %d   rfbuf_ts: %u   rfbuf_cnt: %u\n",
 	    tp->t_rttlow, tp->rfbuf_ts, tp->rfbuf_cnt);
 
 	db_print_indent(indent);
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index 8400824761ed..75efd8eb92e0 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -422,7 +422,7 @@ struct tcpcb {
 	struct sackblk sackblks[MAX_SACK_BLKS]; /* seq nos. of sack blocks */
 	struct sackhint	sackhint;	/* SACK scoreboard hint */
 	int	t_rttlow;		/* smallest observerved RTT */
-	int	rfbuf_cnt;		/* recv buffer autoscaling byte count */
+	u_int	rfbuf_cnt;		/* recv buffer autoscaling byte count */
 	struct toedev	*tod;		/* toedev handling this connection */
 	int	t_sndrexmitpack;	/* retransmit packets sent */
 	int	t_rcvoopack;		/* out-of-order packets received */
@@ -1303,13 +1303,13 @@ VNET_DECLARE(int, path_mtu_discovery);
 VNET_DECLARE(int, tcp_abc_l_var);
 VNET_DECLARE(uint32_t, tcp_ack_war_cnt);
 VNET_DECLARE(uint32_t, tcp_ack_war_time_window);
-VNET_DECLARE(int, tcp_autorcvbuf_max);
+VNET_DECLARE(u_int, tcp_autorcvbuf_max);
 VNET_DECLARE(int, tcp_autosndbuf_inc);
 VNET_DECLARE(int, tcp_autosndbuf_max);
 VNET_DECLARE(int, tcp_bind_all_fibs);
 VNET_DECLARE(int, tcp_delack_enabled);
-VNET_DECLARE(int, tcp_do_autorcvbuf);
 VNET_DECLARE(int, tcp_do_autosndbuf);
+VNET_DECLARE(bool, tcp_do_autorcvbuf);
 VNET_DECLARE(int, tcp_do_ecn);
 VNET_DECLARE(int, tcp_do_lrd);
 VNET_DECLARE(int, tcp_do_prr);
@@ -1336,7 +1336,7 @@ VNET_DECLARE(int, tcp_mssdflt);
 VNET_DECLARE(int, tcp_perconn_stats_dflt_tpl);
 VNET_DECLARE(int, tcp_perconn_stats_enable);
 #endif /* STATS */
-VNET_DECLARE(int, tcp_recvspace);
+VNET_DECLARE(u_int, tcp_recvspace);
 VNET_DECLARE(int, tcp_retries);
 VNET_DECLARE(int, tcp_sack_globalholes);
 VNET_DECLARE(int, tcp_sack_globalmaxholes);
@@ -1403,6 +1403,7 @@ VNET_DECLARE(struct hhook_head *, tcp_hhh[HHOOK_TCP_LAST + 1]);
 #define	V_tcp_hhh		VNET(tcp_hhh)
 #endif
 
+void	tcp_autorcvbuf(struct tcpcb *, u_int);
 void	tcp_account_for_send(struct tcpcb *, uint32_t, uint8_t, uint8_t, bool);
 int	 tcp_addoptions(struct tcpopt *, u_char *);
 struct tcpcb *
@@ -1437,8 +1438,6 @@ void	hhook_run_tcp_est_in(struct tcpcb *tp,
 #endif
 
 int	 tcp_input(struct mbuf **, int *, int);
-int	 tcp_autorcvbuf(struct mbuf *, struct tcphdr *, struct socket *,
-	    struct tcpcb *, int);
 int	 tcp_input_with_port(struct mbuf **, int *, int, uint16_t);
 void	tcp_do_segment(struct tcpcb *, struct mbuf *, struct tcphdr *, int,
     int, uint8_t);