Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 5 Mar 2012 17:33:01 +0000 (UTC)
From:      "Bjoern A. Zeeb" <bz@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r232552 - in stable/8: contrib/netcat etc etc/rc.d share/man/man4 sys/contrib/pf/net sys/fs/nfsclient sys/i386/conf sys/kern sys/net sys/netinet sys/netinet/ipfw sys/netinet6 sys/netips...
Message-ID:  <201203051733.q25HX1CM096134@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bz
Date: Mon Mar  5 17:33:01 2012
New Revision: 232552
URL: http://svn.freebsd.org/changeset/base/232552

Log:
  MFC r231852,232127:
  
    Merge multi-FIB IPv6 support.
  
    Extend the so far IPv4-only support for multiple routing tables (FIBs)
    introduced in r178888 to IPv6 providing feature parity.
  
    This includes an extended rtalloc(9) KPI for IPv6, the necessary
    adjustments to the network stack, and user land support as in netstat.
  
  Sponsored by:	Cisco Systems, Inc.

Modified:
  stable/8/contrib/netcat/netcat.c
  stable/8/etc/network.subr
  stable/8/etc/rc.d/network_ipv6
  stable/8/etc/rc.d/routing
  stable/8/share/man/man4/faith.4
  stable/8/sys/contrib/pf/net/pf.c
  stable/8/sys/contrib/pf/net/pf_ioctl.c
  stable/8/sys/fs/nfsclient/nfs_clport.c
  stable/8/sys/fs/nfsclient/nfs_clvfsops.c
  stable/8/sys/kern/uipc_socket.c
  stable/8/sys/net/flowtable.c
  stable/8/sys/net/if_faith.c
  stable/8/sys/net/route.c
  stable/8/sys/net/route.h
  stable/8/sys/netinet/in.c
  stable/8/sys/netinet/ipfw/ip_fw2.c
  stable/8/sys/netinet/sctp_os_bsd.h
  stable/8/sys/netinet/tcp_subr.c
  stable/8/sys/netinet6/icmp6.c
  stable/8/sys/netinet6/in6.c
  stable/8/sys/netinet6/in6_gif.c
  stable/8/sys/netinet6/in6_ifattach.c
  stable/8/sys/netinet6/in6_mcast.c
  stable/8/sys/netinet6/in6_rmx.c
  stable/8/sys/netinet6/in6_src.c
  stable/8/sys/netinet6/in6_var.h
  stable/8/sys/netinet6/ip6_forward.c
  stable/8/sys/netinet6/ip6_input.c
  stable/8/sys/netinet6/ip6_output.c
  stable/8/sys/netinet6/ip6_var.h
  stable/8/sys/netinet6/nd6.c
  stable/8/sys/netinet6/nd6_nbr.c
  stable/8/sys/netinet6/nd6_rtr.c
  stable/8/sys/netinet6/raw_ip6.c
  stable/8/sys/netipsec/ipsec_output.c
  stable/8/sys/nfs/bootp_subr.c
  stable/8/sys/nfsclient/nfs_vfsops.c
  stable/8/usr.bin/netstat/route.c   (contents, props changed)
Directory Properties:
  stable/8/contrib/netcat/   (props changed)
  stable/8/etc/   (props changed)
  stable/8/share/man/man4/   (props changed)
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/boot/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/e1000/   (props changed)
  stable/8/sys/i386/conf/XENHVM   (props changed)
  stable/8/usr.bin/netstat/   (props changed)
  stable/8/usr.bin/netstat/Makefile   (props changed)
  stable/8/usr.bin/netstat/atalk.c   (props changed)
  stable/8/usr.bin/netstat/bpf.c   (props changed)
  stable/8/usr.bin/netstat/if.c   (props changed)
  stable/8/usr.bin/netstat/inet.c   (props changed)
  stable/8/usr.bin/netstat/inet6.c   (props changed)
  stable/8/usr.bin/netstat/ipsec.c   (props changed)
  stable/8/usr.bin/netstat/ipx.c   (props changed)
  stable/8/usr.bin/netstat/main.c   (props changed)
  stable/8/usr.bin/netstat/mbuf.c   (props changed)
  stable/8/usr.bin/netstat/mroute.c   (props changed)
  stable/8/usr.bin/netstat/mroute6.c   (props changed)
  stable/8/usr.bin/netstat/netgraph.c   (props changed)
  stable/8/usr.bin/netstat/netisr.c   (props changed)
  stable/8/usr.bin/netstat/netstat.1   (props changed)
  stable/8/usr.bin/netstat/netstat.h   (props changed)
  stable/8/usr.bin/netstat/pfkey.c   (props changed)
  stable/8/usr.bin/netstat/sctp.c   (props changed)
  stable/8/usr.bin/netstat/unix.c   (props changed)

