Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 15 Feb 2012 06:49:51 +0000 (UTC)
From:      "Bjoern A. Zeeb" <bz@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r231744 - in projects/multi-fibv6/8: contrib/netcat etc etc/rc.d share/man/man4 sys/contrib/pf/net sys/fs/nfsclient sys/kern sys/net sys/netinet sys/netinet/ipfw sys/netinet6 sys/netips...
Message-ID:  <201202150649.q1F6np39041797@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bz
Date: Wed Feb 15 06:49:50 2012
New Revision: 231744
URL: http://svn.freebsd.org/changeset/base/231744

Log:
  Initial backport of the multi-FIB IPv6 changes from HEAD.
  
  Sponsored by:	Cisco Systems, Inc.

Modified:
  projects/multi-fibv6/8/contrib/netcat/netcat.c
  projects/multi-fibv6/8/etc/network.subr
  projects/multi-fibv6/8/etc/rc.d/network_ipv6
  projects/multi-fibv6/8/share/man/man4/faith.4
  projects/multi-fibv6/8/sys/contrib/pf/net/pf.c
  projects/multi-fibv6/8/sys/contrib/pf/net/pf_ioctl.c
  projects/multi-fibv6/8/sys/fs/nfsclient/nfs_clport.c
  projects/multi-fibv6/8/sys/fs/nfsclient/nfs_clvfsops.c
  projects/multi-fibv6/8/sys/kern/uipc_socket.c
  projects/multi-fibv6/8/sys/net/flowtable.c
  projects/multi-fibv6/8/sys/net/if_faith.c
  projects/multi-fibv6/8/sys/net/route.c
  projects/multi-fibv6/8/sys/net/route.h
  projects/multi-fibv6/8/sys/netinet/in.c
  projects/multi-fibv6/8/sys/netinet/ipfw/ip_fw2.c
  projects/multi-fibv6/8/sys/netinet/sctp_os_bsd.h
  projects/multi-fibv6/8/sys/netinet/tcp_subr.c
  projects/multi-fibv6/8/sys/netinet6/icmp6.c
  projects/multi-fibv6/8/sys/netinet6/in6.c
  projects/multi-fibv6/8/sys/netinet6/in6_gif.c
  projects/multi-fibv6/8/sys/netinet6/in6_ifattach.c
  projects/multi-fibv6/8/sys/netinet6/in6_mcast.c
  projects/multi-fibv6/8/sys/netinet6/in6_rmx.c
  projects/multi-fibv6/8/sys/netinet6/in6_src.c
  projects/multi-fibv6/8/sys/netinet6/in6_var.h
  projects/multi-fibv6/8/sys/netinet6/ip6_forward.c
  projects/multi-fibv6/8/sys/netinet6/ip6_input.c
  projects/multi-fibv6/8/sys/netinet6/ip6_output.c
  projects/multi-fibv6/8/sys/netinet6/ip6_var.h
  projects/multi-fibv6/8/sys/netinet6/nd6.c
  projects/multi-fibv6/8/sys/netinet6/nd6_nbr.c
  projects/multi-fibv6/8/sys/netinet6/nd6_rtr.c
  projects/multi-fibv6/8/sys/netinet6/raw_ip6.c
  projects/multi-fibv6/8/sys/netipsec/ipsec_output.c
  projects/multi-fibv6/8/sys/nfs/bootp_subr.c
  projects/multi-fibv6/8/sys/nfsclient/nfs_vfsops.c
  projects/multi-fibv6/8/usr.bin/netstat/route.c

Modified: projects/multi-fibv6/8/contrib/netcat/netcat.c
==============================================================================
--- projects/multi-fibv6/8/contrib/netcat/netcat.c	Wed Feb 15 06:45:49 2012	(r231743)
+++ projects/multi-fibv6/8/contrib/netcat/netcat.c	Wed Feb 15 06:49:50 2012	(r231744)
@@ -605,8 +605,10 @@ remote_connect(const char *host, const c
 #endif
 
 		if (rtableid) {
-			if (setfib(rtableid) == -1)
-				err(1, "setfib");
+			if (setsockopt(s, SOL_SOCKET, SO_SETFIB, &rtableid,
+			    sizeof(rtableid)) == -1)
+				err(1, "setsockopt(.., SO_SETFIB, %u, ..)",
+				    rtableid);
 		}
 
 		/* Bind to a local port or source address if specified. */
@@ -678,8 +680,11 @@ local_listen(char *host, char *port, str
 			continue;
 
 		if (rtableid) {
-			if (setfib(rtableid) == -1)
-				err(1, "setfib");
+			ret = setsockopt(s, SOL_SOCKET, SO_SETFIB, &rtableid,
+			    sizeof(rtableid));
+			if (ret == -1)
+				err(1, "setsockopt(.., SO_SETFIB, %u, ..)",
+				    rtableid);
 		}
 
 		ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x));

Modified: projects/multi-fibv6/8/etc/network.subr
==============================================================================
--- projects/multi-fibv6/8/etc/network.subr	Wed Feb 15 06:45:49 2012	(r231743)
+++ projects/multi-fibv6/8/etc/network.subr	Wed Feb 15 06:49:50 2012	(r231744)
@@ -1125,16 +1125,33 @@ network6_default_interface_setup()
 		;;
 	esac
 
+	# Get the number of FIBs supported.
+	fibs=`sysctl -n net.fibs`
+	: ${fibs:=1}
+
 	# Disallow unicast packets without outgoing scope identifiers,
 	# or route such packets to a "default" interface, if it is specified.
 	route add -inet6 fe80:: -prefixlen 10 ::1 -reject
 	case ${ipv6_default_interface} in
 	[Nn][Oo] | '')
