Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 3 Feb 2012 13:08:44 +0000 (UTC)
From:      "Bjoern A. Zeeb" <bz@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r230942 - in projects/multi-fibv6/head/sys: fs/nfsclient net netinet netinet6 netipsec nfs nfsclient
Message-ID:  <201202031308.q13D8igQ088505@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bz
Date: Fri Feb  3 13:08:44 2012
New Revision: 230942
URL: http://svn.freebsd.org/changeset/base/230942

Log:
  Add multi-FIB IPv6 support to the core network stack supplementing
  the original IPv4 implementation from r178888:
  
  - Use RT_DEFAULT_FIB in the IPv4 implementation where noticed.
  - Use rt*fib() KPI with explicit RT_DEFAULT_FIB where applicable in
    the NFS code.
  - Use the new in6_rt* KPI in TCP, gif(4), and the IPv6 network stack
    where applicable.
  - Split in6_rtqtimo() and in6_mtutimo() as done in IPv4 and equally
    prevent multiple initializations of callouts in in6_inithead().
  - Use wrapper functions where needed to preserve the current KPI to
    ease MFCs.  Use BURN_BRIDGES to indicate expected future cleanup.
  - Fix (related) comments (both technical or style).
  - Convert to rtinit() where applicable and only use custom loops where
    currently not possible otherwise.
  - Multicast group, most neighbor discovery address actions and faith(4)
    are locked to the default FIB.  Individual IPv6 addresses will only
    appear in the default FIB, however redirect information and prefixes
    of connected subnets are automatically propagated to all FIBs by
    default (mimicking IPv4 behavior as closely as possible).
  
  Sponsored by:	Cisco Systems, Inc.

Modified:
  projects/multi-fibv6/head/sys/fs/nfsclient/nfs_clport.c
  projects/multi-fibv6/head/sys/fs/nfsclient/nfs_clvfsops.c
  projects/multi-fibv6/head/sys/net/if_faith.c
  projects/multi-fibv6/head/sys/netinet/in.c
  projects/multi-fibv6/head/sys/netinet/tcp_subr.c
  projects/multi-fibv6/head/sys/netinet6/icmp6.c
  projects/multi-fibv6/head/sys/netinet6/in6.c
  projects/multi-fibv6/head/sys/netinet6/in6_gif.c
  projects/multi-fibv6/head/sys/netinet6/in6_ifattach.c
  projects/multi-fibv6/head/sys/netinet6/in6_mcast.c
  projects/multi-fibv6/head/sys/netinet6/in6_rmx.c
  projects/multi-fibv6/head/sys/netinet6/in6_src.c
  projects/multi-fibv6/head/sys/netinet6/ip6_forward.c
  projects/multi-fibv6/head/sys/netinet6/ip6_input.c
  projects/multi-fibv6/head/sys/netinet6/ip6_output.c
  projects/multi-fibv6/head/sys/netinet6/ip6_var.h
  projects/multi-fibv6/head/sys/netinet6/nd6.c
  projects/multi-fibv6/head/sys/netinet6/nd6_nbr.c
  projects/multi-fibv6/head/sys/netinet6/nd6_rtr.c
  projects/multi-fibv6/head/sys/netipsec/ipsec_output.c
  projects/multi-fibv6/head/sys/nfs/bootp_subr.c
  projects/multi-fibv6/head/sys/nfsclient/nfs_vfsops.c

