summaryrefslogtreecommitdiffstats
path: root/sys/netinet
diff options
context:
space:
mode:
authorwollman <wollman@FreeBSD.org>1995-09-20 21:00:59 +0000
committerwollman <wollman@FreeBSD.org>1995-09-20 21:00:59 +0000
commite18c331b1e6f91656cba38295f18835adce3f11d (patch)
tree572521b669715309966bebc91e904cbbebae377c /sys/netinet
parent485a0e0b8aad01680b4766dcbaf62a6d43067b02 (diff)
downloadFreeBSD-src-e18c331b1e6f91656cba38295f18835adce3f11d.zip
FreeBSD-src-e18c331b1e6f91656cba38295f18835adce3f11d.tar.gz
Add support in TCP for Path MTU discovery. This is highly experimental
and gated on `options MTUDISC' in the source. It is also practically untested becausse (sniff!) I don't have easy access to a network with an MTU of less than an Ethernet. If you have a small MTU network, please try it and tell me if it works!
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/tcp_output.c24
-rw-r--r--sys/netinet/tcp_subr.c48
-rw-r--r--sys/netinet/tcp_timewait.c48
3 files changed, 108 insertions, 12 deletions
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c
index 6c7ccd1..f5500ee 100644
--- a/sys/netinet/tcp_output.c
+++ b/sys/netinet/tcp_output.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)tcp_output.c 8.3 (Berkeley) 12/30/93
- * $Id: tcp_output.c,v 1.11 1995/05/30 08:09:56 rgrimes Exp $
+ * $Id: tcp_output.c,v 1.12 1995/09/13 17:36:31 wollman Exp $
*/
#include <sys/param.h>
@@ -661,16 +661,28 @@ send:
else
#endif
{
+#ifdef MTUDISC
+ struct rtentry *rt;
+#endif
((struct ip *)ti)->ip_len = m->m_pkthdr.len;
((struct ip *)ti)->ip_ttl = tp->t_inpcb->inp_ip.ip_ttl; /* XXX */
((struct ip *)ti)->ip_tos = tp->t_inpcb->inp_ip.ip_tos; /* XXX */
-#if BSD >= 43
+#ifdef MTUDISC
+ /*
+ * See if we should do MTU discovery. We do it only if the following
+ * are true:
+ * 1) we have a valid route to the destination
+ * 2) the MTU is not locked (if it is, then discovery has been
+ * disabled)
+ */
+ if ((rt = tp->t_inpcb->inp_route.ro_rt)
+ && rt->rt_flags & RTF_UP
+ && !(rt->rt_rmx.rmx_locks & RTV_MTU)) {
+ ((struct ip *)ti)->ip_off |= IP_DF;
+ }
+#endif /* MTUDISC */
error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route,
so->so_options & SO_DONTROUTE, 0);
-#else
- error = ip_output(m, (struct mbuf *)0, &tp->t_inpcb->inp_route,
- so->so_options & SO_DONTROUTE);
-#endif
}
if (error) {
out:
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index be84884..feec90b 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -479,6 +479,7 @@ tcp_quench(inp, errno)
* When `need fragmentation' ICMP is received, update our idea of the MSS
* based on the new value in the route. Also nudge TCP to send something,
* since we know the packet we just sent was dropped.
+ * This duplicates some code in the tcp_mss() function in tcp_input.c.
*/
static void
tcp_mtudisc(inp, errno)
@@ -486,11 +487,52 @@ tcp_mtudisc(inp, errno)
int errno;
{
struct tcpcb *tp = intotcpcb(inp);
+ struct rtentry *rt;
+ struct rmxp_tao *taop;
+ struct socket *so = inp->inp_socket;
+ int offered;
+ int mss;
-#if 0
- if (tp)
- ; /* XXX implement */
+ if (tp) {
+ rt = tcp_rtlookup(inp);
+ if (!rt || !rt->rt_rmx.rmx_mtu) {
+ tp->t_maxopd = tp->t_maxseg = tcp_mssdflt;
+ return;
+ }
+ taop = rmx_taop(rt->rt_rmx);
+ offered = taop->tao_mssopt;
+ mss = rt->rt_rmx.rmx_mtu - sizeof(struct tcpiphdr);
+ mss = min(mss, offer);
+ tp->t_maxopd = mss;
+
+ if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP &&
+ (tp->t_flags & TF_RCVD_TSTMP) == TF_RCVD_TSTMP)
+ mss -= TCPOLEN_TSTAMP_APPA;
+ if ((tp->t_flags & (TF_REQ_CC|TF_NOOPT)) == TF_REQ_CC &&
+ (tp->t_flags & TF_RCVD_CC) == TF_RCVD_CC)
+ mss -= TCPOLEN_CC_APPA;
+#if (MCLBYTES & (MCLBYTES - 1)) == 0
+ if (mss > MCLBYTES)
+ mss &= ~(MCLBYTES-1);
+#else
+ if (mss > MCLBYTES)
+ mss = mss / MCLBYTES * MCLBYTES;
#endif
+ if (so->so_snd.sb_hiwat < mss)
+ mss = so->so_snd.sb_hiwat;
+
+ tp->t_maxseg = mss;
+
+ /*
+ * Nudge TCP output. Unfortunately, we have no way to know
+ * which packet that we sent is the failing one, but in the
+ * vast majority of cases we expect that it will be at the
+ * beginning of the window, so this should do the right
+ * thing (I hope).
+ */
+ tp->snd_nxt = tp->snd_una;
+ tcp_output(tp);
+ }
}
#endif /* MTUDISC */
diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c
index be84884..feec90b 100644
--- a/sys/netinet/tcp_timewait.c
+++ b/sys/netinet/tcp_timewait.c
@@ -479,6 +479,7 @@ tcp_quench(inp, errno)
* When `need fragmentation' ICMP is received, update our idea of the MSS
* based on the new value in the route. Also nudge TCP to send something,
* since we know the packet we just sent was dropped.
+ * This duplicates some code in the tcp_mss() function in tcp_input.c.
*/
static void
tcp_mtudisc(inp, errno)
@@ -486,11 +487,52 @@ tcp_mtudisc(inp, errno)
int errno;
{
struct tcpcb *tp = intotcpcb(inp);
+ struct rtentry *rt;
+ struct rmxp_tao *taop;
+ struct socket *so = inp->inp_socket;
+ int offered;
+ int mss;
-#if 0
- if (tp)
- ; /* XXX implement */
+ if (tp) {
+ rt = tcp_rtlookup(inp);
+ if (!rt || !rt->rt_rmx.rmx_mtu) {
+ tp->t_maxopd = tp->t_maxseg = tcp_mssdflt;
+ return;
+ }
+ taop = rmx_taop(rt->rt_rmx);
+ offered = taop->tao_mssopt;
+ mss = rt->rt_rmx.rmx_mtu - sizeof(struct tcpiphdr);
+ mss = min(mss, offer);
+ tp->t_maxopd = mss;
+
+ if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP &&
+ (tp->t_flags & TF_RCVD_TSTMP) == TF_RCVD_TSTMP)
+ mss -= TCPOLEN_TSTAMP_APPA;
+ if ((tp->t_flags & (TF_REQ_CC|TF_NOOPT)) == TF_REQ_CC &&
+ (tp->t_flags & TF_RCVD_CC) == TF_RCVD_CC)
+ mss -= TCPOLEN_CC_APPA;
+#if (MCLBYTES & (MCLBYTES - 1)) == 0
+ if (mss > MCLBYTES)
+ mss &= ~(MCLBYTES-1);
+#else
+ if (mss > MCLBYTES)
+ mss = mss / MCLBYTES * MCLBYTES;
#endif
+ if (so->so_snd.sb_hiwat < mss)
+ mss = so->so_snd.sb_hiwat;
+
+ tp->t_maxseg = mss;
+
+ /*
+ * Nudge TCP output. Unfortunately, we have no way to know
+ * which packet that we sent is the failing one, but in the
+ * vast majority of cases we expect that it will be at the
+ * beginning of the window, so this should do the right
+ * thing (I hope).
+ */
+ tp->snd_nxt = tp->snd_una;
+ tcp_output(tp);
+ }
}
#endif /* MTUDISC */
OpenPOWER on IntegriCloud