summaryrefslogtreecommitdiff
path: root/usr/src/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd')
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/Makefile2
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c56
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h3
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_main.c173
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c201
-rw-r--r--usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c17
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c3
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c46
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/route.c6
-rw-r--r--usr/src/cmd/svc/milestone/net-physical28
-rw-r--r--usr/src/cmd/svc/shell/net_include.sh40
-rw-r--r--usr/src/cmd/zoneadmd/Makefile8
-rw-r--r--usr/src/cmd/zoneadmd/vplat.c487
-rw-r--r--usr/src/cmd/zonecfg/zonecfg.c202
-rw-r--r--usr/src/cmd/zonecfg/zonecfg.h3
-rw-r--r--usr/src/cmd/zonecfg/zonecfg_grammar.y4
-rw-r--r--usr/src/cmd/zonecfg/zonecfg_lex.l3
17 files changed, 1189 insertions, 93 deletions
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/Makefile b/usr/src/cmd/cmd-inet/lib/ipmgmtd/Makefile
index 4e7f342ed5..73ec4241c2 100644
--- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/Makefile
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/Makefile
@@ -44,7 +44,7 @@ $(ROOTCFGFILES) := FILEMODE= 644
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.
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c
index 54472333d2..8e9e153b21 100644
--- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c
@@ -554,33 +554,9 @@ i_ipmgmt_delif_aobjs(char *ifname, sa_family_t af, uint32_t flags)
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 @@ fail:
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);
+}
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h
index f693a34266..36768b5ae0 100644
--- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h
@@ -38,6 +38,7 @@ extern "C" {
#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 boolean_t ipmgmt_aobjmap_init(void *, nvlist_t *, char *,
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
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_main.c b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_main.c
index 011126d010..63b1e48a89 100644
--- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_main.c
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_main.c
@@ -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 int ipmgmt_door_fd = -1;
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 @@ ipmgmt_db_init()
}
(void) pthread_rwlock_init(&ipmgmt_dbconf_lock, NULL);
+
+ ipmgmt_ngz_persist_if(); /* create persistent interface info for NGZ */
+
return (err);
}
@@ -214,11 +235,89 @@ ipmgmt_exit(int signo)
}
/*
- * 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 @@ ipmgmt_init_privileges()
}
/*
+ * 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 @@ child_out:
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 */
+}
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c
index 09275519a6..25e2f3a5ee 100644
--- a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c
@@ -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 @@ ipmgmt_persist_aobjmap(ipmgmt_aobjmap_t *nodep, ipadm_db_op_t op)
}
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);
+}
diff --git a/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c b/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c
index 65c9d83cfb..119293f472 100644
--- a/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c
+++ b/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c
@@ -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 @@ static m_label_t *zone_security_label = NULL;
#define FLF_I 0x00000400 /* RTF_INDIRECT */
#define FLF_R 0x00000800 /* RTF_REJECT */
#define FLF_B 0x00001000 /* RTF_BLACKHOLE */
+#define FLF_Z 0x00100000 /* RTF_ZONE */
-static const char flag_list[] = "AbDGHLUMSCIRB";
+static const char flag_list[] = "AbDGHLUMSCIRBZ";
typedef struct filter_rule filter_t;
@@ -4342,6 +4339,10 @@ form_v4_route_flags(const mib2_ipRouteEntry_t *rp, char *flags)
(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 @@ form_v6_route_flags(const mib2_ipv6RouteEntry_t *rp6, char *flags)
(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);
}
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c
index b1409d8420..a2b477c06b 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c
@@ -73,7 +73,8 @@ static if_flags_t if_flags_tbl[] = {
{ IFF_DUPLICATE, "DUPLICATE" },
{ IFF_IPMP, "IPMP"},
{ IFF_VRRP, "VRRP"},
- { IFF_NOACCEPT, "NOACCEPT"}
+ { IFF_NOACCEPT, "NOACCEPT"},
+ { IFF_L3PROTECT, "L3PROTECT"}
};
typedef struct {
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c b/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c
index bae4b9915e..a3b2fcd19e 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c
@@ -308,7 +308,7 @@ static ofmt_field_t show_if_fields[] = {
/* 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 @@ flags2str(uint64_t flags, fmask_t *tbl, boolean_t is_bits,
}
}
+/*
+ * 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 @@ print_sa_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
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 @@ print_si_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
{ "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 }
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/route.c b/usr/src/cmd/cmd-inet/usr.sbin/route.c
index e078d9df38..a2fd0d2d17 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/route.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/route.c
@@ -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 metricnames[] =
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"
diff --git a/usr/src/cmd/svc/milestone/net-physical b/usr/src/cmd/svc/milestone/net-physical
index b7a8144358..3a873db121 100644
--- a/usr/src/cmd/svc/milestone/net-physical
+++ b/usr/src/cmd/svc/milestone/net-physical
@@ -305,21 +305,35 @@ if [ -n "$ipmp6_list" ]; then
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
diff --git a/usr/src/cmd/svc/shell/net_include.sh b/usr/src/cmd/svc/shell/net_include.sh
index cbc5b051b5..ce5972ccee 100644
--- a/usr/src/cmd/svc/shell/net_include.sh
+++ b/usr/src/cmd/svc/shell/net_include.sh
@@ -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 @@ move_addresses()
}
#
+# 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 @@ if_configure()
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
diff --git a/usr/src/cmd/zoneadmd/Makefile b/usr/src/cmd/zoneadmd/Makefile
index 2ca1d2f01e..cb03ef459a 100644
--- a/usr/src/cmd/zoneadmd/Makefile
+++ b/usr/src/cmd/zoneadmd/Makefile
@@ -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 @@ POFILES= $(OBJS:%.o=%.po)
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:
diff --git a/usr/src/cmd/zoneadmd/vplat.c b/usr/src/cmd/zoneadmd/vplat.c
index 998fc6a750..b4cc20951f 100644
--- a/usr/src/cmd/zoneadmd/vplat.c
+++ b/usr/src/cmd/zoneadmd/vplat.c
@@ -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 int getnetmaskbyaddr(struct in_addr, struct in_addr *);
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 @@ add_datalink(zlog_t *zlogp, char *zone_name, datalink_id_t linkid, char *dlname)
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 @@ configure_exclusive_network_interfaces(zlog_t *zlogp)
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 @@ configure_exclusive_network_interfaces(zlog_t *zlogp)
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 @@ remove_datalink_pool(zlog_t *zlogp, zoneid_t zoneid)
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 @@ remove_datalink_pool(zlog_t *zlogp, zoneid_t zoneid)
}
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 @@ vplat_bringup(zlog_t *zlogp, zone_mnt_t mount_cmd, zoneid_t zoneid)
}
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 @@ vplat_teardown(zlog_t *zlogp, boolean_t unmount_cmd, boolean_t rebooting)
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;
diff --git a/usr/src/cmd/zonecfg/zonecfg.c b/usr/src/cmd/zonecfg/zonecfg.c
index a9568128fa..5261e82342 100644
--- a/usr/src/cmd/zonecfg/zonecfg.c
+++ b/usr/src/cmd/zonecfg/zonecfg.c
@@ -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 @@ char *prop_types[] = {
"auths",
"fs-allowed",
ALIAS_MAXPROCS,
+ "allowed-address",
NULL
};
@@ -500,8 +502,18 @@ static const char *admin_res_scope_cmds[] = {
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 @@ usage(boolean_t verbose, uint_t flags)
(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 @@ usage(boolean_t verbose, uint_t flags)
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 @@ export_func(cmd_t *cmd)
(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 @@ fill_in_nwiftab(cmd_t *cmd, struct zone_nwiftab *nwiftab,
(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 @@ select_func(cmd_t *cmd)
* 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 @@ validate_net_address_syntax(char *address)
(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 @@ validate_net_address_syntax(char *address)
}
/* 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 @@ set_aliased_rctl(char *alias, int prop_type, char *s)
}
}
+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 @@ set_func(cmd_t *cmd)
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 @@ set_func(cmd_t *cmd)
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 @@ output_net(FILE *fp, struct zone_nwiftab *nwiftab)
{
(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 @@ brand_verify(zone_dochandle_t handle)
}
/*
+ * 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 @@ verify_func(cmd_t *cmd)
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,27 +5841,46 @@ verify_func(cmd_t *cmd)
case ZS_SHARED:
check_reqd_prop(nwiftab.zone_nwif_address, RT_NET,
PT_ADDRESS, &ret_val);
- break;
- case ZS_EXCLUSIVE:
- if (strlen(nwiftab.zone_nwif_address) > 0) {
+ if (strlen(nwiftab.zone_nwif_allowed_address) > 0) {
zerr(gettext("%s: %s cannot be specified "
- "for an exclusive IP type"),
- rt_to_str(RT_NET), pt_to_str(PT_ADDRESS));
+ "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;
}
- if (strlen(nwiftab.zone_nwif_defrouter) > 0) {
+ break;
+ case ZS_EXCLUSIVE:
+ if (strlen(nwiftab.zone_nwif_address) > 0) {
zerr(gettext("%s: %s cannot be specified "
"for an exclusive IP type"),
- rt_to_str(RT_NET), pt_to_str(PT_DEFROUTER));
+ rt_to_str(RT_NET), pt_to_str(PT_ADDRESS));
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 @@ end_check_reqd(char *attr, int pt, boolean_t *validation_failed)
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 @@ end_func(cmd_t *cmd)
(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;
}
diff --git a/usr/src/cmd/zonecfg/zonecfg.h b/usr/src/cmd/zonecfg/zonecfg.h
index 1ac8acf9de..7bfecad72f 100644
--- a/usr/src/cmd/zonecfg/zonecfg.h
+++ b/usr/src/cmd/zonecfg/zonecfg.h
@@ -136,9 +136,10 @@ extern "C" {
#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
diff --git a/usr/src/cmd/zonecfg/zonecfg_grammar.y b/usr/src/cmd/zonecfg/zonecfg_grammar.y
index 3143080a1e..86dde3c99d 100644
--- a/usr/src/cmd/zonecfg/zonecfg_grammar.y
+++ b/usr/src/cmd/zonecfg/zonecfg_grammar.y
@@ -123,7 +123,7 @@ complex_piece_func(int cp_type, const char *str, complex_property_ptr_t cp_next)
%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 @@ complex_piece_func(int cp_type, const char *str, complex_property_ptr_t cp_next)
%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 @@ property_name: SPECIAL { $$ = PT_SPECIAL; }
| LIMITPRIV { $$ = PT_LIMITPRIV; }
| BOOTARGS { $$ = PT_BOOTARGS; }
| ADDRESS { $$ = PT_ADDRESS; }
+ | ALLOWED_ADDRESS { $$ = PT_ALLOWED_ADDRESS; }
| PHYSICAL { $$ = PT_PHYSICAL; }
| DEFROUTER { $$ = PT_DEFROUTER; }
| NAME { $$ = PT_NAME; }
diff --git a/usr/src/cmd/zonecfg/zonecfg_lex.l b/usr/src/cmd/zonecfg/zonecfg_lex.l
index 8285a778f7..8353603148 100644
--- a/usr/src/cmd/zonecfg/zonecfg_lex.l
+++ b/usr/src/cmd/zonecfg/zonecfg_lex.l
@@ -204,6 +204,9 @@ char *safe_strdup(char *s);
<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; }