Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 6 Nov 2014 13:13:09 +0000 (UTC)
From:      "Alexander V. Chernikov" <melifaro@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r274175 - in head/sys: net netinet netinet6 sys
Message-ID:  <201411061313.sA6DD9Gw048172@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: melifaro
Date: Thu Nov  6 13:13:09 2014
New Revision: 274175
URL: https://svnweb.freebsd.org/changeset/base/274175

Log:
  Make checks for rt_mtu generic:
  
  Some virtual if drivers has (ab)used ifa ifa_rtrequest hook to enforce
  route MTU to be not bigger that interface MTU. While ifa_rtrequest hooking
  might be an option in some situation, it is not feasible to do MTU checks
  there: generic (or per-domain) routing code is perfectly capable of doing
  this.
  
  We currrently have 3 places where MTU is altered:
  
  1) route addition.
   In this case domain overrides radix _addroute callback (in[6]_addroute)
   and all necessary checks/fixes are/can be done there.
  
  2) route change (especially, GW change).
   In this case, there are no explicit per-domain calls, but one can
   override rte by setting ifa_rtrequest hook to domain handler
   (inet6 does this).
  
  3) ifconfig ifaceX mtu YYYY
   In this case, we have no callbacks, but ip[6]_output performes runtime
   checks and decreases rt_mtu if necessary.
  
  Generally, the goals are to be able to handle all MTU changes in
   control plane, not in runtime part, and properly deal with increased
   interface MTU.
  
  This commit changes the following:
  * removes hooks setting MTU from drivers side
  * adds proper per-doman MTU checks for case 1)
  * adds generic MTU check for case 2)
  
  * The latter is done by using new dom_ifmtu callback since
   if_mtu denotes L3 interface MTU, e.g. maximum trasmitted _packet_ size.
   However, IPv6 mtu might be different from if_mtu one (e.g. default 1280)
   for some cases, so we need an abstract way to know maximum MTU size
   for given interface and domain.
  * moves rt_setmetrics() before MTU/ifa_rtrequest hooks since it copies
    user-supplied data which must be checked.
  * removes RT_LOCK_ASSERT() from other ifa_rtrequest hooks to be able to
    use this functions on new non-inserted rte.
  
  More changes will follow soon.
  
  MFC after:	1 month
  Sponsored by:	Yandex LLC

Modified:
  head/sys/net/if.c
  head/sys/net/if_disc.c
  head/sys/net/if_faith.c
  head/sys/net/if_loop.c
  head/sys/net/if_stf.c
  head/sys/net/if_var.h
  head/sys/net/route.c
  head/sys/netinet/in_rmx.c
  head/sys/netinet6/in6.c
  head/sys/netinet6/in6_proto.c
  head/sys/netinet6/in6_rmx.c
  head/sys/netinet6/in6_var.h
  head/sys/netinet6/nd6.c
  head/sys/sys/domain.h

Modified: head/sys/net/if.c
==============================================================================
--- head/sys/net/if.c	Thu Nov  6 13:12:12 2014	(r274174)
+++ head/sys/net/if.c	Thu Nov  6 13:13:09 2014	(r274175)
@@ -2009,8 +2009,6 @@ link_rtrequest(int cmd, struct rtentry *
 	struct sockaddr *dst;
 	struct ifnet *ifp;
 
-	RT_LOCK_ASSERT(rt);
-
 	if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
 	    ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
 		return;
@@ -3759,6 +3757,19 @@ if_getmtu(if_t ifp)
 }
 
 int
