aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Tuexen <tuexen@FreeBSD.org>2017-04-29 19:20:50 +0000
committerMichael Tuexen <tuexen@FreeBSD.org>2017-04-29 19:20:50 +0000
commit10e0318afac9a26bd6ef86585033783be4888582 (patch)
treec7545a487282641c8fe9ff7cc4342eaa5441d7ba
parent2b223a01ef11e13ba0b20495c4f8b2f24e540950 (diff)
downloadsrc-10e0318afac9a26bd6ef86585033783be4888582.tar.gz
src-10e0318afac9a26bd6ef86585033783be4888582.zip
Allow SCTP to use the hostcache.
This patch allows the MTU stored in the hostcache to be used as an initial value for SCTP paths. When an ICMP PTB message is received, store the MTU in the hostcache. MFC after: 1 week
Notes
Notes: svn path=/head/; revision=317597
-rw-r--r--sys/netinet/sctp_pcb.c24
-rw-r--r--sys/netinet/sctp_usrreq.c5
-rw-r--r--sys/netinet/sctputil.c90
-rw-r--r--sys/netinet/sctputil.h5
4 files changed, 108 insertions, 16 deletions
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index db3f39c2e5c4..551a9cb914cc 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -3933,6 +3933,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
stcb->asoc.vrf_id,
stcb->sctp_ep->fibnum);
+ net->src_addr_selected = 0;
if (SCTP_ROUTE_HAS_VALID_IFN(&net->ro)) {
/* Get source address */
net->ro._s_addr = sctp_source_address_selection(stcb->sctp_ep,
@@ -3942,18 +3943,18 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
0,
stcb->asoc.vrf_id);
if (net->ro._s_addr != NULL) {
+ uint32_t imtu, rmtu, hcmtu;
+
net->src_addr_selected = 1;
/* Now get the interface MTU */
if (net->ro._s_addr->ifn_p != NULL) {
- net->mtu = SCTP_GATHER_MTU_FROM_INTFC(net->ro._s_addr->ifn_p);
+ imtu = SCTP_GATHER_MTU_FROM_INTFC(net->ro._s_addr->ifn_p);
+ } else {
+ imtu = 0;
}
- } else {
- net->src_addr_selected = 0;
- }
- if (net->mtu > 0) {
- uint32_t rmtu;
-
rmtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, net->ro.ro_rt);
+ hcmtu = sctp_hc_get_mtu(&net->ro._l_addr, stcb->sctp_ep->fibnum);
+ net->mtu = sctp_min_mtu(hcmtu, rmtu, imtu);
if (rmtu == 0) {
/*
* Start things off to match mtu of
@@ -3961,17 +3962,8 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
*/
SCTP_SET_MTU_OF_ROUTE(&net->ro._l_addr.sa,
net->ro.ro_rt, net->mtu);
- } else {
- /*
- * we take the route mtu over the interface,
- * since the route may be leading out the
- * loopback, or a different interface.
- */
- net->mtu = rmtu;
}
}
- } else {
- net->src_addr_selected = 0;
}
if (net->mtu == 0) {
switch (newaddr->sa_family) {
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index b433df57a594..75d817559bc1 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -225,6 +225,11 @@ sctp_notify(struct sctp_inpcb *inp,
}
if (net->mtu > next_mtu) {
net->mtu = next_mtu;
+ if (net->port) {
+ sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu + sizeof(struct udphdr));
+ } else {
+ sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu);
+ }
}
/* Update the association MTU */
if (stcb->asoc.smallest_mtu > next_mtu) {
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index 2951ad686145..1dd3c3e2f0c8 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -49,6 +49,9 @@ __FBSDID("$FreeBSD$");
#include <netinet/sctp_auth.h>
#include <netinet/sctp_asconf.h>
#include <netinet/sctp_bsd_addr.h>
+#if defined(INET6) || defined(INET)
+#include <netinet/tcp_var.h>
+#endif
#include <netinet/udp.h>
#include <netinet/udp_var.h>
#include <sys/proc.h>
@@ -7235,3 +7238,90 @@ sctp_over_udp_start(void)
#endif
return (0);
}
+
+#if defined(INET6) || defined(INET)
+
+/*
+ * sctp_min_mtu ()returns the minimum of all non-zero arguments.
+ * If all arguments are zero, zero is returned.
+ */
+uint32_t
+sctp_min_mtu(uint32_t mtu1, uint32_t mtu2, uint32_t mtu3)
+{
+ if (mtu1 > 0) {
+ if (mtu2 > 0) {
+ if (mtu3 > 0) {
+ return (min(mtu1, min(mtu2, mtu3)));
+ } else {
+ return (min(mtu1, mtu2));
+ }
+ } else {
+ if (mtu3 > 0) {
+ return (min(mtu1, mtu3));
+ } else {
+ return (mtu1);
+ }
+ }
+ } else {
+ if (mtu2 > 0) {
+ if (mtu3 > 0) {
+ return (min(mtu2, mtu3));
+ } else {
+ return (mtu2);
+ }
+ } else {
+ return (mtu3);
+ }
+ }
+}
+
+void
+sctp_hc_set_mtu(union sctp_sockstore *addr, uint16_t fibnum, uint32_t mtu)
+{
+ struct in_conninfo inc;
+
+ memset(&inc, 0, sizeof(struct in_conninfo));
+ inc.inc_fibnum = fibnum;
+ switch (addr->sa.sa_family) {
+#ifdef INET
+ case AF_INET:
+ inc.inc_faddr = addr->sin.sin_addr;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ inc.inc_flags |= INC_ISIPV6;
+ inc.inc6_faddr = addr->sin6.sin6_addr;
+ break;
+#endif
+ default:
+ return;
+ }
+ tcp_hc_updatemtu(&inc, (u_long)mtu);
+}
+
+uint32_t
+sctp_hc_get_mtu(union sctp_sockstore *addr, uint16_t fibnum)
+{
+ struct in_conninfo inc;
+
+ memset(&inc, 0, sizeof(struct in_conninfo));
+ inc.inc_fibnum = fibnum;
+ switch (addr->sa.sa_family) {
+#ifdef INET
+ case AF_INET:
+ inc.inc_faddr = addr->sin.sin_addr;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ inc.inc_flags |= INC_ISIPV6;
+ inc.inc6_faddr = addr->sin6.sin6_addr;
+ break;
+#endif
+ default:
+ return (0);
+ }
+ return ((uint32_t)tcp_hc_getmtu(&inc));
+}
+#endif
diff --git a/sys/netinet/sctputil.h b/sys/netinet/sctputil.h
index dd45e49a9963..50118b7a5ed0 100644
--- a/sys/netinet/sctputil.h
+++ b/sys/netinet/sctputil.h
@@ -388,5 +388,10 @@ sctp_auditing(int, struct sctp_inpcb *, struct sctp_tcb *,
void sctp_audit_log(uint8_t, uint8_t);
#endif
+#if defined(INET6) || defined(INET)
+uint32_t sctp_min_mtu(uint32_t, uint32_t, uint32_t);
+void sctp_hc_set_mtu(union sctp_sockstore *, uint16_t, uint32_t);
+uint32_t sctp_hc_get_mtu(union sctp_sockstore *, uint16_t);
+#endif
#endif /* _KERNEL */
#endif