git: cd84e78f09ec - main - tcp idle reduce does not work for a server.

From: Randall Stewart <rrs_at_FreeBSD.org>
Date: Tue, 04 Oct 2022 11:10:18 UTC
The branch main has been updated by rrs:

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

commit cd84e78f09ec55c0ae8339e0e6738452ea4c7424
Author:     Randall Stewart <rrs@FreeBSD.org>
AuthorDate: 2022-10-04 11:09:01 +0000
Commit:     Randall Stewart <rrs@FreeBSD.org>
CommitDate: 2022-10-04 11:09:01 +0000

    tcp idle reduce does not work for a server.
    
    TCP has an idle-reduce feature that allows a connection to reduce its
    cwnd after it has been idle more than an RTT. This feature only works
    for a sending side connection. It does this by at output checking the
    idle time (t_rcvtime vs ticks) to see if its more than the RTO timeout.
    
    The problem comes if you are a web server. You get a request and
    then send out all the data.. then go idle. The next time you would
    send is in response to a request from the peer asking for more data.
    But the thing is you updated t_rcvtime when the request came in so
    you never reduce.
    
    The fix is to do the idle reduce check also on inbound.
    
    Reviewed by: tuexen, rscheff
    Sponsored by: Netflix Inc
    Differential Revision: https://reviews.freebsd.org/D36721
---
 sys/netinet/tcp_input.c  | 4 ++++
 sys/netinet/tcp_output.c | 4 +---
 sys/netinet/tcp_var.h    | 1 +
 3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 7293fde6c580..7cd9494e5e4f 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -1614,6 +1614,10 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
 	 * XXX: This should be done after segment
 	 * validation to ignore broken/spoofed segs.
 	 */
+	if  (tp->t_idle_reduce &&
+	     (tp->snd_max == tp->snd_una) &&
+	     ((ticks - tp->t_rcvtime) >= tp->t_rxtcur))
+		cc_after_idle(tp);
 	tp->t_rcvtime = ticks;
 
 	if (thflags & TH_FIN)
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c
index 885170f626b6..e23c35ce4d81 100644
--- a/sys/netinet/tcp_output.c
+++ b/sys/netinet/tcp_output.c
@@ -155,8 +155,6 @@ SYSCTL_INT(_net_inet_tcp, OID_AUTO, sendbuf_auto_lowat, CTLFLAG_VNET | CTLFLAG_R
 	    tcp_timer_active((tp), TT_PERSIST),				\
 	    ("neither rexmt nor persist timer is set"))
 
-static void inline	cc_after_idle(struct tcpcb *tp);
-
 #ifdef TCP_HHOOK
 /*
  * Wrapper for the TCP established output helper hook.
@@ -183,7 +181,7 @@ hhook_run_tcp_est_out(struct tcpcb *tp, struct tcphdr *th,
 /*
  * CC wrapper hook functions
  */
-static void inline
+void
 cc_after_idle(struct tcpcb *tp)
 {
 	INP_WLOCK_ASSERT(tp->t_inpcb);
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index 3eebbefd9b7f..369dda66b08d 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -1206,6 +1206,7 @@ void	 tcp_hc_get(struct in_conninfo *, struct hc_metrics_lite *);
 uint32_t tcp_hc_getmtu(struct in_conninfo *);
 void	 tcp_hc_updatemtu(struct in_conninfo *, uint32_t);
 void	 tcp_hc_update(struct in_conninfo *, struct hc_metrics_lite *);
+void 	 cc_after_idle(struct tcpcb *tp);
 
 extern	struct protosw tcp_protosw;		/* shared for TOE */
 extern	struct protosw tcp6_protosw;		/* shared for TOE */