+if_getmtu_family(if_t ifp, int family)
+{
+	struct domain *dp;
+
+	for (dp = domains; dp; dp = dp->dom_next) {
+		if (dp->dom_family == family && dp->dom_ifmtu != NULL)
+			return (dp->dom_ifmtu((struct ifnet *)ifp));
+	}
+
+	return (((struct ifnet *)ifp)->if_mtu);
+}
+
+int
 if_setsoftc(if_t ifp, void *softc)
 {
 	((struct ifnet *)ifp)->if_softc = softc;

Modified: head/sys/net/if_disc.c
==============================================================================
--- head/sys/net/if_disc.c	Thu Nov  6 13:12:12 2014	(r274174)
+++ head/sys/net/if_disc.c	Thu Nov  6 13:13:09 2014	(r274175)
@@ -67,7 +67,6 @@ struct disc_softc {
 
 static int	discoutput(struct ifnet *, struct mbuf *,
 		    const struct sockaddr *, struct route *);
-static void	discrtrequest(int, struct rtentry *, struct rt_addrinfo *);
 static int	discioctl(struct ifnet *, u_long, caddr_t);
 static int	disc_clone_create(struct if_clone *, int, caddr_t);
 static void	disc_clone_destroy(struct ifnet *);
@@ -198,31 +197,19 @@ discoutput(struct ifnet *ifp, struct mbu
 	return (0);
 }
 
-/* ARGSUSED */
-static void
-discrtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info)
-{
-
-	RT_LOCK_ASSERT(rt);
-	rt->rt_mtu = DSMTU;
-}
-
 /*
  * Process an ioctl request.
  */
 static int
 discioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 {
-	struct ifaddr *ifa;
 	struct ifreq *ifr = (struct ifreq *)data;
 	int error = 0;
 
 	switch (cmd) {
 	case SIOCSIFADDR:
 		ifp->if_flags |= IFF_UP;
-		ifa = (struct ifaddr *)data;
-		if (ifa != 0)
-			ifa->ifa_rtrequest = discrtrequest;
+
 		/*
 		 * Everything else is done at a higher level.
 		 */

Modified: head/sys/net/if_faith.c
==============================================================================
--- head/sys/net/if_faith.c	Thu Nov  6 13:12:12 2014	(r274174)
+++ head/sys/net/if_faith.c	Thu Nov  6 13:13:09 2014	(r274175)
@@ -87,7 +87,6 @@ struct faith_softc {
 static int faithioctl(struct ifnet *, u_long, caddr_t);
 static int faithoutput(struct ifnet *, struct mbuf *, const struct sockaddr *,
 	struct route *);
-static void faithrtrequest(int, struct rtentry *, struct rt_addrinfo *);
 #ifdef INET6
 static int faithprefix(struct in6_addr *);
 #endif
@@ -238,17 +237,6 @@ faithoutput(struct ifnet *ifp, struct mb
 	return (0);
 }
 
-/* ARGSUSED */
-static void
-faithrtrequest(cmd, rt, info)
-	int cmd;
-	struct rtentry *rt;
-	struct rt_addrinfo *info;
-{
-	RT_LOCK_ASSERT(rt);
-	rt->rt_mtu = rt->rt_ifp->if_mtu;
-}
-
 /*
  * Process an ioctl request.
  */
@@ -259,7 +247,6 @@ faithioctl(ifp, cmd, data)
 	u_long cmd;
 	caddr_t data;
 {
-	struct ifaddr *ifa;
 	struct ifreq *ifr = (struct ifreq *)data;
 	int error = 0;
 
@@ -268,8 +255,7 @@ faithioctl(ifp, cmd, data)
 	case SIOCSIFADDR:
 		ifp->if_flags |= IFF_UP;
 		ifp->if_drv_flags |= IFF_DRV_RUNNING;
-		ifa = (struct ifaddr *)data;
-		ifa->ifa_rtrequest = faithrtrequest;
+
 		/*
 		 * Everything else is done at a higher level.
 		 */

Modified: head/sys/net/if_loop.c
==============================================================================
--- head/sys/net/if_loop.c	Thu Nov  6 13:12:12 2014	(r274174)
+++ head/sys/net/if_loop.c	Thu Nov  6 13:13:09 2014	(r274175)
@@ -88,7 +88,6 @@
 				    CSUM_SCTP_VALID)
 
 int		loioctl(struct ifnet *, u_long, caddr_t);
-static void	lortrequest(int, struct rtentry *, struct rt_addrinfo *);
 int		looutput(struct ifnet *ifp, struct mbuf *m,
 		    const struct sockaddr *dst, struct route *ro);
 static int	lo_clone_create(struct if_clone *, int, caddr_t);
@@ -364,15 +363,6 @@ if_simloop(struct ifnet *ifp, struct mbu
 	return (0);
 }
 
-/* ARGSUSED */
-static void
-lortrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info)
-{
-
-	RT_LOCK_ASSERT(rt);
-	rt->rt_mtu = rt->rt_ifp->if_mtu;
-}
-
 /*
  * Process an ioctl request.
  */
@@ -380,7 +370,6 @@ lortrequest(int cmd, struct rtentry *rt,
 int
 loioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 {
-	struct ifaddr *ifa;
 	struct ifreq *ifr = (struct ifreq *)data;
 	int error = 0, mask;
 
@@ -388,8 +377,6 @@ loioctl(struct ifnet *ifp, u_long cmd, c
 	case SIOCSIFADDR:
 		ifp->if_flags |= IFF_UP;
 		ifp->if_drv_flags |= IFF_DRV_RUNNING;
-		ifa = (struct ifaddr *)data;
-		ifa->ifa_rtrequest = lortrequest;
 		/*
 		 * Everything else is done at a higher level.
 		 */

Modified: head/sys/net/if_stf.c
==============================================================================
--- head/sys/net/if_stf.c	Thu Nov  6 13:12:12 2014	(r274174)
+++ head/sys/net/if_stf.c	Thu Nov  6 13:13:09 2014	(r274175)
@@ -179,7 +179,6 @@ static int stf_checkaddr4(struct stf_sof
 	struct ifnet *);
 static int stf_checkaddr6(struct stf_softc *, struct in6_addr *,
 	struct ifnet *);
-static void stf_rtrequest(int, struct rtentry *, struct rt_addrinfo *);
 static int stf_ioctl(struct ifnet *, u_long, caddr_t);
 
 static int stf_clone_match(struct if_clone *, const char *);
@@ -722,17 +721,6 @@ in_stf_input(struct mbuf **mp, int *offp
 	return (IPPROTO_DONE);
 }
 
-/* ARGSUSED */
-static void
-stf_rtrequest(cmd, rt, info)
-	int cmd;
-	struct rtentry *rt;
-	struct rt_addrinfo *info;
-{
-	RT_LOCK_ASSERT(rt);
-	rt->rt_mtu = rt->rt_ifp->if_mtu;
-}
-
 static int
 stf_ioctl(ifp, cmd, data)
 	struct ifnet *ifp;
@@ -764,7 +752,6 @@ stf_ioctl(ifp, cmd, data)
 			break;
 		}
 
-		ifa->ifa_rtrequest = stf_rtrequest;
 		ifp->if_flags |= IFF_UP;
 		break;
 

Modified: head/sys/net/if_var.h
==============================================================================
--- head/sys/net/if_var.h	Thu Nov  6 13:12:12 2014	(r274174)
+++ head/sys/net/if_var.h	Thu Nov  6 13:13:09 2014	(r274175)
@@ -556,6 +556,7 @@ void *if_getsoftc(if_t ifp);
 int if_setflags(if_t ifp, int flags);
 int if_setmtu(if_t ifp, int mtu);
 int if_getmtu(if_t ifp);
+int if_getmtu_family(if_t ifp, int family);
 int if_setflagbits(if_t ifp, int set, int clear);
 int if_getflags(if_t ifp);
 int if_sendq_empty(if_t ifp);

Modified: head/sys/net/route.c
==============================================================================
--- head/sys/net/route.c	Thu Nov  6 13:12:12 2014	(r274174)
+++ head/sys/net/route.c	Thu Nov  6 13:13:09 2014	(r274175)
@@ -1279,6 +1279,8 @@ rtrequest1_fib(int req, struct rt_addrin
 		rt->rt_ifp = ifa->ifa_ifp;
 		rt->rt_weight = 1;
 
+		rt_setmetrics(info, rt);
+
 #ifdef RADIX_MPATH
 		/* do not permit exactly the same dst/mask/gw pair */
 		if (rn_mpath_capable(rnh) &&
@@ -1373,8 +1375,6 @@ rtrequest1_fib(int req, struct rt_addrin
 		if (ifa->ifa_rtrequest)
 			ifa->ifa_rtrequest(req, rt, info);
 
-		rt_setmetrics(info, rt);
-
 		/*
 		 * actually return a resultant rtentry and
 		 * give the caller a single reference.
@@ -1412,6 +1412,7 @@ rtrequest1_fib_change(struct radix_node_
 	struct rtentry *rt = NULL;
 	int error = 0;
 	int free_ifa = 0;
+	int family, mtu;
 
 	rt = (struct rtentry *)rnh->rnh_lookup(info->rti_info[RTAX_DST],
 	    info->rti_info[RTAX_NETMASK], rnh);
@@ -1433,6 +1434,8 @@ rtrequest1_fib_change(struct radix_node_
 
 	RT_LOCK(rt);
 
+	rt_setmetrics(info, rt);
+
 	/*
 	 * New gateway could require new ifaddr, ifp;
 	 * flags may also be different; ifp may be specified
@@ -1480,7 +1483,13 @@ rtrequest1_fib_change(struct radix_node_
 	if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest != NULL)
 	       rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, info);
 
-	rt_setmetrics(info, rt);
+	/* Ensure route MTU is not bigger than interface MTU */
+	if (rt->rt_ifp != NULL) {
+		family = info->rti_info[RTAX_DST]->sa_family;
+		mtu = if_getmtu_family(rt->rt_ifp, family);
+		if (rt->rt_mtu > mtu)
+			rt->rt_mtu = mtu;
+	}
 
 	if (ret_nrt) {
 		*ret_nrt = rt;

Modified: head/sys/netinet/in_rmx.c
==============================================================================
--- head/sys/netinet/in_rmx.c	Thu Nov  6 13:12:12 2014	(r274174)
+++ head/sys/netinet/in_rmx.c	Thu Nov  6 13:13:09 2014	(r274175)
@@ -94,8 +94,18 @@ in_addroute(void *v_arg, void *n_arg, st
 	if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
 		rt->rt_flags |= RTF_MULTICAST;
 
-	if (rt->rt_mtu == 0 && rt->rt_ifp != NULL)
-		rt->rt_mtu = rt->rt_ifp->if_mtu;
+	if (rt->rt_ifp != NULL) {
+
+		/*
+		 * Check route MTU:
+		 * inherit interface MTU if not set or
+		 * check if MTU is too large.
+		 */
+		if (rt->rt_mtu == 0) {
+			rt->rt_mtu = rt->rt_ifp->if_mtu;
+		} else if (rt->rt_mtu > rt->rt_ifp->if_mtu)
+			rt->rt_mtu = rt->rt_ifp->if_mtu;
+	}
 
 	return (rn_addroute(v_arg, n_arg, head, treenodes));
 }

Modified: head/sys/netinet6/in6.c
==============================================================================
--- head/sys/netinet6/in6.c	Thu Nov  6 13:12:12 2014	(r274174)
+++ head/sys/netinet6/in6.c	Thu Nov  6 13:13:09 2014	(r274175)
@@ -2367,6 +2367,13 @@ in6_domifattach(struct ifnet *ifp)
 	return ext;
 }
 
+int
+in6_domifmtu(struct ifnet *ifp)
+{
+
+	return (IN6_LINKMTU(ifp));
+}
+
 void
 in6_domifdetach(struct ifnet *ifp, void *aux)
 {

Modified: head/sys/netinet6/in6_proto.c
==============================================================================
--- head/sys/netinet6/in6_proto.c	Thu Nov  6 13:12:12 2014	(r274174)
+++ head/sys/netinet6/in6_proto.c	Thu Nov  6 13:13:09 2014	(r274175)
@@ -382,7 +382,8 @@ struct domain inet6domain = {
 	.dom_rtoffset =		offsetof(struct sockaddr_in6, sin6_addr) << 3,
 	.dom_maxrtkey =		sizeof(struct sockaddr_in6),
 	.dom_ifattach =		in6_domifattach,
-	.dom_ifdetach =		in6_domifdetach
+	.dom_ifdetach =		in6_domifdetach,
+	.dom_ifmtu    =		in6_domifmtu
 };
 
 VNET_DOMAIN_SET(inet6);

Modified: head/sys/netinet6/in6_rmx.c
==============================================================================
--- head/sys/netinet6/in6_rmx.c	Thu Nov  6 13:12:12 2014	(r274174)
+++ head/sys/netinet6/in6_rmx.c	Thu Nov  6 13:13:09 2014	(r274175)
@@ -136,8 +136,18 @@ in6_addroute(void *v_arg, void *n_arg, s
 		}
 	}
 
-	if (!rt->rt_mtu && rt->rt_ifp)
-		rt->rt_mtu = IN6_LINKMTU(rt->rt_ifp);
+	if (rt->rt_ifp != NULL) {
+
+		/*
+		 * Check route MTU:
+		 * inherit interface MTU if not set or
+		 * check if MTU is too large.
+		 */
+		if (rt->rt_mtu == 0) {
+			rt->rt_mtu = IN6_LINKMTU(rt->rt_ifp);
+		} else if (rt->rt_mtu > IN6_LINKMTU(rt->rt_ifp))
+			rt->rt_mtu = IN6_LINKMTU(rt->rt_ifp);
+	}
 
 	ret = rn_addroute(v_arg, n_arg, head, treenodes);
 	if (ret == NULL) {

Modified: head/sys/netinet6/in6_var.h
==============================================================================
--- head/sys/netinet6/in6_var.h	Thu Nov  6 13:12:12 2014	(r274174)
+++ head/sys/netinet6/in6_var.h	Thu Nov  6 13:13:09 2014	(r274175)
@@ -807,6 +807,7 @@ int	in6if_do_dad(struct ifnet *);
 void	in6_savemkludge(struct in6_ifaddr *);
 void	*in6_domifattach(struct ifnet *);
 void	in6_domifdetach(struct ifnet *, void *);
+int	in6_domifmtu(struct ifnet *);
 void	in6_setmaxmtu(void);
 int	in6_if2idlen(struct ifnet *);
 struct in6_ifaddr *in6ifa_ifpforlinklocal(struct ifnet *, int);

Modified: head/sys/netinet6/nd6.c
==============================================================================
--- head/sys/netinet6/nd6.c	Thu Nov  6 13:12:12 2014	(r274174)
+++ head/sys/netinet6/nd6.c	Thu Nov  6 13:13:09 2014	(r274175)
@@ -1188,7 +1188,6 @@ nd6_rtrequest(int req, struct rtentry *r
 	struct nd_defrouter *dr;
 	struct ifnet *ifp;
 
-	RT_LOCK_ASSERT(rt);
 	gateway = (struct sockaddr_in6 *)rt->rt_gateway;
 	ifp = rt->rt_ifp;
 

Modified: head/sys/sys/domain.h
==============================================================================
--- head/sys/sys/domain.h	Thu Nov  6 13:12:12 2014	(r274174)
+++ head/sys/sys/domain.h	Thu Nov  6 13:13:09 2014	(r274175)
@@ -64,6 +64,7 @@ struct domain {
 	int	dom_maxrtkey;		/* for routing layer */
 	void	*(*dom_ifattach)(struct ifnet *);
 	void	(*dom_ifdetach)(struct ifnet *, void *);
+	int	(*dom_ifmtu)(struct ifnet *);
 					/* af-dependent data on ifnet */
 };
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201411061313.sA6DD9Gw048172>