Print this page
OS-200 need a better mechanism for storing persistent zone_did
OS-511 make zonecfg device resource extensible, like the net resource
OS-224 add more zonecfg net properties
OS-216 store all net config info on zone
Reduce lint
OS-5139 cpu_cap is sometimes off by 1 when set with package fss or cap_cap direct update
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
OS-399 zone phys. mem. cap should be a rctl and have associated kstat
        
@@ -21,10 +21,11 @@
 
 /*
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  * Copyright 2014 Gary Mills
+ * Copyright 2016, Joyent Inc.
  */
 
 /*
  * zonecfg is a lex/yacc based command interpreter used to manage zone
  * configurations.  The lexer (see zonecfg_lex.l) builds up tokens, which
@@ -232,10 +233,15 @@
         "user",
         "auths",
         "fs-allowed",
         ALIAS_MAXPROCS,
         "allowed-address",
+        ALIAS_ZFSPRI,
+        "mac-addr",
+        "vlan-id",
+        "global-nic",
+        "property",
         NULL
 };
 
 /* These *must* match the order of the PROP_VAL_ define's from zonecfg.h */
 static char *prop_val_types[] = {
@@ -404,22 +410,34 @@
         "cancel",
         "end",
         "exit",
         "help",
         "info",
+        "add property ",
+        "clear allowed-address",
+        "clear defrouter",
+        "clear global-nic",
+        "clear mac-addr",
+        "clear vlan-id",
+        "remove property ",
         "set address=",
-        "set physical=",
+        "set allowed-address=",
         "set defrouter=",
+        "set global-nic=",
+        "set mac-addr=",
+        "set physical=",
+        "set vlan-id=",
         NULL
 };
 
 static const char *device_res_scope_cmds[] = {
         "cancel",
         "end",
         "exit",
         "help",
         "info",
+        "add property ",
         "set match=",
         NULL
 };
 
 static const char *attr_res_scope_cmds[] = {
@@ -577,11 +595,10 @@
 static struct zone_devtab       old_devtab, in_progress_devtab;
 static struct zone_rctltab      old_rctltab, in_progress_rctltab;
 static struct zone_attrtab      old_attrtab, in_progress_attrtab;
 static struct zone_dstab        old_dstab, in_progress_dstab;
 static struct zone_psettab      old_psettab, in_progress_psettab;
-static struct zone_mcaptab      old_mcaptab, in_progress_mcaptab;
 static struct zone_admintab     old_admintab, in_progress_admintab;
 
 static GetLine *gl;     /* The gl_get_line() resource object */
 
 static void bytes_to_units(char *str, char *buf, int bufsize);
@@ -1076,26 +1093,37 @@
                             "used to configure a network interface.\n"),
                             rt_to_str(resource_scope));
                         (void) fprintf(fp, gettext("Valid commands:\n"));
                         (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=<value>,%s=<value>)\n",
+                            cmd_to_str(CMD_ADD), pt_to_str(PT_NPROP),
+                            pt_to_str(PT_NAME), pt_to_str(PT_VALUE));
                         (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, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
+                            pt_to_str(PT_MAC), gettext("<mac-address>"));
+                        (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
+                            pt_to_str(PT_GNIC), gettext("<global zone NIC>"));
+                        (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
+                            pt_to_str(PT_VLANID), gettext("<vlan ID>"));
                         (void) fprintf(fp, gettext("See ifconfig(1M) for "
                             "details of the <interface> string.\n"));
                         (void) fprintf(fp, gettext("%s %s is valid "
                             "if the %s property is set to %s, otherwise it "
                             "must not be set.\n"),
                             cmd_to_str(CMD_SET), pt_to_str(PT_ADDRESS),
                             pt_to_str(PT_IPTYPE), 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),
+                        (void) fprintf(fp, gettext("%s (%s, %s, %s, %s) are "
+                            "valid if the %s property is set to %s, otherwise "
+                            "they must not be set.\n"),
+                            cmd_to_str(CMD_SET),
+                            pt_to_str(PT_ALLOWED_ADDRESS), pt_to_str(PT_MAC),
+                            pt_to_str(PT_VLANID), pt_to_str(PT_GNIC),
                             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),
@@ -1107,10 +1135,13 @@
                 case RT_DEVICE:
                         (void) fprintf(fp, gettext("The '%s' resource scope is "
                             "used to configure a device node.\n"),
                             rt_to_str(resource_scope));
                         (void) fprintf(fp, gettext("Valid commands:\n"));
+                        (void) fprintf(fp, "\t%s %s (%s=<value>,%s=<value>)\n",
+                            cmd_to_str(CMD_ADD), pt_to_str(PT_NPROP),
+                            pt_to_str(PT_NAME), pt_to_str(PT_VALUE));
                         (void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
                             pt_to_str(PT_MATCH), gettext("<device-path>"));
                         break;
                 case RT_RCTL:
                         (void) fprintf(fp, gettext("The '%s' resource scope is "
@@ -1334,15 +1365,18 @@
                     pt_to_str(PT_SHARES));
                 (void) fprintf(fp, "\t%s\t\t%s, %s, %s, %s, %s\n",
                     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|%s\n", rt_to_str(RT_NET),
+                (void) fprintf(fp, "\t%s\t\t%s, %s, %s, %s, %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));
+                    pt_to_str(PT_GNIC), pt_to_str(PT_MAC),
+                    pt_to_str(PT_PHYSICAL), pt_to_str(PT_NPROP),
+                    pt_to_str(PT_VLANID), pt_to_str(PT_DEFROUTER));
+                (void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_DEVICE),
+                    pt_to_str(PT_MATCH), pt_to_str(PT_NPROP));
                 (void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_RCTL),
                     pt_to_str(PT_NAME), pt_to_str(PT_VALUE));
                 (void) fprintf(fp, "\t%s\t\t%s, %s, %s\n", rt_to_str(RT_ATTR),
                     pt_to_str(PT_NAME), pt_to_str(PT_TYPE),
                     pt_to_str(PT_VALUE));
