summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortuexen <tuexen@FreeBSD.org>2018-04-07 20:08:17 +0000
committertuexen <tuexen@FreeBSD.org>2018-04-07 20:08:17 +0000
commit230fea64ae0153ef4abbbac17813b16ec372e3d4 (patch)
treea8b47e5388f71bafe295f12aa21c5d708581b3d7
parent78821f62e8f6078dc43985eb05cda70b4b1b639c (diff)
downloadFreeBSD-src-230fea64ae0153ef4abbbac17813b16ec372e3d4.zip
FreeBSD-src-230fea64ae0153ef4abbbac17813b16ec372e3d4.tar.gz
MFC r325370:
Allow the setting of the MTU for future paths using an SCTP socket option. This functionality was missing.
-rw-r--r--sys/netinet/sctp_output.c12
-rw-r--r--sys/netinet/sctp_pcb.c65
-rw-r--r--sys/netinet/sctp_pcb.h1
-rw-r--r--sys/netinet/sctp_structs.h1
-rw-r--r--sys/netinet/sctp_usrreq.c15
-rw-r--r--sys/netinet/sctputil.c1
-rw-r--r--sys/netinet6/sctp6_usrreq.c4
7 files changed, 78 insertions, 21 deletions
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index 12075fe..2a667c1 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -4273,12 +4273,8 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
/* free tempy routes */
RO_RTFREE(ro);
} else {
- /*
- * PMTU check versus smallest asoc MTU goes
- * here
- */
- if ((ro->ro_rt != NULL) &&
- (net->ro._s_addr)) {
+ if ((ro->ro_rt != NULL) && (net->ro._s_addr) &&
+ ((net->dest_state & SCTP_ADDR_NO_PMTUD) == 0)) {
uint32_t mtu;
mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, ro->ro_rt);
@@ -4635,8 +4631,8 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
}
net->src_addr_selected = 0;
}
- if ((ro->ro_rt != NULL) &&
- (net->ro._s_addr)) {
+ if ((ro->ro_rt != NULL) && (net->ro._s_addr) &&
+ ((net->dest_state & SCTP_ADDR_NO_PMTUD) == 0)) {
uint32_t mtu;
mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, ro->ro_rt);
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index a60a619..6669d1b 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -2577,6 +2577,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
/* number of streams to pre-open on a association */
m->pre_open_stream_count = SCTP_BASE_SYSCTL(sctp_nr_outgoing_streams_default);
+ m->default_mtu = 0;
/* Add adaptation cookie */
m->adaptation_layer_indicator = 0;
m->adaptation_layer_indicator_provided = 0;
@@ -3942,7 +3943,28 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
net,
0,
stcb->asoc.vrf_id);
- if (net->ro._s_addr != NULL) {
+ if (stcb->asoc.default_mtu > 0) {
+ net->mtu = stcb->asoc.default_mtu;
+ switch (net->ro._l_addr.sa.sa_family) {
+#ifdef INET
+ case AF_INET:
+ net->mtu += SCTP_MIN_V4_OVERHEAD;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ net->mtu += SCTP_MIN_OVERHEAD;
+ break;
+#endif
+ default:
+ break;
+ }
+#if defined(INET) || defined(INET6)
+ if (net->port) {
+ net->mtu += (uint32_t)sizeof(struct udphdr);
+ }
+#endif
+ } else if (net->ro._s_addr != NULL) {
uint32_t imtu, rmtu, hcmtu;
net->src_addr_selected = 1;
@@ -3966,19 +3988,42 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
}
}
if (net->mtu == 0) {
- switch (newaddr->sa_family) {
+ if (stcb->asoc.default_mtu > 0) {
+ net->mtu = stcb->asoc.default_mtu;
+ switch (net->ro._l_addr.sa.sa_family) {
#ifdef INET
- case AF_INET:
- net->mtu = SCTP_DEFAULT_MTU;
- break;
+ case AF_INET:
+ net->mtu += SCTP_MIN_V4_OVERHEAD;
+ break;
#endif
#ifdef INET6
- case AF_INET6:
- net->mtu = 1280;
- break;
+ case AF_INET6:
+ net->mtu += SCTP_MIN_OVERHEAD;
+ break;
#endif
- default:
- break;
+ default:
+ break;
+ }
+#if defined(INET) || defined(INET6)
+ if (net->port) {
+ net->mtu += (uint32_t)sizeof(struct udphdr);
+ }
+#endif
+ } else {
+ switch (newaddr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ net->mtu = SCTP_DEFAULT_MTU;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ net->mtu = 1280;
+ break;
+#endif
+ default:
+ break;
+ }
}
}
#if defined(INET) || defined(INET6)
diff --git a/sys/netinet/sctp_pcb.h b/sys/netinet/sctp_pcb.h
index acc6831..8d40b69 100644
--- a/sys/netinet/sctp_pcb.h
+++ b/sys/netinet/sctp_pcb.h
@@ -287,6 +287,7 @@ struct sctp_pcb {
sctp_auth_chklist_t *local_auth_chunks;
sctp_hmaclist_t *local_hmacs;
uint16_t default_keyid;
+ uint32_t default_mtu;
/* various thresholds */
/* Max times I will init at a guy */
diff --git a/sys/netinet/sctp_structs.h b/sys/netinet/sctp_structs.h
index f737174..ed907f1 100644
--- a/sys/netinet/sctp_structs.h
+++ b/sys/netinet/sctp_structs.h
@@ -1098,6 +1098,7 @@ struct sctp_association {
uint32_t chunks_on_out_queue; /* total chunks floating around,
* locked by send socket buffer */
uint32_t peers_adaptation;
+ uint32_t default_mtu;
uint16_t peer_hmac_id; /* peer HMAC id to send */
/*
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index 54e2632..f96816d 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -202,6 +202,10 @@ sctp_notify(struct sctp_inpcb *inp,
#endif
/* no need to unlock here, since the TCB is gone */
} else if (icmp_code == ICMP_UNREACH_NEEDFRAG) {
+ if ((net->dest_state & SCTP_ADDR_NO_PMTUD) == 0) {
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+ }
/* Find the next (smaller) MTU */
if (next_mtu == 0) {
/*
@@ -2447,7 +2451,7 @@ flags_out:
* value
*/
paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure;
- paddrp->spp_pathmtu = 0;
+ paddrp->spp_pathmtu = stcb->asoc.default_mtu;
if (stcb->asoc.default_dscp & 0x01) {
paddrp->spp_dscp = stcb->asoc.default_dscp & 0xfc;
paddrp->spp_flags |= SPP_DSCP;
@@ -2494,8 +2498,7 @@ flags_out:
paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
}
#endif
- /* can't return this */
- paddrp->spp_pathmtu = 0;
+ paddrp->spp_pathmtu = inp->sctp_ep.default_mtu;
if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
paddrp->spp_flags |= SPP_HB_ENABLE;
@@ -5479,6 +5482,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
sctp_pathmtu_adjustment(stcb, net->mtu);
}
}
+ stcb->asoc.default_mtu = paddrp->spp_pathmtu;
sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
}
if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
@@ -5488,6 +5492,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
net->dest_state &= ~SCTP_ADDR_NO_PMTUD;
}
+ stcb->asoc.default_mtu = 0;
sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
}
if (paddrp->spp_flags & SPP_DSCP) {
@@ -5544,8 +5549,12 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
}
if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
+ inp->sctp_ep.default_mtu = 0;
sctp_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
} else if (paddrp->spp_flags & SPP_PMTUD_DISABLE) {
+ if (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU) {
+ inp->sctp_ep.default_mtu = paddrp->spp_pathmtu;
+ }
sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
}
if (paddrp->spp_flags & SPP_DSCP) {
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index 97ed5b1..8950ba4 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -1042,6 +1042,7 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
asoc->initial_init_rto_max = inp->sctp_ep.initial_init_rto_max;
asoc->initial_rto = inp->sctp_ep.initial_rto;
+ asoc->default_mtu = inp->sctp_ep.default_mtu;
asoc->max_init_times = inp->sctp_ep.max_init_times;
asoc->max_send_times = inp->sctp_ep.max_send_times;
asoc->def_net_failure = inp->sctp_ep.def_net_failure;
diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c
index c88ca96..a61eae1 100644
--- a/sys/netinet6/sctp6_usrreq.c
+++ b/sys/netinet6/sctp6_usrreq.c
@@ -229,6 +229,10 @@ sctp6_notify(struct sctp_inpcb *inp,
}
break;
case ICMP6_PACKET_TOO_BIG:
+ if ((net->dest_state & SCTP_ADDR_NO_PMTUD) == 0) {
+ SCTP_TCB_UNLOCK(stcb);
+ break;
+ }
if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
timer_stopped = 1;
sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
OpenPOWER on IntegriCloud