Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 18 Sep 2014 21:48:06 +0000 (UTC)
From:      Alan Somers <asomers@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org
Subject:   svn commit: r271840 - in stable/9/sys: net netinet
Message-ID:  <201409182148.s8ILm6il084424@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: asomers
Date: Thu Sep 18 21:48:05 2014
New Revision: 271840
URL: http://svnweb.freebsd.org/changeset/base/271840

Log:
  MFC r264905 and r266860, except for the ATF parts.
  
  r266860
  Fix unintended KBI change from r264905.  Add _fib versions of
  ifa_ifwithnet() and ifa_ifwithdstaddr()  The legacy functions will call the
  _fib() versions with RT_ALL_FIBS, preserving legacy behavior.
  
  sys/net/if_var.h
  sys/net/if.c
          Add legacy-compatible functions as described above.  Ensure legacy
          behavior when RT_ALL_FIBS is passed as fibnum.
  
  sys/netinet/in_pcb.c
  sys/netinet/ip_output.c
  sys/netinet/ip_options.c
  sys/net/route.c
  sys/net/rtsock.c
  sys/netinet6/nd6.c
          Call with _fib() functions if we must use a specific fib, or the
          legacy functions otherwise.
  
  r264905
  Fix subnet and default routes on different FIBs on the same subnet.
  
  These two bugs are closely related.  The root cause is that ifa_ifwithnet
  does not consider FIBs when searching for an interface address.
  
  sys/net/if_var.h
  sys/net/if.c
          Add a fib argument to ifa_ifwithnet and ifa_ifwithdstadddr.  Those
          functions will only return an address whose interface fib equals the
          argument.
  
  sys/net/route.c
          Update calls to ifa_ifwithnet and ifa_ifwithdstaddr with fib
          arguments.
  
  sys/netinet/in.c
          Update in_addprefix to consider the interface fib when adding
          prefixes.  This will prevent it from not adding a subnet route when
          one already exists on a different fib.
  
  sys/net/rtsock.c
  sys/netinet/in_pcb.c
  sys/netinet/ip_output.c
  sys/netinet/ip_options.c
  sys/netinet6/nd6.c
          Add RT_DEFAULT_FIB arguments to ifa_ifwithdstaddr and ifa_ifwithnet.
          In some cases it there wasn't a clear specific fib number to use.
          In others, I was unable to test those functions so I chose
          RT_DEFAULT_FIB to minimize divergence from current behavior.  I will
          fix some of the latter changes along with PR kern/187553.
  
  PR:             kern/187550
  PR:             kern/187552

Modified:
  stable/9/sys/net/if.c
  stable/9/sys/net/if_var.h
  stable/9/sys/net/route.c
  stable/9/sys/netinet/in.c
Directory Properties:
  stable/9/   (props changed)
  stable/9/sys/   (props changed)
  stable/9/sys/net/   (props changed)

Modified: stable/9/sys/net/if.c
==============================================================================
--- stable/9/sys/net/if.c	Thu Sep 18 21:39:00 2014	(r271839)
+++ stable/9/sys/net/if.c	Thu Sep 18 21:48:05 2014	(r271840)
@@ -1628,7 +1628,7 @@ done:
  */
 /*ARGSUSED*/
 struct ifaddr *
-ifa_ifwithdstaddr(struct sockaddr *addr)
+ifa_ifwithdstaddr_fib(struct sockaddr *addr, int fibnum)
 {
 	struct ifnet *ifp;
 	struct ifaddr *ifa;
@@ -1637,6 +1637,8 @@ ifa_ifwithdstaddr(struct sockaddr *addr)
 	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
 			continue;
+		if ((fibnum != RT_ALL_FIBS) && (ifp->if_fib != fibnum))
+			continue;
 		IF_ADDR_RLOCK(ifp);
 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
 			if (ifa->ifa_addr->sa_family != addr->sa_family)
@@ -1656,12 +1658,19 @@ done:
 	return (ifa);
 }
 
+struct ifaddr *
+ifa_ifwithdstaddr(struct sockaddr *addr)
+{
+
+	return (ifa_ifwithdstaddr_fib(addr, RT_ALL_FIBS));
+}
+
 /*
  * Find an interface on a specific network.  If many, choice
  * is most specific found.
  */
 struct ifaddr *