@@ -1393,10 +1427,13 @@
         char brandname[MAXNAMELEN];
 
         if (zonecfg_check_handle(handle) != Z_OK) {
                 if ((err = zonecfg_get_handle(zone, handle)) == Z_OK) {
                         got_handle = B_TRUE;
+
+                        (void) zonecfg_fix_obsolete(handle);
+
                         if (zonecfg_get_brand(handle, brandname,
                             sizeof (brandname)) != Z_OK) {
                                 zerr("Zone %s is inconsistent: missing "
                                     "brand attribute", zone);
                                 exit(Z_ERR);
@@ -1693,10 +1730,21 @@
                         break;
                 case 't':
                         (void) strlcpy(zone_template, optarg,
                             sizeof (zone_template));
                         break;
+                case 'X':
+                        (void) snprintf(zone_template, sizeof (zone_template),
+                            "%s/%s.xml", ZONE_CONFIG_ROOT, zone);
+                        err = zonecfg_get_xml_handle(zone_template, handle);
+                        if (err != Z_OK) {
+                                zone_perror(execname, err, B_TRUE);
+                                exit(Z_ERR);
+                        }
+                        got_handle = B_TRUE;
+                        need_to_commit = B_TRUE;
+                        return;
                 default:
                         short_usage(CMD_CREATE);
                         arg_err = B_TRUE;
                         break;
                 }
@@ -1795,12 +1843,12 @@
         struct zone_devtab devtab;
         struct zone_attrtab attrtab;
         struct zone_rctltab rctltab;
         struct zone_dstab dstab;
         struct zone_psettab psettab;
-        struct zone_mcaptab mcaptab;
         struct zone_rctlvaltab *valptr;
+        struct zone_res_attrtab *rap;
         struct zone_admintab admintab;
         int err, arg;
         char zonepath[MAXPATHLEN], outfile[MAXPATHLEN], pool[MAXNAMELEN];
         char bootargs[BOOTARGS_MAX];
         char sched[MAXNAMELEN];
@@ -1966,11 +2014,21 @@
                     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_MAC, nwiftab.zone_nwif_mac);
+                export_prop(of, PT_VLANID, nwiftab.zone_nwif_vlan_id);
+                export_prop(of, PT_GNIC, nwiftab.zone_nwif_gnic);
                 export_prop(of, PT_DEFROUTER, nwiftab.zone_nwif_defrouter);
+                for (rap = nwiftab.zone_nwif_attrp; rap != NULL;
+                    rap = rap->zone_res_attr_next) {
+                        fprintf(of, "%s %s (%s=%s,%s=\"%s\")\n",
+                            cmd_to_str(CMD_ADD), pt_to_str(PT_NPROP),
+                            pt_to_str(PT_NAME), rap->zone_res_attr_name,
+                            pt_to_str(PT_VALUE), rap->zone_res_attr_value);
+                }
                 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
         }
         (void) zonecfg_endnwifent(handle);
 
         if ((err = zonecfg_setdevent(handle)) != Z_OK) {
@@ -1979,25 +2037,21 @@
         }
         while (zonecfg_getdevent(handle, &devtab) == Z_OK) {
                 (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
                     rt_to_str(RT_DEVICE));
                 export_prop(of, PT_MATCH, devtab.zone_dev_match);
+                for (rap = devtab.zone_dev_attrp; rap != NULL;
+                    rap = rap->zone_res_attr_next) {
+                        fprintf(of, "%s %s (%s=%s,%s=\"%s\")\n",
+                            cmd_to_str(CMD_ADD), pt_to_str(PT_NPROP),
+                            pt_to_str(PT_NAME), rap->zone_res_attr_name,
+                            pt_to_str(PT_VALUE), rap->zone_res_attr_value);
+                }
                 (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
         }
         (void) zonecfg_enddevent(handle);
 
-        if (zonecfg_getmcapent(handle, &mcaptab) == Z_OK) {
-                char buf[128];
-
-                (void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
-                    rt_to_str(RT_MCAP));
-                bytes_to_units(mcaptab.zone_physmem_cap, buf, sizeof (buf));
-                (void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
-                    pt_to_str(PT_PHYSICAL), buf);
-                (void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
-        }
-
         if ((err = zonecfg_setrctlent(handle)) != Z_OK) {
                 zone_perror(zone, err, B_FALSE);
                 goto done;
         }
         while (zonecfg_getrctlent(handle, &rctltab) == Z_OK) {
@@ -2147,11 +2201,10 @@
 static void
 add_resource(cmd_t *cmd)
 {
         int type;
         struct zone_psettab tmp_psettab;
-        struct zone_mcaptab tmp_mcaptab;
         uint64_t tmp;
         uint64_t tmp_mcap;
         char pool[MAXNAMELEN];
 
         if ((type = cmd->cmd_res_type) == RT_UNKNOWN) {
@@ -2239,13 +2292,14 @@
         case RT_MCAP:
                 /*
                  * Make sure there isn't already a mem-cap entry or max-swap
                  * or max-locked rctl.
                  */
-                if (zonecfg_lookup_mcap(handle, &tmp_mcaptab) == Z_OK ||
-                    zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp_mcap)
-                    == Z_OK ||
+                if (zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP,
+                    &tmp_mcap) == Z_OK ||
+                    zonecfg_get_aliased_rctl(handle, ALIAS_MAXPHYSMEM,
+                    &tmp_mcap) == Z_OK ||
                     zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
                     &tmp_mcap) == Z_OK) {
                         zerr(gettext("The %s resource or a related resource "
                             "control already exists."), rt_to_str(RT_MCAP));
                         goto bad;
@@ -2254,11 +2308,10 @@
                         zerr(gettext("WARNING: Setting a global zone memory "
                             "cap too low could deny\nservice "
                             "to even the root user; "
                             "this could render the system impossible\n"
                             "to administer.  Please use caution."));
-                bzero(&in_progress_mcaptab, sizeof (in_progress_mcaptab));
                 return;
         case RT_ADMIN:
                 bzero(&in_progress_admintab, sizeof (in_progress_admintab));
                 return;
         default:
@@ -2357,11 +2410,73 @@
 
 bad:
         zonecfg_free_rctl_value_list(rctlvaltab);
 }
 
+/*
+ * Resource attribute ("property" resource embedded on net or dev resource)
+ */
 static void
+do_res_attr(struct zone_res_attrtab **headp, complex_property_ptr_t cpp)
+{
+        complex_property_ptr_t cp;
+        struct zone_res_attrtab *np;
+        int err;
+        boolean_t seen_name = B_FALSE, seen_value = B_FALSE;
+
+        if ((np = calloc(1, sizeof (struct zone_res_attrtab))) == NULL) {
+                zone_perror(zone, Z_NOMEM, B_TRUE);
+                exit(Z_ERR);
+        }
+
+        for (cp = cpp; cp != NULL; cp = cp->cp_next) {
+                switch (cp->cp_type) {
+                case PT_NAME:
+                        if (seen_name) {
+                                zerr(gettext("%s already specified"),
+                                    pt_to_str(PT_NAME));
+                                goto bad;
+                        }
+                        (void) strlcpy(np->zone_res_attr_name, cp->cp_value,
+                            sizeof (np->zone_res_attr_name));
+                        seen_name = B_TRUE;
+                        break;
+                case PT_VALUE:
+                        if (seen_value) {
+                                zerr(gettext("%s already specified"),
+                                    pt_to_str(PT_VALUE));
+                                goto bad;
+                        }
+                        (void) strlcpy(np->zone_res_attr_value, cp->cp_value,
+                            sizeof (np->zone_res_attr_value));
+                        seen_value = B_TRUE;
+                        break;
+                default:
+                        zone_perror(pt_to_str(PT_NPROP), Z_NO_PROPERTY_TYPE,
+                            B_TRUE);
+                        long_usage(CMD_ADD, B_TRUE);
+                        usage(B_FALSE, HELP_PROPS);
+                        zonecfg_free_res_attr_list(np);
+                        return;
+                }
+        }
+
+        if (!seen_name)
+                zerr(gettext("%s not specified"), pt_to_str(PT_NAME));
+        if (!seen_value)
+                zerr(gettext("%s not specified"), pt_to_str(PT_VALUE));
+
+        err = zonecfg_add_res_attr(headp, np);
+        if (err != Z_OK)
+                zone_perror(pt_to_str(PT_NPROP), err, B_TRUE);
+        return;
+
+bad:
+        zonecfg_free_res_attr_list(np);
+}
+
+static void
 add_property(cmd_t *cmd)
 {
         char *prop_id;
         int err, res_type, prop_type;
         property_value_ptr_t pp;
@@ -2424,10 +2539,48 @@
                                         zone_perror(pt_to_str(prop_type), err,
                                             B_TRUE);
                         }
                 }
                 return;
+        case RT_NET:
+                if (prop_type != PT_NPROP) {
+                        zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
+                            B_TRUE);
+                        long_usage(CMD_ADD, B_TRUE);
+                        usage(B_FALSE, HELP_PROPS);
+                        return;
+                }
+                pp = cmd->cmd_property_ptr[0];
+                if (pp->pv_type != PROP_VAL_COMPLEX) {
+                        zerr(gettext("A %s value was expected here."),
+                            pvt_to_str(PROP_VAL_COMPLEX));
+                        saw_error = B_TRUE;
+                        return;
+                }
+
+                do_res_attr(&(in_progress_nwiftab.zone_nwif_attrp),
+                    pp->pv_complex);
+                return;
+        case RT_DEVICE:
+                if (prop_type != PT_NPROP) {
+                        zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
+                            B_TRUE);
+                        long_usage(CMD_ADD, B_TRUE);
+                        usage(B_FALSE, HELP_PROPS);
+                        return;
+                }
+                pp = cmd->cmd_property_ptr[0];
+                if (pp->pv_type != PROP_VAL_COMPLEX) {
+                        zerr(gettext("A %s value was expected here."),
+                            pvt_to_str(PROP_VAL_COMPLEX));
+                        saw_error = B_TRUE;
+                        return;
+                }
+
+                do_res_attr(&(in_progress_devtab.zone_dev_attrp),
+                    pp->pv_complex);
+                return;
         case RT_RCTL:
                 if (prop_type != PT_VALUE) {
                         zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
                             B_TRUE);
                         long_usage(CMD_ADD, B_TRUE);
