Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 14 Feb 2012 11:51:32 +0000 (UTC)
From:      "Bjoern A. Zeeb" <bz@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r231671 - projects/multi-fibv6/head/sys/netinet6
Message-ID:  <201202141151.q1EBpWUW096749@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bz
Date: Tue Feb 14 11:51:32 2012
New Revision: 231671
URL: http://svn.freebsd.org/changeset/base/231671

Log:
  Allow to provide a hint to in6_selectsrc() for the interface using the
  return ifnet double pointer.
  Pass that hint down to in6_selectif() to be used when i) the default FIB
  is queried and ii) route lookup fails because the network is not present
  (i.e. someone deleted the connected subnet).
  This hint should not be generally used from anywhere outside the neighbor
  discovery code.  We just make use of it from nd6_ns_output().
  
  Extend the nd6_na_output() interface by a nd6_na_output_fib() version
  and pass the FIB number from the NS mbuf on to NA to allow the new mbuf
  to inherit the FIB tag and a later lookup from ip6_output() to succeed
  in the aformentioned example case.
  Provide a wrapper function for the old public interface also used from
  CARP but mark it with BURN_BRIDGES to cleanup in HEAD after MFC.
  
  Sponsored by:	Cisco Systems, Inc.

Modified:
  projects/multi-fibv6/head/sys/netinet6/in6_src.c
  projects/multi-fibv6/head/sys/netinet6/nd6_nbr.c

Modified: projects/multi-fibv6/head/sys/netinet6/in6_src.c
==============================================================================
--- projects/multi-fibv6/head/sys/netinet6/in6_src.c	Tue Feb 14 11:37:04 2012	(r231670)
+++ projects/multi-fibv6/head/sys/netinet6/in6_src.c	Tue Feb 14 11:51:32 2012	(r231671)
@@ -131,7 +131,8 @@ static int selectroute __P((struct socka
 	struct ip6_moptions *, struct route_in6 *, struct ifnet **,
 	struct rtentry **, int, int));
 static int in6_selectif __P((struct sockaddr_in6 *, struct ip6_pktopts *,
-	struct ip6_moptions *, struct route_in6 *ro, struct ifnet **, int));
+	struct ip6_moptions *, struct route_in6 *ro, struct ifnet **,
+	struct ifnet *, int));
 
 static struct in6_addrpolicy *lookup_addrsel_policy(struct sockaddr_in6 *);
 