Modified: projects/multi-fibv6/head/sys/fs/nfsclient/nfs_clport.c
==============================================================================
--- projects/multi-fibv6/head/sys/fs/nfsclient/nfs_clport.c	Fri Feb  3 12:39:04 2012	(r230941)
+++ projects/multi-fibv6/head/sys/fs/nfsclient/nfs_clport.c	Fri Feb  3 13:08:44 2012	(r230942)
@@ -976,7 +976,8 @@ nfscl_getmyip(struct nfsmount *nmp, int 
 		sad.sin_len = sizeof (struct sockaddr_in);
 		sad.sin_addr.s_addr = sin->sin_addr.s_addr;
 		CURVNET_SET(CRED_TO_VNET(nmp->nm_sockreq.nr_cred));
-		rt = rtalloc1((struct sockaddr *)&sad, 0, 0UL);
+		rt = rtalloc1_fib((struct sockaddr *)&sad, 0, 0UL,
+		     curthread->td_proc->p_fibnum);
 		if (rt != NULL) {
 			if (rt->rt_ifp != NULL &&
 			    rt->rt_ifa != NULL &&
@@ -1001,7 +1002,8 @@ nfscl_getmyip(struct nfsmount *nmp, int 
 		sad6.sin6_len = sizeof (struct sockaddr_in6);
 		sad6.sin6_addr = sin6->sin6_addr;
 		CURVNET_SET(CRED_TO_VNET(nmp->nm_sockreq.nr_cred));
-		rt = rtalloc1((struct sockaddr *)&sad6, 0, 0UL);
+		rt = rtalloc1_fib((struct sockaddr *)&sad6, 0, 0UL,
+		     curthread->td_proc->p_fibnum);
 		if (rt != NULL) {
 			if (rt->rt_ifp != NULL &&
 			    rt->rt_ifa != NULL &&

Modified: projects/multi-fibv6/head/sys/fs/nfsclient/nfs_clvfsops.c
==============================================================================
--- projects/multi-fibv6/head/sys/fs/nfsclient/nfs_clvfsops.c	Fri Feb  3 12:39:04 2012	(r230941)
+++ projects/multi-fibv6/head/sys/fs/nfsclient/nfs_clvfsops.c	Fri Feb  3 13:08:44 2012	(r230942)
@@ -459,10 +459,10 @@ nfs_mountroot(struct mount *mp)
 		sin.sin_len = sizeof(sin);
                 /* XXX MRT use table 0 for this sort of thing */
 		CURVNET_SET(TD_TO_VNET(td));
-		error = rtrequest(RTM_ADD, (struct sockaddr *)&sin,
+		error = rtrequest_fib(RTM_ADD, (struct sockaddr *)&sin,
 		    (struct sockaddr *)&nd->mygateway,
 		    (struct sockaddr *)&mask,
-		    RTF_UP | RTF_GATEWAY, NULL);
+		    RTF_UP | RTF_GATEWAY, NULL, RT_DEFAULT_FIB);
 		CURVNET_RESTORE();
 		if (error)
 			panic("nfs_mountroot: RTM_ADD: %d", error);

Modified: projects/multi-fibv6/head/sys/net/if_faith.c
==============================================================================
--- projects/multi-fibv6/head/sys/net/if_faith.c	Fri Feb  3 12:39:04 2012	(r230941)
+++ projects/multi-fibv6/head/sys/net/if_faith.c	Fri Feb  3 13:08:44 2012	(r230942)
@@ -338,7 +338,7 @@ faithprefix(in6)
 	sin6.sin6_family = AF_INET6;
 	sin6.sin6_len = sizeof(struct sockaddr_in6);
 	sin6.sin6_addr = *in6;
-	rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
+	rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, 0UL, RT_DEFAULT_FIB);
 	if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_FAITH &&
 	    (rt->rt_ifp->if_flags & IFF_UP) != 0)
 		ret = 1;

Modified: projects/multi-fibv6/head/sys/netinet/in.c
==============================================================================
--- projects/multi-fibv6/head/sys/netinet/in.c	Fri Feb  3 12:39:04 2012	(r230941)
+++ projects/multi-fibv6/head/sys/netinet/in.c	Fri Feb  3 13:08:44 2012	(r230942)
@@ -879,7 +879,7 @@ in_ifinit(struct ifnet *ifp, struct in_i
 
 		bzero(&ia_ro, sizeof(ia_ro));
 		*((struct sockaddr_in *)(&ia_ro.ro_dst)) = ia->ia_addr;
-		rtalloc_ign_fib(&ia_ro, 0, 0);
+		rtalloc_ign_fib(&ia_ro, 0, RT_DEFAULT_FIB);
 		if ((ia_ro.ro_rt != NULL) && (ia_ro.ro_rt->rt_ifp != NULL) &&
 		    (ia_ro.ro_rt->rt_ifp == V_loif)) {
 			RT_LOCK(ia_ro.ro_rt);

Modified: projects/multi-fibv6/head/sys/netinet/tcp_subr.c
==============================================================================
--- projects/multi-fibv6/head/sys/netinet/tcp_subr.c	Fri Feb  3 12:39:04 2012	(r230941)
+++ projects/multi-fibv6/head/sys/netinet/tcp_subr.c	Fri Feb  3 13:08:44 2012	(r230942)
@@ -1750,7 +1750,7 @@ tcp_maxmtu6(struct in_conninfo *inc, int
 		sro6.ro_dst.sin6_family = AF_INET6;
 		sro6.ro_dst.sin6_len = sizeof(struct sockaddr_in6);
 		sro6.ro_dst.sin6_addr = inc->inc6_faddr;
-		rtalloc_ign((struct route *)&sro6, 0);
+		in6_rtalloc_ign(&sro6, 0, inc->inc_fibnum);
 	}
 	if (sro6.ro_rt != NULL) {
 		ifp = sro6.ro_rt->rt_ifp;

Modified: projects/multi-fibv6/head/sys/netinet6/icmp6.c
==============================================================================
--- projects/multi-fibv6/head/sys/netinet6/icmp6.c	Fri Feb  3 12:39:04 2012	(r230941)
+++ projects/multi-fibv6/head/sys/netinet6/icmp6.c	Fri Feb  3 13:08:44 2012	(r230942)
@@ -360,7 +360,7 @@ icmp6_error(struct mbuf *m, int type, in
 		m_adj(m, ICMPV6_PLD_MAXLEN - m->m_pkthdr.len);
 
 	preplen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
-	M_PREPEND(m, preplen, M_DONTWAIT);
+	M_PREPEND(m, preplen, M_DONTWAIT);	/* FIB is also copied over. */
 	if (m && m->m_len < preplen)
 		m = m_pullup(m, preplen);
 	if (m == NULL) {
@@ -584,7 +584,7 @@ icmp6_input(struct mbuf **mp, int *offp,
 			MGETHDR(n, M_DONTWAIT, n0->m_type);
 			n0len = n0->m_pkthdr.len;	/* save for use below */
 			if (n)
-				M_MOVE_PKTHDR(n, n0);
+				M_MOVE_PKTHDR(n, n0);	/* FIB copied. */
 			if (n && maxlen >= MHLEN) {
 				MCLGET(n, M_DONTWAIT);
 				if ((n->m_flags & M_EXT) == 0) {
@@ -1502,7 +1502,7 @@ ni6_input(struct mbuf *m, int off)
 		m_freem(m);
 		return (NULL);
 	}
-	M_MOVE_PKTHDR(n, m); /* just for recvif */
+	M_MOVE_PKTHDR(n, m); /* just for recvif and FIB */
 	if (replylen > MHLEN) {
 		if (replylen > MCLBYTES) {
 			/*
@@ -2414,7 +2414,7 @@ icmp6_redirect_input(struct mbuf *m, int
 	sin6.sin6_family = AF_INET6;
 	sin6.sin6_len = sizeof(struct sockaddr_in6);
 	bcopy(&reddst6, &sin6.sin6_addr, sizeof(reddst6));
-	rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
+	rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, 0UL, RT_DEFAULT_FIB);
 	if (rt) {
 		if (rt->rt_gateway == NULL ||
 		    rt->rt_gateway->sa_family != AF_INET6) {
@@ -2501,6 +2501,7 @@ icmp6_redirect_input(struct mbuf *m, int
 		struct sockaddr_in6 sdst;
 		struct sockaddr_in6 sgw;
 		struct sockaddr_in6 ssrc;
+		u_int fibnum;
 
 		bzero(&sdst, sizeof(sdst));
 		bzero(&sgw, sizeof(sgw));
@@ -2511,9 +2512,11 @@ icmp6_redirect_input(struct mbuf *m, int
 		bcopy(&redtgt6, &sgw.sin6_addr, sizeof(struct in6_addr));
 		bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr));
 		bcopy(&src6, &ssrc.sin6_addr, sizeof(struct in6_addr));
-		rtredirect((struct sockaddr *)&sdst, (struct sockaddr *)&sgw,
-		    (struct sockaddr *)NULL, RTF_GATEWAY | RTF_HOST,
-		    (struct sockaddr *)&ssrc);
+		for (fibnum = 0; fibnum < rt_numfibs; fibnum++)
+			in6_rtredirect((struct sockaddr *)&sdst,
+			    (struct sockaddr *)&sgw, (struct sockaddr *)NULL,
+			    RTF_GATEWAY | RTF_HOST, (struct sockaddr *)&ssrc,
+			    fibnum);
 	}
 	/* finally update cached route in each socket via pfctlinput */
     {
@@ -2598,6 +2601,7 @@ icmp6_redirect_output(struct mbuf *m0, s
 		MCLGET(m, M_DONTWAIT);
 	if (!m)
 		goto fail;
+	M_SETFIB(m, rt->rt_fibnum);
 	m->m_pkthdr.rcvif = NULL;
 	m->m_len = 0;
 	maxlen = M_TRAILINGSPACE(m);

Modified: projects/multi-fibv6/head/sys/netinet6/in6.c
==============================================================================
--- projects/multi-fibv6/head/sys/netinet6/in6.c	Fri Feb  3 12:39:04 2012	(r230941)
+++ projects/multi-fibv6/head/sys/netinet6/in6.c	Fri Feb  3 13:08:44 2012	(r230942)
@@ -180,6 +180,7 @@ in6_ifaddloop(struct ifaddr *ifa)
 	rt_mask(&rt) = (struct sockaddr *)&mask;
 	rt_key(&rt) = (struct sockaddr *)&addr;
 	rt.rt_flags = RTF_UP | RTF_HOST | RTF_STATIC;
+	/* Announce arrival of local address to all FIBs. */
 	rt_newaddrmsg(RTM_ADD, ifa, 0, &rt);
 }
 
@@ -214,6 +215,7 @@ in6_ifremloop(struct ifaddr *ifa)
 	rt_mask(&rt0) = (struct sockaddr *)&mask;
 	rt_key(&rt0) = (struct sockaddr *)&addr;
 	rt0.rt_flags = RTF_HOST | RTF_STATIC;
+	/* Announce removal of local address to all FIBs. */
 	rt_newaddrmsg(RTM_DELETE, ifa, 0, &rt0);
 }
 
@@ -282,6 +284,11 @@ in6_control(struct socket *so, u_long cm
 	switch (cmd) {
 	case SIOCGETSGCNT_IN6:
 	case SIOCGETMIFCNT_IN6:
+		/*	
+		 * XXX mrt_ioctl has a 3rd, unused, FIB argument in route.c.
+		 * We cannot see how that would be needed, so do not adjust the
+		 * KPI blindly; more likely should clean up the IPv4 variant.
+		 */
 		return (mrt6_ioctl ? mrt6_ioctl(cmd, data) : EOPNOTSUPP);
 	}
 
@@ -820,6 +827,7 @@ out:
 	return (error);
 }
 
+
 /*
  * Join necessary multicast groups.  Factored out from in6_update_ifa().
  * This entire work should only be done once, for the default FIB.
@@ -890,7 +898,7 @@ in6_update_ifa_join_mc(struct ifnet *ifp
 	 * reconsider this stuff.  Most applications actually do not need the
 	 * routes, since they usually specify the outgoing interface.
 	 */
-	rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
+	rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB);
 	if (rt != NULL) {
 		/* XXX: only works in !SCOPEDROUTING case. */
 		if (memcmp(&mltaddr.sin6_addr,
@@ -901,10 +909,10 @@ in6_update_ifa_join_mc(struct ifnet *ifp
 		}
 	}
 	if (rt == NULL) {
-		error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
+		error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
 		    (struct sockaddr *)&ia->ia_addr,
 		    (struct sockaddr *)&mltmask, RTF_UP,
-		    (struct rtentry **)0);
+		    (struct rtentry **)0, RT_DEFAULT_FIB);
 		if (error)
 			goto cleanup;
 	} else
@@ -950,7 +958,7 @@ in6_update_ifa_join_mc(struct ifnet *ifp
 	if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
 		goto cleanup; /* XXX: should not fail */
 	/* XXX: again, do we really need the route? */
-	rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
+	rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB);
 	if (rt != NULL) {
 		if (memcmp(&mltaddr.sin6_addr,
 		    &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
@@ -960,10 +968,10 @@ in6_update_ifa_join_mc(struct ifnet *ifp
 		}
 	}
 	if (rt == NULL) {
-		error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
+		error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
 		    (struct sockaddr *)&ia->ia_addr,
 		    (struct sockaddr *)&mltmask, RTF_UP,
-		    (struct rtentry **)0);
+		    (struct rtentry **)0, RT_DEFAULT_FIB);
 		if (error)
 			goto cleanup;
 	} else
@@ -1254,8 +1262,7 @@ in6_update_ifa(struct ifnet *ifp, struct
 
 	/*
 	 * Perform DAD, if needed.
-	 * XXX It may be of use, if we can administratively
-	 * disable DAD.
+	 * XXX It may be of use, if we can administratively disable DAD.
 	 */
 	if (in6if_do_dad(ifp) && ((ifra->ifra_flags & IN6_IFF_NODAD) == 0) &&
 	    (ia->ia6_flags & IN6_IFF_TENTATIVE))
@@ -1349,7 +1356,7 @@ in6_purgeaddr_mc(struct ifnet *ifp, stru
 	if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
 		return (error);
 
-	rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
+	rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB);
 	if (rt != NULL && rt->rt_gateway != NULL &&
 	    (memcmp(&satosin6(rt->rt_gateway)->sin6_addr, 
 		    &ia->ia_addr.sin6_addr,
@@ -1362,11 +1369,11 @@ in6_purgeaddr_mc(struct ifnet *ifp, stru
 			memcpy(&mltaddr.sin6_addr, &satosin6(rt_key(rt))->sin6_addr, 
 			       sizeof(mltaddr.sin6_addr));
 			RTFREE_LOCKED(rt);
-			error = rtrequest(RTM_DELETE,
+			error = in6_rtrequest(RTM_DELETE,
 			    (struct sockaddr *)&mltaddr,
 			    (struct sockaddr *)&ia->ia_addr,
 			    (struct sockaddr *)&mltmask, RTF_UP,
-			    (struct rtentry **)0);
+			    (struct rtentry **)0, RT_DEFAULT_FIB);
 			if (error)
 				log(LOG_INFO, "%s: link-local all-nodes "
 				    "multicast address deletion error\n",
@@ -1398,7 +1405,7 @@ in6_purgeaddr_mc(struct ifnet *ifp, stru
 	if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
 		return (error);
 
-	rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
+	rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB);
 	if (rt != NULL && rt->rt_gateway != NULL &&
 	    (memcmp(&satosin6(rt->rt_gateway)->sin6_addr, 
 		    &ia->ia_addr.sin6_addr,
@@ -1412,11 +1419,11 @@ in6_purgeaddr_mc(struct ifnet *ifp, stru
 			       sizeof(mltaddr.sin6_addr));
 
 			RTFREE_LOCKED(rt);
-			error = rtrequest(RTM_DELETE,
+			error = in6_rtrequest(RTM_DELETE,
 			    (struct sockaddr *)&mltaddr,
 			    (struct sockaddr *)&ia->ia_addr,
 			    (struct sockaddr *)&mltmask, RTF_UP,
-			    (struct rtentry **)0);
+			    (struct rtentry **)0, RT_DEFAULT_FIB);
 			if (error)
 				log(LOG_INFO, "%s: node-local all-nodes"
 				    "multicast address deletion error\n",
@@ -1489,6 +1496,7 @@ in6_purgeaddr(struct ifaddr *ifa)
 	/* stop DAD processing */
 	nd6_dad_stop(ifa);
 
+	/* Remove local address entry from lltable. */
 	in6_ifremloop(ifa);
 
 	/* Leave multicast groups. */
@@ -1499,25 +1507,11 @@ in6_purgeaddr(struct ifaddr *ifa)
 
 	plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */
 	if ((ia->ia_flags & IFA_ROUTE) && plen == 128) {
-		int error;
-		struct sockaddr *dstaddr;
-
-		/* 
-		 * use the interface address if configuring an
-		 * interface address with a /128 prefix len
-		 */
-		if (ia->ia_dstaddr.sin6_family == AF_INET6)
-			dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
-		else
-			dstaddr = (struct sockaddr *)&ia->ia_addr;
-
-		error = rtrequest(RTM_DELETE,
-		    (struct sockaddr *)dstaddr,
-		    (struct sockaddr *)&ia->ia_addr,
-		    (struct sockaddr *)&ia->ia_prefixmask,
-		    ia->ia_flags | RTF_HOST, NULL);
+		error = rtinit(&(ia->ia_ifa), RTM_DELETE, ia->ia_flags |
+		    (ia->ia_dstaddr.sin6_family == AF_INET6) ? RTF_HOST : 0);
 		if (error != 0)
-			return;
+			log(LOG_INFO, "%s: err=%d, destination address delete "
+			    "failed\n", __func__, error);
 		ia->ia_flags &= ~IFA_ROUTE;
 	}
 
@@ -1849,8 +1843,7 @@ in6_lifaddr_ioctl(struct socket *so, u_l
 }
 
 /*
- * Initialize an interface's intetnet6 address
- * and routing table entry.
+ * Initialize an interface's IPv6 address and routing table entry.
  */
 static int
 in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia,
@@ -1900,13 +1893,8 @@ in6_ifinit(struct ifnet *ifp, struct in6
 	if (!(ia->ia_flags & IFA_ROUTE) && plen == 128 &&
 	    ia->ia_dstaddr.sin6_family == AF_INET6) {
 		int rtflags = RTF_UP | RTF_HOST;
-
-		error = rtrequest(RTM_ADD,
-		    (struct sockaddr *)&ia->ia_dstaddr,
-		    (struct sockaddr *)&ia->ia_addr,
-		    (struct sockaddr *)&ia->ia_prefixmask,
-		    ia->ia_flags | rtflags, NULL);
-		if (error != 0)
+		error = rtinit(&ia->ia_ifa, RTM_ADD, ia->ia_flags | rtflags);
+		if (error)
 			return (error);
 		ia->ia_flags |= IFA_ROUTE;
 		/*
@@ -1926,7 +1914,7 @@ in6_ifinit(struct ifnet *ifp, struct in6
 			ia->ia_flags |= IFA_RTSELF;
 	}
 
-	/* Add ownaddr as loopback rtentry, if necessary (ex. on p2p link). */
+	/* Add local address to lltable, if necessary (ex. on p2p link). */
 	if (newhost)
 		in6_ifaddloop(&(ia->ia_ifa));
 
@@ -2529,8 +2517,10 @@ in6_lltable_rtcheck(struct ifnet *ifp, 
 	KASSERT(l3addr->sa_family == AF_INET6,
 	    ("sin_family %d", l3addr->sa_family));
 
+	/* Our local addresses are always only installed on the default FIB. */
 	/* XXX rtalloc1 should take a const param */
-	rt = rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0);
+	rt = in6_rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0,
+	    RT_DEFAULT_FIB);
 	if (rt == NULL || (rt->rt_flags & RTF_GATEWAY) || rt->rt_ifp != ifp) {
 		struct ifaddr *ifa;
 		/* 

Modified: projects/multi-fibv6/head/sys/netinet6/in6_gif.c
==============================================================================
--- projects/multi-fibv6/head/sys/netinet6/in6_gif.c	Fri Feb  3 12:39:04 2012	(r230941)
+++ projects/multi-fibv6/head/sys/netinet6/in6_gif.c	Fri Feb  3 13:08:44 2012	(r230942)
@@ -228,6 +228,8 @@ in6_gif_output(struct ifnet *ifp,
 	ip6->ip6_flow &= ~htonl(0xff << 20);
 	ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
 
+	M_SETFIB(m, sc->gif_fibnum);
+
 	if (dst->sin6_family != sin6_dst->sin6_family ||
 	     !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) {
 		/* cache route doesn't match */
@@ -245,7 +247,7 @@ in6_gif_output(struct ifnet *ifp,
 	}
 
 	if (sc->gif_ro6.ro_rt == NULL) {
-		rtalloc((struct route *)&sc->gif_ro6);
+		in6_rtalloc(&sc->gif_ro6, sc->gif_fibnum);
 		if (sc->gif_ro6.ro_rt == NULL) {
 			m_freem(m);
 			return ENETUNREACH;
@@ -404,7 +406,8 @@ gif_validate6(const struct ip6_hdr *ip6,
 		sin6.sin6_addr = ip6->ip6_src;
 		sin6.sin6_scope_id = 0; /* XXX */
 
-		rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
+		rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, 0UL,
+		    sc->gif_fibnum);
 		if (!rt || rt->rt_ifp != ifp) {
 #if 0
 			char ip6buf[INET6_ADDRSTRLEN];

Modified: projects/multi-fibv6/head/sys/netinet6/in6_ifattach.c
==============================================================================
--- projects/multi-fibv6/head/sys/netinet6/in6_ifattach.c	Fri Feb  3 12:39:04 2012	(r230941)
+++ projects/multi-fibv6/head/sys/netinet6/in6_ifattach.c	Fri Feb  3 13:08:44 2012	(r230942)
@@ -790,7 +790,6 @@ in6_ifdetach(struct ifnet *ifp)
 	struct ifaddr *ifa, *next;
 	struct radix_node_head *rnh;
 	struct rtentry *rt;
-	short rtflags;
 	struct sockaddr_in6 sin6;
 	struct in6_multi_mship *imm;
 
@@ -821,16 +820,9 @@ in6_ifdetach(struct ifnet *ifp)
 			in6_leavegroup(imm);
 		}
 
-		/* remove from the routing table */
-		if ((ia->ia_flags & IFA_ROUTE) &&
-		    (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0, 0UL))) {
-			rtflags = rt->rt_flags;
-			RTFREE_LOCKED(rt);
-			rtrequest(RTM_DELETE, (struct sockaddr *)&ia->ia_addr,
-			    (struct sockaddr *)&ia->ia_addr,
-			    (struct sockaddr *)&ia->ia_prefixmask,
-			    rtflags, (struct rtentry **)0);
-		}
+		/* Remove link-local from the routing table. */
+		if (ia->ia_flags & IFA_ROUTE)
+			(void)rtinit(&ia->ia_ifa, RTM_DELETE, ia->ia_flags);
 
 		/* remove from the linked list */
 		IF_ADDR_WLOCK(ifp);
@@ -859,7 +851,10 @@ in6_ifdetach(struct ifnet *ifp)
 	 */
 	nd6_purge(ifp);
 
-	/* remove route to link-local allnodes multicast (ff02::1) */
+	/*
+	 * Remove route to link-local allnodes multicast (ff02::1).
+	 * These only get automatically installed for the default FIB.
+	 */
 	bzero(&sin6, sizeof(sin6));
 	sin6.sin6_len = sizeof(struct sockaddr_in6);
 	sin6.sin6_family = AF_INET6;
@@ -868,10 +863,11 @@ in6_ifdetach(struct ifnet *ifp)
 		/* XXX: should not fail */
 		return;
 	/* XXX grab lock first to avoid LOR */
-	rnh = rt_tables_get_rnh(0, AF_INET6);
+	rnh = rt_tables_get_rnh(RT_DEFAULT_FIB, AF_INET6);
 	if (rnh != NULL) {
 		RADIX_NODE_HEAD_LOCK(rnh);
-		rt = rtalloc1((struct sockaddr *)&sin6, 0, RTF_RNH_LOCKED);
+		rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, RTF_RNH_LOCKED,
+		    RT_DEFAULT_FIB);
 		if (rt) {
 			if (rt->rt_ifp == ifp)
 				rtexpunge(rt);

Modified: projects/multi-fibv6/head/sys/netinet6/in6_mcast.c
==============================================================================
--- projects/multi-fibv6/head/sys/netinet6/in6_mcast.c	Fri Feb  3 12:39:04 2012	(r230941)
+++ projects/multi-fibv6/head/sys/netinet6/in6_mcast.c	Fri Feb  3 13:08:44 2012	(r230942)
@@ -1764,7 +1764,7 @@ ip6_getmoptions(struct inpcb *inp, struc
  * Returns NULL if no ifp could be found.
  */
 static struct ifnet *
-in6p_lookup_mcast_ifp(const struct inpcb *in6p __unused,
+in6p_lookup_mcast_ifp(const struct inpcb *in6p,
     const struct sockaddr_in6 *gsin6)
 {
 	struct route_in6	 ro6;
@@ -1780,11 +1780,8 @@ in6p_lookup_mcast_ifp(const struct inpcb
 	ifp = NULL;
 	memset(&ro6, 0, sizeof(struct route_in6));
 	memcpy(&ro6.ro_dst, gsin6, sizeof(struct sockaddr_in6));
-#ifdef notyet
-	rtalloc_ign_fib(&ro6, 0, inp ? inp->inp_inc.inc_fibnum : 0);
-#else
-	rtalloc_ign((struct route *)&ro6, 0);
-#endif
+	rtalloc_ign_fib((struct route *)&ro6, 0,
+	    in6p ? in6p->inp_inc.inc_fibnum : RT_DEFAULT_FIB);
 	if (ro6.ro_rt != NULL) {
 		ifp = ro6.ro_rt->rt_ifp;
 		KASSERT(ifp != NULL, ("%s: null ifp", __func__));

Modified: projects/multi-fibv6/head/sys/netinet6/in6_rmx.c
==============================================================================
--- projects/multi-fibv6/head/sys/netinet6/in6_rmx.c	Fri Feb  3 12:39:04 2012	(r230941)
+++ projects/multi-fibv6/head/sys/netinet6/in6_rmx.c	Fri Feb  3 13:08:44 2012	(r230942)
@@ -168,7 +168,8 @@ in6_addroute(void *v_arg, void *n_arg, s
 		 *	net route entry, 3ffe:0501:: -> if0.
 		 *	This case should not raise an error.
 		 */
-		rt2 = rtalloc1((struct sockaddr *)sin6, 0, RTF_RNH_LOCKED);
+		rt2 = in6_rtalloc1((struct sockaddr *)sin6, 0, RTF_RNH_LOCKED,
+		    rt->rt_fibnum);
 		if (rt2) {
 			if (((rt2->rt_flags & (RTF_HOST|RTF_GATEWAY)) == 0)
 			 && rt2->rt_gateway
@@ -255,10 +256,11 @@ in6_rtqkill(struct radix_node *rn, void 
 			if (rt->rt_refcnt > 0)
 				panic("rtqkill route really not free");
 
-			err = rtrequest(RTM_DELETE,
+			err = in6_rtrequest(RTM_DELETE,
 					(struct sockaddr *)rt_key(rt),
 					rt->rt_gateway, rt_mask(rt),
-					rt->rt_flags|RTF_RNH_LOCKED, 0);
+					rt->rt_flags|RTF_RNH_LOCKED, 0,
+					rt->rt_fibnum);
 			if (err) {
 				log(LOG_WARNING, "in6_rtqkill: error %d", err);
 			} else {
@@ -287,19 +289,11 @@ static VNET_DEFINE(struct callout, rtq_t
 #define	V_rtq_timer6			VNET(rtq_timer6)
 
 static void
-in6_rtqtimo(void *rock)
+in6_rtqtimo_one(struct radix_node_head *rnh)
 {
-	CURVNET_SET_QUIET((struct vnet *) rock);
-	struct radix_node_head *rnh;
 	struct rtqk_arg arg;
-	struct timeval atv;
 	static time_t last_adjusted_timeout = 0;
 
-	rnh = rt_tables_get_rnh(0, AF_INET6);
-	if (rnh == NULL) {
-		CURVNET_RESTORE();
-		return;
-	}
 	arg.found = arg.killed = 0;
 	arg.rnh = rnh;
 	arg.nextstop = time_uptime + V_rtq_timeout6;
@@ -335,9 +329,24 @@ in6_rtqtimo(void *rock)
 		rnh->rnh_walktree(rnh, in6_rtqkill, &arg);
 		RADIX_NODE_HEAD_UNLOCK(rnh);
 	}
+}
+
+static void
+in6_rtqtimo(void *rock)
+{
+	CURVNET_SET_QUIET((struct vnet *) rock);
+	struct radix_node_head *rnh;
+	struct timeval atv;
+	u_int fibnum;
+
+	for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
+		rnh = rt_tables_get_rnh(fibnum, AF_INET6);
+		if (rnh != NULL)
+			in6_rtqtimo_one(rnh);
+	}
 
 	atv.tv_usec = 0;
-	atv.tv_sec = arg.nextstop - time_uptime;
+	atv.tv_sec = V_rtq_timeout6;
 	callout_reset(&V_rtq_timer6, tvtohz(&atv), in6_rtqtimo, rock);
 	CURVNET_RESTORE();
 }
@@ -377,31 +386,33 @@ in6_mtuexpire(struct radix_node *rn, voi
 #define	MTUTIMO_DEFAULT	(60*1)
 
 static void
-in6_mtutimo(void *rock)
+in6_mtutimo_one(struct radix_node_head *rnh)
 {
-	CURVNET_SET_QUIET((struct vnet *) rock);
-	struct radix_node_head *rnh;
 	struct mtuex_arg arg;
-	struct timeval atv;
 
-	rnh = rt_tables_get_rnh(0, AF_INET6);
-	if (rnh == NULL) {
-		CURVNET_RESTORE();
-		return;
-	}
 	arg.rnh = rnh;
 	arg.nextstop = time_uptime + MTUTIMO_DEFAULT;
 	RADIX_NODE_HEAD_LOCK(rnh);
 	rnh->rnh_walktree(rnh, in6_mtuexpire, &arg);
 	RADIX_NODE_HEAD_UNLOCK(rnh);
+}
 
-	atv.tv_usec = 0;
-	atv.tv_sec = arg.nextstop - time_uptime;
-	if (atv.tv_sec < 0) {
-		printf("invalid mtu expiration time on routing table\n");
-		arg.nextstop = time_uptime + 30;	/* last resort */
-		atv.tv_sec = 30;
+static void
+in6_mtutimo(void *rock)
+{
+	CURVNET_SET_QUIET((struct vnet *) rock);
+	struct radix_node_head *rnh;
+	struct timeval atv;
+	u_int fibnum;
+
+	for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
+		rnh = rt_tables_get_rnh(fibnum, AF_INET6);
+		if (rnh != NULL)
+			in6_mtutimo_one(rnh);
 	}
+
+	atv.tv_sec = MTUTIMO_DEFAULT;
+	atv.tv_usec = 0;
 	callout_reset(&V_rtq_mtutimer, tvtohz(&atv), in6_mtutimo, rock);
 	CURVNET_RESTORE();
 }
@@ -413,6 +424,9 @@ in6_mtutimo(void *rock)
  * value should be so just use that).. FIX AFTER RELENG_7 is MFC'd
  * see also comments in in_inithead() vfs_export.c and domain.h
  */
+static VNET_DEFINE(int, _in6_rt_was_here);
+#define	V__in6_rt_was_here	VNET(_in6_rt_was_here)
+
 int
 in6_inithead(void **head, int off)
 {
@@ -425,13 +439,17 @@ in6_inithead(void **head, int off)
 		return 1;	/* only do the rest for the real thing */
 
 	rnh = *head;
-	KASSERT(rnh == rt_tables_get_rnh(0, AF_INET6), ("rnh?"));
 	rnh->rnh_addaddr = in6_addroute;
 	rnh->rnh_matchaddr = in6_matroute;
-	callout_init(&V_rtq_timer6, CALLOUT_MPSAFE);
-	callout_init(&V_rtq_mtutimer, CALLOUT_MPSAFE);
-	in6_rtqtimo(curvnet);	/* kick off timeout first time */
-	in6_mtutimo(curvnet);	/* kick off timeout first time */
+
+	if (V__in6_rt_was_here == 0) {
+		callout_init(&V_rtq_timer6, CALLOUT_MPSAFE);
+		callout_init(&V_rtq_mtutimer, CALLOUT_MPSAFE);
+		in6_rtqtimo(curvnet);	/* kick off timeout first time */
+		in6_mtutimo(curvnet);	/* kick off timeout first time */
+		V__in6_rt_was_here = 1;
+	}
+
 	return 1;
 }
 

Modified: projects/multi-fibv6/head/sys/netinet6/in6_src.c
==============================================================================
--- projects/multi-fibv6/head/sys/netinet6/in6_src.c	Fri Feb  3 12:39:04 2012	(r230941)
+++ projects/multi-fibv6/head/sys/netinet6/in6_src.c	Fri Feb  3 13:08:44 2012	(r230942)
@@ -129,9 +129,9 @@ VNET_DEFINE(int, ip6_prefer_tempaddr) = 
 
 static int selectroute __P((struct sockaddr_in6 *, struct ip6_pktopts *,
 	struct ip6_moptions *, struct route_in6 *, struct ifnet **,
-	struct rtentry **, int));
+	struct rtentry **, int, int));
 static int in6_selectif __P((struct sockaddr_in6 *, struct ip6_pktopts *,
-	struct ip6_moptions *, struct route_in6 *ro, struct ifnet **));
+	struct ip6_moptions *, struct route_in6 *ro, struct ifnet **, int));
 
 static struct in6_addrpolicy *lookup_addrsel_policy(struct sockaddr_in6 *);
 
@@ -217,7 +217,9 @@ in6_selectsrc(struct sockaddr_in6 *dstso
 		struct in6_ifaddr *ia6;
 
 		/* get the outgoing interface */
-		if ((error = in6_selectif(dstsock, opts, mopts, ro, &ifp)) != 0)
+		if ((error = in6_selectif(dstsock, opts, mopts, ro, &ifp,
+		    (inp != NULL) ? inp->inp_inc.inc_fibnum : RT_DEFAULT_FIB))
+		    != 0)
 			return (error);
 
 		/*
@@ -281,7 +283,8 @@ 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)) != 0)
+	if ((error = in6_selectif(dstsock, opts, mopts, ro, &ifp,
+	    (inp != NULL) ? inp->inp_inc.inc_fibnum : RT_DEFAULT_FIB)) != 0)
 		return (error);
 
 #ifdef DIAGNOSTIC
@@ -504,7 +507,7 @@ in6_selectsrc(struct sockaddr_in6 *dstso
 static int
 selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
     struct ip6_moptions *mopts, struct route_in6 *ro,
-    struct ifnet **retifp, struct rtentry **retrt, int norouteok)
+    struct ifnet **retifp, struct rtentry **retrt, int norouteok, int fibnum)
 {
 	int error = 0;
 	struct ifnet *ifp = NULL;
@@ -581,7 +584,7 @@ selectroute(struct sockaddr_in6 *dstsock
 
 
 		if (ron->ro_rt == NULL) {
-			rtalloc((struct route *)ron); /* multi path case? */
+			in6_rtalloc(ron, fibnum); /* multi path case? */
 			if (ron->ro_rt == NULL) {
 				if (ron->ro_rt) {
 					RTFREE(ron->ro_rt);
@@ -616,7 +619,7 @@ selectroute(struct sockaddr_in6 *dstsock
 			*satosin6(&ron->ro_dst) = *sin6_next;
 		}
 		if (ron->ro_rt == NULL) {
-			rtalloc((struct route *)ron); /* multi path case? */
+			in6_rtalloc(ron); /* multi path case? */
 			if (ron->ro_rt == NULL ||
 			    !(ron->ro_rt->rt_flags & RTF_LLINFO)) {
 				if (ron->ro_rt) {
@@ -661,11 +664,11 @@ selectroute(struct sockaddr_in6 *dstsock
 			sa6->sin6_scope_id = 0;
 
 #ifdef RADIX_MPATH
-				rtalloc_mpath((struct route *)ro,
-				    ntohl(sa6->sin6_addr.s6_addr32[3]));
+				rtalloc_mpath_fib((struct route *)ro,
+				    ntohl(sa6->sin6_addr.s6_addr32[3]), fibnum);
 #else			
-				ro->ro_rt = rtalloc1(&((struct route *)ro)
-				    ->ro_dst, 0, 0UL);
+				ro->ro_rt = in6_rtalloc1((struct sockaddr *)
+				    &ro->ro_dst, 0, 0UL, fibnum);
 				if (ro->ro_rt)
 					RT_UNLOCK(ro->ro_rt);
 #endif
@@ -746,7 +749,8 @@ 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)
+    struct ip6_moptions *mopts, struct route_in6 *ro, struct ifnet **retifp,
+    int fibnum)
 {
 	int error;
 	struct route_in6 sro;
@@ -758,7 +762,7 @@ in6_selectif(struct sockaddr_in6 *dstsoc
 	}
 
 	if ((error = selectroute(dstsock, opts, mopts, ro, retifp,
-				     &rt, 1)) != 0) {
+	    &rt, 1, fibnum)) != 0) {
 		if (ro == &sro && rt && rt == sro.ro_rt)
 			RTFREE(rt);
 		return (error);
@@ -795,7 +799,10 @@ in6_selectif(struct sockaddr_in6 *dstsoc
 }
 
 /*
- * clone - meaningful only for bsdi and freebsd
+ * Public wrapper function to selectroute().
+ *
+ * XXX-BZ in6_selectroute() should and will grow the FIB argument. The
+ * in6_selectroute_fib() function is only there for backward compat on stable.
  */
 int
 in6_selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
@@ -804,9 +811,21 @@ in6_selectroute(struct sockaddr_in6 *dst
 {
 
 	return (selectroute(dstsock, opts, mopts, ro, retifp,
-	    retrt, 0));
+	    retrt, 0, RT_DEFAULT_FIB));
 }
 
+#ifndef BURN_BRIDGES
+int
+in6_selectroute_fib(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
+    struct ip6_moptions *mopts, struct route_in6 *ro,
+    struct ifnet **retifp, struct rtentry **retrt, int fibnum)
+{
+
+	return (selectroute(dstsock, opts, mopts, ro, retifp,
+	    retrt, 0, fibnum));
+}
+#endif
+
 /*
  * Default hop limit selection. The precedence is as follows:
  * 1. Hoplimit value specified via ioctl.
@@ -830,7 +849,8 @@ in6_selecthlim(struct inpcb *in6p, struc
 		ro6.ro_dst.sin6_family = AF_INET6;
 		ro6.ro_dst.sin6_len = sizeof(struct sockaddr_in6);
 		ro6.ro_dst.sin6_addr = in6p->in6p_faddr;
-		rtalloc((struct route *)&ro6);
+		in6_rtalloc(&ro6, in6p ? in6p->inp_inc.inc_fibnum :
+		    RT_DEFAULT_FIB);
 		if (ro6.ro_rt) {
 			lifp = ro6.ro_rt->rt_ifp;
 			RTFREE(ro6.ro_rt);

Modified: projects/multi-fibv6/head/sys/netinet6/ip6_forward.c
==============================================================================
--- projects/multi-fibv6/head/sys/netinet6/ip6_forward.c	Fri Feb  3 12:39:04 2012	(r230941)
+++ projects/multi-fibv6/head/sys/netinet6/ip6_forward.c	Fri Feb  3 13:08:44 2012	(r230942)
@@ -362,7 +362,7 @@ again:
 #ifdef IPFIREWALL_FORWARD
 again2:
 #endif
-	rin6.ro_rt = rtalloc1((struct sockaddr *)dst, 0, 0);
+	rin6.ro_rt = in6_rtalloc1((struct sockaddr *)dst, 0, 0, M_GETFIB(m));
 	if (rin6.ro_rt != NULL)
 		RT_UNLOCK(rin6.ro_rt);
 	else {

Modified: projects/multi-fibv6/head/sys/netinet6/ip6_input.c
==============================================================================
--- projects/multi-fibv6/head/sys/netinet6/ip6_input.c	Fri Feb  3 12:39:04 2012	(r230941)
+++ projects/multi-fibv6/head/sys/netinet6/ip6_input.c	Fri Feb  3 13:08:44 2012	(r230942)
@@ -666,7 +666,7 @@ passin:
 	dst->sin6_len = sizeof(struct sockaddr_in6);
 	dst->sin6_family = AF_INET6;
 	dst->sin6_addr = ip6->ip6_dst;
-	rin6.ro_rt = rtalloc1((struct sockaddr *)dst, 0, 0);
+	rin6.ro_rt = in6_rtalloc1((struct sockaddr *)dst, 0, 0, M_GETFIB(m));
 	if (rin6.ro_rt)
 		RT_UNLOCK(rin6.ro_rt);
 

Modified: projects/multi-fibv6/head/sys/netinet6/ip6_output.c
==============================================================================
--- projects/multi-fibv6/head/sys/netinet6/ip6_output.c	Fri Feb  3 12:39:04 2012	(r230941)
+++ projects/multi-fibv6/head/sys/netinet6/ip6_output.c	Fri Feb  3 13:08:44 2012	(r230942)
@@ -142,7 +142,7 @@ static int ip6_insertfraghdr __P((struct
 static int ip6_insert_jumboopt(struct ip6_exthdrs *, u_int32_t);
 static int ip6_splithdr(struct mbuf *, struct ip6_exthdrs *);
 static int ip6_getpmtu __P((struct route_in6 *, struct route_in6 *,
-	struct ifnet *, struct in6_addr *, u_long *, int *));
+	struct ifnet *, struct in6_addr *, u_long *, int *, int));
 static int copypktopts(struct ip6_pktopts *, struct ip6_pktopts *, int);
 
 
@@ -241,6 +241,9 @@ ip6_output(struct mbuf *m0, struct ip6_p
 		goto bad;
 	}
 
+	if (inp != NULL)
+		M_SETFIB(m, inp->inp_inc.inc_fibnum);
+
 	finaldst = ip6->ip6_dst;
 	bzero(&exthdrs, sizeof(exthdrs));
 	if (opt) {
@@ -604,8 +607,8 @@ again:
 	if (flevalid) {
 		rt = ro->ro_rt;
 		ifp = ro->ro_rt->rt_ifp;
-	} else if ((error = in6_selectroute(&dst_sa, opt, im6o, ro,
-	    &ifp, &rt)) != 0) {
+	} else if ((error = in6_selectroute_fib(&dst_sa, opt, im6o, ro,
+	    &ifp, &rt, inp ? inp->inp_inc.inc_fibnum : M_GETFIB(m))) != 0) {
 		switch (error) {
 		case EHOSTUNREACH:
 			V_ip6stat.ip6s_noroute++;
@@ -773,7 +776,7 @@ again:
 
 	/* Determine path MTU. */
 	if ((error = ip6_getpmtu(ro_pmtu, ro, ifp, &finaldst, &mtu,
-	    &alwaysfrag)) != 0)
+	    &alwaysfrag, inp ? inp->inp_inc.inc_fibnum : M_GETFIB(m))) != 0)
 		goto bad;
 
 	/*
@@ -1064,7 +1067,7 @@ passout:
 				goto sendorfree;
 			}
 			m->m_pkthdr.rcvif = NULL;
-			m->m_flags = m0->m_flags & M_COPYFLAGS;
+			m->m_flags = m0->m_flags & M_COPYFLAGS;	/* incl. FIB */
 			*mnext = m;
 			mnext = &m->m_nextpkt;
 			m->m_data += max_linkhdr;
@@ -1321,7 +1324,7 @@ ip6_insertfraghdr(struct mbuf *m0, struc
 static int
 ip6_getpmtu(struct route_in6 *ro_pmtu, struct route_in6 *ro,
     struct ifnet *ifp, struct in6_addr *dst, u_long *mtup,
-    int *alwaysfragp)
+    int *alwaysfragp, int fibnum)
 {
 	u_int32_t mtu = 0;
 	int alwaysfrag = 0;
@@ -1343,7 +1346,7 @@ ip6_getpmtu(struct route_in6 *ro_pmtu, s
 			sa6_dst->sin6_len = sizeof(struct sockaddr_in6);
 			sa6_dst->sin6_addr = *dst;
 
-			rtalloc((struct route *)ro_pmtu);
+			in6_rtalloc(ro_pmtu, fibnum);
 		}
 	}
 	if (ro_pmtu->ro_rt) {
@@ -1981,7 +1984,8 @@ do { \
 				 * the outgoing interface.
 				 */
 				error = ip6_getpmtu(&sro, NULL, NULL,
-				    &in6p->in6p_faddr, &pmtu, NULL);
+				    &in6p->in6p_faddr, &pmtu, NULL,
+				    so->so_fibnum);
 				if (sro.ro_rt)
 					RTFREE(sro.ro_rt);
 				if (error)

Modified: projects/multi-fibv6/head/sys/netinet6/ip6_var.h
==============================================================================
--- projects/multi-fibv6/head/sys/netinet6/ip6_var.h	Fri Feb  3 12:39:04 2012	(r230941)
+++ projects/multi-fibv6/head/sys/netinet6/ip6_var.h	Fri Feb  3 13:08:44 2012	(r230942)
@@ -445,6 +445,9 @@ int	in6_selectsrc(struct sockaddr_in6 *,
 int in6_selectroute __P((struct sockaddr_in6 *, struct ip6_pktopts *,
 	struct ip6_moptions *, struct route_in6 *, struct ifnet **,
 	struct rtentry **));
+int	in6_selectroute_fib(struct sockaddr_in6 *, struct ip6_pktopts *,
+	    struct ip6_moptions *, struct route_in6 *, struct ifnet **,
+	    struct rtentry **, int);
 u_int32_t ip6_randomid __P((void));
 u_int32_t ip6_randomflowlabel __P((void));
 #endif /* _KERNEL */

Modified: projects/multi-fibv6/head/sys/netinet6/nd6.c
==============================================================================
--- projects/multi-fibv6/head/sys/netinet6/nd6.c	Fri Feb  3 12:39:04 2012	(r230941)
+++ projects/multi-fibv6/head/sys/netinet6/nd6.c	Fri Feb  3 13:08:44 2012	(r230942)
@@ -900,7 +900,10 @@ nd6_is_new_addr_neighbor(struct sockaddr
 
 		if (!(pr->ndpr_stateflags & NDPRF_ONLINK)) {
 			struct rtentry *rt;
-			rt = rtalloc1((struct sockaddr *)&pr->ndpr_prefix, 0, 0);
+
+			/* Always use the default FIB here. */
+			rt = in6_rtalloc1((struct sockaddr *)&pr->ndpr_prefix,
+			    0, 0, RT_DEFAULT_FIB);
 			if (rt == NULL)
 				continue;
 			/*

Modified: projects/multi-fibv6/head/sys/netinet6/nd6_nbr.c
==============================================================================
--- projects/multi-fibv6/head/sys/netinet6/nd6_nbr.c	Fri Feb  3 12:39:04 2012	(r230941)
+++ projects/multi-fibv6/head/sys/netinet6/nd6_nbr.c	Fri Feb  3 13:08:44 2012	(r230942)
@@ -242,13 +242,16 @@ nd6_ns_input(struct mbuf *m, int off, in
 		tsin6.sin6_family = AF_INET6;
 		tsin6.sin6_addr = taddr6;
 
+		/* Always use the default FIB. */
 #ifdef RADIX_MPATH
 		bzero(&ro, sizeof(ro));
 		ro.ro_dst = tsin6;
-		rtalloc_mpath((struct route *)&ro, RTF_ANNOUNCE);
+		rtalloc_mpath_fib((struct route *)&ro, RTF_ANNOUNCE,
+		    RT_DEFAULT_FIB);
 		rt = ro.ro_rt;
 #else
-		rt = rtalloc1((struct sockaddr *)&tsin6, 0, 0);
+		rt = in6_rtalloc1((struct sockaddr *)&tsin6, 0, 0,
+		    RT_DEFAULT_FIB);
 #endif
 		need_proxy = (rt && (rt->rt_flags & RTF_ANNOUNCE) != 0 &&
 		    rt->rt_gateway->sa_family == AF_LINK);

Modified: projects/multi-fibv6/head/sys/netinet6/nd6_rtr.c
==============================================================================
--- projects/multi-fibv6/head/sys/netinet6/nd6_rtr.c	Fri Feb  3 12:39:04 2012	(r230941)
+++ projects/multi-fibv6/head/sys/netinet6/nd6_rtr.c	Fri Feb  3 13:08:44 2012	(r230942)
@@ -463,7 +463,7 @@ nd6_rtmsg(int cmd, struct rtentry *rt)
 	} else
 		ifa = NULL;
 
-	rt_missmsg(cmd, &info, rt->rt_flags, 0);
+	rt_missmsg_fib(cmd, &info, rt->rt_flags, 0, rt->rt_fibnum);
 	if (ifa != NULL)
 		ifa_free(ifa);
 }
@@ -486,9 +486,9 @@ defrouter_addreq(struct nd_defrouter *ne
 	gate.sin6_addr = new->rtaddr;
 
 	s = splnet();
-	error = rtrequest(RTM_ADD, (struct sockaddr *)&def,
+	error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&def,
 	    (struct sockaddr *)&gate, (struct sockaddr *)&mask,
-	    RTF_GATEWAY, &newrt);
+	    RTF_GATEWAY, &newrt, RT_DEFAULT_FIB);
 	if (newrt) {
 		nd6_rtmsg(RTM_ADD, newrt); /* tell user process */
 		RTFREE(newrt);
@@ -532,9 +532,9 @@ defrouter_delreq(struct nd_defrouter *dr
 	def.sin6_family = gate.sin6_family = AF_INET6;
 	gate.sin6_addr = dr->rtaddr;
 
-	rtrequest(RTM_DELETE, (struct sockaddr *)&def,
+	in6_rtrequest(RTM_DELETE, (struct sockaddr *)&def,
 	    (struct sockaddr *)&gate,
-	    (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt);
+	    (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt, RT_DEFAULT_FIB);
 	if (oldrt) {
 		nd6_rtmsg(RTM_DELETE, oldrt);
 		RTFREE(oldrt);
@@ -1541,18 +1541,91 @@ pfxlist_onlink_check()
 }
 
 static int
+nd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa)
+{
+	static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
+	struct radix_node_head *rnh;
+	struct rtentry *rt;
+	struct sockaddr_in6 mask6;
+	u_long rtflags;
+	int error, a_failure, fibnum;
+
+	/*
+	 * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs.
+	 * ifa->ifa_rtrequest = nd6_rtrequest;
+	 */
+	bzero(&mask6, sizeof(mask6));
+	mask6.sin6_len = sizeof(mask6);
+	mask6.sin6_addr = pr->ndpr_mask;
+	rtflags = (ifa->ifa_flags & ~IFA_RTSELF) | RTF_UP;
+
+	a_failure = 0;
+	for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
+
+		rt = NULL;
+		error = in6_rtrequest(RTM_ADD,
+		    (struct sockaddr *)&pr->ndpr_prefix, ifa->ifa_addr,
+		    (struct sockaddr *)&mask6, rtflags, &rt, fibnum);
+		if (error == 0) {
+			KASSERT(rt != NULL, ("%s: in6_rtrequest return no "
+			    "error(%d) but rt is NULL, pr=%p, ifa=%p", __func__,
+			    error, pr, ifa));
+
+			rnh = rt_tables_get_rnh(rt->rt_fibnum, AF_INET6);
+			/* XXX what if rhn == NULL? */
+			RADIX_NODE_HEAD_LOCK(rnh);
+			RT_LOCK(rt);
+			if (rt_setgate(rt, rt_key(rt),
+			    (struct sockaddr *)&null_sdl) == 0) {
+				struct sockaddr_dl *dl;
+
+				dl = (struct sockaddr_dl *)rt->rt_gateway;
+				dl->sdl_type = rt->rt_ifp->if_type;
+				dl->sdl_index = rt->rt_ifp->if_index;
+			}
+			RADIX_NODE_HEAD_UNLOCK(rnh);
+			nd6_rtmsg(RTM_ADD, rt);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



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