@@ -2528,12 +2681,13 @@
 
                 global_scope = B_FALSE;
                 resource_scope = cmd->cmd_res_type;
                 end_op = CMD_ADD;
                 add_resource(cmd);
-        } else
+        } else {
                 add_property(cmd);
+        }
 }
 
 /*
  * This routine has an unusual implementation, because it tries very
  * hard to succeed in the face of a variety of failure modes.
@@ -2727,10 +2881,25 @@
                 case PT_PHYSICAL:
                         (void) strlcpy(nwiftab->zone_nwif_physical,
                             pp->pv_simple,
                             sizeof (nwiftab->zone_nwif_physical));
                         break;
+                case PT_MAC:
+                        (void) strlcpy(nwiftab->zone_nwif_mac,
+                            pp->pv_simple,
+                            sizeof (nwiftab->zone_nwif_mac));
+                        break;
+                case PT_VLANID:
+                        (void) strlcpy(nwiftab->zone_nwif_vlan_id,
+                            pp->pv_simple,
+                            sizeof (nwiftab->zone_nwif_vlan_id));
+                        break;
+                case PT_GNIC:
+                        (void) strlcpy(nwiftab->zone_nwif_gnic,
+                            pp->pv_simple,
+                            sizeof (nwiftab->zone_nwif_gnic));
+                        break;
                 case PT_DEFROUTER:
                         (void) strlcpy(nwiftab->zone_nwif_defrouter,
                             pp->pv_simple,
                             sizeof (nwiftab->zone_nwif_defrouter));
                         break;
@@ -3244,14 +3413,13 @@
 static void
 remove_mcap()
 {
         int err, res1, res2, res3;
         uint64_t tmp;
-        struct zone_mcaptab mcaptab;
         boolean_t revert = B_FALSE;
 
-        res1 = zonecfg_lookup_mcap(handle, &mcaptab);
+        res1 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXPHYSMEM, &tmp);
         res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &tmp);
         res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &tmp);
 
         /* if none of these exist, there is no resource to remove */
         if (res1 != Z_OK && res2 != Z_OK && res3 != Z_OK) {
@@ -3259,17 +3427,19 @@
                     zonecfg_strerror(Z_NO_RESOURCE_TYPE));
                 saw_error = B_TRUE;
                 return;
         }
         if (res1 == Z_OK) {
-                if ((err = zonecfg_delete_mcap(handle)) != Z_OK) {
+                if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXPHYSMEM))
+                    != Z_OK) {
                         z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
                         revert = B_TRUE;
                 } else {
                         need_to_commit = B_TRUE;
                 }
         }