-		route add -inet6 ff02:: -prefixlen 16 ::1 -reject
+		i=0
+		while test ${i} -lt ${fibs}; do
+			setfib -F ${i} \
+			    route add -inet6 ff02:: -prefixlen 16 ::1 -reject
+			i=$((i + 1))
+		done
 		;;
 	*)
 		laddr=`network6_getladdr ${ipv6_default_interface}`
+		# Only add the laddr route to the default FIB and a reject
+		# route to all others.
 		route add -inet6 ff02:: ${laddr} -prefixlen 16 -interface
+		i=1
+		while test ${i} -lt ${fibs}; do
+			setfib -F ${i} \
+			    route add -inet6 ff02:: -prefixlen 16 ::1 -reject
+			i=$((i + 1))
+		done
 
 		# Disable installing the default interface with the
 		# case net.inet6.ip6.forwarding=0 and

Modified: projects/multi-fibv6/8/etc/rc.d/network_ipv6
==============================================================================
--- projects/multi-fibv6/8/etc/rc.d/network_ipv6	Wed Feb 15 06:45:49 2012	(r231743)
+++ projects/multi-fibv6/8/etc/rc.d/network_ipv6	Wed Feb 15 06:49:50 2012	(r231744)
@@ -41,9 +41,21 @@ start_cmd="network_ipv6_start"
 
 network_ipv6_start()
 {
-	# disallow "internal" addresses to appear on the wire
-	route add -inet6 ::ffff:0.0.0.0 -prefixlen 96 ::1 -reject
-	route add -inet6 ::0.0.0.0 -prefixlen 96 ::1 -reject
+	local fibs i
+
+	# Get the number of FIBs supported.
+	fibs=`sysctl -n net.fibs`
+	: ${fibs:=1}
+
+  	# disallow "internal" addresses to appear on the wire
+	i=0
+	while test ${i} -lt ${fibs}; do
+		setfib -F ${i} route add -inet6 \
+		   ::ffff:0.0.0.0 -prefixlen 96 ::1 -reject
+		setfib -F ${i} route add -inet6 \
+		  ::0.0.0.0 -prefixlen 96 ::1 -reject
+		i=$((i + 1))
+	done
 
 	case ${ipv6_network_interfaces} in
 	[Aa][Uu][Tt][Oo])

Modified: projects/multi-fibv6/8/share/man/man4/faith.4
==============================================================================
--- projects/multi-fibv6/8/share/man/man4/faith.4	Wed Feb 15 06:45:49 2012	(r231743)
+++ projects/multi-fibv6/8/share/man/man4/faith.4	Wed Feb 15 06:49:50 2012	(r231744)
@@ -29,7 +29,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd April 10, 1999
+.Dd January 23, 2012
 .Dt FAITH 4
 .Os
 .Sh NAME
@@ -58,7 +58,7 @@ variable in
 .Xr rc.conf 5 .
 .Pp
 Special action will be taken when IPv6 TCP traffic is seen on a router,
-and the routing table suggests to route it to the
+and the default routing table suggests to route it to the
 .Nm
 interface.
 In this case, the packet will be accepted by the router,