@@ -182,7 +183,7 @@ in6_selectsrc(struct sockaddr_in6 *dstso
     struct ifnet **ifpp, struct in6_addr *srcp)
 {
 	struct in6_addr dst, tmp;
-	struct ifnet *ifp = NULL;
+	struct ifnet *ifp = NULL, *oifp = NULL;
 	struct in6_ifaddr *ia = NULL, *ia_best = NULL;
 	struct in6_pktinfo *pi = NULL;
 	int dst_scope = -1, best_scope = -1, best_matchlen = -1;
@@ -195,8 +196,18 @@ in6_selectsrc(struct sockaddr_in6 *dstso
 	KASSERT(srcp != NULL, ("%s: srcp is NULL", __func__));
 
 	dst = dstsock->sin6_addr; /* make a copy for local operation */
-	if (ifpp)
+	if (ifpp) {
+		/*
+		 * Save a possibly passed in ifp for in6_selectsrc. Only
+		 * neighbor discovery code should use this feature, where
+		 * we may know the interface but not the FIB number holding
+		 * the connected subnet in case someone deleted it from the
+		 * default FIB and we need to check the interface.
+		 */
+		if (*ifpp != NULL)
+			oifp = *ifpp;
 		*ifpp = NULL;
+	}
 
 	if (inp != NULL) {
 		INP_LOCK_ASSERT(inp);
@@ -217,7 +228,7 @@ in6_selectsrc(struct sockaddr_in6 *dstso
 		struct in6_ifaddr *ia6;
 
 		/* get the outgoing interface */
-		if ((error = in6_selectif(dstsock, opts, mopts, ro, &ifp,
+		if ((error = in6_selectif(dstsock, opts, mopts, ro, &ifp, oifp,
 		    (inp != NULL) ? inp->inp_inc.inc_fibnum : RT_DEFAULT_FIB))
 		    != 0)
 			return (error);
@@ -283,7 +294,7 @@ in6_selectsrc(struct sockaddr_in6 *dstso
 	 * the outgoing interface and the destination address.
 	 */
 	/* get the outgoing interface */
-	if ((error = in6_selectif(dstsock, opts, mopts, ro, &ifp,
+	if ((error = in6_selectif(dstsock, opts, mopts, ro, &ifp, oifp,
 	    (inp != NULL) ? inp->inp_inc.inc_fibnum : RT_DEFAULT_FIB)) != 0)
 		return (error);
 
@@ -750,12 +761,14 @@ selectroute(struct sockaddr_in6 *dstsock
 static int
 in6_selectif(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
     struct ip6_moptions *mopts, struct route_in6 *ro, struct ifnet **retifp,
-    int fibnum)
+    struct ifnet *oifp, int fibnum)
 {
 	int error;
 	struct route_in6 sro;
 	struct rtentry *rt = NULL;
 
+	KASSERT(retifp != NULL, ("%s: retifp is NULL", __func__));
+
 	if (ro == NULL) {
 		bzero(&sro, sizeof(sro));
 		ro = &sro;
@@ -765,6 +778,11 @@ in6_selectif(struct sockaddr_in6 *dstsoc
 	    &rt, 1, fibnum)) != 0) {
 		if (ro == &sro && rt && rt == sro.ro_rt)
 			RTFREE(rt);
+		/* Help ND. See oifp comment in in6_selectsrc(). */
+		if (oifp != NULL && fibnum == RT_DEFAULT_FIB) {
+			*retifp = oifp;
+			error = 0;
+		}
 		return (error);
 	}
 

Modified: projects/multi-fibv6/head/sys/netinet6/nd6_nbr.c
==============================================================================
--- projects/multi-fibv6/head/sys/netinet6/nd6_nbr.c	Tue Feb 14 11:37:04 2012	(r231670)
+++ projects/multi-fibv6/head/sys/netinet6/nd6_nbr.c	Tue Feb 14 11:51:32 2012	(r231671)
@@ -85,6 +85,8 @@ static void nd6_dad_timer(struct dadq *)
 static void nd6_dad_ns_output(struct dadq *, struct ifaddr *);
 static void nd6_dad_ns_input(struct ifaddr *);
 static void nd6_dad_na_input(struct ifaddr *);
+static void nd6_na_output_fib(struct ifnet *, const struct in6_addr *,
+    const struct in6_addr *, u_long, int, struct sockaddr *, u_int);
 
 VNET_DEFINE(int, dad_ignore_ns) = 0;	/* ignore NS in DAD - specwise incorrect*/
 VNET_DEFINE(int, dad_maxtry) = 15;	/* max # of *tries* to transmit DAD packet */
@@ -344,19 +346,20 @@ nd6_ns_input(struct mbuf *m, int off, in
 		in6_all = in6addr_linklocal_allnodes;
 		if (in6_setscope(&in6_all, ifp, NULL) != 0)
 			goto bad;
-		nd6_na_output(ifp, &in6_all, &taddr6,
+		nd6_na_output_fib(ifp, &in6_all, &taddr6,
 		    ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
-		    rflag, tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL);
+		    rflag, tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL,
+		    M_GETFIB(m));
 		goto freeit;
 	}
 
 	nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen,
 	    ND_NEIGHBOR_SOLICIT, 0);
 
-	nd6_na_output(ifp, &saddr6, &taddr6,
+	nd6_na_output_fib(ifp, &saddr6, &taddr6,
 	    ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
 	    rflag | ND_NA_FLAG_SOLICITED, tlladdr,
-	    proxy ? (struct sockaddr *)&proxydl : NULL);
+	    proxy ? (struct sockaddr *)&proxydl : NULL, M_GETFIB(m));
  freeit:
 	if (ifa != NULL)
 		ifa_free(ifa);
@@ -508,14 +511,16 @@ nd6_ns_output(struct ifnet *ifp, const s
 			int error;
 			struct sockaddr_in6 dst_sa;
 			struct in6_addr src_in;
+			struct ifnet *oifp;
 
 			bzero(&dst_sa, sizeof(dst_sa));
 			dst_sa.sin6_family = AF_INET6;
 			dst_sa.sin6_len = sizeof(dst_sa);
 			dst_sa.sin6_addr = ip6->ip6_dst;
 
+			oifp = ifp;
 			error = in6_selectsrc(&dst_sa, NULL,
-			    NULL, &ro, NULL, NULL, &src_in);
+			    NULL, &ro, NULL, &oifp, &src_in);
 			if (error) {
 				char ip6buf[INET6_ADDRSTRLEN];
 				nd6log((LOG_DEBUG,
@@ -957,13 +962,14 @@ nd6_na_input(struct mbuf *m, int off, in
  * tlladdr - 1 if include target link-layer address
  * sdl0 - sockaddr_dl (= proxy NA) or NULL
  */
-void
-nd6_na_output(struct ifnet *ifp, const struct in6_addr *daddr6_0,
+static void
+nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0,
     const struct in6_addr *taddr6, u_long flags, int tlladdr,
-    struct sockaddr *sdl0)
+    struct sockaddr *sdl0, u_int fibnum)
 {
 	struct mbuf *m;
 	struct m_tag *mtag;
+	struct ifnet *oifp;
 	struct ip6_hdr *ip6;
 	struct nd_neighbor_advert *nd_na;
 	struct ip6_moptions im6o;
@@ -999,6 +1005,7 @@ nd6_na_output(struct ifnet *ifp, const s
 	if (m == NULL)
 		return;
 	m->m_pkthdr.rcvif = NULL;
+	M_SETFIB(m, fibnum);
 
 	if (IN6_IS_ADDR_MULTICAST(&daddr6)) {
 		m->m_flags |= M_MCAST;
@@ -1040,7 +1047,8 @@ nd6_na_output(struct ifnet *ifp, const s
 	 * Select a source whose scope is the same as that of the dest.
 	 */
 	bcopy(&dst_sa, &ro.ro_dst, sizeof(dst_sa));
-	error = in6_selectsrc(&dst_sa, NULL, NULL, &ro, NULL, NULL, &src);
+	oifp = ifp;
+	error = in6_selectsrc(&dst_sa, NULL, NULL, &ro, NULL, &oifp, &src);
 	if (error) {
 		char ip6buf[INET6_ADDRSTRLEN];
 		nd6log((LOG_DEBUG, "nd6_na_output: source can't be "
@@ -1129,6 +1137,18 @@ nd6_na_output(struct ifnet *ifp, const s
 	return;
 }
 
+#ifndef BURN_BRIDGES
+void
+nd6_na_output(struct ifnet *ifp, const struct in6_addr *daddr6_0,
+    const struct in6_addr *taddr6, u_long flags, int tlladdr,
+    struct sockaddr *sdl0)
+{
+
+	nd6_na_output_fib(ifp, daddr6_0, taddr6, flags, tlladdr, sdl0,
+	    RT_DEFAULT_FIB);
+}
+#endif
+
 caddr_t
 nd6_ifptomac(struct ifnet *ifp)
 {



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