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

@@ -233,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[] = {

@@ -405,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[] = {

@@ -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));

@@ -1696,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;
                 }

@@ -1799,10 +1844,11 @@
         struct zone_attrtab attrtab;
         struct zone_rctltab rctltab;
         struct zone_dstab dstab;
         struct zone_psettab psettab;
         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];

@@ -1968,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) {

@@ -1981,10 +2037,17 @@
         }
         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 ((err = zonecfg_setrctlent(handle)) != Z_OK) {

@@ -2347,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;

@@ -2414,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);

@@ -2518,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.

@@ -2717,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;

@@ -3399,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) {

@@ -3459,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);

@@ -3511,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;

@@ -3595,10 +3813,34 @@
                 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);

@@ -4201,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;

@@ -4464,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;

@@ -4474,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);

@@ -4489,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);

@@ -5028,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)
 {

@@ -5076,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)
 {

@@ -6104,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));
                         }