Modified: projects/multi-fibv6/8/sys/contrib/pf/net/pf.c
==============================================================================
--- projects/multi-fibv6/8/sys/contrib/pf/net/pf.c	Wed Feb 15 06:45:49 2012	(r231743)
+++ projects/multi-fibv6/8/sys/contrib/pf/net/pf.c	Wed Feb 15 06:49:50 2012	(r231744)
@@ -3197,11 +3197,7 @@ pf_calc_mss(struct pf_addr *addr, sa_fam
 		dst->sin_len = sizeof(*dst);
 		dst->sin_addr = addr->v4;
 #ifdef __FreeBSD__
-#ifdef RTF_PRCLONING
-		rtalloc_ign(&ro, (RTF_CLONING | RTF_PRCLONING));
-#else /* !RTF_PRCLONING */
-		in_rtalloc_ign(&ro, 0, 0);
-#endif
+		in_rtalloc_ign(&ro, 0, RT_DEFAULT_FIB);
 #else /* ! __FreeBSD__ */
 		rtalloc_noclone(&ro, NO_CLONING);
 #endif
@@ -3217,12 +3213,7 @@ pf_calc_mss(struct pf_addr *addr, sa_fam
 		dst6->sin6_len = sizeof(*dst6);
 		dst6->sin6_addr = addr->v6;
 #ifdef __FreeBSD__
-#ifdef RTF_PRCLONING
-		rtalloc_ign((struct route *)&ro6,
-		    (RTF_CLONING | RTF_PRCLONING));
-#else /* !RTF_PRCLONING */
-		rtalloc_ign((struct route *)&ro6, 0);
-#endif
+		in6_rtalloc_ign(&ro6, 0, RT_DEFAULT_FIB);
 #else /* ! __FreeBSD__ */
 		rtalloc_noclone((struct route *)&ro6, NO_CLONING);
 #endif
@@ -6134,9 +6125,11 @@ pf_routable(struct pf_addr *addr, sa_fam
 #ifdef __FreeBSD__
 /* XXX MRT not always INET */ /* stick with table 0 though */
 	if (af == AF_INET)
-		in_rtalloc_ign((struct route *)&ro, 0, 0);
+		in_rtalloc_ign((struct route *)&ro, 0, RT_DEFAULT_FIB);
+#ifdef INET6
 	else
-		rtalloc_ign((struct route *)&ro, 0);
+		in6_rtalloc_ign(&ro, 0, RT_DEFAULT_FIB);
+#endif
 #else /* ! __FreeBSD__ */
 	rtalloc_noclone((struct route *)&ro, NO_CLONING);
 #endif
@@ -6212,14 +6205,12 @@ pf_rtlabel_match(struct pf_addr *addr, s
 	}
 
 #ifdef __FreeBSD__
-# ifdef RTF_PRCLONING
-	rtalloc_ign((struct route *)&ro, (RTF_CLONING|RTF_PRCLONING));
-# else /* !RTF_PRCLONING */
 	if (af == AF_INET)
-		in_rtalloc_ign((struct route *)&ro, 0, 0);
+		in_rtalloc_ign((struct route *)&ro, 0, RT_DEFAULT_FIB);
+#ifdef INET6
 	else
-		rtalloc_ign((struct route *)&ro, 0);
-# endif
+		in6_rtalloc_ign(&ro, 0, RT_DEFAULT_FIB);
+#endif
 #else /* ! __FreeBSD__ */
 	rtalloc_noclone((struct route *)&ro, NO_CLONING);
 #endif

Modified: projects/multi-fibv6/8/sys/contrib/pf/net/pf_ioctl.c
==============================================================================
--- projects/multi-fibv6/8/sys/contrib/pf/net/pf_ioctl.c	Wed Feb 15 06:45:49 2012	(r231743)
+++ projects/multi-fibv6/8/sys/contrib/pf/net/pf_ioctl.c	Wed Feb 15 06:49:50 2012	(r231744)
@@ -1531,7 +1531,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t a
 		}
 
 #ifdef __FreeBSD__ /* ROUTING */
-		if (rule->rtableid > 0 && rule->rtableid > rt_numfibs)
+		if (rule->rtableid > 0 && rule->rtableid >= rt_numfibs)
 #else
 		if (rule->rtableid > 0 && !rtable_exists(rule->rtableid))
 #endif
@@ -1794,7 +1794,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t a
 
 			if (newrule->rtableid > 0 &&
 #ifdef __FreeBSD__ /* ROUTING */
-			    newrule->rtableid > rt_numfibs)
+			    newrule->rtableid >= rt_numfibs)
 #else
 			    !rtable_exists(newrule->rtableid))
 #endif