+
         if (res2 == Z_OK) {
                 if ((err = zonecfg_rm_aliased_rctl(handle, ALIAS_MAXSWAP))
                     != Z_OK) {
                         z_cmd_rt_perror(CMD_REMOVE, RT_MCAP, err, B_TRUE);
                         revert = B_TRUE;
@@ -3408,10 +3578,11 @@
 {
         char *prop_id;
         int err, res_type, prop_type;
         property_value_ptr_t pp;
         struct zone_rctlvaltab *rctlvaltab;
+        struct zone_res_attrtab *np;
         complex_property_ptr_t cx;
 
         res_type = resource_scope;
         prop_type = cmd->cmd_prop_name[0];
         if (res_type == RT_UNKNOWN || prop_type == PT_UNKNOWN) {
@@ -3468,10 +3639,60 @@
                                         zone_perror(pt_to_str(prop_type), err,
                                             B_TRUE);
                         }
                 }
                 return;
+        case RT_NET:            /* FALLTHRU */
+        case RT_DEVICE:
+                if (prop_type != PT_NPROP) {
+                        zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
+                            B_TRUE);
+                        long_usage(CMD_REMOVE, B_TRUE);
+                        usage(B_FALSE, HELP_PROPS);
+                        return;
+                }
+                pp = cmd->cmd_property_ptr[0];
+                if (pp->pv_type != PROP_VAL_COMPLEX) {
+                        zerr(gettext("A %s value was expected here."),
+                            pvt_to_str(PROP_VAL_COMPLEX));
+                        saw_error = B_TRUE;
+                        return;
+                }
+
+                np = alloca(sizeof (struct zone_res_attrtab));
+                for (cx = pp->pv_complex; cx != NULL; cx = cx->cp_next) {
+                        switch (cx->cp_type) {
+                        case PT_NAME:
+                                (void) strlcpy(np->zone_res_attr_name,
+                                    cx->cp_value,
+                                    sizeof (np->zone_res_attr_name));
+                                break;
+                        case PT_VALUE:
+                                (void) strlcpy(np->zone_res_attr_value,
+                                    cx->cp_value,
+                                    sizeof (np->zone_res_attr_value));
+                                break;
+                        default:
+                                zone_perror(pt_to_str(prop_type),
+                                    Z_NO_PROPERTY_TYPE, B_TRUE);
+                                long_usage(CMD_REMOVE, B_TRUE);
+                                usage(B_FALSE, HELP_PROPS);
+                                return;
+                        }
+                }
+                np->zone_res_attr_next = NULL;
+
+                if (res_type == RT_NET) {
+                        err = zonecfg_remove_res_attr(
+                            &(in_progress_nwiftab.zone_nwif_attrp), np);
+                } else {                                /* RT_DEVICE */
+                        err = zonecfg_remove_res_attr(
+                            &(in_progress_devtab.zone_dev_attrp), np);
+                }
+                if (err != Z_OK)
+                        zone_perror(pt_to_str(prop_type), err, B_TRUE);
+                return;
         case RT_RCTL:
                 if (prop_type != PT_VALUE) {
                         zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
                             B_TRUE);
                         long_usage(CMD_REMOVE, B_TRUE);
@@ -3520,22 +3741,10 @@
                     rctlvaltab);
                 if (err != Z_OK)
                         zone_perror(pt_to_str(prop_type), err, B_TRUE);
                 zonecfg_free_rctl_value_list(rctlvaltab);
                 return;
