PSARC 2010/166 layer-3 net properties for exclusive-IP zones
6944327 need to support address and defrouter resources for exclusive-IP zones
--- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/Makefile Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/Makefile Thu Jul 01 17:10:52 2010 -0400
@@ -44,7 +44,7 @@
ROOTCMDDIR= $(ROOTFS_LIBDIR)/inet
-LDLIBS += -lipadm -lnvpair -lsecdb -lnsl -lumem
+LDLIBS += -lipadm -lnvpair -lsecdb -lnsl -lumem -lscf
#
# Instrument ipmgmtd with CTF data to ease debugging.
--- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c Thu Jul 01 17:10:52 2010 -0400
@@ -554,33 +554,9 @@
static void
ipmgmt_setif_handler(void *argp)
{
- ipmgmt_if_arg_t *sargp = argp;
ipmgmt_retval_t rval;
- ipadm_dbwrite_cbarg_t cb;
- uint32_t flags = sargp->ia_flags;
- nvlist_t *nvl = NULL;
- int err = 0;
- char strval[IPMGMT_STRSIZE];
- if (!(flags & IPMGMT_PERSIST) || sargp->ia_family == AF_UNSPEC ||
- sargp->ia_ifname[0] == '\0') {
- err = EINVAL;
- goto ret;
- }
- if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
- goto ret;
- if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
- sargp->ia_ifname)) != 0)
- goto ret;
- (void) snprintf(strval, IPMGMT_STRSIZE, "%d", sargp->ia_family);
- if ((err = nvlist_add_string(nvl, IPADM_NVP_FAMILY, strval)) != 0)
- goto ret;
- cb.dbw_nvl = nvl;
- cb.dbw_flags = 0;
- err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE);
-ret:
- rval.ir_err = err;
- nvlist_free(nvl);
+ rval.ir_err = ipmgmt_persist_if(argp);
(void) door_return((char *)&rval, sizeof (rval), NULL, 0);
}
@@ -856,3 +832,33 @@
rvalp->ir_err = err;
(void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
}
+
+int
+ipmgmt_persist_if(ipmgmt_if_arg_t *sargp)
+{
+ ipadm_dbwrite_cbarg_t cb;
+ uint32_t flags = sargp->ia_flags;
+ nvlist_t *nvl = NULL;
+ int err = 0;
+ char strval[IPMGMT_STRSIZE];
+
+ if (!(flags & IPMGMT_PERSIST) || sargp->ia_family == AF_UNSPEC ||
+ sargp->ia_ifname[0] == '\0') {
+ err = EINVAL;
+ goto ret;
+ }
+ if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
+ goto ret;
+ if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
+ sargp->ia_ifname)) != 0)
+ goto ret;
+ (void) snprintf(strval, IPMGMT_STRSIZE, "%d", sargp->ia_family);
+ if ((err = nvlist_add_string(nvl, IPADM_NVP_FAMILY, strval)) != 0)
+ goto ret;
+ cb.dbw_nvl = nvl;
+ cb.dbw_flags = 0;
+ err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE);
+ret:
+ nvlist_free(nvl);
+ return (err);
+}
--- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h Thu Jul 01 17:10:52 2010 -0400
@@ -38,6 +38,7 @@
#include <pthread.h>
#define IPMGMT_STRSIZE 256
+#define IPMGMTD_FMRI "svc:/network/ip-interface-management:default"
/* ipmgmt_door.c */
extern void ipmgmt_handler(void *, char *, size_t, door_desc_t *, uint_t);
@@ -145,6 +146,8 @@
extern int ipmgmt_persist_aobjmap(ipmgmt_aobjmap_t *,
ipadm_db_op_t);
+extern boolean_t ipmgmt_first_boot();
+extern int ipmgmt_persist_if(ipmgmt_if_arg_t *);
#ifdef __cplusplus
}
#endif
--- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_main.c Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_main.c Thu Jul 01 17:10:52 2010 -0400
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -63,6 +62,13 @@
#include <sys/stat.h>
#include <unistd.h>
#include "ipmgmt_impl.h"
+#include <zone.h>
+#include <libipadm.h>
+#include <libdladm.h>
+#include <libdllink.h>
+#include <net/route.h>
+#include <ipadm_ipmgmt.h>
+#include <sys/brand.h>
const char *progname;
@@ -81,6 +87,18 @@
static void ipmgmt_exit(int);
static int ipmgmt_init();
static int ipmgmt_init_privileges();
+static void ipmgmt_ngz_init();
+static void ipmgmt_ngz_persist_if();
+
+static ipadm_handle_t iph;
+typedef struct ipmgmt_pif_s {
+ struct ipmgmt_pif_s *pif_next;
+ char pif_ifname[LIFNAMSIZ];
+ boolean_t pif_v4;
+ boolean_t pif_v6;
+} ipmgmt_pif_t;
+
+static ipmgmt_pif_t *ngz_pifs;
static int
ipmgmt_db_init()
@@ -115,6 +133,9 @@
}
(void) pthread_rwlock_init(&ipmgmt_dbconf_lock, NULL);
+
+ ipmgmt_ngz_persist_if(); /* create persistent interface info for NGZ */
+
return (err);
}
@@ -214,11 +235,89 @@
}
/*
- * Set the uid of this daemon to the "ipadm" user. Finish the following
+ * On the first reboot after installation of an ipkg zone,
+ * ipmgmt_persist_if_cb() is used in non-global zones to track the interfaces
+ * that have IP address configuration assignments from the global zone.
+ * Persistent configuration for the interfaces is created on the first boot
+ * by ipmgmtd, and the addresses assigned to the interfaces by the GZ
+ * will be subsequently configured when the interface is enabled.
+ * Note that ipmgmt_persist_if_cb() only sets up a list of interfaces
+ * that need to be persisted- the actual update of the ipadm data-store happens
+ * in ipmgmt_persist_if() after the appropriate privs/uid state has been set up.
+ */
+static void
+ipmgmt_persist_if_cb(char *ifname, boolean_t v4, boolean_t v6)
+{
+ ipmgmt_pif_t *pif;
+
+ pif = calloc(1, sizeof (*pif));
+ if (pif == NULL) {
+ ipmgmt_log(LOG_WARNING,
+ "Could not allocate memory to configure %s", ifname);
+ return;
+ }
+ (void) strlcpy(pif->pif_ifname, ifname, sizeof (pif->pif_ifname));
+ pif->pif_v4 = v4;
+ pif->pif_v6 = v6;
+ pif->pif_next = ngz_pifs;
+ ngz_pifs = pif;
+}
+
+/*
+ * ipmgmt_ngz_init() initializes exclusive-IP stack non-global zones by
+ * extracting configuration that has been saved in the kernel and applying
+ * it at zone boot.
+ */
+static void
+ipmgmt_ngz_init()
+{
+ zoneid_t zoneid;
+ boolean_t firstboot = B_TRUE, s10c = B_FALSE;
+ char brand[MAXNAMELEN];
+ ipadm_status_t ipstatus;
+
+ zoneid = getzoneid();
+ if (zoneid != GLOBAL_ZONEID) {
+
+ if (zone_getattr(zoneid, ZONE_ATTR_BRAND, brand,
+ sizeof (brand)) < 0) {
+ ipmgmt_log(LOG_ERR, "Could not get brand name");
+ return;
+ }
+ /*
+ * firstboot is always true for S10C zones, where ipadm is not
+ * available for restoring persistent configuration.
+ */
+ if (strcmp(brand, NATIVE_BRAND_NAME) == 0)
+ firstboot = ipmgmt_first_boot();
+ else
+ s10c = B_TRUE;
+
+ if (!firstboot)
+ return;
+
+ ipstatus = ipadm_open(&iph, IPH_IPMGMTD);
+ if (ipstatus != IPADM_SUCCESS) {
+ ipmgmt_log(LOG_ERR, "could not open ipadm handle",
+ ipadm_status2str(ipstatus));
+ return;
+ }
+ /*
+ * Only pass down the callback to persist the interface
+ * for NATIVE (ipkg) zones.
+ */
+ (void) ipadm_init_net_from_gz(iph, NULL,
+ (s10c ? NULL : ipmgmt_persist_if_cb));
+ ipadm_close(iph);
+ }
+}
+
+/*
+ * Set the uid of this daemon to the "netadm" user. Finish the following
* operations before setuid() because they need root privileges:
*
* - create the /etc/svc/volatile/ipadm directory;
- * - change its uid/gid to "ipadm"/"sys";
+ * - change its uid/gid to "netadm"/"netadm";
*/
static int
ipmgmt_init_privileges()
@@ -246,6 +345,14 @@
}
/*
+ * initialize any NGZ specific network information before dropping
+ * privileges. We need these privileges to plumb IP interfaces handed
+ * down from the GZ (for dlpi_open() etc.) and also to configure the
+ * address itself (for any IPI_PRIV ioctls like SLIFADDR)
+ */
+ ipmgmt_ngz_init();
+
+ /*
* limit the privileges of this daemon and set the uid of this
* daemon to UID_NETADM
*/
@@ -380,3 +487,61 @@
ipmgmt_inform_parent_exit(EXIT_FAILURE);
return (EXIT_FAILURE);
}
+
+/*
+ * Return TRUE if `ifname' has persistent configuration for the `af' address
+ * family in the datastore
+ */
+static boolean_t
+ipmgmt_persist_if_exists(char *ifname, sa_family_t af)
+{
+ ipmgmt_getif_cbarg_t cbarg;
+ boolean_t exists = B_FALSE;
+ ipadm_if_info_t *ifp;
+
+ bzero(&cbarg, sizeof (cbarg));
+ cbarg.cb_ifname = ifname;
+ (void) ipmgmt_db_walk(ipmgmt_db_getif, &cbarg, IPADM_DB_READ);
+ if ((ifp = cbarg.cb_ifinfo) != NULL) {
+ if ((af == AF_INET && (ifp->ifi_pflags & IFIF_IPV4)) ||
+ (af == AF_INET6 && (ifp->ifi_pflags & IFIF_IPV6))) {
+ exists = B_TRUE;
+ }
+ }
+ free(ifp);
+ return (exists);
+}
+
+/*
+ * Persist any NGZ interfaces assigned to us from the global zone if they do
+ * not already exist in the persistent db. We need to
+ * do this before any calls to ipadm_enable_if() can succeed (i.e.,
+ * before opening up for door_calls), and after setuid to 'netadm' so that
+ * the persistent db is created with the right permissions.
+ */
+static void
+ipmgmt_ngz_persist_if()
+{
+ ipmgmt_pif_t *pif, *next;
+ ipmgmt_if_arg_t ifarg;
+
+ for (pif = ngz_pifs; pif != NULL; pif = next) {
+ next = pif->pif_next;
+ bzero(&ifarg, sizeof (ifarg));
+ (void) strlcpy(ifarg.ia_ifname, pif->pif_ifname,
+ sizeof (ifarg.ia_ifname));
+ ifarg.ia_flags = IPMGMT_PERSIST;
+ if (pif->pif_v4 &&
+ !ipmgmt_persist_if_exists(pif->pif_ifname, AF_INET)) {
+ ifarg.ia_family = AF_INET;
+ (void) ipmgmt_persist_if(&ifarg);
+ }
+ if (pif->pif_v6 &&
+ !ipmgmt_persist_if_exists(pif->pif_ifname, AF_INET6)) {
+ ifarg.ia_family = AF_INET6;
+ (void) ipmgmt_persist_if(&ifarg);
+ }
+ free(pif);
+ }
+ ngz_pifs = NULL; /* no red herrings */
+}
--- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c Thu Jul 01 17:10:52 2010 -0400
@@ -56,6 +56,7 @@
#include <arpa/inet.h>
#include <unistd.h>
#include "ipmgmt_impl.h"
+#include <libscf.h>
#define ATYPE "_atype" /* name of the address type nvpair */
#define FLAGS "_flags" /* name of the flags nvpair */
@@ -1164,3 +1165,203 @@
}
return (err);
}
+
+typedef struct scf_resources {
+ scf_handle_t *sr_handle;
+ scf_instance_t *sr_inst;
+ scf_propertygroup_t *sr_pg;
+ scf_property_t *sr_prop;
+ scf_value_t *sr_val;
+ scf_transaction_t *sr_tx;
+ scf_transaction_entry_t *sr_ent;
+} scf_resources_t;
+
+/*
+ * Inputs:
+ * res is a pointer to the scf_resources_t to be released.
+ */
+static void
+ipmgmt_release_scf_resources(scf_resources_t *res)
+{
+ scf_entry_destroy(res->sr_ent);
+ scf_transaction_destroy(res->sr_tx);
+ scf_value_destroy(res->sr_val);
+ scf_property_destroy(res->sr_prop);
+ scf_pg_destroy(res->sr_pg);
+ scf_instance_destroy(res->sr_inst);
+ (void) scf_handle_unbind(res->sr_handle);
+ scf_handle_destroy(res->sr_handle);
+}
+
+/*
+ * Inputs:
+ * fmri is the instance to look up
+ * Outputs:
+ * res is a pointer to an scf_resources_t. This is an internal
+ * structure that holds all the handles needed to get a specific
+ * property from the running snapshot; on a successful return it
+ * contains the scf_value_t that should be passed to the desired
+ * scf_value_get_foo() function, and must be freed after use by
+ * calling release_scf_resources(). On a failure return, any
+ * resources that may have been assigned to res are released, so
+ * the caller does not need to do any cleanup in the failure case.
+ * Returns:
+ * 0 on success
+ * -1 on failure
+ */
+
+static int
+ipmgmt_create_scf_resources(const char *fmri, scf_resources_t *res)
+{
+ res->sr_tx = NULL;
+ res->sr_ent = NULL;
+ res->sr_inst = NULL;
+ res->sr_pg = NULL;
+ res->sr_prop = NULL;
+ res->sr_val = NULL;
+
+ if ((res->sr_handle = scf_handle_create(SCF_VERSION)) == NULL) {
+ return (-1);
+ }
+
+ if (scf_handle_bind(res->sr_handle) != 0) {
+ scf_handle_destroy(res->sr_handle);
+ return (-1);
+ }
+ if ((res->sr_inst = scf_instance_create(res->sr_handle)) == NULL) {
+ goto failure;
+ }
+ if (scf_handle_decode_fmri(res->sr_handle, fmri, NULL, NULL,
+ res->sr_inst, NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
+ goto failure;
+ }
+ if ((res->sr_pg = scf_pg_create(res->sr_handle)) == NULL) {
+ goto failure;
+ }
+ if ((res->sr_prop = scf_property_create(res->sr_handle)) == NULL) {
+ goto failure;
+ }
+ if ((res->sr_val = scf_value_create(res->sr_handle)) == NULL) {
+ goto failure;
+ }
+ if ((res->sr_tx = scf_transaction_create(res->sr_handle)) == NULL) {
+ goto failure;
+ }
+ if ((res->sr_ent = scf_entry_create(res->sr_handle)) == NULL) {
+ goto failure;
+ }
+ return (0);
+
+failure:
+ ipmgmt_release_scf_resources(res);
+ return (-1);
+}
+
+static int
+ipmgmt_set_property_value(scf_resources_t *res, const char *propname,
+ scf_type_t proptype)
+{
+ int result = -1;
+ boolean_t new;
+
+retry:
+ new = (scf_pg_get_property(res->sr_pg, propname, res->sr_prop) != 0);
+
+ if (scf_transaction_start(res->sr_tx, res->sr_pg) == -1) {
+ goto failure;
+ }
+ if (new) {
+ if (scf_transaction_property_new(res->sr_tx, res->sr_ent,
+ propname, proptype) == -1) {
+ goto failure;
+ }
+ } else {
+ if (scf_transaction_property_change(res->sr_tx, res->sr_ent,
+ propname, proptype) == -1) {
+ goto failure;
+ }
+ }
+
+ if (scf_entry_add_value(res->sr_ent, res->sr_val) != 0) {
+ goto failure;
+ }
+
+ result = scf_transaction_commit(res->sr_tx);
+ if (result == 0) {
+ scf_transaction_reset(res->sr_tx);
+ if (scf_pg_update(res->sr_pg) == -1) {
+ goto failure;
+ }
+ goto retry;
+ }
+ if (result == -1)
+ goto failure;
+ return (0);
+
+failure:
+ return (-1);
+}
+
+/*
+ * Returns TRUE if this is the first boot, else return FALSE. The
+ * "ipmgmtd/first_boot_done" property is persistently set up on
+ * IPMGMTD_FMRI on the first boot. Note that the presence of
+ * "first_boot_done" itself is sufficient to indicate that this is
+ * not the first boot i.e., the value of the property is immaterial.
+ */
+extern boolean_t
+ipmgmt_first_boot()
+{
+ scf_simple_prop_t *prop;
+ ssize_t numvals;
+ scf_resources_t res;
+ scf_error_t err;
+
+ if (ipmgmt_create_scf_resources(IPMGMTD_FMRI, &res) != 0)
+ return (B_TRUE); /* err on the side of caution */
+ prop = scf_simple_prop_get(res.sr_handle,
+ IPMGMTD_FMRI, "ipmgmtd", "first_boot_done");
+ numvals = scf_simple_prop_numvalues(prop);
+ if (numvals > 0) {
+ scf_simple_prop_free(prop);
+ ipmgmt_release_scf_resources(&res);
+ return (B_FALSE);
+ }
+
+ /*
+ * mark the first boot by setting ipmgmtd/first_boot_done to true
+ */
+ if (scf_instance_add_pg(res.sr_inst, "ipmgmtd", SCF_GROUP_APPLICATION,
+ 0, res.sr_pg) != 0) {
+ if ((err = scf_error()) != SCF_ERROR_EXISTS)
+ goto failure;
+ /*
+ * err == SCF_ERROR_EXISTS is by itself sufficient to declare
+ * that this is not the first boot, but we create a simple
+ * property as a place-holder, so that we don't leave an
+ * empty process group behind.
+ */
+ if (scf_instance_get_pg_composed(res.sr_inst, NULL, "ipmgmtd",
+ res.sr_pg) != 0) {
+ err = scf_error();
+ goto failure;
+ }
+ }
+
+ if (scf_value_set_astring(res.sr_val, "true") != 0) {
+ err = scf_error();
+ goto failure;
+ }
+
+ if (ipmgmt_set_property_value(&res, "first_boot_done",
+ SCF_TYPE_ASTRING) != 0) {
+ ipmgmt_log(LOG_WARNING,
+ "Could not set rval of first_boot_done");
+ }
+
+failure:
+ ipmgmt_log(LOG_WARNING, "ipmgmt_first_boot scf error %s",
+ scf_strerror(err));
+ ipmgmt_release_scf_resources(&res);
+ return (B_TRUE);
+}
--- a/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c Thu Jul 01 17:10:52 2010 -0400
@@ -19,11 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1990 Mentat Inc.
* netstat.c 2.2, last change 9/9/91
* MROUTING Revision 3.5
@@ -314,8 +310,9 @@
#define FLF_I 0x00000400 /* RTF_INDIRECT */
#define FLF_R 0x00000800 /* RTF_REJECT */
#define FLF_B 0x00001000 /* RTF_BLACKHOLE */
-
-static const char flag_list[] = "AbDGHLUMSCIRB";
+#define FLF_Z 0x00100000 /* RTF_ZONE */
+
+static const char flag_list[] = "AbDGHLUMSCIRBZ";
typedef struct filter_rule filter_t;
@@ -4342,6 +4339,10 @@
(void) strcat(flags, "B");
flag_b |= FLF_B;
}
+ if (rp->ipRouteInfo.re_flags & RTF_ZONE) {
+ (void) strcat(flags, "Z");
+ flag_b |= FLF_Z;
+ }
return (flag_b);
}
@@ -4589,6 +4590,10 @@
(void) strcat(flags, "B");
flag_b |= FLF_B;
}
+ if (rp6->ipv6RouteInfo.re_flags & RTF_ZONE) {
+ (void) strcat(flags, "Z");
+ flag_b |= FLF_Z;
+ }
return (flag_b);
}
--- a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c Thu Jul 01 17:10:52 2010 -0400
@@ -73,7 +73,8 @@
{ IFF_DUPLICATE, "DUPLICATE" },
{ IFF_IPMP, "IPMP"},
{ IFF_VRRP, "VRRP"},
- { IFF_NOACCEPT, "NOACCEPT"}
+ { IFF_NOACCEPT, "NOACCEPT"},
+ { IFF_L3PROTECT, "L3PROTECT"}
};
typedef struct {
--- a/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c Thu Jul 01 17:10:52 2010 -0400
@@ -308,7 +308,7 @@
/* name, field width, id, callback */
{ "IFNAME", 11, SI_IFNAME, print_si_cb},
{ "STATE", 9, SI_STATE, print_si_cb},
-{ "CURRENT", 12, SI_CURRENT, print_si_cb},
+{ "CURRENT", 13, SI_CURRENT, print_si_cb},
{ "PERSISTENT", 11, SI_PERSISTENT, print_si_cb},
{ NULL, 0, 0, NULL}
};
@@ -1604,6 +1604,43 @@
}
}
+/*
+ * return true if the address for lifname comes to us from the global zone
+ * with 'allowed-ips' constraints.
+ */
+static boolean_t
+is_from_gz(const char *lifname)
+{
+ ipadm_if_info_t *if_info;
+ char phyname[LIFNAMSIZ], *cp;
+ boolean_t ret = _B_FALSE;
+ ipadm_status_t status;
+ zoneid_t zoneid;
+ ushort_t zflags;
+
+ if ((zoneid = getzoneid()) == GLOBAL_ZONEID)
+ return (_B_FALSE); /* from-gz only makes sense in a NGZ */
+
+ if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &zflags, sizeof (zflags)) < 0)
+ return (_B_FALSE);
+
+ if (!(zflags & ZF_NET_EXCL))
+ return (_B_TRUE); /* everything is from the GZ for shared-ip */
+
+ (void) strncpy(phyname, lifname, sizeof (phyname));
+ if ((cp = strchr(phyname, ':')) != NULL)
+ *cp = '\0';
+ status = ipadm_if_info(iph, phyname, &if_info, 0, LIFC_DEFAULT);
+ if (status != IPADM_SUCCESS)
+ return (ret);
+
+ if (if_info->ifi_cflags & IFIF_L3PROTECT)
+ ret = _B_TRUE;
+ if (if_info)
+ ipadm_free_if_info(if_info);
+ return (ret);
+}
+
static boolean_t
print_sa_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
{
@@ -1668,7 +1705,11 @@
buf, bufsize);
break;
case SA_TYPE:
- flags2str(ainfo->ia_atype, type, _B_FALSE, buf, bufsize);
+ if (is_from_gz(ifa->ifa_name))
+ (void) snprintf(buf, bufsize, "from-gz");
+ else
+ flags2str(ainfo->ia_atype, type, _B_FALSE, buf,
+ bufsize);
break;
case SA_CURRENT:
flags2str(ainfo->ia_cflags, cflags_mask, _B_TRUE, buf, bufsize);
@@ -1877,6 +1918,7 @@
{ "i", IFIF_INACTIVE, IFIF_INACTIVE },
{ "V", IFIF_VRRP, IFIF_VRRP },
{ "a", IFIF_NOACCEPT, IFIF_NOACCEPT },
+ { "Z", IFIF_L3PROTECT, IFIF_L3PROTECT },
{ "4", IFIF_IPV4, IFIF_IPV4 },
{ "6", IFIF_IPV6, IFIF_IPV6 },
{ NULL, 0, 0 }
--- a/usr/src/cmd/cmd-inet/usr.sbin/route.c Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/cmd/cmd-inet/usr.sbin/route.c Thu Jul 01 17:10:52 2010 -0400
@@ -1,6 +1,5 @@
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
@@ -2567,7 +2566,8 @@
static char routeflags[] =
"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT"
"\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE"
- "\016PRIVATE\017PROTO2\020PROTO1\021MULTIRT\022SETSRC\023INDIRECT";
+ "\016PRIVATE\017PROTO2\020PROTO1\021MULTIRT\022SETSRC\023INDIRECT"
+ "\024KERNEL\025ZONE";
static char ifnetflags[] =
"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP"
"\011PPROMISC\012ALLMULTI\013INTELLIGENT\014MULTICAST"
--- a/usr/src/cmd/svc/milestone/net-physical Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/cmd/svc/milestone/net-physical Thu Jul 01 17:10:52 2010 -0400
@@ -305,21 +305,35 @@
fi
#
-# Finally configure interfaces set up with ipadm.
+# Finally configure interfaces set up with ipadm. Any /etc/hostname*.intf
+# files take precedence over ipadm defined configurations except when
+# we are in a non-global zone and Layer-3 protection of IP addresses is
+# enforced on the interface by the global zone.
#
-for showif_output in `/sbin/ipadm show-if -p -o ifname,state`; do
+for showif_output in `/sbin/ipadm show-if -p -o ifname,state,current`; do
intf=`echo $showif_output | /usr/bin/cut -f1 -d:`
state=`echo $showif_output | /usr/bin/cut -f2 -d:`
- if [ "$state" != "disabled" ]; then
- # skip if not a persistent interface
+ current=`echo $showif_output | /usr/bin/cut -f3 -d:`
+ if [[ "$state" != "disabled" && $current != *Z* ]]; then
+ #
+ # skip if not a persistent interface, or if it should get IP
+ # configuration from the global zone ('Z' flag is set)
+ #
continue;
elif is_iptun $intf; then
# skip IP tunnel interfaces plumbed by net-iptun
continue;
elif [ -f /etc/hostname.$intf ] || [ -f /etc/hostname6.$intf ]; then
- echo "found /etc/hostname.$intf or /etc/hostname6.$intf, "\
- "ignoring ipadm configuration" > /dev/msglog
- continue;
+ if [[ $current != *Z* ]]; then
+ echo "found /etc/hostname.$intf "\
+ "or /etc/hostname6.$intf, "\
+ "ignoring ipadm configuration" > /dev/msglog
+ continue;
+ else
+ echo "Ignoring /etc/hostname*.$intf" > /dev/msglog
+ /sbin/ifconfig $intf unplumb > /dev/null 2>&1
+ /sbin/ifconfig $intf inet6 unplumb > /dev/null 2>&1
+ fi
fi
# Enable the interface managed by ipadm
--- a/usr/src/cmd/svc/shell/net_include.sh Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/cmd/svc/shell/net_include.sh Thu Jul 01 17:10:52 2010 -0400
@@ -20,8 +20,7 @@
# CDDL HEADER END
#
#
-# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
#
# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T.
# All rights reserved.
@@ -547,6 +546,38 @@
}
#
+# ipadm_from_gz_if ifname
+#
+# Return true if we are in a non-global zone and Layer-3 protection of
+# IP addresses is being enforced on the interface by the global zone
+#
+ipadm_from_gz_if()
+{
+ pif=`/sbin/ipadm show-if -o persistent -p $1 2>/dev/null | egrep '4|6'`
+ if smf_is_globalzone || ![[ $pif == *4* || $pif == *6* ]]; then
+ return 1
+ else
+ #
+ # In the non-global zone, plumb the interface to show current
+ # flags and check if Layer-3 protection has been enforced by
+ # the global zone. Note that this function may return
+ # with a plumbed interface. Ideally, we would not have to
+ # plumb the interface to check l3protect, but since we
+ # the `allowed-ips' datalink property cannot currently be
+ # examined in any other way from the non-global zone, we
+ # resort to plumbing the interface
+ #
+ /sbin/ifconfig $1 plumb > /dev/null 2>&1
+ l3protect=`/sbin/ipadm show-if -o current -p $1|grep -c 'Z'`
+ if [ $l3protect = 0 ]; then
+ return 1
+ else
+ return 0
+ fi
+ fi
+}
+
+#
# if_configure type class interface_list
#
# Configure all of the interfaces of type `type' (e.g., "inet6") in
@@ -575,7 +606,10 @@
while [ $# -gt 0 ]; do
$process_func /sbin/ifconfig $1 $type < $hostpfx.$1 >/dev/null
if [ $? != 0 ]; then
- fail="$fail $1"
+ ipadm_from_gz_if $1
+ if [ $? != 0 ]; then
+ fail="$fail $1"
+ fi
elif [ "$type" = inet6 ]; then
#
# only bring the interface up if it is not a
--- a/usr/src/cmd/zoneadmd/Makefile Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/cmd/zoneadmd/Makefile Thu Jul 01 17:10:52 2010 -0400
@@ -22,10 +22,7 @@
#
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
-#
-# ident "%Z%%M% %I% %E% SMI"
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
#
PROG= zoneadmd
@@ -41,7 +38,8 @@
CFLAGS += $(CCVERBOSE)
LDLIBS += -lsocket -lzonecfg -lnsl -ldevinfo -ldevice -lnvpair \
- -lgen -lbsm -lcontract -lzfs -luuid -lbrand -ldladm -ltsnet -ltsol
+ -lgen -lbsm -lcontract -lzfs -luuid -lbrand -ldladm -ltsnet -ltsol \
+ -linetutil
XGETFLAGS += -a -x zoneadmd.xcl
.KEEP_STATE:
--- a/usr/src/cmd/zoneadmd/vplat.c Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/cmd/zoneadmd/vplat.c Thu Jul 01 17:10:52 2010 -0400
@@ -119,6 +119,7 @@
#include <tsol/label.h>
#include <libtsnet.h>
#include <sys/priv.h>
+#include <libinetutil.h>
#define V4_ADDR_LEN 32
#define V6_ADDR_LEN 128
@@ -159,11 +160,29 @@
extern char query_hook[];
/*
+ * For each "net" resource configured in zonecfg, we track a zone_addr_list_t
+ * node in a linked list that is sorted by linkid. The list is constructed as
+ * the xml configuration file is parsed, and the information
+ * contained in each node is added to the kernel before the zone is
+ * booted, to be retrieved and applied from within the exclusive-IP NGZ
+ * on boot.
+ */
+typedef struct zone_addr_list {
+ struct zone_addr_list *za_next;
+ datalink_id_t za_linkid; /* datalink_id_t of interface */
+ struct zone_nwiftab za_nwiftab; /* address, defrouter properties */
+} zone_addr_list_t;
+
+/*
* An optimization for build_mnttable: reallocate (and potentially copy the
* data) only once every N times through the loop.
*/
#define MNTTAB_HUNK 32
+/* some handy macros */
+#define SIN(s) ((struct sockaddr_in *)s)
+#define SIN6(s) ((struct sockaddr_in6 *)s)
+
/*
* Private autofs system call
*/
@@ -2502,13 +2521,369 @@
return (0);
}
+static boolean_t
+sockaddr_to_str(sa_family_t af, const struct sockaddr *sockaddr,
+ char *straddr, size_t len)
+{
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+ const char *str = NULL;
+
+ if (af == AF_INET) {
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ sin = SIN(sockaddr);
+ str = inet_ntop(AF_INET, (void *)&sin->sin_addr, straddr, len);
+ } else if (af == AF_INET6) {
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ sin6 = SIN6(sockaddr);
+ str = inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, straddr,
+ len);
+ }
+
+ return (str != NULL);
+}
+
+static int
+ipv4_prefixlen(struct sockaddr_in *sin)
+{
+ struct sockaddr_in *m;
+ struct sockaddr_storage mask;
+
+ m = SIN(&mask);
+ m->sin_family = AF_INET;
+ if (getnetmaskbyaddr(sin->sin_addr, &m->sin_addr) == 0) {
+ return (mask2plen(&mask));
+ } else if (IN_CLASSA(htonl(sin->sin_addr.s_addr))) {
+ return (8);
+ } else if (IN_CLASSB(ntohl(sin->sin_addr.s_addr))) {
+ return (16);
+ } else if (IN_CLASSC(ntohl(sin->sin_addr.s_addr))) {
+ return (24);
+ }
+ return (0);
+}
+
+static int
+zone_setattr_network(int type, zoneid_t zoneid, datalink_id_t linkid,
+ void *buf, size_t bufsize)
+{
+ zone_net_data_t *zndata;
+ size_t znsize;
+ int err;
+
+ znsize = sizeof (*zndata) + bufsize;
+ zndata = calloc(1, znsize);
+ if (zndata == NULL)
+ return (ENOMEM);
+ zndata->zn_type = type;
+ zndata->zn_len = bufsize;
+ zndata->zn_linkid = linkid;
+ bcopy(buf, zndata->zn_val, zndata->zn_len);
+ err = zone_setattr(zoneid, ZONE_ATTR_NETWORK, zndata, znsize);
+ free(zndata);
+ return (err);
+}
+
+static int
+add_net_for_linkid(zlog_t *zlogp, zoneid_t zoneid, zone_addr_list_t *start)
+{
+ struct lifreq lifr;
+ char **astr, *address;
+ dladm_status_t dlstatus;
+ char *ip_nospoof = "ip-nospoof";
+ int nnet, naddr, err = 0, j;
+ size_t zlen, cpleft;
+ zone_addr_list_t *ptr, *end;
+ char tmp[INET6_ADDRSTRLEN], *maskstr;
+ char *zaddr, *cp;
+ struct in6_addr *routes = NULL;
+ boolean_t is_set;
+ datalink_id_t linkid;
+
+ assert(start != NULL);
+ naddr = 0; /* number of addresses */
+ nnet = 0; /* number of net resources */
+ linkid = start->za_linkid;
+ for (ptr = start; ptr != NULL && ptr->za_linkid == linkid;
+ ptr = ptr->za_next) {
+ nnet++;
+ }
+ end = ptr;
+ zlen = nnet * (INET6_ADDRSTRLEN + 1);
+ astr = calloc(1, nnet * sizeof (uintptr_t));
+ zaddr = calloc(1, zlen);
+ if (astr == NULL || zaddr == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+ cp = zaddr;
+ cpleft = zlen;
+ j = 0;
+ for (ptr = start; ptr != end; ptr = ptr->za_next) {
+ address = ptr->za_nwiftab.zone_nwif_allowed_address;
+ if (address[0] == '\0')
+ continue;
+ (void) snprintf(tmp, sizeof (tmp), "%s", address);
+ /*
+ * Validate the data. zonecfg_valid_net_address() clobbers
+ * the /<mask> in the address string.
+ */
+ if (zonecfg_valid_net_address(address, &lifr) != Z_OK) {
+ zerror(zlogp, B_FALSE, "invalid address [%s]\n",
+ address);
+ err = EINVAL;
+ goto done;
+ }
+ /*
+ * convert any hostnames to numeric address strings.
+ */
+ if (!sockaddr_to_str(lifr.lifr_addr.ss_family,
+ (const struct sockaddr *)&lifr.lifr_addr, cp, cpleft)) {
+ err = EINVAL;
+ goto done;
+ }
+ /*
+ * make a copy of the numeric string for the data needed
+ * by the "allowed-ips" datalink property.
+ */
+ astr[j] = strdup(cp);
+ if (astr[j] == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+ j++;
+ /*
+ * compute the default netmask from the address, if necessary
+ */
+ if ((maskstr = strchr(tmp, '/')) == NULL) {
+ int prefixlen;
+
+ if (lifr.lifr_addr.ss_family == AF_INET) {
+ prefixlen = ipv4_prefixlen(
+ SIN(&lifr.lifr_addr));
+ } else {
+ struct sockaddr_in6 *sin6;
+
+ sin6 = SIN6(&lifr.lifr_addr);
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
+ prefixlen = 10;
+ else
+ prefixlen = 64;
+ }
+ (void) snprintf(tmp, sizeof (tmp), "%d", prefixlen);
+ maskstr = tmp;
+ } else {
+ maskstr++;
+ }
+ /* append the "/<netmask>" */
+ (void) strlcat(cp, "/", cpleft);
+ (void) strlcat(cp, maskstr, cpleft);
+ (void) strlcat(cp, ",", cpleft);
+ cp += strnlen(cp, zlen);
+ cpleft = &zaddr[INET6_ADDRSTRLEN] - cp;
+ }
+ naddr = j; /* the actual number of addresses in the net resource */
+ assert(naddr <= nnet);
+
+ /*
+ * zonecfg has already verified that the defrouter property can only
+ * be set if there is at least one address defined for the net resource.
+ * If j is 0, there are no addresses defined, and therefore no routers
+ * to configure, and we are done at that point.
+ */
+ if (j == 0)
+ goto done;
+
+ /* over-write last ',' with '\0' */
+ zaddr[strnlen(zaddr, zlen) + 1] = '\0';
+
+ /*
+ * First make sure L3 protection is not already set on the link.
+ */
+ dlstatus = dladm_linkprop_is_set(dld_handle, linkid, DLADM_OPT_ACTIVE,
+ "protection", &is_set);
+ if (dlstatus != DLADM_STATUS_OK) {
+ err = EINVAL;
+ zerror(zlogp, B_FALSE, "unable to check if protection is set");
+ goto done;
+ }
+ if (is_set) {
+ err = EINVAL;
+ zerror(zlogp, B_FALSE, "Protection is already set");
+ goto done;
+ }
+ dlstatus = dladm_linkprop_is_set(dld_handle, linkid, DLADM_OPT_ACTIVE,
+ "allowed-ips", &is_set);
+ if (dlstatus != DLADM_STATUS_OK) {
+ err = EINVAL;
+ zerror(zlogp, B_FALSE, "unable to check if allowed-ips is set");
+ goto done;
+ }
+ if (is_set) {
+ zerror(zlogp, B_FALSE, "allowed-ips is already set");
+ err = EINVAL;
+ goto done;
+ }
+
+ /*
+ * Enable ip-nospoof for the link, and add address to the allowed-ips
+ * list.
+ */
+ dlstatus = dladm_set_linkprop(dld_handle, linkid, "protection",
+ &ip_nospoof, 1, DLADM_OPT_ACTIVE);
+ if (dlstatus != DLADM_STATUS_OK) {
+ zerror(zlogp, B_FALSE, "could not set protection\n");
+ err = EINVAL;
+ goto done;
+ }
+ dlstatus = dladm_set_linkprop(dld_handle, linkid, "allowed-ips",
+ astr, naddr, DLADM_OPT_ACTIVE);
+ if (dlstatus != DLADM_STATUS_OK) {
+ zerror(zlogp, B_FALSE, "could not set allowed-ips\n");
+ err = EINVAL;
+ goto done;
+ }
+
+ /* now set the address in the data-store */
+ err = zone_setattr_network(ZONE_NETWORK_ADDRESS, zoneid, linkid,
+ zaddr, strnlen(zaddr, zlen) + 1);
+ if (err != 0)
+ goto done;
+
+ /*
+ * add the defaultrouters
+ */
+ routes = calloc(1, nnet * sizeof (*routes));
+ j = 0;
+ for (ptr = start; ptr != end; ptr = ptr->za_next) {
+ address = ptr->za_nwiftab.zone_nwif_defrouter;
+ if (address[0] == '\0')
+ continue;
+ if (strchr(address, '/') == NULL && strchr(address, ':') != 0) {
+ /*
+ * zonecfg_valid_net_address() expects numeric IPv6
+ * addresses to have a CIDR format netmask.
+ */
+ (void) snprintf(tmp, sizeof (tmp), "/%d", V6_ADDR_LEN);
+ (void) strlcat(address, tmp, INET6_ADDRSTRLEN);
+ }
+ if (zonecfg_valid_net_address(address, &lifr) != Z_OK) {
+ zerror(zlogp, B_FALSE,
+ "invalid router [%s]\n", address);
+ err = EINVAL;
+ goto done;
+ }
+ if (lifr.lifr_addr.ss_family == AF_INET6) {
+ routes[j] = SIN6(&lifr.lifr_addr)->sin6_addr;
+ } else {
+ IN6_INADDR_TO_V4MAPPED(&SIN(&lifr.lifr_addr)->sin_addr,
+ &routes[j]);
+ }
+ j++;
+ }
+ assert(j <= nnet);
+ if (j > 0) {
+ err = zone_setattr_network(ZONE_NETWORK_DEFROUTER, zoneid,
+ linkid, routes, j * sizeof (*routes));
+ }
+done:
+ free(routes);
+ for (j = 0; j < naddr; j++)
+ free(astr[j]);
+ free(astr);
+ free(zaddr);
+ return (err);
+
+}
+
+static int
+add_net(zlog_t *zlogp, zoneid_t zoneid, zone_addr_list_t *zalist)
+{
+ zone_addr_list_t *ptr;
+ datalink_id_t linkid;
+ int err;
+
+ if (zalist == NULL)
+ return (0);
+
+ linkid = zalist->za_linkid;
+
+ err = add_net_for_linkid(zlogp, zoneid, zalist);
+ if (err != 0)
+ return (err);
+
+ for (ptr = zalist; ptr != NULL; ptr = ptr->za_next) {
+ if (ptr->za_linkid == linkid)
+ continue;
+ linkid = ptr->za_linkid;
+ err = add_net_for_linkid(zlogp, zoneid, ptr);
+ if (err != 0)
+ return (err);
+ }
+ return (0);
+}
+
+/*
+ * Add "new" to the list of network interfaces to be configured by
+ * add_net on zone boot in "old". The list of interfaces in "old" is
+ * sorted by datalink_id_t, with interfaces sorted FIFO for a given
+ * datalink_id_t.
+ *
+ * Returns the merged list of IP interfaces containing "old" and "new"
+ */
+static zone_addr_list_t *
+add_ip_interface(zone_addr_list_t *old, zone_addr_list_t *new)
+{
+ zone_addr_list_t *ptr, *next;
+ datalink_id_t linkid = new->za_linkid;
+
+ assert(old != new);
+
+ if (old == NULL)
+ return (new);
+ for (ptr = old; ptr != NULL; ptr = ptr->za_next) {
+ if (ptr->za_linkid == linkid)
+ break;
+ }
+ if (ptr == NULL) {
+ /* linkid does not already exist, add to the beginning */
+ new->za_next = old;
+ return (new);
+ }
+ /*
+ * adding to the middle of the list; ptr points at the first
+ * occurrence of linkid. Find the last occurrence.
+ */
+ while ((next = ptr->za_next) != NULL) {
+ if (next->za_linkid != linkid)
+ break;
+ ptr = next;
+ }
+ /* insert new after ptr */
+ new->za_next = next;
+ ptr->za_next = new;
+ return (old);
+}
+
+void
+free_ip_interface(zone_addr_list_t *zalist)
+{
+ zone_addr_list_t *ptr, *new;
+
+ for (ptr = zalist; ptr != NULL; ) {
+ new = ptr;
+ ptr = ptr->za_next;
+ free(new);
+ }
+}
+
/*
* 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)
+configure_exclusive_network_interfaces(zlog_t *zlogp, zoneid_t zoneid)
{
zone_dochandle_t handle;
struct zone_nwiftab nwiftab;
@@ -2517,6 +2892,7 @@
datalink_id_t linkid;
di_prof_t prof = NULL;
boolean_t added = B_FALSE;
+ zone_addr_list_t *zalist = NULL, *new;
if ((handle = zonecfg_init_handle()) == NULL) {
zerror(zlogp, B_TRUE, "getting zone configuration handle");
@@ -2579,6 +2955,28 @@
zerror(zlogp, B_TRUE, "failed to add network device");
return (-1);
}
+ /* set up the new IP interface, and add them all later */
+ new = malloc(sizeof (*new));
+ if (new == NULL) {
+ zerror(zlogp, B_TRUE, "no memory for %s",
+ nwiftab.zone_nwif_physical);
+ zonecfg_fini_handle(handle);
+ free_ip_interface(zalist);
+ }
+ bzero(new, sizeof (*new));
+ new->za_nwiftab = nwiftab;
+ new->za_linkid = linkid;
+ zalist = add_ip_interface(zalist, new);
+ }
+ if (zalist != NULL) {
+ if ((errno = add_net(zlogp, zoneid, zalist)) != 0) {
+ (void) zonecfg_endnwifent(handle);
+ zonecfg_fini_handle(handle);
+ zerror(zlogp, B_TRUE, "failed to add address");
+ free_ip_interface(zalist);
+ return (-1);
+ }
+ free_ip_interface(zalist);
}
(void) zonecfg_endnwifent(handle);
zonecfg_fini_handle(handle);
@@ -2610,8 +3008,7 @@
if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags,
sizeof (flags)) < 0) {
if (vplat_get_iptype(zlogp, &iptype) < 0) {
- zerror(zlogp, B_TRUE, "unable to determine "
- "ip-type");
+ zerror(zlogp, B_FALSE, "unable to determine ip-type");
return (-1);
}
} else {
@@ -2662,6 +3059,74 @@
}
static int
+remove_datalink_protect(zlog_t *zlogp, zoneid_t zoneid)
+{
+ ushort_t flags;
+ zone_iptype_t iptype;
+ int i, dlnum = 0;
+ dladm_status_t dlstatus;
+ datalink_id_t *dllink, *dllinks = NULL;
+
+ if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &flags,
+ sizeof (flags)) < 0) {
+ if (vplat_get_iptype(zlogp, &iptype) < 0) {
+ zerror(zlogp, B_FALSE, "unable to determine ip-type");
+ return (-1);
+ }
+ } else {
+ if (flags & ZF_NET_EXCL)
+ iptype = ZS_EXCLUSIVE;
+ else
+ iptype = ZS_SHARED;
+ }
+
+ if (iptype != ZS_EXCLUSIVE)
+ return (0);
+
+ /*
+ * Get the datalink count and for each datalink,
+ * attempt to clear the pool property and clear
+ * the pool_name.
+ */
+ if (zone_list_datalink(zoneid, &dlnum, NULL) != 0) {
+ zerror(zlogp, B_TRUE, "unable to count network interfaces");
+ return (-1);
+ }
+
+ if (dlnum == 0)
+ return (0);
+
+ if ((dllinks = malloc(dlnum * sizeof (datalink_id_t))) == NULL) {
+ zerror(zlogp, B_TRUE, "memory allocation failed");
+ return (-1);
+ }
+ if (zone_list_datalink(zoneid, &dlnum, dllinks) != 0) {
+ zerror(zlogp, B_TRUE, "unable to list network interfaces");
+ free(dllinks);
+ return (-1);
+ }
+
+ for (i = 0, dllink = dllinks; i < dlnum; i++, dllink++) {
+ dlstatus = dladm_set_linkprop(dld_handle, *dllink,
+ "protection", NULL, 0, DLADM_OPT_ACTIVE);
+ if (dlstatus != DLADM_STATUS_OK) {
+ zerror(zlogp, B_TRUE, "could not reset protection\n");
+ free(dllinks);
+ return (-1);
+ }
+ dlstatus = dladm_set_linkprop(dld_handle, *dllink,
+ "allowed-ips", NULL, 0, DLADM_OPT_ACTIVE);
+ if (dlstatus != DLADM_STATUS_OK) {
+ zerror(zlogp, B_TRUE, "could not reset allowed-ips\n");
+ free(dllinks);
+ return (-1);
+ }
+ }
+ free(dllinks);
+ return (0);
+}
+
+static int
unconfigure_exclusive_network_interfaces(zlog_t *zlogp, zoneid_t zoneid)
{
int dlnum = 0;
@@ -4542,7 +5007,8 @@
}
break;
case ZS_EXCLUSIVE:
- if (configure_exclusive_network_interfaces(zlogp) !=
+ if (configure_exclusive_network_interfaces(zlogp,
+ zoneid) !=
0) {
lofs_discard_mnttab();
return (-1);
@@ -4667,6 +5133,19 @@
goto error;
}
+ if (remove_datalink_protect(zlogp, zoneid) != 0) {
+ zerror(zlogp, B_FALSE,
+ "unable clear datalink protect property");
+ goto error;
+ }
+
+ /*
+ * The datalinks assigned to the zone will be removed from the NGZ as
+ * part of zone_shutdown() so that we need to remove protect/pool etc.
+ * before zone_shutdown(). Even if the shutdown itself fails, the zone
+ * will not be able to violate any constraints applied because the
+ * datalinks are no longer available to the zone.
+ */
if (zone_shutdown(zoneid) != 0) {
zerror(zlogp, B_TRUE, "unable to shutdown zone");
goto error;
--- a/usr/src/cmd/zonecfg/zonecfg.c Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/cmd/zonecfg/zonecfg.c Thu Jul 01 17:10:52 2010 -0400
@@ -76,6 +76,7 @@
#include <libdladm.h>
#include <libinetutil.h>
#include <pwd.h>
+#include <inet/ip.h>
#include <libzonecfg.h>
#include "zonecfg.h"
@@ -230,6 +231,7 @@
"auths",
"fs-allowed",
ALIAS_MAXPROCS,
+ "allowed-address",
NULL
};
@@ -500,8 +502,18 @@
NULL
};
+struct xif {
+ struct xif *xif_next;
+ char xif_name[LIFNAMSIZ];
+ boolean_t xif_has_address;
+ boolean_t xif_has_defrouter;
+};
+
/* Global variables */
+/* list of network interfaces specified for exclusive IP zone */
+struct xif *xif;
+
/* set early in main(), never modified thereafter, used all over the place */
static char *execname;
@@ -976,17 +988,30 @@
(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
pt_to_str(PT_ADDRESS), gettext("<IP-address>"));
(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
+ pt_to_str(PT_ALLOWED_ADDRESS),
+ gettext("<IP-address>"));
+ (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
pt_to_str(PT_PHYSICAL), gettext("<interface>"));
(void) fprintf(fp, gettext("See ifconfig(1M) for "
"details of the <interface> string.\n"));
- (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
- pt_to_str(PT_DEFROUTER), gettext("<IP-address>"));
- (void) fprintf(fp, gettext("%s %s and %s %s are valid "
- "if the %s property is set to %s, otherwise they "
+ (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), gettext("shared"));
+ (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_ALLOWED_ADDRESS),
+ pt_to_str(PT_IPTYPE), gettext("exclusive"));
+ (void) fprintf(fp, gettext("\t%s %s=%s\n%s %s "
+ "is valid if the %s or %s property is set, "
+ "otherwise it must not be set\n"),
+ cmd_to_str(CMD_SET),
+ pt_to_str(PT_DEFROUTER), gettext("<IP-address>"),
cmd_to_str(CMD_SET), pt_to_str(PT_DEFROUTER),
- pt_to_str(PT_IPTYPE), "shared");
+ gettext(pt_to_str(PT_ADDRESS)),
+ gettext(pt_to_str(PT_ALLOWED_ADDRESS)));
break;
case RT_DEVICE:
(void) fprintf(fp, gettext("The '%s' resource scope is "
@@ -1220,9 +1245,9 @@
rt_to_str(RT_FS), pt_to_str(PT_DIR),
pt_to_str(PT_SPECIAL), pt_to_str(PT_RAW),
pt_to_str(PT_TYPE), pt_to_str(PT_OPTIONS));
- (void) fprintf(fp, "\t%s\t\t%s, %s, %s\n", rt_to_str(RT_NET),
- pt_to_str(PT_ADDRESS), pt_to_str(PT_PHYSICAL),
- pt_to_str(PT_DEFROUTER));
+ (void) fprintf(fp, "\t%s\t\t%s, %s, %s|%s\n", rt_to_str(RT_NET),
+ pt_to_str(PT_ADDRESS), pt_to_str(PT_ALLOWED_ADDRESS),
+ pt_to_str(PT_PHYSICAL), pt_to_str(PT_DEFROUTER));
(void) fprintf(fp, "\t%s\t\t%s\n", rt_to_str(RT_DEVICE),
pt_to_str(PT_MATCH));
(void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_RCTL),
@@ -1849,6 +1874,8 @@
(void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
rt_to_str(RT_NET));
export_prop(of, PT_ADDRESS, nwiftab.zone_nwif_address);
+ export_prop(of, PT_ALLOWED_ADDRESS,
+ nwiftab.zone_nwif_allowed_address);
export_prop(of, PT_PHYSICAL, nwiftab.zone_nwif_physical);
export_prop(of, PT_DEFROUTER, nwiftab.zone_nwif_defrouter);
(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
@@ -2601,6 +2628,11 @@
(void) strlcpy(nwiftab->zone_nwif_address,
pp->pv_simple, sizeof (nwiftab->zone_nwif_address));
break;
+ case PT_ALLOWED_ADDRESS:
+ (void) strlcpy(nwiftab->zone_nwif_allowed_address,
+ pp->pv_simple,
+ sizeof (nwiftab->zone_nwif_allowed_address));
+ break;
case PT_PHYSICAL:
(void) strlcpy(nwiftab->zone_nwif_physical,
pp->pv_simple,
@@ -3758,10 +3790,14 @@
* IPv4 addresses and host names, 0 to 128 for IPv6 addresses.
* Host names must start with an alpha-numeric character, and all subsequent
* characters must be either alpha-numeric or "-".
+ *
+ * In some cases, e.g., the nexthop for the defrouter, the context indicates
+ * that this is the IPV4_ABITS or IPV6_ABITS netmask, in which case we don't
+ * require the /<prefix length> (and should ignore it if provided).
*/
static int
-validate_net_address_syntax(char *address)
+validate_net_address_syntax(char *address, boolean_t ishost)
{
char *slashp, part1[MAXHOSTNAMELEN];
struct in6_addr in6;
@@ -3781,8 +3817,17 @@
(void) strlcpy(part1, address, sizeof (part1));
}
+ if (ishost && slashp != NULL) {
+ zerr(gettext("Warning: prefix length in %s is not required and "
+ "will be ignored. The default host-prefix length "
+ "will be used"), address);
+ }
+
+
if (inet_pton(AF_INET6, part1, &in6) == 1) {
- if (slashp == NULL) {
+ if (ishost) {
+ prefixlen = IPV6_ABITS;
+ } else if (slashp == NULL) {
zerr(gettext("%s: IPv6 addresses "
"require /prefix-length suffix."), address);
return (Z_ERR);
@@ -3796,13 +3841,16 @@
}
/* At this point, any /prefix must be for IPv4. */
- if (slashp != NULL) {
+ if (ishost)
+ prefixlen = IPV4_ABITS;
+ else if (slashp != NULL) {
if (prefixlen < 0 || prefixlen > 32) {
zerr(gettext("%s: IPv4 address "
"prefix lengths must be 0 - 32."), address);
return (Z_ERR);
}
}
+
if (inet_pton(AF_INET, part1, &in4) == 1)
return (Z_OK);
@@ -3953,6 +4001,20 @@
}
}
+static void
+set_in_progress_nwiftab_address(char *prop_id, int prop_type)
+{
+ if (prop_type == PT_ADDRESS) {
+ (void) strlcpy(in_progress_nwiftab.zone_nwif_address, prop_id,
+ sizeof (in_progress_nwiftab.zone_nwif_address));
+ } else {
+ assert(prop_type == PT_ALLOWED_ADDRESS);
+ (void) strlcpy(in_progress_nwiftab.zone_nwif_allowed_address,
+ prop_id,
+ sizeof (in_progress_nwiftab.zone_nwif_allowed_address));
+ }
+}
+
void
set_func(cmd_t *cmd)
{
@@ -4312,13 +4374,13 @@
case RT_NET:
switch (prop_type) {
case PT_ADDRESS:
- if (validate_net_address_syntax(prop_id) != Z_OK) {
+ case PT_ALLOWED_ADDRESS:
+ if (validate_net_address_syntax(prop_id, B_FALSE)
+ != Z_OK) {
saw_error = B_TRUE;
return;
}
- (void) strlcpy(in_progress_nwiftab.zone_nwif_address,
- prop_id,
- sizeof (in_progress_nwiftab.zone_nwif_address));
+ set_in_progress_nwiftab_address(prop_id, prop_type);
break;
case PT_PHYSICAL:
if (validate_net_physical_syntax(prop_id) != Z_OK) {
@@ -4330,7 +4392,8 @@
sizeof (in_progress_nwiftab.zone_nwif_physical));
break;
case PT_DEFROUTER:
- if (validate_net_address_syntax(prop_id) != Z_OK) {
+ if (validate_net_address_syntax(prop_id, B_TRUE)
+ != Z_OK) {
saw_error = B_TRUE;
return;
}
@@ -4879,6 +4942,8 @@
{
(void) fprintf(fp, "%s:\n", rt_to_str(RT_NET));
output_prop(fp, PT_ADDRESS, nwiftab->zone_nwif_address, B_TRUE);
+ output_prop(fp, PT_ALLOWED_ADDRESS,
+ nwiftab->zone_nwif_allowed_address, B_TRUE);
output_prop(fp, PT_PHYSICAL, nwiftab->zone_nwif_physical, B_TRUE);
output_prop(fp, PT_DEFROUTER, nwiftab->zone_nwif_defrouter, B_TRUE);
}
@@ -5597,6 +5662,41 @@
}
/*
+ * Track the network interfaces listed in zonecfg(1m) in a linked list
+ * so that we can later check that defrouter is specified for an exclusive IP
+ * zone if and only if at least one allowed-address has been specified.
+ */
+static boolean_t
+add_nwif(struct zone_nwiftab *nwif)
+{
+ struct xif *tmp;
+
+ for (tmp = xif; tmp != NULL; tmp = tmp->xif_next) {
+ if (strcmp(tmp->xif_name, nwif->zone_nwif_physical) == 0) {
+ if (strlen(nwif->zone_nwif_allowed_address) > 0)
+ tmp->xif_has_address = B_TRUE;
+ if (strlen(nwif->zone_nwif_defrouter) > 0)
+ tmp->xif_has_defrouter = B_TRUE;
+ return (B_TRUE);
+ }
+ }
+
+ tmp = malloc(sizeof (*tmp));
+ if (tmp == NULL) {
+ zerr(gettext("memory allocation failed for %s"),
+ nwif->zone_nwif_physical);
+ return (B_FALSE);
+ }
+ strlcpy(tmp->xif_name, nwif->zone_nwif_physical,
+ sizeof (tmp->xif_name));
+ tmp->xif_has_defrouter = (strlen(nwif->zone_nwif_defrouter) > 0);
+ tmp->xif_has_address = (strlen(nwif->zone_nwif_allowed_address) > 0);
+ tmp->xif_next = xif;
+ xif = tmp;
+ return (B_TRUE);
+}
+
+/*
* See the DTD for which attributes are required for which resources.
*
* This function can be called by commit_func(), which needs to save things,
@@ -5627,6 +5727,7 @@
zone_iptype_t iptype;
boolean_t has_cpu_shares = B_FALSE;
boolean_t has_cpu_cap = B_FALSE;
+ struct xif *tmp;
optind = 0;
while ((arg = getopt(cmd->cmd_argc, cmd->cmd_argv, "?")) != EOF) {
@@ -5740,6 +5841,15 @@
case ZS_SHARED:
check_reqd_prop(nwiftab.zone_nwif_address, RT_NET,
PT_ADDRESS, &ret_val);
+ if (strlen(nwiftab.zone_nwif_allowed_address) > 0) {
+ zerr(gettext("%s: %s cannot be specified "
+ "for a shared IP type"),
+ rt_to_str(RT_NET),
+ pt_to_str(PT_ALLOWED_ADDRESS));
+ saw_error = B_TRUE;
+ if (ret_val == Z_OK)
+ ret_val = Z_INVAL;
+ }
break;
case ZS_EXCLUSIVE:
if (strlen(nwiftab.zone_nwif_address) > 0) {
@@ -5749,18 +5859,28 @@
saw_error = B_TRUE;
if (ret_val == Z_OK)
ret_val = Z_INVAL;
- }
- if (strlen(nwiftab.zone_nwif_defrouter) > 0) {
- zerr(gettext("%s: %s cannot be specified "
- "for an exclusive IP type"),
- rt_to_str(RT_NET), pt_to_str(PT_DEFROUTER));
- saw_error = B_TRUE;
- if (ret_val == Z_OK)
- ret_val = Z_INVAL;
+ } else {
+ if (!add_nwif(&nwiftab)) {
+ saw_error = B_TRUE;
+ if (ret_val == Z_OK)
+ ret_val = Z_INVAL;
+ }
}
break;
}
}
+ for (tmp = xif; tmp != NULL; tmp = tmp->xif_next) {
+ if (!tmp->xif_has_address && tmp->xif_has_defrouter) {
+ zerr(gettext("%s: %s for %s cannot be specified "
+ "without %s for an exclusive IP type"),
+ rt_to_str(RT_NET), pt_to_str(PT_DEFROUTER),
+ tmp->xif_name, pt_to_str(PT_ALLOWED_ADDRESS));
+ saw_error = B_TRUE;
+ ret_val = Z_INVAL;
+ }
+ }
+ free(xif);
+ xif = NULL;
(void) zonecfg_endnwifent(handle);
if ((err = zonecfg_setrctlent(handle)) != Z_OK) {
@@ -6023,6 +6143,28 @@
return (Z_OK);
}
+static void
+net_exists_error(struct zone_nwiftab nwif)
+{
+ if (strlen(nwif.zone_nwif_address) > 0) {
+ zerr(gettext("A %s resource with the %s '%s', "
+ "and %s '%s' already exists."),
+ rt_to_str(RT_NET),
+ pt_to_str(PT_PHYSICAL),
+ nwif.zone_nwif_physical,
+ pt_to_str(PT_ADDRESS),
+ in_progress_nwiftab.zone_nwif_address);
+ } else {
+ zerr(gettext("A %s resource with the %s '%s', "
+ "and %s '%s' already exists."),
+ rt_to_str(RT_NET),
+ pt_to_str(PT_PHYSICAL),
+ nwif.zone_nwif_physical,
+ pt_to_str(PT_ALLOWED_ADDRESS),
+ nwif.zone_nwif_allowed_address);
+ }
+}
+
void
end_func(cmd_t *cmd)
{
@@ -6151,14 +6293,14 @@
(void) strlcpy(tmp_nwiftab.zone_nwif_address,
in_progress_nwiftab.zone_nwif_address,
sizeof (tmp_nwiftab.zone_nwif_address));
+ (void) strlcpy(tmp_nwiftab.zone_nwif_allowed_address,
+ in_progress_nwiftab.zone_nwif_allowed_address,
+ sizeof (tmp_nwiftab.zone_nwif_allowed_address));
+ (void) strlcpy(tmp_nwiftab.zone_nwif_defrouter,
+ in_progress_nwiftab.zone_nwif_defrouter,
+ sizeof (tmp_nwiftab.zone_nwif_defrouter));
if (zonecfg_lookup_nwif(handle, &tmp_nwiftab) == Z_OK) {
- 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);
+ net_exists_error(in_progress_nwiftab);
saw_error = B_TRUE;
return;
}
--- a/usr/src/cmd/zonecfg/zonecfg.h Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/cmd/zonecfg/zonecfg.h Thu Jul 01 17:10:52 2010 -0400
@@ -136,9 +136,10 @@
#define PT_AUTHS 38
#define PT_FS_ALLOWED 39
#define PT_MAXPROCS 40
+#define PT_ALLOWED_ADDRESS 41
#define PT_MIN PT_UNKNOWN
-#define PT_MAX PT_MAXPROCS
+#define PT_MAX PT_ALLOWED_ADDRESS
#define MAX_EQ_PROP_PAIRS 3
--- a/usr/src/cmd/zonecfg/zonecfg_grammar.y Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/cmd/zonecfg/zonecfg_grammar.y Thu Jul 01 17:10:52 2010 -0400
@@ -123,7 +123,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 ATTR DEVICE RCTL SPECIAL RAW DIR OPTIONS TYPE ADDRESS PHYSICAL
-%token IPTYPE HOSTID FS_ALLOWED
+%token IPTYPE HOSTID FS_ALLOWED ALLOWED_ADDRESS
%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 PCAP
%token MCAP NCPUS IMPORTANCE SHARES MAXLWPS MAXSHMMEM MAXSHMIDS MAXMSGIDS
@@ -137,6 +137,7 @@
%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 IPTYPE DEFROUTER HOSTID USER AUTHS FS_ALLOWED
+ ALLOWED_ADDRESS
%type <cmd> command
%type <cmd> add_command ADD
%type <cmd> cancel_command CANCEL
@@ -956,6 +957,7 @@
| LIMITPRIV { $$ = PT_LIMITPRIV; }
| BOOTARGS { $$ = PT_BOOTARGS; }
| ADDRESS { $$ = PT_ADDRESS; }
+ | ALLOWED_ADDRESS { $$ = PT_ALLOWED_ADDRESS; }
| PHYSICAL { $$ = PT_PHYSICAL; }
| DEFROUTER { $$ = PT_DEFROUTER; }
| NAME { $$ = PT_NAME; }
--- a/usr/src/cmd/zonecfg/zonecfg_lex.l Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/cmd/zonecfg/zonecfg_lex.l Thu Jul 01 17:10:52 2010 -0400
@@ -204,6 +204,9 @@
<TSTATE>options { return OPTIONS; }
<CSTATE>options { return OPTIONS; }
+<TSTATE>allowed-address { return ALLOWED_ADDRESS; }
+<CSTATE>allowed-address { return ALLOWED_ADDRESS; }
+
<TSTATE>address { return ADDRESS; }
<CSTATE>address { return ADDRESS; }
--- a/usr/src/head/libzonecfg.h Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/head/libzonecfg.h Thu Jul 01 17:10:52 2010 -0400
@@ -192,7 +192,8 @@
};
struct zone_nwiftab {
- char zone_nwif_address[INET6_ADDRSTRLEN];
+ char zone_nwif_address[INET6_ADDRSTRLEN]; /* shared-ip only */
+ char zone_nwif_allowed_address[INET6_ADDRSTRLEN]; /* excl-ip only */
char zone_nwif_physical[LIFNAMSIZ];
char zone_nwif_defrouter[INET6_ADDRSTRLEN];
};
--- a/usr/src/lib/libdladm/common/linkprop.c Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/lib/libdladm/common/linkprop.c Thu Jul 01 17:10:52 2010 -0400
@@ -4503,11 +4503,13 @@
uint_t valcnt = DLADM_MAX_PROP_VALCNT;
int i;
dladm_status_t status = DLADM_STATUS_OK;
+ size_t bufsize;
*is_set = B_FALSE;
- if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) *
- DLADM_MAX_PROP_VALCNT)) == NULL)
+ bufsize = (sizeof (char *) + DLADM_PROP_VAL_MAX) *
+ DLADM_MAX_PROP_VALCNT;
+ if ((buf = calloc(1, bufsize)) == NULL)
return (DLADM_STATUS_NOMEM);
propvals = (char **)(void *)buf;
@@ -4522,7 +4524,15 @@
goto done;
}
- if ((strcmp(prop_name, "pool") == 0) && (strlen(*propvals) != 0)) {
+ /*
+ * valcnt is always set to 1 by get_pool(), hence we need to check
+ * for a non-null string to see if it is set. For protection and
+ * allowed-ips, we can check either the *propval or the valcnt.
+ */
+ if ((strcmp(prop_name, "pool") == 0 ||
+ strcmp(prop_name, "protection") == 0 ||
+ strcmp(prop_name, "allowed-ips") == 0) &&
+ (strlen(*propvals) != 0)) {
*is_set = B_TRUE;
} else if ((strcmp(prop_name, "cpus") == 0) && (valcnt != 0)) {
*is_set = B_TRUE;
--- a/usr/src/lib/libipadm/Makefile.com Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/lib/libipadm/Makefile.com Thu Jul 01 17:10:52 2010 -0400
@@ -19,15 +19,14 @@
# CDDL HEADER END
#
#
-# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
#
#
LIBRARY = libipadm.a
VERS = .1
OBJECTS = libipadm.o ipadm_prop.o ipadm_persist.o ipadm_addr.o ipadm_if.o \
- ipadm_ndpd.o
+ ipadm_ndpd.o ipadm_ngz.o
include ../../Makefile.lib
--- a/usr/src/lib/libipadm/common/ipadm_addr.c Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/lib/libipadm/common/ipadm_addr.c Thu Jul 01 17:10:52 2010 -0400
@@ -1312,7 +1312,7 @@
int s;
size_t nbytes = 0;
- if (getzoneid() != GLOBAL_ZONEID) {
+ if (iph->iph_zoneid != GLOBAL_ZONEID) {
buf[0] = '\0';
return (IPADM_SUCCESS);
}
@@ -1660,7 +1660,7 @@
return (IPADM_SUCCESS);
}
-static ipadm_status_t
+ipadm_status_t
i_ipadm_resolve_addr(const char *name, sa_family_t af,
struct sockaddr_storage *ss)
{
@@ -1935,6 +1935,9 @@
ipmgmt_retval_t rval, *rvalp;
int err;
+ if (iph->iph_flags & IPH_IPMGMTD)
+ return (IPADM_SUCCESS);
+
bzero(&larg, sizeof (larg));
larg.ia_cmd = IPMGMT_CMD_ADDROBJ_SETLIFNUM;
(void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname,
@@ -2266,6 +2269,8 @@
* also checks if the interface is under DHCP control. If the condition is true,
* the output argument `exists' will be set to B_TRUE. Otherwise, `exists'
* is set to B_FALSE.
+ *
+ * Note that *exists will not be initialized if an error is encountered.
*/
static ipadm_status_t
i_ipadm_addr_exists_on_if(ipadm_handle_t iph, const char *ifname,
@@ -2405,6 +2410,7 @@
boolean_t is_6to4;
struct lifreq lifr;
uint64_t ifflags;
+ boolean_t is_boot = (iph->iph_flags & IPH_IPMGMTD);
/* check for solaris.network.interface.config authorization */
if (!ipadm_check_auth())
@@ -2450,10 +2456,16 @@
af = addr->ipadm_af;
/*
* Create a placeholder for this address object in the daemon.
- * Skip this step for IPH_LEGACY case if the addrobj already
- * exists.
+ * Skip this step if we are booting a zone (and therefore being called
+ * from ipmgmtd itself), and, for IPH_LEGACY case if the
+ * addrobj already exists.
+ *
+ * Note that the placeholder is not needed in the NGZ boot case,
+ * when zoneadmd has itself applied the "allowed-ips" property to clamp
+ * down any interface configuration, so the namespace for the interface
+ * is fully controlled by the GZ.
*/
- if (!legacy || !aobjfound) {
+ if (!is_boot && (!legacy || !aobjfound)) {
status = i_ipadm_lookupadd_addrobj(iph, addr);
if (status != IPADM_SUCCESS)
return (status);
@@ -2479,11 +2491,23 @@
created_other_af = B_TRUE;
}
- /* Validate static addresses for IFF_POINTOPOINT interfaces. */
+ /*
+ * Some input validation based on the interface flags:
+ * 1. in non-global zones, make sure that we are not persistently
+ * creating addresses on interfaces that are acquiring
+ * address from the global zone.
+ * 2. Validate static addresses for IFF_POINTOPOINT interfaces.
+ */
if (addr->ipadm_atype == IPADM_ADDR_STATIC) {
status = i_ipadm_get_flags(iph, ifname, af, &ifflags);
if (status != IPADM_SUCCESS)
goto fail;
+
+ if (iph->iph_zoneid != GLOBAL_ZONEID &&
+ (ifflags & IFF_L3PROTECT) && (flags & IPADM_OPT_PERSIST)) {
+ status = IPADM_GZ_PERM;
+ goto fail;
+ }
daf = addr->ipadm_static_dst_addr.ss_family;
if (ifflags & IFF_POINTOPOINT) {
if (is_6to4) {
@@ -2596,7 +2620,9 @@
boolean_t legacy = (iph->iph_flags & IPH_LEGACY);
struct ipadm_addrobj_s legacy_addr;
boolean_t default_prefixlen = B_FALSE;
-
+ boolean_t is_boot;
+
+ is_boot = ((iph->iph_flags & IPH_IPMGMTD) != 0);
af = ipaddr->ipadm_af;
sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
@@ -2668,7 +2694,7 @@
status = IPADM_SUCCESS;
}
- if (status == IPADM_SUCCESS) {
+ if (status == IPADM_SUCCESS && !is_boot) {
/*
* For IPH_LEGACY, we might be modifying the address on
* an address object that already exists e.g. by doing
--- a/usr/src/lib/libipadm/common/ipadm_if.c Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/lib/libipadm/common/ipadm_if.c Thu Jul 01 17:10:52 2010 -0400
@@ -169,6 +169,8 @@
ifp->ifi_cflags |= IFIF_IPV4;
if (lifrl.lifr_flags & IFF_IPV6)
ifp->ifi_cflags |= IFIF_IPV6;
+ if (lifrl.lifr_flags & IFF_L3PROTECT)
+ ifp->ifi_cflags |= IFIF_L3PROTECT;
}
free(buf);
return (IPADM_SUCCESS);
@@ -376,6 +378,15 @@
ipadm_if_info_t *ifinfo;
ipadm_status_t status;
+ /*
+ * if IPH_IPMGMTD is set, we know that the caller (ipmgmtd) already
+ * knows about persistent configuration in the first place, so we
+ * just return success.
+ */
+ if (iph->iph_flags & IPH_IPMGMTD) {
+ *exists = B_FALSE;
+ return (IPADM_SUCCESS);
+ }
status = i_ipadm_persist_if_info(iph, ifname, &ifinfo);
if (status == IPADM_SUCCESS) {
*exists = ((af == AF_INET &&
@@ -688,7 +699,7 @@
* that the non-global zones don't need this check, because zoneadm
* has taken care of this when the zones boot.
*/
- if (getzoneid() == GLOBAL_ZONEID && dlstatus == DLADM_STATUS_OK) {
+ if (iph->iph_zoneid == GLOBAL_ZONEID && dlstatus == DLADM_STATUS_OK) {
zoneid = ALL_ZONES;
if (zone_check_datalink(&zoneid, linkid) == 0) {
/* interface is in use by a non-global zone. */
--- a/usr/src/lib/libipadm/common/ipadm_ipmgmt.h Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/lib/libipadm/common/ipadm_ipmgmt.h Thu Jul 01 17:10:52 2010 -0400
@@ -265,6 +265,17 @@
extern int ipadm_rw_db(db_wfunc_t *, void *, const char *, mode_t,
ipadm_db_op_t);
+/* zone related functions */
+/*
+ * callback function to persist an interface in ipmgmtd data store
+ */
+typedef void (*persist_cb_t)(char *, boolean_t, boolean_t);
+/*
+ * ipmgmtd/libipadm network initialization interface.
+ */
+extern ipadm_status_t ipadm_init_net_from_gz(ipadm_handle_t, char *,
+ persist_cb_t);
+
#ifdef __cplusplus
}
#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipadm/common/ipadm_ngz.c Thu Jul 01 17:10:52 2010 -0400
@@ -0,0 +1,485 @@
+/*
+ * 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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <priv_utils.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <strings.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <zone.h>
+#include <libipadm.h>
+#include <libdladm.h>
+#include <libdllink.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <net/route.h>
+#include <errno.h>
+#include <inet/ip.h>
+#include <string.h>
+#include <libinetutil.h>
+#include <unistd.h>
+#include <libipadm_impl.h>
+#include <sys/brand.h>
+
+#define ROUNDUP_LONG(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof (long) - 1))) : sizeof (long))
+#define HOST_MASK 0xffffffffU
+
+typedef struct ngz_walk_data_s {
+ ipadm_handle_t ngz_iph;
+ zoneid_t ngz_zoneid;
+ char *ngz_ifname;
+ boolean_t ngz_s10c;
+ ipadm_status_t ngz_ipstatus;
+ persist_cb_t ngz_persist_if;
+} ngz_walk_data_t;
+
+/*
+ * Tell the kernel to add, delete or change a route
+ */
+static void
+i_ipadm_rtioctl4(int rtsock,
+ int action, /* RTM_DELETE, etc */
+ in_addr_t dst,
+ in_addr_t gate,
+ uint_t masklen,
+ char *ifname,
+ uint8_t metric,
+ int flags)
+{
+ static int rt_sock_seqno = 0;
+ struct {
+ struct rt_msghdr w_rtm;
+ struct sockaddr_in w_dst;
+ struct sockaddr_in w_gate;
+ uint8_t w_space[512];
+ } w;
+ struct sockaddr_in w_mask;
+ struct sockaddr_dl w_ifp;
+ uint8_t *cp;
+ long cc;
+
+again:
+ (void) memset(&w, 0, sizeof (w));
+ (void) memset(&w_mask, 0, sizeof (w_mask));
+ (void) memset(&w_ifp, 0, sizeof (w_ifp));
+ cp = w.w_space;
+ w.w_rtm.rtm_msglen = sizeof (struct rt_msghdr) +
+ 2 * ROUNDUP_LONG(sizeof (struct sockaddr_in));
+ w.w_rtm.rtm_version = RTM_VERSION;
+ w.w_rtm.rtm_type = action;
+ w.w_rtm.rtm_flags = (flags | RTF_ZONE);
+ w.w_rtm.rtm_seq = ++rt_sock_seqno;
+ w.w_rtm.rtm_addrs = RTA_DST|RTA_GATEWAY;
+ if (metric != 0 || action == RTM_CHANGE) {
+ w.w_rtm.rtm_rmx.rmx_hopcount = metric;
+ w.w_rtm.rtm_inits |= RTV_HOPCOUNT;
+ }
+ w.w_dst.sin_family = AF_INET;
+ w.w_dst.sin_addr.s_addr = dst;
+ w.w_gate.sin_family = AF_INET;
+ w.w_gate.sin_addr.s_addr = gate;
+ if (masklen == HOST_MASK) {
+ w.w_rtm.rtm_flags |= RTF_HOST;
+ } else {
+ struct sockaddr_storage m4;
+
+ w.w_rtm.rtm_addrs |= RTA_NETMASK;
+ w_mask.sin_family = AF_INET;
+ if (plen2mask(masklen, AF_INET, &m4) != 0) {
+ return;
+ }
+ w_mask.sin_addr = ((struct sockaddr_in *)&m4)->sin_addr;
+ (void) memmove(cp, &w_mask, sizeof (w_mask));
+ cp += ROUNDUP_LONG(sizeof (struct sockaddr_in));
+ w.w_rtm.rtm_msglen += ROUNDUP_LONG(sizeof (struct sockaddr_in));
+ }
+ w_ifp.sdl_family = AF_LINK;
+ w.w_rtm.rtm_addrs |= RTA_IFP;
+ w_ifp.sdl_index = if_nametoindex(ifname);
+ (void) memmove(cp, &w_ifp, sizeof (w_ifp));
+ w.w_rtm.rtm_msglen += ROUNDUP_LONG(sizeof (struct sockaddr_dl));
+
+ cc = write(rtsock, &w, w.w_rtm.rtm_msglen);
+ if (cc < 0) {
+ if (errno == ESRCH && (action == RTM_CHANGE ||
+ action == RTM_DELETE)) {
+ if (action == RTM_CHANGE) {
+ action = RTM_ADD;
+ goto again;
+ }
+ return;
+ }
+ return;
+ } else if (cc != w.w_rtm.rtm_msglen) {
+ return;
+ }
+}
+
+static void
+i_ipadm_rtioctl6(int rtsock,
+ int action, /* RTM_DELETE, etc */
+ in6_addr_t dst,
+ in6_addr_t gate,
+ uint_t prefix_length,
+ char *ifname,
+ int flags)
+{
+ static int rt_sock_seqno = 0;
+ struct {
+ struct rt_msghdr w_rtm;
+ struct sockaddr_in6 w_dst;
+ struct sockaddr_in6 w_gate;
+ uint8_t w_space[512];
+ } w;
+ struct sockaddr_in6 w_mask;
+ struct sockaddr_dl w_ifp;
+ uint8_t *cp;
+ long cc;
+
+again:
+ (void) memset(&w, 0, sizeof (w));
+ (void) memset(&w_mask, 0, sizeof (w_mask));
+ (void) memset(&w_ifp, 0, sizeof (w_ifp));
+ cp = w.w_space;
+ w.w_rtm.rtm_msglen = sizeof (struct rt_msghdr) +
+ 2 * ROUNDUP_LONG(sizeof (struct sockaddr_in6));
+ w.w_rtm.rtm_version = RTM_VERSION;
+ w.w_rtm.rtm_type = action;
+ w.w_rtm.rtm_flags = (flags | RTF_ZONE);
+ w.w_rtm.rtm_seq = ++rt_sock_seqno;
+ w.w_rtm.rtm_addrs = RTA_DST|RTA_GATEWAY;
+ w.w_dst.sin6_family = AF_INET6;
+ w.w_dst.sin6_addr = dst;
+ w.w_gate.sin6_family = AF_INET6;
+ w.w_gate.sin6_addr = gate;
+ if (prefix_length == IPV6_ABITS) {
+ w.w_rtm.rtm_flags |= RTF_HOST;
+ } else {
+ struct sockaddr_storage m6;
+
+ w.w_rtm.rtm_addrs |= RTA_NETMASK;
+ w_mask.sin6_family = AF_INET6;
+ if (plen2mask(prefix_length, AF_INET6, &m6) != 0) {
+ return;
+ }
+ w_mask.sin6_addr = ((struct sockaddr_in6 *)&m6)->sin6_addr;
+ (void) memmove(cp, &w_mask, sizeof (w_mask));
+ cp += ROUNDUP_LONG(sizeof (struct sockaddr_in6));
+ w.w_rtm.rtm_msglen +=
+ ROUNDUP_LONG(sizeof (struct sockaddr_in6));
+ }
+ w_ifp.sdl_family = AF_LINK;
+ w.w_rtm.rtm_addrs |= RTA_IFP;
+ w_ifp.sdl_index = if_nametoindex(ifname);
+ (void) memmove(cp, &w_ifp, sizeof (w_ifp));
+ w.w_rtm.rtm_msglen += ROUNDUP_LONG(sizeof (struct sockaddr_dl));
+
+ cc = write(rtsock, &w, w.w_rtm.rtm_msglen);
+ if (cc < 0) {
+ if (errno == ESRCH && (action == RTM_CHANGE ||
+ action == RTM_DELETE)) {
+ if (action == RTM_CHANGE) {
+ action = RTM_ADD;
+ goto again;
+ }
+ return;
+ }
+ return;
+ } else if (cc != w.w_rtm.rtm_msglen) {
+ return;
+ }
+}
+
+/*
+ * Return TRUE if running in a Solaris 10 Container.
+ */
+static boolean_t
+i_ipadm_zone_is_s10c(zoneid_t zoneid)
+{
+ char brand[MAXNAMELEN];
+
+ if (zone_getattr(zoneid, ZONE_ATTR_BRAND, brand, sizeof (brand)) < 0)
+ return (B_FALSE);
+ return (strcmp(brand, NATIVE_BRAND_NAME) != 0);
+}
+
+/*
+ * Configure addresses on link. `buf' is a string of comma-separated
+ * IP addresses.
+ */
+static ipadm_status_t
+i_ipadm_ngz_addr(ipadm_handle_t iph, char *link, char *buf)
+{
+ ipadm_status_t ipstatus;
+ ipadm_addrobj_t ipaddr;
+ char *cp;
+
+ for (cp = strtok(buf, ","); cp != NULL; cp = strtok(NULL, ",")) {
+ ipstatus = ipadm_create_addrobj(IPADM_ADDR_STATIC, link,
+ &ipaddr);
+ if (ipstatus != IPADM_SUCCESS)
+ return (ipstatus);
+ /*
+ * ipadm_set_addr does the appropriate name resolution and
+ * sets up the ipadm_static_addr field.
+ */
+ ipstatus = ipadm_set_addr(ipaddr, cp, AF_UNSPEC);
+ if (ipstatus != IPADM_SUCCESS) {
+ ipadm_destroy_addrobj(ipaddr);
+ return (ipstatus);
+ }
+
+ ipstatus = ipadm_create_addr(iph, ipaddr,
+ (IPADM_OPT_ACTIVE | IPADM_OPT_UP));
+ if (ipstatus != IPADM_SUCCESS) {
+ ipadm_destroy_addrobj(ipaddr);
+ return (ipstatus);
+ }
+ ipadm_destroy_addrobj(ipaddr);
+ }
+ return (IPADM_SUCCESS);
+}
+
+/*
+ * The (*persist_if)() will set up persistent information for the interface,
+ * based on what interface families are required, so just resolve the
+ * address and inform the callback about the linkname, and required address
+ * families.
+ */
+static ipadm_status_t
+i_ipadm_ngz_persist_if(char *link, char *buf,
+ void (*ngz_persist_if)(char *, boolean_t, boolean_t))
+{
+ char *cp, *slashp, addr[INET6_ADDRSTRLEN];
+ ipadm_status_t ipstatus;
+ struct sockaddr_storage ss;
+ boolean_t v4 = B_FALSE;
+ boolean_t v6 = B_FALSE;
+
+ for (cp = strtok(buf, ","); cp != NULL; cp = strtok(NULL, ",")) {
+ /* remove the /<masklen> that's always added by zoneadmd */
+ slashp = strchr(cp, '/');
+ (void) strlcpy(addr, cp, (slashp - cp + 1));
+
+ /* resolve the address to find the family */
+ bzero(&ss, sizeof (ss));
+ ipstatus = i_ipadm_resolve_addr(addr, AF_UNSPEC, &ss);
+ if (ipstatus != IPADM_SUCCESS)
+ return (ipstatus);
+ switch (ss.ss_family) {
+ case AF_INET:
+ v4 = B_TRUE;
+ break;
+ case AF_INET6:
+ v6 = B_TRUE;
+ break;
+ default:
+ return (IPADM_BAD_ADDR);
+ }
+ }
+ (*ngz_persist_if)(link, v4, v6);
+ return (IPADM_SUCCESS);
+}
+
+static void
+i_ipadm_create_ngz_route(int rtsock, char *link, uint8_t *buf, size_t buflen)
+{
+ struct in6_addr defrouter;
+ boolean_t isv6;
+ struct in_addr gw4;
+ uint8_t *cp;
+ const in6_addr_t ipv6_all_zeros = { 0, 0, 0, 0 };
+
+ if (rtsock == -1)
+ return;
+
+ for (cp = buf; cp < buf + buflen; cp += sizeof (defrouter)) {
+ bcopy(cp, &defrouter, sizeof (defrouter));
+ if (IN6_IS_ADDR_UNSPECIFIED(&defrouter))
+ break;
+ isv6 = !IN6_IS_ADDR_V4MAPPED(&defrouter);
+ if (isv6) {
+ i_ipadm_rtioctl6(rtsock, RTM_ADD, ipv6_all_zeros,
+ defrouter, 0, link, RTF_GATEWAY);
+ } else {
+ IN6_V4MAPPED_TO_INADDR(&defrouter, &gw4);
+ i_ipadm_rtioctl4(rtsock, RTM_ADD, INADDR_ANY,
+ gw4.s_addr, 0, link, 0, RTF_GATEWAY);
+ }
+ }
+}
+
+/*
+ * Wrapper function to zone_getattr() for retrieving from-gz attributes that
+ * were made availabe for exclusive IP non-global zones by zoneadmd from teh
+ * global zone.
+ */
+static ipadm_status_t
+i_ipadm_zone_get_network(zoneid_t zoneid, datalink_id_t linkid, int type,
+ void *buf, size_t *bufsize)
+{
+ zone_net_data_t *zndata;
+
+ zndata = calloc(1, sizeof (*zndata) + *bufsize);
+ if (zndata == NULL)
+ return (IPADM_NO_MEMORY);
+ zndata->zn_type = type;
+ zndata->zn_linkid = linkid;
+ zndata->zn_len = *bufsize;
+
+ if (zone_getattr(zoneid, ZONE_ATTR_NETWORK, zndata,
+ sizeof (*zndata) + *bufsize) < 0) {
+ return (ipadm_errno2status(errno));
+ }
+ *bufsize = zndata->zn_len;
+ bcopy(zndata->zn_val, buf, *bufsize);
+ return (IPADM_SUCCESS);
+}
+
+/*
+ * Callback function that configures a single datalink in a non-global zone.
+ */
+static int
+i_ipadm_zone_network_attr(dladm_handle_t dh, datalink_id_t linkid, void *arg)
+{
+ ngz_walk_data_t *nwd = arg;
+ zoneid_t zoneid = nwd->ngz_zoneid;
+ uint8_t buf[PIPE_BUF];
+ dladm_status_t dlstatus;
+ ipadm_status_t ipstatus;
+ char link[MAXLINKNAMELEN];
+ ipadm_handle_t iph = nwd->ngz_iph;
+ int rtsock = iph->iph_rtsock;
+ char *ifname = nwd->ngz_ifname;
+ boolean_t s10c = nwd->ngz_s10c;
+ boolean_t is_ipmgmtd = (iph->iph_flags & IPH_IPMGMTD);
+ size_t bufsize = sizeof (buf);
+
+ bzero(buf, bufsize);
+ ipstatus = i_ipadm_zone_get_network(zoneid, linkid,
+ ZONE_NETWORK_ADDRESS, buf, &bufsize);
+ if (ipstatus != IPADM_SUCCESS)
+ goto fail;
+
+ dlstatus = dladm_datalink_id2info(dh, linkid, NULL, NULL,
+ NULL, link, sizeof (link));
+ if (dlstatus != DLADM_STATUS_OK)
+ return (DLADM_WALK_CONTINUE);
+
+ /*
+ * if ifname has been specified, then skip interfaces that don't match
+ */
+ if (ifname != NULL && strcmp(ifname, link) != 0)
+ return (DLADM_WALK_CONTINUE);
+
+ /*
+ * Plumb the interface and configure addresses on for S10 Containers.
+ * We need to always do this for S10C because ipadm persistent
+ * configuration is not available in S10C. For ipkg zones,
+ * we skip the actual plumbing/configuration, but will call the
+ * (*ngz_persist_if)() callback to create the persistent state for the
+ * interface. The interface will be configured in ipkg zones when
+ * ipadm_enable_if() is invoked to restore persistent configuration.
+ */
+ if (is_ipmgmtd && !s10c) {
+ (void) i_ipadm_ngz_persist_if(link, (char *)buf,
+ nwd->ngz_persist_if);
+ return (DLADM_WALK_CONTINUE);
+ }
+ ipstatus = i_ipadm_ngz_addr(iph, link, (char *)buf);
+ if (ipstatus != IPADM_SUCCESS)
+ goto fail;
+
+ /* apply any default router information. */
+ bufsize = sizeof (buf);
+ bzero(buf, bufsize);
+ ipstatus = i_ipadm_zone_get_network(zoneid, linkid,
+ ZONE_NETWORK_DEFROUTER, buf, &bufsize);
+ if (ipstatus != IPADM_SUCCESS)
+ goto fail;
+
+ i_ipadm_create_ngz_route(rtsock, link, buf, bufsize);
+
+ return (DLADM_WALK_CONTINUE);
+fail:
+ if (ifname != NULL) {
+ nwd->ngz_ipstatus = ipstatus;
+ return (DLADM_WALK_TERMINATE);
+ }
+ return (DLADM_WALK_CONTINUE);
+}
+
+/*
+ * ipmgmt_net_from_gz_init() initializes exclusive-IP stack non-global zones by
+ * extracting configuration that has been saved in the kernel and applying
+ * that information to the appropriate datalinks for the zone. If an ifname
+ * argument is passed in, only the selected IP interface corresponding to
+ * datalink will be initialized, otherwise all datalinks will be plumbed for IP
+ * and IP address and route information will be configured.
+ */
+ipadm_status_t
+ipadm_init_net_from_gz(ipadm_handle_t iph, char *ifname,
+ void (*persist_if)(char *, boolean_t, boolean_t))
+{
+ ngz_walk_data_t nwd;
+ uint64_t flags;
+ dladm_handle_t dlh = iph->iph_dlh;
+ datalink_id_t linkid;
+
+ if (iph->iph_zoneid == GLOBAL_ZONEID)
+ return (IPADM_NOTSUP);
+
+ if (ifname != NULL &&
+ i_ipadm_get_flags(iph, ifname, AF_INET, &flags) != IPADM_SUCCESS &&
+ i_ipadm_get_flags(iph, ifname, AF_INET6, &flags) != IPADM_SUCCESS)
+ return (IPADM_ENXIO);
+
+ if (ifname != NULL && !(flags & IFF_L3PROTECT))
+ return (IPADM_SUCCESS); /* nothing to initialize */
+
+ nwd.ngz_iph = iph;
+ nwd.ngz_zoneid = iph->iph_zoneid;
+ nwd.ngz_ifname = ifname;
+ nwd.ngz_persist_if = persist_if;
+ nwd.ngz_s10c = i_ipadm_zone_is_s10c(iph->iph_zoneid);
+ nwd.ngz_ipstatus = IPADM_SUCCESS;
+ if (ifname != NULL) {
+ if (dladm_name2info(dlh, ifname, &linkid, NULL, NULL,
+ NULL) != DLADM_STATUS_OK) {
+ return (IPADM_ENXIO);
+ }
+ (void) i_ipadm_zone_network_attr(dlh, linkid, &nwd);
+ } else {
+ (void) dladm_walk_datalink_id(i_ipadm_zone_network_attr, dlh,
+ &nwd, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE,
+ DLADM_OPT_PERSIST);
+ }
+ return (nwd.ngz_ipstatus);
+}
--- a/usr/src/lib/libipadm/common/libipadm.c Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/lib/libipadm/common/libipadm.c Thu Jul 01 17:10:52 2010 -0400
@@ -97,7 +97,8 @@
{ IPADM_IPC_ERROR, "Could not communicate with ipmgmtd" },
{ IPADM_NOTSUP, "Operation not supported" },
{ IPADM_OP_DISABLE_OBJ, "Operation not supported on disabled object" },
- { IPADM_EBADE, "Invalid data exchange with daemon" }
+ { IPADM_EBADE, "Invalid data exchange with daemon" },
+ { IPADM_GZ_PERM, "Operation not permitted on from-gz interface"}
};
#define IPADM_NUM_ERRORS (sizeof (ipadm_errors) / sizeof (*ipadm_errors))
@@ -186,7 +187,7 @@
return (IPADM_INVALID_ARG);
*handle = NULL;
- if (flags & ~(IPH_VRRP|IPH_LEGACY|IPH_INIT))
+ if (flags & ~(IPH_VRRP|IPH_LEGACY|IPH_INIT|IPH_IPMGMTD))
return (IPADM_INVALID_ARG);
if ((iph = calloc(1, sizeof (struct ipadm_handle))) == NULL)
@@ -194,6 +195,7 @@
iph->iph_sock = -1;
iph->iph_sock6 = -1;
iph->iph_door_fd = -1;
+ iph->iph_rtsock = -1;
iph->iph_flags = flags;
(void) pthread_mutex_init(&iph->iph_lock, NULL);
@@ -213,6 +215,7 @@
* dladm_open() for such zones.
*/
zoneid = getzoneid();
+ iph->iph_zoneid = zoneid;
if (zoneid != GLOBAL_ZONEID) {
if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &zflags,
sizeof (zflags)) < 0) {
@@ -224,6 +227,14 @@
ipadm_close(iph);
return (IPADM_DLADM_FAILURE);
}
+ if (zoneid != GLOBAL_ZONEID) {
+ iph->iph_rtsock = socket(PF_ROUTE, SOCK_RAW, 0);
+ /*
+ * Failure to open rtsock is ignored as this is
+ * only used in non-global zones to initialize
+ * routing socket information.
+ */
+ }
} else {
assert(zoneid != GLOBAL_ZONEID);
iph->iph_dlh = NULL;
@@ -256,6 +267,8 @@
(void) close(iph->iph_sock);
if (iph->iph_sock6 != -1)
(void) close(iph->iph_sock6);
+ if (iph->iph_rtsock != -1)
+ (void) close(iph->iph_rtsock);
if (iph->iph_door_fd != -1)
(void) close(iph->iph_door_fd);
dladm_close(iph->iph_dlh);
@@ -494,7 +507,7 @@
datalink_id_t linkid;
if (iph->iph_dlh == NULL) {
- assert(getzoneid() != GLOBAL_ZONEID);
+ assert(iph->iph_zoneid != GLOBAL_ZONEID);
return (B_FALSE);
}
dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid, NULL,
@@ -682,6 +695,8 @@
ipadm_status_t ret_status = IPADM_SUCCESS;
char newifname[LIFNAMSIZ];
char *aobjstr;
+ sa_family_t af = AF_UNSPEC;
+ boolean_t is_ngz = (iph->iph_zoneid != GLOBAL_ZONEID);
(void) strlcpy(newifname, ifname, sizeof (newifname));
/*
@@ -705,6 +720,9 @@
*/
if (status == IPADM_IF_EXISTS)
status = IPADM_SUCCESS;
+
+ if (is_ngz)
+ af = atoi(afstr);
} else if (nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,
&aobjstr) == 0) {
/*
@@ -736,6 +754,9 @@
if (status != IPADM_SUCCESS)
return (status);
}
+
+ if (is_ngz && af != AF_UNSPEC)
+ ret_status = ipadm_init_net_from_gz(iph, newifname, NULL);
return (ret_status);
}
--- a/usr/src/lib/libipadm/common/libipadm.h Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/lib/libipadm/common/libipadm.h Thu Jul 01 17:10:52 2010 -0400
@@ -91,7 +91,8 @@
IPADM_IPC_ERROR, /* Cannot communicate with ipmgmtd */
IPADM_OP_DISABLE_OBJ, /* Operation on disable object */
IPADM_NOTSUP, /* Operation not supported */
- IPADM_EBADE /* Invalid data exchange with ipmgmtd */
+ IPADM_EBADE, /* Invalid data exchange with ipmgmtd */
+ IPADM_GZ_PERM /* Operation not permitted on from-gz intf */
} ipadm_status_t;
/*
@@ -171,6 +172,7 @@
/* ipadm_handle flags */
#define IPH_VRRP 0x00000001 /* Caller is VRRP */
#define IPH_LEGACY 0x00000002 /* Caller is legacy app */
+#define IPH_IPMGMTD 0x00000004 /* Caller is ipmgmtd itself */
/* opaque address object structure */
typedef struct ipadm_addrobj_s *ipadm_addrobj_t;
@@ -204,6 +206,7 @@
#define IFIF_NOACCEPT 0x00000100
#define IFIF_IPV4 0x00000200
#define IFIF_IPV6 0x00000400
+#define IFIF_L3PROTECT 0x00000800
/* ipadm_addr_info_t state */
typedef enum {
--- a/usr/src/lib/libipadm/common/libipadm_impl.h Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/lib/libipadm/common/libipadm_impl.h Thu Jul 01 17:10:52 2010 -0400
@@ -55,9 +55,11 @@
int iph_sock; /* socket to interface */
int iph_sock6; /* socket to interface */
int iph_door_fd; /* door descriptor to ipmgmtd */
+ int iph_rtsock; /* routing socket */
dladm_handle_t iph_dlh; /* handle to libdladm library */
uint32_t iph_flags; /* internal flags */
pthread_mutex_t iph_lock; /* lock to set door_fd */
+ zoneid_t iph_zoneid; /* zoneid where handle was opened */
};
/*
@@ -210,6 +212,8 @@
const ipadm_addrobj_t, uint32_t);
extern boolean_t i_ipadm_name2atype(const char *, sa_family_t *,
ipadm_addr_type_t *);
+extern ipadm_status_t i_ipadm_resolve_addr(const char *, sa_family_t,
+ struct sockaddr_storage *);
/* ipadm_if.c */
extern ipadm_status_t i_ipadm_create_if(ipadm_handle_t, char *, sa_family_t,
--- a/usr/src/lib/libipadm/common/mapfile-vers Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/lib/libipadm/common/mapfile-vers Thu Jul 01 17:10:52 2010 -0400
@@ -67,6 +67,7 @@
ipadm_if_info;
ipadm_if_move;
ipadm_init_prop;
+ ipadm_init_net_from_gz;
ipadm_ndpd_read;
ipadm_ndpd_write;
ipadm_nvlist2str;
--- a/usr/src/lib/libzonecfg/common/libzonecfg.c Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/lib/libzonecfg/common/libzonecfg.c Thu Jul 01 17:10:52 2010 -0400
@@ -99,6 +99,7 @@
#define DTD_ATTR_ACTION (const xmlChar *) "action"
#define DTD_ATTR_ADDRESS (const xmlChar *) "address"
+#define DTD_ATTR_ALLOWED_ADDRESS (const xmlChar *) "allowed-address"
#define DTD_ATTR_AUTOBOOT (const xmlChar *) "autoboot"
#define DTD_ATTR_IPTYPE (const xmlChar *) "ip-type"
#define DTD_ATTR_DEFROUTER (const xmlChar *) "defrouter"
@@ -2090,6 +2091,8 @@
size_t addrspec; /* nonzero if tabptr has IP addr */
size_t physspec; /* nonzero if tabptr has interface */
size_t defrouterspec; /* nonzero if tabptr has def. router */
+ size_t allowed_addrspec;
+ zone_iptype_t iptype;
if (tabptr == NULL)
return (Z_INVAL);
@@ -2104,12 +2107,18 @@
addrspec = strlen(tabptr->zone_nwif_address);
physspec = strlen(tabptr->zone_nwif_physical);
defrouterspec = strlen(tabptr->zone_nwif_defrouter);
- if (addrspec == 0 && physspec == 0 && defrouterspec == 0)
+ allowed_addrspec = strlen(tabptr->zone_nwif_allowed_address);
+ if (addrspec != 0 && allowed_addrspec != 0)
+ return (Z_INVAL); /* can't specify both */
+ if (addrspec == 0 && physspec == 0 && defrouterspec == 0 &&
+ allowed_addrspec == 0)
return (Z_INSUFFICIENT_SPEC);
if ((err = operation_prep(handle)) != Z_OK)
return (err);
+ if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK)
+ return (err);
/*
* Iterate over the configuration's elements and look for net elements
* that match the query.
@@ -2129,11 +2138,18 @@
physical, sizeof (physical)) != Z_OK ||
strcmp(tabptr->zone_nwif_physical, physical) != 0))
continue;
- if (addrspec != 0 && (fetchprop(cur, DTD_ATTR_ADDRESS, address,
+ if (iptype == ZS_SHARED && addrspec != 0 &&
+ (fetchprop(cur, DTD_ATTR_ADDRESS, address,
sizeof (address)) != Z_OK ||
!zonecfg_same_net_address(tabptr->zone_nwif_address,
address)))
continue;
+ if (iptype == ZS_EXCLUSIVE && allowed_addrspec != 0 &&
+ (fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS, address,
+ sizeof (address)) != Z_OK ||
+ !zonecfg_same_net_address(tabptr->zone_nwif_allowed_address,
+ address)))
+ continue;
if (defrouterspec != 0 && (fetchprop(cur, DTD_ATTR_DEFROUTER,
address, sizeof (address)) != Z_OK ||
!zonecfg_same_net_address(tabptr->zone_nwif_defrouter,
@@ -2158,10 +2174,17 @@
sizeof (tabptr->zone_nwif_physical))) != Z_OK)
return (err);
- if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
+ if (iptype == ZS_SHARED &&
+ (err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
sizeof (tabptr->zone_nwif_address))) != Z_OK)
return (err);
+ if (iptype == ZS_EXCLUSIVE &&
+ (err = fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS,
+ tabptr->zone_nwif_allowed_address,
+ sizeof (tabptr->zone_nwif_allowed_address))) != Z_OK)
+ return (err);
+
if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
tabptr->zone_nwif_defrouter,
sizeof (tabptr->zone_nwif_defrouter))) != Z_OK)
@@ -2177,9 +2200,14 @@
int err;
newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL);
- if ((err = newprop(newnode, DTD_ATTR_ADDRESS,
+ if (strlen(tabptr->zone_nwif_address) > 0 &&
+ (err = newprop(newnode, DTD_ATTR_ADDRESS,
tabptr->zone_nwif_address)) != Z_OK)
return (err);
+ if (strlen(tabptr->zone_nwif_allowed_address) > 0 &&
+ (err = newprop(newnode, DTD_ATTR_ALLOWED_ADDRESS,
+ tabptr->zone_nwif_allowed_address)) != Z_OK)
+ return (err);
if ((err = newprop(newnode, DTD_ATTR_PHYSICAL,
tabptr->zone_nwif_physical)) != Z_OK)
return (err);
@@ -2215,7 +2243,7 @@
zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
{
xmlNodePtr cur = handle->zone_dh_cur;
- boolean_t addr_match, phys_match;
+ boolean_t addr_match, phys_match, allowed_addr_match;
for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
if (xmlStrcmp(cur->name, DTD_ELEM_NET))
@@ -2223,10 +2251,12 @@
addr_match = match_prop(cur, DTD_ATTR_ADDRESS,
tabptr->zone_nwif_address);
+ allowed_addr_match = match_prop(cur, DTD_ATTR_ALLOWED_ADDRESS,
+ tabptr->zone_nwif_allowed_address);
phys_match = match_prop(cur, DTD_ATTR_PHYSICAL,
tabptr->zone_nwif_physical);
- if (addr_match && phys_match) {
+ if ((addr_match || allowed_addr_match) && phys_match) {
xmlUnlinkNode(cur);
xmlFreeNode(cur);
return (Z_OK);
@@ -4734,6 +4764,13 @@
return (err);
}
+ if ((err = fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS,
+ tabptr->zone_nwif_allowed_address,
+ sizeof (tabptr->zone_nwif_allowed_address))) != Z_OK) {
+ handle->zone_dh_cur = handle->zone_dh_top;
+ return (err);
+ }
+
if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
sizeof (tabptr->zone_nwif_physical))) != Z_OK) {
handle->zone_dh_cur = handle->zone_dh_top;
--- a/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1 Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1 Thu Jul 01 17:10:52 2010 -0400
@@ -49,6 +49,7 @@
<!ELEMENT network EMPTY>
<!ATTLIST network address CDATA ""
+ allowed-address CDATA ""
defrouter CDATA ""
physical CDATA #REQUIRED>
--- a/usr/src/uts/common/inet/ip.h Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/uts/common/inet/ip.h Thu Jul 01 17:10:52 2010 -0400
@@ -1801,6 +1801,8 @@
timeout_id_t ill_refresh_tid; /* ill refresh retry timeout id */
uint32_t ill_mrouter_cnt; /* mrouter allmulti joins */
+ uint32_t ill_allowed_ips_cnt;
+ in6_addr_t *ill_allowed_ips;
} ill_t;
/*
--- a/usr/src/uts/common/inet/ip/ip.c Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/uts/common/inet/ip/ip.c Thu Jul 01 17:10:52 2010 -0400
@@ -8579,6 +8579,10 @@
ill_capability_reset(ill, B_TRUE);
ipsq_current_finish(ipsq);
break;
+
+ case DL_NOTE_ALLOWED_IPS:
+ ill_set_allowed_ips(ill, mp);
+ break;
default:
ip0dbg(("ip_rput_dlpi_writer: unknown notification "
"type 0x%x for DL_NOTIFY_IND\n",
--- a/usr/src/uts/common/inet/ip/ip6_if.c Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/uts/common/inet/ip/ip6_if.c Thu Jul 01 17:10:52 2010 -0400
@@ -19,10 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-/*
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1990 Mentat Inc.
*/
@@ -2302,7 +2299,7 @@
(DL_NOTE_PHYS_ADDR | DL_NOTE_SDU_SIZE | DL_NOTE_FASTPATH_FLUSH |
DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN | DL_NOTE_CAPAB_RENEG |
DL_NOTE_PROMISC_ON_PHYS | DL_NOTE_PROMISC_OFF_PHYS |
- DL_NOTE_REPLUMB);
+ DL_NOTE_REPLUMB | DL_NOTE_ALLOWED_IPS);
phys_mp = ip_dlpi_alloc(sizeof (dl_phys_addr_req_t) +
sizeof (t_scalar_t), DL_PHYS_ADDR_REQ);
--- a/usr/src/uts/common/inet/ip/ip_if.c Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/uts/common/inet/ip/ip_if.c Thu Jul 01 17:10:52 2010 -0400
@@ -94,6 +94,7 @@
#include <inet/ipclassifier.h>
#include <sys/mac_client.h>
#include <sys/dld.h>
+#include <sys/mac_flow.h>
#include <sys/systeminfo.h>
#include <sys/bootconf.h>
@@ -546,6 +547,15 @@
ill->ill_dld_capab = NULL;
}
+ /* Clean up ill_allowed_ips* related state */
+ if (ill->ill_allowed_ips != NULL) {
+ ASSERT(ill->ill_allowed_ips_cnt > 0);
+ kmem_free(ill->ill_allowed_ips,
+ ill->ill_allowed_ips_cnt * sizeof (in6_addr_t));
+ ill->ill_allowed_ips = NULL;
+ ill->ill_allowed_ips_cnt = 0;
+ }
+
while (ill->ill_ipif != NULL)
ipif_free_tail(ill->ill_ipif);
@@ -2683,6 +2693,9 @@
if (IS_LOOPBACK(ill))
return (EINVAL);
+ if (enable && ill->ill_allowed_ips_cnt > 0)
+ return (EPERM);
+
if (IS_IPMP(ill) || IS_UNDER_IPMP(ill)) {
/*
* Update all of the interfaces in the group.
@@ -9656,15 +9669,17 @@
int err = 0;
in6_addr_t v6addr;
boolean_t need_up = B_FALSE;
+ ill_t *ill;
+ int i;
ip1dbg(("ip_sioctl_addr(%s:%u %p)\n",
ipif->ipif_ill->ill_name, ipif->ipif_id, (void *)ipif));
ASSERT(IAM_WRITER_IPIF(ipif));
+ ill = ipif->ipif_ill;
if (ipif->ipif_isv6) {
sin6_t *sin6;
- ill_t *ill;
phyint_t *phyi;
if (sin->sin_family != AF_INET6)
@@ -9672,7 +9687,6 @@
sin6 = (sin6_t *)sin;
v6addr = sin6->sin6_addr;
- ill = ipif->ipif_ill;
phyi = ill->ill_phyint;
/*
@@ -9731,7 +9745,21 @@
IN6_IPADDR_TO_V4MAPPED(addr, &v6addr);
}
-
+ /*
+ * verify that the address being configured is permitted by the
+ * ill_allowed_ips[] for the interface.
+ */
+ if (ill->ill_allowed_ips_cnt > 0) {
+ for (i = 0; i < ill->ill_allowed_ips_cnt; i++) {
+ if (IN6_ARE_ADDR_EQUAL(&ill->ill_allowed_ips[i],
+ &v6addr))
+ break;
+ }
+ if (i == ill->ill_allowed_ips_cnt) {
+ pr_addr_dbg("!allowed addr %s\n", AF_INET6, &v6addr);
+ return (EPERM);
+ }
+ }
/*
* Even if there is no change we redo things just to rerun
* ipif_set_default.
@@ -10373,8 +10401,11 @@
* If ILLF_ROUTER changes, we need to change the ip forwarding
* status of the interface.
*/
- if ((turn_on | turn_off) & ILLF_ROUTER)
- (void) ill_forward_set(ill, ((turn_on & ILLF_ROUTER) != 0));
+ if ((turn_on | turn_off) & ILLF_ROUTER) {
+ err = ill_forward_set(ill, ((turn_on & ILLF_ROUTER) != 0));
+ if (err != 0)
+ return (err);
+ }
/*
* If the interface is not UP and we are not going to
@@ -17781,6 +17812,51 @@
}
/*
+ * When the allowed-ips link property is set on the datalink, IP receives a
+ * DL_NOTE_ALLOWED_IPS notification that is processed in ill_set_allowed_ips()
+ * to initialize the ill_allowed_ips[] array in the ill_t. This array is then
+ * used to vet addresses passed to ip_sioctl_addr() and to ensure that the
+ * only IP addresses configured on the ill_t are those in the ill_allowed_ips[]
+ * array.
+ */
+void
+ill_set_allowed_ips(ill_t *ill, mblk_t *mp)
+{
+ ipsq_t *ipsq = ill->ill_phyint->phyint_ipsq;
+ dl_notify_ind_t *dlip = (dl_notify_ind_t *)mp->b_rptr;
+ mac_protect_t *mrp;
+ int i;
+
+ ASSERT(IAM_WRITER_IPSQ(ipsq));
+ mrp = (mac_protect_t *)&dlip[1];
+
+ if (mrp->mp_ipaddrcnt == 0) { /* reset allowed-ips */
+ kmem_free(ill->ill_allowed_ips,
+ ill->ill_allowed_ips_cnt * sizeof (in6_addr_t));
+ ill->ill_allowed_ips_cnt = 0;
+ ill->ill_allowed_ips = NULL;
+ mutex_enter(&ill->ill_phyint->phyint_lock);
+ ill->ill_phyint->phyint_flags &= ~PHYI_L3PROTECT;
+ mutex_exit(&ill->ill_phyint->phyint_lock);
+ return;
+ }
+
+ if (ill->ill_allowed_ips != NULL) {
+ kmem_free(ill->ill_allowed_ips,
+ ill->ill_allowed_ips_cnt * sizeof (in6_addr_t));
+ }
+ ill->ill_allowed_ips_cnt = mrp->mp_ipaddrcnt;
+ ill->ill_allowed_ips = kmem_alloc(
+ ill->ill_allowed_ips_cnt * sizeof (in6_addr_t), KM_SLEEP);
+ for (i = 0; i < mrp->mp_ipaddrcnt; i++)
+ ill->ill_allowed_ips[i] = mrp->mp_ipaddrs[i].ip_addr;
+
+ mutex_enter(&ill->ill_phyint->phyint_lock);
+ ill->ill_phyint->phyint_flags |= PHYI_L3PROTECT;
+ mutex_exit(&ill->ill_phyint->phyint_lock);
+}
+
+/*
* Once the ill associated with `q' has quiesced, set its physical address
* information to the values in `addrmp'. Note that two copies of `addrmp'
* are passed (linked by b_cont), since we sometimes need to save two distinct
--- a/usr/src/uts/common/inet/ip_if.h Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/uts/common/inet/ip_if.h Thu Jul 01 17:10:52 2010 -0400
@@ -19,10 +19,9 @@
* CDDL HEADER END
*/
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1990 Mentat Inc.
*/
-/* Copyright (c) 1990 Mentat Inc. */
#ifndef _INET_IP_IF_H
#define _INET_IP_IF_H
@@ -76,7 +75,7 @@
*/
#define IFF_PHYINT_FLAGS (IFF_LOOPBACK|IFF_RUNNING|IFF_PROMISC| \
IFF_ALLMULTI|IFF_INTELLIGENT|IFF_MULTI_BCAST|IFF_FAILED|IFF_STANDBY| \
- IFF_INACTIVE|IFF_OFFLINE|IFF_VIRTUAL|IFF_IPMP)
+ IFF_INACTIVE|IFF_OFFLINE|IFF_VIRTUAL|IFF_IPMP|IFF_L3PROTECT)
#define IFF_PHYINTINST_FLAGS (IFF_DEBUG|IFF_NOTRAILERS|IFF_NOARP| \
IFF_MULTICAST|IFF_ROUTER|IFF_NONUD|IFF_NORTEXCH|IFF_IPV4|IFF_IPV6| \
@@ -99,6 +98,7 @@
#define PHYI_OFFLINE IFF_OFFLINE /* NIC has been offlined */
#define PHYI_VIRTUAL IFF_VIRTUAL /* Will not send or recv pkts */
#define PHYI_IPMP IFF_IPMP /* IPMP meta-interface */
+#define PHYI_L3PROTECT IFF_L3PROTECT /* Layer-3 protected */
#define ILLF_DEBUG IFF_DEBUG /* turn on debugging */
#define ILLF_NOTRAILERS IFF_NOTRAILERS /* avoid use of trailers */
@@ -195,6 +195,7 @@
extern void ill_set_inputfn(ill_t *);
extern void ill_set_inputfn_all(ip_stack_t *);
extern int ill_set_phys_addr(ill_t *, mblk_t *);
+extern void ill_set_allowed_ips(ill_t *, mblk_t *);
extern int ill_replumb(ill_t *, mblk_t *);
extern void ill_set_ndmp(ill_t *, mblk_t *, uint_t, uint_t);
--- a/usr/src/uts/common/io/dld/dld_proto.c Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/uts/common/io/dld/dld_proto.c Thu Jul 01 17:10:52 2010 -0400
@@ -1127,7 +1127,8 @@
DL_NOTE_CAPAB_RENEG |
DL_NOTE_FASTPATH_FLUSH |
DL_NOTE_SPEED |
- DL_NOTE_SDU_SIZE;
+ DL_NOTE_SDU_SIZE|
+ DL_NOTE_ALLOWED_IPS;
if (MBLKL(mp) < sizeof (dl_notify_req_t)) {
dl_err = DL_BADPRIM;
--- a/usr/src/uts/common/io/dld/dld_str.c Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/uts/common/io/dld/dld_str.c Thu Jul 01 17:10:52 2010 -0400
@@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -38,6 +37,7 @@
#include <sys/list.h>
#include <sys/mac_client.h>
#include <sys/mac_client_priv.h>
+#include <sys/mac_flow.h>
static int str_constructor(void *, void *, int);
static void str_destructor(void *, void *);
@@ -1719,6 +1719,35 @@
qreply(dsp->ds_wq, mp);
}
+static void
+str_notify_allowed_ips(dld_str_t *dsp)
+{
+ mblk_t *mp;
+ dl_notify_ind_t *dlip;
+ size_t mp_size;
+ mac_protect_t mrp;
+
+ if (!(dsp->ds_notifications & DL_NOTE_ALLOWED_IPS))
+ return;
+
+ mp_size = sizeof (mac_protect_t) + sizeof (dl_notify_ind_t);
+ if ((mp = mexchange(dsp->ds_wq, NULL, mp_size, M_PROTO, 0)) == NULL)
+ return;
+
+ mac_protect_get(dsp->ds_mh, &mrp);
+ bzero(mp->b_rptr, mp_size);
+ dlip = (dl_notify_ind_t *)mp->b_rptr;
+ dlip->dl_primitive = DL_NOTIFY_IND;
+ dlip->dl_notification = DL_NOTE_ALLOWED_IPS;
+ dlip->dl_data = 0;
+ dlip->dl_addr_offset = sizeof (dl_notify_ind_t);
+ dlip->dl_addr_length = sizeof (mac_protect_t);
+ bcopy(&mrp, mp->b_rptr + sizeof (dl_notify_ind_t),
+ sizeof (mac_protect_t));
+
+ qreply(dsp->ds_wq, mp);
+}
+
/*
* MAC notification callback.
*/
@@ -1849,6 +1878,10 @@
case MAC_NOTE_MARGIN:
break;
+ case MAC_NOTE_ALLOWED_IPS:
+ str_notify_allowed_ips(dsp);
+ break;
+
default:
ASSERT(B_FALSE);
break;
--- a/usr/src/uts/common/io/mac/mac_protect.c Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/uts/common/io/mac/mac_protect.c Thu Jul 01 17:10:52 2010 -0400
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <sys/strsun.h>
@@ -194,6 +193,7 @@
} dhcpv6_txn_t;
static void start_txn_cleanup_timer(mac_client_impl_t *);
+static boolean_t allowed_ips_set(mac_resource_props_t *, uint32_t);
#define BUMP_STAT(m, s) (m)->mci_misc_stat.mms_##s++
@@ -552,29 +552,34 @@
/*
* Core logic for intercepting outbound DHCPv4 packets.
*/
-static void
+static boolean_t
intercept_dhcpv4_outbound(mac_client_impl_t *mcip, ipha_t *ipha, uchar_t *end)
{
- struct dhcp *dh4;
- uchar_t *opt;
- dhcpv4_txn_t *txn, *ctxn;
- ipaddr_t ipaddr;
- uint8_t opt_len, mtype, cid[DHCP_MAX_OPT_SIZE], cid_len;
+ struct dhcp *dh4;
+ uchar_t *opt;
+ dhcpv4_txn_t *txn, *ctxn;
+ ipaddr_t ipaddr;
+ uint8_t opt_len, mtype, cid[DHCP_MAX_OPT_SIZE], cid_len;
+ mac_resource_props_t *mrp = MCIP_RESOURCE_PROPS(mcip);
if (get_dhcpv4_info(ipha, end, &dh4) != 0)
- return;
+ return (B_TRUE);
+
+ /* ip_nospoof/allowed-ips and DHCP are mutually exclusive by default */
+ if (allowed_ips_set(mrp, IPV4_VERSION))
+ return (B_FALSE);
if (get_dhcpv4_option(dh4, end, CD_DHCP_TYPE, &opt, &opt_len) != 0 ||
opt_len != 1) {
DTRACE_PROBE2(mtype__not__found, mac_client_impl_t *, mcip,
struct dhcp *, dh4);
- return;
+ return (B_TRUE);
}
mtype = *opt;
if (mtype != REQUEST && mtype != RELEASE) {
DTRACE_PROBE3(ignored__mtype, mac_client_impl_t *, mcip,
struct dhcp *, dh4, uint8_t, mtype);
- return;
+ return (B_TRUE);
}
/* client ID is optional for IPv4 */
@@ -639,6 +644,7 @@
done:
mutex_exit(&mcip->mci_protect_lock);
+ return (B_TRUE);
}
/*
@@ -1208,7 +1214,7 @@
/*
* Core logic for intercepting outbound DHCPv6 packets.
*/
-static void
+static boolean_t
intercept_dhcpv6_outbound(mac_client_impl_t *mcip, ip6_t *ip6h, uchar_t *end)
{
dhcpv6_message_t *dh6;
@@ -1216,17 +1222,22 @@
dhcpv6_cid_t *cid = NULL;
uint32_t xid;
uint8_t mtype;
+ mac_resource_props_t *mrp = MCIP_RESOURCE_PROPS(mcip);
if (get_dhcpv6_info(ip6h, end, &dh6) != 0)
- return;
+ return (B_TRUE);
+
+ /* ip_nospoof/allowed-ips and DHCP are mutually exclusive by default */
+ if (allowed_ips_set(mrp, IPV6_VERSION))
+ return (B_FALSE);
mtype = dh6->d6m_msg_type;
if (mtype != DHCPV6_MSG_REQUEST && mtype != DHCPV6_MSG_RENEW &&
mtype != DHCPV6_MSG_REBIND && mtype != DHCPV6_MSG_RELEASE)
- return;
+ return (B_TRUE);
if ((cid = create_dhcpv6_cid(dh6, end)) == NULL)
- return;
+ return (B_TRUE);
mutex_enter(&mcip->mci_protect_lock);
if (mtype == DHCPV6_MSG_RELEASE) {
@@ -1260,6 +1271,7 @@
free_dhcpv6_cid(cid);
mutex_exit(&mcip->mci_protect_lock);
+ return (B_TRUE);
}
/*
@@ -1524,7 +1536,8 @@
V4_PART_OF_V6(v4addr->ip_addr) == *addr)
return (B_TRUE);
}
- return (check_dhcpv4_dyn_ip(mcip, *addr));
+ return (protect->mp_ipaddrcnt == 0 ?
+ check_dhcpv4_dyn_ip(mcip, *addr) : B_FALSE);
}
static boolean_t
@@ -1549,7 +1562,8 @@
IN6_ARE_ADDR_EQUAL(&v6addr->ip_addr, addr))
return (B_TRUE);
}
- return (check_dhcpv6_dyn_ip(mcip, addr));
+ return (protect->mp_ipaddrcnt == 0 ?
+ check_dhcpv6_dyn_ip(mcip, addr) : B_FALSE);
}
/*
@@ -1694,7 +1708,8 @@
if (!ipnospoof_check_v4(mcip, protect, &ipha->ipha_src))
goto fail;
- intercept_dhcpv4_outbound(mcip, ipha, end);
+ if (!intercept_dhcpv4_outbound(mcip, ipha, end))
+ goto fail;
break;
}
case ETHERTYPE_ARP: {
@@ -1739,7 +1754,8 @@
if (!ipnospoof_check_ndp(mcip, protect, ip6h, end))
goto fail;
- intercept_dhcpv6_outbound(mcip, ip6h, end);
+ if (!intercept_dhcpv6_outbound(mcip, ip6h, end))
+ goto fail;
break;
}
}
@@ -2187,7 +2203,12 @@
if ((err = mac_protect_validate(mrp)) != 0)
return (err);
+ if (err != 0)
+ return (err);
+
mac_update_resources(mrp, MCIP_RESOURCE_PROPS(mcip), B_FALSE);
+ i_mac_notify(((mcip->mci_state_flags & MCIS_IS_VNIC) != 0 ?
+ mcip->mci_upper_mip : mip), MAC_NOTE_ALLOWED_IPS);
return (0);
}
@@ -2261,3 +2282,23 @@
mcip->mci_protect_flags = 0;
mutex_destroy(&mcip->mci_protect_lock);
}
+
+static boolean_t
+allowed_ips_set(mac_resource_props_t *mrp, uint32_t af)
+{
+ int i;
+
+ for (i = 0; i < mrp->mrp_protect.mp_ipaddrcnt; i++) {
+ if (mrp->mrp_protect.mp_ipaddrs[i].ip_version == af)
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+}
+
+void
+mac_protect_get(mac_handle_t mh, mac_protect_t *mrp)
+{
+ mac_impl_t *mip = (mac_impl_t *)mh;
+
+ *mrp = mip->mi_resource_props.mrp_protect;
+}
--- a/usr/src/uts/common/net/if.h Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/uts/common/net/if.h Thu Jul 01 17:10:52 2010 -0400
@@ -1,6 +1,5 @@
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -171,6 +170,7 @@
#define IFF_VRRP 0x10000000000ll /* Managed by VRRP */
#define IFF_NOLINKLOCAL 0x20000000000ll /* No default linklocal */
+#define IFF_L3PROTECT 0x40000000000ll /* Layer-3 protection enforced */
/* flags that cannot be changed by userland on any interface */
#define IFF_CANTCHANGE \
@@ -178,7 +178,7 @@
IFF_MULTICAST | IFF_MULTI_BCAST | IFF_UNNUMBERED | IFF_IPV4 | \
IFF_IPV6 | IFF_IPMP | IFF_FIXEDMTU | IFF_VIRTUAL | \
IFF_LOOPBACK | IFF_ALLMULTI | IFF_DUPLICATE | IFF_COS_ENABLED | \
- IFF_VRRP | IFF_NOLINKLOCAL)
+ IFF_VRRP | IFF_NOLINKLOCAL | IFF_L3PROTECT)
/* flags that cannot be changed by userland on an IPMP interface */
#define IFF_IPMP_CANTCHANGE IFF_FAILED
--- a/usr/src/uts/common/net/route.h Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/uts/common/net/route.h Thu Jul 01 17:10:52 2010 -0400
@@ -1,6 +1,5 @@
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Copyright (c) 1980, 1986, 1993
@@ -132,6 +131,7 @@
#define RTF_SETSRC 0x20000 /* set default outgoing src address */
#define RTF_INDIRECT 0x40000 /* gateway not directly reachable */
#define RTF_KERNEL 0x80000 /* created by kernel; can't delete */
+#define RTF_ZONE 0x100000 /* (NGZ only) route from global zone */
/*
* OLD statistics not used by the kernel. The kernel uses <inet/mib2.h>.
--- a/usr/src/uts/common/os/zone.c Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/uts/common/os/zone.c Thu Jul 01 17:10:52 2010 -0400
@@ -252,6 +252,7 @@
/* List of data link IDs which are accessible from the zone */
typedef struct zone_dl {
datalink_id_t zdl_id;
+ nvlist_t *zdl_net;
list_node_t zdl_linkage;
} zone_dl_t;
@@ -364,6 +365,8 @@
static int zone_add_datalink(zoneid_t, datalink_id_t);
static int zone_remove_datalink(zoneid_t, datalink_id_t);
static int zone_list_datalink(zoneid_t, int *, datalink_id_t *);
+static int zone_set_network(zoneid_t, zone_net_data_t *);
+static int zone_get_network(zoneid_t, zone_net_data_t *);
typedef boolean_t zsd_applyfn_t(kmutex_t *, boolean_t, zone_t *, zone_key_t);
@@ -4719,6 +4722,7 @@
boolean_t global = (curzone == global_zone);
boolean_t inzone = (curzone->zone_id == zoneid);
ushort_t flags;
+ zone_net_data_t *zbuf;
mutex_enter(&zonehash_lock);
if ((zone = zone_find_all_by_id(zoneid)) == NULL) {
@@ -4973,6 +4977,17 @@
error = EFAULT;
}
break;
+ case ZONE_ATTR_NETWORK:
+ zbuf = kmem_alloc(bufsize, KM_SLEEP);
+ if (copyin(buf, zbuf, bufsize) != 0) {
+ error = EFAULT;
+ } else {
+ error = zone_get_network(zoneid, zbuf);
+ if (error == 0 && copyout(zbuf, buf, bufsize) != 0)
+ error = EFAULT;
+ }
+ kmem_free(zbuf, bufsize);
+ break;
default:
if ((attr >= ZONE_ATTR_BRAND_ATTRS) && ZONE_IS_BRANDED(zone)) {
size = bufsize;
@@ -4998,6 +5013,7 @@
zone_t *zone;
zone_status_t zone_status;
int err;
+ zone_net_data_t *zbuf;
if (secpolicy_zone_config(CRED()) != 0)
return (set_errno(EPERM));
@@ -5055,6 +5071,19 @@
err = EINVAL;
}
break;
+ case ZONE_ATTR_NETWORK:
+ if (bufsize > (PIPE_BUF + sizeof (zone_net_data_t))) {
+ err = EINVAL;
+ goto done;
+ }
+ zbuf = kmem_alloc(bufsize, KM_SLEEP);
+ if (copyin(buf, zbuf, bufsize) != 0) {
+ err = EFAULT;
+ goto done;
+ }
+ err = zone_set_network(zoneid, zbuf);
+ kmem_free(zbuf, bufsize);
+ break;
default:
if ((attr >= ZONE_ATTR_BRAND_ATTRS) && ZONE_IS_BRANDED(zone))
err = ZBROP(zone)->b_setattr(zone, attr, buf, bufsize);
@@ -6328,6 +6357,7 @@
zdl = kmem_zalloc(sizeof (*zdl), KM_SLEEP);
zdl->zdl_id = linkid;
+ zdl->zdl_net = NULL;
mutex_enter(&thiszone->zone_lock);
list_insert_head(&thiszone->zone_dl_list, zdl);
mutex_exit(&thiszone->zone_lock);
@@ -6351,6 +6381,8 @@
err = ENXIO;
} else {
list_remove(&zone->zone_dl_list, zdl);
+ if (zdl->zdl_net != NULL)
+ nvlist_free(zdl->zdl_net);
kmem_free(zdl, sizeof (zone_dl_t));
}
mutex_exit(&zone->zone_lock);
@@ -6524,3 +6556,125 @@
kmem_free(idarray, sizeof (datalink_id_t) * idcount);
return (ret);
}
+
+static char *
+zone_net_type2name(int type)
+{
+ switch (type) {
+ case ZONE_NETWORK_ADDRESS:
+ return (ZONE_NET_ADDRNAME);
+ case ZONE_NETWORK_DEFROUTER:
+ return (ZONE_NET_RTRNAME);
+ default:
+ return (NULL);
+ }
+}
+
+static int
+zone_set_network(zoneid_t zoneid, zone_net_data_t *znbuf)
+{
+ zone_t *zone;
+ zone_dl_t *zdl;
+ nvlist_t *nvl;
+ int err = 0;
+ uint8_t *new = NULL;
+ char *nvname;
+ int bufsize;
+ datalink_id_t linkid = znbuf->zn_linkid;
+
+ if (secpolicy_zone_config(CRED()) != 0)
+ return (set_errno(EPERM));
+
+ if (zoneid == GLOBAL_ZONEID)
+ return (set_errno(EINVAL));
+
+ nvname = zone_net_type2name(znbuf->zn_type);
+ bufsize = znbuf->zn_len;
+ new = znbuf->zn_val;
+ if (nvname == NULL)
+ return (set_errno(EINVAL));
+
+ if ((zone = zone_find_by_id(zoneid)) == NULL) {
+ return (set_errno(EINVAL));
+ }
+
+ mutex_enter(&zone->zone_lock);
+ if ((zdl = zone_find_dl(zone, linkid)) == NULL) {
+ err = ENXIO;
+ goto done;
+ }
+ if ((nvl = zdl->zdl_net) == NULL) {
+ if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP)) {
+ err = ENOMEM;
+ goto done;
+ } else {
+ zdl->zdl_net = nvl;
+ }
+ }
+ if (nvlist_exists(nvl, nvname)) {
+ err = EINVAL;
+ goto done;
+ }
+ err = nvlist_add_uint8_array(nvl, nvname, new, bufsize);
+ ASSERT(err == 0);
+done:
+ mutex_exit(&zone->zone_lock);
+ zone_rele(zone);
+ if (err != 0)
+ return (set_errno(err));
+ else
+ return (0);
+}
+
+static int
+zone_get_network(zoneid_t zoneid, zone_net_data_t *znbuf)
+{
+ zone_t *zone;
+ zone_dl_t *zdl;
+ nvlist_t *nvl;
+ uint8_t *ptr;
+ uint_t psize;
+ int err = 0;
+ char *nvname;
+ int bufsize;
+ void *buf;
+ datalink_id_t linkid = znbuf->zn_linkid;
+
+ if (zoneid == GLOBAL_ZONEID)
+ return (set_errno(EINVAL));
+
+ nvname = zone_net_type2name(znbuf->zn_type);
+ bufsize = znbuf->zn_len;
+ buf = znbuf->zn_val;
+
+ if (nvname == NULL)
+ return (set_errno(EINVAL));
+ if ((zone = zone_find_by_id(zoneid)) == NULL)
+ return (set_errno(EINVAL));
+
+ mutex_enter(&zone->zone_lock);
+ if ((zdl = zone_find_dl(zone, linkid)) == NULL) {
+ err = ENXIO;
+ goto done;
+ }
+ if ((nvl = zdl->zdl_net) == NULL || !nvlist_exists(nvl, nvname)) {
+ err = ENOENT;
+ goto done;
+ }
+ err = nvlist_lookup_uint8_array(nvl, nvname, &ptr, &psize);
+ ASSERT(err == 0);
+
+ if (psize > bufsize) {
+ err = ENOBUFS;
+ goto done;
+ }
+ znbuf->zn_len = psize;
+ bcopy(ptr, buf, psize);
+done:
+ mutex_exit(&zone->zone_lock);
+ zone_rele(zone);
+ if (err != 0)
+ return (set_errno(err));
+ else
+ return (0);
+}
--- a/usr/src/uts/common/sys/dlpi.h Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/uts/common/sys/dlpi.h Thu Jul 01 17:10:52 2010 -0400
@@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
@@ -407,6 +406,7 @@
#define DL_NOTE_FASTPATH_FLUSH 0x0200 /* Fast Path info changes */
#define DL_NOTE_CAPAB_RENEG 0x0400 /* Initiate capability renegotiation */
#define DL_NOTE_REPLUMB 0x0800 /* Inform the link to replumb */
+#define DL_NOTE_ALLOWED_IPS 0x1000 /* "allowed-ips" notification */
/*
* DLPI notification codes for DL_NOTIFY_CONF primitives.
--- a/usr/src/uts/common/sys/mac.h Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/uts/common/sys/mac.h Thu Jul 01 17:10:52 2010 -0400
@@ -349,6 +349,7 @@
MAC_NOTE_MARGIN,
MAC_NOTE_CAPAB_CHG,
MAC_NOTE_LOWLINK,
+ MAC_NOTE_ALLOWED_IPS,
MAC_NNOTE /* must be the last entry */
} mac_notify_type_t;
--- a/usr/src/uts/common/sys/mac_provider.h Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/uts/common/sys/mac_provider.h Thu Jul 01 17:10:52 2010 -0400
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _SYS_MAC_PROVIDER_H
@@ -33,6 +32,7 @@
#include <sys/stream.h>
#include <sys/mkdev.h>
#include <sys/mac.h>
+#include <sys/mac_flow.h>
/*
* MAC Provider Interface
@@ -455,6 +455,7 @@
/*
* Driver interface functions.
*/
+extern void mac_protect_get(mac_handle_t, mac_protect_t *);
extern void mac_sdu_get(mac_handle_t, uint_t *, uint_t *);
extern int mac_maxsdu_update(mac_handle_t, uint_t);
--- a/usr/src/uts/common/sys/zone.h Thu Jul 01 13:48:34 2010 -0700
+++ b/usr/src/uts/common/sys/zone.h Thu Jul 01 17:10:52 2010 -0400
@@ -36,6 +36,8 @@
#include <sys/netstack.h>
#include <sys/uadmin.h>
#include <sys/ksynch.h>
+#include <sys/socket_impl.h>
+#include <netinet/in.h>
#ifdef __cplusplus
extern "C" {
@@ -97,6 +99,7 @@
#define ZONE_ATTR_FLAGS 14
#define ZONE_ATTR_HOSTID 15
#define ZONE_ATTR_FS_ALLOWED 16
+#define ZONE_ATTR_NETWORK 17
/* Start of the brand-specific attribute namespace */
#define ZONE_ATTR_BRAND_ATTRS 32768
@@ -279,6 +282,21 @@
/* zone_create flags */
#define ZCF_NET_EXCL 0x1 /* Create a zone with exclusive IP */
+/* zone network properties */
+#define ZONE_NETWORK_ADDRESS 1
+#define ZONE_NETWORK_DEFROUTER 2
+
+#define ZONE_NET_ADDRNAME "address"
+#define ZONE_NET_RTRNAME "route"
+
+typedef struct zone_net_data {
+ int zn_type;
+ int zn_len;
+ datalink_id_t zn_linkid;
+ uint8_t zn_val[1];
+} zone_net_data_t;
+
+
#ifdef _KERNEL
/*
* We need to protect the definition of 'list_t' from userland applications and