Modified: projects/multi-fibv6/8/sys/fs/nfsclient/nfs_clport.c
==============================================================================
--- projects/multi-fibv6/8/sys/fs/nfsclient/nfs_clport.c	Wed Feb 15 06:45:49 2012	(r231743)
+++ projects/multi-fibv6/8/sys/fs/nfsclient/nfs_clport.c	Wed Feb 15 06:49:50 2012	(r231744)
@@ -946,7 +946,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 &&
@@ -971,7 +972,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/8/sys/fs/nfsclient/nfs_clvfsops.c
==============================================================================
--- projects/multi-fibv6/8/sys/fs/nfsclient/nfs_clvfsops.c	Wed Feb 15 06:45:49 2012	(r231743)
+++ projects/multi-fibv6/8/sys/fs/nfsclient/nfs_clvfsops.c	Wed Feb 15 06:49:50 2012	(r231744)
@@ -455,10 +455,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/8/sys/kern/uipc_socket.c
==============================================================================
--- projects/multi-fibv6/8/sys/kern/uipc_socket.c	Wed Feb 15 06:45:49 2012	(r231743)
+++ projects/multi-fibv6/8/sys/kern/uipc_socket.c	Wed Feb 15 06:49:50 2012	(r231744)
@@ -383,6 +383,7 @@ socreate(int dom, struct socket **aso, i
 	so->so_type = type;
 	so->so_cred = crhold(cred);
 	if ((prp->pr_domain->dom_family == PF_INET) ||
+	    (prp->pr_domain->dom_family == PF_INET6) ||
 	    (prp->pr_domain->dom_family == PF_ROUTE))
 		so->so_fibnum = td->td_proc->p_fibnum;
 	else
@@ -2492,12 +2493,13 @@ sosetopt(struct socket *so, struct socko
 		case SO_SETFIB:
 			error = sooptcopyin(sopt, &optval, sizeof optval,
 					    sizeof optval);
-			if (optval < 0 || optval > rt_numfibs) {
+			if (optval < 0 || optval >= rt_numfibs) {
 				error = EINVAL;
 				goto bad;
 			}
 			if (so->so_proto != NULL &&
 			   ((so->so_proto->pr_domain->dom_family == PF_INET) ||
+			   (so->so_proto->pr_domain->dom_family == PF_INET6) ||
 			   (so->so_proto->pr_domain->dom_family == PF_ROUTE))) {
 				so->so_fibnum = optval;
 				/* Note: ignore error */

Modified: projects/multi-fibv6/8/sys/net/flowtable.c
==============================================================================
--- projects/multi-fibv6/8/sys/net/flowtable.c	Wed Feb 15 06:45:49 2012	(r231743)
+++ projects/multi-fibv6/8/sys/net/flowtable.c	Wed Feb 15 06:49:50 2012	(r231744)
@@ -373,7 +373,7 @@ SYSCTL_VNET_PROC(_net_inet_flowtable, OI
 
 #ifndef RADIX_MPATH
 static void
-in_rtalloc_ign_wrapper(struct route *ro, uint32_t hash, u_int fibnum)
+rtalloc_ign_wrapper(struct route *ro, uint32_t hash, u_int fibnum)
 {
 
 	rtalloc_ign_fib(ro, 0, fibnum);
@@ -1313,7 +1313,7 @@ flowtable_alloc(char *name, int nentry, 
 #ifdef RADIX_MPATH
 	ft->ft_rtalloc = rtalloc_mpath_fib;
 #else
-	ft->ft_rtalloc = in_rtalloc_ign_wrapper;
+	ft->ft_rtalloc = rtalloc_ign_wrapper;
 #endif
 	if (flags & FL_PCPU) {
 		ft->ft_lock = flowtable_pcpu_lock;

Modified: projects/multi-fibv6/8/sys/net/if_faith.c
==============================================================================
--- projects/multi-fibv6/8/sys/net/if_faith.c	Wed Feb 15 06:45:49 2012	(r231743)
+++ projects/multi-fibv6/8/sys/net/if_faith.c	Wed Feb 15 06:49:50 2012	(r231744)
@@ -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/8/sys/net/route.c
==============================================================================
--- projects/multi-fibv6/8/sys/net/route.c	Wed Feb 15 06:45:49 2012	(r231743)
+++ projects/multi-fibv6/8/sys/net/route.c	Wed Feb 15 06:49:50 2012	(r231744)
@@ -35,6 +35,7 @@
  ***********************************************************************/
 
 #include "opt_inet.h"
+#include "opt_inet6.h"
 #include "opt_route.h"
 #include "opt_mrouting.h"
 #include "opt_mpath.h"
@@ -72,7 +73,11 @@ SYSCTL_INT(_net, OID_AUTO, fibs, CTLFLAG
 /*
  * Allow the boot code to allow LESS than RT_MAXFIBS to be used.
  * We can't do more because storage is statically allocated for now.
- * (for compatibility reasons.. this will change).
+ * (for compatibility reasons.. this will change. When this changes, code should
+ * be refactored to protocol independent parts and protocol dependent parts,
+ * probably hanging of domain(9) specific storage to not need the full
+ * fib * af RNH allocation etc. but allow tuning the number of tables per
+ * address family).
  */
 TUNABLE_INT("net.fibs", &rt_numfibs);
 
@@ -82,6 +87,9 @@ TUNABLE_INT("net.fibs", &rt_numfibs);
  * changes for the FIB of the caller when adding a new set of addresses
  * to an interface.  XXX this is a shotgun aproach to a problem that needs
  * a more fine grained solution.. that will come.
+ * XXX also has the problems getting the FIB from curthread which will not
+ * always work given the fib can be overridden and prefixes can be added
+ * from the network stack context.
  */
 u_int rt_add_addr_allfibs = 1;
 SYSCTL_INT(_net, OID_AUTO, add_addr_allfibs, CTLFLAG_RW,
@@ -196,27 +204,23 @@ vnet_route_init(const void *unused __unu
 	V_rtzone = uma_zcreate("rtentry", sizeof(struct rtentry), NULL, NULL,
 	    NULL, NULL, UMA_ALIGN_PTR, 0);
 	for (dom = domains; dom; dom = dom->dom_next) {
-		if (dom->dom_rtattach)  {
-			for  (table = 0; table < rt_numfibs; table++) {
-				if ( (fam = dom->dom_family) == AF_INET ||
-				    table == 0) {
- 			        	/* for now only AF_INET has > 1 table */
-					/* XXX MRT 
-					 * rtattach will be also called
-					 * from vfs_export.c but the
-					 * offset will be 0
-					 * (only for AF_INET and AF_INET6
-					 * which don't need it anyhow)
-					 */
-					rnh = rt_tables_get_rnh_ptr(table, fam);
-					if (rnh == NULL)
-						panic("%s: rnh NULL", __func__);
-					dom->dom_rtattach((void **)rnh,
-				    	    dom->dom_rtoffset);
-				} else {
-					break;
-				}
-			}
+		if (dom->dom_rtattach == NULL)
+			continue;
+
+		for  (table = 0; table < rt_numfibs; table++) {
+			fam = dom->dom_family;
+			if (table != 0 && fam != AF_INET6 && fam != AF_INET)
+				break;
+
+			/*
+			 * XXX MRT rtattach will be also called from
+			 * vfs_export.c but the offset will be 0 (only for
+			 * AF_INET and AF_INET6 which don't need it anyhow).
+			 */
+			rnh = rt_tables_get_rnh_ptr(table, fam);
+			if (rnh == NULL)
+				panic("%s: rnh NULL", __func__);
+			dom->dom_rtattach((void **)rnh, dom->dom_rtoffset);
 		}
 	}
 }
@@ -233,20 +237,19 @@ vnet_route_uninit(const void *unused __u
 	struct radix_node_head **rnh;
 
 	for (dom = domains; dom; dom = dom->dom_next) {
-		if (dom->dom_rtdetach) {
-			for (table = 0; table < rt_numfibs; table++) {
-				if ( (fam = dom->dom_family) == AF_INET ||
-				    table == 0) {
-					/* For now only AF_INET has > 1 tbl. */
-					rnh = rt_tables_get_rnh_ptr(table, fam);
-					if (rnh == NULL)
-						panic("%s: rnh NULL", __func__);
-					dom->dom_rtdetach((void **)rnh,
-					    dom->dom_rtoffset);
-				} else {
-					break;
-				}
-			}
+		if (dom->dom_rtdetach == NULL)
+			continue;
+
+		for (table = 0; table < rt_numfibs; table++) {
+			fam = dom->dom_family;
+
+			if (table != 0 && fam != AF_INET6 && fam != AF_INET)
+				break;
+
+			rnh = rt_tables_get_rnh_ptr(table, fam);
+			if (rnh == NULL)
+				panic("%s: rnh NULL", __func__);
+			dom->dom_rtdetach((void **)rnh, dom->dom_rtoffset);
 		}
 	}
 }
@@ -274,7 +277,8 @@ setfib(struct thread *td, struct setfib_
 void
 rtalloc(struct route *ro)
 {
-	rtalloc_ign_fib(ro, 0UL, 0);
+
+	rtalloc_ign_fib(ro, 0UL, RT_DEFAULT_FIB);
 }
 
 void
@@ -294,7 +298,7 @@ rtalloc_ign(struct route *ro, u_long ign
 		RTFREE(rt);
 		ro->ro_rt = NULL;
 	}
-	ro->ro_rt = rtalloc1_fib(&ro->ro_dst, 1, ignore, 0);
+	ro->ro_rt = rtalloc1_fib(&ro->ro_dst, 1, ignore, RT_DEFAULT_FIB);
 	if (ro->ro_rt)
 		RT_UNLOCK(ro->ro_rt);
 }
@@ -324,7 +328,8 @@ rtalloc_ign_fib(struct route *ro, u_long
 struct rtentry *
 rtalloc1(struct sockaddr *dst, int report, u_long ignflags)
 {
-	return (rtalloc1_fib(dst, report, ignflags, 0));
+
+	return (rtalloc1_fib(dst, report, ignflags, RT_DEFAULT_FIB));
 }
 
 struct rtentry *
@@ -339,8 +344,15 @@ rtalloc1_fib(struct sockaddr *dst, int r
 	int needlock;
 
 	KASSERT((fibnum < rt_numfibs), ("rtalloc1_fib: bad fibnum"));
-	if (dst->sa_family != AF_INET)	/* Only INET supports > 1 fib now */
-		fibnum = 0;
+	switch (dst->sa_family) {
+	case AF_INET6:
+	case AF_INET:
+		/* We support multiple FIBs. */
+		break;
+	default:
+		fibnum = RT_DEFAULT_FIB;
+		break;
+	}
 	rnh = rt_tables_get_rnh(fibnum, dst->sa_family);
 	newrt = NULL;
 	if (rnh == NULL)
@@ -486,7 +498,8 @@ rtredirect(struct sockaddr *dst,
 	int flags,
 	struct sockaddr *src)
 {
-	rtredirect_fib(dst, gateway, netmask, flags, src, 0);
+
+	rtredirect_fib(dst, gateway, netmask, flags, src, RT_DEFAULT_FIB);
 }
 
 void
@@ -617,7 +630,8 @@ out:
 int
 rtioctl(u_long req, caddr_t data)
 {
-	return (rtioctl_fib(req, data, 0));
+
+	return (rtioctl_fib(req, data, RT_DEFAULT_FIB));
 }
 
 /*
@@ -647,7 +661,8 @@ rtioctl_fib(u_long req, caddr_t data, u_
 struct ifaddr *
 ifa_ifwithroute(int flags, struct sockaddr *dst, struct sockaddr *gateway)
 {
-	return (ifa_ifwithroute_fib(flags, dst, gateway, 0));
+
+	return (ifa_ifwithroute_fib(flags, dst, gateway, RT_DEFAULT_FIB));
 }
 
 struct ifaddr *
@@ -732,7 +747,9 @@ rtrequest(int req,
 	int flags,
 	struct rtentry **ret_nrt)
 {
-	return (rtrequest_fib(req, dst, gateway, netmask, flags, ret_nrt, 0));
+
+	return (rtrequest_fib(req, dst, gateway, netmask, flags, ret_nrt,
+	    RT_DEFAULT_FIB));
 }
 
 int
@@ -771,7 +788,8 @@ rtrequest_fib(int req,
 int
 rt_getifa(struct rt_addrinfo *info)
 {
-	return (rt_getifa_fib(info, 0));
+
+	return (rt_getifa_fib(info, RT_DEFAULT_FIB));
 }
 
 /*
@@ -1029,8 +1047,16 @@ rtrequest1_fib(int req, struct rt_addrin
 #define senderr(x) { error = x ; goto bad; }
 
 	KASSERT((fibnum < rt_numfibs), ("rtrequest1_fib: bad fibnum"));
-	if (dst->sa_family != AF_INET)	/* Only INET supports > 1 fib now */
-		fibnum = 0;
+	switch (dst->sa_family) {
+	case AF_INET6:
+	case AF_INET:
+		/* We support multiple FIBs. */
+		break;
+	default:
+		fibnum = RT_DEFAULT_FIB;
+		break;
+	}
+
 	/*
 	 * Find the correct routing tree to use for this Address Family
 	 */
@@ -1136,8 +1162,7 @@ rtrequest1_fib(int req, struct rt_addrin
 		rt->rt_flags = RTF_UP | flags;
 		rt->rt_fibnum = fibnum;
 		/*
-		 * Add the gateway. Possibly re-malloc-ing the storage for it
-		 * 
+		 * Add the gateway. Possibly re-malloc-ing the storage for it.
 		 */
 		RT_LOCK(rt);
 		if ((error = rt_setgate(rt, dst, gateway)) != 0) {
@@ -1186,12 +1211,17 @@ rtrequest1_fib(int req, struct rt_addrin
 
 #ifdef FLOWTABLE
 		rt0 = NULL;
-		/* XXX
-		 * "flow-table" only support IPv4 at the moment.
-		 * XXX-BZ as of r205066 it would support IPv6.
-		 */
+		/* "flow-table" only supports IPv6 and IPv4 at the moment. */
+		switch (dst->sa_family) {
+#ifdef notyet
+#ifdef INET6
+		case AF_INET6:
+#endif
+#endif
 #ifdef INET
-		if (dst->sa_family == AF_INET) {
+		case AF_INET:
+#endif
+#if defined(INET6) || defined(INET)
 			rn = rnh->rnh_matchaddr(dst, rnh);
 			if (rn && ((rn->rn_flags & RNF_ROOT) == 0)) {
 				struct sockaddr *mask;
@@ -1230,9 +1260,9 @@ rtrequest1_fib(int req, struct rt_addrin
 					}
 				}
 			}
+#endif/* INET6 || INET */
 		}
-#endif
-#endif
+#endif /* FLOWTABLE */
 
 		/* XXX mtu manipulation will be done in rnh_addaddr -- itojun */
 		rn = rnh->rnh_addaddr(ndst, netmask, rnh, rt->rt_nodes);
@@ -1254,9 +1284,20 @@ rtrequest1_fib(int req, struct rt_addrin
 		} 
 #ifdef FLOWTABLE
 		else if (rt0 != NULL) {
+			switch (dst->sa_family) {
+#ifdef notyet
+#ifdef INET6
+			case AF_INET6:
+				flowtable_route_flush(V_ip6_ft, rt0);
+				break;
+#endif
+#endif
 #ifdef INET
-			flowtable_route_flush(V_ip_ft, rt0);
+			case AF_INET:
+				flowtable_route_flush(V_ip_ft, rt0);
+				break;
 #endif
+			}
 			RTFREE(rt0);
 		}
 #endif
@@ -1388,8 +1429,17 @@ rtinit1(struct ifaddr *ifa, int cmd, int
 		dst = ifa->ifa_addr;
 		netmask = ifa->ifa_netmask;
 	}
-	if ( dst->sa_family != AF_INET)
-		fibnum = 0;
+	if (dst->sa_len == 0)
+		return(EINVAL);
+	switch (dst->sa_family) {
+	case AF_INET6:
+	case AF_INET:
+		/* We support multiple FIBs. */
+		break;
+	default:
+		fibnum = RT_DEFAULT_FIB;
+		break;
+	}
 	if (fibnum == -1) {
 		if (rt_add_addr_allfibs == 0 && cmd == (int)RTM_ADD) {
 			startfib = endfib = curthread->td_proc->p_fibnum;
@@ -1402,8 +1452,6 @@ rtinit1(struct ifaddr *ifa, int cmd, int
 		startfib = fibnum;
 		endfib = fibnum;
 	}
-	if (dst->sa_len == 0)
-		return(EINVAL);
 
 	/*
 	 * If it's a delete, check that if it exists,
@@ -1427,9 +1475,7 @@ rtinit1(struct ifaddr *ifa, int cmd, int
 	 * Now go through all the requested tables (fibs) and do the
 	 * requested action. Realistically, this will either be fib 0
 	 * for protocols that don't do multiple tables or all the
-	 * tables for those that do. XXX For this version only AF_INET.
-	 * When that changes code should be refactored to protocol
-	 * independent parts and protocol dependent parts.
+	 * tables for those that do.
 	 */
 	for ( fibnum = startfib; fibnum <= endfib; fibnum++) {
 		if (cmd == RTM_DELETE) {
@@ -1569,12 +1615,14 @@ rtinit1(struct ifaddr *ifa, int cmd, int
 	return (error);
 }
 
+#ifndef BURN_BRIDGES
 /* special one for inet internal use. may not use. */
 int
 rtinit_fib(struct ifaddr *ifa, int cmd, int flags)
 {
 	return (rtinit1(ifa, cmd, flags, -1));
 }
+#endif
 
 /*
  * Set up a routing table entry, normally
@@ -1584,7 +1632,7 @@ int
 rtinit(struct ifaddr *ifa, int cmd, int flags)
 {
 	struct sockaddr *dst;
-	int fib = 0;
+	int fib = RT_DEFAULT_FIB;
 
 	if (flags & RTF_HOST) {
 		dst = ifa->ifa_dstaddr;
@@ -1592,7 +1640,12 @@ rtinit(struct ifaddr *ifa, int cmd, int 
 		dst = ifa->ifa_addr;
 	}
 
-	if (dst->sa_family == AF_INET)
+	switch (dst->sa_family) {
+	case AF_INET6:
+	case AF_INET:
+		/* We do support multiple FIBs. */
 		fib = -1;
+		break;
+	}
 	return (rtinit1(ifa, cmd, flags, fib));
 }

Modified: projects/multi-fibv6/8/sys/net/route.h
==============================================================================
--- projects/multi-fibv6/8/sys/net/route.h	Wed Feb 15 06:45:49 2012	(r231743)
+++ projects/multi-fibv6/8/sys/net/route.h	Wed Feb 15 06:49:50 2012	(r231744)
@@ -107,6 +107,7 @@ struct rt_metrics {
  #endif
 #endif
 
+#define	RT_DEFAULT_FIB	0	/* Explicitly mark fib=0 restricted cases */
 extern u_int rt_numfibs;	/* number fo usable routing tables */
 /*
  * XXX kernel function pointer `rt_output' is visible to applications.
@@ -401,8 +402,10 @@ void	 rtredirect(struct sockaddr *, stru
 int	 rtrequest(int, struct sockaddr *,
 	    struct sockaddr *, struct sockaddr *, int, struct rtentry **);
 
+#ifndef BURN_BRIDGES
 /* defaults to "all" FIBs */
 int	 rtinit_fib(struct ifaddr *, int, int);
+#endif
 
 /* XXX MRT NEW VERSIONS THAT USE FIBs
  * For now the protocol indepedent versions are the same as the AF_INET ones

Modified: projects/multi-fibv6/8/sys/netinet/in.c
==============================================================================
--- projects/multi-fibv6/8/sys/netinet/in.c	Wed Feb 15 06:45:49 2012	(r231743)
+++ projects/multi-fibv6/8/sys/netinet/in.c	Wed Feb 15 06:49:50 2012	(r231744)
@@ -957,7 +957,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/8/sys/netinet/ipfw/ip_fw2.c
==============================================================================
--- projects/multi-fibv6/8/sys/netinet/ipfw/ip_fw2.c	Wed Feb 15 06:45:49 2012	(r231743)
+++ projects/multi-fibv6/8/sys/netinet/ipfw/ip_fw2.c	Wed Feb 15 06:49:50 2012	(r231744)
@@ -494,7 +494,7 @@ search_ip6_addr_net (struct in6_addr * i
 }
 
 static int
-verify_path6(struct in6_addr *src, struct ifnet *ifp)
+verify_path6(struct in6_addr *src, struct ifnet *ifp, u_int fib)
 {
 	struct route_in6 ro;
 	struct sockaddr_in6 *dst;
@@ -505,9 +505,8 @@ verify_path6(struct in6_addr *src, struc
 	dst->sin6_family = AF_INET6;
 	dst->sin6_len = sizeof(*dst);
 	dst->sin6_addr = *src;
-	/* XXX MRT 0 for ipv6 at this time */
-	rtalloc_ign((struct route *)&ro, 0);
 
+	in6_rtalloc_ign(&ro, 0, fib);
 	if (ro.ro_rt == NULL)
 		return 0;
 
@@ -1682,7 +1681,7 @@ do {								\
 #ifdef INET6
 				    is_ipv6 ?
 					verify_path6(&(args->f_id.src_ip6),
-					    m->m_pkthdr.rcvif) :
+					    m->m_pkthdr.rcvif, args->f_id.fib) :
 #endif
 				    verify_path(src_ip, m->m_pkthdr.rcvif,
 				        args->f_id.fib)));
@@ -1694,7 +1693,7 @@ do {								\
 #ifdef INET6
 				    is_ipv6 ?
 				        verify_path6(&(args->f_id.src_ip6),
-				            NULL) :
+				            NULL, args->f_id.fib) :
 #endif
 				    verify_path(src_ip, NULL, args->f_id.fib)));
 				break;
@@ -1712,7 +1711,8 @@ do {								\
 #ifdef INET6
 					    is_ipv6 ? verify_path6(
 					        &(args->f_id.src_ip6),
-					        m->m_pkthdr.rcvif) :
+					        m->m_pkthdr.rcvif,
+						args->f_id.fib) :
 #endif
 					    verify_path(src_ip,
 					    	m->m_pkthdr.rcvif,

Modified: projects/multi-fibv6/8/sys/netinet/sctp_os_bsd.h
==============================================================================
--- projects/multi-fibv6/8/sys/netinet/sctp_os_bsd.h	Wed Feb 15 06:45:49 2012	(r231743)
+++ projects/multi-fibv6/8/sys/netinet/sctp_os_bsd.h	Wed Feb 15 06:49:50 2012	(r231744)
@@ -424,6 +424,12 @@ typedef struct callout sctp_os_timer_t;
 typedef struct route sctp_route_t;
 typedef struct rtentry sctp_rtentry_t;
 
+/*
+ * XXX multi-FIB support was backed out in r179783 and it seems clear that the
+ * VRF support as currently in FreeBSD is not ready to support multi-FIB.
+ * It might be best to implement multi-FIB support for both v4 and v6 indepedent
+ * of VRFs and leave those to a real MPLS stack.
+ */
 #define SCTP_RTALLOC(ro, vrf_id) rtalloc_ign((struct route *)ro, 0UL)
 
 /* Future zero copy wakeup/send  function */

Modified: projects/multi-fibv6/8/sys/netinet/tcp_subr.c
==============================================================================
--- projects/multi-fibv6/8/sys/netinet/tcp_subr.c	Wed Feb 15 06:45:49 2012	(r231743)
+++ projects/multi-fibv6/8/sys/netinet/tcp_subr.c	Wed Feb 15 06:49:50 2012	(r231744)
@@ -1801,7 +1801,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/8/sys/netinet6/icmp6.c
==============================================================================
--- projects/multi-fibv6/8/sys/netinet6/icmp6.c	Wed Feb 15 06:45:49 2012	(r231743)
+++ projects/multi-fibv6/8/sys/netinet6/icmp6.c	Wed Feb 15 06:49:50 2012	(r231744)
@@ -359,7 +359,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) {
@@ -581,7 +581,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) {
@@ -1419,7 +1419,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) {
 			/*
@@ -2332,7 +2332,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) {
@@ -2421,6 +2421,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));
@@ -2431,9 +2432,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 */
     {
@@ -2517,6 +2520,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/8/sys/netinet6/in6.c
==============================================================================
--- projects/multi-fibv6/8/sys/netinet6/in6.c	Wed Feb 15 06:45:49 2012	(r231743)
+++ projects/multi-fibv6/8/sys/netinet6/in6.c	Wed Feb 15 06:49:50 2012	(r231744)
@@ -198,6 +198,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);
 	}
 
@@ -696,6 +701,169 @@ out:
 }
 
 /*
+ * Join necessary multicast groups.  Factored out from in6_update_ifa().
+ * This entire work should only be done once, for the default FIB.
+ */
+static int
+in6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra,
+    struct in6_ifaddr *ia, int flags, struct in6_multi **in6m_sol)
+{
+	char ip6buf[INET6_ADDRSTRLEN];
+	struct sockaddr_in6 mltaddr, mltmask;
+	struct in6_addr llsol;
+	struct in6_multi_mship *imm;
+	struct rtentry *rt;
+	int delay, error;
+
+	KASSERT(in6m_sol != NULL, ("%s: in6m_sol is NULL", __func__));
+
+	/* Join solicited multicast addr for new host id. */
+	bzero(&llsol, sizeof(struct in6_addr));
+	llsol.s6_addr32[0] = IPV6_ADDR_INT32_MLL;
+	llsol.s6_addr32[1] = 0;
+	llsol.s6_addr32[2] = htonl(1);
+	llsol.s6_addr32[3] = ifra->ifra_addr.sin6_addr.s6_addr32[3];
+	llsol.s6_addr8[12] = 0xff;
+	if ((error = in6_setscope(&llsol, ifp, NULL)) != 0) {
+		/* XXX: should not happen */
+		log(LOG_ERR, "%s: in6_setscope failed\n", __func__);
+		goto cleanup;
+	}
+	delay = 0;
+	if ((flags & IN6_IFAUPDATE_DADDELAY)) {
+		/*
+		 * We need a random delay for DAD on the address being
+		 * configured.  It also means delaying transmission of the
+		 * corresponding MLD report to avoid report collision.
+		 * [RFC 4861, Section 6.3.7]
+		 */
+		delay = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz);
+	}
+	imm = in6_joingroup(ifp, &llsol, &error, delay);
+	if (imm == NULL) {
+		nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
+		    "(errno=%d)\n", __func__, ip6_sprintf(ip6buf, &llsol),
+		    if_name(ifp), error));
+		goto cleanup;
+	}
+	LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
+	*in6m_sol = imm->i6mm_maddr;
+
+	bzero(&mltmask, sizeof(mltmask));
+	mltmask.sin6_len = sizeof(struct sockaddr_in6);
+	mltmask.sin6_family = AF_INET6;
+	mltmask.sin6_addr = in6mask32;
+#define	MLTMASK_LEN  4	/* mltmask's masklen (=32bit=4octet) */
+
+	/*
+	 * Join link-local all-nodes address.
+	 */
+	bzero(&mltaddr, sizeof(mltaddr));
+	mltaddr.sin6_len = sizeof(struct sockaddr_in6);
+	mltaddr.sin6_family = AF_INET6;
+	mltaddr.sin6_addr = in6addr_linklocal_allnodes;
+	if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
+		goto cleanup; /* XXX: should not fail */
+
+	/*
+	 * XXX: do we really need this automatic routes?  We should probably
+	 * reconsider this stuff.  Most applications actually do not need the
+	 * routes, since they usually specify the outgoing interface.
+	 */
+	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,
+		    &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
+		    MLTMASK_LEN)) {
+			RTFREE_LOCKED(rt);
+			rt = NULL;
+		}
+	}
+	if (rt == NULL) {
+		error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
+		    (struct sockaddr *)&ia->ia_addr,
+		    (struct sockaddr *)&mltmask, RTF_UP,
+		    (struct rtentry **)0, RT_DEFAULT_FIB);
+		if (error)
+			goto cleanup;
+	} else
+		RTFREE_LOCKED(rt);
+
+	imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
+	if (imm == NULL) {
+		nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
+		    "(errno=%d)\n", __func__, ip6_sprintf(ip6buf,
+		    &mltaddr.sin6_addr), if_name(ifp), error));
+		goto cleanup;
+	}
+	LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
+
+	/*
+	 * Join node information group address.
+	 */
+	delay = 0;
+	if ((flags & IN6_IFAUPDATE_DADDELAY)) {
+		/*
+		 * The spec does not say anything about delay for this group,
+		 * but the same logic should apply.
+		 */
+		delay = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz);
+	}
+	if (in6_nigroup(ifp, NULL, -1, &mltaddr.sin6_addr) == 0) {
+		/* XXX jinmei */
+		imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, delay);
+		if (imm == NULL)
+			nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
+			    "(errno=%d)\n", __func__, ip6_sprintf(ip6buf,
+			    &mltaddr.sin6_addr), if_name(ifp), error));
+			/* XXX not very fatal, go on... */
+		else
+			LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
+	}
+
+	/*
+	 * Join interface-local all-nodes address.
+	 * (ff01::1%ifN, and ff01::%ifN/32)
+	 */
+	mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
+	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 = 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,
+		    MLTMASK_LEN)) {
+			RTFREE_LOCKED(rt);
+			rt = NULL;
+		}
+	}
+	if (rt == NULL) {
+		error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
+		    (struct sockaddr *)&ia->ia_addr,
+		    (struct sockaddr *)&mltmask, RTF_UP,
+		    (struct rtentry **)0, RT_DEFAULT_FIB);

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



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