PSARC 2006/366 IP Instances
6289221 RFE: Need virtualized ip-stack for each local zone
6512601 panic in ipsec_in_tag - allocation failure
6514637 error message from dhcpagent: add_pkt_opt: option type 60 is missing required value
6364643 RFE: allow persistent setting of interface flags per zone
6307539 RFE: Invalid network address causes zone boot failure
5041214 Allow IPMP configuration with zones
5005887 RFE: zoneadmd should support plumbing an interface via DHCP
4991139 RFE: zones should provide a mechanism to configure a defaultrouter for a zone
6218378 zoneadmd doesn't set the netmask for non-loopback addresses hosted on lo0
4963280 zones: need to virtualize the IPv6 default address selection mechanism
4963285 zones: need support of stateless address autoconfiguration for IPv6
5048068 zones don't boot if one of its interfaces has failed
5057154 RFE: ability to change interface status from within a zone
4963287 zones should support the plumbing of the first (and only) logical interface
4978517 TCP privileged port space should be partitioned per zone
5023347 zones don't work well with network routes other than default
4963372 investigate whether global zone can act as a router for local zones
6378364 RFE: Allow each zone to have its own virtual IPFilter
diff --git a/usr/src/Makefile b/usr/src/Makefile
index 0e3d6f5..b69335d 100644
--- a/usr/src/Makefile
+++ b/usr/src/Makefile
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -134,13 +134,12 @@
 $(SUBDIRS) head ucbhead pkgdefs: FRC
 	@cd $@; pwd; $(MAKE) $(TARGET)
 
-.PARALLEL:	sysheaders userheaders libheaders ucbheaders cmdheaders \
-		commonheaders
+.PARALLEL:	sysheaders userheaders libheaders ucbheaders cmdheaders
 
 # librpcsvc has a dependency on headers installed by
 # userheaders, hence the .WAIT before libheaders.
 sgs: rootdirs .WAIT sysheaders userheaders .WAIT \
-	libheaders ucbheaders cmdheaders commonheaders
+	libheaders ucbheaders cmdheaders
 
 #
 # top-level setup target to setup the development environment
@@ -182,9 +181,6 @@
 	@cd cmd/fm; pwd; $(MAKE) install_h
 	@cd cmd/mdb; pwd; $(MAKE) install_h
 
-commonheaders: FRC
-	@cd uts/common/inet/ipf/netinet; pwd; $(MAKE) install_h
-
 # each xmod target depends on a corresponding MACH-specific pseudotarget
 # before doing common xmod work
 #
diff --git a/usr/src/Makefile.master b/usr/src/Makefile.master
index a433e01..b5af375 100644
--- a/usr/src/Makefile.master
+++ b/usr/src/Makefile.master
@@ -144,6 +144,9 @@
 CHGRP=		$(TRUE)
 MV=		/usr/bin/mv -f
 RM=		/usr/bin/rm -f
+CUT=		/usr/bin/cut
+NM=		/usr/ccs/bin/nm
+DIFF=		/usr/bin/diff
 GREP=		/usr/bin/grep
 EGREP=		/usr/bin/egrep
 SED=		/usr/bin/sed
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/inform.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/inform.c
index f4ba297..e742e91 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/inform.c
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/inform.c
@@ -87,7 +87,10 @@
 		(void) add_pkt_opt16(dpkt, CD_MAX_DHCP_SIZE,
 		    htons(dsmp->dsm_lif->lif_pif->pif_max -
 		    sizeof (struct udpiphdr)));
-		(void) add_pkt_opt(dpkt, CD_CLASS_ID, class_id, class_id_len);
+		if (class_id_len != 0) {
+			(void) add_pkt_opt(dpkt, CD_CLASS_ID, class_id,
+			    class_id_len);
+		}
 		(void) add_pkt_prl(dpkt, dsmp);
 		(void) add_pkt_opt(dpkt, CD_END, NULL, 0);
 
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/init_reboot.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/init_reboot.c
index 16f7dbb..497a3e9 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/init_reboot.c
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/init_reboot.c
@@ -78,7 +78,8 @@
 	(void) add_pkt_opt16(dpkt, CD_MAX_DHCP_SIZE,
 	    htons(dsmp->dsm_lif->lif_pif->pif_max - sizeof (struct udpiphdr)));
 
-	(void) add_pkt_opt(dpkt, CD_CLASS_ID, class_id, class_id_len);
+	if (class_id_len != 0)
+		(void) add_pkt_opt(dpkt, CD_CLASS_ID, class_id, class_id_len);
 	(void) add_pkt_prl(dpkt, dsmp);
 
 	/*
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/renew.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/renew.c
index d6a81ad..dd65950 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/renew.c
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/renew.c
@@ -480,7 +480,10 @@
 		    htons(lif->lif_max - sizeof (struct udpiphdr)));
 		(void) add_pkt_opt32(dpkt, CD_LEASE_TIME, htonl(DHCP_PERM));
 
-		(void) add_pkt_opt(dpkt, CD_CLASS_ID, class_id, class_id_len);
+		if (class_id_len != 0) {
+			(void) add_pkt_opt(dpkt, CD_CLASS_ID, class_id,
+			    class_id_len);
+		}
 		(void) add_pkt_prl(dpkt, dsmp);
 		/*
 		 * dsm_reqhost was set for this state machine in
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/request.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/request.c
index f6e418f..936965e 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/request.c
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/request.c
@@ -304,7 +304,10 @@
 		    offer->opts[CD_SERVER_ID]->value,
 		    offer->opts[CD_SERVER_ID]->len);
 
-		(void) add_pkt_opt(dpkt, CD_CLASS_ID, class_id, class_id_len);
+		if (class_id_len != 0) {
+			(void) add_pkt_opt(dpkt, CD_CLASS_ID, class_id,
+			    class_id_len);
+		}
 		(void) add_pkt_prl(dpkt, dsmp);
 
 		/*
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/select.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/select.c
index 41cc76f..9dfead3 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/select.c
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/select.c
@@ -169,7 +169,10 @@
 		    htons(dsmp->dsm_lif->lif_max - sizeof (struct udpiphdr)));
 		(void) add_pkt_opt32(dpkt, CD_LEASE_TIME, htonl(DHCP_PERM));
 
-		(void) add_pkt_opt(dpkt, CD_CLASS_ID, class_id, class_id_len);
+		if (class_id_len != 0) {
+			(void) add_pkt_opt(dpkt, CD_CLASS_ID, class_id,
+			    class_id_len);
+		}
 		(void) add_pkt_prl(dpkt, dsmp);
 
 		if (df_get_bool(dsmp->dsm_name, dsmp->dsm_isv6,
@@ -280,7 +283,7 @@
 		return;
 	}
 
-	if (pkt_v4_match(recv_type, DHCP_PACK | DHCP_PNAK)) {
+	if (pkt_v4_match(recv_type, DHCP_PACK)) {
 		if (!dhcp_bound(dsmp, plp)) {
 			dhcpmsg(MSG_WARNING, "dhcp_collect_dlpi: dhcp_bound "
 			    "failed for %s", dsmp->dsm_name);
@@ -289,6 +292,9 @@
 		}
 		dhcpmsg(MSG_VERBOSE, "dhcp_collect_dlpi: %s on %s",
 		    pname, dsmp->dsm_name);
+	} else if (pkt_v4_match(recv_type, DHCP_PNAK)) {
+		free_pkt_entry(plp);
+		dhcp_restart(dsmp);
 	} else {
 		pkt_smach_enqueue(dsmp, plp);
 	}
diff --git a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/svc-ndp b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/svc-ndp
index 0937c37..fe52065 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/svc-ndp
+++ b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/svc-ndp
@@ -20,7 +20,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -28,7 +28,7 @@
 . /lib/svc/share/smf_include.sh
 . /lib/svc/share/routing_include.sh
 
-smf_is_globalzone || exit $SMF_EXIT_OK
+smf_configure_ip || exit $SMF_EXIT_OK
 
 daemon_args=`get_daemon_args $SMF_FMRI`
 options="adtf:"
diff --git a/usr/src/cmd/cmd-inet/usr.lib/in.ripngd/ripng.xml b/usr/src/cmd/cmd-inet/usr.lib/in.ripngd/ripng.xml
index 05391c8..5b65c94 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/in.ripngd/ripng.xml
+++ b/usr/src/cmd/cmd-inet/usr.lib/in.ripngd/ripng.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
 <!--
- Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  Use is subject to license terms.
 
  CDDL HEADER START
@@ -75,7 +75,7 @@
 		timeout_seconds='60'>
 		<method_context>
 			<method_credential user='root' group='root'
-privileges='basic,proc_owner,proc_fork,proc_exec,proc_info,proc_session,file_chown,sys_net_config,net_privaddr,net_icmpaccess,net_rawaccess'/>
+privileges='basic,proc_owner,proc_fork,proc_exec,proc_info,proc_session,file_chown,sys_ip_config,net_privaddr,net_icmpaccess,net_rawaccess'/>
 		</method_context>
 	</exec_method>
 
diff --git a/usr/src/cmd/cmd-inet/usr.lib/in.ripngd/svc-ripng b/usr/src/cmd/cmd-inet/usr.lib/in.ripngd/svc-ripng
index 6e0bea0..f0fb43c 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/in.ripngd/svc-ripng
+++ b/usr/src/cmd/cmd-inet/usr.lib/in.ripngd/svc-ripng
@@ -20,7 +20,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -28,7 +28,7 @@
 . /lib/svc/share/smf_include.sh
 . /lib/svc/share/routing_include.sh
 
-smf_is_globalzone || exit $SMF_EXIT_OK
+smf_configure_ip || exit $SMF_EXIT_OK
 
 daemon_args=`get_daemon_args $SMF_FMRI`
 options="sqp:Ptv"
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c
index c1f32fd..c297c2c 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c
@@ -193,6 +193,10 @@
 static void	selectifs(int argc, char *argv[], int af,
 			struct lifreq *lifrp);
 static int	updownifs(iface_t *ifs, int up);
+static int	find_all_global_interfaces(struct lifconf *lifcp, char **buf,
+		    int64_t lifc_flags);
+static int	find_all_zone_interfaces(struct lifconf *lifcp, char **buf,
+		    int64_t lifc_flags);
 
 #define	max(a, b)	((a) < (b) ? (b) : (a))
 
@@ -484,59 +488,30 @@
 	struct lifreq lifrl;	/* Local lifreq struct */
 	int numifs;
 	unsigned bufsize;
-	ni_t *nip;
 	int plumball = 0;
 	int save_af = af;
 
+	buf = NULL;
 	/*
 	 * Special case:
 	 * ifconfig -a plumb should find all network interfaces
-	 * in the machine by traversing the devinfo tree.
+	 * in the machine by traversing the devinfo tree for global zone.
+	 * For non-global zones, only find the assigned interfaces.
 	 * Also, there is no need to  SIOCGLIF* ioctls, since
 	 * those interfaces have already been plumbed
 	 */
 	if (argc > 0 && (strcmp(*argv, "plumb") == 0)) {
-		/*
-		 * Look through the kernel's devinfo tree for
-		 * network devices
-		 */
-		di_node_t root;
-
-		/*
-		 * DINFOCACHE is equivalent to DINFOSUBTREE | DINFOMINOR |
-		 * DINFOPROP | DINFOFORCE.
-		 */
-		if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
-			(void) fprintf(stderr, "ifconfig: di_init failed;"
-			    " check the devinfo driver.\n");
-			exit(1);
+		if (getzoneid() == GLOBAL_ZONEID) {
+			if (find_all_global_interfaces(&lifc, &buf,
+			    lifc_flags) != 0)
+				return;
+		} else {
+			if (find_all_zone_interfaces(&lifc, &buf,
+			    lifc_flags) != 0)
+				return;
 		}
-
-		(void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, NULL,
-		    devfs_entry);
-		di_fini(root);
-
-		/*
-		 * Now, translate the linked list into
-		 * a struct lifreq buffer
-		 */
-		bufsize = num_ni * sizeof (struct lifreq);
-		if ((buf = malloc(bufsize)) == NULL)
-			Perror0_exit("foreachinterface: malloc failed");
-
-		lifc.lifc_family = AF_UNSPEC;
-		lifc.lifc_flags = lifc_flags;
-		lifc.lifc_len = bufsize;
-		lifc.lifc_buf = buf;
-
-		for (n = 0, lifrp = lifc.lifc_req; n < num_ni; n++, lifrp++) {
-			nip = ni_list;
-			(void) strncpy(lifrp->lifr_name, nip->ni_name,
-			    sizeof (lifr.lifr_name));
-			ni_list = nip->ni_next;
-			free(nip);
-		}
-
+		if (lifc.lifc_len == 0)
+			return;
 		plumball = 1;
 	} else {
 		lifn.lifn_family = AF_UNSPEC;
@@ -664,7 +639,8 @@
 		/* the func could have overwritten origname, so restore */
 		(void) strncpy(name, origname, sizeof (name));
 	}
-	free(buf);
+	if (buf != NULL)
+		free(buf);
 }
 
 static void
@@ -1781,6 +1757,161 @@
 }
 
 /*
+ * static int find_all_global_interfaces(struct lifconf *lifcp, char **buf,
+ *     int64_t lifc_flags)
+ *
+ * It finds all interfaces for the global zone, that is all
+ * the physical interfaces, using the kernel's devinfo tree.
+ *
+ * It takes in input a pointer to struct lifconf to receive interfaces
+ * informations, a **char to hold allocated buffer, and a lifc_flags.
+ *
+ * Return values:
+ *  0 = everything OK
+ * -1 = problem
+ */
+static int
+find_all_global_interfaces(struct lifconf *lifcp, char **buf,
+    int64_t lifc_flags)
+{
+	unsigned bufsize;
+	int n;
+	di_node_t root;
+	ni_t *nip;
+	struct lifreq *lifrp;
+
+	/*
+	 * DINFOCACHE is equivalent to DINFOSUBTREE | DINFOMINOR |
+	 * DINFOPROP | DINFOFORCE.
+	 */
+	if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) {
+		(void) fprintf(stderr, "ifconfig: di_init "
+		    "failed; check the devinfo driver.\n");
+		exit(1);
+	}
+
+	(void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS,
+	    NULL, devfs_entry);
+	di_fini(root);
+
+	/*
+	 * Now, translate the linked list into
+	 * a struct lifreq buffer
+	 */
+	if (num_ni == 0) {
+		lifcp->lifc_family = AF_UNSPEC;
+		lifcp->lifc_flags = lifc_flags;
+		lifcp->lifc_len = 0;
+		lifcp->lifc_buf = NULL;
+		return (0);
+	}
+
+	bufsize = num_ni * sizeof (struct lifreq);
+	if ((*buf = malloc(bufsize)) == NULL)
+		Perror0_exit("find_all_interfaces: malloc failed");
+
+	lifcp->lifc_family = AF_UNSPEC;
+	lifcp->lifc_flags = lifc_flags;
+	lifcp->lifc_len = bufsize;
+	lifcp->lifc_buf = *buf;
+
+	for (n = 0, lifrp = lifcp->lifc_req; n < num_ni; n++, lifrp++) {
+		nip = ni_list;
+		(void) strncpy(lifrp->lifr_name, nip->ni_name,
+		    sizeof (lifr.lifr_name));
+		ni_list = nip->ni_next;
+		free(nip);
+	}
+	return (0);
+}
+
+/*
+ * static int find_all_zone_interfaces(struct lifconf *lifcp, char **buf,
+ *     int64_t lifc_flags)
+ *
+ * It finds all interfaces for an exclusive-IP zone, that is all the interfaces
+ * assigned to it.
+ *
+ * It takes in input a pointer to struct lifconf to receive interfaces
+ * informations, a **char to hold allocated buffer, and a lifc_flags.
+ *
+ * Return values:
+ *  0 = everything OK
+ * -1 = problem
+ */
+static int
+find_all_zone_interfaces(struct lifconf *lifcp, char **buf, int64_t lifc_flags)
+{
+	zoneid_t zoneid;
+	unsigned bufsize;
+	char *dlnames, *ptr;
+	struct lifreq *lifrp;
+	int num_ni_saved, i;
+
+	zoneid = getzoneid();
+
+	num_ni = 0;
+	if (zone_list_datalink(zoneid, &num_ni, NULL) != 0)
+		Perror0_exit("find_all_interfaces: list interfaces failed");
+again:
+	/* this zone doesn't have any data-links */
+	if (num_ni == 0) {
+		lifcp->lifc_family = AF_UNSPEC;
+		lifcp->lifc_flags = lifc_flags;
+		lifcp->lifc_len = 0;
+		lifcp->lifc_buf = NULL;
+		return (0);
+	}
+
+	dlnames = malloc(num_ni * LIFNAMSIZ);
+	if (dlnames == NULL)
+		Perror0_exit("find_all_interfaces: out of memory");
+	num_ni_saved = num_ni;
+
+	if (zone_list_datalink(zoneid, &num_ni, dlnames) != 0)
+		Perror0_exit("find_all_interfaces: list interfaces failed");
+
+	if (num_ni_saved < num_ni) {
+		/* list increased, try again */
+		free(dlnames);
+		goto again;
+	}
+
+	/* this zone doesn't have any data-links now */
+	if (num_ni == 0) {
+		free(dlnames);
+		lifcp->lifc_family = AF_UNSPEC;
+		lifcp->lifc_flags = lifc_flags;
+		lifcp->lifc_len = 0;
+		lifcp->lifc_buf = NULL;
+		return (0);
+	}
+
+	bufsize = num_ni * sizeof (struct lifreq);
+	if ((*buf = malloc(bufsize)) == NULL) {
+		free(dlnames);
+		Perror0_exit("find_all_interfaces: malloc failed");
+	}
+
+	lifrp = (struct lifreq *)*buf;
+	ptr = dlnames;
+	for (i = 0; i < num_ni; i++) {
+		if (strlcpy(lifrp->lifr_name, ptr, LIFNAMSIZ) >=
+		    LIFNAMSIZ)
+			Perror0_exit("find_all_interfaces: overflow");
+		ptr += LIFNAMSIZ;
+		lifrp++;
+	}
+
+	free(dlnames);
+	lifcp->lifc_family = AF_UNSPEC;
+	lifcp->lifc_flags = lifc_flags;
+	lifcp->lifc_len = bufsize;
+	lifcp->lifc_buf = *buf;
+	return (0);
+}
+
+/*
  * Create the next unused logical interface using the original name
  * and assign the address (and mask if '/<n>' is part of the address).
  * Use the new logical interface for subsequent subcommands by updating
@@ -2760,8 +2891,13 @@
 	if (!v4compat) {
 		if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0)
 			(void) printf(" index %d", lifr.lifr_index);
+		/*
+		 * Stack instances use GLOBAL_ZONEID for IP data structures
+		 * even in the non-global zone.
+		 */
 		if (ioctl(s, SIOCGLIFZONE, (caddr_t)&lifr) >= 0 &&
-		    lifr.lifr_zoneid != getzoneid()) {
+		    lifr.lifr_zoneid != getzoneid() &&
+		    lifr.lifr_zoneid != GLOBAL_ZONEID) {
 			char zone_name[ZONENAME_MAX];
 
 			if (lifr.lifr_zoneid == ALL_ZONES) {
@@ -3928,6 +4064,7 @@
 	int		dev_fd;
 	dlpi_if_attr_t	dia;
 	boolean_t	islo;
+	zoneid_t	zoneid;
 
 	strptr = strchr(name, ':');
 	islo = (strcmp(name, LOOPBACK_IF) == 0);
@@ -3962,6 +4099,27 @@
 		return (0);
 	}
 
+	/*
+	 * For global zone, check if the interface is used by a non-global
+	 * zone, note that the non-global zones doesn't need this check,
+	 * because zoneadm has taken care of this when the zone boots.
+	 */
+	zoneid = getzoneid();
+	if (zoneid == GLOBAL_ZONEID) {
+		int ret;
+
+		zoneid = ALL_ZONES;
+		ret = zone_check_datalink(&zoneid, name);
+		if (ret == 0) {
+			char zonename[ZONENAME_MAX];
+
+			(void) getzonenamebyid(zoneid, zonename, ZONENAME_MAX);
+			(void) fprintf(stderr, "%s is used by non-global"
+			    "zone: %s\n", name, zonename);
+			return (1);
+		}
+	}
+
 	if (debug)
 		(void) printf("inetplumb: %s af %d\n", name, afp->af_af);
 
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/in.rdisc/rdisc.xml b/usr/src/cmd/cmd-inet/usr.sbin/in.rdisc/rdisc.xml
index 7ae84f1..005b491 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/in.rdisc/rdisc.xml
+++ b/usr/src/cmd/cmd-inet/usr.sbin/in.rdisc/rdisc.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
 <!--
- Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  Use is subject to license terms.
 
  CDDL HEADER START
@@ -58,7 +58,7 @@
 		timeout_seconds='60'>
 		<method_context>
 			<method_credential user='root' group='root'
-privileges='basic,proc_owner,proc_fork,proc_exec,proc_info,proc_session,file_chown,sys_net_config,net_icmpaccess,net_rawaccess'/>
+privileges='basic,proc_owner,proc_fork,proc_exec,proc_info,proc_session,file_chown,sys_ip_config,net_icmpaccess,net_rawaccess'/>
 		</method_context>
 	</exec_method>
 
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/in.rdisc/svc-rdisc b/usr/src/cmd/cmd-inet/usr.sbin/in.rdisc/svc-rdisc
index 76cdda3..1bdb4dc 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/in.rdisc/svc-rdisc
+++ b/usr/src/cmd/cmd-inet/usr.sbin/in.rdisc/svc-rdisc
@@ -20,7 +20,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -28,7 +28,7 @@
 . /lib/svc/share/smf_include.sh
 . /lib/svc/share/routing_include.sh
 
-smf_is_globalzone || exit $SMF_EXIT_OK
+smf_configure_ip || exit $SMF_EXIT_OK
 
 daemon_args=`get_daemon_args $SMF_FMRI`
 options="afsp:T:r"
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/in.routed/route.xml b/usr/src/cmd/cmd-inet/usr.sbin/in.routed/route.xml
index c7867bb..8982aba 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/in.routed/route.xml
+++ b/usr/src/cmd/cmd-inet/usr.sbin/in.routed/route.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
 <!--
- Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  Use is subject to license terms.
 
  CDDL HEADER START
@@ -58,7 +58,7 @@
 		timeout_seconds='60'>
 		<method_context>
 			<method_credential user='root' group='root'
-privileges='basic,proc_owner,proc_fork,proc_exec,proc_info,proc_session,file_chown,sys_net_config,net_privaddr,net_icmpaccess,net_rawaccess'/>
+privileges='basic,proc_owner,proc_fork,proc_exec,proc_info,proc_session,file_chown,sys_ip_config,net_privaddr,net_icmpaccess,net_rawaccess'/>
 		</method_context>
 	</exec_method>
 
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/in.routed/svc-route b/usr/src/cmd/cmd-inet/usr.sbin/in.routed/svc-route
index aa67456..a0a82c8 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/in.routed/svc-route
+++ b/usr/src/cmd/cmd-inet/usr.sbin/in.routed/svc-route
@@ -20,7 +20,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -28,7 +28,7 @@
 . /lib/svc/share/smf_include.sh
 . /lib/svc/share/routing_include.sh
 
-smf_is_globalzone || exit $SMF_EXIT_OK
+smf_configure_ip || exit $SMF_EXIT_OK
 
 daemon_args=`get_daemon_args $SMF_FMRI`
 options="AdghmnqsStvVzT:F:P:"
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ping/ping.c b/usr/src/cmd/cmd-inet/usr.sbin/ping/ping.c
index a0ea8b8..17891ff 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/ping/ping.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ping/ping.c
@@ -18,7 +18,7 @@
  *
  * CDDL HEADER END
  *
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -246,25 +246,25 @@
 	char tmp_buf[INET6_ADDRSTRLEN];
 	int c;
 	int i;
-	boolean_t has_sys_net_config;
+	boolean_t has_sys_ip_config;
 
 	progname = argv[0];
 
 	/*
 	 * This program needs the net_icmpaccess privilege for creating
-	 * raw ICMP sockets.  It needs sys_net_config for using the
+	 * raw ICMP sockets.  It needs sys_ip_config for using the
 	 * IP_NEXTHOP socket option (IPv4 only).  We'll fail
 	 * on the socket call and report the error there when we have
 	 * insufficient privileges.
 	 *
-	 * Non-global zones don't have the sys_net_config privilege, so
+	 * Shared-IP zones don't have the sys_ip_config privilege, so
 	 * we need to check for it in our limit set before trying
 	 * to set it.
 	 */
-	has_sys_net_config = priv_ineffect(PRIV_SYS_NET_CONFIG);
+	has_sys_ip_config = priv_ineffect(PRIV_SYS_IP_CONFIG);
 
 	(void) __init_suid_priv(PU_CLEARLIMITSET, PRIV_NET_ICMPACCESS,
-	    has_sys_net_config ? PRIV_SYS_NET_CONFIG : (char *)NULL,
+	    has_sys_ip_config ? PRIV_SYS_IP_CONFIG : (char *)NULL,
 	    (char *)NULL);
 
 	setbuf(stdout, (char *)0);
@@ -1228,7 +1228,7 @@
 		nh = ((struct sockaddr_in *)ai_nexthop->
 		    ai_addr)->sin_addr.s_addr;
 
-		/* now we need the sys_net_config privilege */
+		/* now we need the sys_ip_config privilege */
 		(void) __priv_bracket(PRIV_ON);
 		if (setsockopt(sock, IPPROTO_IP, IP_NEXTHOP,
 		    &nh, sizeof (ipaddr_t)) < 0) {
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/routeadm/svc-forwarding b/usr/src/cmd/cmd-inet/usr.sbin/routeadm/svc-forwarding
index fc9c5e3..db3ead4 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/routeadm/svc-forwarding
+++ b/usr/src/cmd/cmd-inet/usr.sbin/routeadm/svc-forwarding
@@ -20,7 +20,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -61,7 +61,7 @@
 
 case "$1" in
 'start' | 'refresh' )
-	smf_is_globalzone || exit $SMF_EXIT_OK
+	smf_configure_ip || exit $SMF_EXIT_OK
 	#
 	# Start ip forwarding.
 	#
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/routeadm/svc-legacy-routing b/usr/src/cmd/cmd-inet/usr.sbin/routeadm/svc-legacy-routing
index dcf8b39..d063801 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/routeadm/svc-legacy-routing
+++ b/usr/src/cmd/cmd-inet/usr.sbin/routeadm/svc-legacy-routing
@@ -20,7 +20,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -55,7 +55,7 @@
 		echo "${proto}-routing-stop-cmd not specified by routeadm."
 		exit $SMF_EXIT_ERR_CONFIG
 	fi
-	smf_is_globalzone || exit $SMF_EXIT_OK
+	smf_configure_ip || exit $SMF_EXIT_OK
 
 	# Run daemon - fail if it does not successfully daemonize.
 	eval "$daemon_prog $daemon_args"
@@ -65,10 +65,16 @@
 	fi
 	# Create pidfile.
 	daemon_name=`/usr/bin/basename $daemon_prog`
-	/usr/bin/pgrep -P 1 -f $daemon_prog > /var/tmp/${daemon_name}.pid
+	if smf_is_globalzone; then
+		/usr/bin/pgrep -P 1 -z `smf_zonename` -f $daemon_prog > \
+			/var/tmp/${daemon_name}.pid
+	else
+		/usr/bin/pgrep -z `smf_zonename` -f $daemon_prog > \
+			/var/tmp/${daemon_name}.pid
+	fi
 	;;
 'stop' )
-	smf_is_globalzone || exit $SMF_EXIT_OK
+	smf_configure_ip || exit $SMF_EXIT_OK
 
 	# Stop daemon - ignore result.
 	if [ -n "$daemon_stop" ]; then
diff --git a/usr/src/cmd/diff/Makefile b/usr/src/cmd/diff/Makefile
index 1c44145..d5443bb 100644
--- a/usr/src/cmd/diff/Makefile
+++ b/usr/src/cmd/diff/Makefile
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -22,14 +21,14 @@
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
 #
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
 PROG= diff diffh
 SRCS=	$(PROG:%=%.c)
-DIFF= diff
-DIFFH= diffh
+BINDIFF= diff
+LIBDIFFH= diffh
 
 include ../Makefile.cmd
 #
@@ -39,8 +38,8 @@
 DCFILE= diff.dc
 #XGETFLAGS += -a -x diff.xcl
 
-ROOTBINDIFF = $(DIFF:%=$(ROOTBIN)/%)
-ROOTLIBDIFFH = $(DIFFH:%=$(ROOTLIB)/%)
+ROOTBINDIFF = $(BINDIFF:%=$(ROOTBIN)/%)
+ROOTLIBDIFFH = $(LIBDIFFH:%=$(ROOTLIB)/%)
 
 .KEEP_STATE:
 
diff --git a/usr/src/cmd/dladm/dladm.c b/usr/src/cmd/dladm/dladm.c
index cd07c7c..c088f44 100644
--- a/usr/src/cmd/dladm/dladm.c
+++ b/usr/src/cmd/dladm/dladm.c
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -116,6 +116,8 @@
 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj;
 static cmdfunc_t do_init_linkprop, do_init_secobj;
 
+static void	show_linkprop_onelink(void *, const char *);
+
 static void	link_stats(const char *, uint_t);
 static void	aggr_stats(uint32_t, uint_t);
 static void	dev_stats(const char *dev, uint32_t);
@@ -2340,6 +2342,7 @@
 	const char	*ls_link;
 	char		*ls_line;
 	char		**ls_propvals;
+	prop_list_t	*ls_proplist;
 	boolean_t	ls_parseable;
 	boolean_t	ls_persist;
 	boolean_t	ls_header;
@@ -2420,8 +2423,8 @@
 static void
 print_linkprop_head(void)
 {
-	(void) printf("%-15s %-14s %-14s %-30s \n",
-	    "PROPERTY", "VALUE", "DEFAULT", "POSSIBLE");
+	(void) printf("%-12s %-15s %-14s %-14s %-20s \n",
+	    "LINK", "PROPERTY", "VALUE", "DEFAULT", "POSSIBLE");
 }
 
 static void
@@ -2481,6 +2484,15 @@
 	char			*ptr = statep->ls_line;
 	char			*lim = ptr + MAX_PROP_LINE;
 
+	if (statep->ls_persist && dladm_is_prop_temponly(propname, NULL))
+		return (B_TRUE);
+
+	if (statep->ls_parseable)
+		ptr += snprintf(ptr, lim - ptr, "LINK=\"%s\" ",
+		    statep->ls_link);
+	else
+		ptr += snprintf(ptr, lim - ptr, "%-12s ", statep->ls_link);
+
 	if (statep->ls_parseable)
 		ptr += snprintf(ptr, lim - ptr, "PROPERTY=\"%s\" ", propname);
 	else
@@ -2492,7 +2504,7 @@
 	print_linkprop(statep, propname, DLADM_PROP_VAL_DEFAULT,
 	    "DEFAULT", "%-14s ", &ptr);
 	print_linkprop(statep, propname, DLADM_PROP_VAL_MODIFIABLE,
-	    "POSSIBLE", "%-30s ", &ptr);
+	    "POSSIBLE", "%-20s ", &ptr);
 
 	if (statep->ls_header) {
 		statep->ls_header = B_FALSE;
@@ -2506,11 +2518,8 @@
 static void
 do_show_linkprop(int argc, char **argv)
 {
-	int			i, option, fd;
-	char			linkname[MAXPATHLEN];
+	int			option;
 	prop_list_t		*proplist = NULL;
-	char			*buf;
-	dladm_status_t		status;
 	show_linkprop_state_t	state;
 
 	opterr = 0;
@@ -2544,8 +2553,31 @@
 	else if (optind != argc)
 		usage();
 
-	if (state.ls_link == NULL)
-		die("link name must be specified");
+	state.ls_proplist = proplist;
+
+	if (state.ls_link == NULL) {
+		(void) dladm_walk(show_linkprop_onelink, &state);
+	} else {
+		show_linkprop_onelink(&state, state.ls_link);
+	}
+	free_props(proplist);
+}
+
+static void
+show_linkprop_onelink(void *arg, const char *link)
+{
+	int			i, fd;
+	char			linkname[MAXPATHLEN];
+	char			*buf;
+	dladm_status_t		status;
+	prop_list_t		*proplist = NULL;
+	show_linkprop_state_t	*statep;
+	const char		*savep;
+
+	statep = (show_linkprop_state_t *)arg;
+	savep = statep->ls_link;
+	statep->ls_link = link;
+	proplist = statep->ls_proplist;
 
 	/*
 	 * When some WiFi links are opened for the first time, their hardware
@@ -2553,37 +2585,37 @@
 	 * if there are no open links, the retrieval of link properties
 	 * (below) will proceed slowly unless we hold the link open.
 	 */
-	(void) snprintf(linkname, MAXPATHLEN, "/dev/%s", state.ls_link);
+	(void) snprintf(linkname, MAXPATHLEN, "/dev/%s", link);
 	if ((fd = open(linkname, O_RDWR)) < 0)
-		die("cannot open %s: %s", state.ls_link, strerror(errno));
+		die("cannot open %s: %s", link, strerror(errno));
 
 	buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * MAX_PROP_VALS +
 	    MAX_PROP_LINE);
 	if (buf == NULL)
 		die("insufficient memory");
 
-	state.ls_propvals = (char **)(void *)buf;
+	statep->ls_propvals = (char **)(void *)buf;
 	for (i = 0; i < MAX_PROP_VALS; i++) {
-		state.ls_propvals[i] = buf + sizeof (char *) * MAX_PROP_VALS +
+		statep->ls_propvals[i] = buf + sizeof (char *) * MAX_PROP_VALS +
 		    i * DLADM_PROP_VAL_MAX;
 	}
-	state.ls_line = buf +
+	statep->ls_line = buf +
 	    (sizeof (char *) + DLADM_PROP_VAL_MAX) * MAX_PROP_VALS;
 
 	if (proplist != NULL) {
 		for (i = 0; i < proplist->pl_count; i++) {
-			if (!show_linkprop(&state,
+			if (!show_linkprop(statep,
 			    proplist->pl_info[i].pi_name))
 				break;
 		}
 	} else {
-		status = dladm_walk_prop(state.ls_link, &state, show_linkprop);
+		status = dladm_walk_prop(link, statep, show_linkprop);
 		if (status != DLADM_STATUS_OK)
 			die_dlerr(status, "show-linkprop");
 	}
 	(void) close(fd);
 	free(buf);
-	free_props(proplist);
+	statep->ls_link = savep;
 }
 
 static dladm_status_t
@@ -2591,17 +2623,18 @@
     uint_t val_cnt, boolean_t reset)
 {
 	dladm_status_t	status;
+	char		*errprop;
 
 	status = dladm_set_prop(link, prop_name, prop_val, val_cnt,
-	    DLADM_OPT_PERSIST);
+	    DLADM_OPT_PERSIST, &errprop);
 
 	if (status != DLADM_STATUS_OK) {
 		if (reset) {
 			warn_dlerr(status, "cannot persistently reset link "
-			    "property '%s' on '%s'", prop_name, link);
+			    "property '%s' on '%s'", errprop, link);
 		} else {
 			warn_dlerr(status, "cannot persistently set link "
-			    "property '%s' on '%s'", prop_name, link);
+			    "property '%s' on '%s'", errprop, link);
 		}
 	}
 	return (status);
@@ -2650,13 +2683,16 @@
 		die("link name must be specified");
 
 	if (proplist == NULL) {
+		char *errprop;
+
 		if (!reset)
 			die("link property must be specified");
 
-		status = dladm_set_prop(link, NULL, NULL, 0, DLADM_OPT_TEMP);
+		status = dladm_set_prop(link, NULL, NULL, 0, DLADM_OPT_TEMP,
+		    &errprop);
 		if (status != DLADM_STATUS_OK) {
-			warn_dlerr(status, "cannot reset link properties "
-			    "on '%s'", link);
+			warn_dlerr(status, "cannot reset link property '%s' "
+			    "on '%s'", errprop, link);
 		}
 		if (!temp) {
 			dladm_status_t	s;
@@ -2688,7 +2724,7 @@
 			}
 		}
 		s = dladm_set_prop(link, pip->pi_name, val, count,
-		    DLADM_OPT_TEMP);
+		    DLADM_OPT_TEMP, NULL);
 		if (s == DLADM_STATUS_OK) {
 			if (!temp) {
 				s = set_linkprop_persist(link,
@@ -2734,10 +2770,12 @@
 				if (ptr >= lim)
 					break;
 			}
-			if (ptr > errmsg)
+			if (ptr > errmsg) {
 				*(ptr - 1) = '\0';
-			warn("link property '%s' must be one of: %s",
-			    pip->pi_name, errmsg);
+				warn("link property '%s' must be one of: %s",
+				    pip->pi_name, errmsg);
+			} else
+				warn("invalid link property '%s'", *val);
 			free(propvals);
 			break;
 		}
diff --git a/usr/src/cmd/ipf/lib/Makefile.com b/usr/src/cmd/ipf/lib/Makefile.com
index e6bf79f..8019bb8 100644
--- a/usr/src/cmd/ipf/lib/Makefile.com
+++ b/usr/src/cmd/ipf/lib/Makefile.com
@@ -1,5 +1,25 @@
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -35,7 +55,9 @@
 		remove_pool.o remove_poolnode.o remove_hash.o \
 		remove_hashnode.o resetlexer.o rwlock_emul.o \
 		tcpflags.o var.o verbose.o \
-		v6ionames.o v6optvalue.o
+		v6ionames.o v6optvalue.o printpool_live.o \
+		printpooldata.o printhash_live.o printhashdata.o \
+		printactivenat.o
 
 include $(SRC)/lib/Makefile.lib
 include ../../Makefile.ipf
diff --git a/usr/src/cmd/ipf/lib/common/getifname.c b/usr/src/cmd/ipf/lib/common/getifname.c
index ec3ae92..ef25075 100644
--- a/usr/src/cmd/ipf/lib/common/getifname.c
+++ b/usr/src/cmd/ipf/lib/common/getifname.c
@@ -3,7 +3,7 @@
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -38,7 +38,7 @@
 	int len;
 # endif
 	struct ifnet netif;
-
+#define SOLARIS_PFHOOKS	1
 # ifdef SOLARIS_PFHOOKS
 	if ((opts & OPT_DONOTHING) == 0)
 		return "@";
diff --git a/usr/src/cmd/ipf/lib/common/getnattype.c b/usr/src/cmd/ipf/lib/common/getnattype.c
index 312a862..2c89b2b 100644
--- a/usr/src/cmd/ipf/lib/common/getnattype.c
+++ b/usr/src/cmd/ipf/lib/common/getnattype.c
@@ -4,7 +4,13 @@
  * See the IPFILTER.LICENCE file for details on licencing.
  *
  * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com)
+ *
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
  */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
 #include "ipf.h"
 #include "kmem.h"
 
@@ -16,19 +22,27 @@
 /*
  * Get a nat filter type given its kernel address.
  */
-char *getnattype(ipnat)
-ipnat_t *ipnat;
+char *getnattype(nat, alive)
+nat_t *nat;
+int alive;
 {
 	static char unknownbuf[20];
-	ipnat_t ipnatbuff;
+	ipnat_t *ipn, ipnatbuff;
 	char *which;
+	int type;
 
-	if (!ipnat)
+	if (!nat)
 		return "???";
-	if (kmemcpy((char *)&ipnatbuff, (long)ipnat, sizeof(ipnatbuff)))
-		return "!!!";
+	if (alive) {
+		type = nat->nat_redir;
+	} else {
+		ipn = nat->nat_ptr;
+		if (kmemcpy((char *)&ipnatbuff, (long)ipn, sizeof(ipnatbuff)))
+			return "!!!";
+		type = ipnatbuff.in_redir;
+	}
 
-	switch (ipnatbuff.in_redir)
+	switch (type)
 	{
 	case NAT_MAP :
 		which = "MAP";
@@ -43,8 +57,7 @@
 		which = "BIMAP";
 		break;
 	default :
-		sprintf(unknownbuf, "unknown(%04x)",
-			ipnatbuff.in_redir & 0xffffffff);
+		sprintf(unknownbuf, "unknown(%04x)", type & 0xffffffff);
 		which = unknownbuf;
 		break;
 	}
diff --git a/usr/src/cmd/ipf/lib/common/load_pool.c b/usr/src/cmd/ipf/lib/common/load_pool.c
index d27b6c3..b8146c0 100644
--- a/usr/src/cmd/ipf/lib/common/load_pool.c
+++ b/usr/src/cmd/ipf/lib/common/load_pool.c
@@ -4,8 +4,13 @@
  * See the IPFILTER.LICENCE file for details on licencing.
  *
  * $Id: load_pool.c,v 1.14.2.2 2005/02/01 02:44:06 darrenr Exp $
+ *
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
  */
 
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
 #include <fcntl.h>
 #include <sys/ioctl.h>
 #include "ipf.h"
diff --git a/usr/src/cmd/ipf/lib/common/printactivenat.c b/usr/src/cmd/ipf/lib/common/printactivenat.c
index 389818b..ace6b6c 100644
--- a/usr/src/cmd/ipf/lib/common/printactivenat.c
+++ b/usr/src/cmd/ipf/lib/common/printactivenat.c
@@ -4,8 +4,13 @@
  * See the IPFILTER.LICENCE file for details on licencing.
  *
  * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com)
+ *
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
  */
 
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
 #include "ipf.h"
 
 
@@ -14,12 +19,12 @@
 #endif
 
 
-void printactivenat(nat, opts)
+void printactivenat(nat, opts, alive)
 nat_t *nat;
-int opts;
+int opts, alive;
 {
 
-	printf("%s", getnattype(nat->nat_ptr));
+	printf("%s", getnattype(nat, alive));
 
 	if (nat->nat_flags & SI_CLONE)
 		printf(" CLONE");
diff --git a/usr/src/cmd/ipf/lib/common/printhash_live.c b/usr/src/cmd/ipf/lib/common/printhash_live.c
new file mode 100755
index 0000000..082ee74
--- /dev/null
+++ b/usr/src/cmd/ipf/lib/common/printhash_live.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2002 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/ioctl.h>
+#include "ipf.h"
+#include "netinet/ipl.h"
+
+#define	PRINTF	(void)printf
+#define	FPRINTF	(void)fprintf
+
+
+iphtable_t *printhash_live(hp, fd, name, opts)
+iphtable_t *hp;
+int fd;
+char *name;
+int opts;
+{
+	iphtent_t entry, *top, *node;
+	ipflookupiter_t iter;
+	int i, printed, last;
+	ipfobj_t obj;
+
+	if ((name != NULL) && strncmp(name, hp->iph_name, FR_GROUPLEN))
+		return hp->iph_next;
+
+	printhashdata(hp, opts);
+
+	if ((opts & OPT_DEBUG) == 0)
+		PRINTF("\t{");
+
+	obj.ipfo_rev = IPFILTER_VERSION;
+	obj.ipfo_type = IPFOBJ_LOOKUPITER;
+	obj.ipfo_ptr = &iter;
+	obj.ipfo_size = sizeof(iter);
+
+	iter.ili_data = &entry;
+	iter.ili_type = IPLT_HASH;
+	iter.ili_otype = IPFLOOKUPITER_NODE;
+	iter.ili_ival = IPFGENITER_LOOKUP;
+	iter.ili_unit = hp->iph_unit;
+	strncpy(iter.ili_name, hp->iph_name, FR_GROUPLEN);
+
+	last = 0;
+	top = NULL;
+
+	while (!last && (ioctl(fd, SIOCLOOKUPITER, &obj) == 0)) {
+		if (entry.ipe_snext == NULL)
+			last = 1;
+		entry.ipe_snext = top;
+		top = malloc(sizeof(*top));
+		if (top == NULL)
+			break;
+		bcopy(&entry, top, sizeof(entry));
+	}
+
+	while (top != NULL) {
+		node = top;
+		(void) printhashnode(hp, node, bcopywrap, opts);
+		top = node->ipe_snext;
+		free(node);
+		printed++;
+
+                if ((opts & OPT_DEBUG) == 0)
+                        putchar(';');
+	}
+
+	if (printed == 0)
+		putchar(';');
+
+	if ((opts & OPT_DEBUG) == 0)
+		PRINTF(" };\n");
+	return hp->iph_next;
+}
diff --git a/usr/src/cmd/ipf/lib/common/printhashdata.c b/usr/src/cmd/ipf/lib/common/printhashdata.c
new file mode 100755
index 0000000..cef1afb
--- /dev/null
+++ b/usr/src/cmd/ipf/lib/common/printhashdata.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2002 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include "ipf.h"
+
+#define	PRINTF	(void)printf
+#define	FPRINTF	(void)fprintf
+
+
+void printhashdata(hp, opts)
+iphtable_t *hp;
+int opts;
+{
+
+	if ((opts & OPT_DEBUG) == 0) {
+		if ((hp->iph_type & IPHASH_ANON) == IPHASH_ANON)
+			PRINTF("# 'anonymous' table\n");
+		switch (hp->iph_type & ~IPHASH_ANON)
+		{
+		case IPHASH_LOOKUP :
+			PRINTF("table");
+			break;
+		case IPHASH_GROUPMAP :
+			PRINTF("group-map");
+			if (hp->iph_flags & FR_INQUE)
+				PRINTF(" in");
+			else if (hp->iph_flags & FR_OUTQUE)
+				PRINTF(" out");
+			else
+				PRINTF(" ???");
+			break;
+		default :
+			PRINTF("%#x", hp->iph_type);
+			break;
+		}
+		PRINTF(" role = ");
+	} else {
+		PRINTF("Hash Table Number: %s", hp->iph_name);
+		if ((hp->iph_type & IPHASH_ANON) == IPHASH_ANON)
+			PRINTF("(anon)");
+		putchar(' ');
+		PRINTF("Role: ");
+	}
+
+	switch (hp->iph_unit)
+	{
+	case IPL_LOGNAT :
+		PRINTF("nat");
+		break;
+	case IPL_LOGIPF :
+		PRINTF("ipf");
+		break;
+	case IPL_LOGAUTH :
+		PRINTF("auth");
+		break;
+	case IPL_LOGCOUNT :
+		PRINTF("count");
+		break;
+	default :
+		PRINTF("#%d", hp->iph_unit);
+		break;
+	}
+
+	if ((opts & OPT_DEBUG) == 0) {
+		if ((hp->iph_type & ~IPHASH_ANON) == IPHASH_LOOKUP)
+			PRINTF(" type = hash");
+		PRINTF(" number = %s size = %lu",
+			hp->iph_name, (u_long)hp->iph_size);
+		if (hp->iph_seed != 0)
+			PRINTF(" seed = %lu", hp->iph_seed);
+		putchar('\n');
+	} else {
+		PRINTF(" Type: ");
+		switch (hp->iph_type & ~IPHASH_ANON)
+		{
+		case IPHASH_LOOKUP :
+			PRINTF("lookup");
+			break;
+		case IPHASH_GROUPMAP :
+			PRINTF("groupmap Group. %s", hp->iph_name);
+			break;
+		default :
+			break;
+		}
+
+		putchar('\n');
+		PRINTF("\t\tSize: %lu\tSeed: %lu",
+			(u_long)hp->iph_size, hp->iph_seed);
+		PRINTF("\tRef. Count: %d\tMasks: %#x\n", hp->iph_ref,
+			hp->iph_masks[0]);
+	}
+
+	if ((opts & OPT_DEBUG) != 0) {
+		struct in_addr m;
+		int i;
+
+		for (i = 0; i < 32; i++) {
+			if ((1 << i) & hp->iph_masks[0]) {
+				ntomask(4, i, &m.s_addr);
+				PRINTF("\t\tMask: %s\n", inet_ntoa(m));
+			}
+		}
+	}
+}
diff --git a/usr/src/cmd/ipf/lib/common/printpool_live.c b/usr/src/cmd/ipf/lib/common/printpool_live.c
new file mode 100644
index 0000000..77f95d8
--- /dev/null
+++ b/usr/src/cmd/ipf/lib/common/printpool_live.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2002 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/ioctl.h>
+#include "ipf.h"
+#include "netinet/ipl.h"
+
+#define	PRINTF	(void)printf
+#define	FPRINTF	(void)fprintf
+
+
+ip_pool_t *printpool_live(pool, fd, name, opts)
+ip_pool_t *pool;
+int fd;
+char *name;
+int opts;
+{
+	ip_pool_node_t entry, *top, *node;
+	ipflookupiter_t iter;
+	int i, printed, last;
+	ipfobj_t obj;
+
+	if ((name != NULL) && strncmp(name, pool->ipo_name, FR_GROUPLEN))
+		return pool->ipo_next;
+
+	printpooldata(pool, opts);
+
+	if ((opts & OPT_DEBUG) == 0)
+		PRINTF("\t{");
+
+	obj.ipfo_rev = IPFILTER_VERSION;
+	obj.ipfo_type = IPFOBJ_LOOKUPITER;
+	obj.ipfo_ptr = &iter;
+	obj.ipfo_size = sizeof(iter);
+
+	iter.ili_data = &entry;
+	iter.ili_type = IPLT_POOL;
+	iter.ili_otype = IPFLOOKUPITER_NODE;
+	iter.ili_ival = IPFGENITER_LOOKUP;
+	iter.ili_unit = pool->ipo_unit;
+	strncpy(iter.ili_name, pool->ipo_name, FR_GROUPLEN);
+
+	last = 0;
+	top = NULL;
+
+	while (!last && (ioctl(fd, SIOCLOOKUPITER, &obj) == 0)) {
+		if (entry.ipn_next == NULL)
+			last = 1;
+		entry.ipn_next = top;
+		top = malloc(sizeof(*top));
+		if (top == NULL)
+			break;
+		bcopy(&entry, top, sizeof(entry));
+	}
+
+	while (top != NULL) {
+		node = top;
+		(void) printpoolnode(node, opts);
+		top = node->ipn_next;
+		free(node);
+		printed++;
+
+		if ((opts & OPT_DEBUG) == 0)
+			putchar(';');
+	}
+
+	if (printed == 0)
+		putchar(';');
+
+	if ((opts & OPT_DEBUG) == 0)
+		PRINTF(" };\n");
+	return pool->ipo_next;
+}
diff --git a/usr/src/cmd/ipf/lib/common/printpooldata.c b/usr/src/cmd/ipf/lib/common/printpooldata.c
new file mode 100644
index 0000000..a699af6
--- /dev/null
+++ b/usr/src/cmd/ipf/lib/common/printpooldata.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2002 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include "ipf.h"
+
+#define	PRINTF	(void)printf
+#define	FPRINTF	(void)fprintf
+
+void printpooldata(pool, opts)
+ip_pool_t *pool;
+int opts;
+{
+
+	if ((opts & OPT_DEBUG) == 0) {
+		if ((pool->ipo_flags & IPOOL_ANON) != 0)
+			PRINTF("# 'anonymous' tree %s\n", pool->ipo_name);
+		PRINTF("table role = ");
+	} else {
+		PRINTF("Name: %s", pool->ipo_name);
+		if ((pool->ipo_flags & IPOOL_ANON) == IPOOL_ANON)
+			PRINTF("(anon)");
+		putchar(' ');
+		PRINTF("Role: ");
+	}
+
+	switch (pool->ipo_unit)
+	{
+	case IPL_LOGIPF :
+		PRINTF("ipf");
+		break;
+	case IPL_LOGNAT :
+		PRINTF("nat");
+		break;
+	case IPL_LOGSTATE :
+		PRINTF("state");
+		break;
+	case IPL_LOGAUTH :
+		PRINTF("auth");
+		break;
+	case IPL_LOGSYNC :
+		PRINTF("sync");
+		break;
+	case IPL_LOGSCAN :
+		PRINTF("scan");
+		break;
+	case IPL_LOGLOOKUP :
+		PRINTF("lookup");
+		break;
+	case IPL_LOGCOUNT :
+		PRINTF("count");
+		break;
+	default :
+		PRINTF("unknown(%d)", pool->ipo_unit);
+	}
+
+	if ((opts & OPT_DEBUG) == 0) {
+		PRINTF(" type = tree number = %s\n", pool->ipo_name);
+	} else {
+		putchar(' ');
+
+		PRINTF("\tReferences: %d\tHits: %lu\n", pool->ipo_ref,
+			pool->ipo_hits);
+		PRINTF("\tNodes Starting at %p\n", pool->ipo_list);
+	}
+}
diff --git a/usr/src/cmd/ipf/svc/ipfilter b/usr/src/cmd/ipf/svc/ipfilter
index 43d25c4..0709018 100644
--- a/usr/src/cmd/ipf/svc/ipfilter
+++ b/usr/src/cmd/ipf/svc/ipfilter
@@ -22,7 +22,7 @@
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -36,11 +36,12 @@
 IPPOOLCONF=/etc/ipf/ippool.conf
 PFILCHECKED=no
 
+zone=`smf_zonename`
 ipfid=`/usr/sbin/modinfo 2>&1 | awk '/ipf/ { print $1 } ' - 2>/dev/null`
 if [ -f $PIDFILE ] ; then
 	pid=`cat $PIDFILE 2>/dev/null`
 else
-	pid=`pgrep ipmon`
+	pid=`pgrep -z $zone ipmon`
 fi
 
 logmsg()
diff --git a/usr/src/cmd/ipf/tools/Makefile.tools b/usr/src/cmd/ipf/tools/Makefile.tools
index e346756..2cb3585 100644
--- a/usr/src/cmd/ipf/tools/Makefile.tools
+++ b/usr/src/cmd/ipf/tools/Makefile.tools
@@ -1,5 +1,25 @@
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #
@@ -48,7 +68,7 @@
 ipfstat		:=	LDLIBS += -lsocket -lnsl -lkvm -lelf
 ipmon		:=	LDLIBS += -lsocket -lnsl
 ipnat		:=	LDLIBS += -lsocket -lnsl -lkvm -lelf
-ippool		:=	LDLIBS += -lsocket -lnsl -lkvm
+ippool		:=	LDLIBS += -lsocket -lnsl -lkvm -lelf
 
 CLEANFILES	+= $(OBJS)
 
diff --git a/usr/src/cmd/ipf/tools/ip_fil.c b/usr/src/cmd/ipf/tools/ip_fil.c
index 4aaa993..daf170f 100644
--- a/usr/src/cmd/ipf/tools/ip_fil.c
+++ b/usr/src/cmd/ipf/tools/ip_fil.c
@@ -3,7 +3,7 @@
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -68,6 +68,7 @@
 #include <stdlib.h>
 #include <ctype.h>
 #include <fcntl.h>
+#include <sys/zone.h>
 #include <arpa/inet.h>
 
 #ifdef __hpux
@@ -133,6 +134,7 @@
 #ifdef IPFILTER_COMPILED
 # include "netinet/ip_rules.h"
 #endif
+#include "netinet/ipf_stack.h"
 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
 # include <sys/malloc.h>
 #endif
@@ -150,7 +152,7 @@
 static	struct	ifnet **ifneta = NULL;
 static	int	nifs = 0;
 
-static	int	frzerostats __P((caddr_t));
+static	int	frzerostats __P((caddr_t, ipf_stack_t *ifs));
 static	void	fr_setifpaddr __P((struct ifnet *, char *));
 void	init_ifp __P((void));
 #if defined(__sgi) && (IRIX < 60500)
@@ -173,32 +175,36 @@
 #endif
 
 
-int iplattach()
+int iplattach(ifs, ns)
+ipf_stack_t *ifs;
+netstack_t *ns;
 {
-	fr_running = 1;
+	ifs->ifs_fr_running = 1;
 	return 0;
 }
 
 
-int ipldetach()
+int ipldetach(ifs)
+ipf_stack_t *ifs;
 {
-	fr_running = -1;
+	ifs->ifs_fr_running = -1;
 	return 0;
 }
 
 
-static	int	frzerostats(data)
+static	int	frzerostats(data, ifs)
 caddr_t	data;
+ipf_stack_t *ifs;
 {
 	friostat_t fio;
 	int error;
 
-	fr_getstat(&fio);
+	fr_getstat(&fio, ifs);
 	error = copyoutptr(&fio, data, sizeof(fio));
 	if (error)
 		return EFAULT;
 
-	bzero((char *)frstats, sizeof(*frstats) * 2);
+	bzero((char *)ifs->ifs_frstats, sizeof(*ifs->ifs_frstats) * 2);
 
 	return 0;
 }
@@ -213,41 +219,46 @@
 caddr_t data;
 int mode;
 {
-	int error = 0, unit = 0, tmp;
+	int error = 0, unit = 0, tmp, uid;
 	friostat_t fio;
+	ipf_stack_t *ifs;
+	extern ipf_stack_t *get_ifs();
 
 	unit = dev;
+	uid = getuid();
+
+	ifs = get_ifs();
 
 	SPL_NET(s);
 
 	if (unit == IPL_LOGNAT) {
-		if (fr_running > 0)
-			error = fr_nat_ioctl(data, cmd, mode);
+		if (ifs->ifs_fr_running > 0)
+			error = fr_nat_ioctl(data, cmd, mode, uid, NULL, ifs);
 		else
 			error = EIO;
 		SPL_X(s);
 		return error;
 	}
 	if (unit == IPL_LOGSTATE) {
-		if (fr_running > 0)
-			error = fr_state_ioctl(data, cmd, mode);
+		if (ifs->ifs_fr_running > 0)
+			error = fr_state_ioctl(data, cmd, mode, uid, NULL, ifs);
 		else
 			error = EIO;
 		SPL_X(s);
 		return error;
 	}
 	if (unit == IPL_LOGAUTH) {
-		if (fr_running > 0) {
+		if (ifs->ifs_fr_running > 0) {
 			if ((cmd == (ioctlcmd_t)SIOCADAFR) ||
 			    (cmd == (ioctlcmd_t)SIOCRMAFR)) {
 				if (!(mode & FWRITE)) {
 					error = EPERM;
 				} else {
 					error = frrequest(unit, cmd, data,
-							  fr_active, 1);
+					    ifs->ifs_fr_active, 1, ifs);
 				}
 			} else {
-				error = fr_auth_ioctl(data, mode, cmd);
+				error = fr_auth_ioctl(data, mode, cmd, uid, NULL, ifs);
 			}
 		} else
 			error = EIO;
@@ -256,7 +267,7 @@
 	}
 	if (unit == IPL_LOGSYNC) {
 #ifdef	IPFILTER_SYNC
-		if (fr_running > 0)
+		if (ifs->ifs_fr_running > 0)
 			error = fr_sync_ioctl(data, cmd, mode);
 		else
 #endif
@@ -266,7 +277,7 @@
 	}
 	if (unit == IPL_LOGSCAN) {
 #ifdef	IPFILTER_SCAN
-		if (fr_running > 0)
+		if (ifs->ifs_fr_running > 0)
 			error = fr_scan_ioctl(data, cmd, mode);
 		else
 #endif
@@ -275,8 +286,9 @@
 		return error;
 	}
 	if (unit == IPL_LOGLOOKUP) {
-		if (fr_running > 0)
-			error = ip_lookup_ioctl(data, cmd, mode);
+		if (ifs->ifs_fr_running > 0)
+			error = ip_lookup_ioctl(data, cmd, mode, uid,
+			    NULL, ifs);
 		else
 			error = EIO;
 		SPL_X(s);
@@ -287,8 +299,8 @@
 	{
 	case FIONREAD :
 #ifdef IPFILTER_LOG
-		error = COPYOUT(&iplused[IPL_LOGIPF], (caddr_t)data,
-			       sizeof(iplused[IPL_LOGIPF]));
+		error = COPYOUT(&ifs->ifs_iplused[IPL_LOGIPF], (caddr_t)data,
+			       sizeof(ifs->ifs_iplused[IPL_LOGIPF]));
 #endif
 		break;
 	case SIOCFRENB :
@@ -299,9 +311,9 @@
 			if (error)
 				break;
 			if (tmp)
-				error = iplattach();
+				error = iplattach(ifs, NULL);
 			else
-				error = ipldetach();
+				error = ipldetach(ifs);
 		}
 		break;
 	case SIOCIPFSET :
@@ -311,16 +323,18 @@
 		}
 	case SIOCIPFGETNEXT :
 	case SIOCIPFGET :
-		error = fr_ipftune(cmd, (void *)data);
+		error = fr_ipftune(cmd, (void *)data, ifs);
 		break;
 	case SIOCSETFF :
 		if (!(mode & FWRITE))
 			error = EPERM;
 		else
-			error = COPYIN(data, &fr_flags, sizeof(fr_flags));
+			error = COPYIN(data, &ifs->ifs_fr_flags,
+			    sizeof(ifs->ifs_fr_flags));
 		break;
 	case SIOCGETFF :
-		error = COPYOUT(&fr_flags, data, sizeof(fr_flags));
+		error = COPYOUT(&ifs->ifs_fr_flags, data,
+		    sizeof(ifs->ifs_fr_flags));
 		break;
 	case SIOCFUNCL :
 		error = fr_resolvefunc(data);
@@ -332,7 +346,8 @@
 		if (!(mode & FWRITE))
 			error = EPERM;
 		else
-			error = frrequest(unit, cmd, data, fr_active, 1);
+			error = frrequest(unit, cmd, data,
+			    ifs->ifs_fr_active, 1, ifs);
 		break;
 	case SIOCINIFR :
 	case SIOCRMIFR :
@@ -340,26 +355,28 @@
 		if (!(mode & FWRITE))
 			error = EPERM;
 		else
-			error = frrequest(unit, cmd, data, 1 - fr_active, 1);
+			error = frrequest(unit, cmd, data,
+			    1 - ifs->ifs_fr_active, 1, ifs);
 		break;
 	case SIOCSWAPA :
 		if (!(mode & FWRITE))
 			error = EPERM;
 		else {
-			bzero((char *)frcache, sizeof(frcache[0]) * 2);
-			*(u_int *)data = fr_active;
-			fr_active = 1 - fr_active;
+			bzero((char *)ifs->ifs_frcache,
+			    sizeof(ifs->ifs_frcache[0]) * 2);
+			*(u_int *)data = ifs->ifs_fr_active;
+			ifs->ifs_fr_active = 1 - ifs->ifs_fr_active;
 		}
 		break;
 	case SIOCGETFS :
-		fr_getstat(&fio);
+		fr_getstat(&fio, ifs);
 		error = fr_outobj(data, &fio, IPFOBJ_IPFSTAT);
 		break;
 	case	SIOCFRZST :
 		if (!(mode & FWRITE))
 			error = EPERM;
 		else
-			error = frzerostats(data);
+			error = frzerostats(data, ifs);
 		break;
 	case	SIOCIPFFL :
 		if (!(mode & FWRITE))
@@ -367,7 +384,7 @@
 		else {
 			error = COPYIN(data, &tmp, sizeof(tmp));
 			if (!error) {
-				tmp = frflush(unit, 4, tmp);
+				tmp = frflush(unit, 4, tmp, ifs);
 				error = COPYOUT(&tmp, data, sizeof(tmp));
 			}
 		}
@@ -379,7 +396,7 @@
 		else {
 			error = COPYIN(data, &tmp, sizeof(tmp));
 			if (!error) {
-				tmp = frflush(unit, 6, tmp);
+				tmp = frflush(unit, 6, tmp, ifs);
 				error = COPYOUT(&tmp, data, sizeof(tmp));
 			}
 		}
@@ -388,10 +405,10 @@
 	case SIOCSTLCK :
 		error = COPYIN(data, &tmp, sizeof(tmp));
 		if (error == 0) {
-			fr_state_lock = tmp;
-			fr_nat_lock = tmp;
-			fr_frag_lock = tmp;
-			fr_auth_lock = tmp;
+			ifs->ifs_fr_state_lock = tmp;
+			ifs->ifs_fr_nat_lock = tmp;
+			ifs->ifs_fr_frag_lock = tmp;
+			ifs->ifs_fr_auth_lock = tmp;
 		} else
 			error = EFAULT;
 		break;
@@ -400,17 +417,17 @@
 		if (!(mode & FWRITE))
 			error = EPERM;
 		else
-			*(int *)data = ipflog_clear(unit);
+			*(int *)data = ipflog_clear(unit, ifs);
 		break;
 #endif /* IPFILTER_LOG */
 	case SIOCGFRST :
-		error = fr_outobj(data, fr_fragstats(), IPFOBJ_FRAGSTAT);
+		error = fr_outobj(data, fr_fragstats(ifs), IPFOBJ_FRAGSTAT);
 		break;
 	case SIOCFRSYN :
 		if (!(mode & FWRITE))
 			error = EPERM;
 		else {
-			frsync(IPFSYNC_RESYNC, IPFSYNC_RESYNC, NULL, NULL);
+			frsync(IPFSYNC_RESYNC, IPFSYNC_RESYNC, NULL, NULL, ifs);
 		}
 		break;
 	default :
@@ -422,51 +439,61 @@
 }
 
 
-void fr_forgetifp(ifp)
+void fr_forgetifp(ifp, ifs)
 void *ifp;
+ipf_stack_t *ifs;
 {
 	register frentry_t *f;
 
-	WRITE_ENTER(&ipf_mutex);
-	for (f = ipacct[0][fr_active]; (f != NULL); f = f->fr_next)
+	WRITE_ENTER(&ifs->ifs_ipf_mutex);
+	for (f = ifs->ifs_ipacct[0][ifs->ifs_fr_active]; (f != NULL);
+	    f = f->fr_next)
 		if (f->fr_ifa == ifp)
 			f->fr_ifa = (void *)-1;
-	for (f = ipacct[1][fr_active]; (f != NULL); f = f->fr_next)
+	for (f = ifs->ifs_ipacct[1][ifs->ifs_fr_active]; (f != NULL);
+	    f = f->fr_next)
 		if (f->fr_ifa == ifp)
 			f->fr_ifa = (void *)-1;
-	for (f = ipfilter[0][fr_active]; (f != NULL); f = f->fr_next)
+	for (f = ifs->ifs_ipfilter[0][ifs->ifs_fr_active]; (f != NULL);
+	    f = f->fr_next)
 		if (f->fr_ifa == ifp)
 			f->fr_ifa = (void *)-1;
-	for (f = ipfilter[1][fr_active]; (f != NULL); f = f->fr_next)
+	for (f = ifs->ifs_ipfilter[1][ifs->ifs_fr_active]; (f != NULL);
+	    f = f->fr_next)
 		if (f->fr_ifa == ifp)
 			f->fr_ifa = (void *)-1;
 #ifdef	USE_INET6
-	for (f = ipacct6[0][fr_active]; (f != NULL); f = f->fr_next)
+	for (f = ifs->ifs_ipacct6[0][ifs->ifs_fr_active]; (f != NULL);
+	    f = f->fr_next)
 		if (f->fr_ifa == ifp)
 			f->fr_ifa = (void *)-1;
-	for (f = ipacct6[1][fr_active]; (f != NULL); f = f->fr_next)
+	for (f = ifs->ifs_ipacct6[1][ifs->ifs_fr_active]; (f != NULL);
+	    f = f->fr_next)
 		if (f->fr_ifa == ifp)
 			f->fr_ifa = (void *)-1;
-	for (f = ipfilter6[0][fr_active]; (f != NULL); f = f->fr_next)
+	for (f = ifs->ifs_ipfilter6[0][ifs->ifs_fr_active]; (f != NULL);
+	    f = f->fr_next)
 		if (f->fr_ifa == ifp)
 			f->fr_ifa = (void *)-1;
-	for (f = ipfilter6[1][fr_active]; (f != NULL); f = f->fr_next)
+	for (f = ifs->ifs_ipfilter6[1][ifs->ifs_fr_active]; (f != NULL);
+	    f = f->fr_next)
 		if (f->fr_ifa == ifp)
 			f->fr_ifa = (void *)-1;
 #endif
-	RWLOCK_EXIT(&ipf_mutex);
-	fr_natifpsync(IPFSYNC_OLDIFP, ifp, NULL);
+	RWLOCK_EXIT(&ifs->ifs_ipf_mutex);
+	fr_natifpsync(IPFSYNC_OLDIFP, ifp, NULL, ifs);
 }
 
 
-void fr_resolvedest(fdp, v)
+void fr_resolvedest(fdp, v, ifs)
 frdest_t *fdp;
 int v;
+ipf_stack_t *ifs;
 {
 	fdp->fd_ifp = NULL;
 
 	if (*fdp->fd_ifname) {
-		fdp->fd_ifp = GETIFP(fdp->fd_ifname, v);
+		fdp->fd_ifp = GETIFP(fdp->fd_ifname, v, ifs);
 		if (!fdp->fd_ifp)
 			fdp->fd_ifp = (struct ifnet *)-1;
 	}
@@ -579,9 +606,11 @@
 	}
 }
 
-struct ifnet *get_unit(name, v)
+/*ARGSUSED*/
+struct ifnet *get_unit(name, v, ifs)
 char *name;
 int v;
+ipf_stack_t *ifs;
 {
 	struct ifnet *ifp, **ifpp, **old_ifneta;
 	char *addr;
@@ -781,10 +810,11 @@
 }
 
 
-void frsync(command, version, nic, data)
+void frsync(command, version, nic, data, ifs)
 int command, version;
 void *nic;
 char *data;
+ipf_stack_t *ifs;
 {
 	return;
 }
@@ -897,10 +927,11 @@
 {
 	static u_short ipid = 0;
 	u_short id;
+	ipf_stack_t *ifs = fin->fin_ifs;
 
-	MUTEX_ENTER(&ipf_rw);
+	MUTEX_ENTER(&ifs->ifs_ipf_rw);
 	id = ipid++;
-	MUTEX_EXIT(&ipf_rw);
+	MUTEX_EXIT(&ifs->ifs_ipf_rw);
 
 	return id;
 }
@@ -957,10 +988,11 @@
 /*
  * return the first IP Address associated with an interface
  */
-int fr_ifpaddr(v, atype, ifptr, inp, inpmask)
+int fr_ifpaddr(v, atype, ifptr, inp, inpmask, ifs)
 int v, atype;
 void *ifptr;
 struct in_addr *inp, *inpmask;
+ipf_stack_t *ifs;
 {
 	struct ifnet *ifp = ifptr;
 #ifdef __sgi
diff --git a/usr/src/cmd/ipf/tools/ipfstat.c b/usr/src/cmd/ipf/tools/ipfstat.c
index b2f3195..de7d9c9 100644
--- a/usr/src/cmd/ipf/tools/ipfstat.c
+++ b/usr/src/cmd/ipf/tools/ipfstat.c
@@ -3,7 +3,7 @@
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -143,6 +143,8 @@
 static	void	showauthstates __P((fr_authstat_t *));
 static	void	showgroups __P((friostat_t *));
 static	void	usage __P((char *));
+static	void	printlivelist __P((int, int, frentry_t *, char *, char *));
+static	void	printdeadlist __P((int, int, frentry_t *, char *, char *));
 static	void	printlist __P((frentry_t *, char *));
 static	void	parse_ipportstr __P((const char *, i6addr_t *, int *));
 static	void	ipfstate_live __P((char *, friostat_t **, ips_stat_t **,
@@ -261,13 +263,12 @@
 	if (kern != NULL || memf != NULL) {
 		(void)setgid(getgid());
 		(void)setreuid(getuid(), getuid());
+		if (openkmem(kern, memf) == -1)
+			exit(-1);
 	}
 
 	if (live_kernel == 1)
 		(void) checkrev(device);
-	if (openkmem(kern, memf) == -1)
-		exit(-1);
-
 	(void)setgid(getgid());
 	(void)setreuid(getuid(), getuid());
 
@@ -778,21 +779,52 @@
 /*
  * Print out a list of rules from the kernel, starting at the one passed.
  */
-static void printlist(fp, comment)
+static void printlivelist(out, set, fp, group, comment)
+int out, set;
 frentry_t *fp;
-char *comment;
+char *group, *comment;
 {
+	frgroup_t *grtop, *grtail, *g;
 	struct	frentry	fb, *fg;
-	char	*data;
-	u_32_t	type;
 	int	n;
+	ipfruleiter_t rule;
+	ipfobj_t obj;
 
-	for (n = 1; fp; n++) {
-		if (kmemcpy((char *)&fb, (u_long)fp, sizeof(fb)) == -1) {
-			perror("kmemcpy");
+	fb.fr_next = fp;
+	n = 0;
+
+	grtop = NULL;
+	grtail = NULL;
+	rule.iri_ver = use_inet6? AF_INET6 : AF_INET;
+	rule.iri_inout = out;
+	rule.iri_active = set;
+	rule.iri_rule = &fb;
+	if (group != NULL)
+		strncpy(rule.iri_group, group, FR_GROUPLEN);
+	else
+		rule.iri_group[0] = '\0';
+
+	bzero((char *)&obj, sizeof(obj));
+	obj.ipfo_rev = IPFILTER_VERSION;
+	obj.ipfo_type = IPFOBJ_IPFITER;
+	obj.ipfo_size = sizeof(rule);
+	obj.ipfo_ptr = &rule;
+
+	do {
+		u_long array[1000];
+
+		memset(array, 0xff, sizeof(array));
+		fp = (frentry_t *)array;
+		rule.iri_rule = fp;
+		if (ioctl(ipf_fd, SIOCIPFITER, &obj) == -1) {
+			perror("ioctl(SIOCIPFITER)");
 			return;
 		}
-		fp = &fb;
+		if (fp->fr_data != NULL)
+			fp->fr_data = (char *)fp + sizeof(*fp);
+
+		n++;
+
 		if (opts & (OPT_HITS|OPT_VERBOSE))
 #ifdef	USE_QUAD_T
 			PRINTF("%qu ", (unsigned long long) fp->fr_hits);
@@ -807,24 +839,6 @@
 #endif
 		if (opts & OPT_SHOWLINENO)
 			PRINTF("@%d ", n);
-		data = NULL;
-		type = fp->fr_type & ~FR_T_BUILTIN;
-		if (type == FR_T_IPF || type == FR_T_BPFOPC) {
-			if (fp->fr_dsize) {
-				data = malloc(fp->fr_dsize);
-				if (data == NULL) {
-					perror("malloc");
-					exit(1);
-				}
-
-				if (kmemcpy(data, (u_long)fp->fr_data,
-					    fp->fr_dsize) == -1) {
-					perror("kmemcpy");
-					return;
-				}
-				fp->fr_data = data;
-			}
-		}
 
 		printfr(fp, ioctl);
 		if (opts & OPT_DEBUG) {
@@ -832,20 +846,125 @@
 			if (fp->fr_data != NULL && fp->fr_dsize > 0)
 				binprint(fp->fr_data, fp->fr_dsize);
 		}
-		if (data != NULL)
-			free(data);
-		if (fp->fr_grp != NULL) {
-			if (!kmemcpy((char *)&fg, (u_long)fp->fr_grp,
-				     sizeof(fg)))
-				printlist(fg, comment);
+
+		if (fp->fr_grhead[0] != '\0') {
+			g = calloc(1, sizeof(*g));
+
+			if (g != NULL) {
+				strncpy(g->fg_name, fp->fr_grhead,
+					FR_GROUPLEN);
+				if (grtop == NULL) {
+					grtop = g;
+					grtail = g;
+				} else {
+					grtail->fg_next = g;
+					grtail = g;
+				}
+			}
 		}
-		if (type == FR_T_CALLFUNC) {
-			printlist(fp->fr_data, "# callfunc: ");
-		}
-		fp = fp->fr_next;
+	} while (fp->fr_next != NULL);
+
+	while ((g = grtop) != NULL) {
+		printlivelist(out, set, NULL, g->fg_name, comment);
+		grtop = g->fg_next;
+		free(g);
 	}
 }
 
+
+static void printdeadlist(out, set, fp, group, comment)
+int out, set;
+frentry_t *fp;
+char *group, *comment;
+{
+	frgroup_t *grtop, *grtail, *g;
+	struct	frentry	fb, *fg;
+	char	*data;
+	u_32_t	type;
+	int	n;
+
+	fb.fr_next = fp;
+	n = 0;
+	grtop = NULL;
+	grtail = NULL;
+
+	do {
+		fp = fb.fr_next;
+		if (kmemcpy((char *)&fb, (u_long)fb.fr_next,
+			    sizeof(fb)) == -1) {
+			perror("kmemcpy");
+			return;
+		}
+
+		data = NULL;
+		type = fb.fr_type & ~FR_T_BUILTIN;
+		if (type == FR_T_IPF || type == FR_T_BPFOPC) {
+			if (fb.fr_dsize) {
+				data = malloc(fb.fr_dsize);
+
+				if (kmemcpy(data, (u_long)fb.fr_data,
+					    fb.fr_dsize) == -1) {
+					perror("kmemcpy");
+					return;
+				}
+				fb.fr_data = data;
+			}
+		}
+
+		n++;
+
+		if (opts & (OPT_HITS|OPT_VERBOSE))
+#ifdef	USE_QUAD_T
+			PRINTF("%qu ", (unsigned long long) fb.fr_hits);
+#else
+			PRINTF("%lu ", fb.fr_hits);
+#endif
+		if (opts & (OPT_ACCNT|OPT_VERBOSE))
+#ifdef	USE_QUAD_T
+			PRINTF("%qu ", (unsigned long long) fb.fr_bytes);
+#else
+			PRINTF("%lu ", fb.fr_bytes);
+#endif
+		if (opts & OPT_SHOWLINENO)
+			PRINTF("@%d ", n);
+
+		printfr(fp, ioctl);
+		if (opts & OPT_DEBUG) {
+			binprint(fp, sizeof(*fp));
+			if (fb.fr_data != NULL && fb.fr_dsize > 0)
+				binprint(fb.fr_data, fb.fr_dsize);
+		}
+		if (data != NULL)
+			free(data);
+		if (fb.fr_grhead[0] != '\0') {
+			g = calloc(1, sizeof(*g));
+
+			if (g != NULL) {
+				strncpy(g->fg_name, fb.fr_grhead,
+					FR_GROUPLEN);
+				if (grtop == NULL) {
+					grtop = g;
+					grtail = g;
+				} else {
+					grtail->fg_next = g;
+					grtail = g;
+				}
+			}
+		}
+		if (type == FR_T_CALLFUNC) {
+			printdeadlist(out, set, fb.fr_data, group,
+				      "# callfunc: ");
+		}
+	} while (fb.fr_next != NULL);
+
+	while ((g = grtop) != NULL) {
+		printdeadlist(out, set, NULL, g->fg_name, comment);
+		grtop = g->fg_next;
+		free(g);
+	}
+}
+
+
 /*
  * print out all of the asked for rule sets, using the stats struct as
  * the base from which to get the pointers.
@@ -908,7 +1027,10 @@
 			(opts & OPT_INACTIVE) ? "inactive " : "", filters[i]);
 		return;
 	}
-	printlist(fp, NULL);
+	if (live_kernel == 1)
+		printlivelist(i, set, fp, NULL, NULL);
+	else
+		printdeadlist(i, set, fp, NULL, NULL);
 }
 
 
diff --git a/usr/src/cmd/ipf/tools/ipftest.c b/usr/src/cmd/ipf/tools/ipftest.c
index e523386..37b47b6 100644
--- a/usr/src/cmd/ipf/tools/ipftest.c
+++ b/usr/src/cmd/ipf/tools/ipftest.c
@@ -3,7 +3,7 @@
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -22,14 +22,9 @@
 extern	char	*optarg;
 extern	struct frentry	*ipfilter[2][2];
 extern	struct ipread	snoop, etherf, tcpd, pcap, iptext, iphex;
-extern	struct ifnet	*get_unit __P((char *, int));
+extern	struct ifnet	*get_unit __P((char *, int, ipf_stack_t *));
 extern	void	init_ifp __P((void));
-extern	int	fr_running;
 
-ipfmutex_t	ipl_mutex, ipf_authmx, ipf_rw, ipf_stinsert;
-ipfmutex_t	ipf_nat_new, ipf_natio, ipf_timeoutlock;
-ipfrwlock_t	ipf_mutex, ipf_global, ipf_ipidfrag, ip_poolrw, ipf_frcache;
-ipfrwlock_t	ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth;
 int	opts = OPT_DONOTHING;
 int	use_inet6 = 0;
 int	pfil_delayed_copy = 0;
@@ -37,12 +32,16 @@
 int	loadrules __P((char *, int));
 int	kmemcpy __P((char *, long, int));
 int     kstrncpy __P((char *, long, int n));
-void	dumpnat __P((void));
-void	dumpstate __P((void));
-void	dumplookups __P((void));
-void	dumpgroups __P((void));
-void	drain_log __P((char *));
+void	dumpnat __P((ipf_stack_t *ifs));
+void	dumpstate __P((ipf_stack_t *ifs));
+void	dumplookups __P((ipf_stack_t *ifs));
+void	dumpgroups __P((ipf_stack_t *ifs));
+void	drain_log __P((char *, ipf_stack_t *ifs));
 void	fixv4sums __P((mb_t *, ip_t *));
+ipf_stack_t *get_ifs __P((void));
+ipf_stack_t *create_ifs __P((void));
+netstack_t *create_ns __P((void));
+
 
 #if defined(__NetBSD__) || defined(__OpenBSD__) || SOLARIS || \
 	(_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) || \
@@ -84,6 +83,8 @@
 	struct	ipread	*r;
 	mb_t	mb, *m;
 	ip_t	*ip;
+	ipf_stack_t *ifs;
+	netstack_t *ns;
 
 	m = &mb;
 	dir = 0;
@@ -96,17 +97,34 @@
 	ifname = "anon0";
 	datain = NULL;
 
-	MUTEX_INIT(&ipf_rw, "ipf rw mutex");
-	MUTEX_INIT(&ipf_timeoutlock, "ipf timeout lock");
-	RWLOCK_INIT(&ipf_global, "ipf filter load/unload mutex");
-	RWLOCK_INIT(&ipf_mutex, "ipf filter rwlock");
-	RWLOCK_INIT(&ipf_frcache, "ipf cache rwlock");
-	RWLOCK_INIT(&ipf_ipidfrag, "ipf IP NAT-Frag rwlock");
-
 	initparse();
-	if (fr_initialise() == -1)
-		abort();
-	fr_running = 1;
+	ifs = create_ifs();
+	ns = create_ns();
+	ifs->ifs_netstack = ns;
+
+#if defined(IPFILTER_DEFAULT_BLOCK)
+        ifs->ifs_fr_pass = FR_BLOCK|FR_NOMATCH;
+#else
+        ifs->ifs_fr_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH;
+#endif
+	ipftuneable_alloc(ifs);
+	
+	bzero((char *)ifs->ifs_frcache, sizeof(ifs->ifs_frcache));
+	MUTEX_INIT(&ifs->ifs_ipf_rw, "ipf rw mutex");
+	MUTEX_INIT(&ifs->ifs_ipf_timeoutlock, "ipf timeout lock");
+	RWLOCK_INIT(&ifs->ifs_ipf_global, "ipf filter load/unload mutex");
+	RWLOCK_INIT(&ifs->ifs_ipf_mutex, "ipf filter rwlock");
+	RWLOCK_INIT(&ifs->ifs_ipf_ipidfrag, "ipf IP NAT-Frag rwlock");
+	RWLOCK_INIT(&ifs->ifs_ipf_frcache, "ipf cache rwlock");
+
+	fr_loginit(ifs);
+	fr_authinit(ifs);
+	fr_fraginit(ifs);
+	fr_stateinit(ifs);
+	fr_natinit(ifs);
+	appr_init(ifs);
+	ip_lookup_init(ifs);
+	ifs->ifs_fr_running = 1;
 
 	while ((c = getopt(argc, argv, "6bdDF:i:I:l:N:P:or:RT:vxX")) != -1)
 		switch (c)
@@ -207,7 +225,7 @@
 				    &iface, &dir)) > 0) {
 		if (iface == NULL || *iface == '\0')
 			iface = ifname;
-		ifp = get_unit(iface, IP_V(ip));
+		ifp = get_unit(iface, IP_V(ip), ifs);
 		if (ifp == NULL) {
 			fprintf(stderr, "out of memory\n");
 			exit(1);
@@ -226,7 +244,7 @@
 		/* ipfr_slowtimer(); */
 		m = &mb;
 		m->mb_len = i;
-		i = fr_check(ip, hlen, ifp, dir, &m);
+		i = fr_check(ip, hlen, ifp, dir, &m, ifs);
 		if ((opts & OPT_NAT) == 0)
 			switch (i)
 			{
@@ -294,17 +312,17 @@
 	(*r->r_close)();
 
 	if (logout != NULL) {
-		drain_log(logout);
+		drain_log(logout, ifs);
 	}
 
 	if (dump == 1)  {
-		dumpnat();
-		dumpstate();
-		dumplookups();
-		dumpgroups();
+		dumpnat(ifs);
+		dumpstate(ifs);
+		dumplookups(ifs);
+		dumpgroups(ifs);
 	}
 
-	fr_deinitialise();
+	fr_deinitialise(ifs);
 
 	return 0;
 }
@@ -621,17 +639,18 @@
 /*
  * Display the built up NAT table rules and mapping entries.
  */
-void dumpnat()
+void dumpnat(ifs)
+	ipf_stack_t *ifs;
 {
 	ipnat_t	*ipn;
 	nat_t	*nat;
 
 	printf("List of active MAP/Redirect filters:\n");
-	for (ipn = nat_list; ipn != NULL; ipn = ipn->in_next)
+	for (ipn = ifs->ifs_nat_list; ipn != NULL; ipn = ipn->in_next)
 		printnat(ipn, opts & (OPT_DEBUG|OPT_VERBOSE));
 	printf("\nList of active sessions:\n");
-	for (nat = nat_instances; nat; nat = nat->nat_next) {
-		printactivenat(nat, opts);
+	for (nat = ifs->ifs_nat_instances; nat; nat = nat->nat_next) {
+		printactivenat(nat, opts, 0);
 		if (nat->nat_aps)
 			printaps(nat->nat_aps, opts);
 	}
@@ -641,18 +660,20 @@
 /*
  * Display the built up state table rules and mapping entries.
  */
-void dumpstate()
+void dumpstate(ifs)
+	ipf_stack_t *ifs;
 {
 	ipstate_t *ips;
 
 	printf("List of active state sessions:\n");
-	for (ips = ips_list; ips != NULL; )
+	for (ips = ifs->ifs_ips_list; ips != NULL; )
 		ips = printstate(ips, opts & (OPT_DEBUG|OPT_VERBOSE),
-				 fr_ticks);
+				 ifs->ifs_fr_ticks);
 }
 
 
-void dumplookups()
+void dumplookups(ifs)
+	ipf_stack_t *ifs;
 {
 	iphtable_t *iph;
 	ip_pool_t *ipl;
@@ -660,17 +681,20 @@
 
 	printf("List of configured pools\n");
 	for (i = 0; i < IPL_LOGSIZE; i++)
-		for (ipl = ip_pool_list[i]; ipl != NULL; ipl = ipl->ipo_next)
+		for (ipl = ifs->ifs_ip_pool_list[i]; ipl != NULL;
+		    ipl = ipl->ipo_next)
 			printpool(ipl, bcopywrap, NULL, opts);
 
 	printf("List of configured hash tables\n");
 	for (i = 0; i < IPL_LOGSIZE; i++)
-		for (iph = ipf_htables[i]; iph != NULL; iph = iph->iph_next)
+		for (iph = ifs->ifs_ipf_htables[i]; iph != NULL;
+		     iph = iph->iph_next)
 			printhash(iph, bcopywrap, NULL, opts);
 }
 
 
-void dumpgroups()
+void dumpgroups(ifs)
+	ipf_stack_t *ifs;
 {
 	frgroup_t *fg;
 	frentry_t *fr;
@@ -678,7 +702,8 @@
 
 	printf("List of groups configured (set 0)\n");
 	for (i = 0; i < IPL_LOGSIZE; i++)
-		for (fg =  ipfgroups[i][0]; fg != NULL; fg = fg->fg_next) {
+		for (fg =  ifs->ifs_ipfgroups[i][0]; fg != NULL;
+		    fg = fg->fg_next) {
 			printf("Dev.%d. Group %s Ref %d Flags %#x\n",
 				i, fg->fg_name, fg->fg_ref, fg->fg_flags);
 			for (fr = fg->fg_start; fr != NULL; fr = fr->fr_next) {
@@ -693,7 +718,8 @@
 
 	printf("List of groups configured (set 1)\n");
 	for (i = 0; i < IPL_LOGSIZE; i++)
-		for (fg =  ipfgroups[i][1]; fg != NULL; fg = fg->fg_next) {
+		for (fg =  ifs->ifs_ipfgroups[i][1]; fg != NULL;
+		    fg = fg->fg_next) {
 			printf("Dev.%d. Group %s Ref %d Flags %#x\n",
 				i, fg->fg_name, fg->fg_ref, fg->fg_flags);
 			for (fr = fg->fg_start; fr != NULL; fr = fr->fr_next) {
@@ -708,8 +734,9 @@
 }
 
 
-void drain_log(filename)
+void drain_log(filename, ifs)
 char *filename;
+ipf_stack_t *ifs;
 {
 	char buffer[DEFAULT_IPFLOGSIZE];
 	struct iovec iov;
@@ -735,7 +762,7 @@
 			uio.uio_resid = iov.iov_len;
 			resid = uio.uio_resid;
 
-			if (ipflog_read(i, &uio) == 0) {
+			if (ipflog_read(i, &uio, ifs) == 0) {
 				/*
 				 * If nothing was read then break out.
 				 */
@@ -782,3 +809,35 @@
 		*(u_short *)csump = fr_cksum(m, ip, ip->ip_p, hdr);
 	}
 }
+
+ipf_stack_t *gifs;
+
+/*
+ * Allocate and keep pointer for get_ifs()
+ */
+ipf_stack_t *
+create_ifs()
+{
+	ipf_stack_t *ifs;
+
+	KMALLOCS(ifs, ipf_stack_t *, sizeof (*ifs));
+	bzero(ifs, sizeof (*ifs));
+	gifs = ifs;
+	return (ifs);
+}
+
+ipf_stack_t *
+get_ifs()
+{
+	return (gifs);
+}
+
+netstack_t *
+create_ns()
+{
+	netstack_t *ns;
+
+	KMALLOCS(ns, netstack_t *, sizeof (*ns));
+	bzero(ns, sizeof (*ns));
+	return (ns);
+}
diff --git a/usr/src/cmd/ipf/tools/ipnat.c b/usr/src/cmd/ipf/tools/ipnat.c
index df64e0d..421472e 100644
--- a/usr/src/cmd/ipf/tools/ipnat.c
+++ b/usr/src/cmd/ipf/tools/ipnat.c
@@ -5,7 +5,7 @@
  *
  * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com)
  *
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -83,11 +83,14 @@
 
 extern	char	*optarg;
 
-void	dostats __P((natstat_t *, int)), flushtable __P((int, int));
+void	dostats __P((int, natstat_t *, int, int));
+void	flushtable __P((int, int));
 void	usage __P((char *));
 int	main __P((int, char*[]));
 void	showhostmap __P((natstat_t *nsp));
 void	natstat_dead __P((natstat_t *, char *));
+void	dostats_live __P((int, natstat_t *, int));
+void	showhostmap_live __P((int, natstat_t *));
 
 int	opts;
 
@@ -183,9 +186,10 @@
 
 
 	if (!(opts & OPT_DONOTHING) && (kernel == NULL) && (core == NULL)) {
+#ifdef notdef
 		if (openkmem(kernel, core) == -1)
 			exit(1);
-
+#endif
 		if (((fd = open(IPNAT_NAME, mode)) == -1) &&
 		    ((fd = open(IPNAT_NAME, O_RDONLY)) == -1)) {
 			(void) fprintf(stderr, "%s: open: %s\n", IPNAT_NAME,
@@ -210,7 +214,7 @@
 
 		natstat_dead(nsp, kernel);
 		if (opts & (OPT_LIST|OPT_STAT))
-			dostats(nsp, opts);
+			dostats(fd, nsp, opts, 0);
 		exit(0);
 	}
 
@@ -220,7 +224,7 @@
 		ipnat_parsefile(fd, ipnat_addrule, ioctl, file);
 	}
 	if (opts & (OPT_LIST|OPT_STAT))
-		dostats(nsp, opts);
+		dostats(fd, nsp, opts, 1);
 	return 0;
 }
 
@@ -283,9 +287,9 @@
 /*
  * Display NAT statistics.
  */
-void dostats(nsp, opts)
+void dostats(fd, nsp, opts, alive)
 natstat_t *nsp;
-int opts;
+int fd, opts, alive;
 {
 	nat_t *np, nat;
 	ipnat_t	ipn;
@@ -312,6 +316,10 @@
 	 * Show list of NAT rules and NAT sessions ?
 	 */
 	if (opts & OPT_LIST) {
+		if (alive) {
+			dostats_live(fd, nsp, opts);
+			return;
+		}
 		printf("List of active MAP/Redirect filters:\n");
 		while (nsp->ns_list) {
 			if (kmemcpy((char *)&ipn, (long)nsp->ns_list,
@@ -330,7 +338,7 @@
 		for (np = nsp->ns_instances; np; np = nat.nat_next) {
 			if (kmemcpy((char *)&nat, (long)np, sizeof(nat)))
 				break;
-			printactivenat(&nat, opts);
+			printactivenat(&nat, opts, 0);
 			if (nat.nat_aps)
 				printaps(nat.nat_aps, opts);
 		}
@@ -406,3 +414,87 @@
 			printf("%d entries flushed from NAT list\n", n);
 	}
 }
+
+/*
+ * Display NAT statistics.
+ */
+void dostats_live(fd, nsp, opts)
+natstat_t *nsp;
+int fd, opts;
+{
+	ipfgeniter_t iter;
+	ipfobj_t obj;
+	ipnat_t	ipn;
+	nat_t nat;
+
+	bzero((char *)&obj, sizeof(obj));
+	obj.ipfo_rev = IPFILTER_VERSION;
+	obj.ipfo_type = IPFOBJ_GENITER;
+	obj.ipfo_size = sizeof(iter);
+	obj.ipfo_ptr = &iter;
+
+	iter.igi_type = IPFGENITER_IPNAT;
+	iter.igi_data = &ipn;
+
+	/*
+	 * Show list of NAT rules and NAT sessions ?
+	 */
+	printf("List of active MAP/Redirect filters:\n");
+	while (nsp->ns_list) {
+		if (ioctl(fd, SIOCGENITER, &obj) == -1)
+			break;
+		if (opts & OPT_HITS)
+			printf("%lu ", ipn.in_hits);
+		printnat(&ipn, opts & (OPT_DEBUG|OPT_VERBOSE));
+		nsp->ns_list = ipn.in_next;
+	}
+
+	printf("\nList of active sessions:\n");
+
+	iter.igi_type = IPFGENITER_NAT;
+	iter.igi_data = &nat;
+
+	while (nsp->ns_instances != NULL) {
+		if (ioctl(fd, SIOCGENITER, &obj) == -1)
+			break;
+		printactivenat(&nat, opts, 1);
+		if (nat.nat_aps)
+			printaps(nat.nat_aps, opts);
+		nsp->ns_instances = nat.nat_next;
+	}
+
+	if (opts & OPT_VERBOSE)
+		showhostmap_live(fd, nsp);
+}
+
+/*
+ * Display the active host mapping table.
+ */
+void showhostmap_live(fd, nsp)
+int fd;
+natstat_t *nsp;
+{
+	hostmap_t hm, *hmp;
+	ipfgeniter_t iter;
+	ipfobj_t obj;
+
+	bzero((char *)&obj, sizeof(obj));
+	obj.ipfo_rev = IPFILTER_VERSION;
+	obj.ipfo_type = IPFOBJ_GENITER;
+	obj.ipfo_size = sizeof(iter);
+	obj.ipfo_ptr = &iter;
+
+	iter.igi_type = IPFGENITER_HOSTMAP;
+	iter.igi_data = &hm;
+
+	printf("\nList of active host mappings:\n");
+
+	while (nsp->ns_maplist != NULL) {
+		if (ioctl(fd, SIOCGENITER, &obj) == -1)
+			break;
+		printhostmap(&hm, 0);
+		nsp->ns_maplist = hm.hm_next;
+	}
+}
+
+
diff --git a/usr/src/cmd/ipf/tools/ippool.c b/usr/src/cmd/ipf/tools/ippool.c
index edf6793..5f18379 100644
--- a/usr/src/cmd/ipf/tools/ippool.c
+++ b/usr/src/cmd/ipf/tools/ippool.c
@@ -3,7 +3,7 @@
  *
  * See the IPFILTER.LICENCE file for details on licencing.
  *
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -33,14 +33,15 @@
 #include <netdb.h>
 #include <ctype.h>
 #include <unistd.h>
+#include <nlist.h>
 
 #include "ipf.h"
+#include "netinet/ipl.h"
 #include "netinet/ip_lookup.h"
 #include "netinet/ip_pool.h"
 #include "netinet/ip_htable.h"
 #include "kmem.h"
 
-
 extern	int	ippool_yyparse __P((void));
 extern	int	ippool_yydebug;
 extern	FILE	*ippool_yyin;
@@ -58,6 +59,9 @@
 int	poolstats __P((int, char *[]));
 int	gettype __P((char *, u_int *));
 int	getrole __P((char *));
+void	poollist_dead __P((int, char *, int, char *, char *));
+void	showpools_live(int, int, ip_pool_stat_t *, char *, int);
+void	showhashs_live(int, int, iphtstat_t *, char *, int);
 
 int	opts = 0;
 int	fd = -1;
@@ -418,29 +422,109 @@
 	}
 	op.iplo_unit = role;
 
-	if (openkmem(kernel, core) == -1)
-		exit(-1);
+	if (live_kernel == 0) {
+		poollist_dead(role, poolname, type, kernel, core);
+		return (0);
+	}
 
 	if (type == IPLT_ALL || type == IPLT_POOL) {
 		plstp = &plstat;
 		op.iplo_type = IPLT_POOL;
 		op.iplo_size = sizeof(plstat);
 		op.iplo_struct = &plstat;
-		c = ioctl(fd, SIOCLOOKUPSTAT, &op);
-		if (c == -1) {
-			perror("ioctl(SIOCLOOKUPSTAT)");
-			return -1;
-		}
+		op.iplo_name[0] = '\0';
+		op.iplo_arg = 0;
 
 		if (role != IPL_LOGALL) {
-			ptr = plstp->ipls_list[role];
+			op.iplo_unit = role;
+
+			c = ioctl(fd, SIOCLOOKUPSTAT, &op);
+			if (c == -1) {
+				perror("ioctl(SIOCLOOKUPSTAT)");
+				return -1;
+			}
+
+			showpools_live(fd, role, &plstat, poolname, opts);
+		} else {
+			for (role = 0; role <= IPL_LOGMAX; role++) {
+				op.iplo_unit = role;
+
+				c = ioctl(fd, SIOCLOOKUPSTAT, &op);
+				if (c == -1) {
+					perror("ioctl(SIOCLOOKUPSTAT)");
+					return -1;
+				}
+
+				showpools_live(fd, role, &plstat, poolname, opts);
+			}
+
+			role = IPL_LOGALL;
+		}
+	}
+	if (type == IPLT_ALL || type == IPLT_HASH) {
+		htstp = &htstat;
+		op.iplo_type = IPLT_HASH;
+		op.iplo_size = sizeof(htstat);
+		op.iplo_struct = &htstat;
+		op.iplo_name[0] = '\0';
+		op.iplo_arg = 0;
+
+		if (role != IPL_LOGALL) {
+			op.iplo_unit = role;
+
+			c = ioctl(fd, SIOCLOOKUPSTAT, &op);
+			if (c == -1) {
+				perror("ioctl(SIOCLOOKUPSTAT)");
+				return -1;
+			}
+			showhashs_live(fd, role, &htstat, poolname, opts);
+		} else {
+			for (role = 0; role <= IPL_LOGMAX; role++) {
+
+				op.iplo_unit = role;
+				c = ioctl(fd, SIOCLOOKUPSTAT, &op);
+				if (c == -1) {
+					perror("ioctl(SIOCLOOKUPSTAT)");
+					return -1;
+				}
+
+				showhashs_live(fd, role, &htstat, poolname, opts);
+			}
+		}
+	}
+	return 0;
+}
+
+void poollist_dead(role, poolname, type, kernel, core)
+int role, type;
+char *poolname, *kernel, *core;
+{
+	iphtable_t *hptr;
+	ip_pool_t *ptr;
+
+	if (openkmem(kernel, core) == -1)
+		exit(-1);
+
+	if (type == IPLT_ALL || type == IPLT_POOL) {
+		ip_pool_t *pools[IPL_LOGSIZE];
+		struct nlist names[2] = { { "ip_pool_list" } , { "" } };
+
+		if (nlist(kernel, names) != 1)
+			return;
+
+		bzero(&pools, sizeof(pools));
+		if (kmemcpy((char *)&pools, names[0].n_value, sizeof(pools)))
+			return;
+
+		if (role != IPL_LOGALL) {
+			ptr = pools[role];
 			while (ptr != NULL) {
-				ptr = printpool(ptr, kmemcpywrap, poolname,
-						opts);
+				ptr = printpool(ptr, kmemcpywrap,
+						poolname, opts);
 			}
 		} else {
 			for (role = 0; role <= IPL_LOGMAX; role++) {
-				ptr = plstp->ipls_list[role];
+				ptr = pools[role];
 				while (ptr != NULL) {
 					ptr = printpool(ptr, kmemcpywrap,
 							poolname, opts);
@@ -450,43 +534,69 @@
 		}
 	}
 	if (type == IPLT_ALL || type == IPLT_HASH) {
-		htstp = &htstat;
-		op.iplo_type = IPLT_HASH;
-		op.iplo_size = sizeof(htstat);
-		op.iplo_struct = &htstat;
-		c = ioctl(fd, SIOCLOOKUPSTAT, &op);
-		if (c == -1) {
-			perror("ioctl(SIOCLOOKUPSTAT)");
-			return -1;
-		}
+		iphtable_t *tables[IPL_LOGSIZE];
+		struct nlist names[2] = { { "ipf_htables" } , { "" } };
+
+		if (nlist(kernel, names) != 1)
+			return;
+
+		bzero(&tables, sizeof(tables));
+		if (kmemcpy((char *)&tables, names[0].n_value, sizeof(tables)))
+			return;
 
 		if (role != IPL_LOGALL) {
-			hptr = htstp->iphs_tables;
+			hptr = tables[role];
 			while (hptr != NULL) {
 				hptr = printhash(hptr, kmemcpywrap,
 						 poolname, opts);
 			}
 		} else {
 			for (role = 0; role <= IPL_LOGMAX; role++) {
-				hptr = htstp->iphs_tables;
+				hptr = tables[role];
 				while (hptr != NULL) {
 					hptr = printhash(hptr, kmemcpywrap,
 							 poolname, opts);
 				}
-
-				op.iplo_unit = role;
-				c = ioctl(fd, SIOCLOOKUPSTAT, &op);
-				if (c == -1) {
-					perror("ioctl(SIOCLOOKUPSTAT)");
-					return -1;
-				}
 			}
 		}
 	}
-	return 0;
 }
 
 
+void
+showpools_live(fd, role, plstp, poolname, opts)
+int fd, role;
+ip_pool_stat_t *plstp;
+char *poolname;
+int opts;
+{
+	ipflookupiter_t iter;
+	ip_pool_t pool;
+	ipfobj_t obj;
+
+	obj.ipfo_rev = IPFILTER_VERSION;
+	obj.ipfo_type = IPFOBJ_LOOKUPITER;
+	obj.ipfo_size = sizeof(iter);
+	obj.ipfo_ptr = &iter;
+
+	iter.ili_type = IPLT_POOL;
+	iter.ili_otype = IPFLOOKUPITER_LIST;
+	iter.ili_ival = IPFGENITER_LOOKUP;
+	iter.ili_data = &pool;
+	iter.ili_unit = role;
+	*iter.ili_name = '\0';
+
+	while (plstp->ipls_list[role] != NULL) {
+		if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
+			perror("ioctl(SIOCLOOKUPITER)");
+			break;
+		}
+		(void) printpool_live(&pool, fd, poolname, opts);
+
+		plstp->ipls_list[role] = pool.ipo_next;
+	}
+}
+
 int poolstats(argc, argv)
 int argc;
 char *argv[];
@@ -702,3 +812,37 @@
 	}
 	return type;
 }
+
+void showhashs_live(fd, role, htstp, poolname, opts)
+int fd, role;
+iphtstat_t *htstp;
+char *poolname;
+int opts;
+{
+	ipflookupiter_t iter;
+	iphtable_t table;
+	ipfobj_t obj;
+
+	obj.ipfo_rev = IPFILTER_VERSION;
+	obj.ipfo_type = IPFOBJ_LOOKUPITER;
+	obj.ipfo_size = sizeof(iter);
+	obj.ipfo_ptr = &iter;
+
+	iter.ili_type = IPLT_HASH;
+	iter.ili_otype = IPFLOOKUPITER_LIST;
+	iter.ili_ival = IPFGENITER_LOOKUP;
+	iter.ili_data = &table;
+	iter.ili_unit = role;
+	*iter.ili_name = '\0';
+
+	while (htstp->iphs_tables != NULL) {
+		if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
+			perror("ioctl(SIOCLOOKUPITER)");
+			break;
+		}
+
+		printhash_live(&table, fd, poolname, opts);
+
+		htstp->iphs_tables = table.iph_next;
+	}
+}
diff --git a/usr/src/cmd/mdb/common/modules/genunix/Makefile.files b/usr/src/cmd/mdb/common/modules/genunix/Makefile.files
index b125e5f..c4fa447 100644
--- a/usr/src/cmd/mdb/common/modules/genunix/Makefile.files
+++ b/usr/src/cmd/mdb/common/modules/genunix/Makefile.files
@@ -55,6 +55,7 @@
 	modhash.c	\
 	ndievents.c	\
 	net.c		\
+	netstack.c	\
 	nvpair.c	\
 	pg.c		\
 	rctl.c		\
diff --git a/usr/src/cmd/mdb/common/modules/genunix/genunix.c b/usr/src/cmd/mdb/common/modules/genunix/genunix.c
index 66acba3..decf655 100644
--- a/usr/src/cmd/mdb/common/modules/genunix/genunix.c
+++ b/usr/src/cmd/mdb/common/modules/genunix/genunix.c
@@ -87,6 +87,7 @@
 #include "ndievents.h"
 #include "mmd.h"
 #include "net.h"
+#include "netstack.h"
 #include "nvpair.h"
 #include "ctxop.h"
 #include "tsd.h"
@@ -3418,6 +3419,9 @@
 		"[-t stream | dgram | raw | #] [-p #]",
 		"filter and display sonode", sonode },
 
+	/* from netstack.c */
+	{ "netstack", "", "show stack instances", netstack },
+
 	/* from nvpair.c */
 	{ NVPAIR_DCMD_NAME, NVPAIR_DCMD_USAGE, NVPAIR_DCMD_DESCR,
 		nvpair_print },
@@ -3755,20 +3759,28 @@
 		NULL, modchain_walk_step, NULL },
 
 	/* from net.c */
-	{ "ar", "walk ar_t structures using MI",
-		mi_payload_walk_init, mi_payload_walk_step,
-		mi_payload_walk_fini, &mi_ar_arg },
-	{ "icmp", "walk ICMP control structures using MI",
-		mi_payload_walk_init, mi_payload_walk_step,
-		mi_payload_walk_fini, &mi_icmp_arg },
-	{ "ill", "walk ill_t structures using MI",
-		mi_payload_walk_init, mi_payload_walk_step,
-		mi_payload_walk_fini, &mi_ill_arg },
+	{ "ar", "walk ar_t structures using MI for all stacks",
+		mi_payload_walk_init, mi_payload_walk_step, NULL, &mi_ar_arg },
+	{ "icmp", "walk ICMP control structures using MI for all stacks",
+		mi_payload_walk_init, mi_payload_walk_step, NULL,
+		&mi_icmp_arg },
+	{ "ill", "walk ill_t structures using MI for all stacks",
+		mi_payload_walk_init, mi_payload_walk_step, NULL, &mi_ill_arg },
+
 	{ "mi", "given a MI_O, walk the MI",
 		mi_walk_init, mi_walk_step, mi_walk_fini, NULL },
 	{ "sonode", "given a sonode, walk its children",
 		sonode_walk_init, sonode_walk_step, sonode_walk_fini, NULL },
 
+	{ "ar_stacks", "walk all the ar_stack_t",
+		ar_stacks_walk_init, ar_stacks_walk_step, NULL },
+	{ "icmp_stacks", "walk all the icmp_stack_t",
+		icmp_stacks_walk_init, icmp_stacks_walk_step, NULL },
+	{ "tcp_stacks", "walk all the tcp_stack_t",
+		tcp_stacks_walk_init, tcp_stacks_walk_step, NULL },
+	{ "udp_stacks", "walk all the udp_stack_t",
+		udp_stacks_walk_init, udp_stacks_walk_step, NULL },
+
 	/* from nvpair.c */
 	{ NVPAIR_WALKER_NAME, NVPAIR_WALKER_DESCR,
 		nvpair_walk_init, nvpair_walk_step, NULL },
@@ -3860,6 +3872,10 @@
 		mdi_phci_ph_next_walk_step,
 		mdi_phci_ph_next_walk_fini },
 
+	/* from netstack.c */
+	{ "netstack", "walk a list of kernel netstacks",
+		netstack_walk_init, netstack_walk_step, NULL },
+
 	{ NULL }
 };
 
diff --git a/usr/src/cmd/mdb/common/modules/genunix/net.c b/usr/src/cmd/mdb/common/modules/genunix/net.c
index 0195489..00f295c 100644
--- a/usr/src/cmd/mdb/common/modules/genunix/net.c
+++ b/usr/src/cmd/mdb/common/modules/genunix/net.c
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -51,8 +51,6 @@
 #include <inet/rawip_impl.h>
 #include <inet/mi.h>
 
-#define	MIH2MIO(mihp) (&(mihp)->mh_o)
-
 #define	ADDR_V6_WIDTH	23
 #define	ADDR_V4_WIDTH	15
 
@@ -65,6 +63,104 @@
 
 #define	NETSTAT_FIRST	0x80000000u
 
+
+/* Walkers for various *_stack_t */
+int
+ar_stacks_walk_init(mdb_walk_state_t *wsp)
+{
+	if (mdb_layered_walk("netstack", wsp) == -1) {
+		mdb_warn("can't walk 'netstack'");
+		return (WALK_ERR);
+	}
+	return (WALK_NEXT);
+}
+
+int
+ar_stacks_walk_step(mdb_walk_state_t *wsp)
+{
+	uintptr_t kaddr;
+	netstack_t nss;
+
+	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
+		mdb_warn("can't read netstack at %p", wsp->walk_addr);
+		return (WALK_ERR);
+	}
+	kaddr = (uintptr_t)nss.netstack_modules[NS_ARP];
+	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
+}
+
+int
+icmp_stacks_walk_init(mdb_walk_state_t *wsp)
+{
+	if (mdb_layered_walk("netstack", wsp) == -1) {
+		mdb_warn("can't walk 'netstack'");
+		return (WALK_ERR);
+	}
+	return (WALK_NEXT);
+}
+
+int
+icmp_stacks_walk_step(mdb_walk_state_t *wsp)
+{
+	uintptr_t kaddr;
+	netstack_t nss;
+
+	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
+		mdb_warn("can't read netstack at %p", wsp->walk_addr);
+		return (WALK_ERR);
+	}
+	kaddr = (uintptr_t)nss.netstack_modules[NS_ICMP];
+	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
+}
+
+int
+tcp_stacks_walk_init(mdb_walk_state_t *wsp)
+{
+	if (mdb_layered_walk("netstack", wsp) == -1) {
+		mdb_warn("can't walk 'netstack'");
+		return (WALK_ERR);
+	}
+	return (WALK_NEXT);
+}
+
+int
+tcp_stacks_walk_step(mdb_walk_state_t *wsp)
+{
+	uintptr_t kaddr;
+	netstack_t nss;
+
+	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
+		mdb_warn("can't read netstack at %p", wsp->walk_addr);
+		return (WALK_ERR);
+	}
+	kaddr = (uintptr_t)nss.netstack_modules[NS_TCP];
+	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
+}
+
+int
+udp_stacks_walk_init(mdb_walk_state_t *wsp)
+{
+	if (mdb_layered_walk("netstack", wsp) == -1) {
+		mdb_warn("can't walk 'netstack'");
+		return (WALK_ERR);
+	}
+	return (WALK_NEXT);
+}
+
+int
+udp_stacks_walk_step(mdb_walk_state_t *wsp)
+{
+	uintptr_t kaddr;
+	netstack_t nss;
+
+	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
+		mdb_warn("can't read netstack at %p", wsp->walk_addr);
+		return (WALK_ERR);
+	}
+	kaddr = (uintptr_t)nss.netstack_modules[NS_UDP];
+	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
+}
+
 /*
  * Print an IPv4 address and port number in a compact and easy to read format
  * The arguments are in network byte order
@@ -228,11 +324,14 @@
 		return (WALK_ERR);
 	}
 
-	status = wsp->walk_callback(wsp->walk_addr, miop, wsp->walk_cbdata);
-
 	/* Only true in the first iteration */
-	if (wdp->mi_wd_miofirst == NULL)
+	if (wdp->mi_wd_miofirst == NULL) {
 		wdp->mi_wd_miofirst = wsp->walk_addr;
+		status = WALK_NEXT;
+	} else {
+		status = wsp->walk_callback(wsp->walk_addr + sizeof (MI_O),
+		    &miop[1], wsp->walk_cbdata);
+	}
 
 	wsp->walk_addr = (uintptr_t)miop->mi_o_next;
 	return (status);
@@ -244,21 +343,9 @@
 	mdb_free(wsp->walk_data, sizeof (struct mi_walk_data));
 }
 
-typedef struct mi_payload_walk_data_s {
-	uintptr_t mi_pwd_first;
-	void *mi_pwd_data;
-} mi_payload_walk_data_t;
-
-static void
-delete_mi_payload_walk_data(mi_payload_walk_data_t *pwdp, size_t payload_size)
-{
-	mdb_free(pwdp->mi_pwd_data, payload_size);
-	mdb_free(pwdp, sizeof (mi_payload_walk_data_t));
-}
-
 typedef struct mi_payload_walk_arg_s {
-	const char *mi_pwa_obj;		/* load object of mi_o_head_t * */
-	const char *mi_pwa_sym;		/* symbol name of mi_o_head_t * */
+	const char *mi_pwa_walker;	/* Underlying walker */
+	const off_t mi_pwa_head_off;	/* Offset for mi_o_head_t * in stack */
 	const size_t mi_pwa_size;	/* size of mi payload */
 	const uint_t mi_pwa_flags;	/* device and/or module */
 } mi_payload_walk_arg_t;
@@ -270,45 +357,11 @@
 mi_payload_walk_init(mdb_walk_state_t *wsp)
 {
 	const mi_payload_walk_arg_t *arg = wsp->walk_arg;
-	mi_payload_walk_data_t *pwdp;
-	GElf_Sym sym;
-	mi_head_t *mihp;
 
-	/* Determine the address to start or end the walk with */
-	if (mdb_lookup_by_obj(arg->mi_pwa_obj, arg->mi_pwa_sym, &sym) == -1) {
-		mdb_warn("failed to lookup %s`%s",
-		    arg->mi_pwa_obj, arg->mi_pwa_sym);
+	if (mdb_layered_walk(arg->mi_pwa_walker, wsp) == -1) {
+		mdb_warn("can't walk '%s'", arg->mi_pwa_walker);
 		return (WALK_ERR);
 	}
-
-	if (mdb_vread(&mihp, sizeof (mihp), (uintptr_t)sym.st_value) == -1) {
-		mdb_warn("failed to read address of global MI Head "
-		    "mi_o_head_t at %p", (uintptr_t)sym.st_value);
-		return (WALK_ERR);
-	}
-
-	pwdp = mdb_alloc(sizeof (mi_payload_walk_data_t), UM_SLEEP);
-	pwdp->mi_pwd_data = mdb_alloc(arg->mi_pwa_size, UM_SLEEP);
-	wsp->walk_data = pwdp;
-
-	if (wsp->walk_addr == NULL) {
-		/* Do not immediately return WALK_DONE below */
-		pwdp->mi_pwd_first = NULL;
-		/* We determined where to begin */
-		wsp->walk_addr = (uintptr_t)MIH2MIO(mihp);
-	} else {
-		/* Do not cycle through all of the MI_O objects */
-		pwdp->mi_pwd_first = (uintptr_t)MIH2MIO(mihp);
-		/* We were given where to begin */
-		wsp->walk_addr = (uintptr_t)((MI_OP)wsp->walk_addr - 1);
-	}
-
-	if (mdb_layered_walk("genunix`mi", wsp) == -1) {
-		mdb_warn("failed to walk genunix`mi");
-		delete_mi_payload_walk_data(pwdp, arg->mi_pwa_size);
-		return (WALK_ERR);
-	}
-
 	return (WALK_NEXT);
 }
 
@@ -316,63 +369,43 @@
 mi_payload_walk_step(mdb_walk_state_t *wsp)
 {
 	const mi_payload_walk_arg_t *arg = wsp->walk_arg;
-	mi_payload_walk_data_t *pwdp = wsp->walk_data;
-	void *payload = pwdp->mi_pwd_data;
-	uintptr_t payload_kaddr = (uintptr_t)((MI_OP)wsp->walk_addr + 1);
-	const MI_O *mio = wsp->walk_layer;
+	uintptr_t kaddr;
 
-	/* If this is a local walk, prevent cycling */
-	if (wsp->walk_addr == pwdp->mi_pwd_first)
-		return (WALK_DONE);
+	kaddr = wsp->walk_addr + arg->mi_pwa_head_off;
 
-	/*
-	 * This was a global walk, prevent reading this payload as the
-	 * initial MI_O is the head of the list and is not the header
-	 * to a valid payload
-	 */
-	if (pwdp->mi_pwd_first == NULL) {
-		pwdp->mi_pwd_first = wsp->walk_addr;
-		return (WALK_NEXT);
-	}
-
-	if (mio->mi_o_isdev == B_FALSE) {
-		/* mio is a module */
-		if (!(arg->mi_pwa_flags & MI_PAYLOAD_MODULE))
-			return (WALK_NEXT);
-	} else {
-		/* mio is a device */
-		if (!(arg->mi_pwa_flags & MI_PAYLOAD_DEVICE))
-			return (WALK_NEXT);
-	}
-
-	if (mdb_vread(payload, arg->mi_pwa_size, payload_kaddr) == -1) {
-		mdb_warn("failed to read payload at %p", payload_kaddr);
+	if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) {
+		mdb_warn("can't read address of mi head at %p for %s",
+		    kaddr, arg->mi_pwa_walker);
 		return (WALK_ERR);
 	}
 
-	return (wsp->walk_callback(payload_kaddr, payload, wsp->walk_cbdata));
-}
+	if (kaddr == 0) {
+		/* Empty list */
+		return (WALK_DONE);
+	}
 
-void
-mi_payload_walk_fini(mdb_walk_state_t *wsp)
-{
-	const mi_payload_walk_arg_t *arg = wsp->walk_arg;
-
-	delete_mi_payload_walk_data(wsp->walk_data, arg->mi_pwa_size);
+	if (mdb_pwalk("genunix`mi", wsp->walk_callback,
+	    wsp->walk_cbdata, kaddr) == -1) {
+		mdb_warn("failed to walk genunix`mi");
+		return (WALK_ERR);
+	}
+	return (WALK_NEXT);
 }
 
 const mi_payload_walk_arg_t mi_ar_arg = {
-	"arp", "ar_g_head", sizeof (ar_t),
+	"ar_stacks", OFFSETOF(arp_stack_t, as_head), sizeof (ar_t),
 	MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE
 };
 
 const mi_payload_walk_arg_t mi_icmp_arg = {
-	"icmp", "icmp_g_head", sizeof (icmp_t),
+	"icmp_stacks", OFFSETOF(icmp_stack_t, is_head), sizeof (icmp_t),
 	MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE
 };
 
-const mi_payload_walk_arg_t mi_ill_arg =
-	{ "ip", "ip_g_head", sizeof (ill_t), MI_PAYLOAD_MODULE };
+const mi_payload_walk_arg_t mi_ill_arg = {
+	"ip_stacks", OFFSETOF(ip_stack_t, ips_ip_g_head), sizeof (ill_t),
+	MI_PAYLOAD_MODULE
+};
 
 int
 sonode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
@@ -557,6 +590,20 @@
 	return (DCMD_OK);
 }
 
+static int
+ns_to_stackid(uintptr_t kaddr)
+{
+	netstack_t nss;
+
+	if (mdb_vread(&nss, sizeof (nss), kaddr) == -1) {
+		mdb_warn("failed to read netstack_t %p", kaddr);
+		return (0);
+	}
+	return (nss.netstack_stackid);
+}
+
+
+
 static void
 netstat_tcp_verbose_pr(const tcp_t *tcp)
 {
@@ -620,6 +667,8 @@
 		mdb_printf(" ");
 		net_ipv6addrport_pr(&tcp->tcp_remote_v6, tcp->tcp_fport);
 	}
+	mdb_printf(" %4i", ns_to_stackid((uintptr_t)connp->conn_netstack));
+
 	mdb_printf(" %4i\n", connp->conn_zoneid);
 
 	if (opts & NETSTAT_VERBOSE)
@@ -676,6 +725,8 @@
 		mdb_printf(" ");
 		net_ipv6addrport_pr(&udp.udp_v6dst, udp.udp_dstport);
 	}
+	mdb_printf(" %4i", ns_to_stackid((uintptr_t)connp.conn_netstack));
+
 	mdb_printf(" %4i\n", connp.conn_zoneid);
 
 	return (WALK_NEXT);
@@ -1158,10 +1209,10 @@
 	if ((optP == NULL) || (strcmp("tcp", optP) == 0)) {
 		if ((optf == NULL) || (strcmp("inet", optf) == 0)) {
 			/* Print TCPv4 connection */
-			mdb_printf(
-			    "%<u>%-?s St %*s       %*s       %s%</u>\n",
+			mdb_printf("%<u>%-?s St %*s       %*s       "
+			    "%s%       %s%</u>\n",
 			    "TCPv4", ADDR_V4_WIDTH, "Local Address",
-			    ADDR_V4_WIDTH, "Remote Address", "Zone");
+			    ADDR_V4_WIDTH, "Remote Address", "Stack", "Zone");
 
 			if (opts & NETSTAT_VERBOSE)
 				netstat_tcp_verbose_header_pr();
@@ -1175,10 +1226,10 @@
 
 		if ((optf == NULL) || (strcmp("inet6", optf) == 0)) {
 			/* Print TCPv6 connection */
-			mdb_printf(
-			    "%<u>%-?s St %*s       %*s       %s\n%</u>",
+			mdb_printf("%<u>%-?s St %*s       %*s       "
+			    "%s       %s%\n%</u>",
 			    "TCPv6", ADDR_V6_WIDTH, "Local Address",
-			    ADDR_V6_WIDTH, "Remote Address", "Zone");
+			    ADDR_V6_WIDTH, "Remote Address", "Stack", "Zone");
 
 			if (opts & NETSTAT_VERBOSE)
 				netstat_tcp_verbose_header_pr();
@@ -1194,10 +1245,10 @@
 	if ((optP == NULL) || (strcmp("udp", optP) == 0)) {
 		if ((optf == NULL) || (strcmp("inet", optf) == 0)) {
 			/* Print UDPv4 connection */
-			mdb_printf(
-			    "%<u>%-?s St %*s       %*s       %s\n%</u>",
+			mdb_printf("%<u>%-?s St %*s       %*s       "
+			    "%s       %s%\n%</u>",
 			    "UDPv4", ADDR_V4_WIDTH, "Local Address",
-			    ADDR_V4_WIDTH, "Remote Address", "Zone");
+			    ADDR_V4_WIDTH, "Remote Address", "Stack", "Zone");
 
 			if (mdb_walk("udp_cache", netstat_udpv4_cb,
 			    (void *)(uintptr_t)opts) == -1) {
@@ -1209,10 +1260,10 @@
 
 		if ((optf == NULL) || (strcmp("inet6", optf) == 0)) {
 			/* Print UDPv6 connection */
-			mdb_printf(
-			    "%<u>%-?s St %*s       %*s       %s\n%</u>",
+			mdb_printf("%<u>%-?s St %*s       %*s       "
+			    "%s       %s%\n%</u>",
 			    "UDPv6", ADDR_V6_WIDTH, "Local Address",
-			    ADDR_V6_WIDTH, "Remote Address", "Zone");
+			    ADDR_V6_WIDTH, "Remote Address", "Stack", "Zone");
 
 			if (mdb_walk("udp_cache", netstat_udpv6_cb,
 			    (void *)(uintptr_t)opts) == -1) {
diff --git a/usr/src/cmd/mdb/common/modules/genunix/net.h b/usr/src/cmd/mdb/common/modules/genunix/net.h
index 45e03a5..59df026 100644
--- a/usr/src/cmd/mdb/common/modules/genunix/net.h
+++ b/usr/src/cmd/mdb/common/modules/genunix/net.h
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -45,7 +44,14 @@
 extern void mi_walk_fini(mdb_walk_state_t *);
 extern int mi_payload_walk_init(mdb_walk_state_t *);
 extern int mi_payload_walk_step(mdb_walk_state_t *);
-extern void mi_payload_walk_fini(mdb_walk_state_t *);
+extern int ar_stacks_walk_init(mdb_walk_state_t *);
+extern int ar_stacks_walk_step(mdb_walk_state_t *);
+extern int icmp_stacks_walk_init(mdb_walk_state_t *);
+extern int icmp_stacks_walk_step(mdb_walk_state_t *);
+extern int tcp_stacks_walk_init(mdb_walk_state_t *);
+extern int tcp_stacks_walk_step(mdb_walk_state_t *);
+extern int udp_stacks_walk_init(mdb_walk_state_t *);
+extern int udp_stacks_walk_step(mdb_walk_state_t *);
 
 extern int sonode(uintptr_t, uint_t, int, const mdb_arg_t *);
 extern int mi(uintptr_t, uint_t, int, const mdb_arg_t *);
diff --git a/usr/src/cmd/mdb/common/modules/genunix/netstack.c b/usr/src/cmd/mdb/common/modules/genunix/netstack.c
new file mode 100644
index 0000000..588bd6d
--- /dev/null
+++ b/usr/src/cmd/mdb/common/modules/genunix/netstack.c
@@ -0,0 +1,123 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <mdb/mdb_modapi.h>
+#include <mdb/mdb_ks.h>
+#include <mdb/mdb_ctf.h>
+#include <sys/types.h>
+#include <sys/netstack.h>
+
+int
+netstack_walk_init(mdb_walk_state_t *wsp)
+{
+	GElf_Sym sym;
+	uintptr_t addr;
+
+	if (mdb_lookup_by_name("netstack_head", &sym) == -1) {
+		mdb_warn("couldn't find netstack_head");
+		return (WALK_ERR);
+	}
+	addr = (uintptr_t)sym.st_value;
+
+	if (mdb_vread(&wsp->walk_addr, sizeof (wsp->walk_addr),	addr) == -1) {
+		mdb_warn("failed to read address of initial netstack "
+		    "at %p", addr);
+		return (WALK_ERR);
+	}
+	return (WALK_NEXT);
+}
+
+int
+netstack_walk_step(mdb_walk_state_t *wsp)
+{
+	int status;
+	netstack_t nss;
+
+	if (wsp->walk_addr == NULL)
+		return (WALK_DONE);
+
+	if (mdb_vread(&nss, sizeof (netstack_t), wsp->walk_addr) == -1) {
+		mdb_warn("failed to read netstack at %p", wsp->walk_addr);
+		return (WALK_ERR);
+	}
+
+	status = wsp->walk_callback(wsp->walk_addr, &nss,
+	    wsp->walk_cbdata);
+
+	if (status != WALK_NEXT)
+		return (status);
+
+	wsp->walk_addr = (uintptr_t)nss.netstack_next;
+	return (status);
+}
+
+/*ARGSUSED*/
+int
+netstack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+	netstack_t nss;
+	uint_t quiet = FALSE;
+	uint_t verbose = FALSE;
+
+	if (!(flags & DCMD_ADDRSPEC)) {
+		if (mdb_walk_dcmd("genunix`netstack", "genunix`netstack",
+		    argc, argv) == -1) {
+			mdb_warn("failed to walk netstack");
+			return (DCMD_ERR);
+		}
+		return (DCMD_OK);
+	}
+	if (mdb_getopts(argc, argv,
+	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
+	    'q', MDB_OPT_SETBITS, TRUE, &quiet,
+	    NULL) != argc)
+		return (DCMD_USAGE);
+
+	if (DCMD_HDRSPEC(flags) && !quiet) {
+		mdb_printf("%?s %-7s %6s\n",
+		    "ADDR", "STACKID", "FLAGS");
+	}
+
+	if (mdb_vread(&nss, sizeof (nss), addr) == -1) {
+		mdb_warn("couldn't read netstack at %p", addr);
+		return (DCMD_ERR);
+	}
+
+	/*
+	 * Options are specified for filtering, so If any option is specified on
+	 * the command line, just print address and exit.
+	 */
+	if (quiet) {
+		mdb_printf("%0?p\n", addr);
+		return (DCMD_OK);
+	}
+
+	mdb_printf("%0?p %6d    %06x\n",
+	    addr, nss.netstack_stackid, nss.netstack_flags);
+
+	return (DCMD_OK);
+}
diff --git a/usr/src/cmd/mdb/common/modules/genunix/netstack.h b/usr/src/cmd/mdb/common/modules/genunix/netstack.h
new file mode 100644
index 0000000..392565c
--- /dev/null
+++ b/usr/src/cmd/mdb/common/modules/genunix/netstack.h
@@ -0,0 +1,46 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_NETSTACK_H
+#define	_NETSTACK_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <mdb/mdb_modapi.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+int netstack_walk_init(mdb_walk_state_t *);
+int netstack_walk_step(mdb_walk_state_t *);
+
+int netstack(uintptr_t, uint_t, int, const mdb_arg_t *);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _NETSTACK_H */
diff --git a/usr/src/cmd/mdb/common/modules/hook/hook.c b/usr/src/cmd/mdb/common/modules/hook/hook.c
index d9ab29e..ec9679b 100644
--- a/usr/src/cmd/mdb/common/modules/hook/hook.c
+++ b/usr/src/cmd/mdb/common/modules/hook/hook.c
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -29,6 +29,7 @@
 #include <sys/rwlock.h>
 #include <mdb/mdb_modapi.h>
 #include <sys/queue.h>
+#include <inet/ip.h>
 #include <sys/hook.h>
 #include <sys/hook_impl.h>
 
@@ -153,6 +154,7 @@
 int
 hookrootlist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 {
+	struct hook_stack *hks;
 	hook_family_int_head_t hfh;
 	hook_family_int_t hf, *hfp;
 	char hrrstr[MAX_LENGTH];
@@ -160,8 +162,15 @@
 	if (argc)
 		return (DCMD_USAGE);
 
-	if (mdb_readvar(&hfh, "familylist") == -1) {
-		mdb_warn("couldn't read symbol 'familylist'");
+	if (mdb_vread((void *)&hks, sizeof (hks),
+	    (uintptr_t)(addr + OFFSETOF(netstack_t, netstack_hook))) == -1) {
+		mdb_warn("couldn't read netstack_hook");
+		return (DCMD_ERR);
+	}
+
+	if (mdb_vread((void *)&hfh, sizeof (hfh), (uintptr_t)((uintptr_t)hks +
+	    OFFSETOF(hook_stack_t, hks_familylist))) == -1) {
+		mdb_warn("couldn't read hook family head");
 		return (DCMD_ERR);
 	}
 
@@ -192,7 +201,7 @@
 
 
 static int
-hookevent_walk_init(mdb_walk_state_t *wsp)
+hookevent_stack_walk_init(mdb_walk_state_t *wsp)
 {
 	hook_family_int_t hf;
 
@@ -212,7 +221,7 @@
 }
 
 static int
-hookevent_walk_step(mdb_walk_state_t *wsp)
+hookevent_stack_walk_step(mdb_walk_state_t *wsp)
 {
 	hook_event_int_t hr;
 
@@ -228,7 +237,6 @@
 		    wsp->walk_cbdata));
 }
 
-
 static const mdb_dcmd_t dcmds[] = {
 	{ "hookrootlist", "", "display hook family information", hookrootlist },
 	{ "hookeventlist", "", "display hook event information",
@@ -238,8 +246,8 @@
 };
 
 static const mdb_walker_t walkers[] = {
-	{ "hookevent", "walk a list of hooks",
-		hookevent_walk_init, hookevent_walk_step, NULL },
+	{ "hookevent_stack", "walk list of hooks",
+		hookevent_stack_walk_init, hookevent_stack_walk_step, NULL },
 	{ NULL }
 };
 
diff --git a/usr/src/cmd/mdb/common/modules/ip/ip.c b/usr/src/cmd/mdb/common/modules/ip/ip.c
index 8320fee..8a24af3 100644
--- a/usr/src/cmd/mdb/common/modules/ip/ip.c
+++ b/usr/src/cmd/mdb/common/modules/ip/ip.c
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -76,34 +76,92 @@
 static int iphdr(uintptr_t, uint_t, int, const mdb_arg_t *);
 static int ip6hdr(uintptr_t, uint_t, int, const mdb_arg_t *);
 
+static int ire_format(uintptr_t addr, const ire_t *irep, uint_t *verbose);
+
+/*
+ * Given the kernel address of an ip_stack_t, return the stackid
+ */
+static int
+ips_to_stackid(uintptr_t kaddr)
+{
+	ip_stack_t ipss;
+	netstack_t nss;
+
+	if (mdb_vread(&ipss, sizeof (ipss), kaddr) == -1) {
+		mdb_warn("failed to read ip_stack_t %p", kaddr);
+		return (0);
+	}
+	kaddr = (uintptr_t)ipss.ips_netstack;
+	if (mdb_vread(&nss, sizeof (nss), kaddr) == -1) {
+		mdb_warn("failed to read netstack_t %p", kaddr);
+		return (0);
+	}
+	return (nss.netstack_stackid);
+}
+
 int
-illif_walk_init(mdb_walk_state_t *wsp)
+ip_stacks_walk_init(mdb_walk_state_t *wsp)
+{
+	if (mdb_layered_walk("netstack", wsp) == -1) {
+		mdb_warn("can't walk 'netstack'");
+		return (WALK_ERR);
+	}
+	return (WALK_NEXT);
+}
+
+int
+ip_stacks_walk_step(mdb_walk_state_t *wsp)
+{
+	uintptr_t kaddr;
+	netstack_t nss;
+
+#ifdef DEBUG
+	mdb_printf("DEBUG: ip_stacks_walk_step: addr %p\n", wsp->walk_addr);
+#endif
+	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
+		mdb_warn("can't read netstack at %p", wsp->walk_addr);
+		return (WALK_ERR);
+	}
+	kaddr = (uintptr_t)nss.netstack_modules[NS_IP];
+
+#ifdef DEBUG
+	mdb_printf("DEBUG: ip_stacks_walk_step: ip_stack_t at %p\n", kaddr);
+#endif
+	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
+}
+
+/*
+ * Called with walk_addr being the address of ips_ill_g_heads
+ */
+int
+illif_stack_walk_init(mdb_walk_state_t *wsp)
 {
 	illif_walk_data_t *iw;
 
-	if (wsp->walk_addr != NULL) {
-		mdb_warn("illif supports only global walks\n");
+	if (wsp->walk_addr == NULL) {
+		mdb_warn("illif_stack supports only local walks\n");
 		return (WALK_ERR);
 	}
 
 	iw = mdb_alloc(sizeof (illif_walk_data_t), UM_SLEEP);
 
-	if (mdb_readsym(iw->ill_g_heads, MAX_G_HEADS * sizeof (ill_g_head_t),
-	    "ill_g_heads") == -1) {
-		mdb_warn("failed to read 'ill_g_heads'");
+	if (mdb_vread(iw->ill_g_heads, MAX_G_HEADS * sizeof (ill_g_head_t),
+	    wsp->walk_addr) == -1) {
+		mdb_warn("failed to read 'ips_ill_g_heads' at %p",
+		    wsp->walk_addr);
 		mdb_free(iw, sizeof (illif_walk_data_t));
 		return (WALK_ERR);
 	}
 
 	iw->ill_list = 0;
-	wsp->walk_addr = (uintptr_t)iw->IP_VX_ILL_G_LIST(0);
+	wsp->walk_addr = (uintptr_t)iw->ill_g_heads[0].ill_g_list_head;
 	wsp->walk_data = iw;
 
 	return (WALK_NEXT);
 }
 
 int
-illif_walk_step(mdb_walk_state_t *wsp)
+illif_stack_walk_step(mdb_walk_state_t *wsp)
 {
 	uintptr_t addr = wsp->walk_addr;
 	illif_walk_data_t *iw = wsp->walk_data;
@@ -116,13 +174,15 @@
 
 	wsp->walk_addr = (uintptr_t)iw->ill_if.illif_next;
 
-	if (wsp->walk_addr == (uintptr_t)iw->IP_VX_ILL_G_LIST(list)) {
+	if (wsp->walk_addr ==
+	    (uintptr_t)iw->ill_g_heads[list].ill_g_list_head) {
 
 		if (++list >= MAX_G_HEADS)
 			return (WALK_DONE);
 
 		iw->ill_list = list;
-		wsp->walk_addr = (uintptr_t)iw->IP_VX_ILL_G_LIST(list);
+		wsp->walk_addr =
+		    (uintptr_t)iw->ill_g_heads[list].ill_g_list_head;
 		return (WALK_NEXT);
 	}
 
@@ -130,7 +190,7 @@
 }
 
 void
-illif_walk_fini(mdb_walk_state_t *wsp)
+illif_stack_walk_fini(mdb_walk_state_t *wsp)
 {
 	mdb_free(wsp->walk_data, sizeof (illif_walk_data_t));
 }
@@ -176,6 +236,45 @@
 }
 
 int
+illif_walk_init(mdb_walk_state_t *wsp)
+{
+	if (mdb_layered_walk("ip_stacks", wsp) == -1) {
+		mdb_warn("can't walk 'ip_stacks'");
+		return (WALK_ERR);
+	}
+
+	return (WALK_NEXT);
+}
+
+int
+illif_walk_step(mdb_walk_state_t *wsp)
+{
+	uintptr_t kaddr;
+
+#ifdef DEBUG
+	mdb_printf("DEBUG: illif_walk_step: addr %p\n", wsp->walk_addr);
+#endif
+
+	kaddr = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ill_g_heads);
+
+	if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) {
+		mdb_warn("can't read ips_ip_cache_table at %p", kaddr);
+		return (WALK_ERR);
+	}
+#ifdef DEBUG
+	mdb_printf("DEBUG: illif_walk_step: ips_ill_g_heads %p\n", kaddr);
+#endif
+
+	if (mdb_pwalk("illif_stack", wsp->walk_callback,
+		wsp->walk_cbdata, kaddr) == -1) {
+		mdb_warn("couldn't walk 'illif_stack' for ips_ill_g_heads %p",
+		    kaddr);
+		return (WALK_ERR);
+	}
+	return (WALK_NEXT);
+}
+
+int
 illif(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 {
 	illif_cbdata_t id;
@@ -265,6 +364,112 @@
 	return (wsp->walk_callback(wsp->walk_addr, &ire, wsp->walk_cbdata));
 }
 
+int
+ire_ctable_walk_init(mdb_walk_state_t *wsp)
+{
+	if (mdb_layered_walk("ip_stacks", wsp) == -1) {
+		mdb_warn("can't walk 'ip_stacks'");
+		return (WALK_ERR);
+	}
+
+	return (WALK_NEXT);
+}
+
+int
+ire_ctable_walk_step(mdb_walk_state_t *wsp)
+{
+	uintptr_t kaddr;
+	irb_t *irb;
+	int verbose = 0;
+	uint32_t cache_table_size;
+	int i;
+
+#ifdef DEBUG
+	mdb_printf("DEBUG: ire_ctable_walk_step: addr %p\n", wsp->walk_addr);
+#endif
+
+	kaddr = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ip_cache_table_size);
+
+	if (mdb_vread(&cache_table_size, sizeof (uint32_t), kaddr) == -1) {
+		mdb_warn("can't read ips_ip_cache_table at %p", kaddr);
+		return (WALK_ERR);
+	}
+#ifdef DEBUG
+	mdb_printf("DEBUG: ire_ctable_walk_step: ips_ip_cache_table_size %u\n",
+		cache_table_size);
+#endif
+
+	kaddr = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ip_cache_table);
+	if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) {
+		mdb_warn("can't read ips_ip_cache_table at %p", kaddr);
+		return (WALK_ERR);
+	}
+#ifdef DEBUG
+	mdb_printf("DEBUG: ire_ctable_walk_step: ips_ip_cache_table %p\n",
+	    kaddr);
+#endif
+
+	irb = mdb_alloc(sizeof (irb_t) * cache_table_size, UM_SLEEP|UM_GC);
+	if (mdb_vread(irb, sizeof (irb_t) * cache_table_size, kaddr) == -1) {
+		mdb_warn("can't read irb at %p", kaddr);
+		return (WALK_ERR);
+	}
+	for (i = 0; i < cache_table_size; i++) {
+		kaddr = (uintptr_t)irb[i].irb_ire;
+#ifdef DEBUG
+		mdb_printf("DEBUG: ire_ctable_walk_step: %d ire %p\n",
+		    i, kaddr);
+#endif
+
+		if (mdb_pwalk("ire_next", (mdb_walk_cb_t)ire_format, &verbose,
+			kaddr) == -1) {
+			mdb_warn("can't walk 'ire_next' for ire %p", kaddr);
+			return (WALK_ERR);
+		}
+	}
+	return (WALK_NEXT);
+}
+
+/* ARGSUSED */
+int
+ire_next_walk_init(mdb_walk_state_t *wsp)
+{
+#ifdef DEBUG
+	mdb_printf("DEBUG: ire_next_walk_init: addr %p\n", wsp->walk_addr);
+#endif
+	return (WALK_NEXT);
+}
+
+int
+ire_next_walk_step(mdb_walk_state_t *wsp)
+{
+	ire_t ire;
+	int status;
+
+#ifdef DEBUG
+	mdb_printf("DEBUG: ire_next_walk_step: addr %p\n", wsp->walk_addr);
+#endif
+
+	if (wsp->walk_addr == NULL)
+		return (WALK_DONE);
+
+	if (mdb_vread(&ire, sizeof (ire), wsp->walk_addr) == -1) {
+		mdb_warn("can't read ire at %p", wsp->walk_addr);
+		return (WALK_ERR);
+	}
+	status = wsp->walk_callback(wsp->walk_addr, &ire,
+	    wsp->walk_cbdata);
+
+	if (status != WALK_NEXT)
+		return (status);
+
+	wsp->walk_addr = (uintptr_t)ire.ire_next;
+#ifdef DEBUG
+	mdb_printf("DEBUG: ire_ctable_walk_step: next %p\n", wsp->walk_addr);
+#endif
+	return (status);
+}
+
 static int
 ire_format(uintptr_t addr, const ire_t *irep, uint_t *verbose)
 {
@@ -318,15 +523,20 @@
 
 		mdb_printf("%<b>%?p%</b> %40N <%hb>\n"
 		    "%?s %40N <%hb>\n"
-		    "%?s %40d <%hb>\n",
+		    "%?s %40d %4d <%hb>\n",
 		    addr, &irep->ire_src_addr_v6, irep->ire_type, tmasks,
 		    "", &irep->ire_addr_v6, (ushort_t)irep->ire_marks, mmasks,
-		    "", irep->ire_zoneid, irep->ire_flags, fmasks);
+		    "", ips_to_stackid((uintptr_t)irep->ire_ipst),
+		    irep->ire_zoneid,
+		    irep->ire_flags, fmasks);
 
 	} else if (irep->ire_ipversion == 6) {
 
-		mdb_printf("%?p %30N %30N %4d\n", addr, &irep->ire_src_addr_v6,
-		    &irep->ire_addr_v6, irep->ire_zoneid);
+		mdb_printf("%?p %30N %30N %5d %4d\n",
+		    addr, &irep->ire_src_addr_v6,
+		    &irep->ire_addr_v6,
+		    ips_to_stackid((uintptr_t)irep->ire_ipst),
+		    irep->ire_zoneid);
 
 	} else if (*verbose) {
 
@@ -335,12 +545,14 @@
 		    "%?s %40d <%hb>\n",
 		    addr, irep->ire_src_addr, irep->ire_type, tmasks,
 		    "", irep->ire_addr, (ushort_t)irep->ire_marks, mmasks,
-		    "", irep->ire_zoneid, irep->ire_flags, fmasks);
+		    "", ips_to_stackid((uintptr_t)irep->ire_ipst),
+		    irep->ire_zoneid, irep->ire_flags, fmasks);
 
 	} else {
 
-		mdb_printf("%?p %30I %30I %4d\n", addr, irep->ire_src_addr,
-		    irep->ire_addr, irep->ire_zoneid);
+		mdb_printf("%?p %30I %30I %5d %4d\n", addr, irep->ire_src_addr,
+		    irep->ire_addr, ips_to_stackid((uintptr_t)irep->ire_ipst),
+		    irep->ire_zoneid);
 	}
 
 	return (WALK_NEXT);
@@ -676,13 +888,13 @@
 		if (verbose) {
 			mdb_printf("%?s %40s %-20s%\n"
 			    "%?s %40s %-20s%\n"
-			    "%<u>%?s %40s %-20s%</u>\n",
+			    "%<u>%?s %40s %4s %-20s%</u>\n",
 			    "ADDR", "SRC", "TYPE",
 			    "", "DST", "MARKS",
-			    "", "ZONE", "FLAGS");
+			    "", "STACK", "ZONE", "FLAGS");
 		} else {
-			mdb_printf("%<u>%?s %30s %30s %4s%</u>\n",
-			    "ADDR", "SRC", "DST", "ZONE");
+			mdb_printf("%<u>%?s %30s %30s %5s %4s%</u>\n",
+			    "ADDR", "SRC", "DST", "STACK", "ZONE");
 		}
 	}
 
@@ -853,10 +1065,19 @@
 };
 
 static const mdb_walker_t walkers[] = {
-	{ "illif", "walk list of ill interface types",
-		illif_walk_init, illif_walk_step, illif_walk_fini },
+	{ "illif", "walk list of ill interface types for all stacks",
+		illif_walk_init, illif_walk_step, NULL },
+	{ "illif_stack", "walk list of ill interface types",
+		illif_stack_walk_init, illif_stack_walk_step,
+		illif_stack_walk_fini },
 	{ "ire", "walk active ire_t structures",
 		ire_walk_init, ire_walk_step, NULL },
+	{ "ire_ctable", "walk ire_t structures in the ctable",
+		ire_ctable_walk_init, ire_ctable_walk_step, NULL },
+	{ "ire_next", "walk ire_t structures in the ctable",
+		ire_next_walk_init, ire_next_walk_step, NULL },
+	{ "ip_stacks", "walk all the ip_stack_t",
+		ip_stacks_walk_init, ip_stacks_walk_step, NULL },
 	{ NULL }
 };
 
diff --git a/usr/src/cmd/mdb/common/modules/neti/neti.c b/usr/src/cmd/mdb/common/modules/neti/neti.c
index 788099b..e58fa42 100644
--- a/usr/src/cmd/mdb/common/modules/neti/neti.c
+++ b/usr/src/cmd/mdb/common/modules/neti/neti.c
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -38,8 +38,6 @@
  */
 #define	PROT_LENGTH 32
 
-LIST_HEAD(netd_listhead, net_data);
-
 /*
  * List pfhooks netinfo information.
  */
@@ -47,6 +45,7 @@
 int
 netinfolist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 {
+	struct neti_stack *nts;
 	struct netd_listhead nlh;
 	struct net_data nd, *p;
 	char str[PROT_LENGTH];
@@ -54,8 +53,15 @@
 	if (argc)
 		return (DCMD_USAGE);
 
-	if (mdb_readvar(&nlh, "netd_head") == -1) {
-		mdb_warn("couldn't read symbol 'netd_head'");
+	if (mdb_vread((void *)&nts, sizeof (nts),
+	    (uintptr_t)(addr + OFFSETOF(netstack_t, netstack_neti))) == -1) {
+		mdb_warn("couldn't read netstack_neti");
+		return (DCMD_ERR);
+	}
+
+	if (mdb_vread((void *)&nlh, sizeof (nlh), (uintptr_t)((uintptr_t)nts +
+	    OFFSETOF(neti_stack_t, nts_netd_head))) == -1) {
+		mdb_warn("couldn't read netd list head");
 		return (DCMD_ERR);
 	}
 	mdb_printf("%<u>%?s %?s %10s%</u>\n",
diff --git a/usr/src/cmd/mdb/common/modules/sctp/sctp.c b/usr/src/cmd/mdb/common/modules/sctp/sctp.c
index c40d324..aa088b4 100644
--- a/usr/src/cmd/mdb/common/modules/sctp/sctp.c
+++ b/usr/src/cmd/mdb/common/modules/sctp/sctp.c
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -65,23 +65,48 @@
 
 #define	MDB_SCTP_SHOW_ALL	0xffffffff
 
-uint_t sctp_conn_hash_size;
-static GElf_Sym sctp_list_sym;
-static list_t sctp_list;
-
-/*
- * Both the ill and ipif global arrays are small, so we just read
- * in the whole arrays.
- */
-static sctp_ill_hash_t local_g_ills[SCTP_ILL_HASH];
-static sctp_ipif_hash_t local_g_ipifs[SCTP_IPIF_HASH];
-
 /*
  * Copy from usr/src/uts/common/os/list.c.  Should we have a generic
  * mdb list walker?
  */
 #define	list_object(a, node) ((void *)(((char *)node) - (a)->list_offset))
 
+static int
+ns_to_stackid(uintptr_t kaddr)
+{
+	netstack_t nss;
+
+	if (mdb_vread(&nss, sizeof (nss), kaddr) == -1) {
+		mdb_warn("failed to read netdstack info %p", kaddr);
+		return (0);
+	}
+	return (nss.netstack_stackid);
+}
+
+int
+sctp_stacks_walk_init(mdb_walk_state_t *wsp)
+{
+	if (mdb_layered_walk("netstack", wsp) == -1) {
+		mdb_warn("can't walk 'netstack'");
+		return (WALK_ERR);
+	}
+	return (WALK_NEXT);
+}
+
+int
+sctp_stacks_walk_step(mdb_walk_state_t *wsp)
+{
+	uintptr_t kaddr;
+	netstack_t nss;
+
+	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
+		mdb_warn("can't read netstack at %p", wsp->walk_addr);
+		return (WALK_ERR);
+	}
+	kaddr = (uintptr_t)nss.netstack_modules[NS_SCTP];
+	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
+}
+
 static char *
 sctp_faddr_state(int state)
 {
@@ -713,8 +738,9 @@
 
 	mdb_nhconvert(&lport, &sctp.sctp_lport, sizeof (lport));
 	mdb_nhconvert(&fport, &sctp.sctp_fport, sizeof (fport));
-	mdb_printf("%<u>%p% %22s S=%-6hu D=%-6hu% ZONE=%d%</u>", addr,
-	    state2str(&sctp), lport, fport, connp.conn_zoneid);
+	mdb_printf("%<u>%p% %22s S=%-6hu D=%-6hu% STACK=%d ZONE=%d%</u>", addr,
+	    state2str(&sctp), lport, fport,
+	    ns_to_stackid((uintptr_t)connp.conn_netstack), connp.conn_zoneid);
 
 	if (sctp.sctp_faddrs) {
 		sctp_faddr_t faddr;
@@ -888,8 +914,6 @@
 		mdb_printf("%<b>Hash Tables%</b>\n");
 		mdb_printf("conn_hash_next\t%?p\t", sctp.sctp_conn_hash_next);
 		mdb_printf("conn_hash_prev\t%?p\n", sctp.sctp_conn_hash_prev);
-		mdb_printf("[ conn_hash bucket\t%?d ]\n",
-		    SCTP_CONN_HASH(sctp.sctp_ports));
 
 		mdb_printf("listen_hash_next%?p\t",
 		    sctp.sctp_listen_hash_next);
@@ -956,8 +980,9 @@
 } fanout_walk_data_t;
 
 typedef struct fanout_init {
-	const char *symname;
-	int (*getsize)();
+	const char *nested_walker_name;
+	size_t offset;	/* for what used to be a symbol */
+	int (*getsize)(sctp_stack_t *);
 	uintptr_t (*getnext)(sctp_t *);
 } fanout_init_t;
 
@@ -967,8 +992,9 @@
 	return ((uintptr_t)sctp->sctp_listen_hash_next);
 }
 
+/* ARGSUSED */
 static int
-listen_size(void)
+listen_size(sctp_stack_t *sctps)
 {
 	return (SCTP_LISTEN_FANOUT_SIZE);
 }
@@ -980,17 +1006,15 @@
 }
 
 static int
-conn_size(void)
+conn_size(sctp_stack_t *sctps)
 {
-	GElf_Sym sym;
 	int size;
+	uintptr_t kaddr;
 
-	if (mdb_lookup_by_name("sctp_conn_hash_size", &sym) == -1) {
-		mdb_warn("can't read 'sctp_conn_hash_size'");
-		return (1);
-	}
-	if (mdb_vread(&size, sizeof (size), sym.st_value) == -1) {
-		mdb_warn("can't dereference 'sctp_conn_hash_size'");
+	kaddr = (uintptr_t)&sctps->sctps_conn_hash_size;
+
+	if (mdb_vread(&size, sizeof (size), kaddr) == -1) {
+		mdb_warn("can't read 'sctps_conn_hash_size' at %p", kaddr);
 		return (1);
 	}
 	return (size);
@@ -1002,8 +1026,9 @@
 	return ((uintptr_t)sctp->sctp_bind_hash);
 }
 
+/* ARGSUSED */
 static int
-bind_size(void)
+bind_size(sctp_stack_t *sctps)
 {
 	return (SCTP_BIND_FANOUT_SIZE);
 }
@@ -1048,22 +1073,25 @@
 }
 
 static int
-fanout_walk_init(mdb_walk_state_t *wsp)
+fanout_stack_walk_init(mdb_walk_state_t *wsp)
 {
-	GElf_Sym sym;
 	fanout_walk_data_t *lw;
 	fanout_init_t *fi = wsp->walk_arg;
+	sctp_stack_t *sctps = (sctp_stack_t *)wsp->walk_addr;
+	uintptr_t kaddr;
 
-	if (mdb_lookup_by_name(fi->symname, &sym) == -1) {
-		mdb_warn("failed to read '%s'", fi->symname);
+	if (mdb_vread(&kaddr, sizeof (kaddr),
+	    wsp->walk_addr + fi->offset) == -1) {
+		mdb_warn("can't read sctp fanout at %p",
+		    wsp->walk_addr + fi->offset);
 		return (WALK_ERR);
 	}
 
 	lw = mdb_alloc(sizeof (*lw), UM_SLEEP);
 	lw->index = 0;
-	lw->size = fi->getsize();
+	lw->size = fi->getsize(sctps);
 	lw->sctp = NULL;
-	lw->fanout = (sctp_tf_t *)(uintptr_t)sym.st_value;
+	lw->fanout = (sctp_tf_t *)kaddr;
 	lw->getnext = fi->getnext;
 
 	if ((wsp->walk_addr = find_next_hash_item(lw)) == NULL) {
@@ -1074,7 +1102,7 @@
 }
 
 static int
-fanout_walk_step(mdb_walk_state_t *wsp)
+fanout_stack_walk_step(mdb_walk_state_t *wsp)
 {
 	fanout_walk_data_t *fw = wsp->walk_data;
 	uintptr_t addr = wsp->walk_addr;
@@ -1097,43 +1125,62 @@
 }
 
 static void
-fanout_walk_fini(mdb_walk_state_t *wsp)
+fanout_stack_walk_fini(mdb_walk_state_t *wsp)
 {
 	fanout_walk_data_t *fw = wsp->walk_data;
 
 	mdb_free(fw, sizeof (*fw));
 }
 
-static int
-sctp_walk_init(mdb_walk_state_t *wsp)
+int
+fanout_walk_init(mdb_walk_state_t *wsp)
 {
-	wsp->walk_addr = (uintptr_t)list_object(&sctp_list,
-	    sctp_list.list_head.list_next);
+	if (mdb_layered_walk("sctp_stacks", wsp) == -1) {
+		mdb_warn("can't walk 'sctp_stacks'");
+		return (WALK_ERR);
+	}
+
 	return (WALK_NEXT);
 }
 
-static int
-sctp_walk_step(mdb_walk_state_t *wsp)
+int
+fanout_walk_step(mdb_walk_state_t *wsp)
 {
-	uintptr_t psctp = wsp->walk_addr;
-	sctp_t sctp;
-	int status;
+	fanout_init_t *fi = wsp->walk_arg;
 
-	if (mdb_vread(&sctp, sizeof (sctp), psctp) == -1) {
-		mdb_warn("failed to read sctp at %p", psctp);
+	if (mdb_pwalk(fi->nested_walker_name, wsp->walk_callback,
+		wsp->walk_cbdata, wsp->walk_addr) == -1) {
+		mdb_warn("couldn't walk '%s'for address %p",
+		    fi->nested_walker_name, wsp->walk_addr);
 		return (WALK_ERR);
 	}
-	status = wsp->walk_callback(psctp, &sctp, wsp->walk_cbdata);
-	if (status != WALK_NEXT)
-		return (status);
+	return (WALK_NEXT);
+}
 
-	if ((psctp = (uintptr_t)sctp.sctp_list.list_next) ==
-	    sctp_list_sym.st_value + OFFSETOF(list_t, list_head)) {
-		return (WALK_DONE);
-	} else {
-		wsp->walk_addr = (uintptr_t)list_object(&sctp_list, psctp);
-		return (WALK_NEXT);
+int
+sctps_walk_init(mdb_walk_state_t *wsp)
+{
+
+	if (mdb_layered_walk("sctp_stacks", wsp) == -1) {
+		mdb_warn("can't walk 'sctp_stacks'");
+		return (WALK_ERR);
 	}
+
+	return (WALK_NEXT);
+}
+
+int
+sctps_walk_step(mdb_walk_state_t *wsp)
+{
+	uintptr_t kaddr;
+
+	kaddr = wsp->walk_addr + OFFSETOF(sctp_stack_t, sctps_g_list);
+	if (mdb_pwalk("list", wsp->walk_callback,
+		wsp->walk_cbdata, kaddr) == -1) {
+		mdb_warn("couldn't walk 'list' for address %p", kaddr);
+		return (WALK_ERR);
+	}
+	return (WALK_NEXT);
 }
 
 static int
@@ -1281,66 +1328,78 @@
 	mdb_free(swalker, sizeof (saddr_walk_t));
 }
 
-static int
-sctp_walk_ill_init(mdb_walk_state_t *wsp)
+
+typedef struct ill_walk_data {
+	sctp_ill_hash_t ills[SCTP_ILL_HASH];
+	uint32_t	count;
+} ill_walk_data_t;
+
+typedef struct ipuf_walk_data {
+	sctp_ipif_hash_t ipifs[SCTP_IPIF_HASH];
+	uint32_t	count;
+} ipif_walk_data_t;
+
+
+int
+sctp_ill_walk_init(mdb_walk_state_t *wsp)
 {
+	if (mdb_layered_walk("sctp_stacks", wsp) == -1) {
+		mdb_warn("can't walk 'sctp_stacks'");
+		return (WALK_ERR);
+	}
+
+	return (WALK_NEXT);
+}
+
+int
+sctp_ill_walk_step(mdb_walk_state_t *wsp)
+{
+	if (mdb_pwalk("sctp_stack_walk_ill", wsp->walk_callback,
+		wsp->walk_cbdata, wsp->walk_addr) == -1) {
+		mdb_warn("couldn't walk 'sctp_stack_walk_ill' for addr %p",
+		    wsp->walk_addr);
+		return (WALK_ERR);
+	}
+	return (WALK_NEXT);
+}
+
+/*
+ * wsp->walk_addr is the address of sctps_ill_list
+ */
+static int
+sctp_stack_ill_walk_init(mdb_walk_state_t *wsp)
+{
+	ill_walk_data_t iw;
 	intptr_t i;
+	uintptr_t kaddr, uaddr;
+	size_t offset;
+
+	kaddr = wsp->walk_addr + OFFSETOF(sctp_stack_t, sctps_ills_count);
+	if (mdb_vread(&iw.count, sizeof (iw.count), kaddr) == -1) {
+		mdb_warn("can't read sctps_ills_count at %p", kaddr);
+		return (WALK_ERR);
+	}
+	kaddr = wsp->walk_addr + OFFSETOF(sctp_stack_t, sctps_g_ills);
+
+	if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) {
+		mdb_warn("can't read scpts_g_ills %p", kaddr);
+		return (WALK_ERR);
+	}
+	if (mdb_vread(&iw.ills, sizeof (iw.ills), kaddr) == -1) {
+		mdb_warn("failed to read 'sctps_g_ills'");
+		return (NULL);
+	}
 
 	/* Find the first ill. */
 	for (i = 0; i < SCTP_ILL_HASH; i++) {
-		if (local_g_ills[i].ill_count > 0) {
-			wsp->walk_addr = (uintptr_t)list_object(
-			    &local_g_ills[i].sctp_ill_list,
-			    local_g_ills[i].sctp_ill_list.list_head.list_next);
-			wsp->walk_data = (void *)i;
-			wsp->walk_arg = (void *)1;
-			return (WALK_NEXT);
-		}
-	}
-	return (WALK_DONE);
-}
-
-static int
-sctp_walk_ill_step(mdb_walk_state_t *wsp)
-{
-	uintptr_t ill_ptr = wsp->walk_addr;
-	sctp_ill_t ill;
-	int status;
-	intptr_t i, j;
-
-	if (mdb_vread(&ill, sizeof (sctp_ill_t), ill_ptr) == -1) {
-		mdb_warn("failed to read sctp_ill_t at %p", ill_ptr);
-		return (WALK_ERR);
-	}
-	status = wsp->walk_callback(ill_ptr, &ill, wsp->walk_cbdata);
-	if (status != WALK_NEXT)
-		return (status);
-
-	i = (intptr_t)wsp->walk_data;
-	j = (intptr_t)wsp->walk_arg;
-
-	/*
-	 * If there is still an ill in the current list, return it.
-	 * Otherwise, go to the next list and find another one.
-	 */
-	if (j++ < local_g_ills[i].ill_count) {
-		wsp->walk_addr = (uintptr_t)ill.sctp_ills.list_next;
-		wsp->walk_data = (void *)i;
-		wsp->walk_arg = (void *)j;
-		return (WALK_NEXT);
-	} else {
-		list_t *ill_list;
-
-		for (i = i + 1; i < SCTP_ILL_HASH; i++) {
-			if (local_g_ills[i].ill_count > 0) {
-				ill_list = &local_g_ills[i].sctp_ill_list;
-				wsp->walk_addr = (uintptr_t)list_object(
-				    ill_list, ill_list->list_head.list_next);
-
-				/* Record the current position. */
-				wsp->walk_data = (void *)i;
-				wsp->walk_arg = (void *)1;
-				return (WALK_NEXT);
+		if (iw.ills[i].ill_count > 0) {
+			uaddr = (uintptr_t)&iw.ills[i].sctp_ill_list;
+			offset = uaddr - (uintptr_t)&iw.ills;
+			if (mdb_pwalk("list", wsp->walk_callback,
+				wsp->walk_cbdata, kaddr+offset) == -1) {
+				mdb_warn("couldn't walk 'list' for address %p",
+				    kaddr);
+				return (WALK_ERR);
 			}
 		}
 	}
@@ -1348,70 +1407,82 @@
 }
 
 static int
-sctp_walk_ipif_init(mdb_walk_state_t *wsp)
+sctp_stack_ill_walk_step(mdb_walk_state_t *wsp)
 {
+	return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer,
+		    wsp->walk_cbdata));
+}
+
+int
+sctp_ipif_walk_init(mdb_walk_state_t *wsp)
+{
+	if (mdb_layered_walk("sctp_stacks", wsp) == -1) {
+		mdb_warn("can't walk 'sctp_stacks'");
+		return (WALK_ERR);
+	}
+	return (WALK_NEXT);
+}
+
+int
+sctp_ipif_walk_step(mdb_walk_state_t *wsp)
+{
+	if (mdb_pwalk("sctp_stack_walk_ipif", wsp->walk_callback,
+		wsp->walk_cbdata, wsp->walk_addr) == -1) {
+		mdb_warn("couldn't walk 'sctp_stack_walk_ipif' for addr %p",
+		    wsp->walk_addr);
+		return (WALK_ERR);
+	}
+	return (WALK_NEXT);
+}
+
+/*
+ * wsp->walk_addr is the address of sctps_ipif_list
+ */
+static int
+sctp_stack_ipif_walk_init(mdb_walk_state_t *wsp)
+{
+	ipif_walk_data_t iw;
 	intptr_t i;
-	list_t *ipif_list;
+	uintptr_t kaddr, uaddr;
+	size_t offset;
 
+	kaddr = wsp->walk_addr + OFFSETOF(sctp_stack_t, sctps_g_ipifs_count);
+	if (mdb_vread(&iw.count, sizeof (iw.count), kaddr) == -1) {
+		mdb_warn("can't read sctps_g_ipifs_count at %p", kaddr);
+		return (WALK_ERR);
+	}
+	kaddr = wsp->walk_addr + OFFSETOF(sctp_stack_t, sctps_g_ipifs);
+
+	if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) {
+		mdb_warn("can't read scpts_g_ipifs %p", kaddr);
+		return (WALK_ERR);
+	}
+	if (mdb_vread(&iw.ipifs, sizeof (iw.ipifs), kaddr) == -1) {
+		mdb_warn("failed to read 'sctps_g_ipifs'");
+		return (NULL);
+	}
+
+	/* Find the first ipif. */
 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
-		if (local_g_ipifs[i].ipif_count > 0) {
-			ipif_list = &local_g_ipifs[i].sctp_ipif_list;
-
-			wsp->walk_addr = (uintptr_t)list_object(ipif_list,
-			    ipif_list->list_head.list_next);
-			wsp->walk_data = (void *)i;
-			wsp->walk_arg = (void *)1;
-			return (WALK_NEXT);
+		if (iw.ipifs[i].ipif_count > 0) {
+			uaddr = (uintptr_t)&iw.ipifs[i].sctp_ipif_list;
+			offset = uaddr - (uintptr_t)&iw.ipifs;
+			if (mdb_pwalk("list", wsp->walk_callback,
+				wsp->walk_cbdata, kaddr+offset) == -1) {
+				mdb_warn("couldn't walk 'list' for address %p",
+				    kaddr);
+				return (WALK_ERR);
+			}
 		}
 	}
 	return (WALK_DONE);
 }
 
 static int
-sctp_walk_ipif_step(mdb_walk_state_t *wsp)
+sctp_stack_ipif_walk_step(mdb_walk_state_t *wsp)
 {
-	uintptr_t ipif_ptr = wsp->walk_addr;
-	sctp_ipif_t ipif;
-	int status;
-	intptr_t i, j;
-
-	if (mdb_vread(&ipif, sizeof (sctp_ipif_t), ipif_ptr) == -1) {
-		mdb_warn("failed to read sctp_ipif_t at %p", ipif_ptr);
-		return (WALK_ERR);
-	}
-	status = wsp->walk_callback(ipif_ptr, &ipif, wsp->walk_cbdata);
-	if (status != WALK_NEXT)
-		return (status);
-
-	i = (intptr_t)wsp->walk_data;
-	j = (intptr_t)wsp->walk_arg;
-
-	/*
-	 * If there is still an ipif in the current list, return it.
-	 * Otherwise, go to the next list and find another one.
-	 */
-	if (j++ < local_g_ipifs[i].ipif_count) {
-		wsp->walk_addr = (uintptr_t)ipif.sctp_ipifs.list_next;
-		wsp->walk_data = (void *)i;
-		wsp->walk_arg = (void *)j;
-		return (WALK_NEXT);
-	} else {
-		list_t *ipif_list;
-
-		for (i = i + 1; i < SCTP_IPIF_HASH; i++) {
-			if (local_g_ipifs[i].ipif_count > 0) {
-				ipif_list = &local_g_ipifs[i].sctp_ipif_list;
-				wsp->walk_addr = (uintptr_t)list_object(
-				    ipif_list, ipif_list->list_head.list_next);
-
-				/* Record the current position */
-				wsp->walk_data = (void *)i;
-				wsp->walk_arg = (void *)1;
-				return (WALK_NEXT);
-			}
-		}
-	}
-	return (WALK_DONE);
+	return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer,
+		    wsp->walk_cbdata));
 }
 
 static void
@@ -1455,37 +1526,59 @@
 };
 
 static const fanout_init_t listen_fanout_init = {
-	"sctp_listen_fanout", listen_size, listen_next
+	"sctp_stack_listen_fanout", OFFSETOF(sctp_stack_t, sctps_listen_fanout),
+	listen_size, listen_next
 };
 
 static const fanout_init_t conn_fanout_init = {
-	"sctp_conn_fanout", conn_size, conn_next
+	"sctp_stack_conn_fanout",  OFFSETOF(sctp_stack_t, sctps_conn_fanout),
+	conn_size, conn_next
 };
 
 static const fanout_init_t bind_fanout_init = {
-	"sctp_bind_fanout", bind_size, bind_next
+	"sctp_stack_bind_fanout", OFFSETOF(sctp_stack_t, sctps_bind_fanout),
+	bind_size, bind_next
 };
 
 static const mdb_walker_t walkers[] = {
-	{ "sctps", "walk the full chain of sctps",
-	    sctp_walk_init, sctp_walk_step, NULL },
-	{ "sctp_listen_fanout", "walk the sctp listen fanout",
-	    fanout_walk_init, fanout_walk_step, fanout_walk_fini,
+	{ "sctps", "walk the full chain of sctps for all stacks",
+	    sctps_walk_init, sctps_walk_step, NULL },
+	{ "sctp_listen_fanout", "walk the sctp listen fanout for all stacks",
+	    fanout_walk_init, fanout_walk_step, NULL,
 	    (void *)&listen_fanout_init },
-	{ "sctp_conn_fanout", "walk the sctp conn fanout",
-	    fanout_walk_init, fanout_walk_step, fanout_walk_fini,
+	{ "sctp_conn_fanout", "walk the sctp conn fanout for all stacks",
+	    fanout_walk_init, fanout_walk_step, NULL,
 	    (void *)&conn_fanout_init },
-	{ "sctp_bind_fanout", "walk the sctp bind fanout",
-	    fanout_walk_init, fanout_walk_step, fanout_walk_fini,
+	{ "sctp_bind_fanout", "walk the sctp bind fanout for all stacks",
+	    fanout_walk_init, fanout_walk_step, NULL,
+	    (void *)&bind_fanout_init },
+	{ "sctp_stack_listen_fanout",
+	    "walk the sctp listen fanout for one stack",
+	    fanout_stack_walk_init, fanout_stack_walk_step,
+	    fanout_stack_walk_fini,
+	    (void *)&listen_fanout_init },
+	{ "sctp_stack_conn_fanout", "walk the sctp conn fanout for one stack",
+	    fanout_stack_walk_init, fanout_stack_walk_step,
+	    fanout_stack_walk_fini,
+	    (void *)&conn_fanout_init },
+	{ "sctp_stack_bind_fanout", "walk the sctp bind fanoutfor one stack",
+	    fanout_stack_walk_init, fanout_stack_walk_step,
+	    fanout_stack_walk_fini,
 	    (void *)&bind_fanout_init },
 	{ "sctp_walk_faddr", "walk the peer address list of a given sctp_t",
 	    sctp_walk_faddr_init, sctp_walk_faddr_step, NULL },
 	{ "sctp_walk_saddr", "walk the local address list of a given sctp_t",
 	    sctp_walk_saddr_init, sctp_walk_saddr_step, sctp_walk_saddr_fini },
-	{ "sctp_walk_ill", "walk the sctp_g_ills list",
-	    sctp_walk_ill_init, sctp_walk_ill_step, NULL },
-	{ "sctp_walk_ipif", "walk the sctp_g_ipif list",
-	    sctp_walk_ipif_init, sctp_walk_ipif_step, NULL },
+	{ "sctp_walk_ill", "walk the sctp_g_ills list for all stacks",
+	    sctp_ill_walk_init, sctp_ill_walk_step, NULL },
+	{ "sctp_walk_ipif", "walk the sctp_g_ipif list for all stacks",
+		sctp_ipif_walk_init, sctp_ipif_walk_step, NULL },
+	{ "sctp_stack_walk_ill", "walk the sctp_g_ills list for one stack",
+		sctp_stack_ill_walk_init, sctp_stack_ill_walk_step, NULL },
+	{ "sctp_stack_walk_ipif", "walk the sctp_g_ipif list for one stack",
+		sctp_stack_ipif_walk_init, sctp_stack_ipif_walk_step, NULL },
+	{ "sctp_stacks", "walk all the sctp_stack_t",
+		sctp_stacks_walk_init, sctp_stacks_walk_step, NULL },
 	{ NULL }
 };
 
@@ -1494,44 +1587,5 @@
 const mdb_modinfo_t *
 _mdb_init(void)
 {
-	GElf_Sym sym;
-	GElf_Sym ills_sym;
-	GElf_Sym ipifs_sym;
-
-	if (mdb_lookup_by_name("sctp_g_list", &sctp_list_sym) == -1) {
-		mdb_warn("failed to find 'sctp_g_list'");
-		return (NULL);
-	}
-	if (mdb_vread(&sctp_list, sizeof (list_t),
-	    (uintptr_t)sctp_list_sym.st_value) == -1) {
-		mdb_warn("failed to read 'sctp_g_list'");
-		return (NULL);
-	}
-	if (mdb_lookup_by_name("sctp_conn_hash_size", &sym) != -1) {
-		if (mdb_vread(&sctp_conn_hash_size,
-		    sizeof (sctp_conn_hash_size), sym.st_value) == -1) {
-			mdb_warn("failed to read 'sctp_conn_hash_size'");
-			return (NULL);
-		}
-	}
-	if (mdb_lookup_by_name("sctp_g_ills", &ills_sym) == -1) {
-		mdb_warn("failed to find 'sctp_g_ills'");
-		return (NULL);
-	}
-	if (mdb_vread(&local_g_ills, sizeof (local_g_ills),
-	    (uintptr_t)ills_sym.st_value) == -1) {
-		mdb_warn("failed to read 'sctp_g_ills'");
-		return (NULL);
-	}
-	if (mdb_lookup_by_name("sctp_g_ipifs", &ipifs_sym) == -1) {
-		mdb_warn("failed to find 'sctp_g_ipifs'");
-		return (NULL);
-	}
-	if (mdb_vread(&local_g_ipifs, sizeof (local_g_ipifs),
-	    (uintptr_t)ipifs_sym.st_value) == -1) {
-		mdb_warn("failed to read 'sctp_g_ipifs'");
-		return (NULL);
-	}
-
 	return (&modinfo);
 }
diff --git a/usr/src/cmd/svc/milestone/net-init b/usr/src/cmd/svc/milestone/net-init
index 5862c4e..89c0abd 100644
--- a/usr/src/cmd/svc/milestone/net-init
+++ b/usr/src/cmd/svc/milestone/net-init
@@ -20,7 +20,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -39,11 +39,12 @@
 . /lib/svc/share/smf_include.sh
 
 #
-# In a zone we need this service to be up, but all of the work
-# it tries to do is irrelevant (and will actually lead to the service
-# failing if we try to do it), so just bail out.
+# In a shared-IP zone we need this service to be up, but all of the work
+# it tries to do is irrelevant (and will actually lead to the service 
+# failing if we try to do it), so just bail out. 
+# In the global zone and exclusive-IP zones we proceed.
 #
-smf_is_globalzone || exit $SMF_EXIT_OK
+smf_configure_ip || exit $SMF_EXIT_OK
 
 # Configure IPv6 Default Address Selection.
 if [ -f /etc/inet/ipaddrsel.conf ]; then
@@ -56,7 +57,8 @@
 # automatically exit.  Note that it may already be running if we're not
 # executing as part of system boot.
 #
-/usr/bin/pgrep -x -u 0 in.mpathd >/dev/null 2>&1 || /usr/lib/inet/in.mpathd -a
+/usr/bin/pgrep -x -u 0 -z `smf_zonename` in.mpathd >/dev/null 2>&1 || \
+    /usr/lib/inet/in.mpathd -a
 
 #
 # Pass to the kernel the list of supported IPsec protocols and algorithms.
diff --git a/usr/src/cmd/svc/milestone/net-loopback b/usr/src/cmd/svc/milestone/net-loopback
index 9a23eb2..3688a20 100644
--- a/usr/src/cmd/svc/milestone/net-loopback
+++ b/usr/src/cmd/svc/milestone/net-loopback
@@ -20,7 +20,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -28,11 +28,12 @@
 . /lib/svc/share/smf_include.sh
 
 #
-# In a zone we need this service to be up, but all of the work
-# it tries to do is irrelevant (and will actually lead to the service
-# failing if we try to do it), so just bail out.
+# In a shared-IP zone we need this service to be up, but all of the work
+# it tries to do is irrelevant (and will actually lead to the service 
+# failing if we try to do it), so just bail out. 
+# In the global zone and exclusive-IP zones we proceed.
 #
-smf_is_globalzone || exit $SMF_EXIT_OK
+smf_configure_ip || exit $SMF_EXIT_OK
 
 #
 # Cause ifconfig to not automatically start in.mpathd when IPMP groups are
diff --git a/usr/src/cmd/svc/milestone/net-physical b/usr/src/cmd/svc/milestone/net-physical
index 60c4ee8..cc26006 100644
--- a/usr/src/cmd/svc/milestone/net-physical
+++ b/usr/src/cmd/svc/milestone/net-physical
@@ -20,7 +20,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T.
@@ -33,11 +33,12 @@
 . /lib/svc/share/net_include.sh
 
 #
-# In a zone we need this service to be up, but all of the work
-# it tries to do is irrelevant (and will actually lead to the service
-# failing if we try to do it), so just bail out.
+# In a shared-IP zone we need this service to be up, but all of the work
+# it tries to do is irrelevant (and will actually lead to the service 
+# failing if we try to do it), so just bail out. 
+# In the global zone and exclusive-IP zones we proceed.
 #
-smf_is_globalzone || exit $SMF_EXIT_OK
+smf_configure_ip || exit $SMF_EXIT_OK
 
 # Print warnings to console
 warn_failed_ifs() {
@@ -57,14 +58,16 @@
 
 smf_netstrategy
 
-#
-# Bring up link aggregations and initialize security objects.
-# Note that link property initialization is deferred until after
-# IP interfaces are plumbed to ensure that the links will not
-# be unloaded (and the property settings lost).
-#
-/sbin/dladm up-aggr
-/sbin/dladm init-secobj
+if smf_is_globalzone; then
+	#
+	# Bring up link aggregations and initialize security objects.
+	# Note that link property initialization is deferred until after
+	# IP interfaces are plumbed to ensure that the links will not
+	# be unloaded (and the property settings lost).
+	#
+	/sbin/dladm up-aggr
+	/sbin/dladm init-secobj
+fi
 
 #
 # If the system was net booted by DHCP, hand DHCP management off to the
@@ -197,13 +200,15 @@
 	[ -n "$inet6_failed" ] && warn_failed_ifs "plumb IPv6" $inet6_failed
 fi
 
-#
-# Unfortunately, if a driver unloads and then is subsequently reloaded, no
-# mechanism currently exists to restore the properties of its associated
-# links.  Hence, we wait until after interfaces have been plumbed (above)
-# to initialize link properties.
-#
-/sbin/dladm init-linkprop
+if smf_is_globalzone; then
+	#
+	# Unfortunately, if a driver unloads and then is subsequently reloaded,
+	# no mechanism currently exists to restore the properties of its
+	# associated links.  Hence, we wait until after interfaces have been
+	# plumbed (above) to initialize link properties.
+	#
+	/sbin/dladm init-linkprop
+fi
 
 #
 # Process the /etc/hostname.* files of plumbed IPv4 interfaces.  If an
diff --git a/usr/src/cmd/svc/milestone/net-routing-setup b/usr/src/cmd/svc/milestone/net-routing-setup
index 09f5f4e..dbc879e 100644
--- a/usr/src/cmd/svc/milestone/net-routing-setup
+++ b/usr/src/cmd/svc/milestone/net-routing-setup
@@ -20,7 +20,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -30,11 +30,12 @@
 . /lib/svc/share/smf_include.sh
 
 #
-# In a zone we need this service to be up, but all of the work
+# In a shared-IP zone we need this service to be up, but all of the work
 # it tries to do is irrelevant (and will actually lead to the service 
 # failing if we try to do it), so just bail out. 
+# In the global zone and exclusive-IP zones we proceed.
 #
-smf_is_globalzone || exit $SMF_EXIT_OK
+smf_configure_ip || exit $SMF_EXIT_OK
 
 #
 # If routing.conf file is in place, and has not already been read in
diff --git a/usr/src/cmd/svc/milestone/net-svc b/usr/src/cmd/svc/milestone/net-svc
index e71e34c..a91d3d0 100644
--- a/usr/src/cmd/svc/milestone/net-svc
+++ b/usr/src/cmd/svc/milestone/net-svc
@@ -20,7 +20,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -36,11 +36,12 @@
 case "$1" in
 'start')
 	#
-	# In a zone we need this service to be up, but all of the work
-	# it tries to do is irrelevant (and will actually lead to the service
-	# failing if we try to do it), so just bail out.
+	# In a shared-IP zone we need this service to be up, but all of the
+	# work it tries to do is irrelevant (and will actually lead to the
+	# service failing if we try to do it), so just bail out. 
+	# In the global zone and exclusive-IP zones we proceed.
 	#
-	smf_is_globalzone || exit 0
+	smf_configure_ip || exit 0
 	;; # Fall through -- rest of script is the initialization code
 
 'stop')
diff --git a/usr/src/cmd/svc/shell/smf_include.sh b/usr/src/cmd/svc/shell/smf_include.sh
index 066993f..9357c1b 100644
--- a/usr/src/cmd/svc/shell/smf_include.sh
+++ b/usr/src/cmd/svc/shell/smf_include.sh
@@ -20,7 +20,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -74,6 +74,27 @@
 	return 1
 }
 
+# smf_configure_ip
+#
+#  Returns zero (success) if this zone needs IP to be configured i.e.
+#  the global zone or has an exclusive stack.  1 otherwise.
+#
+smf_configure_ip() {
+	[ "${SMF_ZONENAME:=`/sbin/zonename`}" = "global" -o \
+	 `/sbin/zonename -t` = exclusive ] && return 0
+	return 1
+}
+
+# smf_dont_configure_ip
+#
+#  Inverse of smf_configure_ip
+#
+smf_dont_configure_ip() {
+	[ "${SMF_ZONENAME:=`/sbin/zonename`}" != "global" -a \
+	 `/sbin/zonename -t` = shared ] && return 0
+	return 1
+}
+
 # smf_is_system_labeled
 #
 #  Returns zero (success) if system is labeled (aka Trusted Extensions).
diff --git a/usr/src/cmd/truss/print.c b/usr/src/cmd/truss/print.c
index 8171869..09dec70 100644
--- a/usr/src/cmd/truss/print.c
+++ b/usr/src/cmd/truss/print.c
@@ -2326,6 +2326,7 @@
 		case ZONE_ATTR_INITNAME:	s = "ZONE_ATTR_INITNAME"; break;
 		case ZONE_ATTR_BOOTARGS:	s = "ZONE_ATTR_BOOTARGS"; break;
 		case ZONE_ATTR_BRAND:	s = "ZONE_ATTR_BRAND"; break;
+		case ZONE_ATTR_FLAGS:	s = "ZONE_ATTR_FLAGS"; break;
 		case ZONE_ATTR_PHYS_MCAP: s = "ZONE_ATTR_PHYS_MCAP"; break;
 		}
 	}
diff --git a/usr/src/cmd/truss/systable.c b/usr/src/cmd/truss/systable.c
index a26004d..e9b8c6a 100644
--- a/usr/src/cmd/truss/systable.c
+++ b/usr/src/cmd/truss/systable.c
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -797,6 +797,10 @@
 {"zone_boot",	2, DEC, NOV, HID, DEC},				/* 7 */
 {"zone_version", 2, HEX, NOV, HID, DEC},			/* 8 */
 {"zone_setattr", 5, DEC, NOV, HID, DEC, ZGA, HEX, DEC},		/* 9 */
+{"zone_add_datalink", 3, DEC, NOV, HID, DEC, STG},		/* 10 */
+{"zone_remove_datalink", 3, DEC, NOV, HID, DEC, STG},		/* 11 */
+{"zone_check_datalink", 3, DEC, NOV, HID, HEX, STG},		/* 12 */
+{"zone_list_datalink", 4, DEC, NOV, HID, DEC, HEX, HEX},	/* 13 */
 };
 #define	NZONECODE	(sizeof (zonetable) / sizeof (struct systable))
 
@@ -963,6 +967,10 @@
 	{ "getzoneid",		SYS_zone	},
 	{ "zone_list",		SYS_zone	},
 	{ "zone_shutdown",	SYS_zone	},
+	{ "zone_add_datalink",	SYS_zone	},
+	{ "zone_remove_datalink", SYS_zone	},
+	{ "zone_check_datalink", SYS_zone	},
+	{ "zone_list_datalink",	SYS_zone	},
 	{ "is_system_labeled",	SYS_labelsys	},
 	{ "tnrh",		SYS_labelsys	},
 	{ "tnrhtp",		SYS_labelsys	},
diff --git a/usr/src/cmd/zoneadm/Makefile b/usr/src/cmd/zoneadm/Makefile
index e11609c..27ced72 100644
--- a/usr/src/cmd/zoneadm/Makefile
+++ b/usr/src/cmd/zoneadm/Makefile
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -34,7 +34,7 @@
 
 ROOTMANIFESTDIR=        $(ROOTSVCSYSTEM)
 
-OBJS= zoneadm.o sw_cmp.o zfs.o
+OBJS= zoneadm.o sw_cmp.o zfs.o dlprims.o
 SRCS = $(OBJS:.o=.c)
 POFILE=zoneadm_all.po
 POFILES= $(OBJS:%.o=%.po)
diff --git a/usr/src/cmd/zoneadm/dlprims.c b/usr/src/cmd/zoneadm/dlprims.c
new file mode 100644
index 0000000..083e5a0
--- /dev/null
+++ b/usr/src/cmd/zoneadm/dlprims.c
@@ -0,0 +1,273 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* FIXME: from snoop. Use common library when it comes into existence */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#include <sys/stropts.h>
+#include <sys/signal.h>
+#include <sys/dlpi.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <net/if.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <strings.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <values.h>
+
+#define	DLMAXWAIT	(10)	/* max wait in seconds for response */
+#define	DLMAXBUF	(80)
+
+typedef union dlbuf {
+	union DL_primitives dl;
+	char *buf[DLMAXBUF];
+} dlbuf_t;
+
+static int	timed_getmsg(int, struct strbuf *, struct strbuf *, int *, int);
+static boolean_t	expecting(ulong_t, union DL_primitives *);
+
+/*
+ * Issue DL_INFO_REQ and wait for DL_INFO_ACK.
+ */
+static int
+dlinforeq(int fd, dl_info_ack_t *infoackp)
+{
+	dlbuf_t	buf;
+	struct	strbuf	ctl;
+	int	flags;
+
+	buf.dl.info_req.dl_primitive = DL_INFO_REQ;
+
+	ctl.maxlen = sizeof (buf);
+	ctl.len = DL_INFO_REQ_SIZE;
+	ctl.buf = (char *)&buf.dl;
+
+	flags = RS_HIPRI;
+
+	if (putmsg(fd, &ctl, NULL, flags) < 0)
+		return (-1);
+	if (timed_getmsg(fd, &ctl, NULL, &flags, DLMAXWAIT) != 0)
+		return (-1);
+
+	if (!expecting(DL_INFO_ACK, &buf.dl))
+		return (-1);
+
+	if (ctl.len < DL_INFO_ACK_SIZE)
+		return (-1);
+	if (flags != RS_HIPRI)
+		return (-1);
+	if (infoackp != NULL)
+		*infoackp = buf.dl.info_ack;
+	return (0);
+}
+
+/*
+ * Issue DL_ATTACH_REQ.
+ * Return zero on success, nonzero on error.
+ */
+static int
+dlattachreq(int fd, ulong_t ppa)
+{
+	dlbuf_t	buf;
+	struct	strbuf	ctl;
+	int	flags;
+
+	buf.dl.attach_req.dl_primitive = DL_ATTACH_REQ;
+	buf.dl.attach_req.dl_ppa = ppa;
+
+	ctl.maxlen = sizeof (buf.dl);
+	ctl.len = DL_ATTACH_REQ_SIZE;
+	ctl.buf = (char *)&buf.dl;
+
+	flags = 0;
+
+	if (putmsg(fd, &ctl, NULL, flags) < 0)
+		return (-1);
+	if (timed_getmsg(fd, &ctl, NULL, &flags, DLMAXWAIT) != 0)
+		return (-1);
+
+	if (!expecting(DL_OK_ACK, &buf.dl))
+		return (-1);
+	return (0);
+}
+
+static int
+timed_getmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp,
+    int timeout)
+{
+	struct pollfd	pfd;
+	int		rc;
+
+	pfd.fd = fd;
+
+	pfd.events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI;
+	if ((rc = poll(&pfd, 1, timeout * 1000)) == 0)
+		return (0);
+	else if (rc == -1)
+		return (0);
+
+	/* poll returned > 0 for this fd so getmsg should not block */
+	*flagsp = 0;
+
+	if ((rc = getmsg(fd, ctlp, datap, flagsp)) < 0)
+		return (0);
+
+	/*
+	 * Check for MOREDATA and/or MORECTL.
+	 */
+	if ((rc & (MORECTL | MOREDATA)) == (MORECTL | MOREDATA))
+		return (-1);
+	if (rc & MORECTL)
+		return (-1);
+	if (rc & MOREDATA)
+		return (-1);
+	/*
+	 * Check for at least sizeof (long) control data portion.
+	 */
+	if (ctlp->len < sizeof (long))
+		return (-1);
+	return (0);
+}
+
+static boolean_t
+expecting(ulong_t prim, union DL_primitives *dlp)
+{
+	if (dlp->dl_primitive == DL_ERROR_ACK || dlp->dl_primitive != prim)
+		return (B_FALSE);
+
+	return (B_TRUE);
+}
+
+/*
+ * Convert a device id to a ppa value
+ * e.g. "le0" -> 0
+ */
+static int
+device_ppa(char *device)
+{
+	char *p;
+	char *tp;
+
+	p = strpbrk(device, "0123456789");
+	if (p == NULL)
+		return (0);
+	/* ignore numbers within device names */
+	for (tp = p; *tp != '\0'; tp++)
+		if (!isdigit(*tp))
+			return (device_ppa(tp));
+	return (atoi(p));
+}
+
+/*
+ * Convert a device id to a pathname.
+ * DLPI style 1 devices: "le0" -> "/dev/le0".
+ * DLPI style 2 devices: "le0" -> "/dev/le".
+ */
+static char *
+device_path(char *device)
+{
+	static char buff[IF_NAMESIZE + 1];
+	struct stat st;
+	char *p;
+
+	(void) strcpy(buff, "/dev/");
+	(void) strlcat(buff, device, IF_NAMESIZE);
+
+	if (stat(buff, &st) == 0)
+		return (buff);
+
+	for (p = buff + (strlen(buff) - 1); p > buff; p--) {
+		if (isdigit(*p))
+			*p = '\0';
+		else
+			break;
+	}
+	return (buff);
+}
+
+/*
+ * Open up the device, and attach if needed.
+ */
+int
+ifname_open(char *device)
+{
+	char *devname;
+	ulong_t ppa;
+	int netfd;
+	dl_info_ack_t	netdl;
+
+	/*
+	 * Determine which network device
+	 * to use if none given.
+	 * Should get back a value like "/dev/le0".
+	 */
+
+	devname = device_path(device);
+	if ((netfd = open(devname, O_RDWR)) < 0)
+		return (-1);
+
+	ppa = device_ppa(device);
+
+	/*
+	 * Check for DLPI Version 2.
+	 */
+	if (dlinforeq(netfd, &netdl) != 0) {
+		(void) close(netfd);
+		return (-1);
+	}
+
+	if (netdl.dl_version != DL_VERSION_2) {
+		(void) close(netfd);
+		return (-1);
+	}
+
+	/*
+	 * Attach for DLPI Style 2.
+	 */
+	if (netdl.dl_provider_style == DL_STYLE2) {
+		if (dlattachreq(netfd, ppa) != 0) {
+			(void) close(netfd);
+			return (-1);
+		}
+
+		/* Reread more specific information */
+		if (dlinforeq(netfd, &netdl) != 0) {
+			(void) close(netfd);
+			return (-1);
+		}
+	}
+
+	return (netfd);
+}
diff --git a/usr/src/cmd/zoneadm/zoneadm.c b/usr/src/cmd/zoneadm/zoneadm.c
index 9da3182..f302cdc 100644
--- a/usr/src/cmd/zoneadm/zoneadm.c
+++ b/usr/src/cmd/zoneadm/zoneadm.c
@@ -95,6 +95,7 @@
 	char		zbrand[MAXNAMELEN];
 	char		zroot[MAXPATHLEN];
 	char		zuuid[UUID_PRINTABLE_STRING_LENGTH];
+	zone_iptype_t	ziptype;
 } zone_entry_t;
 
 static zone_entry_t *zents;
@@ -142,6 +143,8 @@
 
 static int cleanup_zonepath(char *, boolean_t);
 
+extern int ifname_open(char *);
+
 static int help_func(int argc, char *argv[]);
 static int ready_func(int argc, char *argv[]);
 static int boot_func(int argc, char *argv[]);
@@ -415,12 +418,19 @@
 zone_print(zone_entry_t *zent, boolean_t verbose, boolean_t parsable)
 {
 	static boolean_t firsttime = B_TRUE;
+	char *ip_type_str;
+
+	if (zent->ziptype == ZS_EXCLUSIVE)
+		ip_type_str = "excl";
+	else
+		ip_type_str = "shared";
 
 	assert(!(verbose && parsable));
 	if (firsttime && verbose) {
 		firsttime = B_FALSE;
-		(void) printf("%*s %-16s %-14s %-30s %-10s\n", ZONEID_WIDTH,
-		    "ID", "NAME", "STATUS", "PATH", "BRAND");
+		(void) printf("%*s %-16s %-10s %-30s %-8s %-6s\n",
+		    ZONEID_WIDTH, "ID", "NAME", "STATUS", "PATH", "BRAND",
+		    "IP");
 	}
 	if (!verbose) {
 		char *cp, *clim;
@@ -439,7 +449,8 @@
 			(void) printf("%.*s\\:", clim - cp, cp);
 			cp = clim + 1;
 		}
-		(void) printf("%s:%s:%s\n", cp, zent->zuuid, zent->zbrand);
+		(void) printf("%s:%s:%s:%s\n", cp, zent->zuuid, zent->zbrand,
+		    ip_type_str);
 		return;
 	}
 	if (zent->zstate_str != NULL) {
@@ -447,8 +458,8 @@
 			(void) printf("%*s", ZONEID_WIDTH, "-");
 		else
 			(void) printf("%*lu", ZONEID_WIDTH, zent->zid);
-		(void) printf(" %-16s %-14s %-30s %-10s\n", zent->zname,
-		    zent->zstate_str, zent->zroot, zent->zbrand);
+		(void) printf(" %-16s %-10s %-30s %-8s %-6s\n", zent->zname,
+		    zent->zstate_str, zent->zroot, zent->zbrand, ip_type_str);
 	}
 }
 
@@ -524,6 +535,54 @@
 		return (Z_ERR);
 	}
 
+	/*
+	 * Get ip type of the zone.
+	 * Note for global zone, ZS_SHARED is set always.
+	 */
+	if (zid == GLOBAL_ZONEID) {
+		zent->ziptype = ZS_SHARED;
+	} else {
+
+		if (zent->zstate_num == ZONE_STATE_RUNNING) {
+			ushort_t flags;
+
+			if (zone_getattr(zid, ZONE_ATTR_FLAGS, &flags,
+			    sizeof (flags)) < 0) {
+				zperror2(zent->zname,
+				    gettext("could not get zone flags"));
+				return (Z_ERR);
+			}
+			if (flags & ZF_NET_EXCL)
+				zent->ziptype = ZS_EXCLUSIVE;
+			else
+				zent->ziptype = ZS_SHARED;
+		} else {
+			zone_dochandle_t handle;
+
+			if ((handle = zonecfg_init_handle()) == NULL) {
+				zperror2(zent->zname,
+				    gettext("could not init handle"));
+				return (Z_ERR);
+			}
+			if ((err = zonecfg_get_handle(zent->zname, handle))
+			    != Z_OK) {
+				zperror2(zent->zname,
+				    gettext("could not get handle"));
+				zonecfg_fini_handle(handle);
+				return (Z_ERR);
+			}
+
+			if ((err = zonecfg_get_iptype(handle, &zent->ziptype))
+			    != Z_OK) {
+				zperror2(zent->zname,
+				    gettext("could not get ip-type"));
+				zonecfg_fini_handle(handle);
+				return (Z_ERR);
+			}
+			zonecfg_fini_handle(handle);
+		}
+	}
+
 	return (Z_OK);
 }
 
@@ -1542,6 +1601,7 @@
 	ssize_t result;
 	uuid_t uuid;
 	FILE *fp;
+	ushort_t flags;
 
 	(void) memset(zeptr, 0, sizeof (*zeptr));
 
@@ -1575,6 +1635,15 @@
 	if (zonecfg_get_uuid(zeptr->zname, uuid) == Z_OK &&
 	    !uuid_is_null(uuid))
 		uuid_unparse(uuid, zeptr->zuuid);
+
+	if (zone_getattr(zid, ZONE_ATTR_FLAGS, &flags, sizeof (flags)) < 0) {
+		zperror2(zeptr->zname, gettext("could not get zone flags"));
+		exit(Z_ERR);
+	}
+	if (flags & ZF_NET_EXCL)
+		zeptr->ziptype = ZS_EXCLUSIVE;
+	else
+		zeptr->ziptype = ZS_SHARED;
 }
 
 static int
@@ -2739,8 +2808,8 @@
 	if (!found_af && af != AF_UNSPEC) {
 		(void) fprintf(stderr,
 		    gettext("could not verify %s %s=%s %s=%s\n\tthe %s address "
-		    "family is not configured on this interface in the\n\t"
-		    "global zone\n"),
+		    "family is not configured on this network interface in "
+		    "the\n\tglobal zone\n"),
 		    "net", "address", addr, "physical", phys, af2str(af));
 		return;
 	}
@@ -2757,11 +2826,19 @@
 	int return_code = Z_OK;
 	int err;
 	boolean_t in_alt_root;
+	zone_iptype_t iptype;
+	int fd;
 
 	in_alt_root = zonecfg_in_alt_root();
 	if (in_alt_root)
 		goto no_net;
 
+	if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK) {
+		errno = err;
+		zperror(cmd_to_str(cmd_num), B_TRUE);
+		zonecfg_fini_handle(handle);
+		return (Z_ERR);
+	}
 	if ((err = zonecfg_setnwifent(handle)) != Z_OK) {
 		errno = err;
 		zperror(cmd_to_str(cmd_num), B_TRUE);
@@ -2771,47 +2848,114 @@
 	while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) {
 		struct lifreq lifr;
 		sa_family_t af = AF_UNSPEC;
-		int so, res;
+		char dl_owner_zname[ZONENAME_MAX];
+		zoneid_t dl_owner_zid;
+		zoneid_t target_zid;
+		int res;
 
 		/* skip any loopback interfaces */
 		if (strcmp(nwiftab.zone_nwif_physical, "lo0") == 0)
 			continue;
-		if ((res = zonecfg_valid_net_address(nwiftab.zone_nwif_address,
-		    &lifr)) != Z_OK) {
-			print_net_err(nwiftab.zone_nwif_physical,
-			    nwiftab.zone_nwif_address, af,
-			    zonecfg_strerror(res));
-			return_code = Z_ERR;
-			continue;
-		}
-		af = lifr.lifr_addr.ss_family;
-		(void) memset(&lifr, 0, sizeof (lifr));
-		(void) strlcpy(lifr.lifr_name, nwiftab.zone_nwif_physical,
-		    sizeof (lifr.lifr_name));
-		lifr.lifr_addr.ss_family = af;
-		if ((so = socket(af, SOCK_DGRAM, 0)) < 0) {
-			(void) fprintf(stderr, gettext("could not verify %s "
-			    "%s=%s %s=%s: could not get socket: %s\n"), "net",
-			    "address", nwiftab.zone_nwif_address, "physical",
-			    nwiftab.zone_nwif_physical, strerror(errno));
-			return_code = Z_ERR;
-			continue;
-		}
-		if (ioctl(so, SIOCGLIFFLAGS, &lifr) < 0) {
+		switch (iptype) {
+		case ZS_SHARED:
+			if ((res = zonecfg_valid_net_address(
+			    nwiftab.zone_nwif_address, &lifr)) != Z_OK) {
+				print_net_err(nwiftab.zone_nwif_physical,
+				    nwiftab.zone_nwif_address, af,
+				    zonecfg_strerror(res));
+			    return_code = Z_ERR;
+			    continue;
+			}
+			af = lifr.lifr_addr.ss_family;
+			if (!zonecfg_ifname_exists(af,
+			    nwiftab.zone_nwif_physical)) {
+				/*
+				 * The interface failed to come up. We continue
+				 * on anyway for the sake of consistency: a
+				 * zone is not shut down if the interface fails
+				 * any time after boot, nor does the global zone
+				 * fail to boot if an interface fails.
+				 */
+				(void) fprintf(stderr,
+				    gettext("WARNING: skipping network "
+					"interface '%s' which may not be "
+					"present/plumbed in the global "
+					"zone.\n"),
+				    nwiftab.zone_nwif_physical);
+			}
+			break;
+		case ZS_EXCLUSIVE:
+			/* Warning if it exists for either IPv4 or IPv6 */
+
+			if (zonecfg_ifname_exists(AF_INET,
+			    nwiftab.zone_nwif_physical) ||
+			    zonecfg_ifname_exists(AF_INET6,
+			    nwiftab.zone_nwif_physical)) {
+				(void) fprintf(stderr,
+				    gettext("WARNING: skipping network "
+				    "interface '%s' which is used in the "
+				    "global zone.\n"),
+				    nwiftab.zone_nwif_physical);
+				break;
+			}
 			/*
-			 * The interface failed to come up.  We continue on
-			 * anyway for the sake of consistency: a zone is not
-			 * shut down if the interface fails any time after
-			 * boot, nor does the global zone fail to boot if an
-			 * interface fails.
+			 * Verify that the physical interface can
+			 * be opened
+			 */
+			fd = ifname_open(nwiftab.zone_nwif_physical);
+			if (fd == -1) {
+				(void) fprintf(stderr,
+				    gettext("WARNING: skipping network "
+				    "interface '%s' which cannot be opened.\n"),
+				    nwiftab.zone_nwif_physical);
+				break;
+			} else {
+				(void) close(fd);
+			}
+			/*
+			 * Verify whether the physical interface is already
+			 * used by a zone.
+			 */
+			dl_owner_zid = ALL_ZONES;
+			if (zone_check_datalink(&dl_owner_zid,
+			    nwiftab.zone_nwif_physical) != 0)
+				break;
+
+			/*
+			 * If the zone being verified is
+			 * running and owns the interface
+			 */
+			target_zid = getzoneidbyname(target_zone);
+			if (target_zid == dl_owner_zid)
+				break;
+
+			/* Zone id match failed, use name to check */
+			if (getzonenamebyid(dl_owner_zid, dl_owner_zname,
+			    ZONENAME_MAX) < 0) {
+				/* No name, show ID instead */
+				(void) snprintf(dl_owner_zname, ZONENAME_MAX,
+				    "<%d>", dl_owner_zid);
+			} else if (strcmp(dl_owner_zname, target_zone) == 0)
+				break;
+
+			/*
+			 * Note here we only report a warning that
+			 * the interface is already in use by another
+			 * running zone, and the verify process just
+			 * goes on, if the interface is still in use
+			 * when this zone really boots up, zoneadmd
+			 * will find it. If the name of the zone which
+			 * owns this interface cannot be determined,
+			 * then it is not possible to determine if there
+			 * is a conflict so just report it as a warning.
 			 */
 			(void) fprintf(stderr,
-			    gettext("WARNING: skipping interface '%s' which "
-			    "may not be present/plumbed in the global zone.\n"),
-			    nwiftab.zone_nwif_physical);
-
+			    gettext("WARNING: skipping network interface "
+			    "'%s' which is used by the non-global zone "
+			    "'%s'.\n"), nwiftab.zone_nwif_physical,
+			    dl_owner_zname);
+			break;
 		}
-		(void) close(so);
 	}
 	(void) zonecfg_endnwifent(handle);
 no_net:
@@ -3440,6 +3584,10 @@
 			    != NULL)
 				*p = '\0';
 
+			/* For exclusive-IP zones, address is not specified. */
+			if (strlen(s_nwiftab.zone_nwif_address) == 0)
+				continue;
+
 			if (strcmp(t_nwiftab.zone_nwif_address,
 			    s_nwiftab.zone_nwif_address) == 0) {
 				(void) fprintf(stderr,
diff --git a/usr/src/cmd/zoneadmd/Makefile b/usr/src/cmd/zoneadmd/Makefile
index 3491469..2c3077f 100644
--- a/usr/src/cmd/zoneadmd/Makefile
+++ b/usr/src/cmd/zoneadmd/Makefile
@@ -22,7 +22,7 @@
 #
 
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -43,7 +43,7 @@
 LAZYLIBS = $(ZLAZYLOAD) -ltsnet -ltsol $(ZNOLAZYLOAD)
 lint := LAZYLIBS = -ltsnet -ltsol
 LDLIBS += -lsocket -lzonecfg -lnsl -ldevinfo -ldevice -lnvpair \
-	-lgen -lbsm -lcontract -lzfs -luuid -lbrand $(LAZYLIBS)
+	-lgen -lbsm -lcontract -lzfs -luuid -lbrand -ldladm $(LAZYLIBS)
 XGETFLAGS += -a -x zoneadmd.xcl
 
 .KEEP_STATE:
diff --git a/usr/src/cmd/zoneadmd/vplat.c b/usr/src/cmd/zoneadmd/vplat.c
index d12c3ac..68a8592 100644
--- a/usr/src/cmd/zoneadmd/vplat.c
+++ b/usr/src/cmd/zoneadmd/vplat.c
@@ -74,6 +74,10 @@
 #include <sys/stropts.h>
 #include <sys/conf.h>
 
+#include <sys/dlpi.h>
+#include <libdlpi.h>
+#include <libdladm.h>
+
 #include <inet/tcp.h>
 #include <arpa/inet.h>
 #include <netinet/in.h>
@@ -974,6 +978,29 @@
 	return (di_prof_add_symlink(prof, source, target));
 }
 
+static int
+get_iptype(zlog_t *zlogp, zone_iptype_t *iptypep)
+{
+	zone_dochandle_t handle;
+
+	if ((handle = zonecfg_init_handle()) == NULL) {
+		zerror(zlogp, B_TRUE, "getting zone configuration handle");
+		return (-1);
+	}
+	if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
+		zerror(zlogp, B_FALSE, "invalid configuration");
+		zonecfg_fini_handle(handle);
+		return (-1);
+	}
+	if (zonecfg_get_iptype(handle, iptypep) != Z_OK) {
+		zerror(zlogp, B_FALSE, "invalid ip-type configuration");
+		zonecfg_fini_handle(handle);
+		return (-1);
+	}
+	zonecfg_fini_handle(handle);
+	return (0);
+}
+
 /*
  * Apply the standard lists of devices/symlinks/mappings and the user-specified
  * list of devices (via zonecfg) to the /dev filesystem.  The filesystem will
@@ -989,6 +1016,8 @@
 	di_prof_t		prof = NULL;
 	int			err;
 	int			retval = -1;
+	zone_iptype_t		iptype;
+	const char 		*curr_iptype;
 
 	if (di_prof_init(devpath, &prof)) {
 		zerror(zlogp, B_TRUE, "failed to initialize profile");
@@ -1002,8 +1031,21 @@
 		goto cleanup;
 	}
 
+	if (get_iptype(zlogp, &iptype) < 0) {
+		zerror(zlogp, B_TRUE, "unable to determine ip-type");
+		goto cleanup;
+	}
+	switch (iptype) {
+	case ZS_SHARED:
+		curr_iptype = "shared";
+		break;
+	case ZS_EXCLUSIVE:
+		curr_iptype = "exclusive";
+		break;
+	}
+
 	if (brand_platform_iter_devices(bh, zone_name,
-	    mount_one_dev_device_cb, prof) != 0) {
+	    mount_one_dev_device_cb, prof, curr_iptype) != 0) {
 		zerror(zlogp, B_TRUE, "failed to add standard device");
 		goto cleanup;
 	}
@@ -1715,7 +1757,7 @@
  * If anything goes wrong, log an error message and return an error.
  */
 static int
-unconfigure_network_interfaces(zlog_t *zlogp, zoneid_t zone_id)
+unconfigure_shared_network_interfaces(zlog_t *zlogp, zoneid_t zone_id)
 {
 	struct lifnum lifn;
 	struct lifconf lifc;
@@ -1734,7 +1776,7 @@
 	lifn.lifn_flags = (int)lifc_flags;
 	if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) {
 		zerror(zlogp, B_TRUE,
-		    "could not determine number of interfaces");
+		    "could not determine number of network interfaces");
 		ret_code = -1;
 		goto bad;
 	}
@@ -1750,7 +1792,8 @@
 	lifc.lifc_len = bufsize;
 	lifc.lifc_buf = buf;
 	if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) {
-		zerror(zlogp, B_TRUE, "could not get configured interfaces");
+		zerror(zlogp, B_TRUE, "could not get configured network "
+		    "interfaces");
 		ret_code = -1;
 		goto bad;
 	}
@@ -1776,14 +1819,14 @@
 				continue;
 			zerror(zlogp, B_TRUE,
 			    "%s: could not determine the zone to which this "
-			    "interface is bound", lifrl.lifr_name);
+			    "network interface is bound", lifrl.lifr_name);
 			ret_code = -1;
 			continue;
 		}
 		if (lifrl.lifr_zoneid == zone_id) {
 			if (ioctl(s, SIOCLIFREMOVEIF, (caddr_t)&lifrl) < 0) {
 				zerror(zlogp, B_TRUE,
-				    "%s: could not remove interface",
+				    "%s: could not remove network interface",
 				    lifrl.lifr_name);
 				ret_code = -1;
 				continue;
@@ -1927,7 +1970,7 @@
 		return (NULL);
 	}
 	if ((rtmsg.hdr.rtm_addrs & RTA_IFP) == 0) {
-		zerror(zlogp, B_FALSE, "interface not found");
+		zerror(zlogp, B_FALSE, "network interface not found");
 		return (NULL);
 	}
 	cp = ((char *)(&rtmsg.hdr + 1));
@@ -1945,7 +1988,8 @@
 		break;
 	}
 	if (ifp == NULL) {
-		zerror(zlogp, B_FALSE, "interface could not be determined");
+		zerror(zlogp, B_FALSE, "network interface could not be "
+		    "determined");
 		return (NULL);
 	}
 
@@ -1964,8 +2008,8 @@
 	(void) strlcpy(lifr->lifr_name, save_if_name, sizeof (save_if_name));
 	if (i < 0) {
 		zerror(zlogp, B_TRUE,
-		    "%s: could not determine the zone interface belongs to",
-		    lifr->lifr_name);
+		    "%s: could not determine the zone network interface "
+		    "belongs to", lifr->lifr_name);
 		return (NULL);
 	}
 	if (getzonenamebyid(lifr->lifr_zoneid, answer, sizeof (answer)) < 0)
@@ -2061,7 +2105,7 @@
 		 * the console by zoneadm(1M) so instead we log the
 		 * message to syslog and continue.
 		 */
-		zerror(&logsys, B_TRUE, "WARNING: skipping interface "
+		zerror(&logsys, B_TRUE, "WARNING: skipping network interface "
 		    "'%s' which may not be present/plumbed in the "
 		    "global zone.", lifr.lifr_name);
 		(void) close(s);
@@ -2081,8 +2125,8 @@
 
 	lifr.lifr_zoneid = zone_id;
 	if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) < 0) {
-		zerror(zlogp, B_TRUE, "%s: could not place interface into zone",
-		    lifr.lifr_name);
+		zerror(zlogp, B_TRUE, "%s: could not place network interface "
+		    "into zone", lifr.lifr_name);
 		goto bad;
 	}
 
@@ -2180,7 +2224,8 @@
 		 */
 		if (errno != EADDRNOTAVAIL) {
 			zerror(zlogp, B_TRUE,
-			    "%s: could not bring interface up", lifr.lifr_name);
+			    "%s: could not bring network interface up",
+			    lifr.lifr_name);
 			goto bad;
 		}
 		if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) {
@@ -2192,11 +2237,12 @@
 		errno = save_errno;
 		if (zone_using == NULL)
 			zerror(zlogp, B_TRUE,
-			    "%s: could not bring interface up", lifr.lifr_name);
+			    "%s: could not bring network interface up",
+			    lifr.lifr_name);
 		else
-			zerror(zlogp, B_TRUE, "%s: could not bring interface "
-			    "up: address in use by zone '%s'", lifr.lifr_name,
-			    zone_using);
+			zerror(zlogp, B_TRUE, "%s: could not bring network "
+			    "interface up: address in use by zone '%s'",
+			    lifr.lifr_name, zone_using);
 		goto bad;
 	}
 	if ((lifr.lifr_flags & IFF_MULTICAST) && ((af == AF_INET &&
@@ -2249,13 +2295,13 @@
 		 */
 		if (rlen < mcast_rtmsg.m_rtm.rtm_msglen) {
 			if (rlen < 0) {
-				zerror(zlogp, B_TRUE, "WARNING: interface "
-				    "'%s' not available as default for "
-				    "multicast.", lifr.lifr_name);
+				zerror(zlogp, B_TRUE, "WARNING: network "
+				    "interface '%s' not available as default "
+				    "for multicast.", lifr.lifr_name);
 			} else {
-				zerror(zlogp, B_FALSE, "WARNING: interface "
-				    "'%s' not available as default for "
-				    "multicast; routing socket returned "
+				zerror(zlogp, B_FALSE, "WARNING: network "
+				    "interface '%s' not available as default "
+				    "for multicast; routing socket returned "
 				    "unexpected %d bytes.",
 				    lifr.lifr_name, rlen);
 			}
@@ -2321,7 +2367,7 @@
  * whatever we set up, and return an error.
  */
 static int
-configure_network_interfaces(zlog_t *zlogp)
+configure_shared_network_interfaces(zlog_t *zlogp)
 {
 	zone_dochandle_t handle;
 	struct zone_nwiftab nwiftab, loopback_iftab;
@@ -2383,6 +2429,279 @@
 	return (0);
 }
 
+static void
+show_owner(zlog_t *zlogp, char *dlname)
+{
+	zoneid_t dl_owner_zid;
+	char dl_owner_zname[ZONENAME_MAX];
+
+	dl_owner_zid = ALL_ZONES;
+	if (zone_check_datalink(&dl_owner_zid, dlname) != 0)
+		(void) snprintf(dl_owner_zname, ZONENAME_MAX, "<unknown>");
+	else if (getzonenamebyid(dl_owner_zid, dl_owner_zname, ZONENAME_MAX)
+	    < 0)
+		(void) snprintf(dl_owner_zname, ZONENAME_MAX, "<%d>",
+		    dl_owner_zid);
+
+	errno = EPERM;
+	zerror(zlogp, B_TRUE, "WARNING: skipping network interface '%s' "
+	    "which is used by the non-global zone '%s'.\n",
+	    dlname, dl_owner_zname);
+}
+
+static int
+add_datalink(zlog_t *zlogp, zoneid_t zoneid, char *dlname)
+{
+	/* First check if it's in use by global zone. */
+	if (zonecfg_ifname_exists(AF_INET, dlname) ||
+	    zonecfg_ifname_exists(AF_INET6, dlname)) {
+		errno = EPERM;
+		zerror(zlogp, B_TRUE, "WARNING: skipping network interface "
+		    "'%s' which is used in the global zone.", dlname);
+		return (-1);
+	}
+
+	/* Add access control information */
+	if (zone_add_datalink(zoneid, dlname) != 0) {
+		/* If someone got this link before us, show its name */
+		if (errno == EPERM)
+			show_owner(zlogp, dlname);
+		else
+			zerror(zlogp, B_TRUE, "WARNING: unable to add network "
+			    "interface '%s'.", dlname);
+		return (-1);
+	}
+
+	/* Hold the link for this zone */
+	if (dladm_hold_link(dlname, zoneid, B_FALSE) < 0) {
+		zerror(zlogp, B_TRUE, "WARNING: unable to hold network "
+		    "interface '%s'.", dlname);
+		(void) zone_remove_datalink(zoneid, dlname);
+		return (-1);
+	}
+
+	return (0);
+}
+
+static int
+remove_datalink(zlog_t *zlogp, zoneid_t zoneid, char *dlname)
+{
+	/*
+	 * Remove access control information.
+	 * If the errno is ENXIO, the interface is not added yet,
+	 * nothing to report then.
+	 */
+	if (zone_remove_datalink(zoneid, dlname) != 0) {
+		if (errno == ENXIO)
+			return (0);
+		zerror(zlogp, B_TRUE, "unable to remove network interface '%s'",
+		    dlname);
+		return (-1);
+	}
+
+	if (dladm_rele_link(dlname, 0, B_FALSE) < 0) {
+		zerror(zlogp, B_TRUE, "unable to release network "
+		    "interface '%s'", dlname);
+		return (-1);
+	}
+	return (0);
+}
+
+/*
+ * Add the kernel access control information for the interface names.
+ * If anything goes wrong, we log a general error message, attempt to tear down
+ * whatever we set up, and return an error.
+ */
+static int
+configure_exclusive_network_interfaces(zlog_t *zlogp)
+{
+	zone_dochandle_t handle;
+	struct zone_nwiftab nwiftab;
+	zoneid_t zoneid;
+	char rootpath[MAXPATHLEN];
+	char path[MAXPATHLEN];
+	di_prof_t prof = NULL;
+	boolean_t added = B_FALSE;
+
+	if ((zoneid = getzoneidbyname(zone_name)) == -1) {
+		zerror(zlogp, B_TRUE, "unable to get zoneid");
+		return (-1);
+	}
+
+	if ((handle = zonecfg_init_handle()) == NULL) {
+		zerror(zlogp, B_TRUE, "getting zone configuration handle");
+		return (-1);
+	}
+	if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
+		zerror(zlogp, B_FALSE, "invalid configuration");
+		zonecfg_fini_handle(handle);
+		return (-1);
+	}
+
+	if (zonecfg_setnwifent(handle) != Z_OK) {
+		zonecfg_fini_handle(handle);
+		return (0);
+	}
+
+	for (;;) {
+		if (zonecfg_getnwifent(handle, &nwiftab) != Z_OK)
+			break;
+
+		if (prof == NULL) {
+			if (zone_get_devroot(zone_name, rootpath,
+			    sizeof (rootpath)) != Z_OK) {
+				(void) zonecfg_endnwifent(handle);
+				zonecfg_fini_handle(handle);
+				zerror(zlogp, B_TRUE,
+				    "unable to determine dev root");
+				return (-1);
+			}
+			(void) snprintf(path, sizeof (path), "%s%s", rootpath,
+			    "/dev");
+			if (di_prof_init(path, &prof) != 0) {
+				(void) zonecfg_endnwifent(handle);
+				zonecfg_fini_handle(handle);
+				zerror(zlogp, B_TRUE,
+				    "failed to initialize profile");
+				return (-1);
+			}
+		}
+
+		/*
+		 * Only create the /dev entry if it's not in use.
+		 * Note here the zone still boots when the interfaces
+		 * assigned is inaccessible, used by others, etc.
+		 */
+		if (add_datalink(zlogp, zoneid, nwiftab.zone_nwif_physical)
+		    == 0) {
+			if (di_prof_add_dev(prof, nwiftab.zone_nwif_physical)
+			    != 0) {
+				(void) zonecfg_endnwifent(handle);
+				zonecfg_fini_handle(handle);
+				zerror(zlogp, B_TRUE,
+				    "failed to add network device");
+				return (-1);
+			}
+			added = B_TRUE;
+		}
+	}
+	(void) zonecfg_endnwifent(handle);
+	zonecfg_fini_handle(handle);
+
+	if (prof != NULL && added) {
+		if (di_prof_commit(prof) != 0) {
+			zerror(zlogp, B_TRUE, "failed to commit profile");
+			return (-1);
+		}
+	}
+	if (prof != NULL)
+		di_prof_fini(prof);
+
+	return (0);
+}
+
+/*
+ * Get the list of the data-links from kernel, and try to remove it
+ */
+static int
+unconfigure_exclusive_network_interfaces_run(zlog_t *zlogp, zoneid_t zoneid)
+{
+	char *dlnames, *ptr;
+	int dlnum, dlnum_saved, i;
+
+	dlnum = 0;
+	if (zone_list_datalink(zoneid, &dlnum, NULL) != 0) {
+		zerror(zlogp, B_TRUE, "unable to list network interfaces");
+		return (-1);
+	}
+again:
+	/* this zone doesn't have any data-links */
+	if (dlnum == 0)
+		return (0);
+
+	dlnames = malloc(dlnum * LIFNAMSIZ);
+	if (dlnames == NULL) {
+		zerror(zlogp, B_TRUE, "memory allocation failed");
+		return (-1);
+	}
+	dlnum_saved = dlnum;
+
+	if (zone_list_datalink(zoneid, &dlnum, dlnames) != 0) {
+		zerror(zlogp, B_TRUE, "unable to list network interfaces");
+		free(dlnames);
+		return (-1);
+	}
+	if (dlnum_saved < dlnum) {
+		/* list increased, try again */
+		free(dlnames);
+		goto again;
+	}
+	ptr = dlnames;
+	for (i = 0; i < dlnum; i++) {
+		/* Remove access control information */
+		if (remove_datalink(zlogp, zoneid, ptr) != 0) {
+			free(dlnames);
+			return (-1);
+		}
+		ptr += LIFNAMSIZ;
+	}
+	free(dlnames);
+	return (0);
+}
+
+/*
+ * Get the list of the data-links from configuration, and try to remove it
+ */
+static int
+unconfigure_exclusive_network_interfaces_static(zlog_t *zlogp, zoneid_t zoneid)
+{
+	zone_dochandle_t handle;
+	struct zone_nwiftab nwiftab;
+
+	if ((handle = zonecfg_init_handle()) == NULL) {
+		zerror(zlogp, B_TRUE, "getting zone configuration handle");
+		return (-1);
+	}
+	if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
+		zerror(zlogp, B_FALSE, "invalid configuration");
+		zonecfg_fini_handle(handle);
+		return (-1);
+	}
+	if (zonecfg_setnwifent(handle) != Z_OK) {
+		zonecfg_fini_handle(handle);
+		return (0);
+	}
+	for (;;) {
+		if (zonecfg_getnwifent(handle, &nwiftab) != Z_OK)
+			break;
+		/* Remove access control information */
+		if (remove_datalink(zlogp, zoneid, nwiftab.zone_nwif_physical)
+		    != 0) {
+			(void) zonecfg_endnwifent(handle);
+			zonecfg_fini_handle(handle);
+			return (-1);
+		}
+	}
+	(void) zonecfg_endnwifent(handle);
+	zonecfg_fini_handle(handle);
+	return (0);
+}
+
+/*
+ * Remove the access control information from the kernel for the exclusive
+ * network interfaces.
+ */
+static int
+unconfigure_exclusive_network_interfaces(zlog_t *zlogp, zoneid_t zoneid)
+{
+	if (unconfigure_exclusive_network_interfaces_run(zlogp, zoneid) != 0) {
+		return (unconfigure_exclusive_network_interfaces_static(zlogp,
+		    zoneid));
+	}
+
+	return (0);
+}
+
 static int
 tcp_abort_conn(zlog_t *zlogp, zoneid_t zoneid,
     const struct sockaddr_storage *local, const struct sockaddr_storage *remote)
@@ -3562,6 +3881,8 @@
 	tsol_zcent_t *zcent = NULL;
 	int match = 0;
 	int doi = 0;
+	int flags;
+	zone_iptype_t iptype;
 
 	if (zone_get_rootpath(zone_name, rootpath, sizeof (rootpath)) != Z_OK) {
 		zerror(zlogp, B_TRUE, "unable to determine zone root");
@@ -3570,11 +3891,35 @@
 	if (zonecfg_in_alt_root())
 		resolve_lofs(zlogp, rootpath, sizeof (rootpath));
 
+	if (get_iptype(zlogp, &iptype) < 0) {
+		zerror(zlogp, B_TRUE, "unable to determine ip-type");
+		return (-1);
+	}
+	switch (iptype) {
+	case ZS_SHARED:
+		flags = 0;
+		break;
+	case ZS_EXCLUSIVE:
+		flags = ZCF_NET_EXCL;
+		break;
+	}
+
 	if ((privs = priv_allocset()) == NULL) {
 		zerror(zlogp, B_TRUE, "%s failed", "priv_allocset");
 		return (-1);
 	}
 	priv_emptyset(privs);
+	if (iptype == ZS_EXCLUSIVE) {
+		/*
+		 * add PRIV_NET_RAWACCESS and PRIV_SYS_IP_CONFIG
+		 */
+		if (priv_addset(privs, PRIV_NET_RAWACCESS) != 0 ||
+		    priv_addset(privs, PRIV_SYS_IP_CONFIG) != 0) {
+			zerror(zlogp, B_TRUE,
+			    "Failed to add networking privileges");
+			goto error;
+		}
+	}
 	if (get_privset(zlogp, privs, mount_cmd) != 0)
 		goto error;
 
@@ -3669,7 +4014,8 @@
 
 	xerr = 0;
 	if ((zoneid = zone_create(kzone, rootpath, privs, rctlbuf,
-	    rctlbufsz, zfsbuf, zfsbufsz, &xerr, match, doi, zlabel)) == -1) {
+	    rctlbufsz, zfsbuf, zfsbufsz, &xerr, match, doi, zlabel,
+	    flags)) == -1) {
 		if (xerr == ZE_AREMOUNTS) {
 			if (zonecfg_find_mounts(rootpath, NULL, NULL) < 1) {
 				zerror(zlogp, B_FALSE,
@@ -3863,9 +4209,31 @@
 		return (-1);
 	}
 
-	if (!mount_cmd && configure_network_interfaces(zlogp) != 0) {
-		lofs_discard_mnttab();
-		return (-1);
+	if (!mount_cmd) {
+		zone_iptype_t iptype;
+
+		if (get_iptype(zlogp, &iptype) < 0) {
+			zerror(zlogp, B_TRUE, "unable to determine ip-type");
+			lofs_discard_mnttab();
+			return (-1);
+		}
+
+		switch (iptype) {
+		case ZS_SHARED:
+			/* Always do this to make lo0 get configured */
+			if (configure_shared_network_interfaces(zlogp) != 0) {
+				lofs_discard_mnttab();
+				return (-1);
+			}
+			break;
+		case ZS_EXCLUSIVE:
+			if (configure_exclusive_network_interfaces(zlogp) !=
+			    0) {
+				lofs_discard_mnttab();
+				return (-1);
+			}
+			break;
+		}
 	}
 
 	write_index_file(zoneid);
@@ -3952,6 +4320,7 @@
 	char cmdbuf[MAXPATHLEN];
 	char brand[MAXNAMELEN];
 	brand_handle_t bh = NULL;
+	ushort_t flags;
 
 	kzone = zone_name;
 	if (zonecfg_in_alt_root()) {
@@ -4016,11 +4385,41 @@
 		goto error;
 	}
 
-	if (!unmount_cmd &&
-	    unconfigure_network_interfaces(zlogp, zoneid) != 0) {
-		zerror(zlogp, B_FALSE,
-		    "unable to unconfigure network interfaces in zone");
-		goto error;
+	if (!unmount_cmd) {
+		zone_iptype_t iptype;
+
+		if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags,
+		    sizeof (flags)) < 0) {
+			if (get_iptype(zlogp, &iptype) < 0) {
+				zerror(zlogp, B_TRUE, "unable to determine "
+				    "ip-type");
+				goto error;
+			}
+		} else {
+			if (flags & ZF_NET_EXCL)
+				iptype = ZS_EXCLUSIVE;
+			else
+				iptype = ZS_SHARED;
+		}
+
+		switch (iptype) {
+		case ZS_SHARED:
+			if (unconfigure_shared_network_interfaces(zlogp,
+			    zoneid) != 0) {
+				zerror(zlogp, B_FALSE, "unable to unconfigure "
+				    "network interfaces in zone");
+				goto error;
+			}
+			break;
+		case ZS_EXCLUSIVE:
+			if (unconfigure_exclusive_network_interfaces(zlogp,
+			    zoneid) != 0) {
+				zerror(zlogp, B_FALSE, "unable to unconfigure "
+				    "network interfaces in zone");
+				goto error;
+			}
+			break;
+		}
 	}
 
 	if (!unmount_cmd && tcp_abort_connections(zlogp, zoneid) != 0) {
diff --git a/usr/src/cmd/zonecfg/zonecfg.c b/usr/src/cmd/zonecfg/zonecfg.c
index 34d6b99..443c089 100644
--- a/usr/src/cmd/zonecfg/zonecfg.c
+++ b/usr/src/cmd/zonecfg/zonecfg.c
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -178,6 +178,7 @@
 	ALIAS_MAXSEMIDS,
 	ALIAS_SHARES,
 	"scheduling-class",
+	"ip-type",
 	NULL
 };
 
@@ -217,6 +218,7 @@
 	ALIAS_MAXLOCKEDMEM,
 	ALIAS_MAXSWAP,
 	"scheduling-class",
+	"ip-type",
 	NULL
 };
 
@@ -273,6 +275,7 @@
 	"clear limitpriv",
 	"clear bootargs",
 	"clear scheduling-class",
+	"clear ip-type",
 	"clear " ALIAS_MAXLWPS,
 	"clear " ALIAS_MAXSHMMEM,
 	"clear " ALIAS_MAXSHMIDS,
@@ -317,6 +320,7 @@
 	"set limitpriv=",
 	"set bootargs=",
 	"set scheduling-class=",
+	"set ip-type=",
 	"set " ALIAS_MAXLWPS "=",
 	"set " ALIAS_MAXSHMMEM "=",
 	"set " ALIAS_MAXSHMIDS "=",
@@ -344,6 +348,7 @@
 	"info bootargs",
 	"info brand",
 	"info scheduling-class",
+	"info ip-type",
 	"info max-lwps",
 	"info max-shm-memory",
 	"info max-shm-ids",
@@ -914,6 +919,11 @@
 			    pt_to_str(PT_PHYSICAL), gettext("<interface>"));
 			(void) fprintf(fp, gettext("See ifconfig(1M) for "
 			    "details of the <interface> string.\n"));
+			(void) fprintf(fp, gettext("%s %s is valid if the %s "
+			    "property is set to %s, otherwise it must not be "
+			    "set.\n"),
+			    cmd_to_str(CMD_SET), pt_to_str(PT_ADDRESS),
+			    pt_to_str(PT_IPTYPE), "shared");
 			break;
 		case RT_DEVICE:
 			(void) fprintf(fp, gettext("The '%s' resource scope is "
@@ -1095,6 +1105,8 @@
 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
 		    pt_to_str(PT_SCHED));
 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
+		    pt_to_str(PT_IPTYPE));
+		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
 		    pt_to_str(PT_MAXLWPS));
 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
 		    pt_to_str(PT_MAXSHMMEM));
@@ -1571,6 +1583,7 @@
 	char *limitpriv;
 	FILE *of;
 	boolean_t autoboot;
+	zone_iptype_t iptype;
 	bool need_to_close = FALSE;
 
 	assert(cmd != NULL);
@@ -1651,6 +1664,19 @@
 		(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
 		    pt_to_str(PT_SCHED), sched);
 
+	if (zonecfg_get_iptype(handle, &iptype) == Z_OK) {
+		switch (iptype) {
+		case ZS_SHARED:
+			(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
+			    pt_to_str(PT_IPTYPE), "shared");
+			break;
+		case ZS_EXCLUSIVE:
+			(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
+			    pt_to_str(PT_IPTYPE), "exclusive");
+			break;
+		}
+	}
+
 	if ((err = zonecfg_setipdent(handle)) != Z_OK) {
 		zone_perror(zone, err, FALSE);
 		goto done;
@@ -2157,7 +2183,8 @@
 {
 	return (global_zone && (type == RT_ZONENAME || type == RT_ZONEPATH ||
 	    type == RT_AUTOBOOT || type == RT_LIMITPRIV ||
-	    type == RT_BOOTARGS || type == RT_BRAND || type == RT_SCHED));
+	    type == RT_BOOTARGS || type == RT_BRAND || type == RT_SCHED ||
+	    type == RT_IPTYPE));
 }
 
 static boolean_t
@@ -2165,7 +2192,8 @@
 {
 	return (global_zone && (type == PT_ZONENAME || type == PT_ZONEPATH ||
 	    type == PT_AUTOBOOT || type == PT_LIMITPRIV ||
-	    type == PT_BOOTARGS || type == PT_BRAND || type == PT_SCHED));
+	    type == PT_BOOTARGS || type == PT_BRAND || type == PT_SCHED ||
+	    type == PT_IPTYPE));
 }
 
 void
@@ -3268,6 +3296,13 @@
 		else
 			need_to_commit = TRUE;
 		return;
+	case PT_IPTYPE:
+		/* shared is default; we'll treat as equivalent to clearing */
+		if ((err = zonecfg_set_iptype(handle, ZS_SHARED)) != Z_OK)
+			z_cmd_rt_perror(CMD_CLEAR, RT_IPTYPE, err, TRUE);
+		else
+			need_to_commit = TRUE;
+		return;
 	case PT_MAXLWPS:
 		remove_aliased_rctl(PT_MAXLWPS, ALIAS_MAXLWPS);
 		return;
@@ -3555,6 +3590,30 @@
 	return (B_TRUE);
 }
 
+static boolean_t
+allow_exclusive()
+{
+	brand_handle_t	bh;
+	char		brand[MAXNAMELEN];
+	boolean_t	ret;
+
+	if (zonecfg_get_brand(handle, brand, sizeof (brand)) != Z_OK) {
+		zerr("%s: %s\n", zone, gettext("could not get zone brand"));
+		return (B_FALSE);
+	}
+	if ((bh = brand_open(brand)) == NULL) {
+		zerr("%s: %s\n", zone, gettext("unknown brand."));
+		return (B_FALSE);
+	}
+	ret = brand_allow_exclusive_ip(bh);
+	brand_close(bh);
+	if (!ret)
+		zerr(gettext("%s cannot be '%s' when %s is '%s'."),
+		    pt_to_str(PT_IPTYPE), "exclusive",
+		    pt_to_str(PT_BRAND), brand);
+	return (ret);
+}
+
 static void
 set_aliased_rctl(char *alias, int prop_type, char *s)
 {
@@ -3605,6 +3664,7 @@
 	int arg, err, res_type, prop_type;
 	property_value_ptr_t pp;
 	boolean_t autoboot;
+	zone_iptype_t iptype;
 	boolean_t force_set = FALSE;
 	size_t physmem_size = sizeof (in_progress_mcaptab.zone_physmem_cap);
 	uint64_t mem_cap, mem_limit;
@@ -3655,6 +3715,8 @@
 			res_type = RT_BOOTARGS;
 		} else if (prop_type == PT_SCHED) {
 			res_type = RT_SCHED;
+		} else if (prop_type == PT_IPTYPE) {
+			res_type = RT_IPTYPE;
 		} else if (prop_type == PT_MAXLWPS) {
 			res_type = RT_MAXLWPS;
 		} else if (prop_type == PT_MAXSHMMEM) {
@@ -3831,6 +3893,26 @@
 		else
 			need_to_commit = TRUE;
 		return;
+	case RT_IPTYPE:
+		if (strcmp(prop_id, "shared") == 0) {
+			iptype = ZS_SHARED;
+		} else if (strcmp(prop_id, "exclusive") == 0) {
+			iptype = ZS_EXCLUSIVE;
+		} else {
+			zerr(gettext("%s value must be '%s' or '%s'."),
+			    pt_to_str(PT_IPTYPE), "shared", "exclusive");
+			saw_error = TRUE;
+			return;
+		}
+		if (iptype == ZS_EXCLUSIVE && !allow_exclusive()) {
+			saw_error = TRUE;
+			return;
+		}
+		if ((err = zonecfg_set_iptype(handle, iptype)) != Z_OK)
+			zone_perror(zone, err, TRUE);
+		else
+			need_to_commit = TRUE;
+		return;
 	case RT_MAXLWPS:
 		set_aliased_rctl(ALIAS_MAXLWPS, prop_type, prop_id);
 		return;
@@ -4304,6 +4386,28 @@
 }
 
 static void
+info_iptype(zone_dochandle_t handle, FILE *fp)
+{
+	zone_iptype_t iptype;
+	int err;
+
+	if ((err = zonecfg_get_iptype(handle, &iptype)) == Z_OK) {
+		switch (iptype) {
+		case ZS_SHARED:
+			(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_IPTYPE),
+			    "shared");
+			break;
+		case ZS_EXCLUSIVE:
+			(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_IPTYPE),
+			    "exclusive");
+			break;
+		}
+	} else {
+		zone_perror(zone, err, TRUE);
+	}
+}
+
+static void
 output_fs(FILE *fp, struct zone_fstab *fstab)
 {
 	zone_fsopt_t *this;
@@ -4430,6 +4534,7 @@
 		    strcmp(user.zone_nwif_physical,
 		    lookup.zone_nwif_physical) != 0)
 			continue;	/* no match */
+		/* If present make sure it matches */
 		if (strlen(user.zone_nwif_address) > 0 &&
 		    !zonecfg_same_net_address(user.zone_nwif_address,
 		    lookup.zone_nwif_address))
@@ -4822,6 +4927,7 @@
 		if (!global_zone) {
 			info_limitpriv(handle, fp);
 			info_sched(handle, fp);
+			info_iptype(handle, fp);
 		}
 		info_aliased_rctl(handle, fp, ALIAS_MAXLWPS);
 		info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM);
@@ -4867,6 +4973,9 @@
 	case RT_SCHED:
 		info_sched(handle, fp);
 		break;
+	case RT_IPTYPE:
+		info_iptype(handle, fp);
+		break;
 	case RT_MAXLWPS:
 		info_aliased_rctl(handle, fp, ALIAS_MAXLWPS);
 		break;
@@ -5051,6 +5160,7 @@
 	char brand[MAXNAMELEN];
 	int err, ret_val = Z_OK, arg;
 	bool save = FALSE;
+	zone_iptype_t iptype;
 	boolean_t has_cpu_shares = B_FALSE;
 
 	optind = 0;
@@ -5102,6 +5212,11 @@
 		}
 	}
 
+	if (zonecfg_get_iptype(handle, &iptype) != Z_OK) {
+		zerr("%s %s", gettext("cannot get"), pt_to_str(PT_IPTYPE));
+		ret_val = Z_REQD_RESOURCE_MISSING;
+		saw_error = TRUE;
+	}
 	if ((err = zonecfg_setipdent(handle)) != Z_OK) {
 		zone_perror(zone, err, TRUE);
 		return;
@@ -5130,10 +5245,30 @@
 		return;
 	}
 	while (zonecfg_getnwifent(handle, &nwiftab) == Z_OK) {
-		check_reqd_prop(nwiftab.zone_nwif_address, RT_NET,
-		    PT_ADDRESS, &ret_val);
+		/*
+		 * physical is required in all cases.
+		 * A shared IP requires an address, while
+		 * an exclusive IP must not have an address.
+		 */
 		check_reqd_prop(nwiftab.zone_nwif_physical, RT_NET,
 		    PT_PHYSICAL, &ret_val);
+
+		switch (iptype) {
+		case ZS_SHARED:
+			check_reqd_prop(nwiftab.zone_nwif_address, RT_NET,
+			    PT_ADDRESS, &ret_val);
+			break;
+		case ZS_EXCLUSIVE:
+			if (strlen(nwiftab.zone_nwif_address) > 0) {
+				zerr(gettext("%s: %s cannot be specified "
+				    "for an exclusive IP type"),
+				    rt_to_str(RT_NET), pt_to_str(PT_ADDRESS));
+				saw_error = TRUE;
+				if (ret_val == Z_OK)
+					ret_val = Z_INVAL;
+			}
+			break;
+		}
 	}
 	(void) zonecfg_endnwifent(handle);
 
@@ -5492,27 +5627,35 @@
 		}
 		break;
 	case RT_NET:
-		/* First make sure everything was filled in. */
+		/*
+		 * First make sure everything was filled in.
+		 * Since we don't know whether IP will be shared
+		 * or exclusive here, some checks are deferred until
+		 * the verify command.
+		 */
 		(void) end_check_reqd(in_progress_nwiftab.zone_nwif_physical,
 		    PT_PHYSICAL, &validation_failed);
-		(void) end_check_reqd(in_progress_nwiftab.zone_nwif_address,
-		    PT_ADDRESS, &validation_failed);
 
 		if (validation_failed) {
 			saw_error = TRUE;
 			return;
 		}
-
 		if (end_op == CMD_ADD) {
 			/* Make sure there isn't already one like this. */
 			bzero(&tmp_nwiftab, sizeof (tmp_nwiftab));
+			(void) strlcpy(tmp_nwiftab.zone_nwif_physical,
+			    in_progress_nwiftab.zone_nwif_physical,
+			    sizeof (tmp_nwiftab.zone_nwif_physical));
 			(void) strlcpy(tmp_nwiftab.zone_nwif_address,
 			    in_progress_nwiftab.zone_nwif_address,
 			    sizeof (tmp_nwiftab.zone_nwif_address));
 			if (zonecfg_lookup_nwif(handle, &tmp_nwiftab) == Z_OK) {
-				zerr(gettext("A %s resource "
-				    "with the %s '%s' already exists."),
-				    rt_to_str(RT_NET), pt_to_str(PT_ADDRESS),
+				zerr(gettext("A %s resource with the %s '%s', "
+				    "and %s '%s' already exists."),
+				    rt_to_str(RT_NET),
+				    pt_to_str(PT_PHYSICAL),
+				    in_progress_nwiftab.zone_nwif_physical,
+				    pt_to_str(PT_ADDRESS),
 				    in_progress_nwiftab.zone_nwif_address);
 				saw_error = TRUE;
 				return;
diff --git a/usr/src/cmd/zonecfg/zonecfg.h b/usr/src/cmd/zonecfg/zonecfg.h
index 64808e9..4f960b5 100644
--- a/usr/src/cmd/zonecfg/zonecfg.h
+++ b/usr/src/cmd/zonecfg/zonecfg.h
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -93,9 +93,10 @@
 #define	RT_MAXSEMIDS	21	/* really a rctl alias property, but for info */
 #define	RT_SHARES	22	/* really a rctl alias property, but for info */
 #define	RT_SCHED	23	/* really a property, but for info ... */
+#define	RT_IPTYPE	24	/* really a property, but for info ... */
 
 #define	RT_MIN		RT_UNKNOWN
-#define	RT_MAX		RT_SCHED
+#define	RT_MAX		RT_IPTYPE
 
 /* property types: increment PT_MAX when expanding this list */
 #define	PT_UNKNOWN	0
@@ -132,9 +133,10 @@
 #define	PT_MAXLOCKEDMEM	31
 #define	PT_MAXSWAP	32
 #define	PT_SCHED	33
+#define	PT_IPTYPE	34
 
 #define	PT_MIN		PT_UNKNOWN
-#define	PT_MAX		PT_SCHED
+#define	PT_MAX		PT_IPTYPE
 
 #define	MAX_EQ_PROP_PAIRS	3
 
diff --git a/usr/src/cmd/zonecfg/zonecfg_grammar.y b/usr/src/cmd/zonecfg/zonecfg_grammar.y
index 5c0dc22..7ee9b4d 100644
--- a/usr/src/cmd/zonecfg/zonecfg_grammar.y
+++ b/usr/src/cmd/zonecfg/zonecfg_grammar.y
@@ -21,7 +21,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -59,6 +59,7 @@
 %token HELP CREATE EXPORT ADD DELETE REMOVE SELECT SET INFO CANCEL END VERIFY
 %token COMMIT REVERT EXIT SEMICOLON TOKEN ZONENAME ZONEPATH AUTOBOOT POOL NET
 %token FS IPD ATTR DEVICE RCTL SPECIAL RAW DIR OPTIONS TYPE ADDRESS PHYSICAL
+%token IPTYPE
 %token NAME MATCH PRIV LIMIT ACTION VALUE EQUAL OPEN_SQ_BRACKET CLOSE_SQ_BRACKET
 %token OPEN_PAREN CLOSE_PAREN COMMA DATASET LIMITPRIV BOOTARGS BRAND PSET
 %token MCAP NCPUS IMPORTANCE SHARES MAXLWPS MAXSHMMEM MAXSHMIDS MAXMSGIDS
@@ -70,7 +71,7 @@
 %type <ival> resource_type NET FS IPD DEVICE RCTL ATTR DATASET PSET MCAP
 %type <ival> property_name SPECIAL RAW DIR OPTIONS TYPE ADDRESS PHYSICAL NAME
     MATCH ZONENAME ZONEPATH AUTOBOOT POOL LIMITPRIV BOOTARGS VALUE PRIV LIMIT
-    ACTION BRAND SCHED
+    ACTION BRAND SCHED IPTYPE
 %type <cmd> command
 %type <cmd> add_command ADD
 %type <cmd> cancel_command CANCEL
@@ -442,6 +443,15 @@
 		$$->cmd_res_type = RT_AUTOBOOT;
 		$$->cmd_prop_nv_pairs = 0;
 	}
+	|	INFO IPTYPE
+	{
+		if (($$ = alloc_cmd()) == NULL)
+			YYERROR;
+		cmd = $$;
+		$$->cmd_handler = &info_func;
+		$$->cmd_res_type = RT_IPTYPE;
+		$$->cmd_prop_nv_pairs = 0;
+	}
 	|	INFO POOL
 	{
 		if (($$ = alloc_cmd()) == NULL)
@@ -840,6 +850,7 @@
 	| ZONENAME	{ $$ = PT_ZONENAME; }
 	| ZONEPATH	{ $$ = PT_ZONEPATH; }
 	| AUTOBOOT	{ $$ = PT_AUTOBOOT; }
+	| IPTYPE	{ $$ = PT_IPTYPE; }
 	| POOL		{ $$ = PT_POOL; }
 	| LIMITPRIV	{ $$ = PT_LIMITPRIV; }
 	| BOOTARGS	{ $$ = PT_BOOTARGS; }
diff --git a/usr/src/cmd/zonecfg/zonecfg_lex.l b/usr/src/cmd/zonecfg/zonecfg_lex.l
index 53f726c..81a0594 100644
--- a/usr/src/cmd/zonecfg/zonecfg_lex.l
+++ b/usr/src/cmd/zonecfg/zonecfg_lex.l
@@ -21,7 +21,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -184,6 +184,9 @@
 <TSTATE>autoboot	{ return AUTOBOOT; }
 <CSTATE>autoboot	{ return AUTOBOOT; }
 
+<TSTATE>ip-type		{ return IPTYPE; }
+<CSTATE>ip-type		{ return IPTYPE; }
+
 <TSTATE>pool	{ return POOL; }
 <CSTATE>pool	{ return POOL; }
 
diff --git a/usr/src/cmd/zonename/zonename.c b/usr/src/cmd/zonename/zonename.c
index 3a3a5df..2ab2f1f 100644
--- a/usr/src/cmd/zonename/zonename.c
+++ b/usr/src/cmd/zonename/zonename.c
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -33,21 +32,54 @@
 #include <zone.h>
 #include <libzonecfg.h>
 #include <dlfcn.h>
+#include <sys/zone.h>
 
 #if !defined(TEXT_DOMAIN)		/* should be defined by cc -D */
 #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it wasn't */
 #endif
 
+/*
+ * -t prints "shared" vs. "exclusive"
+ */
 int
-main(void)
+main(int argc, char *argv[])
 {
+	zoneid_t zoneid;
 	char zonename[ZONENAME_MAX];
 	FILE *fp;
+	int arg;
+	boolean_t stacktype = B_FALSE;
 
 	(void) setlocale(LC_ALL, "");
 	(void) textdomain(TEXT_DOMAIN);
 
-	if (getzonenamebyid(getzoneid(), zonename, sizeof (zonename)) < 0) {
+	opterr = 0;
+	while ((arg = getopt(argc, argv, "t")) != EOF) {
+		switch (arg) {
+		case 't':
+			stacktype = B_TRUE;
+			break;
+		}
+	}
+
+	zoneid = getzoneid();
+
+	if (stacktype) {
+		ushort_t flags;
+
+		if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags,
+		    sizeof (flags)) < 0) {
+			perror("could not determine zone IP type");
+			exit(1);
+		}
+		if (flags & ZF_NET_EXCL)
+			(void) puts("exclusive");
+		else
+			(void) puts("shared");
+		return (0);
+	}
+
+	if (getzonenamebyid(zoneid, zonename, sizeof (zonename)) < 0) {
 		(void) fputs(gettext("could not determine zone name\n"),
 		    stderr);
 		return (1);
diff --git a/usr/src/common/net/patricia/radix.c b/usr/src/common/net/patricia/radix.c
index ec8bdf5..a61cbaa 100644
--- a/usr/src/common/net/patricia/radix.c
+++ b/usr/src/common/net/patricia/radix.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  * Copyright (c) 1988, 1989, 1993
@@ -1221,6 +1221,7 @@
 	rnh->rnh_walktree = NULL;
 
 #ifdef	_KERNEL
+	RADIX_NODE_HEAD_DESTROY(rnh);
 	FreeHead(rnh, sizeof (*rnh));
 #else
 	Free(rnh, NULL);
diff --git a/usr/src/head/libzonecfg.h b/usr/src/head/libzonecfg.h
index 10ee4a2..8272817 100644
--- a/usr/src/head/libzonecfg.h
+++ b/usr/src/head/libzonecfg.h
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -238,6 +238,11 @@
 	char	*zone_devperm_acl;
 };
 
+typedef enum zone_iptype {
+	ZS_SHARED,
+	ZS_EXCLUSIVE
+} zone_iptype_t;
+
 /*
  * Basic configuration management routines.
  */
@@ -277,6 +282,8 @@
 extern	int	zonecfg_set_zonepath(zone_dochandle_t, char *);
 extern	int	zonecfg_get_autoboot(zone_dochandle_t, boolean_t *);
 extern	int	zonecfg_set_autoboot(zone_dochandle_t, boolean_t);
+extern	int	zonecfg_get_iptype(zone_dochandle_t, zone_iptype_t *);
+extern	int	zonecfg_set_iptype(zone_dochandle_t, zone_iptype_t);
 extern	int	zonecfg_get_pool(zone_dochandle_t, char *, size_t);
 extern	int	zonecfg_set_pool(zone_dochandle_t, char *);
 extern	int	zonecfg_get_bootargs(zone_dochandle_t, char *, size_t);
@@ -500,6 +507,7 @@
  */
 extern boolean_t zonecfg_same_net_address(char *, char *);
 extern int zonecfg_valid_net_address(char *, struct lifreq *);
+extern boolean_t zonecfg_ifname_exists(sa_family_t, char *);
 
 /*
  * Rctl-related common functions.
diff --git a/usr/src/head/zone.h b/usr/src/head/zone.h
index 5250aab..c4077c0 100644
--- a/usr/src/head/zone.h
+++ b/usr/src/head/zone.h
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -58,7 +58,7 @@
 /* System call API */
 extern zoneid_t	zone_create(const char *, const char *,
     const struct priv_set *, const char *, size_t, const char *, size_t, int *,
-    int, int, const bslabel_t *);
+    int, int, const bslabel_t *, int);
 extern int	zone_boot(zoneid_t);
 extern int	zone_destroy(zoneid_t);
 extern ssize_t	zone_getattr(zoneid_t, int, void *, size_t);
@@ -67,6 +67,10 @@
 extern int	zone_list(zoneid_t *, uint_t *);
 extern int	zone_shutdown(zoneid_t);
 extern int	zone_version(int *);
+extern int	zone_add_datalink(zoneid_t, char *);
+extern int	zone_remove_datalink(zoneid_t, char *);
+extern int	zone_check_datalink(zoneid_t *, char *);
+extern int	zone_list_datalink(zoneid_t, int *, char *);
 
 #ifdef	__cplusplus
 }
diff --git a/usr/src/lib/brand/lx/lx_support/lx_support.c b/usr/src/lib/brand/lx/lx_support/lx_support.c
index ab2fcdb..714fc38 100644
--- a/usr/src/lib/brand/lx/lx_support/lx_support.c
+++ b/usr/src/lib/brand/lx/lx_support/lx_support.c
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -420,6 +420,7 @@
 	struct zone_devtab	devtab;
 	boolean_t		audio, restart;
 	char			*idev, *odev;
+	zone_iptype_t		iptype;
 
 	if ((handle = zonecfg_init_handle()) == NULL)
 		lxs_err(gettext("internal libzonecfg.so.1 error"), 0);
@@ -469,6 +470,20 @@
 		lxs_err(gettext("lx zones do not support added devices"));
 	}
 
+	/*
+	 * Check to see whether the zone has ip-type configured as exclusive
+	 */
+	if (zonecfg_get_iptype(handle, &iptype) != Z_OK) {
+		zonecfg_fini_handle(handle);
+		lxs_err(gettext("zonecfg provided an invalid XML file"));
+	}
+
+	if (iptype == ZS_EXCLUSIVE) {
+		zonecfg_fini_handle(handle);
+		lxs_err(gettext("lx zones do not support an 'exclusive' "
+		    "ip-type"));
+	}
+
 	/* Extract any relevant attributes from the config file. */
 	lxs_getattrs(handle, &restart, &audio, &idev, &odev);
 	zonecfg_fini_handle(handle);
diff --git a/usr/src/lib/brand/lx/zone/platform.xml b/usr/src/lib/brand/lx/zone/platform.xml
index 85e763f..a53f0ee 100644
--- a/usr/src/lib/brand/lx/zone/platform.xml
+++ b/usr/src/lib/brand/lx/zone/platform.xml
@@ -20,7 +20,7 @@
 
  CDDL HEADER END
 
- Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  Use is subject to license terms.
 
  ident	"%Z%%M%	%I%	%E% SMI"
@@ -31,7 +31,7 @@
 <!DOCTYPE platform PUBLIC "-//Sun Microsystems Inc//Zones Platform//EN"
     "file:///usr/share/lib/xml/dtd/zone_platform.dtd.1">
 
-<platform name="lx">
+<platform name="lx" allow-exclusive-ip="false">
 	<!-- Global filesystems to mount when booting the zone -->
 	<global_mount special="/dev" directory="/native/dev" type="dev"
 	    opt="attrdir=%R/dev" />
diff --git a/usr/src/lib/brand/native/zone/platform.xml b/usr/src/lib/brand/native/zone/platform.xml
index d2bbc83..0919348 100644
--- a/usr/src/lib/brand/native/zone/platform.xml
+++ b/usr/src/lib/brand/native/zone/platform.xml
@@ -20,7 +20,7 @@
 
  CDDL HEADER END
 
- Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  Use is subject to license terms.
 
  ident	"%Z%%M%	%I%	%E% SMI"
@@ -31,7 +31,7 @@
 <!DOCTYPE platform PUBLIC "-//Sun Microsystems Inc//Zones Platform//EN"
     "file:///usr/share/lib/xml/dtd/zone_platform.dtd.1">
 
-<platform name="native">
+<platform name="native" allow-exclusive-ip="true">
 
 	<!-- Global filesystems to mount when booting the zone -->
 	<global_mount special="/dev" directory="/dev" type="dev"
@@ -86,6 +86,29 @@
 	<device match="zero" />
 	<device match="zfs" />
 
+	<!-- Devices to create in exclusive IP zone only -->
+	<device match="icmp" ip-type="exclusive" />
+	<device match="icmp6" ip-type="exclusive" />
+	<device match="ip" ip-type="exclusive" />
+	<device match="ip6" ip-type="exclusive" />
+	<device match="ipauth" ip-type="exclusive" />
+	<device match="ipf" ip-type="exclusive" />
+	<device match="ipl" ip-type="exclusive" />
+	<device match="iplookup" ip-type="exclusive" />
+	<device match="ipnat" ip-type="exclusive" />
+	<device match="ipscan" ip-type="exclusive" />
+	<device match="ipsecah" ip-type="exclusive" />
+	<device match="ipsecesp" ip-type="exclusive" />
+	<device match="ipstate" ip-type="exclusive" />
+	<device match="ipsync" ip-type="exclusive" />
+	<device match="keysock" ip-type="exclusive" />
+	<device match="rawip" ip-type="exclusive" />
+	<device match="rawip6" ip-type="exclusive" />
+	<device match="rts" ip-type="exclusive" />
+	<device match="sctp" ip-type="exclusive" />
+	<device match="sctp6" ip-type="exclusive" />
+	<device match="spdsock" ip-type="exclusive" />
+
 	<!-- Renamed devices to create under /dev -->
 	<device match="zcons/%z/zoneconsole" name="zconsole" />
 
diff --git a/usr/src/lib/brand/sn1/zone/platform.xml b/usr/src/lib/brand/sn1/zone/platform.xml
index 01b0348..326f2e2 100644
--- a/usr/src/lib/brand/sn1/zone/platform.xml
+++ b/usr/src/lib/brand/sn1/zone/platform.xml
@@ -20,7 +20,7 @@
 
  CDDL HEADER END
 
- Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  Use is subject to license terms.
 
  ident	"%Z%%M%	%I%	%E% SMI"
@@ -31,7 +31,7 @@
 <!DOCTYPE platform PUBLIC "-//Sun Microsystems Inc//Zones Platform//EN"
     "file:///usr/share/lib/xml/dtd/zone_platform.dtd.1">
 
-<platform name="native">
+<platform name="native" allow-exclusive-ip="true">
 
 	<!-- Global filesystems to mount when booting the zone -->
 	<global_mount special="/dev" directory="/dev" type="dev"
@@ -86,6 +86,29 @@
 	<device match="zero" />
 	<device match="zfs" />
 
+	<!-- Devices to create in exclusive IP zone only -->
+	<device match="icmp" ip-type="exclusive" />
+	<device match="icmp6" ip-type="exclusive" />
+	<device match="ip" ip-type="exclusive" />
+	<device match="ip6" ip-type="exclusive" />
+	<device match="ipauth" ip-type="exclusive" />
+	<device match="ipf" ip-type="exclusive" />
+	<device match="ipl" ip-type="exclusive" />
+	<device match="iplookup" ip-type="exclusive" />
+	<device match="ipnat" ip-type="exclusive" />
+	<device match="ipscan" ip-type="exclusive" />
+	<device match="ipsecah" ip-type="exclusive" />
+	<device match="ipsecesp" ip-type="exclusive" />
+	<device match="ipstate" ip-type="exclusive" />
+	<device match="ipsync" ip-type="exclusive" />
+	<device match="keysock" ip-type="exclusive" />
+	<device match="rawip" ip-type="exclusive" />
+	<device match="rawip6" ip-type="exclusive" />
+	<device match="rts" ip-type="exclusive" />
+	<device match="sctp" ip-type="exclusive" />
+	<device match="sctp6" ip-type="exclusive" />
+	<device match="spdsock" ip-type="exclusive" />
+	
 	<!-- Renamed devices to create under /dev -->
 	<device match="zcons/%z/zoneconsole" name="zconsole" />
 
diff --git a/usr/src/lib/libbrand/common/libbrand.c b/usr/src/lib/libbrand/common/libbrand.c
index 0ce5a93..068d720 100644
--- a/usr/src/lib/libbrand/common/libbrand.c
+++ b/usr/src/lib/libbrand/common/libbrand.c
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -65,8 +65,10 @@
 #define	DTD_ELEM_VERIFY_CFG	((const xmlChar *) "verify_cfg")
 #define	DTD_ELEM_VERIFY_ADM	((const xmlChar *) "verify_adm")
 
+#define	DTD_ATTR_ALLOWEXCL	((const xmlChar *) "allow-exclusive-ip")
 #define	DTD_ATTR_ARCH		((const xmlChar *) "arch")
 #define	DTD_ATTR_DIRECTORY	((const xmlChar *) "directory")
+#define	DTD_ATTR_IPTYPE		((const xmlChar *) "ip-type")
 #define	DTD_ATTR_MATCH		((const xmlChar *) "match")
 #define	DTD_ATTR_MODE		((const xmlChar *) "mode")
 #define	DTD_ATTR_NAME		((const xmlChar *) "name")
@@ -78,6 +80,8 @@
 #define	DTD_ATTR_TARGET		((const xmlChar *) "target")
 #define	DTD_ATTR_TYPE		((const xmlChar *) "type")
 
+#define	DTD_ENTITY_TRUE		"true"
+
 static volatile boolean_t	libbrand_initialized = B_FALSE;
 static char			i_curr_arch[MAXNAMELEN];
 static char			i_curr_zone[ZONENAME_MAX];
@@ -538,6 +542,34 @@
 	return ((strcmp(bhp->bh_name, NATIVE_BRAND_NAME) == 0) ? 1 : 0);
 }
 
+boolean_t
+brand_allow_exclusive_ip(brand_handle_t bh)
+{
+	struct brand_handle	*bhp = (struct brand_handle *)bh;
+	xmlNodePtr		node;
+	xmlChar			*allow_excl;
+	boolean_t		ret;
+
+	assert(bhp != NULL);
+
+	if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL)
+		return (B_FALSE);
+
+	allow_excl = xmlGetProp(node, DTD_ATTR_ALLOWEXCL);
+	if (allow_excl == NULL)
+		return (B_FALSE);
+
+	/* Note: only return B_TRUE if it's "true" */
+	if (strcmp((char *)allow_excl, DTD_ENTITY_TRUE) == 0)
+		ret = B_TRUE;
+	else
+		ret = B_FALSE;
+
+	xmlFree(allow_excl);
+
+	return (ret);
+}
+
 /*
  * Iterate over brand privileges
  *
@@ -738,12 +770,13 @@
  */
 int
 brand_platform_iter_devices(brand_handle_t bh, const char *zonename,
-    int (*func)(void *, const char *, const char *), void *data)
+    int (*func)(void *, const char *, const char *), void *data,
+    const char *curr_iptype)
 {
 	struct brand_handle	*bhp = (struct brand_handle *)bh;
 	const char		*curr_arch = get_curr_arch();
 	xmlNodePtr		node;
-	xmlChar			*match, *name, *arch;
+	xmlChar			*match, *name, *arch, *iptype;
 	char			match_exp[MAXPATHLEN];
 	boolean_t		err = B_FALSE;
 	int			ret = 0;
@@ -752,6 +785,7 @@
 	assert(bhp != NULL);
 	assert(zonename != NULL);
 	assert(func != NULL);
+	assert(curr_iptype != NULL);
 
 	if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL)
 		return (-1);
@@ -764,7 +798,9 @@
 		match = xmlGetProp(node, DTD_ATTR_MATCH);
 		name = xmlGetProp(node, DTD_ATTR_NAME);
 		arch = xmlGetProp(node, DTD_ATTR_ARCH);
-		if ((match == NULL) || (name == NULL) || (arch == NULL)) {
+		iptype = xmlGetProp(node, DTD_ATTR_IPTYPE);
+		if ((match == NULL) || (name == NULL) || (arch == NULL) ||
+		    (iptype == NULL)) {
 			err = B_TRUE;
 			goto next;
 		}
@@ -774,6 +810,11 @@
 		    (strcmp((char *)arch, curr_arch) != 0))
 			goto next;
 
+		/* check if the iptype matches */
+		if ((strcmp((char *)iptype, "all") != 0) &&
+		    (strcmp((char *)iptype, curr_iptype) != 0))
+			goto next;
+
 		/* Substitute token values as needed. */
 		if ((ret = i_substitute_tokens((char *)match,
 		    match_exp, sizeof (match_exp),
@@ -798,6 +839,8 @@
 			xmlFree(name);
 		if (arch != NULL)
 			xmlFree(arch);
+		if (iptype != NULL)
+			xmlFree(iptype);
 		if (err)
 			return (-1);
 		if (ret != 0)
diff --git a/usr/src/lib/libbrand/common/libbrand.h b/usr/src/lib/libbrand/common/libbrand.h
index bb31cee..0254a9f 100644
--- a/usr/src/lib/libbrand/common/libbrand.h
+++ b/usr/src/lib/libbrand/common/libbrand.h
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -42,6 +42,8 @@
 
 extern int brand_is_native(brand_handle_t);
 
+extern boolean_t brand_allow_exclusive_ip(brand_handle_t);
+
 extern int brand_get_boot(brand_handle_t, const char *, const char *,
     char *, size_t, int, char **);
 extern int brand_get_brandname(brand_handle_t, char *, size_t);
@@ -63,7 +65,7 @@
     int (*func)(void *, const char *, const char *), void *);
 
 extern int brand_platform_iter_devices(brand_handle_t, const char *,
-    int (*)(void *, const char *, const char *), void *);
+    int (*)(void *, const char *, const char *), void *, const char *);
 extern int brand_platform_iter_gmounts(brand_handle_t, const char *,
     int (*)(void *, const char *, const char *, const char *, const char *),
     void *);
diff --git a/usr/src/lib/libbrand/common/mapfile-vers b/usr/src/lib/libbrand/common/mapfile-vers
index a9daa75..f420114 100644
--- a/usr/src/lib/libbrand/common/mapfile-vers
+++ b/usr/src/lib/libbrand/common/mapfile-vers
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -27,6 +27,7 @@
 
 SUNWprivate {
     global:
+	brand_allow_exclusive_ip;
 	brand_close;
 	brand_config_iter_privilege;
 	brand_get_boot;
diff --git a/usr/src/lib/libbrand/dtd/zone_platform.dtd.1 b/usr/src/lib/libbrand/dtd/zone_platform.dtd.1
index a9e8c07..28ac8d4 100644
--- a/usr/src/lib/libbrand/dtd/zone_platform.dtd.1
+++ b/usr/src/lib/libbrand/dtd/zone_platform.dtd.1
@@ -20,7 +20,7 @@
 
  CDDL HEADER END
 
- Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  Use is subject to license terms.
 
  ident	"%Z%%M%	%I%	%E% SMI"
@@ -45,11 +45,16 @@
       arch	Identifies devices only available for certain architectures.
 		Can be "sparc" or "i386".
 
+      ip-type	Optional, identifies devices only available for certain IP
+		types. Can be "shared" or "exclusive". If it's not specified,
+		the default value "all" will be used, which means it's
+		available regardless the IP type.
+
     For example, the following entry:
 	<device match="brand/windows/foo" name="bar" arch="sparc" />
     would result in mapping the following global zone device:
 	/dev/brand/windows/foo
-    into the zone as:
+    into the zone (disregarding its IP type) as:
 	/dev/bar
     but the mapping would only exist on sparc machines.
 
@@ -58,7 +63,8 @@
 
 <!ATTLIST device	match	CDATA #REQUIRED
 			name	CDATA ""
-			arch	( sparc | i386 ) "all" >
+			arch	( sparc | i386 ) "all" 
+			ip-type	( shared | exclusive ) "all" >
 
 <!--
   symlink
@@ -138,7 +144,10 @@
       name	The name of the brand.  This must match the name of the
 		directory in which this file is stored, as well as the name
 		of the brand that refers to it.
+      allow-exclusive-ip	Whether the zones of this brand can have their
+				own exclusive IP stack. It is a boolean value. 
 -->
 <!ELEMENT platform	(device | global_mount | mount | symlink)* >
 
-<!ATTLIST platform	name		CDATA #REQUIRED>
+<!ATTLIST platform	name			CDATA #REQUIRED
+			allow-exclusive-ip	(true | false) #REQUIRED>
diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers
index 8e1b399..560ac9d 100644
--- a/usr/src/lib/libc/port/mapfile-vers
+++ b/usr/src/lib/libc/port/mapfile-vers
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -2219,14 +2219,18 @@
 	_xgetwidth;
 	__xpg6 = NODIRECT;
 	_yield;
+	zone_add_datalink;
 	zone_boot;
+	zone_check_datalink;
 	zone_create;
 	zone_destroy;
 	zone_enter;
 	zone_getattr;
 	zone_get_id;
 	zone_list;
+	zone_list_datalink;
 	zonept;
+	zone_remove_datalink;
 	zone_setattr;
 	zone_shutdown;
 	zone_version;
diff --git a/usr/src/lib/libc/port/sys/zone.c b/usr/src/lib/libc/port/sys/zone.c
index 609cf38..7c747d9 100644
--- a/usr/src/lib/libc/port/sys/zone.c
+++ b/usr/src/lib/libc/port/sys/zone.c
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -44,7 +44,7 @@
 zoneid_t
 zone_create(const char *name, const char *root, const struct priv_set *privs,
     const char *rctls, size_t rctlsz, const char *zfs, size_t zfssz,
-    int *extended_error, int match, int doi, const bslabel_t *label)
+    int *extended_error, int match, int doi, const bslabel_t *label, int flags)
 {
 	zone_def  zd;
 	priv_data_t *d;
@@ -63,6 +63,7 @@
 	zd.match = match;
 	zd.doi = doi;
 	zd.label = label;
+	zd.flags = flags;
 
 	return ((zoneid_t)syscall(SYS_zone, ZONE_CREATE, &zd));
 }
@@ -221,3 +222,28 @@
 {
 	return (syscall(SYS_zone, ZONE_VERSION, version));
 }
+
+
+int
+zone_add_datalink(zoneid_t zoneid, char *dlname)
+{
+	return (syscall(SYS_zone, ZONE_ADD_DATALINK, zoneid, dlname));
+}
+
+int
+zone_remove_datalink(zoneid_t zoneid, char *dlname)
+{
+	return (syscall(SYS_zone, ZONE_DEL_DATALINK, zoneid, dlname));
+}
+
+int
+zone_check_datalink(zoneid_t *zoneidp, char *dlname)
+{
+	return (syscall(SYS_zone, ZONE_CHECK_DATALINK, zoneidp, dlname));
+}
+
+int
+zone_list_datalink(zoneid_t zoneid, int *dlnump, char *buf)
+{
+	return (syscall(SYS_zone, ZONE_LIST_DATALINK, zoneid, dlnump, buf));
+}
diff --git a/usr/src/lib/libdladm/common/libdladm.c b/usr/src/lib/libdladm/common/libdladm.c
index 154fc08..2a62bb8 100644
--- a/usr/src/lib/libdladm/common/libdladm.c
+++ b/usr/src/lib/libdladm/common/libdladm.c
@@ -19,12 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
+#include <ctype.h>
 #include <unistd.h>
 #include <stropts.h>
 #include <errno.h>
@@ -38,6 +39,7 @@
 #include <libdevinfo.h>
 #include <libdladm_impl.h>
 #include <libintl.h>
+#include <sys/vlan.h>
 
 typedef struct dladm_dev {
 	char			dd_name[IFNAMSIZ];
@@ -162,6 +164,74 @@
 }
 
 /*
+ * Hold a data-link.
+ */
+static int
+i_dladm_hold_link(const char *name, zoneid_t zoneid, boolean_t docheck)
+{
+	int		fd;
+	dld_hold_vlan_t	dhv;
+
+	if (strlen(name) >= IFNAMSIZ) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
+		return (-1);
+
+	bzero(&dhv, sizeof (dld_hold_vlan_t));
+	(void) strlcpy(dhv.dhv_name, name, IFNAMSIZ);
+	dhv.dhv_zid = zoneid;
+	dhv.dhv_docheck = docheck;
+
+	if (i_dladm_ioctl(fd, DLDIOCHOLDVLAN, &dhv, sizeof (dhv)) < 0) {
+		int olderrno = errno;
+
+		(void) close(fd);
+		errno = olderrno;
+		return (-1);
+	}
+
+	(void) close(fd);
+	return (0);
+}
+
+/*
+ * Release a data-link.
+ */
+static int
+i_dladm_rele_link(const char *name, zoneid_t zoneid, boolean_t docheck)
+{
+	int		fd;
+	dld_hold_vlan_t	dhv;
+
+	if (strlen(name) >= IFNAMSIZ) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
+		return (-1);
+
+	bzero(&dhv, sizeof (dld_hold_vlan_t));
+	(void) strlcpy(dhv.dhv_name, name, IFNAMSIZ);
+	dhv.dhv_zid = zoneid;
+	dhv.dhv_docheck = docheck;
+
+	if (i_dladm_ioctl(fd, DLDIOCRELEVLAN, &dhv, sizeof (dhv)) < 0) {
+		int olderrno = errno;
+
+		(void) close(fd);
+		errno = olderrno;
+		return (-1);
+	}
+
+	(void) close(fd);
+	return (0);
+}
+
+/*
  * Invoke the specified callback function for each active DDI_NT_NET
  * node.
  */
@@ -186,7 +256,6 @@
 	ddp = dw.dw_dev_list;
 	while (ddp) {
 		fn(arg, ddp->dd_name);
-		(void) dladm_walk_vlan(fn, arg, ddp->dd_name);
 		last_ddp = ddp;
 		ddp = ddp->dd_next;
 		free(last_ddp);
@@ -304,6 +373,9 @@
 	case DLADM_STATUS_IOERR:
 		s = "I/O error";
 		break;
+	case DLADM_STATUS_TEMPONLY:
+		s = "change cannot be persistent, specify -t please";
+		break;
 	default:
 		s = "<unknown error>";
 		break;
@@ -506,3 +578,21 @@
 	(void) closedir(dp);
 	return (DLADM_STATUS_OK);
 }
+
+/*
+ * Do a "hold" operation to a link.
+ */
+int
+dladm_hold_link(const char *name, zoneid_t zoneid, boolean_t docheck)
+{
+	return (i_dladm_hold_link(name, zoneid, docheck));
+}
+
+/*
+ * Do a "release" operation to a link.
+ */
+int
+dladm_rele_link(const char *name, zoneid_t zoneid, boolean_t docheck)
+{
+	return (i_dladm_rele_link(name, zoneid, docheck));
+}
diff --git a/usr/src/lib/libdladm/common/libdladm.h b/usr/src/lib/libdladm/common/libdladm.h
index 1cf3700..7421ab1 100644
--- a/usr/src/lib/libdladm/common/libdladm.h
+++ b/usr/src/lib/libdladm/common/libdladm.h
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -64,7 +64,8 @@
 	DLADM_STATUS_BADVALCNT,
 	DLADM_STATUS_DBNOTFOUND,
 	DLADM_STATUS_DENIED,
-	DLADM_STATUS_IOERR
+	DLADM_STATUS_IOERR,
+	DLADM_STATUS_TEMPONLY
 } dladm_status_t;
 
 typedef enum {
@@ -82,13 +83,16 @@
 extern int	dladm_walk(dladm_walkcb_t *, void *);
 extern int	dladm_walk_vlan(dladm_walkcb_t *, void *, const char *);
 extern int	dladm_info(const char *, dladm_attr_t *);
+extern int	dladm_hold_link(const char *, zoneid_t, boolean_t);
+extern int	dladm_rele_link(const char *, zoneid_t, boolean_t);
 
 extern dladm_status_t	dladm_set_prop(const char *, const char *,
-			    char **, uint_t, uint_t);
+			    char **, uint_t, uint_t, char **);
 extern dladm_status_t	dladm_get_prop(const char *, dladm_prop_type_t,
 			    const char *, char **, uint_t *);
 extern dladm_status_t	dladm_walk_prop(const char *, void *,
 			    boolean_t (*)(void *, const char *));
+extern boolean_t	dladm_is_prop_temponly(const char *, char **);
 
 extern dladm_status_t	dladm_set_secobj(const char *, dladm_secobj_class_t,
 			    uint8_t *, uint_t, uint_t);
diff --git a/usr/src/lib/libdladm/common/linkprop.c b/usr/src/lib/libdladm/common/linkprop.c
index 8e1ef84..e3b9ed3 100644
--- a/usr/src/lib/libdladm/common/linkprop.c
+++ b/usr/src/lib/libdladm/common/linkprop.c
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -29,14 +29,66 @@
 #include <strings.h>
 #include <errno.h>
 #include <ctype.h>
+#include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/dld.h>
+#include <sys/zone.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <libdevinfo.h>
+#include <zone.h>
 #include <libwladm.h>
 #include <libdladm_impl.h>
 
+#include <dlfcn.h>
+#include <link.h>
+
 static dladm_status_t	i_dladm_set_prop_db(const char *, const char *,
 			    char **, uint_t);
 static dladm_status_t	i_dladm_get_prop_db(const char *, const char *,
 			    char **, uint_t *);
+static dladm_status_t	i_dladm_get_prop_temp(const char *, dladm_prop_type_t,
+			    const char *, char **, uint_t *);
+static dladm_status_t	i_dladm_set_prop_temp(const char *, const char *,
+			    char **, uint_t, uint_t, char **);
+static boolean_t	i_dladm_is_prop_temponly(const char *prop_name,
+			    char **);
+
+typedef struct val_desc {
+	char	*vd_name;
+	void	*vd_val;
+} val_desc_t;
+
+struct prop_desc;
+
+typedef dladm_status_t	pd_getf_t(const char *, char **, uint_t *);
+typedef dladm_status_t	pd_setf_t(const char *, val_desc_t *, uint_t);
+typedef dladm_status_t	pd_checkf_t(struct prop_desc *, char **,
+			    uint_t, val_desc_t **);
+
+static pd_getf_t	do_get_zone;
+static pd_setf_t	do_set_zone;
+static pd_checkf_t	do_check_zone;
+
+typedef struct prop_desc {
+	char		*pd_name;
+	val_desc_t	pd_defval;
+	val_desc_t	*pd_modval;
+	uint_t		pd_nmodval;
+	boolean_t	pd_temponly;
+	pd_setf_t	*pd_set;
+	pd_getf_t	*pd_getmod;
+	pd_getf_t	*pd_get;
+	pd_checkf_t	*pd_check;
+} prop_desc_t;
+
+static prop_desc_t	prop_table[] = {
+	{ "zone",	{ "", NULL }, NULL, 0, B_TRUE,
+	    do_set_zone, NULL,
+	    do_get_zone, do_check_zone}
+};
+
+#define	MAX_PROPS	(sizeof (prop_table) / sizeof (prop_desc_t))
 
 /*
  * Convert a wladm_status_t to a dladm_status_t. This is used by wrappers
@@ -79,7 +131,7 @@
 
 dladm_status_t
 dladm_set_prop(const char *link, const char *prop_name, char **prop_val,
-    uint_t val_cnt, uint_t flags)
+    uint_t val_cnt, uint_t flags, char **errprop)
 {
 	dladm_status_t		status = DLADM_STATUS_BADARG;
 
@@ -88,15 +140,27 @@
 		return (DLADM_STATUS_BADARG);
 
 	if ((flags & DLADM_OPT_TEMP) != 0) {
-		if (wladm_is_valid(link)) {
-			status = dladm_wladmstatus2status(
-			    wladm_set_prop(link, prop_name,
-			    prop_val, val_cnt));
+		status = i_dladm_set_prop_temp(link, prop_name, prop_val,
+		    val_cnt, flags, errprop);
+		if (status == DLADM_STATUS_TEMPONLY &&
+		    (flags & DLADM_OPT_PERSIST) != 0)
+			return (DLADM_STATUS_TEMPONLY);
+
+		if (status == DLADM_STATUS_NOTFOUND) {
+			status = DLADM_STATUS_BADARG;
+			if (wladm_is_valid(link)) {
+				status = dladm_wladmstatus2status(
+				    wladm_set_prop(link, prop_name,
+				    prop_val, val_cnt, errprop));
+			}
 		}
 		if (status != DLADM_STATUS_OK)
 			return (status);
 	}
 	if ((flags & DLADM_OPT_PERSIST) != 0) {
+		if (i_dladm_is_prop_temponly(prop_name, errprop))
+			return (DLADM_STATUS_TEMPONLY);
+
 		status = i_dladm_set_prop_db(link, prop_name,
 		    prop_val, val_cnt);
 	}
@@ -107,20 +171,35 @@
 dladm_walk_prop(const char *link, void *arg,
     boolean_t (*func)(void *, const char *))
 {
+	int	i;
+
 	if (link == NULL || func == NULL)
 		return (DLADM_STATUS_BADARG);
 
+	/* For wifi links, show wifi properties first */
 	if (wladm_is_valid(link)) {
-		return (dladm_wladmstatus2status(
-		    wladm_walk_prop(link, arg, func)));
+		dladm_status_t	status;
+
+		status = dladm_wladmstatus2status(
+		    wladm_walk_prop(link, arg, func));
+		if (status != DLADM_STATUS_OK)
+			return (status);
 	}
-	return (DLADM_STATUS_BADARG);
+
+	/* Then show data-link properties if there are any */
+	for (i = 0; i < MAX_PROPS; i++) {
+		if (!func(arg, prop_table[i].pd_name))
+			break;
+	}
+	return (DLADM_STATUS_OK);
 }
 
 dladm_status_t
 dladm_get_prop(const char *link, dladm_prop_type_t type,
     const char *prop_name, char **prop_val, uint_t *val_cntp)
 {
+	dladm_status_t status;
+
 	if (link == NULL || prop_name == NULL || prop_val == NULL ||
 	    val_cntp == NULL || *val_cntp == 0)
 		return (DLADM_STATUS_BADARG);
@@ -130,6 +209,11 @@
 		    prop_val, val_cntp));
 	}
 
+	status = i_dladm_get_prop_temp(link, type, prop_name,
+	    prop_val, val_cntp);
+	if (status != DLADM_STATUS_NOTFOUND)
+		return (status);
+
 	if (wladm_is_valid(link)) {
 		wladm_prop_type_t	wtype;
 
@@ -421,7 +505,7 @@
 			propval[i] = (char *)lvp->lv_name;
 
 		status = dladm_set_prop(lsp->ls_link, lip->li_name,
-		    propval, valcnt, DLADM_OPT_TEMP);
+		    propval, valcnt, DLADM_OPT_TEMP, NULL);
 
 		/*
 		 * We continue with initializing other properties even
@@ -698,3 +782,422 @@
 
 	return (LINKPROP_RW_DB(&state, B_FALSE));
 }
+
+static dladm_status_t
+i_dladm_get_zoneid(const char *link, zoneid_t *zidp)
+{
+	int fd;
+	dld_hold_vlan_t	dhv;
+
+	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
+		return (dladm_errno2status(errno));
+
+	bzero(&dhv, sizeof (dld_hold_vlan_t));
+	(void) strlcpy(dhv.dhv_name, link, IFNAMSIZ);
+	dhv.dhv_zid = -1;
+
+	if (i_dladm_ioctl(fd, DLDIOCZIDGET, &dhv, sizeof (dhv)) < 0 &&
+	    errno != ENOENT) {
+		dladm_status_t status = dladm_errno2status(errno);
+
+		(void) close(fd);
+		return (status);
+	}
+
+	if (errno == ENOENT)
+		*zidp = GLOBAL_ZONEID;
+	else
+		*zidp = dhv.dhv_zid;
+
+	(void) close(fd);
+	return (DLADM_STATUS_OK);
+}
+
+typedef int (*zone_get_devroot_t)(char *, char *, size_t);
+
+static int
+i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen)
+{
+	char			root[MAXPATHLEN];
+	zone_get_devroot_t	real_zone_get_devroot;
+	void			*dlhandle;
+	void			*sym;
+	int			ret;
+
+	if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL)
+		return (-1);
+
+	if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) {
+		(void) dlclose(dlhandle);
+		return (-1);
+	}
+
+	real_zone_get_devroot = (zone_get_devroot_t)sym;
+
+	if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0)
+		(void) snprintf(dev, devlen, "%s%s", root, "/dev");
+	(void) dlclose(dlhandle);
+	return (ret);
+}
+
+static dladm_status_t
+i_dladm_add_deventry(zoneid_t zid, const char *link)
+{
+	char		path[MAXPATHLEN];
+	di_prof_t	prof = NULL;
+	char		zone_name[ZONENAME_MAX];
+	dladm_status_t	status;
+
+	if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
+		return (dladm_errno2status(errno));
+	if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0)
+		return (dladm_errno2status(errno));
+	if (di_prof_init(path, &prof) != 0)
+		return (dladm_errno2status(errno));
+
+	status = DLADM_STATUS_OK;
+	if (di_prof_add_dev(prof, link) != 0) {
+		status = dladm_errno2status(errno);
+		goto cleanup;
+	}
+	if (di_prof_commit(prof) != 0)
+		status = dladm_errno2status(errno);
+cleanup:
+	if (prof)
+		di_prof_fini(prof);
+
+	return (status);
+}
+
+static dladm_status_t
+i_dladm_remove_deventry(zoneid_t zid, const char *link)
+{
+	char		path[MAXPATHLEN];
+	di_prof_t	prof = NULL;
+	char		zone_name[ZONENAME_MAX];
+	dladm_status_t	status;
+
+	if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
+		return (dladm_errno2status(errno));
+	if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0)
+		return (dladm_errno2status(errno));
+	if (di_prof_init(path, &prof) != 0)
+		return (dladm_errno2status(errno));
+
+	status = DLADM_STATUS_OK;
+	if (di_prof_add_exclude(prof, link) != 0) {
+		status = dladm_errno2status(errno);
+		goto cleanup;
+	}
+	if (di_prof_commit(prof) != 0)
+		status = dladm_errno2status(errno);
+cleanup:
+	if (prof)
+		di_prof_fini(prof);
+
+	return (status);
+}
+
+static dladm_status_t
+do_get_zone(const char *link, char **prop_val, uint_t *val_cnt)
+{
+	char		zone_name[ZONENAME_MAX];
+	zoneid_t	zid;
+	dladm_status_t	status;
+
+	status = i_dladm_get_zoneid(link, &zid);
+	if (status != DLADM_STATUS_OK)
+		return (status);
+
+	*val_cnt = 1;
+	if (zid != GLOBAL_ZONEID) {
+		if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
+			return (dladm_errno2status(errno));
+
+		(void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX);
+	} else {
+		*prop_val[0] = '\0';
+	}
+
+	return (DLADM_STATUS_OK);
+}
+
+static dladm_status_t
+do_set_zone(const char *link, val_desc_t *vdp, uint_t val_cnt)
+{
+	dladm_status_t	status;
+	zoneid_t	zid_old, zid_new;
+	char		buff[IF_NAMESIZE + 1];
+	struct stat	st;
+
+	if (val_cnt != 1)
+		return (DLADM_STATUS_BADVALCNT);
+
+	status = i_dladm_get_zoneid(link, &zid_old);
+	if (status != DLADM_STATUS_OK)
+		return (status);
+
+	/* Do nothing if setting to current value */
+	zid_new = (zoneid_t)vdp->vd_val;
+	if (zid_new == zid_old)
+		return (DLADM_STATUS_OK);
+
+	/* Do a stat to get the vlan created by MAC, if it's not there */
+	(void) strcpy(buff, "/dev/");
+	(void) strlcat(buff, link, IF_NAMESIZE);
+	(void) stat(buff, &st);
+
+	if (zid_old != GLOBAL_ZONEID) {
+		if (dladm_rele_link(link, GLOBAL_ZONEID, B_TRUE) < 0)
+			return (dladm_errno2status(errno));
+
+		if (zone_remove_datalink(zid_old, (char *)link) != 0 &&
+		    errno != ENXIO) {
+			status = dladm_errno2status(errno);
+			goto rollback1;
+		}
+
+		status = i_dladm_remove_deventry(zid_old, link);
+		if (status != DLADM_STATUS_OK)
+			goto rollback2;
+	}
+
+	if (zid_new != GLOBAL_ZONEID) {
+		if (zone_add_datalink(zid_new, (char *)link) != 0) {
+			status = dladm_errno2status(errno);
+			goto rollback3;
+		}
+
+		if (dladm_hold_link(link, zid_new, B_TRUE) < 0) {
+			(void) zone_remove_datalink(zid_new, (char *)link);
+			status = dladm_errno2status(errno);
+			goto rollback3;
+		}
+
+		status = i_dladm_add_deventry(zid_new, link);
+		if (status != DLADM_STATUS_OK) {
+			(void) dladm_rele_link(link, GLOBAL_ZONEID, B_FALSE);
+			(void) zone_remove_datalink(zid_new, (char *)link);
+			goto rollback3;
+		}
+	}
+	return (DLADM_STATUS_OK);
+
+rollback3:
+	if (zid_old != GLOBAL_ZONEID)
+		(void) i_dladm_add_deventry(zid_old, link);
+rollback2:
+	if (zid_old != GLOBAL_ZONEID)
+		(void) zone_add_datalink(zid_old, (char *)link);
+rollback1:
+	(void) dladm_hold_link(link, zid_old, B_FALSE);
+cleanexit:
+	return (status);
+}
+
+/* ARGSUSED */
+static dladm_status_t
+do_check_zone(prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
+    val_desc_t **vdpp)
+{
+	zoneid_t 	zid;
+	val_desc_t	*vdp = NULL;
+
+	if (val_cnt != 1)
+		return (DLADM_STATUS_BADVALCNT);
+
+	if ((zid = getzoneidbyname(*prop_val)) == -1)
+		return (DLADM_STATUS_BADVAL);
+
+	if (zid != GLOBAL_ZONEID) {
+		ushort_t	flags;
+
+		if (zone_getattr(zid, ZONE_ATTR_FLAGS, &flags,
+		    sizeof (flags)) < 0) {
+			return (dladm_errno2status(errno));
+		}
+
+		if (!(flags & ZF_NET_EXCL)) {
+			return (DLADM_STATUS_BADVAL);
+		}
+	}
+
+	vdp = malloc(sizeof (val_desc_t));
+	if (vdp == NULL)
+		return (DLADM_STATUS_NOMEM);
+
+	vdp->vd_val = (void *)zid;
+	*vdpp = vdp;
+	return (DLADM_STATUS_OK);
+}
+
+static dladm_status_t
+i_dladm_get_prop_temp(const char *link, dladm_prop_type_t type,
+    const char *prop_name, char **prop_val, uint_t *val_cntp)
+{
+	int 		i;
+	dladm_status_t	status;
+	uint_t		cnt;
+	prop_desc_t	*pdp;
+
+	if (link == NULL || prop_name == NULL || prop_val == NULL ||
+	    val_cntp == NULL || *val_cntp == 0)
+		return (DLADM_STATUS_BADARG);
+
+	for (i = 0; i < MAX_PROPS; i++)
+		if (strcasecmp(prop_name, prop_table[i].pd_name) == 0)
+			break;
+
+	if (i == MAX_PROPS)
+		return (DLADM_STATUS_NOTFOUND);
+
+	pdp = &prop_table[i];
+	status = DLADM_STATUS_OK;
+
+	switch (type) {
+	case DLADM_PROP_VAL_CURRENT:
+		status = pdp->pd_get(link, prop_val, val_cntp);
+		break;
+	case DLADM_PROP_VAL_DEFAULT:
+		if (pdp->pd_defval.vd_name == NULL) {
+			status = DLADM_STATUS_NOTSUP;
+			break;
+		}
+		(void) strcpy(*prop_val, pdp->pd_defval.vd_name);
+		*val_cntp = 1;
+		break;
+
+	case DLADM_PROP_VAL_MODIFIABLE:
+		if (pdp->pd_getmod != NULL) {
+			status = pdp->pd_getmod(link, prop_val, val_cntp);
+			break;
+		}
+		cnt = pdp->pd_nmodval;
+		if (cnt == 0) {
+			status = DLADM_STATUS_NOTSUP;
+		} else if (cnt > *val_cntp) {
+			status = DLADM_STATUS_TOOSMALL;
+		} else {
+			for (i = 0; i < cnt; i++) {
+				(void) strcpy(prop_val[i],
+				    pdp->pd_modval[i].vd_name);
+			}
+			*val_cntp = cnt;
+		}
+		break;
+	default:
+		status = DLADM_STATUS_BADARG;
+		break;
+	}
+
+	return (status);
+}
+
+static dladm_status_t
+i_dladm_set_one_prop_temp(const char *link, prop_desc_t *pdp, char **prop_val,
+    uint_t val_cnt, uint_t flags)
+{
+	dladm_status_t	status;
+	val_desc_t	*vdp = NULL;
+	uint_t		cnt;
+
+	if (pdp->pd_temponly && (flags & DLADM_OPT_PERSIST) != 0)
+		return (DLADM_STATUS_TEMPONLY);
+
+	if (pdp->pd_set == NULL)
+		return (DLADM_STATUS_PROPRDONLY);
+
+	if (prop_val != NULL) {
+		if (pdp->pd_check != NULL)
+			status = pdp->pd_check(pdp, prop_val, val_cnt, &vdp);
+		else
+			status = DLADM_STATUS_BADARG;
+
+		if (status != DLADM_STATUS_OK)
+			return (status);
+
+		cnt = val_cnt;
+	} else {
+		if (pdp->pd_defval.vd_name == NULL)
+			return (DLADM_STATUS_NOTSUP);
+
+		if ((vdp = malloc(sizeof (val_desc_t))) == NULL)
+			return (DLADM_STATUS_NOMEM);
+
+		(void) memcpy(vdp, &pdp->pd_defval, sizeof (val_desc_t));
+		cnt = 1;
+	}
+
+	status = pdp->pd_set(link, vdp, cnt);
+
+	free(vdp);
+	return (status);
+}
+
+static dladm_status_t
+i_dladm_set_prop_temp(const char *link, const char *prop_name, char **prop_val,
+    uint_t val_cnt, uint_t flags, char **errprop)
+{
+	int 		i;
+	dladm_status_t	status = DLADM_STATUS_OK;
+	boolean_t	found = B_FALSE;
+
+	for (i = 0; i < MAX_PROPS; i++) {
+		prop_desc_t	*pdp = &prop_table[i];
+		dladm_status_t	s;
+
+		if (prop_name != NULL &&
+		    (strcasecmp(prop_name, pdp->pd_name) != 0))
+			continue;
+
+		found = B_TRUE;
+		s = i_dladm_set_one_prop_temp(link, pdp, prop_val, val_cnt,
+		    flags);
+
+		if (prop_name != NULL) {
+			status = s;
+			break;
+		} else {
+			if (s != DLADM_STATUS_OK &&
+			    s != DLADM_STATUS_NOTSUP) {
+				if (errprop != NULL)
+					*errprop = pdp->pd_name;
+				status = s;
+				break;
+			}
+		}
+	}
+
+	if (!found)
+		status = DLADM_STATUS_NOTFOUND;
+
+	return (status);
+}
+
+static boolean_t
+i_dladm_is_prop_temponly(const char *prop_name, char **errprop)
+{
+	int 		i;
+
+	for (i = 0; i < MAX_PROPS; i++) {
+		prop_desc_t	*pdp = &prop_table[i];
+
+		if (prop_name != NULL &&
+		    (strcasecmp(prop_name, pdp->pd_name) != 0))
+			continue;
+
+		if (errprop != NULL)
+			*errprop = pdp->pd_name;
+
+		if (pdp->pd_temponly)
+			return (B_TRUE);
+	}
+
+	return (B_FALSE);
+}
+
+boolean_t
+dladm_is_prop_temponly(const char *prop_name, char **errprop)
+{
+	return (i_dladm_is_prop_temponly(prop_name, errprop));
+}
diff --git a/usr/src/lib/libdladm/common/mapfile-vers b/usr/src/lib/libdladm/common/mapfile-vers
index 2af8201..34d1e2c 100644
--- a/usr/src/lib/libdladm/common/mapfile-vers
+++ b/usr/src/lib/libdladm/common/mapfile-vers
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -33,6 +33,7 @@
 	dladm_get_prop;
 	dladm_set_prop;
 	dladm_walk_prop;
+	dladm_is_prop_temponly;
 	dladm_get_secobj;
 	dladm_set_secobj;
 	dladm_unset_secobj;
@@ -44,6 +45,8 @@
 	dladm_init_secobj;
 	dladm_set_rootdir;
 
+	dladm_hold_link;
+	dladm_rele_link;
     local:
 	*;
 };
diff --git a/usr/src/lib/libsecdb/exec_attr.txt b/usr/src/lib/libsecdb/exec_attr.txt
index 40de76e..e568985 100644
--- a/usr/src/lib/libsecdb/exec_attr.txt
+++ b/usr/src/lib/libsecdb/exec_attr.txt
@@ -104,12 +104,12 @@
 File System Management:suser:cmd:::/usr/sbin/umountall:uid=0
 File System Management:suser:cmd:::/usr/sbin/unshare:uid=0;gid=root
 File System Management:suser:cmd:::/usr/sbin/unshareall:uid=0;gid=root
-IP Filter Management:solaris:cmd:::/usr/sbin/ipf:privs=sys_net_config
-IP Filter Management:solaris:cmd:::/usr/sbin/ipfs:privs=sys_net_config
-IP Filter Management:solaris:cmd:::/usr/sbin/ipmon:privs=sys_net_config
-IP Filter Management:solaris:cmd:::/usr/sbin/ipfstat:privs=sys_net_config;gid=sys
-IP Filter Management:solaris:cmd:::/usr/sbin/ipnat:privs=sys_net_config;gid=sys
-IP Filter Management:solaris:cmd:::/usr/sbin/ippool:privs=sys_net_config;gid=sys
+IP Filter Management:solaris:cmd:::/usr/sbin/ipf:privs=sys_ip_config
+IP Filter Management:solaris:cmd:::/usr/sbin/ipfs:privs=sys_ip_config
+IP Filter Management:solaris:cmd:::/usr/sbin/ipmon:privs=sys_ip_config
+IP Filter Management:solaris:cmd:::/usr/sbin/ipfstat:privs=sys_ip_config;gid=sys
+IP Filter Management:solaris:cmd:::/usr/sbin/ipnat:privs=sys_ip_config;gid=sys
+IP Filter Management:solaris:cmd:::/usr/sbin/ippool:privs=sys_ip_config;gid=sys
 Kerberos Server Management:solaris:cmd:::/usr/lib/krb5/krb5kdc:uid=0
 Kerberos Server Management:solaris:cmd:::/usr/lib/krb5/kadmind:uid=0
 Kerberos Server Management:solaris:cmd:::/usr/lib/krb5/kprop:euid=0;privs=none
@@ -175,9 +175,9 @@
 Name Service Security:suser:cmd:::/usr/sbin/nislog:euid=0
 Name Service Security:suser:cmd:::/usr/sbin/rpc.nisd:uid=0;gid=0
 Network Management:solaris:cmd:::/sbin/ifconfig:uid=0
-Network Management:solaris:cmd:::/sbin/route:privs=sys_net_config
+Network Management:solaris:cmd:::/sbin/route:privs=sys_ip_config
 Network Management:solaris:cmd:::/sbin/routeadm:euid=0;\
-	privs=proc_chroot,proc_owner,sys_net_config
+	privs=proc_chroot,proc_owner,sys_ip_config
 Network Management:solaris:cmd:::/sbin/dladm:euid=dladm;egid=sys;\
 	privs=sys_net_config,net_rawaccess,proc_audit
 Network Management:suser:cmd:::/usr/bin/netstat:uid=0
@@ -194,15 +194,15 @@
 Network Management:suser:cmd:::/usr/sbin/spray:euid=0
 Network Link Security:solaris:cmd:::/sbin/dladm:euid=dladm;egid=sys;\
 	privs=sys_net_config,net_rawaccess,proc_audit
-Network Security:solaris:cmd:::/usr/lib/inet/certdb:privs=sys_net_config
-Network Security:solaris:cmd:::/usr/lib/inet/certlocal:privs=sys_net_config
-Network Security:solaris:cmd:::/usr/lib/inet/certrldb:privs=sys_net_config
-Network Security:solaris:cmd:::/usr/lib/inet/in.iked:privs=sys_net_config,net_privaddr
-Network Security:solaris:cmd:::/usr/sbin/ikeadm:privs=sys_net_config
-Network Security:solaris:cmd:::/usr/sbin/ikecert:privs=sys_net_config
-Network Security:solaris:cmd:::/usr/sbin/ipsecconf:privs=sys_net_config
-Network Security:solaris:cmd:::/usr/sbin/ipseckey:privs=sys_net_config
-Network Security:solaris:cmd:::/usr/sbin/ipsecalgs:privs=sys_net_config
+Network Security:solaris:cmd:::/usr/lib/inet/certdb:privs=sys_ip_config
+Network Security:solaris:cmd:::/usr/lib/inet/certlocal:privs=sys_ip_config
+Network Security:solaris:cmd:::/usr/lib/inet/certrldb:privs=sys_ip_config
+Network Security:solaris:cmd:::/usr/lib/inet/in.iked:privs=sys_ip_config,net_privaddr
+Network Security:solaris:cmd:::/usr/sbin/ikeadm:privs=sys_ip_config
+Network Security:solaris:cmd:::/usr/sbin/ikecert:privs=sys_ip_config
+Network Security:solaris:cmd:::/usr/sbin/ipsecconf:privs=sys_ip_config
+Network Security:solaris:cmd:::/usr/sbin/ipseckey:privs=sys_ip_config
+Network Security:solaris:cmd:::/usr/sbin/ipsecalgs:privs=sys_ip_config
 Network Security:solaris:cmd:::/usr/sbin/ksslcfg:euid=0
 Network Security:suser:cmd:::/usr/bin/ssh-keygen:uid=0;gid=sys
 Network Security:suser:cmd:::/usr/lib/inet/certdb:euid=0
diff --git a/usr/src/lib/libwladm/common/libwladm.c b/usr/src/lib/libwladm/common/libwladm.c
index 567be61..7724008 100644
--- a/usr/src/lib/libwladm/common/libwladm.c
+++ b/usr/src/lib/libwladm/common/libwladm.c
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -1054,7 +1054,7 @@
 
 wladm_status_t
 wladm_set_prop(const char *link, const char *prop_name,
-    char **prop_val, uint_t val_cnt)
+    char **prop_val, uint_t val_cnt, char **errprop)
 {
 	int		fd, i;
 	wldp_t		*gbuf = NULL;
@@ -1089,8 +1089,12 @@
 			break;
 		} else {
 			if (s != WLADM_STATUS_OK &&
-			    s != WLADM_STATUS_NOTSUP)
+			    s != WLADM_STATUS_NOTSUP) {
+				if (errprop != NULL)
+					*errprop = pdp->pd_name;
 				status = s;
+				break;
+			}
 		}
 	}
 	if (!found)
diff --git a/usr/src/lib/libwladm/common/libwladm.h b/usr/src/lib/libwladm/common/libwladm.h
index 0a5d24d..45122cf 100644
--- a/usr/src/lib/libwladm/common/libwladm.h
+++ b/usr/src/lib/libwladm/common/libwladm.h
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -174,7 +174,7 @@
 extern wladm_status_t	wladm_walk(void *, boolean_t (*)(void *, const char *));
 extern boolean_t	wladm_is_valid(const char *);
 extern wladm_status_t	wladm_set_prop(const char *, const char *, char **,
-			    uint_t);
+			    uint_t, char **);
 extern wladm_status_t	wladm_walk_prop(const char *, void *,
 			    boolean_t (*)(void *, const char *));
 extern wladm_status_t	wladm_get_prop(const char *, wladm_prop_type_t,
diff --git a/usr/src/lib/libzonecfg/common/libzonecfg.c b/usr/src/lib/libzonecfg/common/libzonecfg.c
index 1a3fb37..cce47ce 100644
--- a/usr/src/lib/libzonecfg/common/libzonecfg.c
+++ b/usr/src/lib/libzonecfg/common/libzonecfg.c
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -45,6 +45,7 @@
 #include <sys/mnttab.h>
 #include <sys/nvpair.h>
 #include <sys/types.h>
+#include <sys/sockio.h>
 #include <ftw.h>
 #include <pool.h>
 #include <libscf.h>
@@ -65,7 +66,6 @@
 #include <libzonecfg.h>
 #include "zonecfg_impl.h"
 
-
 #define	_PATH_TMPFILE	"/zonecfg.XXXXXX"
 #define	ZONE_CB_RETRY_COUNT		10
 #define	ZONE_EVENT_PING_SUBCLASS	"ping"
@@ -95,6 +95,7 @@
 #define	DTD_ATTR_ACTION		(const xmlChar *) "action"
 #define	DTD_ATTR_ADDRESS	(const xmlChar *) "address"
 #define	DTD_ATTR_AUTOBOOT	(const xmlChar *) "autoboot"
+#define	DTD_ATTR_IPTYPE		(const xmlChar *) "ip-type"
 #define	DTD_ATTR_DIR		(const xmlChar *) "directory"
 #define	DTD_ATTR_LIMIT		(const xmlChar *) "limit"
 #define	DTD_ATTR_LIMITPRIV	(const xmlChar *) "limitpriv"
@@ -1497,6 +1498,69 @@
 	return (error);
 }
 
+int
+zonecfg_get_iptype(zone_dochandle_t handle, zone_iptype_t *iptypep)
+{
+	char property[10]; /* 10 is big enough for "shared"/"exclusive" */
+	int err;
+
+	err = getrootattr(handle, DTD_ATTR_IPTYPE, property, sizeof (property));
+	if (err == Z_BAD_PROPERTY) {
+		/* Return default value */
+		*iptypep = ZS_SHARED;
+		return (Z_OK);
+	} else if (err != Z_OK) {
+		return (err);
+	}
+
+	if (strlen(property) == 0 ||
+	    strcmp(property, "shared") == 0)
+		*iptypep = ZS_SHARED;
+	else if (strcmp(property, "exclusive") == 0)
+		*iptypep = ZS_EXCLUSIVE;
+	else
+		return (Z_INVAL);
+
+	return (Z_OK);
+}
+
+int
+zonecfg_set_iptype(zone_dochandle_t handle, zone_iptype_t iptype)
+{
+	xmlNodePtr cur;
+
+	if (handle == NULL)
+		return (Z_INVAL);
+
+	cur = xmlDocGetRootElement(handle->zone_dh_doc);
+	if (cur == NULL) {
+		return (Z_EMPTY_DOCUMENT);
+	}
+
+	if (xmlStrcmp(cur->name, DTD_ELEM_ZONE) != 0) {
+		return (Z_WRONG_DOC_TYPE);
+	}
+	switch (iptype) {
+	case ZS_SHARED:
+		/*
+		 * Since "shared" is the default, we don't write it to the
+		 * configuration file, so that it's easier to migrate those
+		 * zones elsewhere, eg., to systems which are not IP-Instances
+		 * aware.
+		 * xmlUnsetProp only fails when the attribute doesn't exist,
+		 * which we don't care.
+		 */
+		(void) xmlUnsetProp(cur, DTD_ATTR_IPTYPE);
+		break;
+	case ZS_EXCLUSIVE:
+		if (xmlSetProp(cur, DTD_ATTR_IPTYPE,
+		    (const xmlChar *) "exclusive") == NULL)
+			return (Z_INVAL);
+		break;
+	}
+	return (Z_OK);
+}
+
 static int
 newprop(xmlNodePtr node, const xmlChar *attrname, char *src)
 {
@@ -2038,6 +2102,30 @@
 	return (Z_OK);
 }
 
+boolean_t
+zonecfg_ifname_exists(sa_family_t af, char *ifname)
+{
+	struct lifreq lifr;
+	int so;
+	int save_errno;
+
+	(void) memset(&lifr, 0, sizeof (lifr));
+	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
+	lifr.lifr_addr.ss_family = af;
+	if ((so = socket(af, SOCK_DGRAM, 0)) < 0) {
+		/* Odd - can't tell if the ifname exists */
+		return (B_FALSE);
+	}
+	if (ioctl(so, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
+		save_errno = errno;
+		(void) close(so);
+		errno = save_errno;
+		return (B_FALSE);
+	}
+	(void) close(so);
+	return (B_TRUE);
+}
+
 int
 zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
 {
diff --git a/usr/src/lib/libzonecfg/common/mapfile-vers b/usr/src/lib/libzonecfg/common/mapfile-vers
index e2bb782..384641b 100644
--- a/usr/src/lib/libzonecfg/common/mapfile-vers
+++ b/usr/src/lib/libzonecfg/common/mapfile-vers
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -106,6 +106,7 @@
 	zonecfg_getfsent;
 	zonecfg_get_handle;
 	zonecfg_getipdent;
+	zonecfg_get_iptype;
 	zonecfg_get_limitpriv;
 	zonecfg_getmcapent;
 	zonecfg_get_name;
@@ -125,6 +126,7 @@
 	zonecfg_get_uuid;
 	zonecfg_get_xml_handle;
 	zonecfg_get_zonepath;
+	zonecfg_ifname_exists;
 	zonecfg_in_alt_root;
 	zonecfg_init_handle;
 	zonecfg_is_rctl;
@@ -172,6 +174,7 @@
 	zonecfg_setdsent;
 	zonecfg_setfsent;
 	zonecfg_setipdent;
+	zonecfg_set_iptype;
 	zonecfg_set_limitpriv;
 	zonecfg_set_name;
 	zonecfg_setnwifent;
diff --git a/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1 b/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1
index c51e89a..5de8176 100644
--- a/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1
+++ b/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1
@@ -20,7 +20,7 @@
 
  CDDL HEADER END
 
- Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  Use is subject to license terms.
 
  ident	"%Z%%M%	%I%	%E% SMI"
@@ -44,7 +44,7 @@
 
 <!ELEMENT network	EMPTY>
 
-<!ATTLIST network	address		CDATA #REQUIRED
+<!ATTLIST network	address		CDATA ""
 			physical	CDATA #REQUIRED>
 
 <!ELEMENT device	EMPTY>
@@ -136,6 +136,7 @@
 <!ATTLIST zone		name		CDATA #REQUIRED
 			zonepath	CDATA #REQUIRED
 			autoboot	(true | false) #REQUIRED
+			ip-type		CDATA ""
 			pool		CDATA ""
 			limitpriv	CDATA ""
 			bootargs	CDATA ""
diff --git a/usr/src/pkgdefs/SUNWcnetr/pkginfo.tmpl b/usr/src/pkgdefs/SUNWcnetr/pkginfo.tmpl
index 5a9803a..ddf799c 100644
--- a/usr/src/pkgdefs/SUNWcnetr/pkginfo.tmpl
+++ b/usr/src/pkgdefs/SUNWcnetr/pkginfo.tmpl
@@ -48,7 +48,7 @@
 BASEDIR=/
 SUNW_PKGVERS="1.0"
 SUNW_PKG_ALLZONES="true"
-SUNW_PKG_HOLLOW="true"
+SUNW_PKG_HOLLOW="false"
 SUNW_PKG_THISZONE="false"
 #VSTOCK="<reserved by Release Engineering for package part #>"
 #ISTATES="<developer defined>"
diff --git a/usr/src/pkgdefs/SUNWhea/prototype_com b/usr/src/pkgdefs/SUNWhea/prototype_com
index fc2a8c7..3a53f96 100644
--- a/usr/src/pkgdefs/SUNWhea/prototype_com
+++ b/usr/src/pkgdefs/SUNWhea/prototype_com
@@ -141,10 +141,13 @@
 f none usr/include/inet/ip_multi.h 644 root bin
 f none usr/include/inet/ip_netinfo.h 644 root bin
 f none usr/include/inet/ip_rts.h 644 root bin
+f none usr/include/inet/ip_stack.h 644 root bin
 f none usr/include/inet/ip6.h 644 root bin
 f none usr/include/inet/ip6_asp.h 644 root bin
 f none usr/include/inet/ipclassifier.h 644 root bin
 f none usr/include/inet/ipp_common.h 644 root bin
+d none usr/include/inet/kssl 755 root bin
+f none usr/include/inet/kssl/ksslapi.h 644 root bin
 f none usr/include/inet/led.h 644 root bin
 f none usr/include/inet/mi.h 644 root bin
 f none usr/include/inet/mib2.h 644 root bin
@@ -154,9 +157,8 @@
 f none usr/include/inet/snmpcom.h 644 root bin
 f none usr/include/inet/tcp.h 644 root bin
 f none usr/include/inet/tcp_sack.h 644 root bin
+f none usr/include/inet/tcp_stack.h 644 root bin
 f none usr/include/inet/wifi_ioctl.h 644 root bin
-d none usr/include/inet/kssl 755 root bin
-f none usr/include/inet/kssl/ksslapi.h 644 root bin
 f none usr/include/inttypes.h 644 root bin
 f none usr/include/ipmp.h 644 root bin
 f none usr/include/ipmp_mpathd.h 644 root bin
@@ -904,6 +906,7 @@
 f none usr/include/sys/ndifm.h 644 root bin
 f none usr/include/sys/ndi_impldefs.h 644 root bin
 f none usr/include/sys/neti.h 644 root bin
+f none usr/include/sys/netstack.h 644 root bin
 f none usr/include/sys/note.h 644 root bin
 f none usr/include/sys/nvpair.h 644 root bin
 f none usr/include/sys/nvpair_impl.h 644 root bin
diff --git a/usr/src/pkgdefs/SUNWipfh/prototype_com b/usr/src/pkgdefs/SUNWipfh/prototype_com
index 4e9f9ce..466c971 100644
--- a/usr/src/pkgdefs/SUNWipfh/prototype_com
+++ b/usr/src/pkgdefs/SUNWipfh/prototype_com
@@ -1,5 +1,5 @@
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -26,9 +26,15 @@
 d none usr 755 root sys
 d none usr/include 755 root bin
 d none usr/include/netinet 755 root bin
+f none usr/include/netinet/ipf_stack.h 644 root bin
 f none usr/include/netinet/ip_compat.h 644 root bin
 f none usr/include/netinet/ip_fil.h 644 root bin
 f none usr/include/netinet/ip_nat.h 644 root bin
 f none usr/include/netinet/ip_state.h 644 root bin
 f none usr/include/netinet/ip_proxy.h 644 root bin
 f none usr/include/netinet/ipl.h 644 root bin
+f none usr/include/netinet/ip_frag.h 644 root bin
+f none usr/include/netinet/ip_auth.h 644 root bin
+f none usr/include/netinet/ip_pool.h 644 root bin
+f none usr/include/netinet/ip_htable.h 644 root bin
+f none usr/include/netinet/ip_lookup.h 644 root bin
diff --git a/usr/src/pkgdefs/SUNWipfr/pkginfo.tmpl b/usr/src/pkgdefs/SUNWipfr/pkginfo.tmpl
index ce2abc2..8133ef2 100644
--- a/usr/src/pkgdefs/SUNWipfr/pkginfo.tmpl
+++ b/usr/src/pkgdefs/SUNWipfr/pkginfo.tmpl
@@ -1,5 +1,5 @@
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -27,7 +27,7 @@
 BASEDIR=/
 SUNW_PKGVERS="1.0"
 SUNW_PKG_ALLZONES="true"
-SUNW_PKG_HOLLOW="true"
+SUNW_PKG_HOLLOW="false"
 SUNW_PKG_THISZONE="false"
 #VSTOCK="<reserved by Release Engineering for package part #>"
 #ISTATES="<developer defined>"
diff --git a/usr/src/pkgdefs/SUNWipfr/prototype_com b/usr/src/pkgdefs/SUNWipfr/prototype_com
index 39bf9a0..261071a 100644
--- a/usr/src/pkgdefs/SUNWipfr/prototype_com
+++ b/usr/src/pkgdefs/SUNWipfr/prototype_com
@@ -54,9 +54,6 @@
 d none lib/svc 0755 root bin
 d none lib/svc/method 0755 root bin
 f none lib/svc/method/ipfilter 0555 root bin
-d none kernel 755 root sys
-d none kernel/drv 755 root sys
-d none kernel/strmod 755 root sys
 d none var 755 root sys
 d none var/db 755 root sys
 d none var/db/ipf 755 root sys
diff --git a/usr/src/pkgdefs/common_files/i.devpolicy b/usr/src/pkgdefs/common_files/i.devpolicy
index 811a2db..16df7b2 100644
--- a/usr/src/pkgdefs/common_files/i.devpolicy
+++ b/usr/src/pkgdefs/common_files/i.devpolicy
@@ -22,7 +22,7 @@
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #  NOTE:  When a change is made to the source file for
@@ -41,12 +41,17 @@
 	sed < $dest.$$ > $dest \
 	    -e '/md:admin/s/read_priv_set=sys_config/			/' \
 	    -e '/^icmp[ 	]*read_priv_set=net_rawaccess[ 	]*write_priv_set=net_rawaccess$/d' \
-	    -e '/^icmp6[ 	]*read_priv_set=net_rawaccess[ 	]*write_priv_set=net_rawaccess$/d'
+	    -e '/^icmp6[ 	]*read_priv_set=net_rawaccess[ 	]*write_priv_set=net_rawaccess$/d' \
+	    -e '/^keysock[ 	]*read_priv_set=sys_net_config[ 	]*write_priv_set=sys_net_config$/d' \
+	    -e '/^ipsecah[ 	]*read_priv_set=sys_net_config[ 	]*write_priv_set=sys_net_config$/d' \
+	    -e '/^ipsecesp[ 	]*read_priv_set=sys_net_config[ 	]*write_priv_set=sys_net_config$/d' \
+	    -e '/^spdsock[ 	]*read_priv_set=sys_net_config[ 	]*write_priv_set=sys_net_config$/d' \
+	    -e '/^ipf[ 	]*read_priv_set=sys_net_config[ 	]*write_priv_set=sys_net_config$/d'
 
 	rm -f $dest.$$
 
 	# potential additions
-	additions="aggr aggr:ctl bge dld:ctl dnet ibd icmp icmp6 openeepr random vni ipf pfil scsi_vhci"
+	additions="aggr aggr:ctl bge dld:ctl dnet keysock ibd icmp icmp6 ipsecah ipsecesp openeepr random spdsock vni ipf pfil scsi_vhci"
 
 	for dev in $additions
 	do
diff --git a/usr/src/tools/scripts/bfu.sh b/usr/src/tools/scripts/bfu.sh
index 08ba1a2..694bc9b 100644
--- a/usr/src/tools/scripts/bfu.sh
+++ b/usr/src/tools/scripts/bfu.sh
@@ -99,6 +99,8 @@
 	etc/inet/*
 	etc/init.d/*
 	etc/inittab
+	etc/ipf/ipf.conf
+	etc/iu.ap
 	etc/krb5/kadm5.acl
 	etc/krb5/kdc.conf
 	etc/krb5/kpropd.acl
@@ -185,9 +187,6 @@
 	etc/devlink.tab
 	etc/driver_aliases
 	etc/driver_classes
-	etc/ipf/ipf.conf
-	etc/ipf/pfil.ap
-	etc/iu.ap
 	etc/lvm/devpath
 	etc/lvm/lock
 	etc/lvm/md.cf
@@ -240,7 +239,6 @@
 	dev/pts
 	dev/rdsk
 	dev/rmt
-	dev/sad
 	dev/stderr
 	dev/stdin
 	dev/stdout
@@ -249,66 +247,45 @@
 	devices
 	etc/dacf.conf
 	etc/dat
-	etc/default/dhcpagent
-	etc/default/inetinit
-	etc/default/ipsec
 	etc/default/metassist.xml
-	etc/default/mpathd
 	etc/default/power
 	etc/flash/postdeployment/svm.cleanup
 	etc/flash/predeployment/svm.save
-	etc/inet/datemsk.ndpd
-	etc/inet/ike
 	etc/inet/ipqosconf.1.sample
 	etc/inet/ipqosconf.2.sample
 	etc/inet/ipqosconf.3.sample
-	etc/inet/ipsecalgs
-	etc/inet/ipsecinit.sample
-	etc/inet/mipagent.conf-sample
-	etc/inet/mipagent.conf.fa-sample
-	etc/inet/mipagent.conf.ha-sample
-	etc/inet/secret
 	etc/inet/sock2path
 	etc/init.d/devlinks
 	etc/init.d/dodatadm.udaplt
 	etc/init.d/drvconfig
 	etc/init.d/llc2
-	etc/init.d/mipagent
 	etc/init.d/ncakmod
 	etc/init.d/ncalogd
 	etc/init.d/pcmcia
 	etc/init.d/pppd
 	etc/init.d/wrsmcfg
-	etc/ipf
 	etc/llc2
 	etc/lvm
 	etc/nca
 	etc/openwin
 	etc/ppp
-	etc/rc0.d/K06mipagent
 	etc/rc0.d/K34ncalogd
 	etc/rc0.d/K50pppd
 	etc/rc0.d/K52llc2
-	etc/rc1.d/K06mipagent
 	etc/rc1.d/K34ncalogd
 	etc/rc1.d/K50pppd
 	etc/rc1.d/K52llc2
-	etc/rc2.d/K06mipagent
 	etc/rc2.d/S40llc2
 	etc/rc2.d/S42ncakmod
 	etc/rc2.d/S47pppd
 	etc/rc2.d/S81dodatadm.udaplt
 	etc/rc2.d/S94ncalogd
-	etc/rc3.d/S80mipagent
-	etc/rcS.d/K06mipagent
 	etc/rcS.d/K34ncalogd
 	etc/rcS.d/K44wrsmcfg
 	etc/rcS.d/K50pppd
 	etc/rcS.d/K52llc2
 	etc/rcS.d/S29wrsmcfg
 	etc/rcm
-	etc/snmp/conf/mipagent.acl
-	etc/snmp/conf/mipagent.reg
 	etc/sock2path
 	etc/usb
 	etc/wrsm
@@ -316,7 +293,6 @@
 	kernel
 	lib/libmeta.so
 	lib/libmeta.so.1
-	lib/svc/method/ipfilter
 	lib/svc/method/sf880dr
 	lib/svc/method/svc-cvcd
 	lib/svc/method/svc-dcs
@@ -354,18 +330,11 @@
 	platform/sun4u/wanboot
 	platform/sun4v/ufsboot
 	platform/sun4v/wanboot
-	sbin/dladm
 	sbin/metadb
 	sbin/metadevadm
 	sbin/metainit
 	sbin/metarecover
 	sbin/metastat
-	usr/include/netinet/ip_compat.h
-	usr/include/netinet/ip_fil.h
-	usr/include/netinet/ip_nat.h
-	usr/include/netinet/ip_proxy.h
-	usr/include/netinet/ip_state.h
-	usr/include/netinet/ipl.h
 	usr/include/sys/dcam
 	usr/lib/devfsadm/linkmod/SUNW_dcam1394_link.so
 	usr/lib/ldoms
@@ -375,9 +344,7 @@
 	usr/platform/SUNW,SPARC-Enterprise/lib/llib-ldscp.ln
 	usr/platform/SUNW,SPARC-Enterprise/sbin/prtdscp
 	var/adm/pool
-	var/db/ipf
 	var/log/pool
-	var/svc/manifest/network/ipfilter.xml
 	var/svc/manifest/network/rpc/mdcomm.xml
 	var/svc/manifest/network/rpc/meta.xml
 	var/svc/manifest/network/rpc/metamed.xml
diff --git a/usr/src/uts/Makefile b/usr/src/uts/Makefile
index a3a6e1a..7ed3239 100644
--- a/usr/src/uts/Makefile
+++ b/usr/src/uts/Makefile
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -48,6 +47,7 @@
 lint		:=	TARGET= lint
 clean.lint	:=	TARGET= clean.lint
 check		:=	TARGET= check
+sis_check	:=	TARGET= sis_check
 modlist		:=	TARGET= modlist
 modlist		:=	NO_STATE= -K $$MODSTATE$$$$
 
@@ -95,7 +95,19 @@
 COMMON_HDRDIRS= common/des common/fs common/gssapi common/inet common/net \
 	common/netinet common/nfs common/rpc common/sys common/vm \
 	common/c2 common/pcmcia/sys common/rpcsvc common/inet/kssl \
-	common/inet/nca common/ipp
+	common/inet/nca common/inet/ipf/netinet common/ipp
+
+#
+# Kernel modules which support the sis_check target for symbol checking
+#
+i386_SIS_MODULES= intel/arp intel/hook intel/icmp intel/ip intel/ipf \
+	intel/ipsecah intel/ipsecesp intel/keysock intel/neti \
+	intel/rts intel/spdsock intel/tun
+sparc_SIS_MODULES= sparc/arp sparc/hook sparc/icmp sparc/ip sparc/ipf \
+	sparc/ipsecah sparc/ipsecesp sparc/keysock sparc/neti \
+	sparc/rts sparc/spdsock sparc/tun
+
+SIS_MODULES=$($(MACH)_SIS_MODULES)
 
 # These aren't the only headers in closed.  But the other directories
 # are simple enough that they can be driven from the src tree.
@@ -119,6 +131,12 @@
 	@cd common/rpcsvc; pwd; $(MAKE) $@
 	@cd common/gssapi; pwd; $(MAKE) $@
 
+# run stack instances global symbol checking to make sure
+# you do intend to add a global variable
+sis_check:	$(SIS_MODULES)
+$(SIS_MODULES): FRC
+	cd $@; pwd; $(MAKE) $(TARGET)
+ 
 ONC_FILES=	common/io/timod.c \
 		common/os/sig.c \
 		common/os/flock.c \
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 927ded7..a78f4e9 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -198,6 +198,7 @@
 		nbmlock.o	\
 		ndifm.o		\
 		nice.o		\
+		netstack.o	\
 		ntptime.o	\
 		nvpair.o	\
 		nvpair_alloc_system.o	\
diff --git a/usr/src/uts/common/inet/Makefile b/usr/src/uts/common/inet/Makefile
index 8f6c111..4a2141e 100644
--- a/usr/src/uts/common/inet/Makefile
+++ b/usr/src/uts/common/inet/Makefile
@@ -21,7 +21,7 @@
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # uts/common/inet/Makefile
@@ -33,8 +33,8 @@
 	ipsecesp.h ipsec_info.h ip6_asp.h ip_if.h ip_ire.h ip_multi.h \
 	ip_netinfo.h ip_ndp.h ip_rts.h ipsec_impl.h keysock.h led.h mi.h \
 	mib2.h nd.h optcom.h sadb.h sctp_itf.h snmpcom.h tcp.h tcp_sack.h \
-	tun.h udp_impl.h rawip_impl.h ipp_common.h ip_ftable.h ip_impl.h \
-	tcp_impl.h wifi_ioctl.h
+	tcp_stack.h tun.h udp_impl.h rawip_impl.h ipp_common.h ip_ftable.h \
+	ip_impl.h tcp_impl.h wifi_ioctl.h ip_stack.h
 
 ROOTDIRS= $(ROOT)/usr/include/inet
 
diff --git a/usr/src/uts/common/inet/arp/arp.c b/usr/src/uts/common/inet/arp/arp.c
index 92f98a3..9677c55 100644
--- a/usr/src/uts/common/inet/arp/arp.c
+++ b/usr/src/uts/common/inet/arp/arp.c
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /* Copyright (c) 1990 Mentat Inc. */
@@ -45,6 +45,7 @@
 #include <sys/vtrace.h>
 #include <sys/strsun.h>
 #include <sys/policy.h>
+#include <sys/zone.h>
 #include <sys/ethernet.h>
 #include <sys/zone.h>
 #include <sys/random.h>
@@ -132,10 +133,6 @@
 	(mp->b_prev != AR_DRAINING && (arl->arl_queue != NULL ||	\
 	    arl->arl_dlpi_pending != DL_PRIM_INVAL))
 
-#define	ACE_EXTERNAL_FLAGS_MASK \
-	(ACE_F_PERMANENT | ACE_F_PUBLISH | ACE_F_MAPPING | ACE_F_MYADDR | \
-	ACE_F_AUTHORITY)
-
 #define	ARH_FIXED_LEN	8
 
 /*
@@ -149,21 +146,11 @@
 	uint32_t	ar_mac_hw_addr_length;
 } ar_m_t;
 
-/* Named Dispatch Parameter Management Structure */
-typedef struct arpparam_s {
-	uint32_t	arp_param_min;
-	uint32_t	arp_param_max;
-	uint32_t	arp_param_value;
-	char		*arp_param_name;
-} arpparam_t;
-
 typedef struct msg2_args {
 	mblk_t	*m2a_mpdata;
 	mblk_t	*m2a_mptail;
 } msg2_args_t;
 
-extern ire_stats_t ire_stats_v4;
-
 static mblk_t	*ar_alloc(uint32_t cmd, int);
 static int	ar_ce_create(arl_t *arl, uint32_t proto, uchar_t *hw_addr,
     uint32_t hw_addr_len, uchar_t *proto_addr,
@@ -172,23 +159,24 @@
     uint32_t flags);
 static void	ar_ce_delete(ace_t *ace);
 static void	ar_ce_delete_per_arl(ace_t *ace, void *arg);
-static ace_t	**ar_ce_hash(uint32_t proto, const uchar_t *proto_addr,
-    uint32_t proto_addr_length);
+static ace_t	**ar_ce_hash(arp_stack_t *as, uint32_t proto,
+    const uchar_t *proto_addr, uint32_t proto_addr_length);
 static ace_t	*ar_ce_lookup(arl_t *arl, uint32_t proto,
     const uchar_t *proto_addr, uint32_t proto_addr_length);
 static ace_t	*ar_ce_lookup_entry(arl_t *arl, uint32_t proto,
     const uchar_t *proto_addr, uint32_t proto_addr_length);
-static ace_t	*ar_ce_lookup_from_area(mblk_t *mp, ace_t *matchfn());
+static ace_t	*ar_ce_lookup_from_area(arp_stack_t *as, mblk_t *mp,
+    ace_t *matchfn());
 static ace_t	*ar_ce_lookup_mapping(arl_t *arl, uint32_t proto,
     const uchar_t *proto_addr, uint32_t proto_addr_length);
 static boolean_t ar_ce_resolve(ace_t *ace, const uchar_t *hw_addr,
     uint32_t hw_addr_length);
-static void	ar_ce_walk(void (*pfi)(ace_t *, void *), void *arg1);
+static void	ar_ce_walk(arp_stack_t *as, void (*pfi)(ace_t *, void *),
+    void *arg1);
 
-static void	ar_cleanup(void);
 static void	ar_client_notify(const arl_t *arl, mblk_t *mp, int code);
 static int	ar_close(queue_t *q);
-static int	ar_cmd_dispatch(queue_t *q, mblk_t *mp);
+static int	ar_cmd_dispatch(queue_t *q, mblk_t *mp, boolean_t from_wput);
 static void	ar_cmd_done(arl_t *arl);
 static mblk_t	*ar_dlpi_comm(t_uscalar_t prim, size_t size);
 static void	ar_dlpi_send(arl_t *, mblk_t *);
@@ -203,9 +191,9 @@
 static int	ar_interface_off(queue_t *q, mblk_t *mp);
 static void	ar_ll_cleanup_arl_queue(queue_t *q);
 static void	ar_ll_down(arl_t *arl);
-static arl_t	*ar_ll_lookup_by_name(const char *name);
-static arl_t	*ar_ll_lookup_from_mp(mblk_t *mp);
-static void	ar_ll_init(ar_t *, mblk_t *mp);
+static arl_t	*ar_ll_lookup_by_name(arp_stack_t *as, const char *name);
+static arl_t	*ar_ll_lookup_from_mp(arp_stack_t *as, mblk_t *mp);
+static void	ar_ll_init(arp_stack_t *, ar_t *, mblk_t *mp);
 static void	ar_ll_set_defaults(arl_t *, mblk_t *mp);
 static void	ar_ll_clear_defaults(arl_t *);
 static int	ar_ll_up(arl_t *arl);
@@ -216,13 +204,13 @@
 static int	ar_open(queue_t *q, dev_t *devp, int flag, int sflag,
     cred_t *credp);
 static int	ar_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr);
-static boolean_t	ar_param_register(arpparam_t *arppa, int cnt);
+static boolean_t ar_param_register(IDP *ndp, arpparam_t *arppa, int cnt);
 static int	ar_param_set(queue_t *q, mblk_t *mp, char *value,
     caddr_t cp, cred_t *cr);
 static void	ar_query_delete(ace_t *ace, void *ar);
 static void	ar_query_reply(ace_t *ace, int ret_val,
     uchar_t *proto_addr, uint32_t proto_addr_len);
-static clock_t	ar_query_xmit(ace_t *ace, ace_t *src_ace);
+static clock_t	ar_query_xmit(arp_stack_t *as, ace_t *ace, ace_t *src_ace);
 static void	ar_rput(queue_t *q, mblk_t *mp_orig);
 static void	ar_rput_dlpi(queue_t *q, mblk_t *mp);
 static void	ar_set_address(ace_t *ace, uchar_t *addrpos,
@@ -235,11 +223,14 @@
 static void	ar_wsrv(queue_t *q);
 static void	ar_xmit(arl_t *arl, uint32_t operation, uint32_t proto,
     uint32_t plen, const uchar_t *haddr1, const uchar_t *paddr1,
-    const uchar_t *haddr2, const uchar_t *paddr2, const uchar_t *dstaddr);
+    const uchar_t *haddr2, const uchar_t *paddr2, const uchar_t *dstaddr,
+    arp_stack_t *as);
 static void	ar_cmd_enqueue(arl_t *arl, mblk_t *mp, queue_t *q,
     ushort_t cmd, boolean_t);
 static mblk_t	*ar_cmd_dequeue(arl_t *arl);
 
+static void	*arp_stack_init(netstackid_t stackid, netstack_t *ns);
+static void	arp_stack_fini(netstackid_t stackid, void *arg);
 /*
  * All of these are alterable, within the min/max values given,
  * at run time. arp_publish_interval and arp_publish_count are
@@ -264,20 +255,19 @@
 	{ 0,		3600000,	15000,	"arp_broadcast_interval"},
 	{ 5,		86400,		3600,	"arp_defend_period"}
 };
-
-#define	arp_cleanup_interval	arp_param_arr[0].arp_param_value
-#define	arp_publish_interval	arp_param_arr[1].arp_param_value
-#define	arp_publish_count	arp_param_arr[2].arp_param_value
-#define	arp_probe_delay		arp_param_arr[3].arp_param_value
-#define	arp_probe_interval	arp_param_arr[4].arp_param_value
-#define	arp_probe_count		arp_param_arr[5].arp_param_value
-#define	arp_fastprobe_delay	arp_param_arr[6].arp_param_value
-#define	arp_fastprobe_interval	arp_param_arr[7].arp_param_value
-#define	arp_fastprobe_count	arp_param_arr[8].arp_param_value
-#define	arp_defend_interval	arp_param_arr[9].arp_param_value
-#define	arp_defend_rate		arp_param_arr[10].arp_param_value
-#define	arp_broadcast_interval	arp_param_arr[11].arp_param_value
-#define	arp_defend_period	arp_param_arr[12].arp_param_value
+#define	as_cleanup_interval	as_param_arr[0].arp_param_value
+#define	as_publish_interval	as_param_arr[1].arp_param_value
+#define	as_publish_count	as_param_arr[2].arp_param_value
+#define	as_probe_delay		as_param_arr[3].arp_param_value
+#define	as_probe_interval	as_param_arr[4].arp_param_value
+#define	as_probe_count		as_param_arr[5].arp_param_value
+#define	as_fastprobe_delay	as_param_arr[6].arp_param_value
+#define	as_fastprobe_interval	as_param_arr[7].arp_param_value
+#define	as_fastprobe_count	as_param_arr[8].arp_param_value
+#define	as_defend_interval	as_param_arr[9].arp_param_value
+#define	as_defend_rate		as_param_arr[10].arp_param_value
+#define	as_broadcast_interval	as_param_arr[11].arp_param_value
+#define	as_defend_period	as_param_arr[12].arp_param_value
 
 static struct module_info info = {
 	0, "arp", 0, INFPSZ, 512, 128
@@ -295,18 +285,6 @@
 	&rinit, &winit
 };
 
-static void	*ar_g_head;	/* AR Instance Data List Head */
-static caddr_t	ar_g_nd;	/* AR Named Dispatch Head */
-
-/*
- * With the introduction of netinfo (neti kernel module), it is now possible
- * to access data structures in the ARP module without the code being
- * executed in the context of the IP module, thus there is no locking being
- * enforced through the use of STREAMS.
- */
-krwlock_t	arl_g_lock;
-arl_t		*arl_g_head;	/* ARL List Head */
-
 /*
  * TODO: we need a better mechanism to set the ARP hardware type since
  * the DLPI mac type does not include enough predefined values.
@@ -322,14 +300,6 @@
 	{ DL_OTHER,	ARPHRD_ETHER,	-2,	6},	/* unknown */
 };
 
-/* ARP Cache Entry Hash Table */
-static ace_t	*ar_ce_hash_tbl[ARP_HASH_SIZE];
-
-static ace_t	*ar_ce_mask_entries;	/* proto_mask not all ones */
-
-static uint32_t	arp_index_counter = 1;
-static uint32_t	arp_counter_wrapped = 0;
-
 /*
  * Note that all routines which need to queue the message for later
  * processing have to be ioctl_aware to be able to queue the complete message.
@@ -337,6 +307,7 @@
  */
 #define	ARF_IOCTL_AWARE	0x1	/* Arp command can come down as M_IOCTL */
 #define	ARF_ONLY_CMD	0x2	/* Command is exclusive to ARP */
+#define	ARF_WPUT_OK	0x4	/* Command is allowed from ar_wput */
 
 /* ARP Cmd Table entry */
 typedef struct arct_s {
@@ -348,15 +319,22 @@
 	const char	*arct_txt;
 } arct_t;
 
+/*
+ * AR_ENTRY_ADD, QUERY and SQUERY are used by sdp, hence they need to
+ * have ARF_WPUT_OK set.
+ */
 static arct_t	ar_cmd_tbl[] = {
 	{ ar_entry_add,		AR_ENTRY_ADD,		sizeof (area_t),
-	    ARF_IOCTL_AWARE | ARF_ONLY_CMD, OP_CONFIG, "AR_ENTRY_ADD" },
+	    ARF_IOCTL_AWARE | ARF_ONLY_CMD | ARF_WPUT_OK, OP_CONFIG,
+	    "AR_ENTRY_ADD" },
 	{ ar_entry_delete,	AR_ENTRY_DELETE,	sizeof (ared_t),
 	    ARF_IOCTL_AWARE | ARF_ONLY_CMD, OP_CONFIG, "AR_ENTRY_DELETE" },
 	{ ar_entry_query,	AR_ENTRY_QUERY,		sizeof (areq_t),
-	    ARF_IOCTL_AWARE | ARF_ONLY_CMD, OP_NP, "AR_ENTRY_QUERY" },
+	    ARF_IOCTL_AWARE | ARF_ONLY_CMD | ARF_WPUT_OK, OP_NP,
+	    "AR_ENTRY_QUERY" },
 	{ ar_entry_squery,	AR_ENTRY_SQUERY,	sizeof (area_t),
-	    ARF_IOCTL_AWARE | ARF_ONLY_CMD, OP_NP, "AR_ENTRY_SQUERY" },
+	    ARF_IOCTL_AWARE | ARF_ONLY_CMD | ARF_WPUT_OK, OP_NP,
+	    "AR_ENTRY_SQUERY" },
 	{ ar_mapping_add,	AR_MAPPING_ADD,		sizeof (arma_t),
 	    ARF_IOCTL_AWARE | ARF_ONLY_CMD, OP_CONFIG, "AR_MAPPING_ADD" },
 	{ ar_interface_up,	AR_INTERFACE_UP,	sizeof (arc_t),
@@ -368,15 +346,16 @@
 	{ ar_interface_off,	AR_INTERFACE_OFF,	sizeof (arc_t),
 	    ARF_ONLY_CMD, OP_CONFIG, "AR_INTERFACE_OFF" },
 	{ ar_set_ppa,		(uint32_t)IF_UNITSEL,	sizeof (int),
-	    ARF_IOCTL_AWARE, OP_CONFIG, "IF_UNITSEL" },
+	    ARF_IOCTL_AWARE | ARF_WPUT_OK, OP_CONFIG, "IF_UNITSEL" },
 	{ ar_nd_ioctl,		ND_GET,			1,
-	    ARF_IOCTL_AWARE, OP_NP, "ND_GET" },
+	    ARF_IOCTL_AWARE | ARF_WPUT_OK, OP_NP, "ND_GET" },
 	{ ar_nd_ioctl,		ND_SET,			1,
-	    ARF_IOCTL_AWARE, OP_CONFIG, "ND_SET" },
+	    ARF_IOCTL_AWARE | ARF_WPUT_OK, OP_CONFIG, "ND_SET" },
 	{ ar_snmp_msg,		AR_SNMP_MSG,	sizeof (struct T_optmgmt_ack),
-	    ARF_IOCTL_AWARE | ARF_ONLY_CMD, OP_NP, "AR_SNMP_MSG" },
+	    ARF_IOCTL_AWARE | ARF_WPUT_OK | ARF_ONLY_CMD, OP_NP,
+	    "AR_SNMP_MSG" },
 	{ ar_slifname,		(uint32_t)SIOCSLIFNAME,	sizeof (struct lifreq),
-	    ARF_IOCTL_AWARE, OP_CONFIG, "SIOCSLIFNAME" }
+	    ARF_IOCTL_AWARE | ARF_WPUT_OK, OP_CONFIG, "SIOCSLIFNAME" }
 };
 
 /*
@@ -394,6 +373,7 @@
 	ace_t	**acep;
 	uchar_t	*dst;
 	mblk_t	*mp;
+	arp_stack_t *as = ARL_TO_ARPSTACK(arl);
 	arlphy_t *ap;
 
 	if ((flags & ~ACE_EXTERNAL_FLAGS_MASK) || arl == NULL)
@@ -491,13 +471,12 @@
 	}
 
 	ace->ace_flags = flags;
-
 	if (ar_mask_all_ones(ace->ace_proto_mask,
 	    ace->ace_proto_addr_length)) {
-		acep = ar_ce_hash(ace->ace_proto, ace->ace_proto_addr,
+		acep = ar_ce_hash(as, ace->ace_proto, ace->ace_proto_addr,
 		    ace->ace_proto_addr_length);
 	} else {
-		acep = &ar_ce_mask_entries;
+		acep = &as->as_ce_mask_entries;
 	}
 	if ((ace->ace_next = *acep) != NULL)
 		ace->ace_next->ace_ptpn = &ace->ace_next;
@@ -540,7 +519,7 @@
 
 /* Cache entry hash routine, based on protocol and protocol address. */
 static ace_t **
-ar_ce_hash(uint32_t proto, const uchar_t *proto_addr,
+ar_ce_hash(arp_stack_t *as, uint32_t proto, const uchar_t *proto_addr,
     uint32_t proto_addr_length)
 {
 	const uchar_t *up = proto_addr;
@@ -549,7 +528,7 @@
 
 	while (--len >= 0)
 		hval ^= *up++;
-	return (&ar_ce_hash_tbl[hval % A_CNT(ar_ce_hash_tbl)]);
+	return (&as->as_ce_hash_tbl[hval % ARP_HASH_SIZE]);
 }
 
 /* Cache entry lookup.	Try to find an ace matching the parameters passed. */
@@ -575,10 +554,11 @@
     uint32_t proto_addr_length)
 {
 	ace_t	*ace;
+	arp_stack_t *as = ARL_TO_ARPSTACK(arl);
 
 	if (!proto_addr)
 		return (NULL);
-	ace = *ar_ce_hash(proto, proto_addr, proto_addr_length);
+	ace = *ar_ce_hash(as, proto, proto_addr, proto_addr_length);
 	for (; ace; ace = ace->ace_next) {
 		if (ace->ace_arl == arl &&
 		    ace->ace_proto_addr_length == proto_addr_length &&
@@ -604,7 +584,7 @@
  * call the supplied match function.
  */
 static ace_t *
-ar_ce_lookup_from_area(mblk_t *mp, ace_t *matchfn())
+ar_ce_lookup_from_area(arp_stack_t *as, mblk_t *mp, ace_t *matchfn())
 {
 	uchar_t	*proto_addr;
 	area_t	*area = (area_t *)mp->b_rptr;
@@ -613,7 +593,7 @@
 	    area->area_proto_addr_length);
 	if (!proto_addr)
 		return (NULL);
-	return ((*matchfn)(ar_ll_lookup_from_mp(mp), area->area_proto,
+	return ((*matchfn)(ar_ll_lookup_from_mp(as, mp), area->area_proto,
 	    proto_addr, area->area_proto_addr_length));
 }
 
@@ -626,10 +606,11 @@
     uint32_t proto_addr_length)
 {
 	ace_t	*ace;
+	arp_stack_t *as = ARL_TO_ARPSTACK(arl);
 
 	if (!proto_addr)
 		return (NULL);
-	ace = ar_ce_mask_entries;
+	ace = as->as_ce_mask_entries;
 	for (; ace; ace = ace->ace_next) {
 		if (ace->ace_arl == arl &&
 		    ace->ace_proto_addr_length == proto_addr_length &&
@@ -661,12 +642,12 @@
  * mapping to avoid arp interpreting it as a duplicate.
  */
 static ace_t *
-ar_ce_lookup_permanent(uint32_t proto, uchar_t *proto_addr,
+ar_ce_lookup_permanent(arp_stack_t *as, uint32_t proto, uchar_t *proto_addr,
     uint32_t proto_addr_length)
 {
 	ace_t	*ace;
 
-	ace = *ar_ce_hash(proto, proto_addr, proto_addr_length);
+	ace = *ar_ce_hash(as, proto, proto_addr, proto_addr_length);
 	for (; ace != NULL; ace = ace->ace_next) {
 		if (!(ace->ace_flags & ACE_F_PERMANENT))
 			continue;
@@ -771,8 +752,9 @@
 	uchar_t *ace_addr;
 	uchar_t *mask;
 	int retv = AR_NOTFOUND;
+	arp_stack_t *as = ARL_TO_ARPSTACK(arl);
 
-	ace = *ar_ce_hash(proto, src_paddr, plen);
+	ace = *ar_ce_hash(as, proto, src_paddr, plen);
 	for (; ace != NULL; ace = ace_next) {
 
 		/* ar_ce_resolve may delete the ace; fetch next pointer now */
@@ -853,36 +835,28 @@
 
 /* Pass arg1 to the pfi supplied, along with each ace in existence. */
 static void
-ar_ce_walk(void (*pfi)(ace_t *, void *), void *arg1)
+ar_ce_walk(arp_stack_t *as, void (*pfi)(ace_t *, void *), void *arg1)
 {
 	ace_t	*ace;
 	ace_t	*ace1;
-	ace_t	**acep;
+	int i;
 
-	for (acep = ar_ce_hash_tbl; acep < A_END(ar_ce_hash_tbl); acep++) {
+	for (i = 0; i < ARP_HASH_SIZE; i++) {
 		/*
 		 * We walk the hash chain in a way that allows the current
 		 * ace to get blown off by the called routine.
 		 */
-		for (ace = *acep; ace; ace = ace1) {
+		for (ace = as->as_ce_hash_tbl[i]; ace; ace = ace1) {
 			ace1 = ace->ace_next;
 			(*pfi)(ace, arg1);
 		}
 	}
-	for (ace = ar_ce_mask_entries; ace; ace = ace1) {
+	for (ace = as->as_ce_mask_entries; ace; ace = ace1) {
 		ace1 = ace->ace_next;
 		(*pfi)(ace, arg1);
 	}
 }
 
-/* Free the ND tables if the last ar has gone away. */
-static void
-ar_cleanup(void)
-{
-	if (!ar_g_head)
-		nd_free(&ar_g_nd);
-}
-
 /*
  * Send a copy of interesting packets to the corresponding IP instance.
  * The corresponding IP instance is the ARP-IP-DEV instance for this
@@ -969,6 +943,7 @@
 	arc_t	*arc;
 	mblk_t	*mp1;
 	int	index;
+	arp_stack_t *as = ar->ar_as;
 
 	TRACE_1(TR_FAC_ARP, TR_ARP_CLOSE,
 	    "arp_close: q %p", q);
@@ -997,7 +972,7 @@
 			}
 		}
 		/* Delete all our pending queries, 'arl' is not dereferenced */
-		ar_ce_walk(ar_query_delete, ar);
+		ar_ce_walk(as, ar_query_delete, ar);
 		/*
 		 * The request could be pending on some arl_queue also. This
 		 * happens if the arl is not yet bound, and bind is pending.
@@ -1021,11 +996,12 @@
 		 * If this is the control stream for an arl, delete anything
 		 * hanging off our arl.
 		 */
-		ar_ce_walk(ar_ce_delete_per_arl, arl);
+		ar_ce_walk(as, ar_ce_delete_per_arl, arl);
 		/* Free any messages waiting for a bind_ack */
 		/* Get the arl out of the chain. */
-		rw_enter(&arl_g_lock, RW_WRITER);
-		for (arlp = &arl_g_head; *arlp; arlp = &(*arlp)->arl_next) {
+		rw_enter(&as->as_arl_g_lock, RW_WRITER);
+		for (arlp = &as->as_arl_head; *arlp;
+		    arlp = &(*arlp)->arl_next) {
 			if (*arlp == arl) {
 				*arlp = arl->arl_next;
 				break;
@@ -1034,7 +1010,7 @@
 
 		ASSERT(arl->arl_dlpi_deferred == NULL);
 		ar->ar_arl = NULL;
-		rw_exit(&arl_g_lock);
+		rw_exit(&as->as_arl_g_lock);
 
 		mi_free((char *)arl);
 	}
@@ -1047,8 +1023,7 @@
 	}
 	cr = ar->ar_credp;
 	/* mi_close_comm frees the instance data. */
-	(void) mi_close_comm(&ar_g_head, q);
-	ar_cleanup();
+	(void) mi_close_comm(&as->as_head, q);
 	qprocsoff(q);
 	crfree(cr);
 
@@ -1060,8 +1035,10 @@
 		info.hne_event = NE_UNPLUMB;
 		info.hne_data = name;
 		info.hne_datalen = strlen(name);
-		(void) hook_run(arpnicevents, (hook_data_t)&info);
+		(void) hook_run(as->as_arpnicevents, (hook_data_t)&info,
+		    as->as_netstack);
 	}
+	netstack_rele(as->as_netstack);
 	return (0);
 }
 
@@ -1071,7 +1048,7 @@
  */
 /* TODO: error reporting for M_PROTO case */
 static int
-ar_cmd_dispatch(queue_t *q, mblk_t *mp_orig)
+ar_cmd_dispatch(queue_t *q, mblk_t *mp_orig, boolean_t from_wput)
 {
 	arct_t	*arct;
 	uint32_t	cmd;
@@ -1117,10 +1094,15 @@
 		if (cr == NULL)
 			cr = DB_CREDDEF(mp_orig, ((ar_t *)q->q_ptr)->ar_credp);
 
-		if ((error = secpolicy_net(cr, arct->arct_priv_req,
+		if ((error = secpolicy_ip(cr, arct->arct_priv_req,
 		    B_FALSE)) != 0)
 			return (error);
 	}
+	/* Disallow many commands except if from rput i.e. from IP */
+	if (from_wput && !(arct->arct_flags & ARF_WPUT_OK)) {
+		return (EINVAL);
+	}
+
 	if (arct->arct_flags & ARF_IOCTL_AWARE)
 		mp = mp_orig;
 
@@ -1436,11 +1418,12 @@
 	int	err;
 	uint_t	aflags;
 	boolean_t unverified;
+	arp_stack_t *as = ((ar_t *)q->q_ptr)->ar_as;
 
 	/* We handle both M_IOCTL and M_PROTO messages. */
 	if (DB_TYPE(mp) == M_IOCTL)
 		mp = mp->b_cont;
-	arl = ar_ll_lookup_from_mp(mp);
+	arl = ar_ll_lookup_from_mp(as, mp);
 	if (arl == NULL)
 		return (EINVAL);
 	/*
@@ -1462,7 +1445,8 @@
 	 * duplicate address detection state.  If it's a new entry, then we're
 	 * obligated to do duplicate address detection now.
 	 */
-	if ((ace = ar_ce_lookup_from_area(mp, ar_ce_lookup_entry)) != NULL) {
+	ace = ar_ce_lookup_from_area(as, mp, ar_ce_lookup_entry);
+	if (ace != NULL) {
 		unverified = (ace->ace_flags & ACE_F_UNVERIFIED) != 0;
 		ar_ce_delete(ace);
 	} else {
@@ -1525,11 +1509,11 @@
 		ASSERT(ace != NULL);
 
 		if (ace->ace_flags & ACE_F_FAST) {
-			ace->ace_xmit_count = arp_fastprobe_count;
-			ace->ace_xmit_interval = arp_fastprobe_delay;
+			ace->ace_xmit_count = as->as_fastprobe_count;
+			ace->ace_xmit_interval = as->as_fastprobe_delay;
 		} else {
-			ace->ace_xmit_count = arp_probe_count;
-			ace->ace_xmit_interval = arp_probe_delay;
+			ace->ace_xmit_count = as->as_probe_count;
+			ace->ace_xmit_interval = as->as_probe_delay;
 		}
 
 		/*
@@ -1558,12 +1542,12 @@
 				    area_t *, area);
 				ar_xmit(arl, ARP_REQUEST, area->area_proto,
 				    proto_addr_len, hw_addr, NULL, NULL,
-				    proto_addr, NULL);
+				    proto_addr, NULL, as);
 				ace->ace_xmit_count--;
 				ace->ace_xmit_interval =
 				    (ace->ace_flags & ACE_F_FAST) ?
-				    arp_fastprobe_interval :
-				    arp_probe_interval;
+				    as->as_fastprobe_interval :
+				    as->as_probe_interval;
 				ace_set_timer(ace, B_FALSE);
 			} else {
 				DTRACE_PROBE2(eadd_delay, ace_t *, ace,
@@ -1576,7 +1560,7 @@
 			    area_t *, area);
 			ar_xmit(arl, ARP_REQUEST, area->area_proto,
 			    proto_addr_len, hw_addr, proto_addr,
-			    ap->ap_arp_addr, proto_addr, NULL);
+			    ap->ap_arp_addr, proto_addr, NULL, as);
 			ace->ace_last_bcast = ddi_get_lbolt();
 
 			/*
@@ -1590,10 +1574,11 @@
 			 */
 			if ((aflags & ACE_F_AUTHORITY) &&
 			    !(aflags & ACE_F_DEFEND) &&
-			    arp_publish_count > 0) {
+			    as->as_publish_count > 0) {
 				/* Account for the xmit we just did */
-				ace->ace_xmit_count = arp_publish_count - 1;
-				ace->ace_xmit_interval = arp_publish_interval;
+				ace->ace_xmit_count = as->as_publish_count - 1;
+				ace->ace_xmit_interval =
+				    as->as_publish_interval;
 				if (ace->ace_xmit_count > 0)
 					ace_set_timer(ace, B_FALSE);
 			}
@@ -1609,11 +1594,12 @@
 	ace_t	*ace;
 	arl_t	*arl;
 	mblk_t	*mp = mp_orig;
+	arp_stack_t *as = ((ar_t *)q->q_ptr)->ar_as;
 
 	/* We handle both M_IOCTL and M_PROTO messages. */
 	if (DB_TYPE(mp) == M_IOCTL)
 		mp = mp->b_cont;
-	arl = ar_ll_lookup_from_mp(mp);
+	arl = ar_ll_lookup_from_mp(as, mp);
 	if (arl == NULL)
 		return (EINVAL);
 	/*
@@ -1631,7 +1617,7 @@
 	 * Need to know if it is a mapping or an exact match.  Check exact
 	 * match first.
 	 */
-	ace = ar_ce_lookup_from_area(mp, ar_ce_lookup);
+	ace = ar_ce_lookup_from_area(as, mp, ar_ce_lookup);
 	if (ace != NULL) {
 		/*
 		 * If it's a permanent entry, then the client is the one who
@@ -1667,13 +1653,14 @@
 	uint32_t proto_addr_len;
 	clock_t	ms;
 	boolean_t is_mproto = B_TRUE;
+	arp_stack_t *as = ((ar_t *)q->q_ptr)->ar_as;
 
 	/* We handle both M_IOCTL and M_PROTO messages. */
 	if (DB_TYPE(mp) == M_IOCTL) {
 		is_mproto = B_FALSE;
 		mp = mp->b_cont;
 	}
-	arl = ar_ll_lookup_from_mp(mp);
+	arl = ar_ll_lookup_from_mp(as, mp);
 	if (arl == NULL) {
 		DTRACE_PROBE2(query_no_arl, queue_t *, q, mblk_t *, mp);
 		err = EINVAL;
@@ -1830,8 +1817,8 @@
 		 * search the other arl for a resolved ACE. If we find one,
 		 * we resolve it rather than sending out a ARP request.
 		 */
-		src_ace = ar_ce_lookup_permanent(areq->areq_proto, sender_addr,
-		    areq->areq_sender_addr_length);
+		src_ace = ar_ce_lookup_permanent(as, areq->areq_proto,
+		    sender_addr, areq->areq_sender_addr_length);
 		if (src_ace == NULL) {
 			DTRACE_PROBE3(query_source_missing, arl_t *, arl,
 			    areq_t *, areq, ace_t *, ace);
@@ -1861,7 +1848,7 @@
 			}
 		}
 	}
-	ms = ar_query_xmit(ace, src_ace);
+	ms = ar_query_xmit(as, ace, src_ace);
 	if (ms == 0) {
 		/* Immediate reply requested. */
 		ar_query_reply(ace, ENXIO, NULL, (uint32_t)0);
@@ -1870,8 +1857,11 @@
 	}
 	return (EINPROGRESS);
 err_ret:
-	if (is_mproto)
-		BUMP_IRE_STATS(ire_stats_v4, ire_stats_freed);
+	if (is_mproto) {
+		ip_stack_t *ipst = as->as_netstack->netstack_ip;
+
+		BUMP_IRE_STATS(ipst->ips_ire_stats_v4, ire_stats_freed);
+	}
 	return (err);
 }
 
@@ -1887,10 +1877,11 @@
 	mblk_t	*mp = mp_orig;
 	uchar_t	*proto_addr;
 	int	proto_addr_len;
+	arp_stack_t *as = ((ar_t *)q->q_ptr)->ar_as;
 
 	if (DB_TYPE(mp) == M_IOCTL)
 		mp = mp->b_cont;
-	arl = ar_ll_lookup_from_mp(mp);
+	arl = ar_ll_lookup_from_mp(as, mp);
 	if (arl == NULL)
 		return (EINVAL);
 	/*
@@ -1952,8 +1943,9 @@
 ar_interface_down(queue_t *q, mblk_t *mp)
 {
 	arl_t	*arl;
+	arp_stack_t *as = ((ar_t *)q->q_ptr)->ar_as;
 
-	arl = ar_ll_lookup_from_mp(mp);
+	arl = ar_ll_lookup_from_mp(as, mp);
 	if (arl == NULL || arl->arl_closing) {
 		DTRACE_PROBE2(down_no_arl, queue_t *, q, mblk_t *, mp);
 		return (EINVAL);
@@ -1987,7 +1979,7 @@
 	ASSERT(arl->arl_state == ARL_S_UP);
 
 	/* Free all arp entries for this interface */
-	ar_ce_walk(ar_ce_delete_per_arl, arl);
+	ar_ce_walk(as, ar_ce_delete_per_arl, arl);
 
 	ar_ll_down(arl);
 	/* Return EINPROGRESS so that ar_rput does not free the 'mp' */
@@ -2003,8 +1995,9 @@
 	arl_t	*arl;
 	int	err;
 	mblk_t	*mp1;
+	arp_stack_t *as = ((ar_t *)q->q_ptr)->ar_as;
 
-	arl = ar_ll_lookup_from_mp(mp);
+	arl = ar_ll_lookup_from_mp(as, mp);
 	if (arl == NULL || arl->arl_closing) {
 		DTRACE_PROBE2(up_no_arl, queue_t *, q, mblk_t *, mp);
 		err = EINVAL;
@@ -2063,8 +2056,9 @@
 ar_interface_on(queue_t *q, mblk_t *mp)
 {
 	arl_t	*arl;
+	arp_stack_t *as = ((ar_t *)q->q_ptr)->ar_as;
 
-	arl = ar_ll_lookup_from_mp(mp);
+	arl = ar_ll_lookup_from_mp(as, mp);
 	if (arl == NULL) {
 		DTRACE_PROBE2(on_no_arl, queue_t *, q, mblk_t *, mp);
 		return (EINVAL);
@@ -2084,8 +2078,9 @@
 ar_interface_off(queue_t *q, mblk_t *mp)
 {
 	arl_t	*arl;
+	arp_stack_t *as = ((ar_t *)q->q_ptr)->ar_as;
 
-	arl = ar_ll_lookup_from_mp(mp);
+	arl = ar_ll_lookup_from_mp(as, mp);
 	if (arl == NULL) {
 		DTRACE_PROBE2(off_no_arl, queue_t *, q, mblk_t *, mp);
 		return (EINVAL);
@@ -2108,8 +2103,10 @@
 	mblk_t	*mp;
 	mblk_t	*mpnext;
 	mblk_t	*prev;
+	arp_stack_t *as = ((ar_t *)q->q_ptr)->ar_as;
+	ip_stack_t *ipst = as->as_netstack->netstack_ip;
 
-	for (arl = arl_g_head; arl != NULL; arl = arl->arl_next) {
+	for (arl = as->as_arl_head; arl != NULL; arl = arl->arl_next) {
 		for (prev = NULL, mp = arl->arl_queue; mp != NULL;
 		    mp = mpnext) {
 			mpnext = mp->b_next;
@@ -2123,7 +2120,7 @@
 					arl->arl_queue_tail = prev;
 				if (DB_TYPE(mp) == M_PROTO &&
 				    *(uint32_t *)mp->b_rptr == AR_ENTRY_QUERY) {
-					BUMP_IRE_STATS(ire_stats_v4,
+					BUMP_IRE_STATS(ipst->ips_ire_stats_v4,
 					    ire_stats_freed);
 				}
 				inet_freemsg(mp);
@@ -2138,11 +2135,11 @@
  * Look up a lower level tap by name.
  */
 static arl_t *
-ar_ll_lookup_by_name(const char *name)
+ar_ll_lookup_by_name(arp_stack_t *as, const char *name)
 {
 	arl_t	*arl;
 
-	for (arl = arl_g_head; arl; arl = arl->arl_next) {
+	for (arl = as->as_arl_head; arl; arl = arl->arl_next) {
 		if (strcmp(arl->arl_name, name) == 0) {
 			return (arl);
 		}
@@ -2155,7 +2152,7 @@
  * portion of the ARP command.
  */
 static arl_t *
-ar_ll_lookup_from_mp(mblk_t *mp)
+ar_ll_lookup_from_mp(arp_stack_t *as, mblk_t *mp)
 {
 	arc_t	*arc = (arc_t *)mp->b_rptr;
 	uint8_t	*name;
@@ -2164,11 +2161,11 @@
 	name = mi_offset_param(mp, arc->arc_name_offset, namelen);
 	if (name == NULL || name[namelen - 1] != '\0')
 		return (NULL);
-	return (ar_ll_lookup_by_name((char *)name));
+	return (ar_ll_lookup_by_name(as, (char *)name));
 }
 
 static void
-ar_ll_init(ar_t *ar, mblk_t *mp)
+ar_ll_init(arp_stack_t *as, ar_t *ar, mblk_t *mp)
 {
 	arl_t	*arl;
 	dl_info_ack_t *dlia = (dl_info_ack_t *)mp->b_rptr;
@@ -2200,27 +2197,29 @@
 	 * second of every day (non-leap year) for it to wrap around and the
 	 * for() loop below to kick in as a performance concern.
 	 */
-	if (arp_counter_wrapped) {
-		arl_t *as;
+	if (as->as_arp_counter_wrapped) {
+		arl_t *arl1;
 
 		do {
-			for (as = arl_g_head; as != NULL; as = as->arl_next)
-				if (as->arl_index == arp_index_counter) {
-					arp_index_counter++;
-					if (arp_index_counter == 0) {
-						arp_counter_wrapped++;
-						arp_index_counter = 1;
+			for (arl1 = as->as_arl_g_head; arl1 != NULL;
+			    arl1 = arl1->arl_next)
+				if (arl1->arl_index ==
+				    as->as_arp_index_counter) {
+					as->as_arp_index_counter++;
+					if (as->as_arp_index_counter == 0) {
+						as->as_arp_counter_wrapped++;
+						as->as_arp_index_counter = 1;
 					}
 					break;
 			}
-		} while (as != NULL);
+		} while (arl1 != NULL);
 	} else {
-		arl->arl_index = arp_index_counter;
+		arl->arl_index = as->as_arp_index_counter;
 	}
-	arp_index_counter++;
-	if (arp_index_counter == 0) {
-		arp_counter_wrapped++;
-		arp_index_counter = 1;
+	as->as_arp_index_counter++;
+	if (as->as_arp_index_counter == 0) {
+		as->as_arp_counter_wrapped++;
+		as->as_arp_index_counter = 1;
 	}
 }
 
@@ -2454,11 +2453,12 @@
 	uchar_t	*proto_extract_mask;
 	uint32_t	hw_extract_start;
 	arl_t	*arl;
+	arp_stack_t *as = ((ar_t *)q->q_ptr)->ar_as;
 
 	/* We handle both M_IOCTL and M_PROTO messages. */
 	if (DB_TYPE(mp) == M_IOCTL)
 		mp = mp->b_cont;
-	arl = ar_ll_lookup_from_mp(mp);
+	arl = ar_ll_lookup_from_mp(as, mp);
 	if (arl == NULL)
 		return (EINVAL);
 	/*
@@ -2473,7 +2473,8 @@
 	mp_orig->b_prev = NULL;
 
 	arma = (arma_t *)mp->b_rptr;
-	if ((ace = ar_ce_lookup_from_area(mp, ar_ce_lookup_mapping)) != NULL)
+	ace = ar_ce_lookup_from_area(as, mp, ar_ce_lookup_mapping);
+	if (ace != NULL)
 		ar_ce_delete(ace);
 	hw_addr_len = arma->arma_hw_addr_length;
 	hw_addr = mi_offset_paramc(mp, arma->arma_hw_addr_offset, hw_addr_len);
@@ -2533,7 +2534,10 @@
 static int
 ar_nd_ioctl(queue_t *q, mblk_t *mp)
 {
-	if (DB_TYPE(mp) == M_IOCTL && nd_getset(q, ar_g_nd, mp))
+	ar_t	*ar = (ar_t *)q->q_ptr;
+	arp_stack_t *as = ar->ar_as;
+
+	if (DB_TYPE(mp) == M_IOCTL && nd_getset(q, as->as_nd, mp))
 		return (0);
 	return (ENOENT);
 }
@@ -2546,6 +2550,8 @@
 	int	err;
 	queue_t *tmp_q;
 	mblk_t *mp;
+	netstack_t *ns;
+	arp_stack_t *as;
 
 	TRACE_1(TR_FAC_ARP, TR_ARP_OPEN,
 	    "arp_open: q %p", q);
@@ -2553,17 +2559,17 @@
 	if (q->q_ptr != NULL) {
 		return (0);
 	}
-	/* Load up the Named Dispatch tables, if not already done. */
-	if (ar_g_nd == NULL &&
-	    !ar_param_register(arp_param_arr, A_CNT(arp_param_arr))) {
-		ar_cleanup();
-		return (ENOMEM);
-	}
+
+	ns = netstack_find_by_cred(credp);
+	ASSERT(ns != NULL);
+	as = ns->netstack_arp;
+	ASSERT(as != NULL);
+
 	/* mi_open_comm allocates the instance data structure, etc. */
-	err = mi_open_comm(&ar_g_head, sizeof (ar_t), q, devp, flag, sflag,
+	err = mi_open_comm(&as->as_head, sizeof (ar_t), q, devp, flag, sflag,
 	    credp);
 	if (err) {
-		ar_cleanup();
+		netstack_rele(as->as_netstack);
 		return (err);
 	}
 
@@ -2579,6 +2585,7 @@
 	ar->ar_wq = q;
 	crhold(credp);
 	ar->ar_credp = credp;
+	ar->ar_as = as;
 
 	/*
 	 * Probe for the DLPI info if we are not pushed on IP. Wait for
@@ -2668,14 +2675,14 @@
  * named dispatch handler.
  */
 static boolean_t
-ar_param_register(arpparam_t *arppa, int cnt)
+ar_param_register(IDP *ndp, arpparam_t *arppa, int cnt)
 {
 	for (; cnt-- > 0; arppa++) {
 		if (arppa->arp_param_name && arppa->arp_param_name[0]) {
-			if (!nd_load(&ar_g_nd, arppa->arp_param_name,
+			if (!nd_load(ndp, arppa->arp_param_name,
 			    ar_param_get, ar_param_set,
 			    (caddr_t)arppa)) {
-				nd_free(&ar_g_nd);
+				nd_free(ndp);
 				return (B_FALSE);
 			}
 		}
@@ -2715,7 +2722,8 @@
 	char	*name;
 	mblk_t 	*muxmp;
 	mblk_t 	*mp1;
-	ar_t	*ar;
+	ar_t	*ar = (ar_t *)q->q_ptr;
+	arp_stack_t *as = ar->ar_as;
 	struct	linkblk *li;
 	struct	ipmx_s	*ipmxp;
 	queue_t	*arpwq;
@@ -2764,8 +2772,8 @@
 	 * for use by IP. IP will send the M_IOCACK.
 	 */
 	if (arpwq != NULL) {
-		for (ar = (ar_t *)mi_first_ptr(&ar_g_head); ar != NULL;
-		    ar = (ar_t *)mi_next_ptr(&ar_g_head, (void *)ar)) {
+		for (ar = (ar_t *)mi_first_ptr(&as->as_head); ar != NULL;
+		    ar = (ar_t *)mi_next_ptr(&as->as_head, (void *)ar)) {
 			if ((ar->ar_wq == arpwq) && (ar->ar_arl != NULL)) {
 				ipmxp->ipmx_arpdev_stream = 1;
 				(void) strcpy((char *)ipmxp->ipmx_name,
@@ -2789,6 +2797,8 @@
 	ar_t	*ar = arg;
 	mblk_t	**mpp = &ace->ace_query_mp;
 	mblk_t	*mp;
+	arp_stack_t *as = ar->ar_as;
+	ip_stack_t *ipst = as->as_netstack->netstack_ip;
 
 	while ((mp = *mpp) != NULL) {
 		/* The response queue was stored in the query b_prev. */
@@ -2797,7 +2807,8 @@
 			*mpp = mp->b_next;
 			if (DB_TYPE(mp) == M_PROTO &&
 			    *(uint32_t *)mp->b_rptr == AR_ENTRY_QUERY) {
-				BUMP_IRE_STATS(ire_stats_v4, ire_stats_freed);
+				BUMP_IRE_STATS(ipst->ips_ire_stats_v4,
+				    ire_stats_freed);
 			}
 			inet_freemsg(mp);
 		} else {
@@ -2822,6 +2833,8 @@
 	arl_t	*arl = ace->ace_arl;
 	mblk_t	*mp;
 	mblk_t	*xmit_mp;
+	arp_stack_t *as = ARL_TO_ARPSTACK(arl);
+	ip_stack_t *ipst = as->as_netstack->netstack_ip;
 	arlphy_t *ap = arl->arl_phy;
 
 	/* Cancel any outstanding timer. */
@@ -2870,7 +2883,8 @@
 			if (ret_val != 0) {
 				/* TODO: find some way to let the guy know? */
 				inet_freemsg(mp);
-				BUMP_IRE_STATS(ire_stats_v4, ire_stats_freed);
+				BUMP_IRE_STATS(ipst->ips_ire_stats_v4,
+				    ire_stats_freed);
 				continue;
 			}
 			/*
@@ -2928,7 +2942,7 @@
 			ar_ce_delete(ace);
 		} else {
 			mi_timer(arl->arl_wq, ace->ace_mp,
-			    arp_cleanup_interval);
+			    as->as_cleanup_interval);
 		}
 	}
 }
@@ -2939,7 +2953,7 @@
  * to the source address in the areq sent by IP.
  */
 static clock_t
-ar_query_xmit(ace_t *ace, ace_t *src_ace)
+ar_query_xmit(arp_stack_t *as, ace_t *ace, ace_t *src_ace)
 {
 	areq_t	*areq;
 	mblk_t	*mp;
@@ -2967,8 +2981,8 @@
 	 * interface.
 	 */
 	if (src_ace == NULL) {
-		src_ace = ar_ce_lookup_permanent(areq->areq_proto, sender_addr,
-		    areq->areq_sender_addr_length);
+		src_ace = ar_ce_lookup_permanent(as, areq->areq_proto,
+		    sender_addr, areq->areq_sender_addr_length);
 		if (src_ace == NULL) {
 			DTRACE_PROBE3(xmit_no_source, ace_t *, ace,
 			    areq_t *, areq, uchar_t *, sender_addr);
@@ -3001,7 +3015,7 @@
 	    areq_t *, areq);
 	ar_xmit(src_arl, ARP_REQUEST, areq->areq_proto,
 	    areq->areq_sender_addr_length, src_arl->arl_phy->ap_hw_addr,
-	    sender_addr, src_arl->arl_phy->ap_arp_addr, proto_addr, NULL);
+	    sender_addr, src_arl->arl_phy->ap_arp_addr, proto_addr, NULL, as);
 	src_ace->ace_last_bcast = ddi_get_lbolt();
 	return (areq->areq_xmit_interval);
 }
@@ -3025,6 +3039,7 @@
 	uchar_t	*src_paddr;
 	boolean_t is_probe;
 	int i;
+	arp_stack_t *as = ((ar_t *)q->q_ptr)->ar_as;
 
 	TRACE_1(TR_FAC_ARP, TR_ARP_RPUT_START,
 	    "arp_rput_start: q %p", q);
@@ -3036,7 +3051,7 @@
 	 */
 	switch (DB_TYPE(mp)) {
 	case M_IOCTL:
-		err = ar_cmd_dispatch(q, mp);
+		err = ar_cmd_dispatch(q, mp, B_FALSE);
 		switch (err) {
 		case ENOENT:
 			DB_TYPE(mp) = M_IOCNAK;
@@ -3092,7 +3107,7 @@
 			    "arp_rput_end: q %p (%S)", q, "default");
 			return;
 		}
-		err = ar_cmd_dispatch(q, mp);
+		err = ar_cmd_dispatch(q, mp, B_FALSE);
 		switch (err) {
 		case ENOENT:
 			/* Miscellaneous DLPI messages get shuffled off. */
@@ -3179,8 +3194,8 @@
 	DTRACE_PROBE3(arp__physical__in__start,
 	    arl_t *, arl, arh_t *, arh, mblk_t *, mp);
 
-	ARP_HOOK_IN(arp_physical_in_event, arp_physical_in,
-		    arl->arl_index, arh, mp, mp1);
+	ARP_HOOK_IN(as->as_arp_physical_in_event, as->as_arp_physical_in,
+		    arl->arl_index, arh, mp, mp1, as);
 
 	DTRACE_PROBE1(arp__physical__in__end, mblk_t *, mp);
 
@@ -3318,7 +3333,7 @@
 		 */
 		now = ddi_get_lbolt();
 		if ((now - dst_ace->ace_last_bcast) >
-		    MSEC_TO_TICK(arp_broadcast_interval)) {
+		    MSEC_TO_TICK(as->as_broadcast_interval)) {
 			DTRACE_PROBE3(rput_bcast_reply, arl_t *, arl,
 			    arh_t *, arh, ace_t *, dst_ace);
 			dst_ace->ace_last_bcast = now;
@@ -3334,7 +3349,7 @@
 
 		ar_xmit(arl, ARP_RESPONSE, dst_ace->ace_proto, plen,
 		    dst_ace->ace_hw_addr, dst_ace->ace_proto_addr,
-		    src_haddr, src_paddr, dstaddr);
+		    src_haddr, src_paddr, dstaddr, as);
 		if (!is_probe && err == AR_NOTFOUND &&
 		    ar_ce_create(arl, proto, src_haddr, hlen, src_paddr, plen,
 		    NULL, NULL, 0, 0) == 0) {
@@ -3343,7 +3358,7 @@
 			ace = ar_ce_lookup(arl, proto, src_paddr, plen);
 			ASSERT(ace != NULL);
 			mi_timer(arl->arl_wq, ace->ace_mp,
-			    arp_cleanup_interval);
+			    as->as_cleanup_interval);
 		}
 	}
 	if (err == AR_CHANGED) {
@@ -3359,8 +3374,11 @@
 }
 
 static void
-ar_ce_restart_dad(ace_t *ace, void *arl)
+ar_ce_restart_dad(ace_t *ace, void *arl_arg)
 {
+	arl_t *arl = arl_arg;
+	arp_stack_t *as = ARL_TO_ARPSTACK(arl);
+
 	if ((ace->ace_arl == arl) &&
 	    (ace->ace_flags & (ACE_F_UNVERIFIED|ACE_F_DAD_ABORTED)) ==
 	    (ACE_F_UNVERIFIED|ACE_F_DAD_ABORTED)) {
@@ -3369,11 +3387,11 @@
 		 * in this obscure case.
 		 */
 		if (ace->ace_flags & ACE_F_FAST) {
-			ace->ace_xmit_count = arp_fastprobe_count;
-			ace->ace_xmit_interval = arp_fastprobe_interval;
+			ace->ace_xmit_count = as->as_fastprobe_count;
+			ace->ace_xmit_interval = as->as_fastprobe_interval;
 		} else {
-			ace->ace_xmit_count = arp_probe_count;
-			ace->ace_xmit_interval = arp_probe_interval;
+			ace->ace_xmit_count = as->as_probe_count;
+			ace->ace_xmit_interval = as->as_probe_interval;
 		}
 		ace->ace_flags &= ~ACE_F_DAD_ABORTED;
 		ace_set_timer(ace, B_FALSE);
@@ -3389,6 +3407,7 @@
 	arlphy_t	*ap = NULL;
 	union DL_primitives *dlp;
 	const char	*err_str;
+	arp_stack_t	*as = ar->ar_as;
 
 	if (arl != NULL)
 		ap = arl->arl_phy;
@@ -3451,7 +3470,7 @@
 			ar_ll_set_defaults(arl, mp);
 			ar_dlpi_done(arl, DL_INFO_REQ);
 		} else if (arl == NULL) {
-			ar_ll_init(ar, mp);
+			ar_ll_init(as, ar, mp);
 		}
 		/* Kick off any awaiting messages */
 		qenable(WR(q));
@@ -3509,7 +3528,7 @@
 			switch (dlp->notify_ind.dl_notification) {
 			case DL_NOTE_LINK_UP:
 				ap->ap_link_down = B_FALSE;
-				ar_ce_walk(ar_ce_restart_dad, arl);
+				ar_ce_walk(as, ar_ce_restart_dad, arl);
 				break;
 			case DL_NOTE_LINK_DOWN:
 				ap->ap_link_down = B_TRUE;
@@ -3570,6 +3589,7 @@
 	mblk_t *ioccpy;
 	struct iocblk *iocp;
 	hook_nic_event_t info;
+	arp_stack_t *as = ar->ar_as;
 
 	if (ar->ar_on_ill_stream) {
 		/*
@@ -3613,7 +3633,7 @@
 
 	/* Check whether the name is already in use. */
 
-	old_arl = ar_ll_lookup_by_name(lifr->lifr_name);
+	old_arl = ar_ll_lookup_by_name(as, lifr->lifr_name);
 	if (old_arl != NULL) {
 		DTRACE_PROBE2(slifname_exists, arl_t *, arl, arl_t *, old_arl);
 		return (EEXIST);
@@ -3644,12 +3664,13 @@
 	info.hne_event = NE_PLUMB;
 	info.hne_data = arl->arl_name;
 	info.hne_datalen = strlen(arl->arl_name);
-	(void) hook_run(arpnicevents, (hook_data_t)&info);
+	(void) hook_run(as->as_arpnicevents, (hook_data_t)&info,
+	    as->as_netstack);
 
 	/* Chain in the new arl. */
-	rw_enter(&arl_g_lock, RW_WRITER);
-	arl->arl_next = arl_g_head;
-	arl_g_head = arl;
+	rw_enter(&as->as_arl_g_lock, RW_WRITER);
+	arl->arl_next = as->as_arl_head;
+	as->as_arl_head = arl;
 	DTRACE_PROBE1(slifname_set, arl_t *, arl);
 
 	/*
@@ -3663,7 +3684,7 @@
 	iocp->ioc_count = msgsize(ioccpy->b_cont);
 	ioccpy->b_wptr = (uchar_t *)(iocp + 1);
 	putnext(arl->arl_wq, ioccpy);
-	rw_exit(&arl_g_lock);
+	rw_exit(&as->as_arl_g_lock);
 
 	return (0);
 }
@@ -3677,6 +3698,7 @@
 	char	*cp;
 	mblk_t	*mp = mp_orig;
 	arl_t	*old_arl;
+	arp_stack_t *as = ar->ar_as;
 
 	if (ar->ar_on_ill_stream) {
 		/*
@@ -3714,7 +3736,7 @@
 	ppa = *(int *)(mp->b_rptr);
 	(void) snprintf(arl->arl_name, sizeof (arl->arl_name), "%s%d", cp, ppa);
 
-	old_arl = ar_ll_lookup_by_name(arl->arl_name);
+	old_arl = ar_ll_lookup_by_name(as, arl->arl_name);
 	if (old_arl != NULL) {
 		DTRACE_PROBE2(setppa_exists, arl_t *, arl, arl_t *, old_arl);
 		/* Make it a null string again */
@@ -3725,10 +3747,10 @@
 	arl->arl_ppa = ppa;
 	DTRACE_PROBE1(setppa_done, arl_t *, arl);
 	/* Chain in the new arl. */
-	rw_enter(&arl_g_lock, RW_WRITER);
-	arl->arl_next = arl_g_head;
-	arl_g_head = arl;
-	rw_exit(&arl_g_lock);
+	rw_enter(&as->as_arl_g_lock, RW_WRITER);
+	arl->arl_next = as->as_arl_head;
+	as->as_arl_head = arl;
+	rw_exit(&as->as_arl_g_lock);
 
 	return (0);
 }
@@ -3739,6 +3761,7 @@
 	mblk_t		*mpdata, *mp = mp_orig;
 	struct opthdr	*optp;
 	msg2_args_t	args;
+	arp_stack_t *as = ((ar_t *)q->q_ptr)->ar_as;
 
 	if (mp == NULL)
 		return (0);
@@ -3761,7 +3784,7 @@
 
 		args.m2a_mpdata = mpdata;
 		args.m2a_mptail = NULL;
-		ar_ce_walk(ar_snmp_msg2, &args);
+		ar_ce_walk(as, ar_snmp_msg2, &args);
 		optp->len = msgdsize(mpdata);
 	}
 	putnext(q, mp_orig);
@@ -3828,7 +3851,7 @@
 	 */
 	switch (DB_TYPE(mp)) {
 	case M_IOCTL:
-		switch (err = ar_cmd_dispatch(q, mp)) {
+		switch (err = ar_cmd_dispatch(q, mp, B_TRUE)) {
 		case ENOENT:
 			/*
 			 * If it is an I_PLINK, process it. Otherwise
@@ -3913,7 +3936,7 @@
 		 * Commands in the form of PROTO messages are handled very
 		 * much the same as IOCTLs, but no response is returned.
 		 */
-		switch (err = ar_cmd_dispatch(q, mp)) {
+		switch (err = ar_cmd_dispatch(q, mp, B_TRUE)) {
 		case ENOENT:
 			if (q->q_next) {
 				putnext(q, mp);
@@ -4041,23 +4064,24 @@
 	ace_resched_t art;
 	int i;
 	ace_t *ace;
+	arp_stack_t *as = ARL_TO_ARPSTACK(arl);
 
 	i = ap->ap_defend_count;
 	ap->ap_defend_count = 0;
 	/* If none could be sitting around, then don't reschedule */
-	if (i < arp_defend_rate) {
+	if (i < as->as_defend_rate) {
 		DTRACE_PROBE1(reschedule_none, arl_t *, arl);
 		return;
 	}
 	art.art_arl = arl;
-	while (ap->ap_defend_count < arp_defend_rate) {
+	while (ap->ap_defend_count < as->as_defend_rate) {
 		art.art_naces = 0;
-		ar_ce_walk(ace_reschedule, &art);
+		ar_ce_walk(as, ace_reschedule, &art);
 		for (i = 0; i < art.art_naces; i++) {
 			ace = art.art_aces[i];
 			ace->ace_flags |= ACE_F_DELAYED;
 			ace_set_timer(ace, B_FALSE);
-			if (++ap->ap_defend_count >= arp_defend_rate)
+			if (++ap->ap_defend_count >= as->as_defend_rate)
 				break;
 		}
 		if (art.art_naces < ACE_RESCHED_LIST_LEN)
@@ -4079,6 +4103,7 @@
 	arlphy_t *ap;
 	mblk_t *mp;
 	clock_t	ms;
+	arp_stack_t *as = ((ar_t *)q->q_ptr)->ar_as;
 
 	TRACE_1(TR_FAC_ARP, TR_ARP_WSRV_START,
 	    "arp_wsrv_start: q %p", q);
@@ -4115,15 +4140,16 @@
 					    ace->ace_proto,
 					    ace->ace_proto_addr_length,
 					    ace->ace_hw_addr, NULL, NULL,
-					    ace->ace_proto_addr, NULL);
+					    ace->ace_proto_addr, NULL, as);
 					ace_set_timer(ace, B_FALSE);
 					continue;
 				}
 				if (!arp_say_ready(ace))
 					continue;
 				DTRACE_PROBE1(timer_ready, ace_t *, ace);
-				ace->ace_xmit_interval = arp_publish_interval;
-				ace->ace_xmit_count = arp_publish_count;
+				ace->ace_xmit_interval =
+				    as->as_publish_interval;
+				ace->ace_xmit_count = as->as_publish_count;
 				if (ace->ace_xmit_count == 0)
 					ace->ace_xmit_count++;
 				ace->ace_flags &= ~ACE_F_UNVERIFIED;
@@ -4137,9 +4163,9 @@
 				 * them.
 				 */
 				now = ddi_get_lbolt();
-				if (arp_defend_rate > 0 &&
+				if (as->as_defend_rate > 0 &&
 				    now - ap->ap_defend_start >
-				    SEC_TO_TICK(arp_defend_period)) {
+				    SEC_TO_TICK(as->as_defend_period)) {
 					ap->ap_defend_start = now;
 					arl_reschedule(arl);
 				}
@@ -4164,9 +4190,11 @@
 					DTRACE_PROBE1(timer_send_delayed,
 					    ace_t *, ace);
 					ace->ace_flags &= ~ACE_F_DELAYED;
-				} else if (arp_defend_rate > 0 &&
-				    (ap->ap_defend_count >= arp_defend_rate ||
-				    ++ap->ap_defend_count >= arp_defend_rate)) {
+				} else if (as->as_defend_rate > 0 &&
+				    (ap->ap_defend_count >=
+				    as->as_defend_rate ||
+				    ++ap->ap_defend_count >=
+				    as->as_defend_rate)) {
 					/*
 					 * If we're no longer allowed to send
 					 * unbidden defense messages, then just
@@ -4186,11 +4214,11 @@
 				    ace->ace_hw_addr,
 				    ace->ace_proto_addr,
 				    ap->ap_arp_addr,
-				    ace->ace_proto_addr, NULL);
+				    ace->ace_proto_addr, NULL, as);
 				ace->ace_last_bcast = now;
 				if (ace->ace_xmit_count == 0)
 					ace->ace_xmit_interval =
-					    arp_defend_interval;
+					    as->as_defend_interval;
 				if (ace->ace_xmit_interval != 0)
 					ace_set_timer(ace, B_FALSE);
 				continue;
@@ -4206,10 +4234,10 @@
 			if (ACE_NONPERM(ace)) {
 				if (ace->ace_proto == IP_ARP_PROTO_TYPE &&
 				    ndp_lookup_ipaddr(*(ipaddr_t *)
-				    ace->ace_proto_addr)) {
+				    ace->ace_proto_addr, as->as_netstack)) {
 					ace->ace_flags |= ACE_F_OLD;
 					mi_timer(arl->arl_wq, ace->ace_mp,
-					    arp_cleanup_interval);
+					    as->as_cleanup_interval);
 				} else {
 					ar_delete_notify(ace);
 					ar_ce_delete(ace);
@@ -4226,7 +4254,7 @@
 			 * Otherwise, we restart the timer.
 			 */
 			ASSERT(ace->ace_query_mp != NULL);
-			ms = ar_query_xmit(ace, NULL);
+			ms = ar_query_xmit(as, ace, NULL);
 			if (ms == 0)
 				ar_query_reply(ace, ENXIO, NULL, (uint32_t)0);
 			else
@@ -4245,7 +4273,7 @@
 static void
 ar_xmit(arl_t *arl, uint32_t operation, uint32_t proto, uint32_t plen,
     const uchar_t *haddr1, const uchar_t *paddr1, const uchar_t *haddr2,
-    const uchar_t *paddr2, const uchar_t *dstaddr)
+    const uchar_t *paddr2, const uchar_t *dstaddr, arp_stack_t *as)
 {
 	arh_t	*arh;
 	uint8_t	*cp;
@@ -4320,8 +4348,8 @@
 	DTRACE_PROBE3(arp__physical__out__start,
 	    arl_t *, arl, arh_t *, arh, mblk_t *, mp);
 
-	ARP_HOOK_OUT(arp_physical_out_event, arp_physical_out,
-	    arl->arl_index, arh, mp, mp->b_cont);
+	ARP_HOOK_OUT(as->as_arp_physical_out_event, as->as_arp_physical_out,
+	    arl->arl_index, arh, mp, mp->b_cont, as);
 
 	DTRACE_PROBE1(arp__physical__out__end, mblk_t *, mp);
 
@@ -4370,3 +4398,69 @@
 	linkb(mp, mp1);
 	return (mp);
 }
+
+void
+arp_ddi_init(void)
+{
+	/*
+	 * We want to be informed each time a stack is created or
+	 * destroyed in the kernel, so we can maintain the
+	 * set of arp_stack_t's.
+	 */
+	netstack_register(NS_ARP, arp_stack_init, NULL, arp_stack_fini);
+}
+
+void
+arp_ddi_destroy(void)
+{
+	netstack_unregister(NS_ARP);
+}
+
+/*
+ * Initialize the ARP stack instance.
+ */
+/* ARGSUSED */
+static void *
+arp_stack_init(netstackid_t stackid, netstack_t *ns)
+{
+	arp_stack_t	*as;
+	arpparam_t	*pa;
+
+	as = (arp_stack_t *)kmem_zalloc(sizeof (*as), KM_SLEEP);
+	as->as_netstack = ns;
+
+	pa = (arpparam_t *)kmem_alloc(sizeof (arp_param_arr), KM_SLEEP);
+	as->as_param_arr = pa;
+	bcopy(arp_param_arr, as->as_param_arr, sizeof (arp_param_arr));
+
+	(void) ar_param_register(&as->as_nd,
+	    as->as_param_arr, A_CNT(arp_param_arr));
+
+	as->as_arp_index_counter = 1;
+	as->as_arp_counter_wrapped = 0;
+
+	rw_init(&as->as_arl_g_lock, "ARP ARl lock", RW_DRIVER, NULL);
+	arp_net_init(as, ns);
+	arp_hook_init(as);
+
+	return (as);
+}
+
+/*
+ * Free the ARP stack instance.
+ */
+/* ARGSUSED */
+static void
+arp_stack_fini(netstackid_t stackid, void *arg)
+{
+	arp_stack_t *as = (arp_stack_t *)arg;
+
+	arp_hook_destroy(as);
+	arp_net_destroy(as);
+	rw_destroy(&as->as_arl_g_lock);
+
+	nd_free(&as->as_nd);
+	kmem_free(as->as_param_arr, sizeof (arp_param_arr));
+	as->as_param_arr = NULL;
+	kmem_free(as, sizeof (*as));
+}
diff --git a/usr/src/uts/common/inet/arp/arp_netinfo.c b/usr/src/uts/common/inet/arp/arp_netinfo.c
index 0d2f55e..4869053 100644
--- a/usr/src/uts/common/inet/arp/arp_netinfo.c
+++ b/usr/src/uts/common/inet/arp/arp_netinfo.c
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -33,6 +33,7 @@
 #include <sys/sunddi.h>
 #include <sys/hook.h>
 #include <sys/hook_impl.h>
+#include <sys/netstack.h>
 #include <net/if.h>
 
 #include <sys/neti.h>
@@ -42,16 +43,16 @@
 /*
  * ARP netinfo entry point declarations.
  */
-static int 	arp_getifname(phy_if_t, char *, const size_t);
-static int 	arp_getmtu(phy_if_t, lif_if_t);
-static int 	arp_getpmtuenabled(void);
+static int 	arp_getifname(phy_if_t, char *, const size_t, netstack_t *);
+static int 	arp_getmtu(phy_if_t, lif_if_t, netstack_t *);
+static int 	arp_getpmtuenabled(netstack_t *);
 static int 	arp_getlifaddr(phy_if_t, lif_if_t, size_t,
-		    net_ifaddr_t [], void *);
-static phy_if_t arp_phygetnext(phy_if_t);
-static phy_if_t arp_phylookup(const char *);
-static lif_if_t arp_lifgetnext(phy_if_t, lif_if_t);
-static int 	arp_inject(inject_t, net_inject_t *);
-static phy_if_t arp_routeto(struct sockaddr *);
+		    net_ifaddr_t [], void *, netstack_t *);
+static phy_if_t arp_phygetnext(phy_if_t, netstack_t *);
+static phy_if_t arp_phylookup(const char *, netstack_t *);
+static lif_if_t arp_lifgetnext(phy_if_t, lif_if_t, netstack_t *);
+static int 	arp_inject(inject_t, net_inject_t *, netstack_t *);
+static phy_if_t arp_routeto(struct sockaddr *, netstack_t *);
 static int 	arp_ispartialchecksum(mblk_t *);
 static int 	arp_isvalidchecksum(mblk_t *);
 
@@ -71,115 +72,109 @@
 	arp_isvalidchecksum
 };
 
-static hook_family_t	arproot;
-
-/*
- * Hooks for ARP
- */
-
-hook_event_t		arp_physical_in_event;
-hook_event_t		arp_physical_out_event;
-hook_event_t		arp_nic_events;
-
-hook_event_token_t	arp_physical_in;
-hook_event_token_t	arp_physical_out;
-hook_event_token_t	arpnicevents;
-
-net_data_t		arp = NULL;
-
 /*
  * Register ARP netinfo functions.
  */
 void
-arp_net_init()
+arp_net_init(arp_stack_t *as, netstack_t *ns)
 {
-	arp = net_register(&arp_netinfo);
-	ASSERT(arp != NULL);
+	as->as_net_data = net_register_impl(&arp_netinfo, ns);
+	ASSERT(as->as_net_data != NULL);
 }
 
 /*
  * Unregister ARP netinfo functions.
  */
 void
-arp_net_destroy()
+arp_net_destroy(arp_stack_t *as)
 {
-	(void) net_unregister(arp);
+	(void) net_unregister(as->as_net_data);
 }
 
 /*
  * Initialize ARP hook family and events
  */
 void
-arp_hook_init()
+arp_hook_init(arp_stack_t *as)
 {
-	HOOK_FAMILY_INIT(&arproot, Hn_ARP);
-	if (net_register_family(arp, &arproot) != 0) {
+	HOOK_FAMILY_INIT(&as->as_arproot, Hn_ARP);
+	if (net_register_family(as->as_net_data, &as->as_arproot) != 0) {
 		cmn_err(CE_NOTE, "arp_hook_init: "
 		    "net_register_family failed for arp");
 	}
 
-	HOOK_EVENT_INIT(&arp_physical_in_event, NH_PHYSICAL_IN);
-	arp_physical_in = net_register_event(arp, &arp_physical_in_event);
-	if (arp_physical_in == NULL) {
+	HOOK_EVENT_INIT(&as->as_arp_physical_in_event, NH_PHYSICAL_IN);
+	as->as_arp_physical_in = net_register_event(as->as_net_data,
+	    &as->as_arp_physical_in_event);
+	if (as->as_arp_physical_in == NULL) {
 		cmn_err(CE_NOTE, "arp_hook_init: "
 		    "net_register_event failed for arp/physical_in");
 	}
 
-	HOOK_EVENT_INIT(&arp_physical_out_event, NH_PHYSICAL_OUT);
-	arp_physical_out = net_register_event(arp, &arp_physical_out_event);
-	if (arp_physical_out == NULL) {
+	HOOK_EVENT_INIT(&as->as_arp_physical_out_event, NH_PHYSICAL_OUT);
+	as->as_arp_physical_out = net_register_event(as->as_net_data,
+	    &as->as_arp_physical_out_event);
+	if (as->as_arp_physical_out == NULL) {
 		cmn_err(CE_NOTE, "arp_hook_init: "
 		    "net_register_event failed for arp/physical_out");
 	}
 
-	HOOK_EVENT_INIT(&arp_nic_events, NH_NIC_EVENTS);
-	arpnicevents = net_register_event(arp, &arp_nic_events);
-	if (arpnicevents == NULL) {
+	HOOK_EVENT_INIT(&as->as_arp_nic_events, NH_NIC_EVENTS);
+	as->as_arpnicevents = net_register_event(as->as_net_data,
+	    &as->as_arp_nic_events);
+	if (as->as_arpnicevents == NULL) {
 		cmn_err(CE_NOTE, "arp_hook_init: "
 		    "net_register_event failed for arp/nic_events");
 	}
 }
 
 void
-arp_hook_destroy()
+arp_hook_destroy(arp_stack_t *as)
 {
-	if (arpnicevents != NULL) {
-		if (net_unregister_event(arp, &arp_nic_events) == 0)
-			arpnicevents = NULL;
+	if (as->as_arpnicevents != NULL) {
+		if (net_unregister_event(as->as_net_data,
+		    &as->as_arp_nic_events) == 0)
+			as->as_arpnicevents = NULL;
 	}
 
-	if (arp_physical_out != NULL) {
-		if (net_unregister_event(arp, &arp_physical_out_event) == 0)
-			arp_physical_out = NULL;
+	if (as->as_arp_physical_out != NULL) {
+		if (net_unregister_event(as->as_net_data,
+		    &as->as_arp_physical_out_event) == 0)
+			as->as_arp_physical_out = NULL;
 	}
 
-	if (arp_physical_in != NULL) {
-		if (net_unregister_event(arp, &arp_physical_in_event) == 0)
-			arp_physical_in = NULL;
+	if (as->as_arp_physical_in != NULL) {
+		if (net_unregister_event(as->as_net_data,
+		    &as->as_arp_physical_in_event) == 0)
+			as->as_arp_physical_in = NULL;
 	}
 
-	(void) net_unregister_family(arp, &arproot);
+	(void) net_unregister_family(as->as_net_data, &as->as_arproot);
 }
 
 /*
  * Determine the name of the lower level interface
  */
-int
-arp_getifname(phy_if_t phy_ifdata, char *buffer, const size_t buflen)
+static int
+arp_getifname(phy_if_t phy_ifdata, char *buffer, const size_t buflen,
+    netstack_t *ns)
 {
 	arl_t	*arl;
+	arp_stack_t *as;
 
 	ASSERT(buffer != NULL);
+	ASSERT(ns != NULL);
 
-	rw_enter(&arl_g_lock, RW_READER);
-	for (arl = arl_g_head; arl != NULL; arl = arl->arl_next) {
+	as = ns->netstack_arp;
+	rw_enter(&as->as_arl_g_lock, RW_READER);
+	for (arl = as->as_arl_g_head; arl != NULL; arl = arl->arl_next) {
 		if (arl->arl_index == phy_ifdata) {
 			(void) strlcpy(buffer, arl->arl_name, buflen);
-			rw_exit(&arl_g_lock);
+			rw_exit(&as->as_arl_g_lock);
 			return (0);
 		}
 	}
-	rw_exit(&arl_g_lock);
+	rw_exit(&as->as_arl_g_lock);
 
 	return (1);
 }
@@ -188,8 +183,8 @@
  * Unsupported with ARP.
  */
 /*ARGSUSED*/
-int
-arp_getmtu(phy_if_t phy_ifdata, lif_if_t ifdata)
+static int
+arp_getmtu(phy_if_t phy_ifdata, lif_if_t ifdata, netstack_t *ns)
 {
 	return (-1);
 }
@@ -198,8 +193,8 @@
  * Unsupported with ARP.
  */
 /*ARGSUSED*/
-int
-arp_getpmtuenabled(void)
+static int
+arp_getpmtuenabled(netstack_t *ns)
 {
 	return (-1);
 }
@@ -208,9 +203,9 @@
  * Unsupported with ARP.
  */
 /*ARGSUSED*/
-int
+static int
 arp_getlifaddr(phy_if_t phy_ifdata, lif_if_t ifdata, size_t nelem,
-	net_ifaddr_t type[], void *storage)
+	net_ifaddr_t type[], void *storage, netstack_t *ns)
 {
 	return (-1);
 }
@@ -218,17 +213,22 @@
 /*
  * Determine the instance number of the next lower level interface
  */
-phy_if_t
-arp_phygetnext(phy_if_t phy_ifdata)
+static phy_if_t
+arp_phygetnext(phy_if_t phy_ifdata, netstack_t *ns)
 {
 	arl_t *arl;
 	int index;
+	arp_stack_t *as;
 
-	rw_enter(&arl_g_lock, RW_READER);
+	ASSERT(ns != NULL);
+
+	as = ns->netstack_arp;
+	rw_enter(&as->as_arl_g_lock, RW_READER);
 	if (phy_ifdata == 0) {
-		arl = arl_g_head;
+		arl = as->as_arl_g_head;
 	} else {
-		for (arl = arl_g_head; arl != NULL; arl = arl->arl_next) {
+		for (arl = as->as_arl_g_head; arl != NULL;
+		    arl = arl->arl_next) {
 			if (arl->arl_index == phy_ifdata) {
 				arl = arl->arl_next;
 				break;
@@ -238,7 +238,7 @@
 
 	index = (arl != NULL) ? arl->arl_index : 0;
 
-	rw_exit(&arl_g_lock);
+	rw_exit(&as->as_arl_g_lock);
 
 	return (index);
 }
@@ -246,24 +246,26 @@
 /*
  * Given a network interface name, find its ARP layer instance number.
  */
-phy_if_t
-arp_phylookup(const char *name)
+static phy_if_t
+arp_phylookup(const char *name, netstack_t *ns)
 {
 	arl_t *arl;
 	int index;
+	arp_stack_t *as;
 
 	ASSERT(name != NULL);
+	ASSERT(ns != NULL);
 
 	index = 0;
-
-	rw_enter(&arl_g_lock, RW_READER);
-	for (arl = arl_g_head; arl != NULL; arl = arl->arl_next) {
+	as = ns->netstack_arp;
+	rw_enter(&as->as_arl_g_lock, RW_READER);
+	for (arl = as->as_arl_g_head; arl != NULL; arl = arl->arl_next) {
 		if (strcmp(name, arl->arl_name) == 0) {
 			index = arl->arl_index;
 			break;
 		}
 	}
-	rw_exit(&arl_g_lock);
+	rw_exit(&as->as_arl_g_lock);
 
 	return (index);
 
@@ -273,8 +275,8 @@
  * Unsupported with ARP.
  */
 /*ARGSUSED*/
-lif_if_t
-arp_lifgetnext(phy_if_t ifp, lif_if_t lif)
+static lif_if_t
+arp_lifgetnext(phy_if_t ifp, lif_if_t lif, netstack_t *ns)
 {
 	return ((lif_if_t)-1);
 }
@@ -283,8 +285,8 @@
  * Unsupported with ARP.
  */
 /*ARGSUSED*/
-int
-arp_inject(inject_t injection, net_inject_t *neti)
+static int
+arp_inject(inject_t injection, net_inject_t *neti, netstack_t *ns)
 {
 	return (-1);
 }
@@ -293,8 +295,8 @@
  * Unsupported with ARP.
  */
 /*ARGSUSED*/
-phy_if_t
-arp_routeto(struct sockaddr *addr)
+static phy_if_t
+arp_routeto(struct sockaddr *addr, netstack_t *ns)
 {
 	return ((phy_if_t)-1);
 }
@@ -313,7 +315,7 @@
  * Unsupported with ARP.
  */
 /*ARGSUSED*/
-int
+static int
 arp_isvalidchecksum(mblk_t *mb)
 {
 	return (-1);
diff --git a/usr/src/uts/common/inet/arp/arpddi.c b/usr/src/uts/common/inet/arp/arpddi.c
index 5ca60b1..edd5cd4 100644
--- a/usr/src/uts/common/inet/arp/arpddi.c
+++ b/usr/src/uts/common/inet/arp/arpddi.c
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /* Copyright (c) 1990 Mentat Inc. */
@@ -42,29 +42,35 @@
 #define	INET_DEVMTFLAGS	IP_DEVMTFLAGS	/* since as a driver we're ip */
 #define	INET_MODMTFLAGS	(D_MP | D_MTPERMOD)
 
-static void	arp_ddi_destroy();
-static void	arp_ddi_init();
-
 #include "../inetddi.c"
 
+extern void arp_ddi_init(void);
+extern void arp_ddi_destroy(void);
+
 int
 _init(void)
 {
-	int error;
+	int	error;
 
-	arp_ddi_init();
 	INET_BECOME_IP();
 
+	/*
+	 * Note: After mod_install succeeds, another thread can enter
+	 * therefore all initialization is done before it and any
+	 * de-initialization needed done if it fails.
+	 */
+	arp_ddi_init();
 	error = mod_install(&modlinkage);
 	if (error != 0)
 		arp_ddi_destroy();
+
 	return (error);
 }
 
 int
 _fini(void)
 {
-	int error;
+	int	error;
 
 	error = mod_remove(&modlinkage);
 	if (error == 0)
@@ -77,21 +83,3 @@
 {
 	return (mod_info(&modlinkage, modinfop));
 }
-
-
-static void
-arp_ddi_init()
-{
-	rw_init(&arl_g_lock, "ARP ARl lock", RW_DRIVER, NULL);
-	arp_net_init();
-	arp_hook_init();
-}
-
-
-static void
-arp_ddi_destroy()
-{
-	arp_hook_destroy();
-	arp_net_destroy();
-	rw_destroy(&arl_g_lock);
-}
diff --git a/usr/src/uts/common/inet/arp_impl.h b/usr/src/uts/common/inet/arp_impl.h
index c6e12bc..567e2b8 100644
--- a/usr/src/uts/common/inet/arp_impl.h
+++ b/usr/src/uts/common/inet/arp_impl.h
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -37,10 +37,19 @@
 #include <sys/types.h>
 #include <sys/stream.h>
 #include <net/if.h>
+#include <sys/netstack.h>
 
 /* ARP kernel hash size; used for mdb support */
 #define	ARP_HASH_SIZE	256
 
+/* Named Dispatch Parameter Management Structure */
+typedef struct arpparam_s {
+	uint32_t	arp_param_min;
+	uint32_t	arp_param_max;
+	uint32_t	arp_param_value;
+	char		*arp_param_name;
+} arpparam_t;
+
 /* ARL Structure, one per link level device */
 typedef struct arl_s {
 	struct arl_s	*arl_next;		/* ARL chain at arl_g_head */
@@ -62,6 +71,12 @@
 	struct arlphy_s	*arl_phy;		/* physical info, if any */
 } arl_t;
 
+/*
+ * There is no field to get from an arl_t to an arp_stack_t, but this
+ * macro does it.
+ */
+#define	ARL_TO_ARPSTACK(_arl)	(((ar_t *)(_arl)->arl_rq->q_ptr)->ar_as)
+
 /* ARL physical info structure for a link level device */
 typedef struct arlphy_s {
 	uint32_t	ap_arp_hw_type;		/* hardware type */
@@ -78,27 +93,6 @@
 			ap_link_down : 1;	/* DL_NOTE status */
 } arlphy_t;
 
-extern arl_t		*arl_g_head; 		/* ARL chain head */
-extern krwlock_t	arl_g_lock;
-
-#define	ARL_F_NOARP	0x01
-
-#define	ARL_S_DOWN	0x00
-#define	ARL_S_PENDING	0x01
-#define	ARL_S_UP	0x02
-
-/* AR Structure, one per upper stream */
-typedef struct ar_s {
-	queue_t		*ar_rq;	/* Read queue pointer */
-	queue_t		*ar_wq;	/* Write queue pointer */
-	arl_t		*ar_arl;	/* Associated arl */
-	cred_t		*ar_credp;	/* Credentials associated w/ open */
-	struct ar_s	*ar_arl_ip_assoc;	/* ARL - IP association */
-	uint32_t
-			ar_ip_acked_close : 1,	/* IP has acked the close */
-			ar_on_ill_stream : 1;	/* Module below is IP */
-} ar_t;
-
 /* ARP Cache Entry */
 typedef struct ace_s {
 	struct ace_s	*ace_next;	/* Hash chain next pointer */
@@ -120,23 +114,12 @@
 	int		ace_xmit_count;
 } ace_t;
 
-/*
- * Hooks structures used inside of arp
- */
-extern hook_event_token_t	arp_physical_in;
-extern hook_event_token_t	arp_physical_out;
-extern hook_event_token_t	arpnicevents;
+#define	ARPHOOK_INTERESTED_PHYSICAL_IN(as)	\
+	(as->as_arp_physical_in_event.he_interested)
+#define	ARPHOOK_INTERESTED_PHYSICAL_OUT(as)	\
+	(as->as_arp_physical_out_event.he_interested)
 
-extern hook_event_t	arp_physical_in_event;
-extern hook_event_t	arp_physical_out_event;
-extern hook_event_t	arp_nic_events;
-
-#define	ARPHOOK_INTERESTED_PHYSICAL_IN	\
-	(arp_physical_in_event.he_interested)
-#define	ARPHOOK_INTERESTED_PHYSICAL_OUT	\
-	(arp_physical_out_event.he_interested)
-
-#define	ARP_HOOK_IN(_hook, _event, _ilp, _hdr, _fm, _m)	\
+#define	ARP_HOOK_IN(_hook, _event, _ilp, _hdr, _fm, _m, as)	\
 								\
 	if ((_hook).he_interested) {                       	\
 		hook_pkt_event_t info;                          \
@@ -146,7 +129,8 @@
 		info.hpe_hdr = _hdr;                            \
 		info.hpe_mp = &(_fm);                           \
 		info.hpe_mb = _m;                               \
-		if (hook_run(_event, (hook_data_t)&info) != 0) {\
+		if (hook_run(_event, (hook_data_t)&info, 	\
+		    as->as_netstack) != 0) {			\
 			if (_fm != NULL) {                      \
 				freemsg(_fm);                   \
 				_fm = NULL;                     \
@@ -159,7 +143,7 @@
 		}                                               \
 	}
 
-#define	ARP_HOOK_OUT(_hook, _event, _olp, _hdr, _fm, _m)	\
+#define	ARP_HOOK_OUT(_hook, _event, _olp, _hdr, _fm, _m, as)	\
 								\
 	if ((_hook).he_interested) {                       	\
 		hook_pkt_event_t info;                          \
@@ -169,8 +153,8 @@
 		info.hpe_hdr = _hdr;                            \
 		info.hpe_mp = &(_fm);                           \
 		info.hpe_mb = _m;                               \
-		if (hook_run(_event,                            \
-		    (hook_data_t)&info) != 0) {                 \
+		if (hook_run(_event, (hook_data_t)&info,	\
+		    as->as_netstack) != 0) {			\
 			if (_fm != NULL) {                      \
 				freemsg(_fm);                   \
 				_fm = NULL;                     \
@@ -183,10 +167,77 @@
 		}                                               \
 	}
 
-extern void	arp_hook_init();
-extern void	arp_hook_destroy();
-extern void	arp_net_init();
-extern void	arp_net_destroy();
+#define	ACE_EXTERNAL_FLAGS_MASK \
+	(ACE_F_PERMANENT | ACE_F_PUBLISH | ACE_F_MAPPING | ACE_F_MYADDR | \
+	ACE_F_AUTHORITY)
+
+/*
+ * ARP stack instances
+ */
+struct arp_stack {
+	netstack_t	*as_netstack;	/* Common netstack */
+	void		*as_head;	/* AR Instance Data List Head */
+	caddr_t		as_nd;		/* AR Named Dispatch Head */
+	struct arl_s	*as_arl_head;	/* ARL List Head */
+	arpparam_t	*as_param_arr; 	/* ndd variable table */
+
+	/* ARP Cache Entry Hash Table */
+	ace_t	*as_ce_hash_tbl[ARP_HASH_SIZE];
+	ace_t	*as_ce_mask_entries;
+
+	/*
+	 * With the introduction of netinfo (neti kernel module),
+	 * it is now possible to access data structures in the ARP module
+	 * without the code being executed in the context of the IP module,
+	 * thus there is no locking being enforced through the use of STREAMS.
+	 */
+	krwlock_t	as_arl_g_lock;
+	arl_t		*as_arl_g_head;	/* ARL List Head */
+
+	uint32_t	as_arp_index_counter;
+	uint32_t	as_arp_counter_wrapped;
+
+	/* arp_neti.c */
+	hook_family_t	as_arproot;
+
+	/*
+	 * Hooks for ARP
+	 */
+	hook_event_t	as_arp_physical_in_event;
+	hook_event_t	as_arp_physical_out_event;
+	hook_event_t	as_arp_nic_events;
+
+	hook_event_token_t	as_arp_physical_in;
+	hook_event_token_t	as_arp_physical_out;
+	hook_event_token_t	as_arpnicevents;
+
+	net_data_t	as_net_data;
+};
+typedef struct arp_stack arp_stack_t;
+
+#define	ARL_F_NOARP	0x01
+
+#define	ARL_S_DOWN	0x00
+#define	ARL_S_PENDING	0x01
+#define	ARL_S_UP	0x02
+
+/* AR Structure, one per upper stream */
+typedef struct ar_s {
+	queue_t		*ar_rq;	/* Read queue pointer */
+	queue_t		*ar_wq;	/* Write queue pointer */
+	arl_t		*ar_arl;	/* Associated arl */
+	cred_t		*ar_credp;	/* Credentials associated w/ open */
+	struct ar_s	*ar_arl_ip_assoc;	/* ARL - IP association */
+	uint32_t
+			ar_ip_acked_close : 1,	/* IP has acked the close */
+			ar_on_ill_stream : 1;	/* Module below is IP */
+	arp_stack_t	*ar_as;
+} ar_t;
+
+extern void	arp_hook_init(arp_stack_t *);
+extern void	arp_hook_destroy(arp_stack_t *);
+extern void	arp_net_init(arp_stack_t *, netstack_t *);
+extern void	arp_net_destroy(arp_stack_t *);
 
 #endif	/* _KERNEL */
 
diff --git a/usr/src/uts/common/inet/inetddi.c b/usr/src/uts/common/inet/inetddi.c
index 476de3d..e6a0395 100644
--- a/usr/src/uts/common/inet/inetddi.c
+++ b/usr/src/uts/common/inet/inetddi.c
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -98,10 +97,10 @@
 	{"icmp6", PRIVONLY_DEV,	PRIV_NET_ICMPACCESS,	PRIV_NET_ICMPACCESS},
 	{"ip", PRIVONLY_DEV,	PRIV_NET_RAWACCESS,	PRIV_NET_RAWACCESS},
 	{"ip6", PRIVONLY_DEV,	PRIV_NET_RAWACCESS,	PRIV_NET_RAWACCESS},
-	{"keysock", PRIVONLY_DEV, PRIV_SYS_NET_CONFIG,	PRIV_SYS_NET_CONFIG},
-	{"ipsecah", PRIVONLY_DEV, PRIV_SYS_NET_CONFIG,	PRIV_SYS_NET_CONFIG},
-	{"ipsecesp", PRIVONLY_DEV, PRIV_SYS_NET_CONFIG,	PRIV_SYS_NET_CONFIG},
-	{"spdsock", PRIVONLY_DEV, PRIV_SYS_NET_CONFIG,	PRIV_SYS_NET_CONFIG},
+	{"keysock", PRIVONLY_DEV, PRIV_SYS_IP_CONFIG,	PRIV_SYS_IP_CONFIG},
+	{"ipsecah", PRIVONLY_DEV, PRIV_SYS_IP_CONFIG,	PRIV_SYS_IP_CONFIG},
+	{"ipsecesp", PRIVONLY_DEV, PRIV_SYS_IP_CONFIG,	PRIV_SYS_IP_CONFIG},
+	{"spdsock", PRIVONLY_DEV, PRIV_SYS_IP_CONFIG,	PRIV_SYS_IP_CONFIG},
 	{NULL,	0,		NULL,			NULL}
 };
 
diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h
index ab4e145..993cafb 100644
--- a/usr/src/uts/common/inet/ip.h
+++ b/usr/src/uts/common/inet/ip.h
@@ -47,6 +47,7 @@
 #include <sys/hook.h>
 #include <sys/hook_event.h>
 #include <sys/hook_impl.h>
+#include <inet/ip_stack.h>
 
 #ifdef _KERNEL
 #include <netinet/ip6.h>
@@ -225,7 +226,7 @@
 #define	IP_FORWARD_NEVER	0
 #define	IP_FORWARD_ALWAYS	1
 
-#define	WE_ARE_FORWARDING	(ip_g_forward == IP_FORWARD_ALWAYS)
+#define	WE_ARE_FORWARDING(ipst)	((ipst)->ips_ip_g_forward == IP_FORWARD_ALWAYS)
 
 #define	IPH_HDR_LENGTH(ipha)						\
 	((int)(((ipha_t *)ipha)->ipha_version_and_hdr_length & 0xF) << 2)
@@ -447,9 +448,10 @@
  *  - when the nce is created  or reinit-ed
  *  - every time we get a sane arp response for the nce.
  */
-#define	NCE_EXPIRED(nce)	(nce->nce_last > 0 && \
-	((nce->nce_flags & NCE_F_PERMANENT) == 0) && \
-	((TICK_TO_MSEC(lbolt64) - nce->nce_last) > ip_ire_arp_interval))
+#define	NCE_EXPIRED(nce, ipst)	(nce->nce_last > 0 &&	\
+	    ((nce->nce_flags & NCE_F_PERMANENT) == 0) &&	\
+	    ((TICK_TO_MSEC(lbolt64) - nce->nce_last) > 		\
+		(ipst)->ips_ip_ire_arp_interval))
 
 #endif /* _KERNEL */
 
@@ -682,6 +684,18 @@
 
 #define	IRE_MARK_UNCACHED	0x0080
 
+/*
+ * The comment below (and for other netstack_t references) refers
+ * to the fact that we only do netstack_hold in particular cases,
+ * such as the references from open streams (ill_t and conn_t's
+ * pointers). Internally within IP we rely on IP's ability to cleanup e.g.
+ * ire_t's when an ill goes away.
+ */
+typedef struct ire_expire_arg_s {
+	int		iea_flush_flag;
+	ip_stack_t	*iea_ipst;	/* Does not have a netstack_hold */
+} ire_expire_arg_t;
+
 /* Flags with ire_expire routine */
 #define	FLUSH_ARP_TIME		0x0001	/* ARP info potentially stale timer */
 #define	FLUSH_REDIRECT_TIME	0x0002	/* Redirects potentially stale */
@@ -833,6 +847,12 @@
  * ilm_ipif is used by IPv4 as multicast groups are joined using ipif.
  * ilm_ill is used by IPv6 as multicast groups are joined using ill.
  * ilm_ill is NULL for IPv4 and ilm_ipif is NULL for IPv6.
+ *
+ * The comment below (and for other netstack_t references) refers
+ * to the fact that we only do netstack_hold in particular cases,
+ * such as the references from open streams (ill_t and conn_t's
+ * pointers). Internally within IP we rely on IP's ability to cleanup e.g.
+ * ire_t's when an ill goes away.
  */
 #define	ILM_DELETED	0x1		/* ilm_flags */
 typedef struct ilm_s {
@@ -853,6 +873,7 @@
 	slist_t		*ilm_filter;	/* source filter list */
 	slist_t		*ilm_pendsrcs;	/* relevant src addrs for pending req */
 	rtx_state_t	ilm_rtx;	/* SCR retransmission state */
+	ip_stack_t	*ilm_ipst;	/* Does not have a netstack_hold */
 } ilm_t;
 
 #define	ilm_addr	V4_PART_OF_V6(ilm_v6addr)
@@ -945,11 +966,11 @@
 	ASSERT((ipl)->ipl_refcnt != 0);			\
 }
 
-#define	IPLATCH_REFRELE(ipl) {					\
+#define	IPLATCH_REFRELE(ipl, ns) {				\
 	ASSERT((ipl)->ipl_refcnt != 0);				\
 	membar_exit();						\
 	if (atomic_add_32_nv(&(ipl)->ipl_refcnt, -1) == 0)	\
-		iplatch_free(ipl);				\
+		iplatch_free(ipl, ns);			\
 }
 
 /*
@@ -1107,25 +1128,25 @@
  * 2) Or if we have not cached policy on the conn and the global policy is
  *    non-empty.
  */
-#define	CONN_INBOUND_POLICY_PRESENT(connp)	\
-	((connp)->conn_in_enforce_policy ||	\
-	(!((connp)->conn_policy_cached) &&	\
-	ipsec_inbound_v4_policy_present))
+#define	CONN_INBOUND_POLICY_PRESENT(connp, ipss)	\
+	((connp)->conn_in_enforce_policy ||		\
+	(!((connp)->conn_policy_cached) && 		\
+	(ipss)->ipsec_inbound_v4_policy_present))
 
-#define	CONN_INBOUND_POLICY_PRESENT_V6(connp)	\
-	((connp)->conn_in_enforce_policy ||	\
-	(!(connp)->conn_policy_cached &&	\
-	ipsec_inbound_v6_policy_present))
+#define	CONN_INBOUND_POLICY_PRESENT_V6(connp, ipss)	\
+	((connp)->conn_in_enforce_policy ||		\
+	(!(connp)->conn_policy_cached &&		\
+	(ipss)->ipsec_inbound_v6_policy_present))
 
-#define	CONN_OUTBOUND_POLICY_PRESENT(connp)	\
-	((connp)->conn_out_enforce_policy ||	\
-	(!((connp)->conn_policy_cached) &&	\
-	ipsec_outbound_v4_policy_present))
+#define	CONN_OUTBOUND_POLICY_PRESENT(connp, ipss)	\
+	((connp)->conn_out_enforce_policy ||		\
+	(!((connp)->conn_policy_cached) &&		\
+	(ipss)->ipsec_outbound_v4_policy_present))
 
-#define	CONN_OUTBOUND_POLICY_PRESENT_V6(connp)	\
-	((connp)->conn_out_enforce_policy ||	\
-	(!(connp)->conn_policy_cached &&	\
-	ipsec_outbound_v6_policy_present))
+#define	CONN_OUTBOUND_POLICY_PRESENT_V6(connp, ipss)	\
+	((connp)->conn_out_enforce_policy ||		\
+	(!(connp)->conn_policy_cached &&		\
+	(ipss)->ipsec_outbound_v6_policy_present))
 
 /*
  * Information cached in IRE for upper layer protocol (ULP).
@@ -1451,6 +1472,7 @@
 	int		ipsq_depth;	/* debugging aid */
 	pc_t		ipsq_stack[IP_STACK_DEPTH];	/* debugging aid */
 #endif
+	ip_stack_t	*ipsq_ipst;	/* Does not have a netstack_hold */
 } ipsq_t;
 
 /* ipsq_flags */
@@ -1542,8 +1564,6 @@
 	int		illgrp_ill_count;
 } ill_group_t;
 
-extern	ill_group_t	*illgrp_head_v6;
-
 /*
  * Fragmentation hash bucket
  */
@@ -1582,6 +1602,7 @@
 	uint_t		irb_tmp_ire_cnt; /* Num of temporary IRE */
 	struct ire_s	*irb_rr_origin;	/* origin for round-robin */
 	int		irb_nire;	/* Num of ftable ire's that ref irb */
+	ip_stack_t	*irb_ipst;	/* Does not have a netstack_hold */
 } irb_t;
 
 #define	IRB2RT(irb)	(rt_t *)((caddr_t)(irb) - offsetof(rt_t, rt_irb))
@@ -1619,7 +1640,6 @@
 	char 	illif_filler[CACHE_ALIGN(_ill_if_s_)];
 } ill_if_t;
 
-
 #define	illif_next		ill_if_s.illif_next
 #define	illif_prev		ill_if_s.illif_prev
 #define	illif_avl_by_ppa	ill_if_s.illif_avl_by_ppa
@@ -1635,7 +1655,7 @@
 } ill_walk_context_t;
 
 /*
- * ill_gheads structure, one for IPV4 and one for IPV6
+ * ill_g_heads structure, one for IPV4 and one for IPV6
  */
 struct _ill_g_head_s_ {
 	ill_if_t	*ill_g_list_head;
@@ -1650,20 +1670,19 @@
 #define	ill_g_list_head	ill_g_head_s.ill_g_list_head
 #define	ill_g_list_tail	ill_g_head_s.ill_g_list_tail
 
-#pragma align CACHE_ALIGN_SIZE(ill_g_heads)
-extern ill_g_head_t	ill_g_heads[];	/* ILL List Head */
+#define	IP_V4_ILL_G_LIST(ipst)	\
+	(ipst)->ips_ill_g_heads[IP_V4_G_HEAD].ill_g_list_head
+#define	IP_V6_ILL_G_LIST(ipst)	\
+	(ipst)->ips_ill_g_heads[IP_V6_G_HEAD].ill_g_list_head
+#define	IP_VX_ILL_G_LIST(i, ipst)	\
+	(ipst)->ips_ill_g_heads[i].ill_g_list_head
 
-
-#define	IP_V4_ILL_G_LIST	ill_g_heads[IP_V4_G_HEAD].ill_g_list_head
-#define	IP_V6_ILL_G_LIST	ill_g_heads[IP_V6_G_HEAD].ill_g_list_head
-#define	IP_VX_ILL_G_LIST(i)	ill_g_heads[i].ill_g_list_head
-
-#define	ILL_START_WALK_V4(ctx_ptr)	ill_first(IP_V4_G_HEAD, IP_V4_G_HEAD, \
-					ctx_ptr)
-#define	ILL_START_WALK_V6(ctx_ptr)	ill_first(IP_V6_G_HEAD, IP_V6_G_HEAD, \
-					ctx_ptr)
-#define	ILL_START_WALK_ALL(ctx_ptr)	ill_first(MAX_G_HEADS, MAX_G_HEADS, \
-					ctx_ptr)
+#define	ILL_START_WALK_V4(ctx_ptr, ipst)	\
+	ill_first(IP_V4_G_HEAD, IP_V4_G_HEAD, ctx_ptr, ipst)
+#define	ILL_START_WALK_V6(ctx_ptr, ipst)	\
+	ill_first(IP_V6_G_HEAD, IP_V6_G_HEAD, ctx_ptr, ipst)
+#define	ILL_START_WALK_ALL(ctx_ptr, ipst)	\
+	ill_first(MAX_G_HEADS, MAX_G_HEADS, ctx_ptr, ipst)
 
 /*
  * Capabilities, possible flags for ill_capabilities.
@@ -1973,6 +1992,8 @@
 	th_trace_t	*ill_trace[IP_TR_HASH_MAX];
 	boolean_t	ill_trace_disable;	/* True when alloc fails */
 #endif
+	zoneid_t	ill_zoneid;
+	ip_stack_t	*ill_ipst;	/* Corresponds to a netstack_hold */
 } ill_t;
 
 extern	void	ill_delete_glist(ill_t *);
@@ -2376,7 +2397,7 @@
 	if (atomic_add_32_nv(&(ire)->ire_refcnt, -1) == 0)	\
 		ire_inactive(ire);				\
 }
-#define	IRE_REFRELE_NOTR(ire) {					\
+#define	IRE_REFRELE_NOTR(ire) {				\
 	ASSERT((ire)->ire_refcnt != 0);				\
 	membar_exit();						\
 	if (atomic_add_32_nv(&(ire)->ire_refcnt, -1) == 0)	\
@@ -2530,6 +2551,7 @@
 	uint_t	ire_stq_ifindex;
 	uint_t		ire_defense_count;	/* number of ARP conflicts */
 	uint_t		ire_defense_time;	/* last time defended (secs) */
+	ip_stack_t	*ire_ipst;	/* Does not have a netstack_hold */
 #ifdef IRE_DEBUG
 	th_trace_t	*ire_trace[IP_TR_HASH_MAX];
 	boolean_t	ire_trace_disable;	/* True when alloc fails */
@@ -2612,8 +2634,8 @@
  */
 #define	COMMON_IP_MTU 1500
 #define	MAX_FRAG_MIN 10
-#define	MAX_FRAG_PKTS	\
-	MAX(MAX_FRAG_MIN, (2 * (ip_reass_queue_bytes / \
+#define	MAX_FRAG_PKTS(ipst)	\
+	MAX(MAX_FRAG_MIN, (2 * (ipst->ips_ip_reass_queue_bytes / \
 	    (COMMON_IP_MTU * ILL_FRAG_HASH_TBL_COUNT))))
 
 /*
@@ -2842,104 +2864,96 @@
 	struct lifreq *ci_lifr;	/* the lifreq struct passed down */
 } cmd_info_t;
 
-extern krwlock_t ill_g_lock;
-extern kmutex_t ip_addr_avail_lock;
-extern ipsq_t	*ipsq_g_head;
-
-extern ill_t	*ip_timer_ill;		/* ILL for IRE expiration timer. */
-extern timeout_id_t ip_ire_expire_id;	/* IRE expiration timeout id. */
-extern timeout_id_t ip_ire_reclaim_id;	/* IRE recalaim timeout id. */
-
-extern kmutex_t	ip_mi_lock;
-extern krwlock_t ip_g_nd_lock;		/* For adding/removing nd variables */
-extern kmutex_t ip_trash_timer_lock;	/* Protects ip_ire_expire_id */
-
-extern kmutex_t igmp_timer_lock;	/* Protects the igmp timer */
-extern kmutex_t mld_timer_lock;		/* Protects the mld timer */
-
-extern krwlock_t ill_g_usesrc_lock;	/* Protects usesrc related fields */
+/*
+ * List of AH and ESP IPsec acceleration capable ills
+ */
+typedef struct ipsec_capab_ill_s {
+	uint_t ill_index;
+	boolean_t ill_isv6;
+	struct ipsec_capab_ill_s *next;
+} ipsec_capab_ill_t;
 
 extern struct kmem_cache *ire_cache;
 
-extern uint_t	ip_redirect_cnt;	/* Num of redirect routes in ftable */
-
 extern ipaddr_t	ip_g_all_ones;
-extern caddr_t	ip_g_nd;		/* Named Dispatch List Head */
 
-extern uint_t	ip_loopback_mtu;
+extern	uint_t	ip_loopback_mtu;	/* /etc/system */
 
-extern ipparam_t	*ip_param_arr;
-
-extern int ip_g_forward;
-extern int ipv6_forward;
 extern vmem_t *ip_minor_arena;
 
-#define	ip_respond_to_address_mask_broadcast ip_param_arr[0].ip_param_value
-#define	ip_g_resp_to_echo_bcast		ip_param_arr[1].ip_param_value
-#define	ip_g_resp_to_echo_mcast		ip_param_arr[2].ip_param_value
-#define	ip_g_resp_to_timestamp		ip_param_arr[3].ip_param_value
-#define	ip_g_resp_to_timestamp_bcast	ip_param_arr[4].ip_param_value
-#define	ip_g_send_redirects		ip_param_arr[5].ip_param_value
-#define	ip_g_forward_directed_bcast	ip_param_arr[6].ip_param_value
-#define	ip_debug			ip_param_arr[7].ip_param_value
-#define	ip_mrtdebug			ip_param_arr[8].ip_param_value
-#define	ip_timer_interval		ip_param_arr[9].ip_param_value
-#define	ip_ire_arp_interval		ip_param_arr[10].ip_param_value
-#define	ip_ire_redir_interval		ip_param_arr[11].ip_param_value
-#define	ip_def_ttl			ip_param_arr[12].ip_param_value
-#define	ip_forward_src_routed		ip_param_arr[13].ip_param_value
-#define	ip_wroff_extra			ip_param_arr[14].ip_param_value
-#define	ip_ire_pathmtu_interval		ip_param_arr[15].ip_param_value
-#define	ip_icmp_return			ip_param_arr[16].ip_param_value
-#define	ip_path_mtu_discovery		ip_param_arr[17].ip_param_value
-#define	ip_ignore_delete_time		ip_param_arr[18].ip_param_value
-#define	ip_ignore_redirect		ip_param_arr[19].ip_param_value
-#define	ip_output_queue			ip_param_arr[20].ip_param_value
-#define	ip_broadcast_ttl		ip_param_arr[21].ip_param_value
-#define	ip_icmp_err_interval		ip_param_arr[22].ip_param_value
-#define	ip_icmp_err_burst		ip_param_arr[23].ip_param_value
-#define	ip_reass_queue_bytes		ip_param_arr[24].ip_param_value
-#define	ip_strict_dst_multihoming	ip_param_arr[25].ip_param_value
-#define	ip_addrs_per_if			ip_param_arr[26].ip_param_value
-#define	ipsec_override_persocket_policy	ip_param_arr[27].ip_param_value
-#define	icmp_accept_clear_messages	ip_param_arr[28].ip_param_value
-#define	igmp_accept_clear_messages	ip_param_arr[29].ip_param_value
+/*
+ * ip_g_forward controls IP forwarding.  It takes two values:
+ *	0: IP_FORWARD_NEVER	Don't forward packets ever.
+ *	1: IP_FORWARD_ALWAYS	Forward packets for elsewhere.
+ *
+ * RFC1122 says there must be a configuration switch to control forwarding,
+ * but that the default MUST be to not forward packets ever.  Implicit
+ * control based on configuration of multiple interfaces MUST NOT be
+ * implemented (Section 3.1).  SunOS 4.1 did provide the "automatic" capability
+ * and, in fact, it was the default.  That capability is now provided in the
+ * /etc/rc2.d/S69inet script.
+ */
+
+#define	ips_ip_respond_to_address_mask_broadcast ips_param_arr[0].ip_param_value
+#define	ips_ip_g_resp_to_echo_bcast	ips_param_arr[1].ip_param_value
+#define	ips_ip_g_resp_to_echo_mcast	ips_param_arr[2].ip_param_value
+#define	ips_ip_g_resp_to_timestamp	ips_param_arr[3].ip_param_value
+#define	ips_ip_g_resp_to_timestamp_bcast ips_param_arr[4].ip_param_value
+#define	ips_ip_g_send_redirects		ips_param_arr[5].ip_param_value
+#define	ips_ip_g_forward_directed_bcast	ips_param_arr[6].ip_param_value
+#define	ips_ip_debug			ips_param_arr[7].ip_param_value
+#define	ips_ip_mrtdebug			ips_param_arr[8].ip_param_value
+#define	ips_ip_timer_interval		ips_param_arr[9].ip_param_value
+#define	ips_ip_ire_arp_interval		ips_param_arr[10].ip_param_value
+#define	ips_ip_ire_redir_interval	ips_param_arr[11].ip_param_value
+#define	ips_ip_def_ttl			ips_param_arr[12].ip_param_value
+#define	ips_ip_forward_src_routed	ips_param_arr[13].ip_param_value
+#define	ips_ip_wroff_extra		ips_param_arr[14].ip_param_value
+#define	ips_ip_ire_pathmtu_interval	ips_param_arr[15].ip_param_value
+#define	ips_ip_icmp_return		ips_param_arr[16].ip_param_value
+#define	ips_ip_path_mtu_discovery	ips_param_arr[17].ip_param_value
+#define	ips_ip_ignore_delete_time	ips_param_arr[18].ip_param_value
+#define	ips_ip_ignore_redirect		ips_param_arr[19].ip_param_value
+#define	ips_ip_output_queue		ips_param_arr[20].ip_param_value
+#define	ips_ip_broadcast_ttl		ips_param_arr[21].ip_param_value
+#define	ips_ip_icmp_err_interval	ips_param_arr[22].ip_param_value
+#define	ips_ip_icmp_err_burst		ips_param_arr[23].ip_param_value
+#define	ips_ip_reass_queue_bytes	ips_param_arr[24].ip_param_value
+#define	ips_ip_strict_dst_multihoming	ips_param_arr[25].ip_param_value
+#define	ips_ip_addrs_per_if		ips_param_arr[26].ip_param_value
+#define	ips_ipsec_override_persocket_policy ips_param_arr[27].ip_param_value
+#define	ips_icmp_accept_clear_messages	ips_param_arr[28].ip_param_value
+#define	ips_igmp_accept_clear_messages	ips_param_arr[29].ip_param_value
 
 /* IPv6 configuration knobs */
-#define	delay_first_probe_time		ip_param_arr[30].ip_param_value
-#define	max_unicast_solicit		ip_param_arr[31].ip_param_value
-#define	ipv6_def_hops			ip_param_arr[32].ip_param_value
-#define	ipv6_icmp_return		ip_param_arr[33].ip_param_value
-#define	ipv6_forward_src_routed		ip_param_arr[34].ip_param_value
-#define	ipv6_resp_echo_mcast		ip_param_arr[35].ip_param_value
-#define	ipv6_send_redirects		ip_param_arr[36].ip_param_value
-#define	ipv6_ignore_redirect		ip_param_arr[37].ip_param_value
-#define	ipv6_strict_dst_multihoming	ip_param_arr[38].ip_param_value
-#define	ip_ire_reclaim_fraction		ip_param_arr[39].ip_param_value
-#define	ipsec_policy_log_interval	ip_param_arr[40].ip_param_value
-#define	pim_accept_clear_messages	ip_param_arr[41].ip_param_value
-#define	ip_ndp_unsolicit_interval	ip_param_arr[42].ip_param_value
-#define	ip_ndp_unsolicit_count		ip_param_arr[43].ip_param_value
-#define	ipv6_ignore_home_address_opt	ip_param_arr[44].ip_param_value
-#define	ip_policy_mask			ip_param_arr[45].ip_param_value
-#define	ip_multirt_resolution_interval	ip_param_arr[46].ip_param_value
-#define	ip_multirt_ttl			ip_param_arr[47].ip_param_value
-#define	ip_multidata_outbound		ip_param_arr[48].ip_param_value
-#define	ip_ndp_defense_interval		ip_param_arr[49].ip_param_value
-#define	ip_max_temp_idle		ip_param_arr[50].ip_param_value
-#define	ip_max_temp_defend		ip_param_arr[51].ip_param_value
-#define	ip_max_defend			ip_param_arr[52].ip_param_value
-#define	ip_defend_interval		ip_param_arr[53].ip_param_value
-#define	ip_dup_recovery			ip_param_arr[54].ip_param_value
-#define	ip_restrict_interzone_loopback	ip_param_arr[55].ip_param_value
-#define	ip_lso_outbound			ip_param_arr[56].ip_param_value
-#ifdef DEBUG
-#define	ipv6_drop_inbound_icmpv6	ip_param_arr[57].ip_param_value
-#else
-#define	ipv6_drop_inbound_icmpv6	0
-#endif
-
-extern hrtime_t	ipsec_policy_failure_last;
+#define	ips_delay_first_probe_time	ips_param_arr[30].ip_param_value
+#define	ips_max_unicast_solicit		ips_param_arr[31].ip_param_value
+#define	ips_ipv6_def_hops		ips_param_arr[32].ip_param_value
+#define	ips_ipv6_icmp_return		ips_param_arr[33].ip_param_value
+#define	ips_ipv6_forward_src_routed	ips_param_arr[34].ip_param_value
+#define	ips_ipv6_resp_echo_mcast	ips_param_arr[35].ip_param_value
+#define	ips_ipv6_send_redirects		ips_param_arr[36].ip_param_value
+#define	ips_ipv6_ignore_redirect	ips_param_arr[37].ip_param_value
+#define	ips_ipv6_strict_dst_multihoming	ips_param_arr[38].ip_param_value
+#define	ips_ip_ire_reclaim_fraction	ips_param_arr[39].ip_param_value
+#define	ips_ipsec_policy_log_interval	ips_param_arr[40].ip_param_value
+#define	ips_pim_accept_clear_messages	ips_param_arr[41].ip_param_value
+#define	ips_ip_ndp_unsolicit_interval	ips_param_arr[42].ip_param_value
+#define	ips_ip_ndp_unsolicit_count	ips_param_arr[43].ip_param_value
+#define	ips_ipv6_ignore_home_address_opt ips_param_arr[44].ip_param_value
+#define	ips_ip_policy_mask		ips_param_arr[45].ip_param_value
+#define	ips_ip_multirt_resolution_interval ips_param_arr[46].ip_param_value
+#define	ips_ip_multirt_ttl  		ips_param_arr[47].ip_param_value
+#define	ips_ip_multidata_outbound	ips_param_arr[48].ip_param_value
+#define	ips_ip_ndp_defense_interval	ips_param_arr[49].ip_param_value
+#define	ips_ip_max_temp_idle		ips_param_arr[50].ip_param_value
+#define	ips_ip_max_temp_defend		ips_param_arr[51].ip_param_value
+#define	ips_ip_max_defend		ips_param_arr[52].ip_param_value
+#define	ips_ip_defend_interval		ips_param_arr[53].ip_param_value
+#define	ips_ip_dup_recovery		ips_param_arr[54].ip_param_value
+#define	ips_ip_restrict_interzone_loopback ips_param_arr[55].ip_param_value
+#define	ips_ip_lso_outbound		ips_param_arr[56].ip_param_value
+#define	ips_ipv6_drop_inbound_icmpv6	ips_param_arr[57].ip_param_value
 
 extern int	dohwcksum;	/* use h/w cksum if supported by the h/w */
 #ifdef ZC_TEST
@@ -2950,76 +2964,35 @@
 
 extern nv_t	*ire_nv_tbl;
 
-extern time_t	ip_g_frag_timeout;
-extern clock_t	ip_g_frag_timo_ms;
-
-extern mib2_ipIfStatsEntry_t	ip_mib;	/* For tcpInErrs and udpNoPorts */
-
 extern struct module_info ip_mod_info;
 
-extern timeout_id_t	igmp_slowtimeout_id;
-extern timeout_id_t	mld_slowtimeout_id;
-
-extern uint_t	loopback_packets;
-
-/*
- * Hooks structures used inside of ip
- */
-extern hook_event_token_t	ipv4firewall_physical_in;
-extern hook_event_token_t	ipv4firewall_physical_out;
-extern hook_event_token_t	ipv4firewall_forwarding;
-extern hook_event_token_t	ipv4firewall_loopback_in;
-extern hook_event_token_t	ipv4firewall_loopback_out;
-extern hook_event_token_t	ipv4nicevents;
-
-extern hook_event_token_t	ipv6firewall_physical_in;
-extern hook_event_token_t	ipv6firewall_physical_out;
-extern hook_event_token_t	ipv6firewall_forwarding;
-extern hook_event_token_t	ipv6firewall_loopback_in;
-extern hook_event_token_t	ipv6firewall_loopback_out;
-extern hook_event_token_t	ipv6nicevents;
-
-extern hook_event_t	ip4_physical_in_event;
-extern hook_event_t	ip4_physical_out_event;
-extern hook_event_t	ip4_forwarding_event;
-extern hook_event_t	ip4_loopback_in_event;
-extern hook_event_t	ip4_loopback_out_event;
-extern hook_event_t	ip4_nic_events;
-
-extern hook_event_t	ip6_physical_in_event;
-extern hook_event_t	ip6_physical_out_event;
-extern hook_event_t	ip6_forwarding_event;
-extern hook_event_t	ip6_loopback_in_event;
-extern hook_event_t	ip6_loopback_out_event;
-extern hook_event_t	ip6_nic_events;
-
-#define	HOOKS4_INTERESTED_PHYSICAL_IN	\
-	(ip4_physical_in_event.he_interested)
-#define	HOOKS6_INTERESTED_PHYSICAL_IN	\
-	(ip6_physical_in_event.he_interested)
-#define	HOOKS4_INTERESTED_PHYSICAL_OUT	\
-	(ip4_physical_out_event.he_interested)
-#define	HOOKS6_INTERESTED_PHYSICAL_OUT	\
-	(ip6_physical_out_event.he_interested)
-#define	HOOKS4_INTERESTED_FORWARDING	\
-	(ip4_forwarding_event.he_interested)
-#define	HOOKS6_INTERESTED_FORWARDING	\
-	(ip6_forwarding_event.he_interested)
-#define	HOOKS4_INTERESTED_LOOPBACK_IN	\
-	(ip4_loopback_in_event.he_interested)
-#define	HOOKS6_INTERESTED_LOOPBACK_IN	\
-	(ip6_loopback_in_event.he_interested)
-#define	HOOKS4_INTERESTED_LOOPBACK_OUT	\
-	(ip4_loopback_out_event.he_interested)
-#define	HOOKS6_INTERESTED_LOOPBACK_OUT	\
-	(ip6_loopback_out_event.he_interested)
+#define	HOOKS4_INTERESTED_PHYSICAL_IN(ipst)	\
+	((ipst)->ips_ip4_physical_in_event.he_interested)
+#define	HOOKS6_INTERESTED_PHYSICAL_IN(ipst)	\
+	((ipst)->ips_ip6_physical_in_event.he_interested)
+#define	HOOKS4_INTERESTED_PHYSICAL_OUT(ipst)	\
+	((ipst)->ips_ip4_physical_out_event.he_interested)
+#define	HOOKS6_INTERESTED_PHYSICAL_OUT(ipst)	\
+	((ipst)->ips_ip6_physical_out_event.he_interested)
+#define	HOOKS4_INTERESTED_FORWARDING(ipst)	\
+	((ipst)->ips_ip4_forwarding_event.he_interested)
+#define	HOOKS6_INTERESTED_FORWARDING(ipst)	\
+	((ipst)->ips_ip6_forwarding_event.he_interested)
+#define	HOOKS4_INTERESTED_LOOPBACK_IN(ipst)	\
+	((ipst)->ips_ip4_loopback_in_event.he_interested)
+#define	HOOKS6_INTERESTED_LOOPBACK_IN(ipst)	\
+	((ipst)->ips_ip6_loopback_in_event.he_interested)
+#define	HOOKS4_INTERESTED_LOOPBACK_OUT(ipst)	\
+	((ipst)->ips_ip4_loopback_out_event.he_interested)
+#define	HOOKS6_INTERESTED_LOOPBACK_OUT(ipst)	\
+	((ipst)->ips_ip6_loopback_out_event.he_interested)
 
 /*
  * Hooks marcos used inside of ip
  */
 #define	IPHA_VHL	ipha_version_and_hdr_length
 
-#define	FW_HOOKS(_hook, _event, _ilp, _olp, _iph, _fm, _m)	\
+#define	FW_HOOKS(_hook, _event, _ilp, _olp, _iph, _fm, _m, ipst)	\
 									\
 	if ((_hook).he_interested) {	\
 		hook_pkt_event_t info;					\
@@ -3045,7 +3018,8 @@
 		info.hpe_hdr = _iph;					\
 		info.hpe_mp = &(_fm);					\
 		info.hpe_mb = _m;					\
-		if (hook_run(_event, (hook_data_t)&info) != 0) {	\
+		if (hook_run(_event, (hook_data_t)&info,		\
+		    ipst->ips_netstack) != 0) {				\
 			ip2dbg(("%s hook dropped mblk chain %p hdr %p\n",\
 			    (_hook).he_name, (void *)_fm, (void *)_m));	\
 			if (_fm != NULL) {				\
@@ -3060,7 +3034,7 @@
 		}							\
 	}
 
-#define	FW_HOOKS6(_hook, _event, _ilp, _olp, _iph, _fm, _m)	\
+#define	FW_HOOKS6(_hook, _event, _ilp, _olp, _iph, _fm, _m, ipst)	\
 									\
 	if ((_hook).he_interested) {	\
 		hook_pkt_event_t info;					\
@@ -3086,7 +3060,8 @@
 		info.hpe_hdr = _iph;					\
 		info.hpe_mp = &(_fm);					\
 		info.hpe_mb = _m;					\
-		if (hook_run(_event, (hook_data_t)&info) != 0) {	\
+		if (hook_run(_event, (hook_data_t)&info,		\
+		    ipst->ips_netstack) != 0) {				\
 			ip2dbg(("%s hook dropped mblk chain %p hdr %p\n",\
 			    (_hook).he_name, (void *)_fm, (void *)_m));	\
 			if (_fm != NULL) {				\
@@ -3134,6 +3109,8 @@
 #define	IPSECHW_CALL(f, r, x)	{}
 #endif
 
+extern int	ip_debug;
+
 #ifdef IP_DEBUG
 #include <sys/debug.h>
 #include <sys/promif.h>
@@ -3159,7 +3136,7 @@
 extern const char *dlpi_prim_str(int);
 extern const char *dlpi_err_str(int);
 extern void	ill_frag_timer(void *);
-extern ill_t	*ill_first(int, int, ill_walk_context_t *);
+extern ill_t	*ill_first(int, int, ill_walk_context_t *, ip_stack_t *);
 extern ill_t	*ill_next(ill_walk_context_t *, ill_t *);
 extern void	ill_frag_timer_start(ill_t *);
 extern mblk_t	*ip_carve_mp(mblk_t **, ssize_t);
@@ -3167,10 +3144,12 @@
 extern char	*ip_dot_addr(ipaddr_t, char *);
 extern const char *mac_colon_addr(const uint8_t *, size_t, char *, size_t);
 extern void	ip_lwput(queue_t *, mblk_t *);
-extern boolean_t icmp_err_rate_limit(void);
-extern void	icmp_time_exceeded(queue_t *, mblk_t *, uint8_t, zoneid_t);
-extern void	icmp_unreachable(queue_t *, mblk_t *, uint8_t, zoneid_t);
-extern mblk_t	*ip_add_info(mblk_t *, ill_t *, uint_t, zoneid_t);
+extern boolean_t icmp_err_rate_limit(ip_stack_t *);
+extern void	icmp_time_exceeded(queue_t *, mblk_t *, uint8_t, zoneid_t,
+    ip_stack_t *);
+extern void	icmp_unreachable(queue_t *, mblk_t *, uint8_t, zoneid_t,
+    ip_stack_t *);
+extern mblk_t	*ip_add_info(mblk_t *, ill_t *, uint_t, zoneid_t, ip_stack_t *);
 extern mblk_t	*ip_bind_v4(queue_t *, mblk_t *, conn_t *);
 extern int	ip_bind_connected(conn_t *, mblk_t *, ipaddr_t *, uint16_t,
     ipaddr_t, uint16_t, boolean_t, boolean_t, boolean_t,
@@ -3181,9 +3160,12 @@
 extern uint_t	ip_cksum(mblk_t *, int, uint32_t);
 extern int	ip_close(queue_t *, int);
 extern uint16_t	ip_csum_hdr(ipha_t *);
-extern void	ip_proto_not_sup(queue_t *, mblk_t *, uint_t, zoneid_t);
-extern void	ip_ire_fini(void);
-extern void	ip_ire_init(void);
+extern void	ip_proto_not_sup(queue_t *, mblk_t *, uint_t, zoneid_t,
+    ip_stack_t *);
+extern void	ip_ire_g_fini(void);
+extern void	ip_ire_g_init(void);
+extern void	ip_ire_fini(ip_stack_t *);
+extern void	ip_ire_init(ip_stack_t *);
 extern int	ip_open(queue_t *, dev_t *, int, int, cred_t *);
 extern int	ip_reassemble(mblk_t *, ipf_t *, uint_t, boolean_t, ill_t *,
     size_t);
@@ -3205,7 +3187,7 @@
 extern void	ip_udp_input(queue_t *, mblk_t *, ipha_t *, ire_t *, ill_t *);
 extern void	ip_proto_input(queue_t *, mblk_t *, ipha_t *, ire_t *, ill_t *);
 extern void	ip_rput_other(ipsq_t *, queue_t *, mblk_t *, void *);
-extern void	ip_setqinfo(queue_t *, minor_t, boolean_t);
+extern void	ip_setqinfo(queue_t *, minor_t, boolean_t, ip_stack_t *);
 extern void	ip_trash_ire_reclaim(void *);
 extern void	ip_trash_timer_expire(void *);
 extern void	ip_wput(queue_t *, mblk_t *);
@@ -3224,13 +3206,13 @@
 extern char	*ip_nv_lookup(nv_t *, int);
 extern boolean_t ip_local_addr_ok_v6(const in6_addr_t *, const in6_addr_t *);
 extern boolean_t ip_remote_addr_ok_v6(const in6_addr_t *, const in6_addr_t *);
-extern ipaddr_t ip_massage_options(ipha_t *);
+extern ipaddr_t ip_massage_options(ipha_t *, netstack_t *);
 extern ipaddr_t ip_net_mask(ipaddr_t);
 extern void	ip_newroute(queue_t *, mblk_t *, ipaddr_t, ill_t *, conn_t *,
-		    zoneid_t);
+		    zoneid_t, ip_stack_t *);
 extern ipxmit_state_t	ip_xmit_v4(mblk_t *, ire_t *, struct ipsec_out_s *,
     boolean_t);
-extern int	ip_hdr_complete(ipha_t *, zoneid_t);
+extern int	ip_hdr_complete(ipha_t *, zoneid_t, ip_stack_t *);
 
 extern struct qinit rinit_ipv6;
 extern struct qinit winit_ipv6;
@@ -3240,9 +3222,6 @@
 extern struct qinit rinit_acceptor_tcp;
 extern struct qinit winit_acceptor_tcp;
 
-extern net_data_t ipv4;
-extern net_data_t ipv6;
-
 extern void	conn_drain_insert(conn_t *connp);
 extern	int	conn_ipsec_length(conn_t *connp);
 extern void	ip_wput_ipsec_out(queue_t *, mblk_t *, ipha_t *, ill_t *,
@@ -3250,7 +3229,7 @@
 extern ipaddr_t	ip_get_dst(ipha_t *);
 extern int	ipsec_out_extra_length(mblk_t *);
 extern int	ipsec_in_extra_length(mblk_t *);
-extern mblk_t	*ipsec_in_alloc();
+extern mblk_t	*ipsec_in_alloc(boolean_t, netstack_t *);
 extern boolean_t ipsec_in_is_secure(mblk_t *);
 extern void	ipsec_out_process(queue_t *, mblk_t *, ire_t *, uint_t);
 extern void	ipsec_out_to_in(mblk_t *);
@@ -3271,16 +3250,17 @@
 extern	void	ipif_trace_cleanup(ipif_t *);
 #endif
 
-extern int	ip_srcid_insert(const in6_addr_t *, zoneid_t);
-extern int	ip_srcid_remove(const in6_addr_t *, zoneid_t);
-extern void	ip_srcid_find_id(uint_t, in6_addr_t *, zoneid_t);
-extern uint_t	ip_srcid_find_addr(const in6_addr_t *, zoneid_t);
+extern int	ip_srcid_insert(const in6_addr_t *, zoneid_t, ip_stack_t *);
+extern int	ip_srcid_remove(const in6_addr_t *, zoneid_t, ip_stack_t *);
+extern void	ip_srcid_find_id(uint_t, in6_addr_t *, zoneid_t, netstack_t *);
+extern uint_t	ip_srcid_find_addr(const in6_addr_t *, zoneid_t, netstack_t *);
 extern int	ip_srcid_report(queue_t *, mblk_t *, caddr_t, cred_t *);
 
 extern uint8_t	ipoptp_next(ipoptp_t *);
 extern uint8_t	ipoptp_first(ipoptp_t *, ipha_t *);
 extern int	ip_opt_get_user(const ipha_t *, uchar_t *);
-extern ill_t	*ip_grab_attach_ill(ill_t *, mblk_t *, int, boolean_t);
+extern ill_t	*ip_grab_attach_ill(ill_t *, mblk_t *, int, boolean_t,
+    ip_stack_t *);
 extern ire_t	*conn_set_outgoing_ill(conn_t *, ire_t *, ill_t **);
 extern int	ipsec_req_from_conn(conn_t *, ipsec_req_t *, int);
 extern int	ip_snmp_get(queue_t *q, mblk_t *mctl);
@@ -3347,6 +3327,12 @@
 
 #define	CGTP_MCAST_SUCCESS	1
 
+/*
+ * The separate CGTP module needs these as globals. It uses the first
+ * to unregister (since there is no ip_cgtp_filter_unregister() function)
+ * and it uses the second one to verify that the filter has been
+ * turned off (a ip_cgtp_filter_active() function would be good for that.)
+ */
 extern cgtp_filter_ops_t *ip_cgtp_filter_ops;
 extern boolean_t ip_cgtp_filter;
 
@@ -3520,7 +3506,7 @@
 extern void tcp_wput(queue_t *, mblk_t *);
 
 extern int	ip_fill_mtuinfo(struct in6_addr *, in_port_t,
-	struct ip6_mtuinfo *);
+	struct ip6_mtuinfo *, netstack_t *);
 extern	ipif_t *conn_get_held_ipif(conn_t *, ipif_t **, int *);
 
 typedef void    (*ipsq_func_t)(ipsq_t *, queue_t *, mblk_t *, void *);
diff --git a/usr/src/uts/common/inet/ip/icmp.c b/usr/src/uts/common/inet/ip/icmp.c
index 475d753..e743959 100644
--- a/usr/src/uts/common/inet/ip/icmp.c
+++ b/usr/src/uts/common/inet/ip/icmp.c
@@ -50,6 +50,7 @@
 #include <sys/isa_defs.h>
 #include <sys/suntpi.h>
 #include <sys/xti_inet.h>
+#include <sys/netstack.h>
 
 #include <net/route.h>
 #include <net/if.h>
@@ -102,14 +103,6 @@
  * exited the shared resource.
  */
 
-/* Named Dispatch Parameter Management Structure */
-typedef struct icmpparam_s {
-	uint_t	icmp_param_min;
-	uint_t	icmp_param_max;
-	uint_t	icmp_param_value;
-	char	*icmp_param_name;
-} icmpparam_t;
-
 static void	icmp_addr_req(queue_t *q, mblk_t *mp);
 static void	icmp_bind(queue_t *q, mblk_t *mp);
 static void	icmp_bind_proto(queue_t *q);
@@ -139,7 +132,7 @@
 int		icmp_opt_get(queue_t *q, int level, int name,
 		    uchar_t *ptr);
 static int	icmp_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr);
-static boolean_t icmp_param_register(icmpparam_t *icmppa, int cnt);
+static boolean_t icmp_param_register(IDP *ndp, icmpparam_t *icmppa, int cnt);
 static int	icmp_param_set(queue_t *q, mblk_t *mp, char *value,
 		    caddr_t cp, cred_t *cr);
 static void	icmp_rput(queue_t *q, mblk_t *mp);
@@ -158,8 +151,11 @@
 static void	icmp_wput_iocdata(queue_t *q, mblk_t *mp);
 static void	icmp_wput_restricted(queue_t *q, mblk_t *mp);
 
-static void	rawip_kstat_init(void);
-static void	rawip_kstat_fini(void);
+static void	*rawip_stack_init(netstackid_t stackid, netstack_t *ns);
+static void	rawip_stack_fini(netstackid_t stackid, void *arg);
+
+static void	*rawip_kstat_init(netstackid_t stackid);
+static void	rawip_kstat_fini(netstackid_t stackid, kstat_t *ksp);
 static int	rawip_kstat_update(kstat_t *kp, int rw);
 
 
@@ -181,12 +177,6 @@
 
 static sin_t	sin_null;	/* Zero address for quick clears */
 static sin6_t	sin6_null;	/* Zero address for quick clears */
-static void	*icmp_g_head;	/* Head for list of open icmp streams. */
-static IDP	icmp_g_nd;	/* Points to table of ICMP ND variables. */
-
-/* MIB-2 stuff for SNMP */
-static mib2_rawip_t	rawip_mib;	/* SNMP fixed size info */
-static kstat_t		*rawip_mibkp;	/* kstat exporting rawip_mib data */
 
 /* Default structure copied into T_INFO_ACK messages */
 static struct T_info_ack icmp_g_t_info_ack = {
@@ -204,8 +194,8 @@
 };
 
 /*
- * Table of ND variables supported by icmp.  These are loaded into icmp_g_nd
- * in icmp_open.
+ * Table of ND variables supported by icmp.  These are loaded into is_nd
+ * when the stack instance is created.
  * All of these are alterable, within the min/max values given, at run time.
  */
 static icmpparam_t	icmp_param_arr[] = {
@@ -219,14 +209,14 @@
 	{ 4096,	65536,	8192,	"icmp_recv_hiwat"},
 	{ 65536, 1024*1024*1024, 256*1024,	"icmp_max_buf"},
 };
-#define	icmp_wroff_extra		icmp_param_arr[0].icmp_param_value
-#define	icmp_ipv4_ttl			icmp_param_arr[1].icmp_param_value
-#define	icmp_ipv6_hoplimit		icmp_param_arr[2].icmp_param_value
-#define	icmp_bsd_compat			icmp_param_arr[3].icmp_param_value
-#define	icmp_xmit_hiwat			icmp_param_arr[4].icmp_param_value
-#define	icmp_xmit_lowat			icmp_param_arr[5].icmp_param_value
-#define	icmp_recv_hiwat			icmp_param_arr[6].icmp_param_value
-#define	icmp_max_buf			icmp_param_arr[7].icmp_param_value
+#define	is_wroff_extra			is_param_arr[0].icmp_param_value
+#define	is_ipv4_ttl			is_param_arr[1].icmp_param_value
+#define	is_ipv6_hoplimit		is_param_arr[2].icmp_param_value
+#define	is_bsd_compat			is_param_arr[3].icmp_param_value
+#define	is_xmit_hiwat			is_param_arr[4].icmp_param_value
+#define	is_xmit_lowat			is_param_arr[5].icmp_param_value
+#define	is_recv_hiwat			is_param_arr[6].icmp_param_value
+#define	is_max_buf			is_param_arr[7].icmp_param_value
 
 /*
  * This routine is called to handle each O_T_BIND_REQ/T_BIND_REQ message
@@ -630,6 +620,7 @@
 {
 	icmp_t	*icmp = (icmp_t *)q->q_ptr;
 	int	i1;
+	icmp_stack_t *is = icmp->icmp_is;
 
 	/* tell IP that if we're not here, he can't trust labels */
 	if (is_system_labeled())
@@ -655,9 +646,10 @@
 	ip6_pkt_free(&icmp->icmp_sticky_ipp);
 
 	crfree(icmp->icmp_credp);
+	netstack_rele(icmp->icmp_is->is_netstack);
 
 	/* Free the icmp structure and release the minor device number. */
-	i1 = mi_close_comm(&icmp_g_head, q);
+	i1 = mi_close_comm(&is->is_head, q);
 
 	return (i1);
 }
@@ -926,7 +918,7 @@
 		udi_size = sizeof (struct T_unitdata_ind) + sizeof (sin6_t) +
 		    opt_length;
 		if ((newmp = allocb(udi_size, BPRI_MED)) == NULL) {
-			BUMP_MIB(&rawip_mib, rawipInErrors);
+			BUMP_MIB(&icmp->icmp_rawip_mib, rawipInErrors);
 			break;
 		}
 
@@ -1329,6 +1321,9 @@
 	icmp_t	*icmp;
 	mblk_t	*mp;
 	out_labeled_t *olp;
+	netstack_t *ns;
+	icmp_stack_t *is;
+	zoneid_t zoneid;
 
 	/* If the stream is already open, return immediately. */
 	if (q->q_ptr != NULL)
@@ -1345,20 +1340,36 @@
 	 * has an outer perimeter.)
 	 */
 
+	ns = netstack_find_by_cred(credp);
+	ASSERT(ns != NULL);
+	is = ns->netstack_icmp;
+	ASSERT(is != NULL);
+
+	/*
+	 * For exclusive stacks we set the zoneid to zero
+	 * to make ICMP operate as if in the global zone.
+	 */
+	if (is->is_netstack->netstack_stackid != GLOBAL_NETSTACKID)
+		zoneid = GLOBAL_ZONEID;
+	else
+		zoneid = crgetzoneid(credp);
+
 	/*
 	 * Create a icmp_t structure for this stream and link into the
 	 * list of open streams.
 	 */
-	err = mi_open_comm(&icmp_g_head, sizeof (icmp_t), q, devp,
+	err = mi_open_comm(&is->is_head, sizeof (icmp_t), q, devp,
 	    flag, sflag, credp);
-	if (err != 0)
+	if (err != 0) {
+		netstack_rele(is->is_netstack);
 		return (err);
+	}
 
 	/*
 	 * The receive hiwat is only looked at on the stream head queue.
 	 * Store in q_hiwat in order to return on SO_RCVBUF getsockopts.
 	 */
-	q->q_hiwat = icmp_recv_hiwat;
+	q->q_hiwat = is->is_recv_hiwat;
 
 	/* Set the initial state of the stream and the privilege status. */
 	icmp = (icmp_t *)q->q_ptr;
@@ -1377,7 +1388,8 @@
 	if (getpflags(NET_MAC_AWARE, credp) != 0)
 		icmp->icmp_mac_exempt = B_TRUE;
 
-	icmp->icmp_zoneid = getzoneid();
+	icmp->icmp_zoneid = zoneid;
+	icmp->icmp_is = is;
 
 	if (getmajor(*devp) == (major_t)ICMP6_MAJ) {
 		icmp->icmp_ipversion = IPV6_VERSION;
@@ -1386,14 +1398,14 @@
 		icmp->icmp_proto = IPPROTO_ICMPV6;
 		icmp->icmp_checksum_off = 2;	/* Offset for icmp6_cksum */
 		icmp->icmp_max_hdr_len = IPV6_HDR_LEN;
-		icmp->icmp_ttl = (uint8_t)icmp_ipv6_hoplimit;
+		icmp->icmp_ttl = (uint8_t)is->is_ipv6_hoplimit;
 	} else {
 		icmp->icmp_ipversion = IPV4_VERSION;
 		icmp->icmp_family = AF_INET;
 		/* May be changed by a SO_PROTOTYPE socket option. */
 		icmp->icmp_proto = IPPROTO_ICMP;
 		icmp->icmp_max_hdr_len = IP_SIMPLE_HDR_LENGTH;
-		icmp->icmp_ttl = (uint8_t)icmp_ipv4_ttl;
+		icmp->icmp_ttl = (uint8_t)is->is_ipv4_ttl;
 	}
 	qprocson(q);
 
@@ -1411,9 +1423,9 @@
 	 * Store in q_hiwat in order to return on SO_SNDBUF
 	 * getsockopts.
 	 */
-	WR(q)->q_hiwat = icmp_xmit_hiwat;
+	WR(q)->q_hiwat = is->is_xmit_hiwat;
 	WR(q)->q_next->q_hiwat = WR(q)->q_hiwat;
-	WR(q)->q_lowat = icmp_xmit_lowat;
+	WR(q)->q_lowat = is->is_xmit_lowat;
 	WR(q)->q_next->q_lowat = WR(q)->q_lowat;
 
 	if (icmp->icmp_family == AF_INET6) {
@@ -1423,7 +1435,8 @@
 			goto open_error;
 	}
 	/* Set the Stream head write offset. */
-	(void) mi_set_sth_wroff(q, icmp->icmp_max_hdr_len + icmp_wroff_extra);
+	(void) mi_set_sth_wroff(q,
+	    icmp->icmp_max_hdr_len + is->is_wroff_extra);
 	(void) mi_set_sth_hiwat(q, q->q_hiwat);
 
 	if (is_system_labeled()) {
@@ -1453,7 +1466,8 @@
 open_error:
 	qprocsoff(q);
 	crfree(credp);
-	(void) mi_close_comm(&icmp_g_head, q);
+	(void) mi_close_comm(&is->is_head, q);
+	netstack_rele(is->is_netstack);
 	return (err);
 }
 
@@ -1475,6 +1489,8 @@
 int
 icmp_opt_default(queue_t *q, int level, int name, uchar_t *ptr)
 {
+	icmp_t *icmp = (icmp_t *)q->q_ptr;
+	icmp_stack_t *is = icmp->icmp_is;
 	int *i1 = (int *)ptr;
 
 	switch (level) {
@@ -1497,7 +1513,7 @@
 			*i1 = IP_DEFAULT_MULTICAST_LOOP;
 			return (sizeof (int));
 		case IPV6_UNICAST_HOPS:
-			*i1 = icmp_ipv6_hoplimit;
+			*i1 = is->is_ipv6_hoplimit;
 			return (sizeof (int));
 		}
 		break;
@@ -1523,6 +1539,7 @@
 	icmp_t	*icmp = (icmp_t *)q->q_ptr;
 	int	*i1 = (int *)ptr;
 	ip6_pkt_t	*ipp = &icmp->icmp_sticky_ipp;
+	icmp_stack_t	*is = icmp->icmp_is;
 
 	switch (level) {
 	case SOL_SOCKET:
@@ -1817,7 +1834,8 @@
 				return (0);
 
 			return (ip_fill_mtuinfo(&icmp->icmp_v6dst, 0,
-				(struct ip6_mtuinfo *)ptr));
+				(struct ip6_mtuinfo *)ptr,
+				is->is_netstack));
 		case IPV6_TCLASS:
 			if (ipp->ipp_fields & IPPF_TCLASS)
 				*i1 = ipp->ipp_tclass;
@@ -1866,6 +1884,7 @@
     void *thisdg_attrs, cred_t *cr, mblk_t *mblk)
 {
 	icmp_t	*icmp = (icmp_t *)q->q_ptr;
+	icmp_stack_t *is = icmp->icmp_is;
 	int	*i1 = (int *)invalp;
 	boolean_t onoff = (*i1 == 0) ? 0 : 1;
 	boolean_t checkonly;
@@ -2022,7 +2041,7 @@
 			break;
 
 		case SO_SNDBUF:
-			if (*i1 > icmp_max_buf) {
+			if (*i1 > is->is_max_buf) {
 				*outlenp = 0;
 				return (ENOBUFS);
 			}
@@ -2032,7 +2051,7 @@
 			}
 			break;
 		case SO_RCVBUF:
-			if (*i1 > icmp_max_buf) {
+			if (*i1 > is->is_max_buf) {
 				*outlenp = 0;
 				return (ENOBUFS);
 			}
@@ -2107,7 +2126,7 @@
 			icmp->icmp_max_hdr_len = IP_SIMPLE_HDR_LENGTH +
 			    icmp->icmp_ip_snd_options_len;
 			(void) mi_set_sth_wroff(RD(q), icmp->icmp_max_hdr_len +
-						icmp_wroff_extra);
+						is->is_wroff_extra);
 			break;
 		case IP_HDRINCL:
 			if (!checkonly)
@@ -2278,7 +2297,7 @@
 			if (!checkonly) {
 				if (*i1 == -1) {
 					icmp->icmp_ttl = ipp->ipp_unicast_hops =
-					    icmp_ipv6_hoplimit;
+					    is->is_ipv6_hoplimit;
 					ipp->ipp_fields &= ~IPPF_UNICAST_HOPS;
 					/* Pass modified value to IP. */
 					*i1 = ipp->ipp_hoplimit;
@@ -2478,7 +2497,8 @@
 				if (*i1 > 255 || *i1 < -1)
 					return (EINVAL);
 				if (*i1 == -1)
-					ipp->ipp_hoplimit = icmp_ipv6_hoplimit;
+					ipp->ipp_hoplimit =
+					    is->is_ipv6_hoplimit;
 				else
 					ipp->ipp_hoplimit = *i1;
 				ipp->ipp_fields |= IPPF_HOPLIMIT;
@@ -2814,6 +2834,7 @@
 static int
 icmp_build_hdrs(queue_t *q, icmp_t *icmp)
 {
+	icmp_stack_t *is = icmp->icmp_is;
 	uchar_t	*hdrs;
 	uint_t	hdrs_len;
 	ip6_t	*ip6h;
@@ -2864,7 +2885,7 @@
 	if (hdrs_len > icmp->icmp_max_hdr_len) {
 		icmp->icmp_max_hdr_len = hdrs_len;
 		(void) mi_set_sth_wroff(RD(q), icmp->icmp_max_hdr_len +
-		    icmp_wroff_extra);
+		    is->is_wroff_extra);
 	}
 	return (0);
 }
@@ -2889,21 +2910,21 @@
  * named dispatch (ND) handler.
  */
 static boolean_t
-icmp_param_register(icmpparam_t *icmppa, int cnt)
+icmp_param_register(IDP *ndp, icmpparam_t *icmppa, int cnt)
 {
 	for (; cnt-- > 0; icmppa++) {
 		if (icmppa->icmp_param_name && icmppa->icmp_param_name[0]) {
-			if (!nd_load(&icmp_g_nd, icmppa->icmp_param_name,
+			if (!nd_load(ndp, icmppa->icmp_param_name,
 			    icmp_param_get, icmp_param_set,
 			    (caddr_t)icmppa)) {
-				nd_free(&icmp_g_nd);
+				nd_free(ndp);
 				return (B_FALSE);
 			}
 		}
 	}
-	if (!nd_load(&icmp_g_nd, "icmp_status", icmp_status_report, NULL,
+	if (!nd_load(ndp, "icmp_status", icmp_status_report, NULL,
 	    NULL)) {
-		nd_free(&icmp_g_nd);
+		nd_free(ndp);
 		return (B_FALSE);
 	}
 	return (B_TRUE);
@@ -2937,7 +2958,8 @@
 	struct T_unitdata_ind	*tudi;
 	uchar_t			*rptr;
 	struct T_error_ack	*tea;
-	icmp_t			*icmp;
+	icmp_t			*icmp = (icmp_t *)q->q_ptr;
+	icmp_stack_t		*is = icmp->icmp_is;
 	sin_t			*sin;
 	sin6_t			*sin6;
 	ip6_t			*ip6h;
@@ -2956,7 +2978,6 @@
 	boolean_t		icmp_ipv6_recvhoplimit = B_FALSE;
 	uint_t			hopstrip;
 
-	icmp = (icmp_t *)q->q_ptr;
 	if (icmp->icmp_restricted) {
 		putnext(q, mp);
 		return;
@@ -3106,7 +3127,7 @@
 		freemsg(mp);
 		if (options_mp != NULL)
 			freeb(options_mp);
-		BUMP_MIB(&rawip_mib, rawipInErrors);
+		BUMP_MIB(&icmp->icmp_rawip_mib, rawipInErrors);
 		return;
 	}
 	ipvers = IPH_HDR_VERSION((ipha_t *)rptr);
@@ -3133,7 +3154,7 @@
 				}
 			}
 		}
-		if (icmp_bsd_compat) {
+		if (is->is_bsd_compat) {
 			ushort_t len;
 			len = ntohs(ipha->ipha_length);
 
@@ -3149,7 +3170,8 @@
 					freemsg(mp);
 					if (options_mp != NULL)
 						freeb(options_mp);
-					BUMP_MIB(&rawip_mib, rawipInErrors);
+					BUMP_MIB(&icmp->icmp_rawip_mib,
+					    rawipInErrors);
 					return;
 				}
 				bcopy(rptr, mp1->b_rptr, hdr_len);
@@ -3199,7 +3221,7 @@
 			freemsg(mp);
 			if (options_mp != NULL)
 				freeb(options_mp);
-			BUMP_MIB(&rawip_mib, rawipInErrors);
+			BUMP_MIB(&icmp->icmp_rawip_mib, rawipInErrors);
 			return;
 		}
 		mp1->b_cont = mp;
@@ -3289,7 +3311,7 @@
 			ASSERT(udi_size == 0);
 		}
 
-		BUMP_MIB(&rawip_mib, rawipInDatagrams);
+		BUMP_MIB(&icmp->icmp_rawip_mib, rawipInDatagrams);
 		putnext(q, mp);
 		return;
 	}
@@ -3310,7 +3332,7 @@
 	    IPH_HDR_VERSION((ipha_t *)rptr) != IPV6_VERSION ||
 	    icmp->icmp_family != AF_INET6) {
 		freemsg(mp);
-		BUMP_MIB(&rawip_mib, rawipInErrors);
+		BUMP_MIB(&icmp->icmp_rawip_mib, rawipInErrors);
 		return;
 	}
 
@@ -3449,7 +3471,8 @@
 				ip0dbg(("icmp_rput: RAW checksum "
 				    "failed %x\n", sum));
 				freemsg(mp);
-				BUMP_MIB(&rawip_mib, rawipInCksumErrs);
+				BUMP_MIB(&icmp->icmp_rawip_mib,
+				    rawipInCksumErrs);
 				return;
 			}
 		}
@@ -3516,7 +3539,7 @@
 	mp1 = allocb(udi_size, BPRI_MED);
 	if (mp1 == NULL) {
 		freemsg(mp);
-		BUMP_MIB(&rawip_mib, rawipInErrors);
+		BUMP_MIB(&icmp->icmp_rawip_mib, rawipInErrors);
 		return;
 	}
 	mp1->b_cont = mp;
@@ -3545,7 +3568,7 @@
 		sin6->sin6_scope_id = 0;
 
 	sin6->__sin6_src_id = ip_srcid_find_addr(&ip6h->ip6_dst,
-	    icmp->icmp_zoneid);
+	    icmp->icmp_zoneid, is->is_netstack);
 
 	if (udi_size != 0) {
 		uchar_t *dstopt;
@@ -3664,7 +3687,7 @@
 		/* Consumed all of allocated space */
 		ASSERT(udi_size == 0);
 	}
-	BUMP_MIB(&rawip_mib, rawipInDatagrams);
+	BUMP_MIB(&icmp->icmp_rawip_mib, rawipInDatagrams);
 	putnext(q, mp);
 }
 
@@ -3795,6 +3818,7 @@
 {
 	mblk_t			*mpdata;
 	struct opthdr		*optp;
+	icmp_t			*icmp = (icmp_t *)q->q_ptr;
 
 	if (mpctl == NULL ||
 	    (mpdata = mpctl->b_cont) == NULL) {
@@ -3805,7 +3829,8 @@
 	optp = (struct opthdr *)&mpctl->b_rptr[sizeof (struct T_optmgmt_ack)];
 	optp->level = EXPER_RAWIP;
 	optp->name = 0;
-	(void) snmp_append_data(mpdata, (char *)&rawip_mib, sizeof (rawip_mib));
+	(void) snmp_append_data(mpdata, (char *)&icmp->icmp_rawip_mib,
+	    sizeof (icmp->icmp_rawip_mib));
 	optp->len = msgdsize(mpdata);
 	qreply(q, mpctl);
 
@@ -3840,6 +3865,10 @@
 	char	*state;
 	char	laddrbuf[INET6_ADDRSTRLEN];
 	char	faddrbuf[INET6_ADDRSTRLEN];
+	icmp_stack_t *is;
+
+	icmp = (icmp_t *)q->q_ptr;
+	is = icmp->icmp_is;
 
 	(void) mi_mpprintf(mp,
 	    "RAWIP    " MI_COL_HDRPAD_STR
@@ -3848,9 +3877,9 @@
 	/*   xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx UNBOUND */
 
 
-	for (idp = mi_first_ptr(&icmp_g_head);
+	for (idp = mi_first_ptr(&is->is_head);
 	    (icmp = (icmp_t *)idp) != NULL;
-	    idp = mi_next_ptr(&icmp_g_head, idp)) {
+	    idp = mi_next_ptr(&is->is_head, idp)) {
 		if (icmp->icmp_state == TS_UNBND)
 			state = "UNBOUND";
 		else if (icmp->icmp_state == TS_IDLE)
@@ -3933,6 +3962,7 @@
 icmp_wput_hdrincl(queue_t *q, mblk_t *mp, icmp_t *icmp, ip4_pkt_t *pktinfop,
 boolean_t use_putnext)
 {
+	icmp_stack_t *is = icmp->icmp_is;
 	ipha_t	*ipha;
 	int	ip_hdr_length;
 	int	tp_hdr_len;
@@ -3946,7 +3976,8 @@
 	ip_hdr_length = IP_SIMPLE_HDR_LENGTH + icmp->icmp_ip_snd_options_len;
 	if ((mp->b_wptr - mp->b_rptr) < IP_SIMPLE_HDR_LENGTH) {
 		if (!pullupmsg(mp, IP_SIMPLE_HDR_LENGTH)) {
-			BUMP_MIB(&rawip_mib, rawipOutErrors);
+			ASSERT(icmp != NULL);
+			BUMP_MIB(&icmp->icmp_rawip_mib, rawipOutErrors);
 			freemsg(mp);
 			return;
 		}
@@ -3990,7 +4021,8 @@
 		    tp_hdr_len)) {
 			if (!pullupmsg(mp, IP_SIMPLE_HDR_LENGTH +
 			    tp_hdr_len)) {
-				BUMP_MIB(&rawip_mib, rawipOutErrors);
+				BUMP_MIB(&icmp->icmp_rawip_mib,
+				    rawipOutErrors);
 				freemsg(mp);
 				return;
 			}
@@ -4007,12 +4039,12 @@
 			icmp_ud_err(q, mp, EMSGSIZE);
 			return;
 		}
-		if (!(mp1 = allocb(ip_hdr_length + icmp_wroff_extra +
+		if (!(mp1 = allocb(ip_hdr_length + is->is_wroff_extra +
 		    tp_hdr_len, BPRI_LO))) {
 			icmp_ud_err(q, mp, ENOMEM);
 			return;
 		}
-		mp1->b_rptr += icmp_wroff_extra;
+		mp1->b_rptr += is->is_wroff_extra;
 		mp1->b_wptr = mp1->b_rptr + ip_hdr_length;
 
 		ipha->ipha_length = htons((uint16_t)pkt_len);
@@ -4036,7 +4068,7 @@
 		 * Massage source route putting first source
 		 * route in ipha_dst.
 		 */
-		(void) ip_massage_options(ipha);
+		(void) ip_massage_options(ipha, icmp->icmp_is->is_netstack);
 	}
 
 	if (pktinfop != NULL) {
@@ -4071,14 +4103,15 @@
 	uchar_t opt_storage[IP_MAX_OPT_LENGTH];
 
 	err = tsol_compute_label(DB_CREDDEF(mp, icmp->icmp_credp), dst,
-	    opt_storage, icmp->icmp_mac_exempt);
+	    opt_storage, icmp->icmp_mac_exempt,
+	    icmp->icmp_is->is_netstack->netstack_ip);
 	if (err == 0) {
 		err = tsol_update_options(&icmp->icmp_ip_snd_options,
 		    &icmp->icmp_ip_snd_options_len, &icmp->icmp_label_len,
 		    opt_storage);
 	}
 	if (err != 0) {
-		BUMP_MIB(&rawip_mib, rawipOutErrors);
+		BUMP_MIB(&icmp->icmp_rawip_mib, rawipOutErrors);
 		DTRACE_PROBE4(
 		    tx__ip__log__drop__updatelabel__icmp,
 		    char *, "queue(1) failed to update options(2) on mp(3)",
@@ -4104,7 +4137,8 @@
 	int	ip_hdr_length;
 #define	tudr ((struct T_unitdata_req *)rptr)
 	size_t	ip_len;
-	icmp_t	*icmp;
+	icmp_t	*icmp = (icmp_t *)q->q_ptr;
+	icmp_stack_t *is = icmp->icmp_is;
 	sin6_t	*sin6;
 	sin_t	*sin;
 	ipaddr_t	v4dst;
@@ -4114,7 +4148,6 @@
 	queue_t		*ip_wq;
 	boolean_t	use_putnext = B_TRUE;
 
-	icmp = (icmp_t *)q->q_ptr;
 	if (icmp->icmp_restricted) {
 		icmp_wput_restricted(q, mp);
 		return;
@@ -4127,7 +4160,8 @@
 			ipha = (ipha_t *)mp->b_rptr;
 			if (mp->b_wptr - mp->b_rptr < IP_SIMPLE_HDR_LENGTH) {
 				if (!pullupmsg(mp, IP_SIMPLE_HDR_LENGTH)) {
-					BUMP_MIB(&rawip_mib, rawipOutErrors);
+					BUMP_MIB(&icmp->icmp_rawip_mib,
+					    rawipOutErrors);
 					freemsg(mp);
 					return;
 				}
@@ -4171,19 +4205,19 @@
 
 	if (icmp->icmp_state == TS_UNBND) {
 		/* If a port has not been bound to the stream, fail. */
-		BUMP_MIB(&rawip_mib, rawipOutErrors);
+		BUMP_MIB(&icmp->icmp_rawip_mib, rawipOutErrors);
 		icmp_ud_err(q, mp, EPROTO);
 		return;
 	}
 	mp1 = mp->b_cont;
 	if (mp1 == NULL) {
-		BUMP_MIB(&rawip_mib, rawipOutErrors);
+		BUMP_MIB(&icmp->icmp_rawip_mib, rawipOutErrors);
 		icmp_ud_err(q, mp, EPROTO);
 		return;
 	}
 
 	if ((rptr + tudr->DEST_offset + tudr->DEST_length) > mp->b_wptr) {
-		BUMP_MIB(&rawip_mib, rawipOutErrors);
+		BUMP_MIB(&icmp->icmp_rawip_mib, rawipOutErrors);
 		icmp_ud_err(q, mp, EADDRNOTAVAIL);
 		return;
 	}
@@ -4194,14 +4228,14 @@
 		if (!OK_32PTR((char *)sin6) ||
 		    tudr->DEST_length != sizeof (sin6_t) ||
 		    sin6->sin6_family != AF_INET6) {
-			BUMP_MIB(&rawip_mib, rawipOutErrors);
+			BUMP_MIB(&icmp->icmp_rawip_mib, rawipOutErrors);
 			icmp_ud_err(q, mp, EADDRNOTAVAIL);
 			return;
 		}
 
 		/* No support for mapped addresses on raw sockets */
 		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
-			BUMP_MIB(&rawip_mib, rawipOutErrors);
+			BUMP_MIB(&icmp->icmp_rawip_mib, rawipOutErrors);
 			icmp_ud_err(q, mp, EADDRNOTAVAIL);
 			return;
 		}
@@ -4218,7 +4252,7 @@
 		if (!OK_32PTR((char *)sin) ||
 		    tudr->DEST_length != sizeof (sin_t) ||
 		    sin->sin_family != AF_INET) {
-			BUMP_MIB(&rawip_mib, rawipOutErrors);
+			BUMP_MIB(&icmp->icmp_rawip_mib, rawipOutErrors);
 			icmp_ud_err(q, mp, EADDRNOTAVAIL);
 			return;
 		}
@@ -4246,7 +4280,7 @@
 		if (icmp_unitdata_opt_process(q, mp, &error,
 		    (void *)pktinfop) < 0) {
 			/* failure */
-			BUMP_MIB(&rawip_mib, rawipOutErrors);
+			BUMP_MIB(&icmp->icmp_rawip_mib, rawipOutErrors);
 			icmp_ud_err(q, mp, error);
 			return;
 		}
@@ -4298,9 +4332,9 @@
 	if ((uchar_t *)ipha < mp1->b_datap->db_base ||
 	    mp1->b_datap->db_ref != 1 ||
 	    !OK_32PTR(ipha)) {
-		if (!(mp1 = allocb(ip_hdr_length + icmp_wroff_extra,
+		if (!(mp1 = allocb(ip_hdr_length + is->is_wroff_extra,
 		    BPRI_LO))) {
-			BUMP_MIB(&rawip_mib, rawipOutErrors);
+			BUMP_MIB(&icmp->icmp_rawip_mib, rawipOutErrors);
 			icmp_ud_err(q, mp, ENOMEM);
 			return;
 		}
@@ -4367,7 +4401,7 @@
 	 * as this can cause problems in layers below.
 	 */
 	if (ip_len > IP_MAXPACKET) {
-		BUMP_MIB(&rawip_mib, rawipOutErrors);
+		BUMP_MIB(&icmp->icmp_rawip_mib, rawipOutErrors);
 		icmp_ud_err(q, mp, EMSGSIZE);
 		return;
 	}
@@ -4392,11 +4426,11 @@
 		 * Massage source route putting first source route in ipha_dst.
 		 * Ignore the destination in the T_unitdata_req.
 		 */
-		(void) ip_massage_options(ipha);
+		(void) ip_massage_options(ipha, icmp->icmp_is->is_netstack);
 	}
 
 	freeb(mp);
-	BUMP_MIB(&rawip_mib, rawipOutDatagrams);
+	BUMP_MIB(&icmp->icmp_rawip_mib, rawipOutDatagrams);
 	mblk_setcred(mp1, icmp->icmp_credp);
 	if (use_putnext) {
 		putnext(q, mp1);
@@ -4415,13 +4449,14 @@
 	uchar_t opt_storage[TSOL_MAX_IPV6_OPTION];
 
 	err = tsol_compute_label_v6(DB_CREDDEF(mp, icmp->icmp_credp), dst,
-	    opt_storage, icmp->icmp_mac_exempt);
+	    opt_storage, icmp->icmp_mac_exempt,
+	    icmp->icmp_is->is_netstack->netstack_ip);
 	if (err == 0) {
 		err = tsol_update_sticky(&icmp->icmp_sticky_ipp,
 		    &icmp->icmp_label_len_v6, opt_storage);
 	}
 	if (err != 0) {
-		BUMP_MIB(&rawip_mib, rawipOutErrors);
+		BUMP_MIB(&icmp->icmp_rawip_mib, rawipOutErrors);
 		DTRACE_PROBE4(
 		    tx__ip__log__drop__updatelabel__icmp6,
 		    char *, "queue(1) failed to update options(2) on mp(3)",
@@ -4447,7 +4482,8 @@
 	mblk_t			*mp1;
 	int			ip_hdr_len = IPV6_HDR_LEN;
 	size_t			ip_len;
-	icmp_t			*icmp;
+	icmp_t			*icmp = (icmp_t *)q->q_ptr;
+	icmp_stack_t		*is = icmp->icmp_is;
 	ip6_pkt_t		ipp_s;	/* For ancillary data options */
 	ip6_pkt_t		*ipp = &ipp_s;
 	ip6_pkt_t		*tipp;
@@ -4458,8 +4494,6 @@
 	uint8_t			*nxthdr_ptr;
 	in6_addr_t		ip6_dst;
 
-	icmp = (icmp_t *)q->q_ptr;
-
 	/*
 	 * If the local address is a mapped address return
 	 * an error.
@@ -4468,7 +4502,7 @@
 	 * since it is bound to a mapped address.
 	 */
 	if (IN6_IS_ADDR_V4MAPPED(&icmp->icmp_v6src)) {
-		BUMP_MIB(&rawip_mib, rawipOutErrors);
+		BUMP_MIB(&icmp->icmp_rawip_mib, rawipOutErrors);
 		icmp_ud_err(q, mp, EADDRNOTAVAIL);
 		return;
 	}
@@ -4485,7 +4519,7 @@
 		if (icmp_unitdata_opt_process(q, mp, &error,
 		    (void *)ipp) < 0) {
 			/* failure */
-			BUMP_MIB(&rawip_mib, rawipOutErrors);
+			BUMP_MIB(&icmp->icmp_rawip_mib, rawipOutErrors);
 			icmp_ud_err(q, mp, error);
 			return;
 		}
@@ -4695,11 +4729,11 @@
 		if (ip_hdr_len > icmp->icmp_max_hdr_len) {
 			icmp->icmp_max_hdr_len = ip_hdr_len;
 			(void) mi_set_sth_wroff(RD(q),
-			    icmp->icmp_max_hdr_len + icmp_wroff_extra);
+			    icmp->icmp_max_hdr_len + is->is_wroff_extra);
 		}
-		mp1 = allocb(ip_hdr_len + icmp_wroff_extra, BPRI_LO);
+		mp1 = allocb(ip_hdr_len + is->is_wroff_extra, BPRI_LO);
 		if (!mp1) {
-			BUMP_MIB(&rawip_mib, rawipOutErrors);
+			BUMP_MIB(&icmp->icmp_rawip_mib, rawipOutErrors);
 			icmp_ud_err(q, mp, ENOMEM);
 			return;
 		}
@@ -4800,7 +4834,8 @@
 		if (sin6->__sin6_src_id != 0 &&
 		    IN6_IS_ADDR_UNSPECIFIED(&ip6h->ip6_src)) {
 			ip_srcid_find_id(sin6->__sin6_src_id,
-			    &ip6h->ip6_src, icmp->icmp_zoneid);
+			    &ip6h->ip6_src, icmp->icmp_zoneid,
+			    is->is_netstack);
 		}
 	}
 
@@ -4900,7 +4935,8 @@
 				 * Notify the application as well.
 				 */
 				icmp_ud_err(q, mp, EPROTO);
-				BUMP_MIB(&rawip_mib, rawipOutErrors);
+				BUMP_MIB(&icmp->icmp_rawip_mib,
+				    rawipOutErrors);
 				return;
 			}
 			/*
@@ -4909,7 +4945,8 @@
 			 */
 			if (rth->ip6r_len & 0x1) {
 				icmp_ud_err(q, mp, EPROTO);
-				BUMP_MIB(&rawip_mib, rawipOutErrors);
+				BUMP_MIB(&icmp->icmp_rawip_mib,
+				    rawipOutErrors);
 				return;
 			}
 			/*
@@ -4918,7 +4955,8 @@
 			 * between the first hop (in ip6_dst) and
 			 * the destination (in the last routing hdr entry).
 			 */
-			csum = ip_massage_options_v6(ip6h, rth);
+			csum = ip_massage_options_v6(ip6h, rth,
+			    icmp->icmp_is->is_netstack);
 			/*
 			 * Verify that the first hop isn't a mapped address.
 			 * Routers along the path need to do this verification
@@ -4926,7 +4964,8 @@
 			 */
 			if (IN6_IS_ADDR_V4MAPPED(&ip6h->ip6_dst)) {
 				icmp_ud_err(q, mp, EADDRNOTAVAIL);
-				BUMP_MIB(&rawip_mib, rawipOutErrors);
+				BUMP_MIB(&icmp->icmp_rawip_mib,
+				    rawipOutErrors);
 				return;
 			}
 		}
@@ -4943,7 +4982,7 @@
 	 * as this can cause problems in layers below.
 	 */
 	if (ip_len > IP_MAXPACKET) {
-		BUMP_MIB(&rawip_mib, rawipOutErrors);
+		BUMP_MIB(&icmp->icmp_rawip_mib, rawipOutErrors);
 		icmp_ud_err(q, mp, EMSGSIZE);
 		return;
 	}
@@ -4966,7 +5005,8 @@
 		cksum_off = ip_hdr_len + icmp->icmp_checksum_off;
 		if (cksum_off + sizeof (uint16_t) > mp1->b_wptr - mp1->b_rptr) {
 			if (!pullupmsg(mp1, cksum_off + sizeof (uint16_t))) {
-				BUMP_MIB(&rawip_mib, rawipOutErrors);
+				BUMP_MIB(&icmp->icmp_rawip_mib,
+				    rawipOutErrors);
 				freemsg(mp);
 				return;
 			}
@@ -4994,7 +5034,7 @@
 	freeb(mp);
 
 	/* We're done. Pass the packet to IP */
-	BUMP_MIB(&rawip_mib, rawipOutDatagrams);
+	BUMP_MIB(&icmp->icmp_rawip_mib, rawipOutDatagrams);
 	mblk_setcred(mp1, icmp->icmp_credp);
 	putnext(q, mp1);
 }
@@ -5117,7 +5157,7 @@
 		case ND_SET:
 			/* nd_getset performs the necessary error checking */
 		case ND_GET:
-			if (nd_getset(q, icmp_g_nd, mp)) {
+			if (nd_getset(q, icmp->icmp_is->is_nd, mp)) {
 				qreply(q, mp);
 				return;
 			}
@@ -5367,21 +5407,62 @@
 	    optcom_max_optsize(icmp_opt_obj.odb_opt_des_arr,
 		icmp_opt_obj.odb_opt_arr_cnt);
 
-	(void) icmp_param_register(icmp_param_arr, A_CNT(icmp_param_arr));
-
-	rawip_kstat_init();
+	/*
+	 * We want to be informed each time a stack is created or
+	 * destroyed in the kernel, so we can maintain the
+	 * set of icmp_stack_t's.
+	 */
+	netstack_register(NS_ICMP, rawip_stack_init, NULL, rawip_stack_fini);
 }
 
 void
 icmp_ddi_destroy(void)
 {
-	nd_free(&icmp_g_nd);
-
-	rawip_kstat_fini();
+	netstack_unregister(NS_ICMP);
 }
 
+/*
+ * Initialize the ICMP stack instance.
+ */
+static void *
+rawip_stack_init(netstackid_t stackid, netstack_t *ns)
+{
+	icmp_stack_t	*is;
+	icmpparam_t	*pa;
+
+	is = (icmp_stack_t *)kmem_zalloc(sizeof (*is), KM_SLEEP);
+	is->is_netstack = ns;
+
+	pa = (icmpparam_t *)kmem_alloc(sizeof (icmp_param_arr), KM_SLEEP);
+	is->is_param_arr = pa;
+	bcopy(icmp_param_arr, is->is_param_arr, sizeof (icmp_param_arr));
+
+	(void) icmp_param_register(&is->is_nd,
+	    is->is_param_arr, A_CNT(icmp_param_arr));
+	is->is_ksp = rawip_kstat_init(stackid);
+	return (is);
+}
+
+/*
+ * Free the ICMP stack instance.
+ */
 static void
-rawip_kstat_init(void) {
+rawip_stack_fini(netstackid_t stackid, void *arg)
+{
+	icmp_stack_t *is = (icmp_stack_t *)arg;
+
+	nd_free(&is->is_nd);
+	kmem_free(is->is_param_arr, sizeof (icmp_param_arr));
+	is->is_param_arr = NULL;
+
+	rawip_kstat_fini(stackid, is->is_ksp);
+	is->is_ksp = NULL;
+	kmem_free(is, sizeof (*is));
+}
+
+static void *
+rawip_kstat_init(netstackid_t stackid) {
+	kstat_t	*ksp;
 
 	rawip_named_kstat_t template = {
 		{ "inDatagrams",	KSTAT_DATA_UINT32, 0 },
@@ -5391,45 +5472,59 @@
 		{ "outErrors",		KSTAT_DATA_UINT32, 0 },
 	};
 
-	rawip_mibkp = kstat_create("icmp", 0, "rawip", "mib2",
+	ksp = kstat_create_netstack("icmp", 0, "rawip", "mib2",
 					KSTAT_TYPE_NAMED,
 					NUM_OF_FIELDS(rawip_named_kstat_t),
-					0);
-	if (rawip_mibkp == NULL)
-		return;
+					0, stackid);
+	if (ksp == NULL || ksp->ks_data == NULL)
+		return (NULL);
 
-	bcopy(&template, rawip_mibkp->ks_data, sizeof (template));
+	bcopy(&template, ksp->ks_data, sizeof (template));
+	ksp->ks_update = rawip_kstat_update;
+	ksp->ks_private = (void *)(uintptr_t)stackid;
 
-	rawip_mibkp->ks_update = rawip_kstat_update;
-
-	kstat_install(rawip_mibkp);
+	kstat_install(ksp);
+	return (ksp);
 }
 
 static void
-rawip_kstat_fini(void) {
-	if (rawip_mibkp) {
-		kstat_delete(rawip_mibkp);
-		rawip_mibkp = NULL;
+rawip_kstat_fini(netstackid_t stackid, kstat_t *ksp)
+{
+	if (ksp != NULL) {
+		ASSERT(stackid == (netstackid_t)(uintptr_t)ksp->ks_private);
+		kstat_delete_netstack(ksp, stackid);
 	}
 }
 
 static int
-rawip_kstat_update(kstat_t *kp, int rw) {
+rawip_kstat_update(kstat_t *ksp, int rw)
+{
 	rawip_named_kstat_t *rawipkp;
+	netstackid_t	stackid = (netstackid_t)(uintptr_t)ksp->ks_private;
+	netstack_t	*ns;
+	icmp_stack_t	*is;
 
-	if ((kp == NULL) || (kp->ks_data == NULL))
+	if ((ksp == NULL) || (ksp->ks_data == NULL))
 		return (EIO);
 
 	if (rw == KSTAT_WRITE)
 		return (EACCES);
 
-	rawipkp = (rawip_named_kstat_t *)kp->ks_data;
+	rawipkp = (rawip_named_kstat_t *)ksp->ks_data;
 
-	rawipkp->inDatagrams.value.ui32 =	rawip_mib.rawipInDatagrams;
-	rawipkp->inCksumErrs.value.ui32 =	rawip_mib.rawipInCksumErrs;
-	rawipkp->inErrors.value.ui32 =		rawip_mib.rawipInErrors;
-	rawipkp->outDatagrams.value.ui32 =	rawip_mib.rawipOutDatagrams;
-	rawipkp->outErrors.value.ui32 =		rawip_mib.rawipOutErrors;
-
+	ns = netstack_find_by_stackid(stackid);
+	if (ns == NULL)
+		return (-1);
+	is = ns->netstack_icmp;
+	if (is == NULL) {
+		netstack_rele(ns);
+		return (-1);
+	}
+	rawipkp->inDatagrams.value.ui32 =  is->is_rawip_mib.rawipInDatagrams;
+	rawipkp->inCksumErrs.value.ui32 =  is->is_rawip_mib.rawipInCksumErrs;
+	rawipkp->inErrors.value.ui32 =	   is->is_rawip_mib.rawipInErrors;
+	rawipkp->outDatagrams.value.ui32 = is->is_rawip_mib.rawipOutDatagrams;
+	rawipkp->outErrors.value.ui32 =	   is->is_rawip_mib.rawipOutErrors;
+	netstack_rele(ns);
 	return (0);
 }
diff --git a/usr/src/uts/common/inet/ip/icmp_opt_data.c b/usr/src/uts/common/inet/ip/icmp_opt_data.c
index 3a898bb..b4a2041 100644
--- a/usr/src/uts/common/inet/ip/icmp_opt_data.c
+++ b/usr/src/uts/common/inet/ip/icmp_opt_data.c
@@ -155,7 +155,7 @@
 	(OP_PASSNEXT|OP_NODEFAULT|OP_VARLEN),
 	sizeof (struct in_pktinfo), -1 /* not initialized */ },
 
-{ IP_NEXTHOP, IPPROTO_IP, OA_RW, OA_RW, OP_CONFIG, OP_PASSNEXT,
+{ IP_NEXTHOP, IPPROTO_IP, OA_R, OA_RW, OP_CONFIG, OP_PASSNEXT,
 	sizeof (in_addr_t), -1 /* not initialized */ },
 
 { MRT_INIT, IPPROTO_IP, 0, OA_X, OP_CONFIG,
diff --git a/usr/src/uts/common/inet/ip/igmp.c b/usr/src/uts/common/inet/ip/igmp.c
index 7e01725..60647c3 100644
--- a/usr/src/uts/common/inet/ip/igmp.c
+++ b/usr/src/uts/common/inet/ip/igmp.c
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /* Copyright (c) 1990 Mentat Inc. */
@@ -86,27 +86,6 @@
 		    mcast_record_t rtype, slist_t *flist);
 static mrec_t	*mcast_merge_rtx(ilm_t *ilm, mrec_t *rp, slist_t *flist);
 
-/* Following protected by igmp_timer_lock */
-static int 	igmp_time_to_next;	/* Time since last timeout */
-static int 	igmp_timer_fired_last;
-uint_t		igmp_deferred_next = INFINITY;
-timeout_id_t	igmp_timeout_id = 0;
-kmutex_t	igmp_timer_lock;
-
-/* Protected by igmp_slowtimeout_lock */
-timeout_id_t	igmp_slowtimeout_id = 0;
-kmutex_t	igmp_slowtimeout_lock;
-
-/* Following protected by mld_timer_lock */
-static int 	mld_time_to_next;	/* Time since last timeout */
-static int 	mld_timer_fired_last;
-uint_t		mld_deferred_next = INFINITY;
-timeout_id_t	mld_timeout_id = 0;
-kmutex_t	mld_timer_lock;
-
-/* Protected by mld_slowtimeout_lock */
-timeout_id_t	mld_slowtimeout_id = 0;
-kmutex_t	mld_slowtimeout_lock;
 
 /*
  * Macros used to do timer len conversions.  Timer values are always
@@ -124,18 +103,16 @@
  * The unit for next is milliseconds.
  */
 void
-igmp_start_timers(unsigned next)
+igmp_start_timers(unsigned next, ip_stack_t *ipst)
 {
 	int	time_left;
-	/* Protected by igmp_timer_lock */
-	static  boolean_t igmp_timer_setter_active;
 	int	ret;
 
 	ASSERT(next != 0 && next != INFINITY);
 
-	mutex_enter(&igmp_timer_lock);
+	mutex_enter(&ipst->ips_igmp_timer_lock);
 
-	if (igmp_timer_setter_active) {
+	if (ipst->ips_igmp_timer_setter_active) {
 		/*
 		 * Serialize timer setters, one at a time. If the
 		 * timer is currently being set by someone,
@@ -143,21 +120,22 @@
 		 * invoked and return. The current setter will
 		 * take care.
 		 */
-		igmp_time_to_next = MIN(igmp_time_to_next, next);
-		mutex_exit(&igmp_timer_lock);
+		ipst->ips_igmp_time_to_next =
+		    MIN(ipst->ips_igmp_time_to_next, next);
+		mutex_exit(&ipst->ips_igmp_timer_lock);
 		return;
 	} else {
-		igmp_timer_setter_active = B_TRUE;
+		ipst->ips_igmp_timer_setter_active = B_TRUE;
 	}
-	if (igmp_timeout_id == 0) {
+	if (ipst->ips_igmp_timeout_id == 0) {
 		/*
 		 * The timer is inactive. We need to start a timer
 		 */
-		igmp_time_to_next = next;
-		igmp_timeout_id = timeout(igmp_timeout_handler, NULL,
-		    MSEC_TO_TICK(igmp_time_to_next));
-		igmp_timer_setter_active = B_FALSE;
-		mutex_exit(&igmp_timer_lock);
+		ipst->ips_igmp_time_to_next = next;
+		ipst->ips_igmp_timeout_id = timeout(igmp_timeout_handler,
+		    (void *)ipst, MSEC_TO_TICK(ipst->ips_igmp_time_to_next));
+		ipst->ips_igmp_timer_setter_active = B_FALSE;
+		mutex_exit(&ipst->ips_igmp_timer_lock);
 		return;
 	}
 
@@ -167,17 +145,17 @@
 	 * reschedule the timeout if the new 'next' will happen
 	 * earlier than the currently scheduled timeout
 	 */
-	time_left = igmp_timer_fired_last +
-	    MSEC_TO_TICK(igmp_time_to_next) - ddi_get_lbolt();
+	time_left = ipst->ips_igmp_timer_fired_last +
+	    MSEC_TO_TICK(ipst->ips_igmp_time_to_next) - ddi_get_lbolt();
 	if (time_left < MSEC_TO_TICK(next)) {
-		igmp_timer_setter_active = B_FALSE;
-		mutex_exit(&igmp_timer_lock);
+		ipst->ips_igmp_timer_setter_active = B_FALSE;
+		mutex_exit(&ipst->ips_igmp_timer_lock);
 		return;
 	}
 
-	mutex_exit(&igmp_timer_lock);
-	ret = untimeout(igmp_timeout_id);
-	mutex_enter(&igmp_timer_lock);
+	mutex_exit(&ipst->ips_igmp_timer_lock);
+	ret = untimeout(ipst->ips_igmp_timeout_id);
+	mutex_enter(&ipst->ips_igmp_timer_lock);
 	/*
 	 * The timeout was cancelled, or the timeout handler
 	 * completed, while we were blocked in the untimeout.
@@ -188,18 +166,19 @@
 	 * if needed.
 	 */
 	if (ret == -1) {
-		ASSERT(igmp_timeout_id == 0);
+		ASSERT(ipst->ips_igmp_timeout_id == 0);
 	} else {
-		ASSERT(igmp_timeout_id != 0);
-		igmp_timeout_id = 0;
+		ASSERT(ipst->ips_igmp_timeout_id != 0);
+		ipst->ips_igmp_timeout_id = 0;
 	}
-	if (igmp_time_to_next != 0) {
-		igmp_time_to_next = MIN(igmp_time_to_next, next);
-		igmp_timeout_id = timeout(igmp_timeout_handler, NULL,
-		    MSEC_TO_TICK(igmp_time_to_next));
+	if (ipst->ips_igmp_time_to_next != 0) {
+		ipst->ips_igmp_time_to_next =
+		    MIN(ipst->ips_igmp_time_to_next, next);
+		ipst->ips_igmp_timeout_id = timeout(igmp_timeout_handler,
+		    (void *)ipst, MSEC_TO_TICK(ipst->ips_igmp_time_to_next));
 	}
-	igmp_timer_setter_active = B_FALSE;
-	mutex_exit(&igmp_timer_lock);
+	ipst->ips_igmp_timer_setter_active = B_FALSE;
+	mutex_exit(&ipst->ips_igmp_timer_lock);
 }
 
 /*
@@ -207,17 +186,15 @@
  * The unit for next is milliseconds.
  */
 void
-mld_start_timers(unsigned next)
+mld_start_timers(unsigned next, ip_stack_t *ipst)
 {
 	int	time_left;
-	/* Protedted by mld_timer_lock */
-	static  boolean_t mld_timer_setter_active;
 	int	ret;
 
 	ASSERT(next != 0 && next != INFINITY);
 
-	mutex_enter(&mld_timer_lock);
-	if (mld_timer_setter_active) {
+	mutex_enter(&ipst->ips_mld_timer_lock);
+	if (ipst->ips_mld_timer_setter_active) {
 		/*
 		 * Serialize timer setters, one at a time. If the
 		 * timer is currently being set by someone,
@@ -225,21 +202,22 @@
 		 * invoked and return. The current setter will
 		 * take care.
 		 */
-		mld_time_to_next = MIN(mld_time_to_next, next);
-		mutex_exit(&mld_timer_lock);
+		ipst->ips_mld_time_to_next =
+		    MIN(ipst->ips_mld_time_to_next, next);
+		mutex_exit(&ipst->ips_mld_timer_lock);
 		return;
 	} else {
-		mld_timer_setter_active = B_TRUE;
+		ipst->ips_mld_timer_setter_active = B_TRUE;
 	}
-	if (mld_timeout_id == 0) {
+	if (ipst->ips_mld_timeout_id == 0) {
 		/*
 		 * The timer is inactive. We need to start a timer
 		 */
-		mld_time_to_next = next;
-		mld_timeout_id = timeout(mld_timeout_handler, NULL,
-		    MSEC_TO_TICK(mld_time_to_next));
-		mld_timer_setter_active = B_FALSE;
-		mutex_exit(&mld_timer_lock);
+		ipst->ips_mld_time_to_next = next;
+		ipst->ips_mld_timeout_id = timeout(mld_timeout_handler,
+		    (void *)ipst, MSEC_TO_TICK(ipst->ips_mld_time_to_next));
+		ipst->ips_mld_timer_setter_active = B_FALSE;
+		mutex_exit(&ipst->ips_mld_timer_lock);
 		return;
 	}
 
@@ -249,17 +227,17 @@
 	 * reschedule the timeout if the new 'next' will happen
 	 * earlier than the currently scheduled timeout
 	 */
-	time_left = mld_timer_fired_last +
-	    MSEC_TO_TICK(mld_time_to_next) - ddi_get_lbolt();
+	time_left = ipst->ips_mld_timer_fired_last +
+	    MSEC_TO_TICK(ipst->ips_mld_time_to_next) - ddi_get_lbolt();
 	if (time_left < MSEC_TO_TICK(next)) {
-		mld_timer_setter_active = B_FALSE;
-		mutex_exit(&mld_timer_lock);
+		ipst->ips_mld_timer_setter_active = B_FALSE;
+		mutex_exit(&ipst->ips_mld_timer_lock);
 		return;
 	}
 
-	mutex_exit(&mld_timer_lock);
-	ret = untimeout(mld_timeout_id);
-	mutex_enter(&mld_timer_lock);
+	mutex_exit(&ipst->ips_mld_timer_lock);
+	ret = untimeout(ipst->ips_mld_timeout_id);
+	mutex_enter(&ipst->ips_mld_timer_lock);
 	/*
 	 * The timeout was cancelled, or the timeout handler
 	 * completed, while we were blocked in the untimeout.
@@ -270,18 +248,19 @@
 	 * if needed.
 	 */
 	if (ret == -1) {
-		ASSERT(mld_timeout_id == 0);
+		ASSERT(ipst->ips_mld_timeout_id == 0);
 	} else {
-		ASSERT(mld_timeout_id != 0);
-		mld_timeout_id = 0;
+		ASSERT(ipst->ips_mld_timeout_id != 0);
+		ipst->ips_mld_timeout_id = 0;
 	}
-	if (mld_time_to_next != 0) {
-		mld_time_to_next = MIN(mld_time_to_next, next);
-		mld_timeout_id = timeout(mld_timeout_handler, NULL,
-		    MSEC_TO_TICK(mld_time_to_next));
+	if (ipst->ips_mld_time_to_next != 0) {
+		ipst->ips_mld_time_to_next =
+		    MIN(ipst->ips_mld_time_to_next, next);
+		ipst->ips_mld_timeout_id = timeout(mld_timeout_handler,
+		    (void *)ipst, MSEC_TO_TICK(ipst->ips_mld_time_to_next));
 	}
-	mld_timer_setter_active = B_FALSE;
-	mutex_exit(&mld_timer_lock);
+	ipst->ips_mld_timer_setter_active = B_FALSE;
+	mutex_exit(&ipst->ips_mld_timer_lock);
 }
 
 /*
@@ -303,14 +282,16 @@
 	uint32_t 	group;
 	uint_t		next;
 	ipif_t 		*ipif;
+	ip_stack_t	 *ipst;
 
 	ASSERT(ill != NULL);
 	ASSERT(!ill->ill_isv6);
-	++igmpstat.igps_rcv_total;
+	ipst = ill->ill_ipst;
+	++ipst->ips_igmpstat.igps_rcv_total;
 
 	mblklen = MBLKL(mp);
 	if (mblklen < 1 || mblklen < (iphlen = IPH_HDR_LENGTH(ipha))) {
-		++igmpstat.igps_rcv_tooshort;
+		++ipst->ips_igmpstat.igps_rcv_tooshort;
 		goto bad_pkt;
 	}
 	igmplen = ntohs(ipha->ipha_length) - iphlen;
@@ -321,7 +302,7 @@
 	if (MBLKL(mp) < (igmplen + iphlen)) {
 		mblk_t *mp1;
 		if ((mp1 = msgpullup(mp, -1)) == NULL) {
-			++igmpstat.igps_rcv_tooshort;
+			++ipst->ips_igmpstat.igps_rcv_tooshort;
 			goto bad_pkt;
 		}
 		freemsg(mp);
@@ -333,14 +314,14 @@
 	 * Validate lengths
 	 */
 	if (igmplen < IGMP_MINLEN) {
-		++igmpstat.igps_rcv_tooshort;
+		++ipst->ips_igmpstat.igps_rcv_tooshort;
 		goto bad_pkt;
 	}
 	/*
 	 * Validate checksum
 	 */
 	if (IP_CSUM(mp, iphlen, 0)) {
-		++igmpstat.igps_rcv_badsum;
+		++ipst->ips_igmpstat.igps_rcv_badsum;
 		goto bad_pkt;
 	}
 
@@ -365,14 +346,14 @@
 			next = igmpv3_query_in((igmp3qa_t *)igmpa, ill,
 			    igmplen);
 		} else {
-			++igmpstat.igps_rcv_tooshort;
+			++ipst->ips_igmpstat.igps_rcv_tooshort;
 			goto bad_pkt;
 		}
 		if (next == 0)
 			goto bad_pkt;
 
 		if (next != INFINITY)
-			igmp_start_timers(next);
+			igmp_start_timers(next, ipst);
 
 		break;
 
@@ -404,10 +385,10 @@
 		}
 		mutex_exit(&ill->ill_lock);
 
-		++igmpstat.igps_rcv_reports;
+		++ipst->ips_igmpstat.igps_rcv_reports;
 		group = igmpa->igmpa_group;
 		if (!CLASSD(group)) {
-			++igmpstat.igps_rcv_badreports;
+			++ipst->ips_igmpstat.igps_rcv_badreports;
 			goto bad_pkt;
 		}
 
@@ -445,7 +426,7 @@
 		    ipif = ipif->ipif_next) {
 			ilm = ilm_lookup_ipif(ipif, group);
 			if (ilm != NULL) {
-				++igmpstat.igps_rcv_ourreports;
+				++ipst->ips_igmpstat.igps_rcv_ourreports;
 				ilm->ilm_timer = INFINITY;
 				ilm->ilm_state = IGMP_OTHERMEMBER;
 			}
@@ -478,8 +459,10 @@
 	ilm_t	*ilm;
 	int	timer;
 	uint_t	next;
+	ip_stack_t	 *ipst;
 
-	++igmpstat.igps_rcv_queries;
+	ipst = ill->ill_ipst;
+	++ipst->ips_igmpstat.igps_rcv_queries;
 
 	/*
 	 * In the IGMPv2 specification, there are 3 states and a flag.
@@ -516,7 +499,7 @@
 
 		if (ipha->ipha_dst != htonl(INADDR_ALLHOSTS_GROUP) ||
 		    igmpa->igmpa_group != 0) {
-			++igmpstat.igps_rcv_badqueries;
+			++ipst->ips_igmpstat.igps_rcv_badqueries;
 			return (0);
 		}
 
@@ -529,7 +512,7 @@
 		 */
 		group = igmpa->igmpa_group;
 		if (group != 0 && (!CLASSD(group))) {
-			++igmpstat.igps_rcv_badqueries;
+			++ipst->ips_igmpstat.igps_rcv_badqueries;
 			return (0);
 		}
 
@@ -609,16 +592,18 @@
 	ilm_t		*ilm;
 	ipaddr_t	*src_array;
 	uint8_t		qrv;
+	ip_stack_t	 *ipst;
 
+	ipst = ill->ill_ipst;
 	/* make sure numsrc matches packet size */
 	numsrc = ntohs(igmp3qa->igmp3qa_numsrc);
 	if (igmplen < IGMP_V3_QUERY_MINLEN + (numsrc * sizeof (ipaddr_t))) {
-		++igmpstat.igps_rcv_tooshort;
+		++ipst->ips_igmpstat.igps_rcv_tooshort;
 		return (0);
 	}
 	src_array = (ipaddr_t *)&igmp3qa[1];
 
-	++igmpstat.igps_rcv_queries;
+	++ipst->ips_igmpstat.igps_rcv_queries;
 
 	if ((mrd = (uint_t)igmp3qa->igmp3qa_mxrc) >= IGMP_V3_MAXRT_FPMIN) {
 		uint_t hdrval, mant, exp;
@@ -738,6 +723,7 @@
 igmp_joingroup(ilm_t *ilm)
 {
 	ill_t	*ill;
+	ip_stack_t	*ipst = ilm->ilm_ipst;
 
 	ill = ilm->ilm_ipif->ipif_ill;
 
@@ -802,10 +788,10 @@
 		 * acquire the ipsq. Instead we start the timer after we get
 		 * out of the ipsq in ipsq_exit.
 		 */
-		mutex_enter(&igmp_timer_lock);
-		igmp_deferred_next = MIN(ilm->ilm_rtx.rtx_timer,
-		    igmp_deferred_next);
-		mutex_exit(&igmp_timer_lock);
+		mutex_enter(&ipst->ips_igmp_timer_lock);
+		ipst->ips_igmp_deferred_next = MIN(ilm->ilm_rtx.rtx_timer,
+		    ipst->ips_igmp_deferred_next);
+		mutex_exit(&ipst->ips_igmp_timer_lock);
 	}
 
 	if (ip_debug > 1) {
@@ -820,6 +806,7 @@
 mld_joingroup(ilm_t *ilm)
 {
 	ill_t	*ill;
+	ip_stack_t	*ipst = ilm->ilm_ipst;
 
 	ill = ilm->ilm_ill;
 
@@ -880,10 +867,10 @@
 		 * acquire the ipsq. Instead we start the timer after we get
 		 * out of the ipsq in ipsq_exit
 		 */
-		mutex_enter(&mld_timer_lock);
-		mld_deferred_next = MIN(ilm->ilm_rtx.rtx_timer,
-		    mld_deferred_next);
-		mutex_exit(&mld_timer_lock);
+		mutex_enter(&ipst->ips_mld_timer_lock);
+		ipst->ips_mld_deferred_next = MIN(ilm->ilm_rtx.rtx_timer,
+		    ipst->ips_mld_deferred_next);
+		mutex_exit(&ipst->ips_mld_timer_lock);
 	}
 
 	if (ip_debug > 1) {
@@ -982,6 +969,7 @@
 {
 	ill_t *ill;
 	mrec_t *rp;
+	ip_stack_t	*ipst = ilm->ilm_ipst;
 
 	ASSERT(ilm != NULL);
 
@@ -1059,10 +1047,10 @@
 	if (ilm->ilm_rtx.rtx_timer == INFINITY) {
 		MCAST_RANDOM_DELAY(ilm->ilm_rtx.rtx_timer,
 		    SEC_TO_MSEC(IGMP_MAX_HOST_REPORT_DELAY));
-		mutex_enter(&igmp_timer_lock);
-		igmp_deferred_next = MIN(igmp_deferred_next,
+		mutex_enter(&ipst->ips_igmp_timer_lock);
+		ipst->ips_igmp_deferred_next = MIN(ipst->ips_igmp_deferred_next,
 		    ilm->ilm_rtx.rtx_timer);
-		mutex_exit(&igmp_timer_lock);
+		mutex_exit(&ipst->ips_igmp_timer_lock);
 	}
 
 	mutex_exit(&ill->ill_lock);
@@ -1074,6 +1062,7 @@
 {
 	ill_t *ill;
 	mrec_t *rp = NULL;
+	ip_stack_t	*ipst = ilm->ilm_ipst;
 
 	ASSERT(ilm != NULL);
 
@@ -1146,10 +1135,10 @@
 	if (ilm->ilm_rtx.rtx_timer == INFINITY) {
 		MCAST_RANDOM_DELAY(ilm->ilm_rtx.rtx_timer,
 		    SEC_TO_MSEC(ICMP6_MAX_HOST_REPORT_DELAY));
-		mutex_enter(&mld_timer_lock);
-		mld_deferred_next =
-		    MIN(mld_deferred_next, ilm->ilm_rtx.rtx_timer);
-		mutex_exit(&mld_timer_lock);
+		mutex_enter(&ipst->ips_mld_timer_lock);
+		ipst->ips_mld_deferred_next =
+		    MIN(ipst->ips_mld_deferred_next, ilm->ilm_rtx.rtx_timer);
+		mutex_exit(&ipst->ips_mld_timer_lock);
 	}
 
 	mutex_exit(&ill->ill_lock);
@@ -1392,8 +1381,6 @@
  * The igmp_slowtimeo() function is called thru another timer.
  * igmp_slowtimeout_lock protects the igmp_slowtimeout_id
  */
-
-/* ARGSUSED */
 void
 igmp_timeout_handler(void *arg)
 {
@@ -1403,16 +1390,18 @@
 	uint_t  next;
 	ill_walk_context_t ctx;
 	boolean_t success;
+	ip_stack_t *ipst = (ip_stack_t *)arg;
 
-	mutex_enter(&igmp_timer_lock);
-	ASSERT(igmp_timeout_id != 0);
-	igmp_timer_fired_last = ddi_get_lbolt();
-	elapsed = igmp_time_to_next;
-	igmp_time_to_next = 0;
-	mutex_exit(&igmp_timer_lock);
+	ASSERT(arg != NULL);
+	mutex_enter(&ipst->ips_igmp_timer_lock);
+	ASSERT(ipst->ips_igmp_timeout_id != 0);
+	ipst->ips_igmp_timer_fired_last = ddi_get_lbolt();
+	elapsed = ipst->ips_igmp_time_to_next;
+	ipst->ips_igmp_time_to_next = 0;
+	mutex_exit(&ipst->ips_igmp_timer_lock);
 
-	rw_enter(&ill_g_lock, RW_READER);
-	ill = ILL_START_WALK_V4(&ctx);
+	rw_enter(&ipst->ips_ill_g_lock, RW_READER);
+	ill = ILL_START_WALK_V4(&ctx, ipst);
 	for (; ill != NULL; ill = ill_next(&ctx, ill)) {
 		ASSERT(!ill->ill_isv6);
 		/*
@@ -1422,7 +1411,7 @@
 		 */
 		if (!ill_waiter_inc(ill))
 			continue;
-		rw_exit(&ill_g_lock);
+		rw_exit(&ipst->ips_ill_g_lock);
 		success = ipsq_enter(ill, B_TRUE);
 		if (success) {
 			next = igmp_timeout_handler_per_ill(ill, elapsed);
@@ -1431,18 +1420,18 @@
 			ipsq_exit(ill->ill_phyint->phyint_ipsq, B_FALSE,
 			    B_TRUE);
 		}
-		rw_enter(&ill_g_lock, RW_READER);
+		rw_enter(&ipst->ips_ill_g_lock, RW_READER);
 		ill_waiter_dcr(ill);
 	}
-	rw_exit(&ill_g_lock);
+	rw_exit(&ipst->ips_ill_g_lock);
 
-	mutex_enter(&igmp_timer_lock);
-	ASSERT(igmp_timeout_id != 0);
-	igmp_timeout_id = 0;
-	mutex_exit(&igmp_timer_lock);
+	mutex_enter(&ipst->ips_igmp_timer_lock);
+	ASSERT(ipst->ips_igmp_timeout_id != 0);
+	ipst->ips_igmp_timeout_id = 0;
+	mutex_exit(&ipst->ips_igmp_timer_lock);
 
 	if (global_next != INFINITY)
-		igmp_start_timers(global_next);
+		igmp_start_timers(global_next, ipst);
 }
 
 /*
@@ -1645,7 +1634,6 @@
  * Returns number of ticks to next event (or 0 if none).
  * MT issues are same as igmp_timeout_handler
  */
-/* ARGSUSED */
 void
 mld_timeout_handler(void *arg)
 {
@@ -1655,16 +1643,18 @@
 	uint_t  next;
 	ill_walk_context_t ctx;
 	boolean_t success;
+	ip_stack_t *ipst = (ip_stack_t *)arg;
 
-	mutex_enter(&mld_timer_lock);
-	ASSERT(mld_timeout_id != 0);
-	mld_timer_fired_last = ddi_get_lbolt();
-	elapsed = mld_time_to_next;
-	mld_time_to_next = 0;
-	mutex_exit(&mld_timer_lock);
+	ASSERT(arg != NULL);
+	mutex_enter(&ipst->ips_mld_timer_lock);
+	ASSERT(ipst->ips_mld_timeout_id != 0);
+	ipst->ips_mld_timer_fired_last = ddi_get_lbolt();
+	elapsed = ipst->ips_mld_time_to_next;
+	ipst->ips_mld_time_to_next = 0;
+	mutex_exit(&ipst->ips_mld_timer_lock);
 
-	rw_enter(&ill_g_lock, RW_READER);
-	ill = ILL_START_WALK_V6(&ctx);
+	rw_enter(&ipst->ips_ill_g_lock, RW_READER);
+	ill = ILL_START_WALK_V6(&ctx, ipst);
 	for (; ill != NULL; ill = ill_next(&ctx, ill)) {
 		ASSERT(ill->ill_isv6);
 		/*
@@ -1674,7 +1664,7 @@
 		 */
 		if (!ill_waiter_inc(ill))
 			continue;
-		rw_exit(&ill_g_lock);
+		rw_exit(&ipst->ips_ill_g_lock);
 		success = ipsq_enter(ill, B_TRUE);
 		if (success) {
 			next = mld_timeout_handler_per_ill(ill, elapsed);
@@ -1683,18 +1673,18 @@
 			ipsq_exit(ill->ill_phyint->phyint_ipsq, B_TRUE,
 			    B_FALSE);
 		}
-		rw_enter(&ill_g_lock, RW_READER);
+		rw_enter(&ipst->ips_ill_g_lock, RW_READER);
 		ill_waiter_dcr(ill);
 	}
-	rw_exit(&ill_g_lock);
+	rw_exit(&ipst->ips_ill_g_lock);
 
-	mutex_enter(&mld_timer_lock);
-	ASSERT(mld_timeout_id != 0);
-	mld_timeout_id = 0;
-	mutex_exit(&mld_timer_lock);
+	mutex_enter(&ipst->ips_mld_timer_lock);
+	ASSERT(ipst->ips_mld_timeout_id != 0);
+	ipst->ips_mld_timeout_id = 0;
+	mutex_exit(&ipst->ips_mld_timer_lock);
 
 	if (global_next != INFINITY)
-		mld_start_timers(global_next);
+		mld_start_timers(global_next, ipst);
 }
 
 /*
@@ -1711,16 +1701,17 @@
  *   in IGMP_AGE_THRESHOLD seconds.
  * - Resets slowtimeout.
  */
-/* ARGSUSED */
 void
 igmp_slowtimo(void *arg)
 {
 	ill_t	*ill;
 	ill_if_t *ifp;
 	avl_tree_t *avl_tree;
+	ip_stack_t *ipst = (ip_stack_t *)arg;
 
+	ASSERT(arg != NULL);
 	/* Hold the ill_g_lock so that we can safely walk the ill list */
-	rw_enter(&ill_g_lock, RW_READER);
+	rw_enter(&ipst->ips_ill_g_lock, RW_READER);
 
 	/*
 	 * The ill_if_t list is circular, hence the odd loop parameters.
@@ -1730,7 +1721,8 @@
 	 * structure (allowing us to skip if none of the instances have timers
 	 * running).
 	 */
-	for (ifp = IP_V4_ILL_G_LIST; ifp != (ill_if_t *)&IP_V4_ILL_G_LIST;
+	for (ifp = IP_V4_ILL_G_LIST(ipst);
+	    ifp != (ill_if_t *)&IP_V4_ILL_G_LIST(ipst);
 	    ifp = ifp->illif_next) {
 		/*
 		 * illif_mcast_v[12] are set using atomics. If an ill hears
@@ -1785,11 +1777,11 @@
 		}
 
 	}
-	rw_exit(&ill_g_lock);
-	mutex_enter(&igmp_slowtimeout_lock);
-	igmp_slowtimeout_id = timeout(igmp_slowtimo, NULL,
+	rw_exit(&ipst->ips_ill_g_lock);
+	mutex_enter(&ipst->ips_igmp_slowtimeout_lock);
+	ipst->ips_igmp_slowtimeout_id = timeout(igmp_slowtimo, (void *)ipst,
 		MSEC_TO_TICK(MCAST_SLOWTIMO_INTERVAL));
-	mutex_exit(&igmp_slowtimeout_lock);
+	mutex_exit(&ipst->ips_igmp_slowtimeout_lock);
 }
 
 /*
@@ -1805,12 +1797,14 @@
 	ill_t *ill;
 	ill_if_t *ifp;
 	avl_tree_t *avl_tree;
+	ip_stack_t *ipst = (ip_stack_t *)arg;
 
+	ASSERT(arg != NULL);
 	/* See comments in igmp_slowtimo() above... */
-	rw_enter(&ill_g_lock, RW_READER);
-	for (ifp = IP_V6_ILL_G_LIST; ifp != (ill_if_t *)&IP_V6_ILL_G_LIST;
+	rw_enter(&ipst->ips_ill_g_lock, RW_READER);
+	for (ifp = IP_V6_ILL_G_LIST(ipst);
+	    ifp != (ill_if_t *)&IP_V6_ILL_G_LIST(ipst);
 	    ifp = ifp->illif_next) {
-
 		if (ifp->illif_mcast_v1 == 0)
 			continue;
 
@@ -1834,11 +1828,11 @@
 			mutex_exit(&ill->ill_lock);
 		}
 	}
-	rw_exit(&ill_g_lock);
-	mutex_enter(&mld_slowtimeout_lock);
-	mld_slowtimeout_id = timeout(mld_slowtimo, NULL,
+	rw_exit(&ipst->ips_ill_g_lock);
+	mutex_enter(&ipst->ips_mld_slowtimeout_lock);
+	ipst->ips_mld_slowtimeout_id = timeout(mld_slowtimo, (void *)ipst,
 	    MSEC_TO_TICK(MCAST_SLOWTIMO_INTERVAL));
-	mutex_exit(&mld_slowtimeout_lock);
+	mutex_exit(&ipst->ips_mld_slowtimeout_lock);
 }
 
 /*
@@ -1861,6 +1855,7 @@
 	mblk_t	*first_mp;
 	ipsec_out_t *io;
 	zoneid_t zoneid;
+	ip_stack_t *ipst = ill->ill_ipst;
 
 	/*
 	 * We need to make sure this packet goes out on an ipif. If
@@ -1900,6 +1895,7 @@
 	if ((zoneid = ilm->ilm_zoneid) == ALL_ZONES)
 		zoneid = GLOBAL_ZONEID;
 	io->ipsec_out_zoneid = zoneid;
+	io->ipsec_out_ns = ipst->ips_netstack;	/* No netstack_hold */
 
 	mp = allocb(size, BPRI_HI);
 	if (mp == NULL) {
@@ -1951,7 +1947,7 @@
 
 	ip_wput_multicast(ill->ill_wq, first_mp, ipif, zoneid);
 
-	++igmpstat.igps_snd_reports;
+	++ipst->ips_igmpstat.igps_snd_reports;
 }
 
 /*
@@ -1979,6 +1975,7 @@
 	mrec_t *next_reclist = reclist;
 	boolean_t morepkts;
 	zoneid_t zoneid;
+	ip_stack_t	 *ipst = ill->ill_ipst;
 
 	/* if there aren't any records, there's nothing to send */
 	if (reclist == NULL)
@@ -2134,7 +2131,7 @@
 
 	ip_wput_multicast(ill->ill_wq, first_mp, ipif, zoneid);
 
-	++igmpstat.igps_snd_reports;
+	++ipst->ips_igmpstat.igps_snd_reports;
 
 	if (morepkts) {
 		if (more_src_cnt > 0) {
@@ -2172,6 +2169,7 @@
 	in6_addr_t	*v6group_ptr, *lcladdr_ptr;
 	uint_t		next;
 	int		mldlen;
+	ip_stack_t	*ipst = ill->ill_ipst;
 
 	BUMP_MIB(ill->ill_icmp6_mib, ipv6IfIcmpInGroupMembTotal);
 
@@ -2228,7 +2226,7 @@
 		}
 
 		if (next != INFINITY)
-			mld_start_timers(next);
+			mld_start_timers(next, ipst);
 		break;
 
 	case MLD_LISTENER_REPORT: {
diff --git a/usr/src/uts/common/inet/ip/ip.c b/usr/src/uts/common/inet/ip/ip.c
index f941309..83e13a8 100644
--- a/usr/src/uts/common/inet/ip/ip.c
+++ b/usr/src/uts/common/inet/ip/ip.c
@@ -18,6 +18,7 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
@@ -130,115 +131,11 @@
  * IP_SQUEUE_ENTER: squeue_enter
  * IP_SQUEUE_FILL: squeue_fill
  */
-int ip_squeue_enter = 2;
+int ip_squeue_enter = 2;	/* Setable in /etc/system */
+
 squeue_func_t ip_input_proc;
-/*
- * IP statistics.
- */
-#define	IP_STAT(x)		(ip_statistics.x.value.ui64++)
-#define	IP_STAT_UPDATE(x, n)	(ip_statistics.x.value.ui64 += (n))
 #define	SET_BPREV_FLAG(x)	((mblk_t *)(uintptr_t)(x))
 
-typedef struct ip_stat {
-	kstat_named_t	ipsec_fanout_proto;
-	kstat_named_t	ip_udp_fannorm;
-	kstat_named_t	ip_udp_fanmb;
-	kstat_named_t	ip_udp_fanothers;
-	kstat_named_t	ip_udp_fast_path;
-	kstat_named_t	ip_udp_slow_path;
-	kstat_named_t	ip_udp_input_err;
-	kstat_named_t	ip_tcppullup;
-	kstat_named_t	ip_tcpoptions;
-	kstat_named_t	ip_multipkttcp;
-	kstat_named_t	ip_tcp_fast_path;
-	kstat_named_t	ip_tcp_slow_path;
-	kstat_named_t	ip_tcp_input_error;
-	kstat_named_t	ip_db_ref;
-	kstat_named_t	ip_notaligned1;
-	kstat_named_t	ip_notaligned2;
-	kstat_named_t	ip_multimblk3;
-	kstat_named_t	ip_multimblk4;
-	kstat_named_t	ip_ipoptions;
-	kstat_named_t	ip_classify_fail;
-	kstat_named_t	ip_opt;
-	kstat_named_t	ip_udp_rput_local;
-	kstat_named_t	ipsec_proto_ahesp;
-	kstat_named_t	ip_conn_flputbq;
-	kstat_named_t	ip_conn_walk_drain;
-	kstat_named_t   ip_out_sw_cksum;
-	kstat_named_t   ip_in_sw_cksum;
-	kstat_named_t   ip_trash_ire_reclaim_calls;
-	kstat_named_t   ip_trash_ire_reclaim_success;
-	kstat_named_t   ip_ire_arp_timer_expired;
-	kstat_named_t   ip_ire_redirect_timer_expired;
-	kstat_named_t	ip_ire_pmtu_timer_expired;
-	kstat_named_t	ip_input_multi_squeue;
-	kstat_named_t	ip_tcp_in_full_hw_cksum_err;
-	kstat_named_t	ip_tcp_in_part_hw_cksum_err;
-	kstat_named_t	ip_tcp_in_sw_cksum_err;
-	kstat_named_t	ip_tcp_out_sw_cksum_bytes;
-	kstat_named_t	ip_udp_in_full_hw_cksum_err;
-	kstat_named_t	ip_udp_in_part_hw_cksum_err;
-	kstat_named_t	ip_udp_in_sw_cksum_err;
-	kstat_named_t	ip_udp_out_sw_cksum_bytes;
-	kstat_named_t	ip_frag_mdt_pkt_out;
-	kstat_named_t	ip_frag_mdt_discarded;
-	kstat_named_t	ip_frag_mdt_allocfail;
-	kstat_named_t	ip_frag_mdt_addpdescfail;
-	kstat_named_t	ip_frag_mdt_allocd;
-} ip_stat_t;
-
-static ip_stat_t ip_statistics = {
-	{ "ipsec_fanout_proto",			KSTAT_DATA_UINT64 },
-	{ "ip_udp_fannorm",			KSTAT_DATA_UINT64 },
-	{ "ip_udp_fanmb",			KSTAT_DATA_UINT64 },
-	{ "ip_udp_fanothers",			KSTAT_DATA_UINT64 },
-	{ "ip_udp_fast_path",			KSTAT_DATA_UINT64 },
-	{ "ip_udp_slow_path",			KSTAT_DATA_UINT64 },
-	{ "ip_udp_input_err",			KSTAT_DATA_UINT64 },
-	{ "ip_tcppullup",			KSTAT_DATA_UINT64 },
-	{ "ip_tcpoptions",			KSTAT_DATA_UINT64 },
-	{ "ip_multipkttcp",			KSTAT_DATA_UINT64 },
-	{ "ip_tcp_fast_path",			KSTAT_DATA_UINT64 },
-	{ "ip_tcp_slow_path",			KSTAT_DATA_UINT64 },
-	{ "ip_tcp_input_error",			KSTAT_DATA_UINT64 },
-	{ "ip_db_ref",				KSTAT_DATA_UINT64 },
-	{ "ip_notaligned1",			KSTAT_DATA_UINT64 },
-	{ "ip_notaligned2",			KSTAT_DATA_UINT64 },
-	{ "ip_multimblk3",			KSTAT_DATA_UINT64 },
-	{ "ip_multimblk4",			KSTAT_DATA_UINT64 },
-	{ "ip_ipoptions",			KSTAT_DATA_UINT64 },
-	{ "ip_classify_fail",			KSTAT_DATA_UINT64 },
-	{ "ip_opt",				KSTAT_DATA_UINT64 },
-	{ "ip_udp_rput_local",			KSTAT_DATA_UINT64 },
-	{ "ipsec_proto_ahesp",			KSTAT_DATA_UINT64 },
-	{ "ip_conn_flputbq",			KSTAT_DATA_UINT64 },
-	{ "ip_conn_walk_drain",			KSTAT_DATA_UINT64 },
-	{ "ip_out_sw_cksum",			KSTAT_DATA_UINT64 },
-	{ "ip_in_sw_cksum",			KSTAT_DATA_UINT64 },
-	{ "ip_trash_ire_reclaim_calls",		KSTAT_DATA_UINT64 },
-	{ "ip_trash_ire_reclaim_success",	KSTAT_DATA_UINT64 },
-	{ "ip_ire_arp_timer_expired",		KSTAT_DATA_UINT64 },
-	{ "ip_ire_redirect_timer_expired",	KSTAT_DATA_UINT64 },
-	{ "ip_ire_pmtu_timer_expired",		KSTAT_DATA_UINT64 },
-	{ "ip_input_multi_squeue",		KSTAT_DATA_UINT64 },
-	{ "ip_tcp_in_full_hw_cksum_err",	KSTAT_DATA_UINT64 },
-	{ "ip_tcp_in_part_hw_cksum_err",	KSTAT_DATA_UINT64 },
-	{ "ip_tcp_in_sw_cksum_err",		KSTAT_DATA_UINT64 },
-	{ "ip_tcp_out_sw_cksum_bytes",		KSTAT_DATA_UINT64 },
-	{ "ip_udp_in_full_hw_cksum_err",	KSTAT_DATA_UINT64 },
-	{ "ip_udp_in_part_hw_cksum_err",	KSTAT_DATA_UINT64 },
-	{ "ip_udp_in_sw_cksum_err",		KSTAT_DATA_UINT64 },
-	{ "ip_udp_out_sw_cksum_bytes",		KSTAT_DATA_UINT64 },
-	{ "ip_frag_mdt_pkt_out",		KSTAT_DATA_UINT64 },
-	{ "ip_frag_mdt_discarded",		KSTAT_DATA_UINT64 },
-	{ "ip_frag_mdt_allocfail",		KSTAT_DATA_UINT64 },
-	{ "ip_frag_mdt_addpdescfail",		KSTAT_DATA_UINT64 },
-	{ "ip_frag_mdt_allocd",			KSTAT_DATA_UINT64 },
-};
-
-static kstat_t *ip_kstat;
-
 #define	TCP6 "tcp6"
 #define	TCP "tcp"
 #define	SCTP "sctp"
@@ -249,6 +146,9 @@
 major_t SCTP_MAJ;
 major_t SCTP6_MAJ;
 
+/*
+ * Setable in /etc/system
+ */
 int ip_poll_normal_ms = 100;
 int ip_poll_normal_ticks = 0;
 int ip_modclose_ackwait_ms = 3000;
@@ -709,25 +609,29 @@
 static mblk_t	*ip_wput_attach_llhdr(mblk_t *, ire_t *, ip_proc_t, uint32_t);
 static void	ip_ipsec_out_prepend(mblk_t *, mblk_t *, ill_t *);
 
-static void	icmp_frag_needed(queue_t *, mblk_t *, int, zoneid_t);
+static void	icmp_frag_needed(queue_t *, mblk_t *, int, zoneid_t,
+		    ip_stack_t *);
 static void	icmp_inbound(queue_t *, mblk_t *, boolean_t, ill_t *, int,
-    uint32_t, boolean_t, boolean_t, ill_t *, zoneid_t);
+		    uint32_t, boolean_t, boolean_t, ill_t *, zoneid_t);
 static ipaddr_t	icmp_get_nexthop_addr(ipha_t *, ill_t *, zoneid_t, mblk_t *mp);
 static boolean_t icmp_inbound_too_big(icmph_t *, ipha_t *, ill_t *, zoneid_t,
-		    mblk_t *, int);
+		    mblk_t *, int, ip_stack_t *);
 static void	icmp_inbound_error_fanout(queue_t *, ill_t *, mblk_t *,
 		    icmph_t *, ipha_t *, int, int, boolean_t, boolean_t,
 		    ill_t *, zoneid_t);
 static void	icmp_options_update(ipha_t *);
-static void	icmp_param_problem(queue_t *, mblk_t *, uint8_t, zoneid_t);
+static void	icmp_param_problem(queue_t *, mblk_t *, uint8_t, zoneid_t,
+		    ip_stack_t *);
 static void	icmp_pkt(queue_t *, mblk_t *, void *, size_t, boolean_t,
-		    zoneid_t zoneid);
-static mblk_t	*icmp_pkt_err_ok(mblk_t *);
-static void	icmp_redirect(mblk_t *);
-static void	icmp_send_redirect(queue_t *, mblk_t *, ipaddr_t);
+		    zoneid_t zoneid, ip_stack_t *);
+static mblk_t	*icmp_pkt_err_ok(mblk_t *, ip_stack_t *);
+static void	icmp_redirect(ill_t *, mblk_t *);
+static void	icmp_send_redirect(queue_t *, mblk_t *, ipaddr_t,
+		    ip_stack_t *);
 
 static void	ip_arp_news(queue_t *, mblk_t *);
-static boolean_t ip_bind_insert_ire(mblk_t *, ire_t *, iulp_t *);
+static boolean_t ip_bind_insert_ire(mblk_t *, ire_t *, iulp_t *,
+		    ip_stack_t *);
 mblk_t		*ip_dlpi_alloc(size_t, t_uscalar_t);
 char		*ip_dot_addr(ipaddr_t, char *);
 mblk_t		*ip_carve_mp(mblk_t **, ssize_t);
@@ -740,73 +644,90 @@
 static void	ip_fanout_udp(queue_t *, mblk_t *, ill_t *, ipha_t *, uint32_t,
 		    boolean_t, uint_t, boolean_t, boolean_t, ill_t *, zoneid_t);
 static void	ip_lrput(queue_t *, mblk_t *);
-ipaddr_t	ip_massage_options(ipha_t *);
 static void	ip_mrtun_forward(ire_t *, ill_t *, mblk_t *);
 ipaddr_t	ip_net_mask(ipaddr_t);
 void		ip_newroute(queue_t *, mblk_t *, ipaddr_t, ill_t *, conn_t *,
-		    zoneid_t);
+		    zoneid_t, ip_stack_t *);
 static void	ip_newroute_ipif(queue_t *, mblk_t *, ipif_t *, ipaddr_t,
 		    conn_t *, uint32_t, zoneid_t, ip_opt_info_t *);
 char		*ip_nv_lookup(nv_t *, int);
 static boolean_t	ip_check_for_ipsec_opt(queue_t *, mblk_t *);
 static int	ip_param_get(queue_t *, mblk_t *, caddr_t, cred_t *);
 static int	ip_param_generic_get(queue_t *, mblk_t *, caddr_t, cred_t *);
-static boolean_t	ip_param_register(ipparam_t *, size_t, ipndp_t *,
-			    size_t);
+static boolean_t	ip_param_register(IDP *ndp, ipparam_t *, size_t,
+    ipndp_t *, size_t);
 static int	ip_param_set(queue_t *, mblk_t *, char *, caddr_t, cred_t *);
 void	ip_rput(queue_t *, mblk_t *);
 static void	ip_rput_dlpi_writer(ipsq_t *dummy_sq, queue_t *q, mblk_t *mp,
 		    void *dummy_arg);
 void	ip_rput_forward(ire_t *, ipha_t *, mblk_t *, ill_t *);
-static int	ip_rput_forward_options(mblk_t *, ipha_t *, ire_t *);
+static int	ip_rput_forward_options(mblk_t *, ipha_t *, ire_t *,
+    ip_stack_t *);
 static boolean_t	ip_rput_local_options(queue_t *, mblk_t *, ipha_t *,
-			    ire_t *);
+			    ire_t *, ip_stack_t *);
 static boolean_t	ip_rput_multimblk_ipoptions(queue_t *, ill_t *,
-			    mblk_t *, ipha_t **, ipaddr_t *);
-static int	ip_rput_options(queue_t *, mblk_t *, ipha_t *, ipaddr_t *);
+			    mblk_t *, ipha_t **, ipaddr_t *, ip_stack_t *);
+static int	ip_rput_options(queue_t *, mblk_t *, ipha_t *, ipaddr_t *,
+    ip_stack_t *);
 static boolean_t ip_rput_fragment(queue_t *, mblk_t **, ipha_t *, uint32_t *,
 		    uint16_t *);
 int		ip_snmp_get(queue_t *, mblk_t *);
 static mblk_t	*ip_snmp_get_mib2_ip(queue_t *, mblk_t *,
-		    mib2_ipIfStatsEntry_t *);
-static mblk_t	*ip_snmp_get_mib2_ip_traffic_stats(queue_t *, mblk_t *);
-static mblk_t	*ip_snmp_get_mib2_ip6(queue_t *, mblk_t *);
-static mblk_t	*ip_snmp_get_mib2_icmp(queue_t *, mblk_t *);
-static mblk_t	*ip_snmp_get_mib2_icmp6(queue_t *, mblk_t *);
-static mblk_t	*ip_snmp_get_mib2_igmp(queue_t *, mblk_t *);
-static mblk_t	*ip_snmp_get_mib2_multi(queue_t *, mblk_t *);
-static mblk_t	*ip_snmp_get_mib2_ip_addr(queue_t *, mblk_t *);
-static mblk_t	*ip_snmp_get_mib2_ip6_addr(queue_t *, mblk_t *);
-static mblk_t	*ip_snmp_get_mib2_ip_group_mem(queue_t *, mblk_t *);
-static mblk_t	*ip_snmp_get_mib2_ip6_group_mem(queue_t *, mblk_t *);
-static mblk_t	*ip_snmp_get_mib2_ip_group_src(queue_t *, mblk_t *);
-static mblk_t	*ip_snmp_get_mib2_ip6_group_src(queue_t *, mblk_t *);
-static mblk_t	*ip_snmp_get_mib2_virt_multi(queue_t *, mblk_t *);
-static mblk_t	*ip_snmp_get_mib2_multi_rtable(queue_t *, mblk_t *);
-static mblk_t	*ip_snmp_get_mib2_ip_route_media(queue_t *, mblk_t *);
-static mblk_t	*ip_snmp_get_mib2_ip6_route_media(queue_t *, mblk_t *);
+		    mib2_ipIfStatsEntry_t *, ip_stack_t *);
+static mblk_t	*ip_snmp_get_mib2_ip_traffic_stats(queue_t *, mblk_t *,
+		    ip_stack_t *);
+static mblk_t	*ip_snmp_get_mib2_ip6(queue_t *, mblk_t *, ip_stack_t *);
+static mblk_t	*ip_snmp_get_mib2_icmp(queue_t *, mblk_t *, ip_stack_t *ipst);
+static mblk_t	*ip_snmp_get_mib2_icmp6(queue_t *, mblk_t *, ip_stack_t *ipst);
+static mblk_t	*ip_snmp_get_mib2_igmp(queue_t *, mblk_t *, ip_stack_t *ipst);
+static mblk_t	*ip_snmp_get_mib2_multi(queue_t *, mblk_t *, ip_stack_t *ipst);
+static mblk_t	*ip_snmp_get_mib2_ip_addr(queue_t *, mblk_t *,
+		    ip_stack_t *ipst);
+static mblk_t	*ip_snmp_get_mib2_ip6_addr(queue_t *, mblk_t *,
+		    ip_stack_t *ipst);
+static mblk_t	*ip_snmp_get_mib2_ip_group_src(queue_t *, mblk_t *,
+		    ip_stack_t *ipst);
+static mblk_t	*ip_snmp_get_mib2_ip6_group_src(queue_t *, mblk_t *,
+		    ip_stack_t *ipst);
+static mblk_t	*ip_snmp_get_mib2_ip_group_mem(queue_t *, mblk_t *,
+		    ip_stack_t *ipst);
+static mblk_t	*ip_snmp_get_mib2_ip6_group_mem(queue_t *, mblk_t *,
+		    ip_stack_t *ipst);
+static mblk_t	*ip_snmp_get_mib2_virt_multi(queue_t *, mblk_t *,
+		    ip_stack_t *ipst);
+static mblk_t	*ip_snmp_get_mib2_multi_rtable(queue_t *, mblk_t *,
+		    ip_stack_t *ipst);
+static mblk_t	*ip_snmp_get_mib2_ip_route_media(queue_t *, mblk_t *,
+		    ip_stack_t *ipst);
+static mblk_t	*ip_snmp_get_mib2_ip6_route_media(queue_t *, mblk_t *,
+		    ip_stack_t *ipst);
 static void	ip_snmp_get2_v4(ire_t *, iproutedata_t *);
 static void	ip_snmp_get2_v6_route(ire_t *, iproutedata_t *);
 static int	ip_snmp_get2_v6_media(nce_t *, iproutedata_t *);
 int		ip_snmp_set(queue_t *, int, int, uchar_t *, int);
-static boolean_t	ip_source_routed(ipha_t *);
+static boolean_t	ip_source_routed(ipha_t *, ip_stack_t *);
 static boolean_t	ip_source_route_included(ipha_t *);
+static void	ip_trash_ire_reclaim_stack(ip_stack_t *);
 
 static void	ip_wput_frag(ire_t *, mblk_t *, ip_pkt_t, uint32_t, uint32_t,
-		    zoneid_t);
-static mblk_t	*ip_wput_frag_copyhdr(uchar_t *, int, int);
-static void	ip_wput_local_options(ipha_t *);
+		    zoneid_t, ip_stack_t *);
+static mblk_t	*ip_wput_frag_copyhdr(uchar_t *, int, int, ip_stack_t *);
+static void	ip_wput_local_options(ipha_t *, ip_stack_t *);
 static int	ip_wput_options(queue_t *, mblk_t *, ipha_t *, boolean_t,
-		    zoneid_t);
+		    zoneid_t, ip_stack_t *);
 
-static void	conn_drain_init(void);
-static void	conn_drain_fini(void);
+static void	conn_drain_init(ip_stack_t *);
+static void	conn_drain_fini(ip_stack_t *);
 static void	conn_drain_tail(conn_t *connp, boolean_t closing);
 
-static void	conn_walk_drain(void);
+static void	conn_walk_drain(ip_stack_t *);
 static void	conn_walk_fanout_table(connf_t *, uint_t, pfv_t, void *,
     zoneid_t);
 
+static void	*ip_stack_init(netstackid_t stackid, netstack_t *ns);
+static void	ip_stack_shutdown(netstackid_t stackid, void *arg);
+static void	ip_stack_fini(netstackid_t stackid, void *arg);
+
 static boolean_t	conn_wantpacket(conn_t *, ill_t *, ipha_t *, int,
     zoneid_t);
 static void	ip_arp_done(ipsq_t *dummy_sq, queue_t *q, mblk_t *mp,
@@ -832,12 +753,14 @@
     cred_t *);
 static squeue_func_t ip_squeue_switch(int);
 
-static void	ip_kstat_init(void);
-static void	ip_kstat_fini(void);
+static void	*ip_kstat_init(netstackid_t, ip_stack_t *);
+static void	ip_kstat_fini(netstackid_t, kstat_t *);
 static int	ip_kstat_update(kstat_t *kp, int rw);
-static void	icmp_kstat_init(void);
-static void	icmp_kstat_fini(void);
+static void	*icmp_kstat_init(netstackid_t);
+static void	icmp_kstat_fini(netstackid_t, kstat_t *);
 static int	icmp_kstat_update(kstat_t *kp, int rw);
+static void	*ip_kstat2_init(netstackid_t, ip_stat_t *);
+static void	ip_kstat2_fini(netstackid_t, kstat_t *);
 
 static int	ip_conn_report(queue_t *, mblk_t *, caddr_t, cred_t *);
 
@@ -847,21 +770,13 @@
 static void	ip_rput_process_forward(queue_t *, mblk_t *, ire_t *,
     ipha_t *, ill_t *, boolean_t);
 
-timeout_id_t ip_ire_expire_id;	/* IRE expiration timer. */
-static clock_t ip_ire_arp_time_elapsed; /* Time since IRE cache last flushed */
-static clock_t ip_ire_rd_time_elapsed;	/* ... redirect IREs last flushed */
-static clock_t ip_ire_pmtu_time_elapsed; /* Time since path mtu increase */
-
+static void	ip_rput_process_forward(queue_t *, mblk_t *, ire_t *,
+    ipha_t *, ill_t *, boolean_t);
 ipaddr_t	ip_g_all_ones = IP_HOST_MASK;
-clock_t icmp_pkt_err_last = 0;	/* Time since last icmp_pkt_err */
-uint_t	icmp_pkt_err_sent = 0;	/* Number of packets sent in burst */
 
 /* How long, in seconds, we allow frags to hang around. */
 #define	IP_FRAG_TIMEOUT	60
 
-time_t	ip_g_frag_timeout = IP_FRAG_TIMEOUT;
-clock_t	ip_g_frag_timo_ms = IP_FRAG_TIMEOUT * 1000;
-
 /*
  * Threshold which determines whether MDT should be used when
  * generating IP fragments; payload size must be greater than
@@ -869,49 +784,26 @@
  */
 #define	IP_WPUT_FRAG_MDT_MIN	32768
 
+/* Setable in /etc/system only */
 int	ip_wput_frag_mdt_min = IP_WPUT_FRAG_MDT_MIN;
 
-/* Protected by ip_mi_lock */
-static void	*ip_g_head;		/* Instance Data List Head */
-kmutex_t	ip_mi_lock;		/* Lock for list of instances */
-
-/* Only modified during _init and _fini thus no locking is needed. */
-caddr_t		ip_g_nd;		/* Named Dispatch List Head */
-
-
 static long ip_rput_pullups;
 int	dohwcksum = 1;	/* use h/w cksum if supported by the hardware */
 
 vmem_t *ip_minor_arena;
 
-/*
- * MIB-2 stuff for SNMP (both IP and ICMP)
- */
-mib2_ipIfStatsEntry_t	ip_mib;
-mib2_icmp_t		icmp_mib;
+int	ip_debug;
 
 #ifdef DEBUG
 uint32_t ipsechw_debug = 0;
 #endif
 
-kstat_t		*ip_mibkp;	/* kstat exporting ip_mib data */
-kstat_t		*icmp_mibkp;	/* kstat exporting icmp_mib data */
-
-uint_t	loopback_packets = 0;
-
 /*
  * Multirouting/CGTP stuff
  */
 cgtp_filter_ops_t	*ip_cgtp_filter_ops;	/* CGTP hooks */
 int	ip_cgtp_filter_rev = CGTP_FILTER_REV;	/* CGTP hooks version */
 boolean_t	ip_cgtp_filter;		/* Enable/disable CGTP hooks */
-/* Interval (in ms) between consecutive 'bad MTU' warnings */
-hrtime_t ip_multirt_log_interval = 1000;
-/* Time since last warning issued. */
-static hrtime_t	multirt_bad_mtu_last_time = 0;
-
-kmutex_t ip_trash_timer_lock;
-krwlock_t ip_g_nd_lock;
 
 /*
  * XXX following really should only be in a header. Would need more
@@ -991,17 +883,23 @@
 	{  0,	1,	1,	"ip_lso_outbound" },
 #ifdef DEBUG
 	{  0,	1,	0,	"ip6_drop_inbound_icmpv6" },
+#else
+	{  0,	0,	0,	"" },
 #endif
 };
 
-ipparam_t	*ip_param_arr = lcl_param_arr;
-
-/* Extended NDP table */
+/*
+ * Extended NDP table
+ * The addresses for the first two are filled in to be ips_ip_g_forward
+ * and ips_ipv6_forward at init time.
+ */
 static ipndp_t	lcl_ndp_arr[] = {
 	/* getf			setf		data			name */
-	{  ip_param_generic_get,	ip_forward_set,	(caddr_t)&ip_g_forward,
+#define	IPNDP_IP_FORWARDING_OFFSET	0
+	{  ip_param_generic_get,	ip_forward_set,	NULL,
 	    "ip_forwarding" },
-	{  ip_param_generic_get,	ip_forward_set,	(caddr_t)&ipv6_forward,
+#define	IPNDP_IP6_FORWARDING_OFFSET	1
+	{  ip_param_generic_get,	ip_forward_set,	NULL,
 	    "ip6_forwarding" },
 	{  ip_ill_report,	NULL,		NULL,
 	    "ip_ill_status" },
@@ -1031,31 +929,14 @@
 	    (caddr_t)&ip_squeue_enter, "ip_squeue_enter" },
 	{ ip_param_generic_get, ip_int_set,
 	    (caddr_t)&ip_squeue_fanout, "ip_squeue_fanout" },
-	{  ip_cgtp_filter_get,	ip_cgtp_filter_set, (caddr_t)&ip_cgtp_filter,
+#define	IPNDP_CGTP_FILTER_OFFSET	16
+	{  ip_cgtp_filter_get,	ip_cgtp_filter_set, NULL,
 	    "ip_cgtp_filter" },
 	{ ip_param_generic_get, ip_int_set,
-	    (caddr_t)&ip_soft_rings_cnt, "ip_soft_rings_cnt" }
+	    (caddr_t)&ip_soft_rings_cnt, "ip_soft_rings_cnt" },
 };
 
 /*
- * ip_g_forward controls IP forwarding.  It takes two values:
- *	0: IP_FORWARD_NEVER	Don't forward packets ever.
- *	1: IP_FORWARD_ALWAYS	Forward packets for elsewhere.
- *
- * RFC1122 says there must be a configuration switch to control forwarding,
- * but that the default MUST be to not forward packets ever.  Implicit
- * control based on configuration of multiple interfaces MUST NOT be
- * implemented (Section 3.1).  SunOS 4.1 did provide the "automatic" capability
- * and, in fact, it was the default.  That capability is now provided in the
- * /etc/rc2.d/S69inet script.
- */
-int ip_g_forward = IP_FORWARD_DEFAULT;
-
-/* It also has an IPv6 counterpart. */
-
-int ipv6_forward = IP_FORWARD_DEFAULT;
-
-/*
  * Table of IP ioctls encoding the various properties of the ioctl and
  * indexed based on the last byte of the ioctl command. Occasionally there
  * is a clash, and there is more than 1 ioctl with the same last byte.
@@ -1447,13 +1328,8 @@
 int ip_misc_ioctl_count =
     sizeof (ip_misc_ioctl_table) / sizeof (ip_ioctl_cmd_t);
 
-static  idl_t *conn_drain_list;		/* The array of conn drain lists */
-static  uint_t conn_drain_list_cnt;	/* Total count of conn_drain_list */
-static  int    conn_drain_list_index;	/* Next drain_list to be used */
 int	conn_drain_nthreads;		/* Number of drainers reqd. */
 					/* Settable in /etc/system */
-uint_t	ip_redirect_cnt;		/* Num of redirect routes in ftable */
-
 /* Defined in ip_ire.c */
 extern uint32_t ip_ire_max_bucket_cnt, ip6_ire_max_bucket_cnt;
 extern uint32_t ip_ire_min_bucket_cnt, ip6_ire_min_bucket_cnt;
@@ -1474,15 +1350,9 @@
 
 nv_t	*ire_nv_tbl = ire_nv_arr;
 
-/* Defined in ip_if.c, protect the list of IPsec capable ills */
-extern krwlock_t ipsec_capab_ills_lock;
-
 /* Defined in ip_netinfo.c */
 extern ddi_taskq_t	*eventq_queue_nic;
 
-/* Packet dropper for IP IPsec processing failures */
-ipdropper_t ip_dropper;
-
 /* Simple ICMP IP Header Template */
 static ipha_t icmp_ipha = {
 	IP_SIMPLE_HDR_VERSION, 0, 0, 0, 0, 0, IPPROTO_ICMP
@@ -1532,7 +1402,7 @@
  * appropriately.
  */
 mblk_t *
-ip_prepend_zoneid(mblk_t *mp, zoneid_t zoneid)
+ip_prepend_zoneid(mblk_t *mp, zoneid_t zoneid, ip_stack_t *ipst)
 {
 	mblk_t		*first_mp;
 	ipsec_out_t	*io;
@@ -1545,7 +1415,7 @@
 		return (mp);
 	}
 
-	first_mp = ipsec_alloc_ipsec_out();
+	first_mp = ipsec_alloc_ipsec_out(ipst->ips_netstack);
 	if (first_mp == NULL)
 		return (NULL);
 	io = (ipsec_out_t *)first_mp->b_rptr;
@@ -1580,15 +1450,19 @@
 
 	nmp = copymsg(mp->b_cont);
 
-	if (in->ipsec_info_type == IPSEC_OUT)
-		return (ipsec_out_tag(mp, nmp));
-	else
-		return (ipsec_in_tag(mp, nmp));
+	if (in->ipsec_info_type == IPSEC_OUT) {
+		return (ipsec_out_tag(mp, nmp,
+			    ((ipsec_out_t *)in)->ipsec_out_ns));
+	} else {
+		return (ipsec_in_tag(mp, nmp,
+			    ((ipsec_in_t *)in)->ipsec_in_ns));
+	}
 }
 
 /* Generate an ICMP fragmentation needed message. */
 static void
-icmp_frag_needed(queue_t *q, mblk_t *mp, int mtu, zoneid_t zoneid)
+icmp_frag_needed(queue_t *q, mblk_t *mp, int mtu, zoneid_t zoneid,
+    ip_stack_t *ipst)
 {
 	icmph_t	icmph;
 	mblk_t *first_mp;
@@ -1596,7 +1470,7 @@
 
 	EXTRACT_PKT_MP(mp, first_mp, mctl_present);
 
-	if (!(mp = icmp_pkt_err_ok(mp))) {
+	if (!(mp = icmp_pkt_err_ok(mp, ipst))) {
 		if (mctl_present)
 			freeb(first_mp);
 		return;
@@ -1606,9 +1480,10 @@
 	icmph.icmph_type = ICMP_DEST_UNREACHABLE;
 	icmph.icmph_code = ICMP_FRAGMENTATION_NEEDED;
 	icmph.icmph_du_mtu = htons((uint16_t)mtu);
-	BUMP_MIB(&icmp_mib, icmpOutFragNeeded);
-	BUMP_MIB(&icmp_mib, icmpOutDestUnreachs);
-	icmp_pkt(q, first_mp, &icmph, sizeof (icmph_t), mctl_present, zoneid);
+	BUMP_MIB(&ipst->ips_icmp_mib, icmpOutFragNeeded);
+	BUMP_MIB(&ipst->ips_icmp_mib, icmpOutDestUnreachs);
+	icmp_pkt(q, first_mp, &icmph, sizeof (icmph_t), mctl_present, zoneid,
+	    ipst);
 }
 
 /*
@@ -1720,8 +1595,10 @@
 	boolean_t onlink;
 	timestruc_t now;
 	uint32_t ill_index;
+	ip_stack_t *ipst;
 
 	ASSERT(ill != NULL);
+	ipst = ill->ill_ipst;
 
 	first_mp = mp;
 	if (mctl_present) {
@@ -1730,9 +1607,9 @@
 	}
 
 	ipha = (ipha_t *)mp->b_rptr;
-	if (icmp_accept_clear_messages == 0) {
+	if (ipst->ips_icmp_accept_clear_messages == 0) {
 		first_mp = ipsec_check_global_policy(first_mp, NULL,
-		    ipha, NULL, mctl_present);
+		    ipha, NULL, mctl_present, ipst->ips_netstack);
 		if (first_mp == NULL)
 			return;
 	}
@@ -1747,7 +1624,7 @@
 		if (!tsol_can_accept_raw(mp, B_FALSE)) {
 			ip1dbg(("icmp_inbound: zone %d can't receive raw",
 			    zoneid));
-			BUMP_MIB(&icmp_mib, icmpInErrors);
+			BUMP_MIB(&ipst->ips_icmp_mib, icmpInErrors);
 			freemsg(first_mp);
 			return;
 		}
@@ -1762,12 +1639,12 @@
 
 	ASSERT(ill != NULL);
 
-	BUMP_MIB(&icmp_mib, icmpInMsgs);
+	BUMP_MIB(&ipst->ips_icmp_mib, icmpInMsgs);
 	iph_hdr_length = IPH_HDR_LENGTH(ipha);
 	if ((mp->b_wptr - mp->b_rptr) < (iph_hdr_length + ICMPH_SIZE)) {
 		/* Last chance to get real. */
 		if (!pullupmsg(mp, iph_hdr_length + ICMPH_SIZE)) {
-			BUMP_MIB(&icmp_mib, icmpInErrors);
+			BUMP_MIB(&ipst->ips_icmp_mib, icmpInErrors);
 			freemsg(first_mp);
 			return;
 		}
@@ -1777,7 +1654,7 @@
 	/* ICMP header checksum, including checksum field, should be zero. */
 	if (sum_valid ? (sum != 0 && sum != 0xFFFF) :
 	    IP_CSUM(mp, iph_hdr_length, 0)) {
-		BUMP_MIB(&icmp_mib, icmpInCksumErrs);
+		BUMP_MIB(&ipst->ips_icmp_mib, icmpInCksumErrs);
 		freemsg(first_mp);
 		return;
 	}
@@ -1790,22 +1667,22 @@
 	interested = B_FALSE;
 	switch (icmph->icmph_type) {
 	case ICMP_ECHO_REPLY:
-		BUMP_MIB(&icmp_mib, icmpInEchoReps);
+		BUMP_MIB(&ipst->ips_icmp_mib, icmpInEchoReps);
 		break;
 	case ICMP_DEST_UNREACHABLE:
 		if (icmph->icmph_code == ICMP_FRAGMENTATION_NEEDED)
-			BUMP_MIB(&icmp_mib, icmpInFragNeeded);
+			BUMP_MIB(&ipst->ips_icmp_mib, icmpInFragNeeded);
 		interested = B_TRUE;	/* Pass up to transport */
-		BUMP_MIB(&icmp_mib, icmpInDestUnreachs);
+		BUMP_MIB(&ipst->ips_icmp_mib, icmpInDestUnreachs);
 		break;
 	case ICMP_SOURCE_QUENCH:
 		interested = B_TRUE;	/* Pass up to transport */
-		BUMP_MIB(&icmp_mib, icmpInSrcQuenchs);
+		BUMP_MIB(&ipst->ips_icmp_mib, icmpInSrcQuenchs);
 		break;
 	case ICMP_REDIRECT:
-		if (!ip_ignore_redirect)
+		if (!ipst->ips_ip_ignore_redirect)
 			interested = B_TRUE;
-		BUMP_MIB(&icmp_mib, icmpInRedirects);
+		BUMP_MIB(&ipst->ips_icmp_mib, icmpInRedirects);
 		break;
 	case ICMP_ECHO_REQUEST:
 		/*
@@ -1819,29 +1696,29 @@
 			interested = B_TRUE;
 		} else if (CLASSD(ipha->ipha_dst)) {
 			/* multicast: respond based on tunable */
-			interested = ip_g_resp_to_echo_mcast;
+			interested = ipst->ips_ip_g_resp_to_echo_mcast;
 		} else if (broadcast) {
 			/* broadcast: respond based on tunable */
-			interested = ip_g_resp_to_echo_bcast;
+			interested = ipst->ips_ip_g_resp_to_echo_bcast;
 		}
-		BUMP_MIB(&icmp_mib, icmpInEchos);
+		BUMP_MIB(&ipst->ips_icmp_mib, icmpInEchos);
 		break;
 	case ICMP_ROUTER_ADVERTISEMENT:
 	case ICMP_ROUTER_SOLICITATION:
 		break;
 	case ICMP_TIME_EXCEEDED:
 		interested = B_TRUE;	/* Pass up to transport */
-		BUMP_MIB(&icmp_mib, icmpInTimeExcds);
+		BUMP_MIB(&ipst->ips_icmp_mib, icmpInTimeExcds);
 		break;
 	case ICMP_PARAM_PROBLEM:
 		interested = B_TRUE;	/* Pass up to transport */
-		BUMP_MIB(&icmp_mib, icmpInParmProbs);
+		BUMP_MIB(&ipst->ips_icmp_mib, icmpInParmProbs);
 		break;
 	case ICMP_TIME_STAMP_REQUEST:
 		/* Response to Time Stamp Requests is local policy. */
-		if (ip_g_resp_to_timestamp &&
+		if (ipst->ips_ip_g_resp_to_timestamp &&
 		    /* So is whether to respond if it was an IP broadcast. */
-		    (!broadcast || ip_g_resp_to_timestamp_bcast)) {
+		    (!broadcast || ipst->ips_ip_g_resp_to_timestamp_bcast)) {
 			int tstamp_len = 3 * sizeof (uint32_t);
 
 			if (wptr +  tstamp_len > mp->b_wptr) {
@@ -1859,32 +1736,33 @@
 			}
 			interested = B_TRUE;
 		}
-		BUMP_MIB(&icmp_mib, icmpInTimestamps);
+		BUMP_MIB(&ipst->ips_icmp_mib, icmpInTimestamps);
 		break;
 	case ICMP_TIME_STAMP_REPLY:
-		BUMP_MIB(&icmp_mib, icmpInTimestampReps);
+		BUMP_MIB(&ipst->ips_icmp_mib, icmpInTimestampReps);
 		break;
 	case ICMP_INFO_REQUEST:
 		/* Per RFC 1122 3.2.2.7, ignore this. */
 	case ICMP_INFO_REPLY:
 		break;
 	case ICMP_ADDRESS_MASK_REQUEST:
-		if ((ip_respond_to_address_mask_broadcast || !broadcast) &&
+		if ((ipst->ips_ip_respond_to_address_mask_broadcast ||
+			!broadcast) &&
 		    /* TODO m_pullup of complete header? */
 		    (mp->b_datap->db_lim - wptr) >= IP_ADDR_LEN)
 			interested = B_TRUE;
-		BUMP_MIB(&icmp_mib, icmpInAddrMasks);
+		BUMP_MIB(&ipst->ips_icmp_mib, icmpInAddrMasks);
 		break;
 	case ICMP_ADDRESS_MASK_REPLY:
-		BUMP_MIB(&icmp_mib, icmpInAddrMaskReps);
+		BUMP_MIB(&ipst->ips_icmp_mib, icmpInAddrMaskReps);
 		break;
 	default:
 		interested = B_TRUE;	/* Pass up to transport */
-		BUMP_MIB(&icmp_mib, icmpInUnknowns);
+		BUMP_MIB(&ipst->ips_icmp_mib, icmpInUnknowns);
 		break;
 	}
 	/* See if there is an ICMP client. */
-	if (ipcl_proto_search(IPPROTO_ICMP) != NULL) {
+	if (ipst->ips_ipcl_proto_fanout[IPPROTO_ICMP].connf_head != NULL) {
 		/* If there is an ICMP client and we want one too, copy it. */
 		mblk_t *first_mp1;
 
@@ -1906,14 +1784,14 @@
 		 * Initiate policy processing for this packet if ip_policy
 		 * is true.
 		 */
-		if (IPP_ENABLED(IPP_LOCAL_IN) && ip_policy) {
+		if (IPP_ENABLED(IPP_LOCAL_IN, ipst) && ip_policy) {
 			ill_index = ill->ill_phyint->phyint_ifindex;
 			ip_process(IPP_LOCAL_IN, &mp, ill_index);
 			if (mp == NULL) {
 				if (mctl_present) {
 					freeb(first_mp);
 				}
-				BUMP_MIB(&icmp_mib, icmpInErrors);
+				BUMP_MIB(&ipst->ips_icmp_mib, icmpInErrors);
 				return;
 			}
 		}
@@ -1926,7 +1804,7 @@
 		first_mp1 = ip_copymsg(first_mp);
 		freemsg(first_mp);
 		if (!first_mp1) {
-			BUMP_MIB(&icmp_mib, icmpOutDrops);
+			BUMP_MIB(&ipst->ips_icmp_mib, icmpOutDrops);
 			return;
 		}
 		first_mp = first_mp1;
@@ -1954,11 +1832,11 @@
 		icmph->icmph_type = ICMP_ADDRESS_MASK_REPLY;
 		bcopy(&ipif->ipif_net_mask, wptr, IP_ADDR_LEN);
 		ipif_refrele(ipif);
-		BUMP_MIB(&icmp_mib, icmpOutAddrMaskReps);
+		BUMP_MIB(&ipst->ips_icmp_mib, icmpOutAddrMaskReps);
 		break;
 	case ICMP_ECHO_REQUEST:
 		icmph->icmph_type = ICMP_ECHO_REPLY;
-		BUMP_MIB(&icmp_mib, icmpOutEchoReps);
+		BUMP_MIB(&ipst->ips_icmp_mib, icmpOutEchoReps);
 		break;
 	case ICMP_TIME_STAMP_REQUEST: {
 		uint32_t *tsp;
@@ -1972,7 +1850,7 @@
 		    now.tv_nsec / (NANOSEC / MILLISEC);
 		*tsp++ = htonl(ts);	/* Lay in 'receive time' */
 		*tsp++ = htonl(ts);	/* Lay in 'send time' */
-		BUMP_MIB(&icmp_mib, icmpOutTimestampReps);
+		BUMP_MIB(&ipst->ips_icmp_mib, icmpOutTimestampReps);
 		break;
 	}
 	default:
@@ -2016,12 +1894,12 @@
 			if (mctl_present) {
 				freeb(first_mp);
 			}
-			icmp_redirect(mp);
+			icmp_redirect(ill, mp);
 			return;
 		case ICMP_DEST_UNREACHABLE:
 			if (icmph->icmph_code == ICMP_FRAGMENTATION_NEEDED) {
 				if (!icmp_inbound_too_big(icmph, ipha, ill,
-				    zoneid, mp, iph_hdr_length)) {
+				    zoneid, mp, iph_hdr_length, ipst)) {
 					freemsg(first_mp);
 					return;
 				}
@@ -2086,7 +1964,7 @@
 		ipif_refrele(ipif);
 	}
 	/* Reset time to live. */
-	ipha->ipha_ttl = ip_def_ttl;
+	ipha->ipha_ttl = ipst->ips_ip_def_ttl;
 	{
 		/* Swap source and destination addresses */
 		ipaddr_t tmp;
@@ -2132,7 +2010,7 @@
 		 * accept packets for them afterwards.
 		 */
 		src_ire = ire_ctable_lookup(ipha->ipha_dst, 0, IRE_LOCAL,
-		    NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE);
+		    NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE, ipst);
 		if (src_ire == NULL) {
 			ipif = ipif_get_next_ipif(NULL, ill);
 			if (ipif == NULL) {
@@ -2142,7 +2020,7 @@
 			}
 			src_ire = ire_ftable_lookup(ipha->ipha_dst, 0, 0,
 			    IRE_INTERFACE, ipif, NULL, ALL_ZONES, 0,
-			    NULL, MATCH_IRE_ILL | MATCH_IRE_TYPE);
+			    NULL, MATCH_IRE_ILL | MATCH_IRE_TYPE, ipst);
 			ipif_refrele(ipif);
 			if (src_ire != NULL) {
 				onlink = B_TRUE;
@@ -2160,7 +2038,8 @@
 		 * we attach a IPSEC_IN mp and clear ipsec_in_secure.
 		 */
 		ASSERT(first_mp == mp);
-		if ((first_mp = ipsec_in_alloc(B_TRUE)) == NULL) {
+		first_mp = ipsec_in_alloc(B_TRUE, ipst->ips_netstack);
+		if (first_mp == NULL) {
 			BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards);
 			freemsg(mp);
 			return;
@@ -2182,8 +2061,10 @@
 		ii->ipsec_in_attach_if = B_TRUE;
 		ii->ipsec_in_ill_index = ill->ill_phyint->phyint_ifindex;
 		ii->ipsec_in_rill_index = recv_ill->ill_phyint->phyint_ifindex;
+		ii->ipsec_in_ns = ipst->ips_netstack;	/* No netstack_hold */
 	} else {
 		ii = (ipsec_in_t *)first_mp->b_rptr;
+		ii->ipsec_in_ns = ipst->ips_netstack;	/* No netstack_hold */
 	}
 	ii->ipsec_in_zoneid = zoneid;
 	ASSERT(zoneid != ALL_ZONES);
@@ -2191,7 +2072,7 @@
 		BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards);
 		return;
 	}
-	BUMP_MIB(&icmp_mib, icmpOutMsgs);
+	BUMP_MIB(&ipst->ips_icmp_mib, icmpOutMsgs);
 	put(WR(q), first_mp);
 }
 
@@ -2204,6 +2085,7 @@
 	int hdr_length = IPH_HDR_LENGTH(ipha);
 	uint16_t *up;
 	uint32_t ports;
+	ip_stack_t *ipst = ill->ill_ipst;
 
 	up = (uint16_t *)((uchar_t *)ipha + hdr_length);
 	switch (ipha->ipha_protocol) {
@@ -2214,7 +2096,7 @@
 			/* do a reverse lookup */
 			tcph = (tcph_t *)((uchar_t *)ipha + hdr_length);
 			connp = ipcl_tcp_lookup_reversed_ipv4(ipha, tcph,
-			    TCPS_LISTEN);
+			    TCPS_LISTEN, ipst);
 			break;
 		}
 		case IPPROTO_UDP:
@@ -2228,7 +2110,8 @@
 			dstport = htons(ntohl(ports) & 0xFFFF);
 			srcport = htons(ntohl(ports) >> 16);
 
-			connfp = &ipcl_udp_fanout[IPCL_UDP_HASH(dstport)];
+			connfp = &ipst->ips_ipcl_udp_fanout[
+			    IPCL_UDP_HASH(dstport, ipst)];
 			mutex_enter(&connfp->connf_lock);
 			connp = connfp->connf_head;
 
@@ -2253,10 +2136,11 @@
 			((uint16_t *)&ports)[0] = up[1];
 			((uint16_t *)&ports)[1] = up[0];
 
-			if ((connp = sctp_find_conn(&map_src, &map_dst, ports,
-			    0, zoneid)) == NULL) {
+			connp = sctp_find_conn(&map_src, &map_dst, ports,
+			    0, zoneid, ipst->ips_netstack->netstack_sctp);
+			if (connp == NULL) {
 				connp = ipcl_classify_raw(mp, IPPROTO_SCTP,
-				    zoneid, ports, ipha);
+				    zoneid, ports, ipha, ipst);
 			} else {
 				CONN_INC_REF(connp);
 				SCTP_REFRELE(CONN2SCTP(connp));
@@ -2271,7 +2155,8 @@
 			ripha.ipha_dst = ipha->ipha_src;
 			ripha.ipha_protocol = ipha->ipha_protocol;
 
-			connfp = &ipcl_proto_fanout[ipha->ipha_protocol];
+			connfp = &ipst->ips_ipcl_proto_fanout[
+			    ipha->ipha_protocol];
 			mutex_enter(&connfp->connf_lock);
 			connp = connfp->connf_head;
 			for (connp = connfp->connf_head; connp != NULL;
@@ -2308,7 +2193,8 @@
  */
 static boolean_t
 icmp_inbound_too_big(icmph_t *icmph, ipha_t *ipha, ill_t *ill,
-    zoneid_t zoneid, mblk_t *mp, int iph_hdr_length)
+    zoneid_t zoneid, mblk_t *mp, int iph_hdr_length,
+    ip_stack_t *ipst)
 {
 	ire_t	*ire, *first_ire;
 	int	mtu;
@@ -2345,11 +2231,11 @@
 		/* nexthop set */
 		first_ire = ire_ctable_lookup(ipha->ipha_dst,
 		    nexthop_addr, 0, NULL, ALL_ZONES, MBLK_GETLABEL(mp),
-		    MATCH_IRE_MARK_PRIVATE_ADDR | MATCH_IRE_GW);
+		    MATCH_IRE_MARK_PRIVATE_ADDR | MATCH_IRE_GW, ipst);
 	} else {
 		/* nexthop not set */
 		first_ire = ire_ctable_lookup(ipha->ipha_dst, 0, IRE_CACHE,
-		    NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE);
+		    NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE, ipst);
 	}
 
 	if (!first_ire) {
@@ -2553,9 +2439,13 @@
 	ipsec_in_t *ii;
 	tcph_t	*tcph;
 	conn_t	*connp;
+	ip_stack_t *ipst;
 
 	ASSERT(ill != NULL);
 
+	ASSERT(recv_ill != NULL);
+	ipst = recv_ill->ill_ipst;
+
 	first_mp = mp;
 	if (mctl_present) {
 		mp = first_mp->b_cont;
@@ -2628,7 +2518,8 @@
 		 * in the form we sent it out.
 		 */
 		tcph = (tcph_t *)((uchar_t *)ipha + hdr_length);
-		connp = ipcl_tcp_lookup_reversed_ipv4(ipha, tcph, TCPS_LISTEN);
+		connp = ipcl_tcp_lookup_reversed_ipv4(ipha, tcph, TCPS_LISTEN,
+		    ipst);
 		if (connp == NULL)
 			goto discard_pkt;
 
@@ -2677,6 +2568,7 @@
 	case IPPROTO_ESP:
 	case IPPROTO_AH: {
 		int ipsec_rc;
+		ipsec_stack_t *ipss = ipst->ips_netstack->netstack_ipsec;
 
 		/*
 		 * We need a IPSEC_IN in the front to fanout to AH/ESP.
@@ -2718,7 +2610,7 @@
 			 * to locate the ill.
 			 */
 			ASSERT(first_mp == mp);
-			first_mp = ipsec_in_alloc(B_TRUE);
+			first_mp = ipsec_in_alloc(B_TRUE, ipst->ips_netstack);
 			if (first_mp == NULL) {
 				freemsg(mp);
 				BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards);
@@ -2738,8 +2630,8 @@
 		}
 		ip2dbg(("icmp_inbound_error: ipsec\n"));
 
-		if (!ipsec_loaded()) {
-			ip_proto_not_sup(q, first_mp, 0, zoneid);
+		if (!ipsec_loaded(ipss)) {
+			ip_proto_not_sup(q, first_mp, 0, zoneid, ipst);
 			return;
 		}
 
@@ -3139,9 +3031,8 @@
 /*
  * Process received ICMP Redirect messages.
  */
-/* ARGSUSED */
 static void
-icmp_redirect(mblk_t *mp)
+icmp_redirect(ill_t *ill, mblk_t *mp)
 {
 	ipha_t	*ipha;
 	int	iph_hdr_length;
@@ -3153,12 +3044,16 @@
 	ipaddr_t  src, dst, gateway;
 	iulp_t	ulp_info = { 0 };
 	int	error;
+	ip_stack_t *ipst;
+
+	ASSERT(ill != NULL);
+	ipst = ill->ill_ipst;
 
 	ipha = (ipha_t *)mp->b_rptr;
 	iph_hdr_length = IPH_HDR_LENGTH(ipha);
 	if (((mp->b_wptr - mp->b_rptr) - iph_hdr_length) <
 	    sizeof (icmph_t) + IP_SIMPLE_HDR_LENGTH) {
-		BUMP_MIB(&icmp_mib, icmpInErrors);
+		BUMP_MIB(&ipst->ips_icmp_mib, icmpInErrors);
 		freemsg(mp);
 		return;
 	}
@@ -3169,14 +3064,14 @@
 	gateway = icmph->icmph_rd_gateway;
 	/* Make sure the new gateway is reachable somehow. */
 	ire = ire_route_lookup(gateway, 0, 0, IRE_INTERFACE, NULL, NULL,
-	    ALL_ZONES, NULL, MATCH_IRE_TYPE);
+	    ALL_ZONES, NULL, MATCH_IRE_TYPE, ipst);
 	/*
 	 * Make sure we had a route for the dest in question and that
 	 * that route was pointing to the old gateway (the source of the
 	 * redirect packet.)
 	 */
 	prev_ire = ire_route_lookup(dst, 0, src, 0, NULL, NULL, ALL_ZONES,
-	    NULL, MATCH_IRE_GW);
+	    NULL, MATCH_IRE_GW, ipst);
 	/*
 	 * Check that
 	 *	the redirect was not from ourselves
@@ -3185,7 +3080,7 @@
 	if (!prev_ire ||
 	    !ire ||
 	    ire->ire_type == IRE_LOCAL) {
-		BUMP_MIB(&icmp_mib, icmpInBadRedirects);
+		BUMP_MIB(&ipst->ips_icmp_mib, icmpInBadRedirects);
 		freemsg(mp);
 		if (ire != NULL)
 			ire_refrele(ire);
@@ -3217,7 +3112,8 @@
 
 		tmp_ire = ire_ftable_lookup(dst, 0, gateway, 0, NULL, &sire,
 		    ALL_ZONES, 0, NULL,
-		    (MATCH_IRE_RECURSIVE | MATCH_IRE_GW | MATCH_IRE_DEFAULT));
+		    (MATCH_IRE_RECURSIVE | MATCH_IRE_GW | MATCH_IRE_DEFAULT),
+		    ipst);
 		if (sire != NULL) {
 			bcopy(&sire->ire_uinfo, &ulp_info, sizeof (iulp_t));
 			/*
@@ -3249,7 +3145,7 @@
 		break;
 	default:
 		freemsg(mp);
-		BUMP_MIB(&icmp_mib, icmpInBadRedirects);
+		BUMP_MIB(&ipst->ips_icmp_mib, icmpInBadRedirects);
 		ire_refrele(ire);
 		return;
 	}
@@ -3278,7 +3174,8 @@
 		(RTF_DYNAMIC | RTF_GATEWAY | RTF_HOST),
 		&ulp_info,
 		NULL,
-		NULL);
+		NULL,
+		ipst);
 
 	if (ire == NULL) {
 		freemsg(mp);
@@ -3287,14 +3184,14 @@
 	}
 	error = ire_add(&ire, NULL, NULL, NULL, B_FALSE);
 	ire_refrele(save_ire);
-	atomic_inc_32(&ip_redirect_cnt);
+	atomic_inc_32(&ipst->ips_ip_redirect_cnt);
 
 	if (error == 0) {
 		ire_refrele(ire);		/* Held in ire_add_v4 */
 		/* tell routing sockets that we received a redirect */
 		ip_rts_change(RTM_REDIRECT, dst, gateway, IP_HOST_MASK, 0, src,
 		    (RTF_DYNAMIC | RTF_GATEWAY | RTF_HOST), 0,
-		    (RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_AUTHOR));
+		    (RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_AUTHOR), ipst);
 	}
 
 	/*
@@ -3303,7 +3200,7 @@
 	 * modifying an existing redirect.
 	 */
 	prev_ire = ire_ftable_lookup(dst, 0, src, IRE_HOST, NULL, NULL,
-	    ALL_ZONES, 0, NULL, (MATCH_IRE_GW | MATCH_IRE_TYPE));
+	    ALL_ZONES, 0, NULL, (MATCH_IRE_GW | MATCH_IRE_TYPE), ipst);
 	if (prev_ire != NULL) {
 		if (prev_ire ->ire_flags & RTF_DYNAMIC)
 			ire_delete(prev_ire);
@@ -3317,7 +3214,8 @@
  * Generate an ICMP parameter problem message.
  */
 static void
-icmp_param_problem(queue_t *q, mblk_t *mp, uint8_t ptr, zoneid_t zoneid)
+icmp_param_problem(queue_t *q, mblk_t *mp, uint8_t ptr, zoneid_t zoneid,
+	ip_stack_t *ipst)
 {
 	icmph_t	icmph;
 	boolean_t mctl_present;
@@ -3325,7 +3223,7 @@
 
 	EXTRACT_PKT_MP(mp, first_mp, mctl_present);
 
-	if (!(mp = icmp_pkt_err_ok(mp))) {
+	if (!(mp = icmp_pkt_err_ok(mp, ipst))) {
 		if (mctl_present)
 			freeb(first_mp);
 		return;
@@ -3334,8 +3232,9 @@
 	bzero(&icmph, sizeof (icmph_t));
 	icmph.icmph_type = ICMP_PARAM_PROBLEM;
 	icmph.icmph_pp_ptr = ptr;
-	BUMP_MIB(&icmp_mib, icmpOutParmProbs);
-	icmp_pkt(q, first_mp, &icmph, sizeof (icmph_t), mctl_present, zoneid);
+	BUMP_MIB(&ipst->ips_icmp_mib, icmpOutParmProbs);
+	icmp_pkt(q, first_mp, &icmph, sizeof (icmph_t), mctl_present, zoneid,
+	    ipst);
 }
 
 /*
@@ -3352,7 +3251,7 @@
  */
 static void
 icmp_pkt(queue_t *q, mblk_t *mp, void *stuff, size_t len,
-    boolean_t mctl_present, zoneid_t zoneid)
+    boolean_t mctl_present, zoneid_t zoneid, ip_stack_t *ipst)
 {
 	ipaddr_t dst;
 	icmph_t	*icmph;
@@ -3394,7 +3293,8 @@
 			 * Convert the IPSEC_IN to IPSEC_OUT.
 			 */
 			if (!ipsec_in_to_out(ipsec_mp, ipha, NULL)) {
-				BUMP_MIB(&ip_mib, ipIfStatsOutDiscards);
+				BUMP_MIB(&ipst->ips_ip_mib,
+				    ipIfStatsOutDiscards);
 				return;
 			}
 			io = (ipsec_out_t *)ipsec_mp->b_rptr;
@@ -3422,9 +3322,10 @@
 		 */
 		ipsec_in_t *ii;
 		ASSERT(DB_TYPE(mp) == M_DATA);
-		if ((ipsec_mp = ipsec_in_alloc(B_TRUE)) == NULL) {
+		ipsec_mp = ipsec_in_alloc(B_TRUE, ipst->ips_netstack);
+		if (ipsec_mp == NULL) {
 			freemsg(mp);
-			BUMP_MIB(&ip_mib, ipIfStatsOutDiscards);
+			BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsOutDiscards);
 			return;
 		}
 		ii = (ipsec_in_t *)ipsec_mp->b_rptr;
@@ -3445,7 +3346,7 @@
 		 * Convert the IPSEC_IN to IPSEC_OUT.
 		 */
 		if (!ipsec_in_to_out(ipsec_mp, ipha, NULL)) {
-			BUMP_MIB(&ip_mib, ipIfStatsOutDiscards);
+			BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsOutDiscards);
 			return;
 		}
 		io = (ipsec_out_t *)ipsec_mp->b_rptr;
@@ -3455,7 +3356,7 @@
 	dst = ipha->ipha_src;
 
 	ire = ire_route_lookup(ipha->ipha_dst, 0, 0, (IRE_LOCAL|IRE_LOOPBACK),
-	    NULL, NULL, zoneid, NULL, MATCH_IRE_TYPE);
+	    NULL, NULL, zoneid, NULL, MATCH_IRE_TYPE, ipst);
 	if (ire != NULL &&
 	    (ire->ire_zoneid == zoneid || ire->ire_zoneid == ALL_ZONES)) {
 		src = ipha->ipha_dst;
@@ -3463,9 +3364,10 @@
 		if (ire != NULL)
 			ire_refrele(ire);
 		ire = ire_route_lookup(dst, 0, 0, 0, NULL, NULL, zoneid, NULL,
-		    (MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE|MATCH_IRE_ZONEONLY));
+		    (MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE|MATCH_IRE_ZONEONLY),
+		    ipst);
 		if (ire == NULL) {
-			BUMP_MIB(&ip_mib, ipIfStatsOutNoRoutes);
+			BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsOutNoRoutes);
 			freemsg(ipsec_mp);
 			return;
 		}
@@ -3481,18 +3383,18 @@
 		 */
 		if (io == NULL) {
 			/* This is not a IPSEC_OUT type control msg */
-			BUMP_MIB(&ip_mib, ipIfStatsOutNoRoutes);
+			BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsOutNoRoutes);
 			freemsg(ipsec_mp);
 			return;
 		}
 		ill = ill_lookup_on_ifindex(io->ipsec_out_ill_index, B_FALSE,
-		    NULL, NULL, NULL, NULL);
+		    NULL, NULL, NULL, NULL, ipst);
 		if (ill != NULL) {
 			ipif = ipif_get_next_ipif(NULL, ill);
 			ill_refrele(ill);
 		}
 		if (ipif == NULL) {
-			BUMP_MIB(&ip_mib, ipIfStatsOutNoRoutes);
+			BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsOutNoRoutes);
 			freemsg(ipsec_mp);
 			return;
 		}
@@ -3512,7 +3414,7 @@
 	    (uchar_t *)ipha + len_needed + 1 <= mp->b_wptr) {
 		len_needed += IPH_HDR_LENGTH(((uchar_t *)ipha + len_needed));
 	}
-	len_needed += ip_icmp_return;
+	len_needed += ipst->ips_ip_icmp_return;
 	msg_len = msgdsize(mp);
 	if (msg_len > len_needed) {
 		(void) adjmsg(mp, len_needed - msg_len);
@@ -3520,7 +3422,7 @@
 	}
 	mp1 = allocb(sizeof (icmp_ipha) + len, BPRI_HI);
 	if (mp1 == NULL) {
-		BUMP_MIB(&icmp_mib, icmpOutErrors);
+		BUMP_MIB(&ipst->ips_icmp_mib, icmpOutErrors);
 		freemsg(ipsec_mp);
 		return;
 	}
@@ -3551,7 +3453,7 @@
 	*ipha = icmp_ipha;
 	ipha->ipha_src = src;
 	ipha->ipha_dst = dst;
-	ipha->ipha_ttl = ip_def_ttl;
+	ipha->ipha_ttl = ipst->ips_ip_def_ttl;
 	msg_len += sizeof (icmp_ipha) + len;
 	if (msg_len > IP_MAXPACKET) {
 		(void) adjmsg(mp, IP_MAXPACKET - msg_len);
@@ -3564,7 +3466,7 @@
 	icmph->icmph_checksum = IP_CSUM(mp, (int32_t)sizeof (ipha_t), 0);
 	if (icmph->icmph_checksum == 0)
 		icmph->icmph_checksum = 0xFFFF;
-	BUMP_MIB(&icmp_mib, icmpOutMsgs);
+	BUMP_MIB(&ipst->ips_icmp_mib, icmpOutMsgs);
 	put(q, ipsec_mp);
 }
 
@@ -3579,42 +3481,43 @@
  *	icmp_pkt_err_sent - number of packets sent in current burst
  */
 boolean_t
-icmp_err_rate_limit(void)
+icmp_err_rate_limit(ip_stack_t *ipst)
 {
 	clock_t now = TICK_TO_MSEC(lbolt);
 	uint_t refilled; /* Number of packets refilled in tbf since last */
-	uint_t err_interval = ip_icmp_err_interval; /* Guard against changes */
+	/* Guard against changes by loading into local variable */
+	uint_t err_interval = ipst->ips_ip_icmp_err_interval;
 
 	if (err_interval == 0)
 		return (B_FALSE);
 
-	if (icmp_pkt_err_last > now) {
+	if (ipst->ips_icmp_pkt_err_last > now) {
 		/* 100HZ lbolt in ms for 32bit arch wraps every 49.7 days */
-		icmp_pkt_err_last = 0;
-		icmp_pkt_err_sent = 0;
+		ipst->ips_icmp_pkt_err_last = 0;
+		ipst->ips_icmp_pkt_err_sent = 0;
 	}
 	/*
 	 * If we are in a burst update the token bucket filter.
 	 * Update the "last" time to be close to "now" but make sure
 	 * we don't loose precision.
 	 */
-	if (icmp_pkt_err_sent != 0) {
-		refilled = (now - icmp_pkt_err_last)/err_interval;
-		if (refilled > icmp_pkt_err_sent) {
-			icmp_pkt_err_sent = 0;
+	if (ipst->ips_icmp_pkt_err_sent != 0) {
+		refilled = (now - ipst->ips_icmp_pkt_err_last)/err_interval;
+		if (refilled > ipst->ips_icmp_pkt_err_sent) {
+			ipst->ips_icmp_pkt_err_sent = 0;
 		} else {
-			icmp_pkt_err_sent -= refilled;
-			icmp_pkt_err_last += refilled * err_interval;
+			ipst->ips_icmp_pkt_err_sent -= refilled;
+			ipst->ips_icmp_pkt_err_last += refilled * err_interval;
 		}
 	}
-	if (icmp_pkt_err_sent == 0) {
+	if (ipst->ips_icmp_pkt_err_sent == 0) {
 		/* Start of new burst */
-		icmp_pkt_err_last = now;
+		ipst->ips_icmp_pkt_err_last = now;
 	}
-	if (icmp_pkt_err_sent < ip_icmp_err_burst) {
-		icmp_pkt_err_sent++;
+	if (ipst->ips_icmp_pkt_err_sent < ipst->ips_ip_icmp_err_burst) {
+		ipst->ips_icmp_pkt_err_sent++;
 		ip1dbg(("icmp_err_rate_limit: %d sent in burst\n",
-		    icmp_pkt_err_sent));
+			    ipst->ips_icmp_pkt_err_sent));
 		return (B_FALSE);
 	}
 	ip1dbg(("icmp_err_rate_limit: dropped\n"));
@@ -3628,7 +3531,7 @@
  * ICMP error packet should be sent.
  */
 static mblk_t *
-icmp_pkt_err_ok(mblk_t *mp)
+icmp_pkt_err_ok(mblk_t *mp, ip_stack_t *ipst)
 {
 	icmph_t	*icmph;
 	ipha_t	*ipha;
@@ -3640,20 +3543,20 @@
 		return (NULL);
 	ipha = (ipha_t *)mp->b_rptr;
 	if (ip_csum_hdr(ipha)) {
-		BUMP_MIB(&ip_mib, ipIfStatsInCksumErrs);
+		BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsInCksumErrs);
 		freemsg(mp);
 		return (NULL);
 	}
 	src_ire = ire_ctable_lookup(ipha->ipha_dst, 0, IRE_BROADCAST,
-	    NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE);
+	    NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE, ipst);
 	dst_ire = ire_ctable_lookup(ipha->ipha_src, 0, IRE_BROADCAST,
-	    NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE);
+	    NULL, ALL_ZONES, NULL, MATCH_IRE_TYPE, ipst);
 	if (src_ire != NULL || dst_ire != NULL ||
 	    CLASSD(ipha->ipha_dst) ||
 	    CLASSD(ipha->ipha_src) ||
 	    (ntohs(ipha->ipha_fragment_offset_and_flags) & IPH_OFFSET)) {
 		/* Note: only errors to the fragment with offset 0 */
-		BUMP_MIB(&icmp_mib, icmpOutDrops);
+		BUMP_MIB(&ipst->ips_icmp_mib, icmpOutDrops);
 		freemsg(mp);
 		if (src_ire != NULL)
 			ire_refrele(src_ire);
@@ -3669,7 +3572,7 @@
 		len_needed = IPH_HDR_LENGTH(ipha) + ICMPH_SIZE;
 		if (mp->b_wptr - mp->b_rptr < len_needed) {
 			if (!pullupmsg(mp, len_needed)) {
-				BUMP_MIB(&icmp_mib, icmpInErrors);
+				BUMP_MIB(&ipst->ips_icmp_mib, icmpInErrors);
 				freemsg(mp);
 				return (NULL);
 			}
@@ -3683,7 +3586,7 @@
 		case ICMP_TIME_EXCEEDED:
 		case ICMP_PARAM_PROBLEM:
 		case ICMP_REDIRECT:
-			BUMP_MIB(&icmp_mib, icmpOutDrops);
+			BUMP_MIB(&ipst->ips_icmp_mib, icmpOutDrops);
 			freemsg(mp);
 			return (NULL);
 		default:
@@ -3696,11 +3599,11 @@
 	 */
 	if (is_system_labeled() && !tsol_can_reply_error(mp)) {
 		ip2dbg(("icmp_pkt_err_ok: can't respond to packet\n"));
-		BUMP_MIB(&icmp_mib, icmpOutDrops);
+		BUMP_MIB(&ipst->ips_icmp_mib, icmpOutDrops);
 		freemsg(mp);
 		return (NULL);
 	}
-	if (icmp_err_rate_limit()) {
+	if (icmp_err_rate_limit(ipst)) {
 		/*
 		 * Only send ICMP error packets every so often.
 		 * This should be done on a per port/source basis,
@@ -3716,7 +3619,7 @@
  * Generate an ICMP redirect message.
  */
 static void
-icmp_send_redirect(queue_t *q, mblk_t *mp, ipaddr_t gateway)
+icmp_send_redirect(queue_t *q, mblk_t *mp, ipaddr_t gateway, ip_stack_t *ipst)
 {
 	icmph_t	icmph;
 
@@ -3726,7 +3629,7 @@
 	 */
 	ASSERT(mp->b_datap->db_type == M_DATA);
 
-	if (!(mp = icmp_pkt_err_ok(mp))) {
+	if (!(mp = icmp_pkt_err_ok(mp, ipst))) {
 		return;
 	}
 
@@ -3734,16 +3637,17 @@
 	icmph.icmph_type = ICMP_REDIRECT;
 	icmph.icmph_code = 1;
 	icmph.icmph_rd_gateway = gateway;
-	BUMP_MIB(&icmp_mib, icmpOutRedirects);
+	BUMP_MIB(&ipst->ips_icmp_mib, icmpOutRedirects);
 	/* Redirects sent by router, and router is global zone */
-	icmp_pkt(q, mp, &icmph, sizeof (icmph_t), B_FALSE, GLOBAL_ZONEID);
+	icmp_pkt(q, mp, &icmph, sizeof (icmph_t), B_FALSE, GLOBAL_ZONEID, ipst);
 }
 
 /*
  * Generate an ICMP time exceeded message.
  */
 void
-icmp_time_exceeded(queue_t *q, mblk_t *mp, uint8_t code, zoneid_t zoneid)
+icmp_time_exceeded(queue_t *q, mblk_t *mp, uint8_t code, zoneid_t zoneid,
+    ip_stack_t *ipst)
 {
 	icmph_t	icmph;
 	boolean_t mctl_present;
@@ -3751,7 +3655,7 @@
 
 	EXTRACT_PKT_MP(mp, first_mp, mctl_present);
 
-	if (!(mp = icmp_pkt_err_ok(mp))) {
+	if (!(mp = icmp_pkt_err_ok(mp, ipst))) {
 		if (mctl_present)
 			freeb(first_mp);
 		return;
@@ -3760,15 +3664,17 @@
 	bzero(&icmph, sizeof (icmph_t));
 	icmph.icmph_type = ICMP_TIME_EXCEEDED;
 	icmph.icmph_code = code;
-	BUMP_MIB(&icmp_mib, icmpOutTimeExcds);
-	icmp_pkt(q, first_mp, &icmph, sizeof (icmph_t), mctl_present, zoneid);
+	BUMP_MIB(&ipst->ips_icmp_mib, icmpOutTimeExcds);
+	icmp_pkt(q, first_mp, &icmph, sizeof (icmph_t), mctl_present, zoneid,
+	    ipst);
 }
 
 /*
  * Generate an ICMP unreachable message.
  */
 void
-icmp_unreachable(queue_t *q, mblk_t *mp, uint8_t code, zoneid_t zoneid)
+icmp_unreachable(queue_t *q, mblk_t *mp, uint8_t code, zoneid_t zoneid,
+    ip_stack_t *ipst)
 {
 	icmph_t	icmph;
 	mblk_t *first_mp;
@@ -3776,7 +3682,7 @@
 
 	EXTRACT_PKT_MP(mp, first_mp, mctl_present);
 
-	if (!(mp = icmp_pkt_err_ok(mp))) {
+	if (!(mp = icmp_pkt_err_ok(mp, ipst))) {
 		if (mctl_present)
 			freeb(first_mp);
 		return;
@@ -3785,10 +3691,10 @@
 	bzero(&icmph, sizeof (icmph_t));
 	icmph.icmph_type = ICMP_DEST_UNREACHABLE;
 	icmph.icmph_code = code;
-	BUMP_MIB(&icmp_mib, icmpOutDestUnreachs);
+	BUMP_MIB(&ipst->ips_icmp_mib, icmpOutDestUnreachs);
 	ip2dbg(("send icmp destination unreachable code %d\n", code));
 	icmp_pkt(q, first_mp, (char *)&icmph, sizeof (icmph_t), mctl_present,
-	    zoneid);
+	    zoneid, ipst);
 }
 
 /*
@@ -3814,6 +3720,7 @@
 	mblk_t *arp_add_mp;
 	mblk_t *arp_del_mp;
 	area_t *area;
+	ip_stack_t *ipst = ill->ill_ipst;
 
 	ipif->ipif_recovery_id = 0;
 
@@ -3853,10 +3760,10 @@
 	 */
 	freemsg(arp_add_mp);
 	mutex_enter(&ill->ill_lock);
-	if (ip_dup_recovery > 0 && ipif->ipif_recovery_id == 0 &&
+	if (ipst->ips_ip_dup_recovery > 0 && ipif->ipif_recovery_id == 0 &&
 	    !(ipif->ipif_state_flags & IPIF_CONDEMNED)) {
 		ipif->ipif_recovery_id = timeout(ipif_dup_recovery, ipif,
-		    MSEC_TO_TICK(ip_dup_recovery));
+		    MSEC_TO_TICK(ipst->ips_ip_dup_recovery));
 	}
 	mutex_exit(&ill->ill_lock);
 }
@@ -3878,6 +3785,7 @@
 	char sbuf[INET_ADDRSTRLEN];
 	const char *failtype;
 	boolean_t bring_up;
+	ip_stack_t *ipst = ill->ill_ipst;
 
 	switch (((arcn_t *)mp->b_rptr)->arcn_code) {
 	case AR_CN_READY:
@@ -3922,9 +3830,10 @@
 		    !(ipif->ipif_flags & (IPIF_DHCPRUNNING|IPIF_TEMPORARY)) &&
 		    ill->ill_net_type == IRE_IF_RESOLVER &&
 		    !(ipif->ipif_state_flags & IPIF_CONDEMNED) &&
-		    ip_dup_recovery > 0 && ipif->ipif_recovery_id == 0) {
+		    ipst->ips_ip_dup_recovery > 0 &&
+		    ipif->ipif_recovery_id == 0) {
 			ipif->ipif_recovery_id = timeout(ipif_dup_recovery,
-			    ipif, MSEC_TO_TICK(ip_dup_recovery));
+			    ipif, MSEC_TO_TICK(ipst->ips_ip_dup_recovery));
 			continue;
 		}
 
@@ -3979,9 +3888,9 @@
 		if (!(ipif->ipif_flags & (IPIF_DHCPRUNNING|IPIF_TEMPORARY)) &&
 		    ill->ill_net_type == IRE_IF_RESOLVER &&
 		    !(ipif->ipif_state_flags & IPIF_CONDEMNED) &&
-		    ip_dup_recovery > 0) {
+		    ipst->ips_ip_dup_recovery > 0) {
 			ipif->ipif_recovery_id = timeout(ipif_dup_recovery,
-			    ipif, MSEC_TO_TICK(ip_dup_recovery));
+			    ipif, MSEC_TO_TICK(ipst->ips_ip_dup_recovery));
 		}
 		mutex_exit(&ill->ill_lock);
 	}
@@ -4029,6 +3938,17 @@
 	boolean_t	isv6 = B_FALSE;
 	ipif_t		*ipif;
 	ill_t		*ill;
+	ip_stack_t	*ipst;
+
+	if (CONN_Q(q)) {
+		conn_t *connp = Q_TO_CONN(q);
+
+		ipst = connp->conn_netstack->netstack_ip;
+	} else {
+		ill_t *ill = (ill_t *)q->q_ptr;
+
+		ipst = ill->ill_ipst;
+	}
 
 	if ((mp->b_wptr - mp->b_rptr) < sizeof (arcn_t)	|| !mp->b_cont) {
 		if (q->q_next) {
@@ -4083,11 +4003,12 @@
 		(void) mac_colon_addr((uint8_t *)(arh + 1), arh->arh_hlen,
 		    hbuf, sizeof (hbuf));
 		(void) ip_dot_addr(src, sbuf);
-		if (isv6)
-			ire = ire_cache_lookup_v6(&v6src, ALL_ZONES, NULL);
-		else
-			ire = ire_cache_lookup(src, ALL_ZONES, NULL);
-
+		if (isv6) {
+			ire = ire_cache_lookup_v6(&v6src, ALL_ZONES, NULL,
+			    ipst);
+		} else {
+			ire = ire_cache_lookup(src, ALL_ZONES, NULL, ipst);
+		}
 		if (ire != NULL	&& IRE_IS_LOCAL(ire)) {
 			uint32_t now;
 			uint32_t maxage;
@@ -4104,15 +4025,15 @@
 			ASSERT(ipif != NULL);
 			now = gethrestime_sec();
 			maxage = now - ire->ire_create_time;
-			if (maxage > ip_max_temp_idle)
-				maxage = ip_max_temp_idle;
+			if (maxage > ipst->ips_ip_max_temp_idle)
+				maxage = ipst->ips_ip_max_temp_idle;
 			lused = drv_hztousec(ddi_get_lbolt() -
 			    ire->ire_last_used_time) / MICROSEC + 1;
 			if (lused >= maxage && (ipif->ipif_flags &
 			    (IPIF_DHCPRUNNING | IPIF_TEMPORARY)))
-				maxdefense = ip_max_temp_defend;
+				maxdefense = ipst->ips_ip_max_temp_defend;
 			else
-				maxdefense = ip_max_defend;
+				maxdefense = ipst->ips_ip_max_defend;
 
 			/*
 			 * Now figure out how many times we've defended
@@ -4121,7 +4042,8 @@
 			 */
 			mutex_enter(&ire->ire_lock);
 			if ((defs = ire->ire_defense_count) > 0 &&
-			    now - ire->ire_defense_time > ip_defend_interval) {
+			    now - ire->ire_defense_time >
+			    ipst->ips_ip_defend_interval) {
 				ire->ire_defense_count = defs = 0;
 			}
 			ire->ire_defense_count++;
@@ -4171,7 +4093,7 @@
 			 * Delete the IRE cache entry and NCE for this
 			 * v6 address
 			 */
-			ip_ire_clookup_and_delete_v6(&v6src);
+			ip_ire_clookup_and_delete_v6(&v6src, ipst);
 			/*
 			 * If v6src is a non-zero, it's a router address
 			 * as below. Do the same sort of thing to clean
@@ -4180,7 +4102,7 @@
 			 */
 			if (!IN6_IS_ADDR_UNSPECIFIED(&v6src)) {
 				ire_walk_v6(ire_delete_cache_gw_v6,
-				    (char *)&v6src, ALL_ZONES);
+				    (char *)&v6src, ALL_ZONES, ipst);
 			}
 		} else {
 			nce_hw_map_t hwm;
@@ -4201,7 +4123,7 @@
 			hwm.hwm_addr = src;
 			hwm.hwm_hwlen = arh->arh_hlen;
 			hwm.hwm_hwaddr = (uchar_t *)(arh + 1);
-			ndp_walk_common(&ndp4, NULL,
+			ndp_walk_common(ipst->ips_ndp4, NULL,
 			    (pfi_t)nce_delete_hw_changed, &hwm, ALL_ZONES);
 		}
 		break;
@@ -4213,7 +4135,7 @@
 		if (!(ill->ill_phyint->phyint_flags & PHYI_RUNNING))
 			break;
 		ipif = ipif_lookup_addr(src, ill, ALL_ZONES, NULL, NULL,
-		    NULL, NULL);
+		    NULL, NULL, ipst);
 		if (ipif != NULL) {
 			/*
 			 * If this is a duplicate recovery, then we now need to
@@ -4241,7 +4163,7 @@
 			ipif->ipif_addr_ready = 1;
 			ipif_refrele(ipif);
 		}
-		ire = ire_cache_lookup(src, ALL_ZONES, MBLK_GETLABEL(mp));
+		ire = ire_cache_lookup(src, ALL_ZONES, MBLK_GETLABEL(mp), ipst);
 		if (ire != NULL) {
 			ire->ire_defense_count = 0;
 			ire_refrele(ire);
@@ -4266,7 +4188,8 @@
  * application.
  */
 mblk_t *
-ip_add_info(mblk_t *data_mp, ill_t *ill, uint_t flags, zoneid_t zoneid)
+ip_add_info(mblk_t *data_mp, ill_t *ill, uint_t flags, zoneid_t zoneid,
+    ip_stack_t *ipst)
 {
 	mblk_t		*mp;
 	ip_pktinfo_t	*pinfo;
@@ -4305,7 +4228,7 @@
 			 * ZONEONLY.
 			 */
 			ire = ire_ctable_lookup(ipha->ipha_dst, 0, 0, ipif,
-			    zoneid, NULL, MATCH_IRE_ILL_GROUP);
+			    zoneid, NULL, MATCH_IRE_ILL_GROUP, ipst);
 			if (ire == NULL) {
 				/*
 				 * packet must have come on a different
@@ -4315,7 +4238,7 @@
 				 * for SECATTR and ZONEONLY.
 				 */
 				ire = ire_ctable_lookup(ipha->ipha_dst, 0, 0,
-				    ipif, zoneid, NULL, NULL);
+				    ipif, zoneid, NULL, NULL, ipst);
 			}
 
 			if (ire == NULL) {
@@ -4639,6 +4562,7 @@
 	mblk_t		*policy_mp;
 	ipif_t		*ipif;
 	zoneid_t	zoneid;
+	ip_stack_t	*ipst = connp->conn_netstack->netstack_ip;
 
 	if (ipsec_policy_set) {
 		policy_mp = mp->b_cont;
@@ -4657,7 +4581,7 @@
 
 	if (src_addr) {
 		src_ire = ire_route_lookup(src_addr, 0, 0, 0,
-		    NULL, NULL, zoneid, NULL, MATCH_IRE_ZONEONLY);
+		    NULL, NULL, zoneid, NULL, MATCH_IRE_ZONEONLY, ipst);
 		/*
 		 * If an address other than 0.0.0.0 is requested,
 		 * we verify that it is a valid address for bind
@@ -4691,7 +4615,7 @@
 			*mp->b_wptr++ = (char)connp->conn_ulp;
 			if ((ipif = ipif_lookup_addr(src_addr, NULL, zoneid,
 			    CONNP_TO_WQ(connp), mp, ip_wput_nondata,
-			    &error)) != NULL) {
+			    &error, ipst)) != NULL) {
 				ipif_refrele(ipif);
 			} else if (error == EINPROGRESS) {
 				if (src_ire != NULL)
@@ -4709,7 +4633,8 @@
 				src_ire = ire_ctable_lookup(
 				    INADDR_BROADCAST, INADDR_ANY,
 				    IRE_BROADCAST, NULL, zoneid, NULL,
-				    (MATCH_IRE_TYPE | MATCH_IRE_ZONEONLY));
+				    (MATCH_IRE_TYPE | MATCH_IRE_ZONEONLY),
+				    ipst);
 				if (src_ire == NULL || !ire_requested)
 					error = EADDRNOTAVAIL;
 			} else {
@@ -4767,7 +4692,7 @@
 
 	if (error == 0) {
 		if (ire_requested) {
-			if (!ip_bind_insert_ire(mp, src_ire, NULL)) {
+			if (!ip_bind_insert_ire(mp, src_ire, NULL, ipst)) {
 				error = -1;
 				/* Falls through to bad_addr */
 			}
@@ -4836,6 +4761,7 @@
 	ill_t		*ill = NULL;
 	zoneid_t	zoneid;
 	ipaddr_t	src_addr = *src_addrp;
+	ip_stack_t	*ipst = connp->conn_netstack->netstack_ip;
 
 	src_ire = dst_ire = NULL;
 	protocol = *mp->b_wptr & 0xFF;
@@ -4857,7 +4783,7 @@
 		    NULL, zoneid, MBLK_GETLABEL(mp),
 		    (MATCH_IRE_RECURSIVE |
 		    MATCH_IRE_DEFAULT | MATCH_IRE_RJ_BHOLE |
-		    MATCH_IRE_SECATTR));
+		    MATCH_IRE_SECATTR), ipst);
 	} else {
 		/*
 		 * If conn_dontroute is set or if conn_nexthop_set is set,
@@ -4867,8 +4793,7 @@
 			ipif_t *ipif;
 
 			ipif = ipif_lookup_onlink_addr(connp->conn_dontroute ?
-			    dst_addr : connp->conn_nexthop_v4,
-			    connp->conn_zoneid);
+			    dst_addr : connp->conn_nexthop_v4, zoneid, ipst);
 			if (ipif == NULL) {
 				error = ENETUNREACH;
 				goto bad_addr;
@@ -4879,13 +4804,13 @@
 		if (connp->conn_nexthop_set) {
 			dst_ire = ire_route_lookup(connp->conn_nexthop_v4, 0,
 			    0, 0, NULL, NULL, zoneid, MBLK_GETLABEL(mp),
-			    MATCH_IRE_SECATTR);
+			    MATCH_IRE_SECATTR, ipst);
 		} else {
 			dst_ire = ire_route_lookup(dst_addr, 0, 0, 0, NULL,
 			    &sire, zoneid, MBLK_GETLABEL(mp),
 			    (MATCH_IRE_RECURSIVE | MATCH_IRE_DEFAULT |
 			    MATCH_IRE_PARENT | MATCH_IRE_RJ_BHOLE |
-			    MATCH_IRE_SECATTR));
+			    MATCH_IRE_SECATTR), ipst);
 		}
 	}
 	/*
@@ -4943,7 +4868,7 @@
 	if (dst_ire != NULL && is_system_labeled() &&
 	    !IPCL_IS_TCP(connp) &&
 	    tsol_compute_label(DB_CREDDEF(mp, connp->conn_cred), dst_addr, NULL,
-	    connp->conn_mac_exempt) != 0) {
+	    connp->conn_mac_exempt, ipst) != 0) {
 		error = EHOSTUNREACH;
 		if (ip_debug > 2) {
 			pr_addr_dbg("ip_bind_connected: no label for dst %s\n",
@@ -4983,10 +4908,11 @@
 	if (!ipsec_policy_set && dst_ire != NULL &&
 	    !(dst_ire->ire_type & (IRE_LOCAL | IRE_LOOPBACK | IRE_BROADCAST)) &&
 	    (ill = ire_to_ill(dst_ire), ill != NULL)) {
-		if (ip_lso_outbound && ILL_LSO_CAPABLE(ill)) {
+		if (ipst->ips_ip_lso_outbound && ILL_LSO_CAPABLE(ill)) {
 			lso_dst_ire = dst_ire;
 			IRE_REFHOLD(lso_dst_ire);
-		} else if (ip_multidata_outbound && ILL_MDT_CAPABLE(ill)) {
+		} else if (ipst->ips_ip_multidata_outbound &&
+		    ILL_MDT_CAPABLE(ill)) {
 			md_dst_ire = dst_ire;
 			IRE_REFHOLD(md_dst_ire);
 		}
@@ -5003,7 +4929,7 @@
 		src_ire = ire_ftable_lookup(dst_addr, 0, 0, 0, NULL, NULL,
 		    zoneid, 0, NULL,
 		    MATCH_IRE_RECURSIVE | MATCH_IRE_DEFAULT |
-		    MATCH_IRE_RJ_BHOLE);
+		    MATCH_IRE_RJ_BHOLE, ipst);
 		if (src_ire == NULL) {
 			error = EHOSTUNREACH;
 			goto bad_addr;
@@ -5118,7 +5044,7 @@
 	 */
 	ASSERT(src_ire == NULL);
 	src_ire = ire_route_lookup(src_addr, 0, 0, 0, NULL,
-	    NULL, zoneid, NULL, MATCH_IRE_ZONEONLY);
+	    NULL, zoneid, NULL, MATCH_IRE_ZONEONLY, ipst);
 	/* src_ire must be a local|loopback */
 	if (!IRE_IS_LOCAL(src_ire)) {
 		if (ip_debug > 2) {
@@ -5180,7 +5106,7 @@
 		if (sire != NULL) {
 			ulp_info = &(sire->ire_uinfo);
 		}
-		if (!ip_bind_insert_ire(mp, dst_ire, ulp_info)) {
+		if (!ip_bind_insert_ire(mp, dst_ire, ulp_info, ipst)) {
 			error = -1;
 			goto bad_addr;
 		}
@@ -5282,7 +5208,7 @@
  * Prefers dst_ire over src_ire.
  */
 static boolean_t
-ip_bind_insert_ire(mblk_t *mp, ire_t *ire, iulp_t *ulp_info)
+ip_bind_insert_ire(mblk_t *mp, ire_t *ire, iulp_t *ulp_info, ip_stack_t *ipst)
 {
 	mblk_t	*mp1;
 	ire_t *ret_ire = NULL;
@@ -5307,7 +5233,7 @@
 		 * Pass the latest setting of the ip_path_mtu_discovery and
 		 * copy the ulp info if any.
 		 */
-		ret_ire->ire_frag_flag |= (ip_path_mtu_discovery) ?
+		ret_ire->ire_frag_flag |= (ipst->ips_ip_path_mtu_discovery) ?
 		    IPH_DF : 0;
 		if (ulp_info != NULL) {
 			bcopy(ulp_info, &(ret_ire->ire_uinfo),
@@ -5436,6 +5362,7 @@
 	ipif_t	*ipif;
 	queue_t	*q = ill->ill_rq;
 	hook_nic_event_t *info;
+	ip_stack_t	*ipst = ill->ill_ipst;
 	clock_t timeout;
 
 	/*
@@ -5536,8 +5463,16 @@
 
 	mutex_exit(&ill->ill_lock);
 
+	/*
+	 * ill_delete_tail drops reference on ill_ipst, but we need to keep
+	 * it held until the end of the function since the cleanup
+	 * below needs to be able to use the ip_stack_t.
+	 */
+	netstack_hold(ipst->ips_netstack);
+
 	/* qprocsoff is called in ill_delete_tail */
 	ill_delete_tail(ill);
+	ASSERT(ill->ill_ipst == NULL);
 
 	/*
 	 * Walk through all upper (conn) streams and qenable
@@ -5548,11 +5483,11 @@
 	 * get unblocked.
 	 */
 	ip1dbg(("ip_wsrv: walking\n"));
-	conn_walk_drain();
+	conn_walk_drain(ipst);
 
-	mutex_enter(&ip_mi_lock);
-	mi_close_unlink(&ip_g_head, (IDP)ill);
-	mutex_exit(&ip_mi_lock);
+	mutex_enter(&ipst->ips_ip_mi_lock);
+	mi_close_unlink(&ipst->ips_ip_g_head, (IDP)ill);
+	mutex_exit(&ipst->ips_ip_mi_lock);
 
 	/*
 	 * credp could be null if the open didn't succeed and ip_modopen
@@ -5566,7 +5501,8 @@
 	 * event taskq.
 	 */
 	if ((info = ill->ill_nic_event_info) != NULL) {
-		if (ddi_taskq_dispatch(eventq_queue_nic, ip_ne_queue_func,
+		if (ddi_taskq_dispatch(eventq_queue_nic,
+		    ip_ne_queue_func,
 		    (void *)info, DDI_SLEEP) == DDI_FAILURE) {
 			ip2dbg(("ip_ioctl_finish:ddi_taskq_dispatch failed\n"));
 			if (info->hne_data != NULL)
@@ -5576,6 +5512,12 @@
 		ill->ill_nic_event_info = NULL;
 	}
 
+	/*
+	 * Now we are done with the module close pieces that
+	 * need the netstack_t.
+	 */
+	netstack_rele(ipst->ips_netstack);
+
 	mi_close_free((IDP)ill);
 	q->q_ptr = WR(q)->q_ptr = NULL;
 
@@ -5594,8 +5536,10 @@
 	boolean_t	drain_cleanup_reqd = B_FALSE;
 	boolean_t	conn_ioctl_cleanup_reqd = B_FALSE;
 	boolean_t	ilg_cleanup_reqd = B_FALSE;
+	ip_stack_t	*ipst;
 
 	ASSERT(!IPCL_IS_TCP(connp));
+	ipst = connp->conn_netstack->netstack_ip;
 
 	/*
 	 * Mark the conn as closing, and this conn must not be
@@ -5649,8 +5593,9 @@
 	if (drain_cleanup_reqd)
 		conn_drain_tail(connp, B_TRUE);
 
-	if (connp->conn_rq == ip_g_mrouter || connp->conn_wq == ip_g_mrouter)
-		(void) ip_mrouter_done(NULL);
+	if (connp->conn_rq == ipst->ips_ip_g_mrouter ||
+	    connp->conn_wq == ipst->ips_ip_g_mrouter)
+		(void) ip_mrouter_done(NULL, ipst);
 
 	if (ilg_cleanup_reqd)
 		ilg_delete_all(connp);
@@ -5713,11 +5658,11 @@
 	ASSERT(!IPCL_IS_UDP(connp));
 
 	if (connp->conn_latch != NULL) {
-		IPLATCH_REFRELE(connp->conn_latch);
+		IPLATCH_REFRELE(connp->conn_latch, connp->conn_netstack);
 		connp->conn_latch = NULL;
 	}
 	if (connp->conn_policy != NULL) {
-		IPPH_REFRELE(connp->conn_policy);
+		IPPH_REFRELE(connp->conn_policy, connp->conn_netstack);
 		connp->conn_policy = NULL;
 	}
 	if (connp->conn_ipsec_opt_mp != NULL) {
@@ -5838,39 +5783,155 @@
 	return ((uint16_t)sum);
 }
 
+/*
+ * Called when the module is about to be unloaded
+ */
 void
 ip_ddi_destroy(void)
 {
-	ipv4_hook_destroy();
-	ipv6_hook_destroy();
-	ip_net_destroy();
-
 	tnet_fini();
-	tcp_ddi_destroy();
-	sctp_ddi_destroy();
-	ipsec_loader_destroy();
-	ipsec_policy_destroy();
-	ipsec_kstat_destroy();
-	nd_free(&ip_g_nd);
-	mutex_destroy(&igmp_timer_lock);
-	mutex_destroy(&mld_timer_lock);
-	mutex_destroy(&igmp_slowtimeout_lock);
-	mutex_destroy(&mld_slowtimeout_lock);
-	mutex_destroy(&ip_mi_lock);
-	mutex_destroy(&rts_clients.connf_lock);
-	ip_ire_fini();
-	ip6_asp_free();
-	conn_drain_fini();
-	ipcl_destroy();
+
+	sctp_ddi_g_destroy();
+	tcp_ddi_g_destroy();
+	ipsec_policy_g_destroy();
+	ipcl_g_destroy();
+	ip_net_g_destroy();
+	ip_ire_g_fini();
 	inet_minor_destroy(ip_minor_arena);
-	icmp_kstat_fini();
-	ip_kstat_fini();
-	rw_destroy(&ipsec_capab_ills_lock);
-	rw_destroy(&ill_g_usesrc_lock);
-	ip_drop_unregister(&ip_dropper);
+
+	netstack_unregister(NS_IP);
 }
 
+/*
+ * First step in cleanup.
+ */
+/* ARGSUSED */
+static void
+ip_stack_shutdown(netstackid_t stackid, void *arg)
+{
+	ip_stack_t *ipst = (ip_stack_t *)arg;
 
+#ifdef NS_DEBUG
+	printf("ip_stack_shutdown(%p, stack %d)\n", (void *)ipst, stackid);
+#endif
+
+	/* Get rid of loopback interfaces and their IREs */
+	ip_loopback_cleanup(ipst);
+}
+
+/*
+ * Free the IP stack instance.
+ */
+static void
+ip_stack_fini(netstackid_t stackid, void *arg)
+{
+	ip_stack_t *ipst = (ip_stack_t *)arg;
+	int ret;
+
+#ifdef NS_DEBUG
+	printf("ip_stack_fini(%p, stack %d)\n", (void *)ipst, stackid);
+#endif
+	ipv4_hook_destroy(ipst);
+	ipv6_hook_destroy(ipst);
+	ip_net_destroy(ipst);
+
+	rw_destroy(&ipst->ips_srcid_lock);
+
+	ip_kstat_fini(stackid, ipst->ips_ip_mibkp);
+	ipst->ips_ip_mibkp = NULL;
+	icmp_kstat_fini(stackid, ipst->ips_icmp_mibkp);
+	ipst->ips_icmp_mibkp = NULL;
+	ip_kstat2_fini(stackid, ipst->ips_ip_kstat);
+	ipst->ips_ip_kstat = NULL;
+	bzero(&ipst->ips_ip_statistics, sizeof (ipst->ips_ip_statistics));
+	ip6_kstat_fini(stackid, ipst->ips_ip6_kstat);
+	ipst->ips_ip6_kstat = NULL;
+	bzero(&ipst->ips_ip6_statistics, sizeof (ipst->ips_ip6_statistics));
+
+	nd_free(&ipst->ips_ip_g_nd);
+	kmem_free(ipst->ips_param_arr, sizeof (lcl_param_arr));
+	ipst->ips_param_arr = NULL;
+	kmem_free(ipst->ips_ndp_arr, sizeof (lcl_ndp_arr));
+	ipst->ips_ndp_arr = NULL;
+
+	ip_mrouter_stack_destroy(ipst);
+
+	mutex_destroy(&ipst->ips_ip_mi_lock);
+	rw_destroy(&ipst->ips_ipsec_capab_ills_lock);
+	rw_destroy(&ipst->ips_ill_g_usesrc_lock);
+	rw_destroy(&ipst->ips_ip_g_nd_lock);
+
+	ret = untimeout(ipst->ips_igmp_timeout_id);
+	if (ret == -1) {
+		ASSERT(ipst->ips_igmp_timeout_id == 0);
+	} else {
+		ASSERT(ipst->ips_igmp_timeout_id != 0);
+		ipst->ips_igmp_timeout_id = 0;
+	}
+	ret = untimeout(ipst->ips_igmp_slowtimeout_id);
+	if (ret == -1) {
+		ASSERT(ipst->ips_igmp_slowtimeout_id == 0);
+	} else {
+		ASSERT(ipst->ips_igmp_slowtimeout_id != 0);
+		ipst->ips_igmp_slowtimeout_id = 0;
+	}
+	ret = untimeout(ipst->ips_mld_timeout_id);
+	if (ret == -1) {
+		ASSERT(ipst->ips_mld_timeout_id == 0);
+	} else {
+		ASSERT(ipst->ips_mld_timeout_id != 0);
+		ipst->ips_mld_timeout_id = 0;
+	}
+	ret = untimeout(ipst->ips_mld_slowtimeout_id);
+	if (ret == -1) {
+		ASSERT(ipst->ips_mld_slowtimeout_id == 0);
+	} else {
+		ASSERT(ipst->ips_mld_slowtimeout_id