-        case RT_NET:
-                if (prop_type != PT_DEFROUTER) {
-                        zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
-                            B_TRUE);
-                        long_usage(CMD_REMOVE, B_TRUE);
-                        usage(B_FALSE, HELP_PROPS);
-                        return;
-                } else {
-                        bzero(&in_progress_nwiftab.zone_nwif_defrouter,
-                            sizeof (in_progress_nwiftab.zone_nwif_defrouter));
-                        return;
-                }
         default:
                 zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
                 long_usage(CMD_REMOVE, B_TRUE);
                 usage(B_FALSE, HELP_RESOURCES);
                 return;
@@ -3594,21 +3803,44 @@
                 }
                 break;
         case RT_MCAP:
                 switch (prop_type) {
                 case PT_PHYSICAL:
-                        in_progress_mcaptab.zone_physmem_cap[0] = '\0';
-                        need_to_commit = B_TRUE;
+                        remove_aliased_rctl(PT_PHYSICAL, ALIAS_MAXPHYSMEM);
                         return;
                 case PT_SWAP:
                         remove_aliased_rctl(PT_SWAP, ALIAS_MAXSWAP);
                         return;
                 case PT_LOCKED:
                         remove_aliased_rctl(PT_LOCKED, ALIAS_MAXLOCKEDMEM);
                         return;
                 }
                 break;
+        case RT_NET:
+                switch (prop_type) {
+                case PT_ALLOWED_ADDRESS:
+                        in_progress_nwiftab.zone_nwif_allowed_address[0] = '\0';
+                        need_to_commit = B_TRUE;
+                        return;
+                case PT_DEFROUTER:
+                        in_progress_nwiftab.zone_nwif_defrouter[0] = '\0';
+                        need_to_commit = B_TRUE;
+                        return;
+                case PT_GNIC:
+                        in_progress_nwiftab.zone_nwif_gnic[0] = '\0';
+                        need_to_commit = B_TRUE;
+                        return;
+                case PT_MAC:
+                        in_progress_nwiftab.zone_nwif_mac[0] = '\0';
+                        need_to_commit = B_TRUE;
+                        return;
+                case PT_VLANID:
+                        in_progress_nwiftab.zone_nwif_vlan_id[0] = '\0';
+                        need_to_commit = B_TRUE;
+                        return;
+                }
+                break;
         default:
                 break;
         }
 
         zone_perror(pt_to_str(prop_type), Z_CLEAR_DISALLOW, B_TRUE);
@@ -3737,11 +3969,11 @@
 }
 
 void
 select_func(cmd_t *cmd)
 {
-        int type, err, res;
+        int type, err;
         uint64_t limit;
         uint64_t tmp;
 
         if (zone_is_read_only(CMD_SELECT))
                 return;
@@ -3832,25 +4064,20 @@
                         global_scope = B_TRUE;
                 }
                 return;
         case RT_MCAP:
                 /* if none of these exist, there is no resource to select */
-                if ((res = zonecfg_lookup_mcap(handle, &old_mcaptab)) != Z_OK &&
+                if (zonecfg_get_aliased_rctl(handle, ALIAS_MAXPHYSMEM, &limit)
+                    != Z_OK &&
                     zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &limit)
                     != Z_OK &&
                     zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM, &limit)
                     != Z_OK) {
                         z_cmd_rt_perror(CMD_SELECT, RT_MCAP, Z_NO_RESOURCE_TYPE,
                             B_TRUE);
                         global_scope = B_TRUE;
                 }