Modified: stable/8/contrib/netcat/netcat.c
==============================================================================
--- stable/8/contrib/netcat/netcat.c	Mon Mar  5 17:09:16 2012	(r232551)
+++ stable/8/contrib/netcat/netcat.c	Mon Mar  5 17:33:01 2012	(r232552)
@@ -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: stable/8/etc/network.subr
==============================================================================
--- stable/8/etc/network.subr	Mon Mar  5 17:09:16 2012	(r232551)
+++ stable/8/etc/network.subr	Mon Mar  5 17:33:01 2012	(r232552)
@@ -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: stable/8/etc/rc.d/network_ipv6
==============================================================================
--- stable/8/etc/rc.d/network_ipv6	Mon Mar  5 17:09:16 2012	(r232551)
+++ stable/8/etc/rc.d/network_ipv6	Mon Mar  5 17:33:01 2012	(r232552)
@@ -41,6 +41,7 @@ start_cmd="network_ipv6_start"
 
 network_ipv6_start()
 {
+
 	case ${ipv6_network_interfaces} in
 	[Aa][Uu][Tt][Oo])
 		# Get a list of network interfaces

Modified: stable/8/etc/rc.d/routing
==============================================================================
--- stable/8/etc/rc.d/routing	Mon Mar  5 17:09:16 2012	(r232551)
+++ stable/8/etc/rc.d/routing	Mon Mar  5 17:33:01 2012	(r232552)
@@ -61,9 +61,21 @@ static_start()
 	# Disallow "internal" addresses to appear on the wire if inet6
 	# is enabled.
 	if afexists inet6; then
+		local fibs i
+
+		# Get the number of FIBs supported.
+		fibs=`sysctl -n net.fibs`
+		: ${fibs:=1}
+
 		# 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
+		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
 	fi
 }
 

Modified: stable/8/share/man/man4/faith.4
==============================================================================
--- stable/8/share/man/man4/faith.4	Mon Mar  5 17:09:16 2012	(r232551)
+++ stable/8/share/man/man4/faith.4	Mon Mar  5 17:33:01 2012	(r232552)
@@ -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: stable/8/sys/contrib/pf/net/pf.c
==============================================================================
--- stable/8/sys/contrib/pf/net/pf.c	Mon Mar  5 17:09:16 2012	(r232551)
+++ stable/8/sys/contrib/pf/net/pf.c	Mon Mar  5 17:33:01 2012	(r232552)
@@ -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: stable/8/sys/contrib/pf/net/pf_ioctl.c
==============================================================================
--- stable/8/sys/contrib/pf/net/pf_ioctl.c	Mon Mar  5 17:09:16 2012	(r232551)
+++ stable/8/sys/contrib/pf/net/pf_ioctl.c	Mon Mar  5 17:33:01 2012	(r232552)
@@ -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: stable/8/sys/fs/nfsclient/nfs_clport.c
==============================================================================
--- stable/8/sys/fs/nfsclient/nfs_clport.c	Mon Mar  5 17:09:16 2012	(r232551)
+++ stable/8/sys/fs/nfsclient/nfs_clport.c	Mon Mar  5 17:33:01 2012	(r232552)
@@ -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: stable/8/sys/fs/nfsclient/nfs_clvfsops.c
==============================================================================
--- stable/8/sys/fs/nfsclient/nfs_clvfsops.c	Mon Mar  5 17:09:16 2012	(r232551)
+++ stable/8/sys/fs/nfsclient/nfs_clvfsops.c	Mon Mar  5 17:33:01 2012	(r232552)
@@ -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: stable/8/sys/kern/uipc_socket.c
==============================================================================
--- stable/8/sys/kern/uipc_socket.c	Mon Mar  5 17:09:16 2012	(r232551)
+++ stable/8/sys/kern/uipc_socket.c	Mon Mar  5 17:33:01 2012	(r232552)
@@ -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
@@ -2498,6 +2499,7 @@ sosetopt(struct socket *so, struct socko
 			}
 			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: stable/8/sys/net/flowtable.c
