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
This commit is contained in:
Gleb Smirnoff committed 2026-10-21 20:27:36 -07:00
1 parent da04cf02c9
commit 04cd9bca4d
6 files changed
+35 -67

No files matched your search

+2 -6
View File
@@ -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 *",
+23 -27
View File
@@ -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);
}
+1 -10
View File
@@ -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
+3 -17
View File
@@ -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 =
+1 -1
View File
@@ -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);
+5 -6
View File
@@ -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);