-                if (res == Z_OK)
-                        bcopy(&old_mcaptab, &in_progress_mcaptab,
-                            sizeof (struct zone_mcaptab));
-                else
-                        bzero(&in_progress_mcaptab,
-                            sizeof (in_progress_mcaptab));
                 return;
         case RT_ADMIN:
                 if ((err = fill_in_admintab(cmd, &old_admintab, B_FALSE))
                     != Z_OK) {
                         z_cmd_rt_perror(CMD_SELECT, RT_ADMIN, err,
@@ -4113,13 +4340,12 @@
         int arg, err, res_type, prop_type;
         property_value_ptr_t pp;
         boolean_t autoboot;
         zone_iptype_t iptype;
         boolean_t force_set = B_FALSE;
-        size_t physmem_size = sizeof (in_progress_mcaptab.zone_physmem_cap);
         uint64_t mem_cap, mem_limit;
-        float cap;
+        double cap;
         char *unitp;
         struct zone_psettab tmp_psettab;
         boolean_t arg_err = B_FALSE;
 
         if (zone_is_read_only(CMD_SET))
@@ -4217,14 +4443,16 @@
         pp = cmd->cmd_property_ptr[0];
         /*
          * A nasty expression but not that complicated:
          * 1. fs options are simple or list (tested below)
          * 2. rctl value's are complex or list (tested below)
+         * 3. net attr's are complex (tested below)
          * Anything else should be simple.
          */
         if (!(res_type == RT_FS && prop_type == PT_OPTIONS) &&
             !(res_type == RT_RCTL && prop_type == PT_VALUE) &&
+            !(res_type == RT_NET && prop_type == PT_NPROP) &&
             (pp->pv_type != PROP_VAL_SIMPLE ||
             (prop_id = pp->pv_simple) == NULL)) {
                 zerr(gettext("A %s value was expected here."),
                     pvt_to_str(PROP_VAL_SIMPLE));
                 saw_error = B_TRUE;
@@ -4480,10 +4708,25 @@
                         }
                         (void) strlcpy(in_progress_nwiftab.zone_nwif_physical,
                             prop_id,
                             sizeof (in_progress_nwiftab.zone_nwif_physical));
                         break;
+                case PT_MAC:
+                        (void) strlcpy(in_progress_nwiftab.zone_nwif_mac,
+                            prop_id,
+                            sizeof (in_progress_nwiftab.zone_nwif_mac));
+                        break;
+                case PT_VLANID:
+                        (void) strlcpy(in_progress_nwiftab.zone_nwif_vlan_id,
+                            prop_id,
+                            sizeof (in_progress_nwiftab.zone_nwif_vlan_id));
+                        break;
+                case PT_GNIC:
+                        (void) strlcpy(in_progress_nwiftab.zone_nwif_gnic,
+                            prop_id,
+                            sizeof (in_progress_nwiftab.zone_nwif_gnic));
+                        break;
                 case PT_DEFROUTER:
                         if (validate_net_address_syntax(prop_id, B_TRUE)
                             != Z_OK) {
                                 saw_error = B_TRUE;
                                 return;
@@ -4490,10 +4733,24 @@
                         }
                         (void) strlcpy(in_progress_nwiftab.zone_nwif_defrouter,
                             prop_id,
                             sizeof (in_progress_nwiftab.zone_nwif_defrouter));
                         break;
+                case PT_NPROP:
+                        if (pp->pv_type != PROP_VAL_COMPLEX) {
+                                zerr(gettext("A %s value was expected here."),
+                                    pvt_to_str(PROP_VAL_COMPLEX));
+                                saw_error = B_TRUE;
+                                return;
+                        }
+                        zonecfg_free_res_attr_list(
+                            in_progress_nwiftab.zone_nwif_attrp);
+                        in_progress_nwiftab.zone_nwif_attrp = NULL;
+                        if (!(pp->pv_type == PROP_VAL_LIST &&
+                            pp->pv_list == NULL))
+                                add_property(cmd);
+                        break;
                 default:
                         zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
                             B_TRUE);
                         long_usage(CMD_SET, B_TRUE);
                         usage(B_FALSE, HELP_PROPS);
@@ -4505,10 +4762,24 @@
                 case PT_MATCH:
                         (void) strlcpy(in_progress_devtab.zone_dev_match,
                             prop_id,
                             sizeof (in_progress_devtab.zone_dev_match));
                         break;
+                case PT_NPROP:
+                        if (pp->pv_type != PROP_VAL_COMPLEX) {
+                                zerr(gettext("A %s value was expected here."),
+                                    pvt_to_str(PROP_VAL_COMPLEX));
+                                saw_error = B_TRUE;
+                                return;
+                        }
+                        zonecfg_free_res_attr_list(
+                            in_progress_devtab.zone_dev_attrp);
+                        in_progress_devtab.zone_dev_attrp = NULL;
+                        if (!(pp->pv_type == PROP_VAL_LIST &&
+                            pp->pv_list == NULL))
+                                add_property(cmd);
+                        break;
                 default:
                         zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
                             B_TRUE);
                         long_usage(CMD_SET, B_TRUE);
                         usage(B_FALSE, HELP_PROPS);
@@ -4648,39 +4919,54 @@
                 /*
                  * We already checked that an rctl alias is allowed in
                  * the add_resource() function.
                  */
 