==============================================================================
--- stable/8/sys/net/flowtable.c	Mon Mar  5 17:09:16 2012	(r232551)
+++ stable/8/sys/net/flowtable.c	Mon Mar  5 17:33:01 2012	(r232552)
@@ -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);
@@ -1315,7 +1315,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: stable/8/sys/net/if_faith.c
==============================================================================
--- stable/8/sys/net/if_faith.c	Mon Mar  5 17:09:16 2012	(r232551)
+++ stable/8/sys/net/if_faith.c	Mon Mar  5 17:33:01 2012	(r232552)
@@ -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: stable/8/sys/net/route.c
==============================================================================
--- stable/8/sys/net/route.c	Mon Mar  5 17:09:16 2012	(r232551)
+++ stable/8/sys/net/route.c	Mon Mar  5 17:33:01 2012	(r232552)
@@ -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: stable/8/sys/net/route.h
==============================================================================
--- stable/8/sys/net/route.h	Mon Mar  5 17:09:16 2012	(r232551)
+++ stable/8/sys/net/route.h	Mon Mar  5 17:33:01 2012	(r232552)
@@ -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: stable/8/sys/netinet/in.c
==============================================================================
--- stable/8/sys/netinet/in.c	Mon Mar  5 17:09:16 2012	(r232551)
+++ stable/8/sys/netinet/in.c	Mon Mar  5 17:33:01 2012	(r232552)
@@ -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: stable/8/sys/netinet/ipfw/ip_fw2.c
==============================================================================
--- stable/8/sys/netinet/ipfw/ip_fw2.c	Mon Mar  5 17:09:16 2012	(r232551)
+++ stable/8/sys/netinet/ipfw/ip_fw2.c	Mon Mar  5 17:33:01 2012	(r232552)
@@ -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: stable/8/sys/netinet/sctp_os_bsd.h
==============================================================================
--- stable/8/sys/netinet/sctp_os_bsd.h	Mon Mar  5 17:09:16 2012	(r232551)
+++ stable/8/sys/netinet/sctp_os_bsd.h	Mon Mar  5 17:33:01 2012	(r232552)
@@ -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: stable/8/sys/netinet/tcp_subr.c
==============================================================================
--- stable/8/sys/netinet/tcp_subr.c	Mon Mar  5 17:09:16 2012	(r232551)
+++ stable/8/sys/netinet/tcp_subr.c	Mon Mar  5 17:33:01 2012	(r232552)
@@ -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: stable/8/sys/netinet6/icmp6.c
==============================================================================
--- stable/8/sys/netinet6/icmp6.c	Mon Mar  5 17:09:16 2012	(r232551)
+++ stable/8/sys/netinet6/icmp6.c	Mon Mar  5 17:33:01 2012	(r232552)
@@ -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: stable/8/sys/netinet6/in6.c
==============================================================================
--- stable/8/sys/netinet6/in6.c	Mon Mar  5 17:09:16 2012	(r232551)
+++ stable/8/sys/netinet6/in6.c	Mon Mar  5 17:33:01 2012	(r232552)
@@ -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,

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



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