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
This commit is contained in:
Gleb Smirnoff 2021-10-25 20:53:07 -07:00
parent de156263a5
commit f581a26e46
5 changed files with 84 additions and 37 deletions

View File

@ -14253,6 +14253,12 @@ bbr_set_sockopt(struct socket *so, struct sockopt *sopt,
struct epoch_tracker et; struct epoch_tracker et;
int32_t error = 0, optval; 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) { switch (sopt->sopt_name) {
case TCP_RACK_PACE_MAX_SEG: case TCP_RACK_PACE_MAX_SEG:
case TCP_RACK_MIN_TO: case TCP_RACK_MIN_TO:

View File

@ -20248,6 +20248,25 @@ rack_set_sockopt(struct socket *so, struct sockopt *sopt,
uint64_t loptval; uint64_t loptval;
int32_t error = 0, optval; 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) { switch (sopt->sopt_name) {
case TCP_RACK_TLP_REDUCE: /* URL:tlp_reduce */ case TCP_RACK_TLP_REDUCE: /* URL:tlp_reduce */
/* Pacing related ones */ /* Pacing related ones */

View File

@ -3559,6 +3559,41 @@ tcp_maxmtu6(struct in_conninfo *inc, struct tcp_ifcap *cap)
return (maxmtu); 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 */ #endif /* INET6 */
/* /*

View File

@ -1763,43 +1763,8 @@ tcp_ctloutput_set(struct inpcb *inp, struct sockopt *sopt)
/* Notify tcp stacks that care (e.g. RACK). */ /* Notify tcp stacks that care (e.g. RACK). */
break; break;
case IPV6_USE_MIN_MTU: case IPV6_USE_MIN_MTU:
/* /* Update t_maxseg accordingly. */
* XXXGL: this handling should belong to break;
* 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 */
default: default:
return (error); return (error);
} }
@ -2058,6 +2023,27 @@ tcp_default_ctloutput(struct socket *so, struct sockopt *sopt, struct inpcb *inp
#endif #endif
size_t len; 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 * For TCP_CCALGOOPT forward the control to CC module, for both
* SOPT_SET and SOPT_GET. * SOPT_SET and SOPT_GET.

View File

@ -1053,6 +1053,7 @@ extern uint32_t tcp_ack_war_cnt;
uint32_t tcp_maxmtu(struct in_conninfo *, struct tcp_ifcap *); uint32_t tcp_maxmtu(struct in_conninfo *, struct tcp_ifcap *);
uint32_t tcp_maxmtu6(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_maxseg(const struct tcpcb *);
u_int tcp_fixed_maxseg(const struct tcpcb *); u_int tcp_fixed_maxseg(const struct tcpcb *);
void tcp_mss_update(struct tcpcb *, int, int, struct hc_metrics_lite *, void tcp_mss_update(struct tcpcb *, int, int, struct hc_metrics_lite *,