diff options
author | wollman <wollman@FreeBSD.org> | 1995-09-20 21:00:59 +0000 |
---|---|---|
committer | wollman <wollman@FreeBSD.org> | 1995-09-20 21:00:59 +0000 |
commit | e18c331b1e6f91656cba38295f18835adce3f11d (patch) | |
tree | 572521b669715309966bebc91e904cbbebae377c | |
parent | 485a0e0b8aad01680b4766dcbaf62a6d43067b02 (diff) | |
download | FreeBSD-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!
-rw-r--r-- | sys/netinet/tcp_output.c | 24 | ||||
-rw-r--r-- | sys/netinet/tcp_subr.c | 48 | ||||
-rw-r--r-- | sys/netinet/tcp_timewait.c | 48 |
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 */ |