-                if ((cap = strtof(prop_id, &unitp)) <= 0 || *unitp != '\0' ||
-                    (int)(cap * 100) < 1) {
+                if ((cap = strtod(prop_id, &unitp)) <= 0 || *unitp != '\0' ||
+                    (cap * 100.0) < 1) {
                         zerr(gettext("%s property is out of range."),
                             pt_to_str(PT_NCPUS));
                         saw_error = B_TRUE;
                         return;
                 }
+                cap *= 100.0;
 
+                /* To avoid rounding issues add .5 to force correct value. */
                 if ((err = zonecfg_set_aliased_rctl(handle, ALIAS_CPUCAP,
-                    (int)(cap * 100))) != Z_OK)
+                    (uint_t)(cap + 0.5))) != Z_OK) {
                         zone_perror(zone, err, B_TRUE);
-                else
+                } else {
                         need_to_commit = B_TRUE;
+                }
                 return;
         case RT_MCAP:
                 switch (prop_type) {
                 case PT_PHYSICAL:
+                        /*
+                         * We have to check if an rctl is allowed here since
+                         * there might already be a rctl defined that blocks
+                         * the alias.
+                         */
+                        if (!zonecfg_aliased_rctl_ok(handle,
+                            ALIAS_MAXPHYSMEM)) {
+                                zone_perror(pt_to_str(PT_LOCKED),
+                                    Z_ALIAS_DISALLOW, B_FALSE);
+                                saw_error = B_TRUE;
+                                return;
+                        }
+
                         if (!zonecfg_valid_memlimit(prop_id, &mem_cap)) {
-                                zerr(gettext("A positive number with a "
+                                zerr(gettext("A non-negative number with a "
                                     "required scale suffix (K, M, G or T) was "
-                                    "expected here."));
+                                    "expected\nhere."));
                                 saw_error = B_TRUE;
-                        } else if (mem_cap < ONE_MB) {
-                                zerr(gettext("%s value is too small.  It must "
-                                    "be at least 1M."), pt_to_str(PT_PHYSICAL));
-                                saw_error = B_TRUE;
                         } else {
-                                snprintf(in_progress_mcaptab.zone_physmem_cap,
-                                    physmem_size, "%llu", mem_cap);
+                                if ((err = zonecfg_set_aliased_rctl(handle,
+                                    ALIAS_MAXPHYSMEM, mem_cap)) != Z_OK)
+                                        zone_perror(zone, err, B_TRUE);
+                                else
+                                        need_to_commit = B_TRUE;
                         }
                         break;
                 case PT_SWAP:
                         /*
                          * We have to check if an rctl is allowed here since
@@ -5029,16 +5315,29 @@
 }
 
 static void
 output_net(FILE *fp, struct zone_nwiftab *nwiftab)
 {
+        struct zone_res_attrtab *np;
+
         (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);
+        output_prop(fp, PT_GNIC, nwiftab->zone_nwif_gnic, B_TRUE);
+        output_prop(fp, PT_MAC, nwiftab->zone_nwif_mac, B_TRUE);
+        output_prop(fp, PT_PHYSICAL, nwiftab->zone_nwif_physical, B_TRUE);
+        output_prop(fp, PT_VLANID, nwiftab->zone_nwif_vlan_id, B_TRUE);
+
+        for (np = nwiftab->zone_nwif_attrp; np != NULL;
+            np = np->zone_res_attr_next) {
+                fprintf(fp, "\t%s: (%s=%s,%s=\"%s\")\n",
+                    pt_to_str(PT_NPROP),
+                    pt_to_str(PT_NAME), np->zone_res_attr_name,
+                    pt_to_str(PT_VALUE), np->zone_res_attr_value);
+        }
 }
 
 static void
 info_net(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
 {
@@ -5077,12 +5376,22 @@
 }
 
 static void
 output_dev(FILE *fp, struct zone_devtab *devtab)
 {
+        struct zone_res_attrtab *np;
+
         (void) fprintf(fp, "%s:\n", rt_to_str(RT_DEVICE));
         output_prop(fp, PT_MATCH, devtab->zone_dev_match, B_TRUE);
+
+        for (np = devtab->zone_dev_attrp; np != NULL;
+            np = np->zone_res_attr_next) {
+                fprintf(fp, "\t%s: (%s=%s,%s=\"%s\")\n",
+                    pt_to_str(PT_NPROP),
+                    pt_to_str(PT_NAME), np->zone_res_attr_name,
+                    pt_to_str(PT_VALUE), np->zone_res_attr_value);
+        }
 }
 
 static void
 info_dev(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
 {
@@ -5337,19 +5646,22 @@
         else
                 (void) snprintf(buf, bufsize, "%llu%c", num, *up);
 }
 
 static void
-output_mcap(FILE *fp, struct zone_mcaptab *mcaptab, int showswap,
+output_mcap(FILE *fp, int showphys, uint64_t maxphys, int showswap,
     uint64_t maxswap, int showlocked, uint64_t maxlocked)
 {
         char buf[128];
 
         (void) fprintf(fp, "%s:\n", rt_to_str(RT_MCAP));
-        if (mcaptab->zone_physmem_cap[0] != '\0') {
-                bytes_to_units(mcaptab->zone_physmem_cap, buf, sizeof (buf));
-                output_prop(fp, PT_PHYSICAL, buf, B_TRUE);
+
+        if (showphys == Z_OK) {
+                (void) snprintf(buf, sizeof (buf), "%llu", maxphys);
+                bytes_to_units(buf, buf, sizeof (buf));
+                /* Print directly since "physical" also is a net property. */
+                (void) fprintf(fp, "\t[%s: %s]\n", pt_to_str(PT_PHYSICAL), buf);
         }
 
         if (showswap == Z_OK) {
                 (void) snprintf(buf, sizeof (buf), "%llu", maxswap);
                 bytes_to_units(buf, buf, sizeof (buf));
@@ -5367,20 +5679,20 @@
 info_mcap(zone_dochandle_t handle, FILE *fp)
 {
         int res1, res2, res3;
         uint64_t swap_limit;
         uint64_t locked_limit;
-        struct zone_mcaptab lookup;
+        uint64_t phys_limit;
 
-        bzero(&lookup, sizeof (lookup));
-        res1 = zonecfg_getmcapent(handle, &lookup);
+        res1 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXPHYSMEM, &phys_limit);
         res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP, &swap_limit);
         res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
             &locked_limit);
 
         if (res1 == Z_OK || res2 == Z_OK || res3 == Z_OK)
