Take the route mtu into account, if available, when sending an

ICMP unreach, frag needed.  Up to now we only looked at the
interface MTU. Make sure to only use the minimum of the two.

In case IPSEC is compiled in, loop the mtu through ip_ipsec_mtu()
to avoid any further conditional maths.

Without this, PMTU was broken in those cases when there was a
route with a lower MTU than the MTU of the outgoing interface.

PR:		kern/122338
Tested by:	Mark Cammidge  mark peralex.com
Reviewed by:	silence on net@
MFC after:	2 weeks
This commit is contained in:
Bjoern A. Zeeb 2008-04-09 05:17:18 +00:00
parent 34aec6b9f8
commit b835b6fe2b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=178029
3 changed files with 28 additions and 7 deletions

View File

@ -1249,6 +1249,7 @@ ip_forward(struct mbuf *m, int srcrt)
struct in_ifaddr *ia = NULL;
struct mbuf *mcopy;
struct in_addr dest;
struct route ro;
int error, type = 0, code = 0, mtu = 0;
if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) {
@ -1326,7 +1327,6 @@ ip_forward(struct mbuf *m, int srcrt)
dest.s_addr = 0;
if (!srcrt && ipsendredirects && ia->ia_ifp == m->m_pkthdr.rcvif) {
struct sockaddr_in *sin;
struct route ro;
struct rtentry *rt;
bzero(&ro, sizeof(ro));
@ -1358,7 +1358,20 @@ ip_forward(struct mbuf *m, int srcrt)
RTFREE(rt);
}
error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
/*
* Try to cache the route MTU from ip_output so we can consider it for
* the ICMP_UNREACH_NEEDFRAG "Next-Hop MTU" field described in RFC1191.
*/
bzero(&ro, sizeof(ro));
rtalloc_ign(&ro, RTF_CLONING);
error = ip_output(m, NULL, &ro, IP_FORWARDING, NULL, NULL);
if (error == EMSGSIZE && ro.ro_rt)
mtu = ro.ro_rt->rt_rmx.rmx_mtu;
if (ro.ro_rt)
RTFREE(ro.ro_rt);
if (error)
ipstat.ips_cantforward++;
else {
@ -1394,14 +1407,23 @@ ip_forward(struct mbuf *m, int srcrt)
code = ICMP_UNREACH_NEEDFRAG;
#ifdef IPSEC
mtu = ip_ipsec_mtu(m);
/*
* If IPsec is configured for this path,
* override any possibly mtu value set by ip_output.
*/
mtu = ip_ipsec_mtu(m, mtu);
#endif /* IPSEC */
/*
* If the MTU was set before make sure we are below the
* interface MTU.
* If the MTU wasn't set before use the interface mtu or
* fall back to the next smaller mtu step compared to the
* current packet size.
*/
if (mtu == 0) {
if (mtu != 0) {
if (ia != NULL)
mtu = min(mtu, ia->ia_ifp->if_mtu);
} else {
if (ia != NULL)
mtu = ia->ia_ifp->if_mtu;
else

View File

@ -191,9 +191,8 @@ ip_ipsec_input(struct mbuf *m)
* Returns MTU suggestion for ICMP needfrag reply.
*/
int
ip_ipsec_mtu(struct mbuf *m)
ip_ipsec_mtu(struct mbuf *m, int mtu)
{
int mtu = 0;
/*
* If the packet is routed over IPsec tunnel, tell the
* originator the tunnel MTU.

View File

@ -35,7 +35,7 @@
int ip_ipsec_filtertunnel(struct mbuf *);
int ip_ipsec_fwd(struct mbuf *);
int ip_ipsec_input(struct mbuf *);
int ip_ipsec_mtu(struct mbuf *);
int ip_ipsec_mtu(struct mbuf *, int);
int ip_ipsec_output(struct mbuf **, struct inpcb *, int *, int *,
struct route **, struct route *, struct sockaddr_in **,
struct in_ifaddr **, struct ifnet **);