git: f581a26e46b8 - main - Factor out tcp6_use_min_mtu() to handle IPV6_USE_MIN_MTU by TCP.

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Wed, 27 Oct 2021 15:22:59 UTC
The branch main has been updated by glebius:

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

commit f581a26e46b896657fd502672c134da115057839
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2021-10-26 03:53:07 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2021-10-27 15:22:00 +0000

    Factor out tcp6_use_min_mtu() to handle IPV6_USE_MIN_MTU by TCP.
    
    Pass control for IP/IP6 level options from generic tcp_ctloutput_set()
    down to per-stack ctloutput.
    
    Call tcp6_use_min_mtu() from tcp stack tcp_default_ctloutput().
    
    Reviewed by:            rrs
    Differential Revision:  https://reviews.freebsd.org/D32655
---
 sys/netinet/tcp_stacks/bbr.c  |  6 +++++
 sys/netinet/tcp_stacks/rack.c | 19 ++++++++++++++
 sys/netinet/tcp_subr.c        | 35 +++++++++++++++++++++++++
 sys/netinet/tcp_usrreq.c      | 60 +++++++++++++++++--------------------------
 sys/netinet/tcp_var.h         |  1 +
 5 files changed, 84 insertions(+), 37 deletions(-)

diff --git a/sys/netinet/tcp_stacks/bbr.c b/sys/netinet/tcp_stacks/bbr.c
index 3c4cf0f54d97..41f441da99a1 100644
--- a/sys/netinet/tcp_stacks/bbr.c
+++ b/sys/netinet/tcp_stacks/bbr.c
@@ -14253,6 +14253,12 @@ bbr_set_sockopt(struct socket *so, struct sockopt *sopt,
 	struct epoch_tracker et;
 	int32_t error = 0, optval;
 
+	switch (sopt->sopt_level) {
+	case IPPROTO_IPV6:
+	case IPPROTO_IP:
+		return (tcp_default_ctloutput(so, sopt, inp, tp));
+	}
+
 	switch (sopt->sopt_name) {
 	case TCP_RACK_PACE_MAX_SEG:
 	case TCP_RACK_MIN_TO:
diff --git a/sys/netinet/tcp_stacks/rack.c b/sys/netinet/tcp_stacks/rack.c
index eee7db6e7a4c..3e3997f8e18e 100644
--- a/sys/netinet/tcp_stacks/rack.c
+++ b/sys/netinet/tcp_stacks/rack.c
@@ -20248,6 +20248,25 @@ rack_set_sockopt(struct socket *so, struct sockopt *sopt,
 	uint64_t loptval;
 	int32_t error = 0, optval;
 
+	switch (sopt->sopt_level) {
+#ifdef INET6
+	case IPPROTO_IPV6:
+		MPASS(inp->inp_vflag & INP_IPV6PROTO);
+		switch (sopt->sopt_name) {
+		case IPV6_USE_MIN_MTU:
+			tcp6_use_min_mtu(tp);
+			/* FALLTHROUGH */
+		}
+		INP_WUNLOCK(inp);
+		return (0);
+#endif
+#ifdef INET
+	case IPPROTO_IP:
+		INP_WUNLOCK(inp);
+		return (0);
+#endif
+	}
+
 	switch (sopt->sopt_name) {
 	case TCP_RACK_TLP_REDUCE:		/*  URL:tlp_reduce */
 	/*  Pacing related ones */
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 2752773a95fc..e12eb5682c14 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -3559,6 +3559,41 @@ tcp_maxmtu6(struct in_conninfo *inc, struct tcp_ifcap *cap)
 
 	return (maxmtu);
 }
+
+/*
+ * Handle setsockopt(IPV6_USE_MIN_MTU) by a TCP stack.
+ *
+ * XXXGL: we are updating inpcb here with INC_IPV6MINMTU flag.
+ * The right place to do that is ip6_setpktopt() that has just been
+ * executed.  By the way it just filled ip6po_minmtu for us.
+ */
+void
+tcp6_use_min_mtu(struct tcpcb *tp)
+{
+	struct inpcb *inp = tp->t_inpcb;
+
+	INP_WLOCK_ASSERT(inp);
+	/*
+	 * In case of the IPV6_USE_MIN_MTU socket
+	 * option, the INC_IPV6MINMTU flag to announce
+	 * a corresponding MSS during the initial
+	 * handshake.  If the TCP connection is not in
+	 * the front states, just reduce the MSS being
+	 * used.  This avoids the sending of TCP
+	 * segments which will be fragmented at the
+	 * IPv6 layer.
+	 */
+	inp->inp_inc.inc_flags |= INC_IPV6MINMTU;
+	if ((tp->t_state >= TCPS_SYN_SENT) &&
+	    (inp->inp_inc.inc_flags & INC_ISIPV6)) {
+		struct ip6_pktopts *opt;
+
+		opt = inp->in6p_outputopts;
+		if (opt != NULL && opt->ip6po_minmtu == IP6PO_MINMTU_ALL &&
+		    tp->t_maxseg > TCP6_MSS)
+			tp->t_maxseg = TCP6_MSS;
+	}
+}
 #endif /* INET6 */
 
 /*
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index b6e345bd454c..7e703af5aa67 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -1763,43 +1763,8 @@ tcp_ctloutput_set(struct inpcb *inp, struct sockopt *sopt)
 				/* Notify tcp stacks that care (e.g. RACK). */
 				break;
 			case IPV6_USE_MIN_MTU:
-				/*
-				 * XXXGL: this handling should belong to
-				 * stack specific tfb_tcp_ctloutput, we
-				 * should just break here.
-				 *
-				 * In case of the IPV6_USE_MIN_MTU socket
-				 * option, the INC_IPV6MINMTU flag to announce
-				 * a corresponding MSS during the initial
-				 * handshake.  If the TCP connection is not in
-				 * the front states, just reduce the MSS being
-				 * used.  This avoids the sending of TCP
-				 * segments which will be fragmented at the
-				 * IPv6 layer.
-				 */
-				INP_WLOCK(inp);
-				if ((inp->inp_flags &
-				    (INP_TIMEWAIT | INP_DROPPED))) {
-					INP_WUNLOCK(inp);
-					return (ECONNRESET);
-				}
-				inp->inp_inc.inc_flags |= INC_IPV6MINMTU;
-				tp = intotcpcb(inp);
-				if ((tp->t_state >= TCPS_SYN_SENT) &&
-				    (inp->inp_inc.inc_flags & INC_ISIPV6)) {
-					struct ip6_pktopts *opt;
-
-					opt = inp->in6p_outputopts;
-					if ((opt != NULL) &&
-					    (opt->ip6po_minmtu ==
-					    IP6PO_MINMTU_ALL)) {
-						if (tp->t_maxseg > TCP6_MSS) {
-							tp->t_maxseg = TCP6_MSS;
-						}
-					}
-				}
-				INP_WUNLOCK(inp);
-				/* FALLTHROUGH */
+				/* Update t_maxseg accordingly. */
+				break;
 			default:
 				return (error);
 			}
@@ -2058,6 +2023,27 @@ tcp_default_ctloutput(struct socket *so, struct sockopt *sopt, struct inpcb *inp
 #endif
 	size_t	len;
 
+	INP_WLOCK_ASSERT(inp);
+
+	switch (sopt->sopt_level) {
+#ifdef INET6
+	case IPPROTO_IPV6:
+		MPASS(inp->inp_vflag & INP_IPV6PROTO);
+		switch (sopt->sopt_name) {
+		case IPV6_USE_MIN_MTU:
+			tcp6_use_min_mtu(tp);
+			/* FALLTHROUGH */
+		}
+		INP_WUNLOCK(inp);
+		return (0);
+#endif
+#ifdef INET
+	case IPPROTO_IP:
+		INP_WUNLOCK(inp);
+		return (0);
+#endif
+	}
+
 	/*
 	 * For TCP_CCALGOOPT forward the control to CC module, for both
 	 * SOPT_SET and SOPT_GET.
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index 2775fb392a1a..1511da3c70fd 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -1053,6 +1053,7 @@ extern uint32_t tcp_ack_war_cnt;
 
 uint32_t tcp_maxmtu(struct in_conninfo *, struct tcp_ifcap *);
 uint32_t tcp_maxmtu6(struct in_conninfo *, struct tcp_ifcap *);
+void	 tcp6_use_min_mtu(struct tcpcb *);
 u_int	 tcp_maxseg(const struct tcpcb *);
 u_int	 tcp_fixed_maxseg(const struct tcpcb *);
 void	 tcp_mss_update(struct tcpcb *, int, int, struct hc_metrics_lite *,