-                output_mcap(fp, &lookup, res2, swap_limit, res3, locked_limit);
+                output_mcap(fp, res1, phys_limit, res2, swap_limit,
+                    res3, locked_limit);
 }
 
 static void
 output_auth(FILE *fp, struct zone_admintab *admintab)
 {
@@ -5427,13 +5739,14 @@
 info_func(cmd_t *cmd)
 {
         FILE *fp = stdout;
         boolean_t need_to_close = B_FALSE;
         int type;
-        int res1, res2;
+        int res1, res2, res3;
         uint64_t swap_limit;
         uint64_t locked_limit;
+        uint64_t phys_limit;
 
         assert(cmd != NULL);
 
         if (initialize(B_TRUE) != Z_OK)
                 return;
@@ -5477,11 +5790,13 @@
                 case RT_MCAP:
                         res1 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP,
                             &swap_limit);
                         res2 = zonecfg_get_aliased_rctl(handle,
                             ALIAS_MAXLOCKEDMEM, &locked_limit);
-                        output_mcap(fp, &in_progress_mcaptab, res1, swap_limit,
+                        res3 = zonecfg_get_aliased_rctl(handle,
+                            ALIAS_MAXPHYSMEM, &phys_limit);
+                        output_mcap(fp, res3, phys_limit, res1, swap_limit,
                             res2, locked_limit);
                         break;
                 case RT_ADMIN:
                         output_auth(fp, &in_progress_admintab);
                         break;
@@ -6099,10 +6414,16 @@
                         ret_val = Z_INSUFFICIENT_SPEC;
         }
 
         if (save) {
                 if (ret_val == Z_OK) {
+                        /*
+                         * If the zone doesn't yet have a debug ID, set one now.
+                         */
+                        if (zonecfg_get_did(handle) == -1)
+                                zonecfg_set_did(handle);
+
                         if ((ret_val = zonecfg_save(handle)) == Z_OK) {
                                 need_to_commit = B_FALSE;
                                 (void) strlcpy(revert_zone, zone,
                                     sizeof (revert_zone));
                         }
@@ -6273,10 +6594,11 @@
         struct zone_dstab tmp_dstab;
         struct zone_admintab tmp_admintab;
         int err, arg, res1, res2, res3;
         uint64_t swap_limit;
         uint64_t locked_limit;
+        uint64_t phys_limit;
         uint64_t proc_cap;
 
         assert(cmd != NULL);
 
         optind = 0;
@@ -6576,12 +6898,12 @@
                 }
                 err = Z_OK;
                 break;
         case RT_MCAP:
                 /* Make sure everything was filled in. */
-                res1 = strlen(in_progress_mcaptab.zone_physmem_cap) == 0 ?
-                    Z_ERR : Z_OK;
+                res1 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXPHYSMEM,
+                    &phys_limit);
                 res2 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXSWAP,
                     &swap_limit);
                 res3 = zonecfg_get_aliased_rctl(handle, ALIAS_MAXLOCKEDMEM,
                     &locked_limit);
 
@@ -6593,15 +6915,10 @@
                         return;
                 }
 
                 /* if phys & locked are both set, verify locked <= phys */
                 if (res1 == Z_OK && res3 == Z_OK) {
-                        uint64_t phys_limit;
-                        char *endp;
-
-                        phys_limit = strtoull(
-                            in_progress_mcaptab.zone_physmem_cap, &endp, 10);
                         if (phys_limit < locked_limit) {
                                 zerr(gettext("The %s cap must be less than or "
                                     "equal to the %s cap."),
                                     pt_to_str(PT_LOCKED),
                                     pt_to_str(PT_PHYSICAL));
@@ -6609,27 +6926,10 @@
                                 return;
                         }
                 }
 
                 err = Z_OK;
-                if (res1 == Z_OK) {
-                        /*
-                         * We could be ending from either an add operation
-                         * or a select operation.  Since all of the properties
-                         * within this resource are optional, we always use
-                         * modify on the mcap entry.  zonecfg_modify_mcap()
-                         * will handle both adding and modifying a memory cap.
-                         */
-                        err = zonecfg_modify_mcap(handle, &in_progress_mcaptab);
-                } else if (end_op == CMD_SELECT) {
-                        /*
-                         * If we're ending from a select and the physical
-                         * memory cap is empty then the user could have cleared
-                         * the physical cap value, so try to delete the entry.
-                         */
-                        (void) zonecfg_delete_mcap(handle);
-                }
                 break;
         case RT_ADMIN:
                 /* First make sure everything was filled in. */
                 if (end_check_reqd(in_progress_admintab.zone_admin_user,
                     PT_USER, &validation_failed) == Z_OK) {