-ifa_ifwithnet(struct sockaddr *addr, int ignore_ptp)
+ifa_ifwithnet_fib(struct sockaddr *addr, int ignore_ptp, int fibnum)
 {
 	struct ifnet *ifp;
 	struct ifaddr *ifa;
@@ -1681,12 +1690,14 @@ ifa_ifwithnet(struct sockaddr *addr, int
 
 	/*
 	 * Scan though each interface, looking for ones that have addresses
-	 * in this address family.  Maintain a reference on ifa_maybe once
-	 * we find one, as we release the IF_ADDR_RLOCK() that kept it stable
-	 * when we move onto the next interface.
+	 * in this address family and the requested fib.  Maintain a reference
+	 * on ifa_maybe once we find one, as we release the IF_ADDR_RLOCK() that
+	 * kept it stable when we move onto the next interface.
 	 */
 	IFNET_RLOCK_NOSLEEP();
 	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+		if ((fibnum != RT_ALL_FIBS) && (ifp->if_fib != fibnum))
+			continue;
 		IF_ADDR_RLOCK(ifp);
 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
 			char *cp, *cp2, *cp3;
@@ -1768,6 +1779,13 @@ done:
 	return (ifa);
 }
 
+struct ifaddr *
+ifa_ifwithnet(struct sockaddr *addr, int ignore_ptp)
+{
+
+	return (ifa_ifwithnet_fib(addr, ignore_ptp, RT_ALL_FIBS));
+}
+
 /*
  * Find an interface address specific to an interface best matching
  * a given address.

Modified: stable/9/sys/net/if_var.h
==============================================================================
--- stable/9/sys/net/if_var.h	Thu Sep 18 21:39:00 2014	(r271839)
+++ stable/9/sys/net/if_var.h	Thu Sep 18 21:48:05 2014	(r271840)
@@ -940,7 +940,9 @@ struct	ifaddr *ifa_ifwithaddr(struct soc
 int		ifa_ifwithaddr_check(struct sockaddr *);
 struct	ifaddr *ifa_ifwithbroadaddr(struct sockaddr *);
 struct	ifaddr *ifa_ifwithdstaddr(struct sockaddr *);
+struct	ifaddr *ifa_ifwithdstaddr_fib(struct sockaddr *, int);
 struct	ifaddr *ifa_ifwithnet(struct sockaddr *, int);
+struct	ifaddr *ifa_ifwithnet_fib(struct sockaddr *, int, int);
 struct	ifaddr *ifa_ifwithroute(int, struct sockaddr *, struct sockaddr *);
 struct	ifaddr *ifa_ifwithroute_fib(int, struct sockaddr *, struct sockaddr *, u_int);
 

Modified: stable/9/sys/net/route.c
==============================================================================
--- stable/9/sys/net/route.c	Thu Sep 18 21:39:00 2014	(r271839)
+++ stable/9/sys/net/route.c	Thu Sep 18 21:48:05 2014	(r271840)
@@ -553,7 +553,7 @@ rtredirect_fib(struct sockaddr *dst,
 	}
 
 	/* verify the gateway is directly reachable */
-	if ((ifa = ifa_ifwithnet(gateway, 0)) == NULL) {
+	if ((ifa = ifa_ifwithnet_fib(gateway, 0, fibnum)) == NULL) {
 		error = ENETUNREACH;
 		goto out;
 	}
@@ -710,7 +710,7 @@ ifa_ifwithroute_fib(int flags, struct so
 		 */
 		ifa = NULL;
 		if (flags & RTF_HOST)
-			ifa = ifa_ifwithdstaddr(dst);
+			ifa = ifa_ifwithdstaddr_fib(dst, fibnum);
 		if (ifa == NULL)
 			ifa = ifa_ifwithaddr(gateway);
 	} else {
@@ -719,10 +719,10 @@ ifa_ifwithroute_fib(int flags, struct so
 		 * or host, the gateway may still be on the
 		 * other end of a pt to pt link.
 		 */
-		ifa = ifa_ifwithdstaddr(gateway);
+		ifa = ifa_ifwithdstaddr_fib(gateway, fibnum);
 	}
 	if (ifa == NULL)
-		ifa = ifa_ifwithnet(gateway, 0);
+		ifa = ifa_ifwithnet_fib(gateway, 0, fibnum);
 	if (ifa == NULL) {
 		struct rtentry *rt = rtalloc1_fib(gateway, 0, RTF_RNH_LOCKED, fibnum);
 		if (rt == NULL)
@@ -836,7 +836,7 @@ rt_getifa_fib(struct rt_addrinfo *info, 
 	 */
 	if (info->rti_ifp == NULL && ifpaddr != NULL &&
 	    ifpaddr->sa_family == AF_LINK &&
-	    (ifa = ifa_ifwithnet(ifpaddr, 0)) != NULL) {
+	    (ifa = ifa_ifwithnet_fib(ifpaddr, 0, fibnum)) != NULL) {
 		info->rti_ifp = ifa->ifa_ifp;
 		ifa_free(ifa);
 	}

Modified: stable/9/sys/netinet/in.c
==============================================================================
--- stable/9/sys/netinet/in.c	Thu Sep 18 21:39:00 2014	(r271839)
+++ stable/9/sys/netinet/in.c	Thu Sep 18 21:48:05 2014	(r271840)
@@ -968,7 +968,7 @@ in_addprefix(struct in_ifaddr *target, i
 {
 	struct in_ifaddr *ia;
 	struct in_addr prefix, mask, p, m;
-	int error, fibnum;
+	int error;
 
 	if ((flags & RTF_HOST) != 0) {
 		prefix = target->ia_dstaddr.sin_addr;
@@ -979,9 +979,8 @@ in_addprefix(struct in_ifaddr *target, i
 		prefix.s_addr &= mask.s_addr;
 	}
 
-	fibnum = rt_add_addr_allfibs ? RT_ALL_FIBS : target->ia_ifp->if_fib;
-
 	IN_IFADDR_RLOCK();
+	/* Look for an existing address with the same prefix, mask, and fib */
 	TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) {
 		if (rtinitflags(ia)) {
 			p = ia->ia_dstaddr.sin_addr;
@@ -997,6 +996,8 @@ in_addprefix(struct in_ifaddr *target, i
 			    mask.s_addr != m.s_addr)
 				continue;
 		}
+		if (target->ia_ifp->if_fib != ia->ia_ifp->if_fib)
+			continue;
 
 		/*
 		 * If we got a matching prefix route inserted by other
@@ -1017,6 +1018,10 @@ in_addprefix(struct in_ifaddr *target, i
 				IN_IFADDR_RUNLOCK();
 				return (EEXIST);
 			} else {
+				int fibnum;
+
+				fibnum = rt_add_addr_allfibs ? RT_ALL_FIBS :
+					target->ia_ifp->if_fib;
 				rt_addrmsg(RTM_ADD, &target->ia_ifa, fibnum);
 				IN_IFADDR_RUNLOCK();
 				return (0);



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