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
OS-4361 libzonecfg should be aware of branded zone native root
Reviewed by: Robert Mustacchi <rm@joyent.com>
OS-3437 zonecfg failure when pool is full leaves VMs appearing to be missing
OS-399 zone phys. mem. cap should be a rctl and have associated kstat
        
@@ -21,10 +21,11 @@
 
 /*
  * Copyright 2014 Gary Mills
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2015 Joyent Inc.
  */
 
 #include <libsysevent.h>
 #include <pthread.h>
 #include <stdlib.h>
@@ -57,10 +58,12 @@
 #include <auth_attr.h>
 #include <auth_list.h>
 #include <secdb.h>
 #include <user_attr.h>
 #include <prof_attr.h>
+#include <sys/debug.h>
+#include <os_dtd.h>
 
 #include <arpa/inet.h>
 #include <netdb.h>
 
 #include <libxml/xmlmemory.h>
@@ -77,17 +80,20 @@
 #define _PATH_TMPFILE   "/zonecfg.XXXXXX"
 #define ZONE_CB_RETRY_COUNT             10
 #define ZONE_EVENT_PING_SUBCLASS        "ping"
 #define ZONE_EVENT_PING_PUBLISHER       "solaris"
 
+#define DEBUGID_FILE    "/etc/zones/did.txt"
+
 /* Hard-code the DTD element/attribute/entity names just once, here. */
 #define DTD_ELEM_ATTR           (const xmlChar *) "attr"
 #define DTD_ELEM_COMMENT        (const xmlChar *) "comment"
 #define DTD_ELEM_DEVICE         (const xmlChar *) "device"
 #define DTD_ELEM_FS             (const xmlChar *) "filesystem"
 #define DTD_ELEM_FSOPTION       (const xmlChar *) "fsoption"
 #define DTD_ELEM_NET            (const xmlChar *) "network"
+#define DTD_ELEM_NETATTR        (const xmlChar *) "net-attr"
 #define DTD_ELEM_RCTL           (const xmlChar *) "rctl"
 #define DTD_ELEM_RCTLVALUE      (const xmlChar *) "rctl-value"
 #define DTD_ELEM_ZONE           (const xmlChar *) "zone"
 #define DTD_ELEM_DATASET        (const xmlChar *) "dataset"
 #define DTD_ELEM_TMPPOOL        (const xmlChar *) "tmp_pool"
@@ -103,23 +109,26 @@
 #define DTD_ATTR_ALLOWED_ADDRESS        (const xmlChar *) "allowed-address"
 #define DTD_ATTR_AUTOBOOT       (const xmlChar *) "autoboot"
 #define DTD_ATTR_IPTYPE         (const xmlChar *) "ip-type"
 #define DTD_ATTR_DEFROUTER      (const xmlChar *) "defrouter"
 #define DTD_ATTR_DIR            (const xmlChar *) "directory"
+#define DTD_ATTR_GNIC           (const xmlChar *) "global-nic"
 #define DTD_ATTR_LIMIT          (const xmlChar *) "limit"
 #define DTD_ATTR_LIMITPRIV      (const xmlChar *) "limitpriv"
 #define DTD_ATTR_BOOTARGS       (const xmlChar *) "bootargs"
 #define DTD_ATTR_SCHED          (const xmlChar *) "scheduling-class"
+#define DTD_ATTR_MAC            (const xmlChar *) "mac-addr"
 #define DTD_ATTR_MATCH          (const xmlChar *) "match"
 #define DTD_ATTR_NAME           (const xmlChar *) "name"
 #define DTD_ATTR_PHYSICAL       (const xmlChar *) "physical"
 #define DTD_ATTR_POOL           (const xmlChar *) "pool"
 #define DTD_ATTR_PRIV           (const xmlChar *) "priv"
 #define DTD_ATTR_RAW            (const xmlChar *) "raw"
 #define DTD_ATTR_SPECIAL        (const xmlChar *) "special"
 #define DTD_ATTR_TYPE           (const xmlChar *) "type"
 #define DTD_ATTR_VALUE          (const xmlChar *) "value"
+#define DTD_ATTR_VLANID         (const xmlChar *) "vlan-id"
 #define DTD_ATTR_ZONEPATH       (const xmlChar *) "zonepath"
 #define DTD_ATTR_NCPU_MIN       (const xmlChar *) "ncpu_min"
 #define DTD_ATTR_NCPU_MAX       (const xmlChar *) "ncpu_max"
 #define DTD_ATTR_IMPORTANCE     (const xmlChar *) "importance"
 #define DTD_ATTR_PHYSCAP        (const xmlChar *) "physcap"
@@ -128,10 +137,11 @@
 #define DTD_ATTR_UID            (const xmlChar *) "uid"
 #define DTD_ATTR_GID            (const xmlChar *) "gid"
 #define DTD_ATTR_MODE           (const xmlChar *) "mode"
 #define DTD_ATTR_ACL            (const xmlChar *) "acl"
 #define DTD_ATTR_BRAND          (const xmlChar *) "brand"
+#define DTD_ATTR_DID            (const xmlChar *) "debugid"
 #define DTD_ATTR_HOSTID         (const xmlChar *) "hostid"
 #define DTD_ATTR_USER           (const xmlChar *) "user"
 #define DTD_ATTR_AUTHS          (const xmlChar *) "auths"
 #define DTD_ATTR_FS_ALLOWED     (const xmlChar *) "fs-allowed"
 
@@ -174,10 +184,12 @@
         {ALIAS_MAXSHMIDS, "zone.max-shm-ids", "privileged", "deny", 0},
         {ALIAS_MAXMSGIDS, "zone.max-msg-ids", "privileged", "deny", 0},
         {ALIAS_MAXSEMIDS, "zone.max-sem-ids", "privileged", "deny", 0},
         {ALIAS_MAXLOCKEDMEM, "zone.max-locked-memory", "privileged", "deny", 0},
         {ALIAS_MAXSWAP, "zone.max-swap", "privileged", "deny", 0},
+        {ALIAS_MAXPHYSMEM, "zone.max-physical-memory", "privileged", "deny",
+            1048576},
         {ALIAS_SHARES, "zone.cpu-shares", "privileged", "none", 0},
         {ALIAS_CPUCAP, "zone.cpu-cap", "privileged", "deny", 0},
         {ALIAS_MAXPROCS, "zone.max-processes", "privileged", "deny", 100},
         {NULL, NULL, NULL, NULL, 0}
 };
@@ -267,23 +279,41 @@
  * Callers of the _file_path() functions are expected to have the second
  * parameter be a (char foo[MAXPATHLEN]).
  */
 
 static boolean_t
-config_file_path(const char *zonename, char *answer)
+file_path_common(const char *zonename, const char *subdir, const char *stem,
+    char *answer, size_t answer_size)
 {
-        return (snprintf(answer, MAXPATHLEN, "%s%s/%s.xml", zonecfg_root,
-            ZONE_CONFIG_ROOT, zonename) < MAXPATHLEN);
+        const char *native_root = zone_get_nroot();
+
+        if (native_root == NULL || zonecfg_in_alt_root()) {
+                /*
+                 * Do not prepend the native system root (e.g. "/native") if an
+                 * alternative configuration root has been selected.
+                 */
+                native_root = "";
+        }
+
+        return (snprintf(answer, answer_size, "%s%s%s/%s.%s", native_root,
+            zonecfg_root, subdir, zonename, stem) < answer_size);
 }
 
 static boolean_t
-snap_file_path(const char *zonename, char *answer)
+config_file_path(const char *zonename, char *answer, size_t answer_size)
 {
-        return (snprintf(answer, MAXPATHLEN, "%s%s/%s.snapshot.xml",
-            zonecfg_root, ZONE_SNAPSHOT_ROOT, zonename) < MAXPATHLEN);
+        return (file_path_common(zonename, ZONE_CONFIG_ROOT, "xml", answer,
+            answer_size));
 }
 
+static boolean_t
+snap_file_path(const char *zonename, char *answer, size_t answer_size)
+{
+        return (file_path_common(zonename, ZONE_SNAPSHOT_ROOT, "snapshot.xml",
+            answer, answer_size));
+}
+
 /*ARGSUSED*/
 static void
 zonecfg_error_func(void *ctx, const char *msg, ...)
 {
         /*
@@ -348,11 +378,11 @@
         char path[MAXPATHLEN];
         struct zoneent ze;
         int err, state_err;
         zone_state_t state;
 
-        if (!config_file_path(zonename, path))
+        if (!config_file_path(zonename, path, sizeof (path)))
                 return (Z_MISC_FS);
 
         state_err = zone_get_state((char *)zonename, &state);
         err = access(path, W_OK);
 
@@ -405,11 +435,11 @@
 int
 zonecfg_destroy_snapshot(const char *zonename)
 {
         char path[MAXPATHLEN];
 
-        if (!snap_file_path(zonename, path))
+        if (!snap_file_path(zonename, path, sizeof (path)))
                 return (Z_MISC_FS);
         return (zonecfg_destroy_impl(path));
 }
 
 static int
@@ -572,13 +602,12 @@
 
 static int
 zonecfg_get_handle_impl(const char *zonename, const char *filename,
     zone_dochandle_t handle)
 {
-        xmlValidCtxtPtr cvp;
         struct stat statbuf;
-        int valid;
+        boolean_t valid;
 
         if (zonename == NULL)
                 return (Z_NO_ZONE);
 
         if ((handle->zone_dh_doc = xmlParseFile(filename)) == NULL) {
@@ -585,18 +614,17 @@
                 /* distinguish file not found vs. found but not parsed */
                 if (stat(filename, &statbuf) == 0)
                         return (Z_INVALID_DOCUMENT);
                 return (Z_NO_ZONE);
         }
-        if ((cvp = xmlNewValidCtxt()) == NULL)
+
+        if (os_dtd_validate(handle->zone_dh_doc, B_FALSE, &valid) != 0) {
                 return (Z_NOMEM);
-        cvp->error = zonecfg_error_func;
-        cvp->warning = zonecfg_error_func;
-        valid = xmlValidateDocument(cvp, handle->zone_dh_doc);
-        xmlFreeValidCtxt(cvp);
-        if (valid == 0)
+        }
+        if (!valid) {
                 return (Z_INVALID_DOCUMENT);
+        }
 
         /* delete any comments such as inherited Sun copyright / ident str */
         stripcomments(handle);
         return (Z_OK);
 }
@@ -604,11 +632,11 @@
 int
 zonecfg_get_handle(const char *zonename, zone_dochandle_t handle)
 {
         char path[MAXPATHLEN];
 
-        if (!config_file_path(zonename, path))
+        if (!config_file_path(zonename, path, sizeof (path)))
                 return (Z_MISC_FS);
         handle->zone_dh_newzone = B_FALSE;
 
         return (zonecfg_get_handle_impl(zonename, path, handle));
 }
@@ -648,11 +676,11 @@
 int
 zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle)
 {
         char path[MAXPATHLEN];
 
-        if (!snap_file_path(zonename, path))
+        if (!snap_file_path(zonename, path, sizeof (path)))
                 return (Z_MISC_FS);
         handle->zone_dh_newzone = B_FALSE;
         return (zonecfg_get_handle_impl(zonename, path, handle));
 }
 
@@ -661,11 +689,11 @@
     zone_dochandle_t handle)
 {
         char path[MAXPATHLEN];
         int err;
 
-        if (!config_file_path(template, path))
+        if (!config_file_path(template, path, sizeof (path)))
                 return (Z_MISC_FS);
 
         if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK)
                 return (err);
         handle->zone_dh_newzone = B_TRUE;
@@ -695,25 +723,23 @@
  */
 int
 zonecfg_attach_manifest(int fd, zone_dochandle_t local_handle,
     zone_dochandle_t rem_handle)
 {
-        xmlValidCtxtPtr cvp;
-        int valid;
+        boolean_t valid;
 
         /* load the manifest into the handle for the remote system */
         if ((rem_handle->zone_dh_doc = xmlReadFd(fd, NULL, NULL, 0)) == NULL) {
                 return (Z_INVALID_DOCUMENT);
         }
-        if ((cvp = xmlNewValidCtxt()) == NULL)
+
+        if (os_dtd_validate(rem_handle->zone_dh_doc, B_FALSE, &valid) != 0) {
                 return (Z_NOMEM);
-        cvp->error = zonecfg_error_func;
-        cvp->warning = zonecfg_error_func;
-        valid = xmlValidateDocument(cvp, rem_handle->zone_dh_doc);
-        xmlFreeValidCtxt(cvp);
-        if (valid == 0)
+        }
+        if (!valid) {
                 return (Z_INVALID_DOCUMENT);
+        }
 
         /* delete any comments such as inherited Sun copyright / ident str */
         stripcomments(rem_handle);
 
         rem_handle->zone_dh_newzone = B_TRUE;
@@ -730,18 +756,16 @@
 
         /*
          * We need to re-run xmlValidateDocument on local_handle to properly
          * update the in-core representation of the configuration.
          */
-        if ((cvp = xmlNewValidCtxt()) == NULL)
+        if (os_dtd_validate(local_handle->zone_dh_doc, B_FALSE, &valid) != 0) {
                 return (Z_NOMEM);
-        cvp->error = zonecfg_error_func;
-        cvp->warning = zonecfg_error_func;
-        valid = xmlValidateDocument(cvp, local_handle->zone_dh_doc);
-        xmlFreeValidCtxt(cvp);
-        if (valid == 0)
+        }
+        if (!valid) {
                 return (Z_INVALID_DOCUMENT);
+        }
 
         strip_sw_inv(local_handle);
 
         local_handle->zone_dh_newzone = B_TRUE;
         local_handle->zone_dh_sw_inv = B_FALSE;
@@ -1191,13 +1215,13 @@
 static int
 zonecfg_save_impl(zone_dochandle_t handle, char *filename)
 {
         char tmpfile[MAXPATHLEN];
         char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN];
-        int tmpfd, err, valid;
-        xmlValidCtxt cvp = { NULL };
+        int tmpfd, err;
         boolean_t backup;
+        boolean_t valid;
 
         (void) strlcpy(tmpfile, filename, sizeof (tmpfile));
         (void) dirname(tmpfile);
         (void) strlcat(tmpfile, _PATH_TMPFILE, sizeof (tmpfile));
 
@@ -1206,20 +1230,17 @@
                 (void) unlink(tmpfile);
                 return (Z_TEMP_FILE);
         }
         (void) close(tmpfd);
 
-        cvp.error = zonecfg_error_func;
-        cvp.warning = zonecfg_error_func;
-
         /*
          * We do a final validation of the document.  Since the library has
          * malfunctioned if it fails to validate, we follow-up with an
          * assert() that the doc is valid.
          */
-        valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
-        assert(valid != 0);
+        VERIFY0(os_dtd_validate(handle->zone_dh_doc, B_FALSE, &valid));
+        VERIFY(valid == B_TRUE);
 
         if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0)
                 goto err;
 
         (void) chmod(tmpfile, 0644);
@@ -1270,11 +1291,10 @@
         if ((err = zonecfg_refresh_index_file(handle)) != Z_OK) {
                 if (backup) {
                         /*
                          * Try to restore from our backup.
                          */
-                        (void) unlink(filename);
                         (void) rename(bakfile, filename);
                 } else {
                         /*
                          * Either the zone is new, in which case we can delete
                          * new.xml, or we're doing a rename, so ditto.
@@ -1313,11 +1333,11 @@
                 return (Z_INVAL);
 
         if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK)
                 return (err);
 
-        if (!config_file_path(zname, path))
+        if (!config_file_path(zname, path, sizeof (path)))
                 return (Z_MISC_FS);
 
         addcomment(handle, "\n    DO NOT EDIT THIS "
             "FILE.  Use zonecfg(1M) instead.\n");
 
@@ -1334,38 +1354,35 @@
                 return (err);
 
         handle->zone_dh_newzone = B_FALSE;
 
         if (is_renaming(handle)) {
-                if (config_file_path(handle->zone_dh_delete_name, delpath))
+                if (config_file_path(handle->zone_dh_delete_name, delpath,
+                    sizeof (delpath))) {
                         (void) unlink(delpath);
+                }
                 handle->zone_dh_delete_name[0] = '\0';
         }
 
         return (Z_OK);
 }
 
 int
 zonecfg_verify_save(zone_dochandle_t handle, char *filename)
 {
-        int valid;
+        boolean_t valid;
 
-        xmlValidCtxt cvp = { NULL };
-
         if (zonecfg_check_handle(handle) != Z_OK)
                 return (Z_BAD_HANDLE);
 
-        cvp.error = zonecfg_error_func;
-        cvp.warning = zonecfg_error_func;
-
         /*
          * We do a final validation of the document.  Since the library has
          * malfunctioned if it fails to validate, we follow-up with an
          * assert() that the doc is valid.
          */
-        valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
-        assert(valid != 0);
+        VERIFY0(os_dtd_validate(handle->zone_dh_doc, B_FALSE, &valid));
+        VERIFY(valid == B_TRUE);
 
         if (xmlSaveFormatFile(filename, handle->zone_dh_doc, 1) <= 0)
                 return (Z_SAVING_FILE);
 
         return (Z_OK);
@@ -1375,13 +1392,12 @@
 zonecfg_detach_save(zone_dochandle_t handle, uint_t flags)
 {
         char zname[ZONENAME_MAX];
         char path[MAXPATHLEN];
         char migpath[MAXPATHLEN];
-        xmlValidCtxt cvp = { NULL };
         int err = Z_SAVING_FILE;
-        int valid;
+        boolean_t valid;
 
         if (zonecfg_check_handle(handle) != Z_OK)
                 return (Z_BAD_HANDLE);
 
         if (flags & ZONE_DRY_RUN) {
@@ -1404,20 +1420,17 @@
                 return (err);
 
         addcomment(handle, "\n    DO NOT EDIT THIS FILE.  "
             "Use zonecfg(1M) and zoneadm(1M) attach.\n");
 
-        cvp.error = zonecfg_error_func;
-        cvp.warning = zonecfg_error_func;
-
         /*
          * We do a final validation of the document.  Since the library has
          * malfunctioned if it fails to validate, we follow-up with an
          * assert() that the doc is valid.
          */
-        valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
-        assert(valid != 0);
+        VERIFY0(os_dtd_validate(handle->zone_dh_doc, B_FALSE, &valid));
+        VERIFY(valid == B_TRUE);
 
         if (xmlSaveFormatFile(migpath, handle->zone_dh_doc, 1) <= 0)
                 return (Z_SAVING_FILE);
 
         if (!(flags & ZONE_DRY_RUN))
@@ -1486,11 +1499,11 @@
 int
 zonecfg_access(const char *zonename, int amode)
 {
         char path[MAXPATHLEN];
 
-        if (!config_file_path(zonename, path))
+        if (!config_file_path(zonename, path, sizeof (path)))
                 return (Z_INVAL);
         if (access(path, amode) == 0)
                 return (Z_OK);
         if (errno == ENOENT) {
                 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
@@ -1551,11 +1564,11 @@
         if ((mkdir(path, S_IRWXU) == -1) && (errno != EEXIST)) {
                 error = Z_MISC_FS;
                 goto out;
         }
 
-        if (!snap_file_path(zonename, path)) {
+        if (!snap_file_path(zonename, path, sizeof (path))) {
                 error = Z_MISC_FS;
                 goto out;
         }
 
         addcomment(handle, "\n    DO NOT EDIT THIS FILE.  "
@@ -2082,17 +2095,21 @@
  * address, and default router information are stored in 'tabptr'.
  */
 int
 zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
 {
-        xmlNodePtr cur;
+        xmlNodePtr cur, val;
         xmlNodePtr firstmatch;
         int err;
         char address[INET6_ADDRSTRLEN];
         char physical[LIFNAMSIZ];
+        char mac[MAXMACADDRLEN];
+        char gnic[LIFNAMSIZ];
         size_t addrspec;                /* nonzero if tabptr has IP addr */
         size_t physspec;                /* nonzero if tabptr has interface */
+        size_t macspec;                 /* nonzero if tabptr has mac addr */
+        size_t gnicspec;                /* nonzero if tabptr has gnic */
         size_t defrouterspec;           /* nonzero if tabptr has def. router */
         size_t allowed_addrspec;
         zone_iptype_t iptype;
 
         if (tabptr == NULL)
@@ -2100,21 +2117,24 @@
 
         /*
          * Determine the fields that will be searched.  There must be at least
          * one.
          *
-         * zone_nwif_address, zone_nwif_physical, and zone_nwif_defrouter are
+         * zone_nwif_address, zone_nwif_physical, zone_nwif_defrouter,
+         * zone_nwif_mac, zone_nwif_vlan_id and zone_nwif_gnic  are
          * arrays, so no NULL checks are necessary.
          */
         addrspec = strlen(tabptr->zone_nwif_address);
         physspec = strlen(tabptr->zone_nwif_physical);
+        macspec = strlen(tabptr->zone_nwif_mac);
+        gnicspec = strlen(tabptr->zone_nwif_gnic);
         defrouterspec = strlen(tabptr->zone_nwif_defrouter);
         allowed_addrspec = strlen(tabptr->zone_nwif_allowed_address);
         if (addrspec != 0 && allowed_addrspec != 0)
                 return (Z_INVAL); /* can't specify both */
         if (addrspec == 0 && physspec == 0 && defrouterspec == 0 &&
-            allowed_addrspec == 0)
+            allowed_addrspec == 0 && macspec == 0 && gnicspec == 0)
                 return (Z_INSUFFICIENT_SPEC);
 
         if ((err = operation_prep(handle)) != Z_OK)
                 return (err);
 
@@ -2137,10 +2157,19 @@
                  */
                 if (physspec != 0 && (fetchprop(cur, DTD_ATTR_PHYSICAL,
                     physical, sizeof (physical)) != Z_OK ||
                     strcmp(tabptr->zone_nwif_physical, physical) != 0))
                         continue;
+                if (iptype == ZS_EXCLUSIVE && macspec != 0 &&
+                    (fetchprop(cur, DTD_ATTR_MAC, mac, sizeof (mac)) != Z_OK ||
+                    strcmp(tabptr->zone_nwif_mac, mac) != 0))
+                        continue;
+                if (iptype == ZS_EXCLUSIVE && gnicspec != 0 &&
+                    (fetchprop(cur, DTD_ATTR_GNIC, gnic,
+                    sizeof (gnic)) != Z_OK ||
+                    strcmp(tabptr->zone_nwif_gnic, gnic) != 0))
+                        continue;
                 if (iptype == ZS_SHARED && addrspec != 0 &&
                     (fetchprop(cur, DTD_ATTR_ADDRESS, address,
                     sizeof (address)) != Z_OK ||
                     !zonecfg_same_net_address(tabptr->zone_nwif_address,
                     address)))
@@ -2179,10 +2208,25 @@
             (err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
             sizeof (tabptr->zone_nwif_address))) != Z_OK)
                 return (err);
 
         if (iptype == ZS_EXCLUSIVE &&
+            (err = fetchprop(cur, DTD_ATTR_MAC, tabptr->zone_nwif_mac,
+            sizeof (tabptr->zone_nwif_mac))) != Z_OK)
+                return (err);
+
+        if (iptype == ZS_EXCLUSIVE &&
+            (err = fetchprop(cur, DTD_ATTR_VLANID, tabptr->zone_nwif_vlan_id,
+            sizeof (tabptr->zone_nwif_vlan_id))) != Z_OK)
+                return (err);
+
+        if (iptype == ZS_EXCLUSIVE &&
+            (err = fetchprop(cur, DTD_ATTR_GNIC, tabptr->zone_nwif_gnic,
+            sizeof (tabptr->zone_nwif_gnic))) != Z_OK)
+                return (err);
+
+        if (iptype == ZS_EXCLUSIVE &&
             (err = fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS,
             tabptr->zone_nwif_allowed_address,
             sizeof (tabptr->zone_nwif_allowed_address))) != Z_OK)
                 return (err);
 
@@ -2189,17 +2233,44 @@
         if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
             tabptr->zone_nwif_defrouter,
             sizeof (tabptr->zone_nwif_defrouter))) != Z_OK)
                 return (err);
 
+        tabptr->zone_nwif_attrp = NULL;
+        for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
+                struct zone_res_attrtab *valptr;
+
+                valptr = (struct zone_res_attrtab *)malloc(
+                    sizeof (struct zone_res_attrtab));
+                if (valptr == NULL)
+                        return (Z_NOMEM);
+
+                valptr->zone_res_attr_name[0] =
+                    valptr->zone_res_attr_value[0] = '\0';
+                if (zonecfg_add_res_attr(&(tabptr->zone_nwif_attrp), valptr)
+                    != Z_OK) {
+                        free(valptr);
+                        break;
+                }
+
+                if ((fetchprop(val, DTD_ATTR_NAME, valptr->zone_res_attr_name,
+                    sizeof (valptr->zone_res_attr_name)) != Z_OK))
+                        break;
+                if ((fetchprop(val, DTD_ATTR_VALUE,
+                    valptr->zone_res_attr_value,
+                    sizeof (valptr->zone_res_attr_value)) != Z_OK))
+                        break;
+        }
+
         return (Z_OK);
 }
 
 static int
 zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
 {
-        xmlNodePtr newnode, cur = handle->zone_dh_cur;
+        xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode;
+        struct zone_res_attrtab *valptr;
         int err;
 
         newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL);
         if (strlen(tabptr->zone_nwif_address) > 0 &&
             (err = newprop(newnode, DTD_ATTR_ADDRESS,
@@ -2211,17 +2282,44 @@
                 return (err);
         if ((err = newprop(newnode, DTD_ATTR_PHYSICAL,
             tabptr->zone_nwif_physical)) != Z_OK)
                 return (err);
         /*
-         * Do not add this property when it is not set, for backwards
-         * compatibility and because it is optional.
+         * Do not add these properties when they are not set, for backwards
+         * compatibility and because they are optional.
          */
         if ((strlen(tabptr->zone_nwif_defrouter) > 0) &&
             ((err = newprop(newnode, DTD_ATTR_DEFROUTER,
             tabptr->zone_nwif_defrouter)) != Z_OK))
                 return (err);
+        if (strlen(tabptr->zone_nwif_mac) > 0 &&
+            (err = newprop(newnode, DTD_ATTR_MAC,
+            tabptr->zone_nwif_mac)) != Z_OK)
+                return (err);
+        if (strlen(tabptr->zone_nwif_vlan_id) > 0 &&
+            (err = newprop(newnode, DTD_ATTR_VLANID,
+            tabptr->zone_nwif_vlan_id)) != Z_OK)
+                return (err);
+        if (strlen(tabptr->zone_nwif_gnic) > 0 &&
+            (err = newprop(newnode, DTD_ATTR_GNIC,
+            tabptr->zone_nwif_gnic)) != Z_OK)
+                return (err);
+
+        for (valptr = tabptr->zone_nwif_attrp; valptr != NULL;
+            valptr = valptr->zone_res_attr_next) {
+                valnode = xmlNewTextChild(newnode, NULL, DTD_ELEM_NETATTR,
+                    NULL);
+                err = newprop(valnode, DTD_ATTR_NAME,
+                    valptr->zone_res_attr_name);
+                if (err != Z_OK)
+                        return (err);
+                err = newprop(valnode, DTD_ATTR_VALUE,
+                    valptr->zone_res_attr_value);
+                if (err != Z_OK)
+                        return (err);
+        }
+
         return (Z_OK);
 }
 
 int
 zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
@@ -2242,11 +2340,12 @@
 
 static int
 zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
 {
         xmlNodePtr cur = handle->zone_dh_cur;
-        boolean_t addr_match, phys_match, allowed_addr_match;
+        boolean_t addr_match, phys_match, allowed_addr_match, mac_match,
+            gnic_match;
 
         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
                 if (xmlStrcmp(cur->name, DTD_ELEM_NET))
                         continue;
 
@@ -2254,12 +2353,17 @@
                     tabptr->zone_nwif_address);
                 allowed_addr_match = match_prop(cur, DTD_ATTR_ALLOWED_ADDRESS,
                     tabptr->zone_nwif_allowed_address);
                 phys_match = match_prop(cur, DTD_ATTR_PHYSICAL,
                     tabptr->zone_nwif_physical);
+                mac_match = match_prop(cur, DTD_ATTR_MAC,
+                    tabptr->zone_nwif_mac);
+                gnic_match = match_prop(cur, DTD_ATTR_GNIC,
+                    tabptr->zone_nwif_gnic);
 
-                if (addr_match && allowed_addr_match && phys_match) {
+                if ((addr_match || allowed_addr_match || mac_match ||
+                    gnic_match) && phys_match) {
                         xmlUnlinkNode(cur);
                         xmlFreeNode(cur);
                         return (Z_OK);
                 }
         }
@@ -2304,10 +2408,62 @@
                 return (err);
 
         return (Z_OK);
 }
 
+void
+zonecfg_free_res_attr_list(struct zone_res_attrtab *valtab)
+{
+        if (valtab == NULL)
+                return;
+        zonecfg_free_res_attr_list(valtab->zone_res_attr_next);
+        free(valtab);
+}
+
+int
+zonecfg_add_res_attr(struct zone_res_attrtab **headptr,
+    struct zone_res_attrtab *valtabptr)
+{
+        struct zone_res_attrtab *last, *old, *new;
+
+        last = *headptr;
+        for (old = last; old != NULL; old = old->zone_res_attr_next)
+                last = old;     /* walk to the end of the list */
+        new = valtabptr;        /* alloc'd by caller */
+        new->zone_res_attr_next = NULL;
+        if (last == NULL)
+                *headptr = new;
+        else
+                last->zone_res_attr_next = new;
+        return (Z_OK);
+}
+
+int
+zonecfg_remove_res_attr(struct zone_res_attrtab **headptr,
+    struct zone_res_attrtab *valtabptr)
+{
+        struct zone_res_attrtab *last, *this, *next;
+
+        last = *headptr;
+        for (this = last; this != NULL; this = this->zone_res_attr_next) {
+                if (strcmp(this->zone_res_attr_name,
+                    valtabptr->zone_res_attr_name) == 0 &&
+                    strcmp(this->zone_res_attr_value,
+                    valtabptr->zone_res_attr_value) == 0) {
+                        next = this->zone_res_attr_next;
+                        if (this == *headptr)
+                                *headptr = next;
+                        else
+                                last->zone_res_attr_next = next;
+                        free(this);
+                        return (Z_OK);
+                } else
+                        last = this;
+        }
+        return (Z_NO_PROPERTY_ID);
+}
+
 /*
  * Must be a comma-separated list of alpha-numeric file system names.
  */
 static int
 zonecfg_valid_fs_allowed(const char *fsallowedp)
@@ -2453,11 +2609,11 @@
 }
 
 int
 zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
 {
-        xmlNodePtr cur, firstmatch;
+        xmlNodePtr cur, val, firstmatch;
         int err;
         char match[MAXPATHLEN];
 
         if (tabptr == NULL)
                 return (Z_INVAL);
@@ -2498,25 +2654,67 @@
 
         if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
             sizeof (tabptr->zone_dev_match))) != Z_OK)
                 return (err);
 
+        tabptr->zone_dev_attrp = NULL;
+        for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
+                struct zone_res_attrtab *valptr;
+
+                valptr = (struct zone_res_attrtab *)malloc(
+                    sizeof (struct zone_res_attrtab));
+                if (valptr == NULL)
+                        return (Z_NOMEM);
+
+                valptr->zone_res_attr_name[0] =
+                    valptr->zone_res_attr_value[0] = '\0';
+                if (zonecfg_add_res_attr(&(tabptr->zone_dev_attrp), valptr)
+                    != Z_OK) {
+                        free(valptr);
+                        break;
+                }
+
+                if ((fetchprop(val, DTD_ATTR_NAME, valptr->zone_res_attr_name,
+                    sizeof (valptr->zone_res_attr_name)) != Z_OK))
+                        break;
+                if ((fetchprop(val, DTD_ATTR_VALUE,
+                    valptr->zone_res_attr_value,
+                    sizeof (valptr->zone_res_attr_value)) != Z_OK))
+                        break;
+        }
+
         return (Z_OK);
 }
 
 static int
 zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
 {
-        xmlNodePtr newnode, cur = handle->zone_dh_cur;
+        xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode;
+        struct zone_res_attrtab *valptr;
         int err;
 
         newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL);
 
         if ((err = newprop(newnode, DTD_ATTR_MATCH,
             tabptr->zone_dev_match)) != Z_OK)
                 return (err);
 
+        for (valptr = tabptr->zone_dev_attrp; valptr != NULL;
+            valptr = valptr->zone_res_attr_next) {
+                valnode = xmlNewTextChild(newnode, NULL, DTD_ELEM_NETATTR,
+                    NULL);
+                err = newprop(valnode, DTD_ATTR_NAME,
+                    valptr->zone_res_attr_name);
+                if (err != Z_OK)
+                        return (err);
+                err = newprop(valnode, DTD_ATTR_VALUE,
+                    valptr->zone_res_attr_value);
+                if (err != Z_OK)
+                        return (err);
+        }
+
+
         return (Z_OK);
 }
 
 int
 zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
@@ -4710,11 +4908,12 @@
 }
 
 int
 zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
 {
-        xmlNodePtr cur;
+        xmlNodePtr cur, val;
+        struct zone_res_attrtab *valptr;
         int err;
 
         if (handle == NULL)
                 return (Z_INVAL);
 
@@ -4746,17 +4945,58 @@
             sizeof (tabptr->zone_nwif_physical))) != Z_OK) {
                 handle->zone_dh_cur = handle->zone_dh_top;
                 return (err);
         }
 
+        if ((err = fetchprop(cur, DTD_ATTR_MAC, tabptr->zone_nwif_mac,
+            sizeof (tabptr->zone_nwif_mac))) != Z_OK) {
+                handle->zone_dh_cur = handle->zone_dh_top;
+                return (err);
+        }
+
+        if ((err = fetchprop(cur, DTD_ATTR_VLANID, tabptr->zone_nwif_vlan_id,
+            sizeof (tabptr->zone_nwif_vlan_id))) != Z_OK) {
+                handle->zone_dh_cur = handle->zone_dh_top;
+                return (err);
+        }
+
+        if ((err = fetchprop(cur, DTD_ATTR_GNIC, tabptr->zone_nwif_gnic,
+            sizeof (tabptr->zone_nwif_gnic))) != Z_OK) {
+                handle->zone_dh_cur = handle->zone_dh_top;
+                return (err);
+        }
+
         if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
             tabptr->zone_nwif_defrouter,
             sizeof (tabptr->zone_nwif_defrouter))) != Z_OK) {
                 handle->zone_dh_cur = handle->zone_dh_top;
                 return (err);
         }
 
+        tabptr->zone_nwif_attrp = NULL;
+        for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
+                valptr = (struct zone_res_attrtab *)malloc(
+                    sizeof (struct zone_res_attrtab));
+                if (valptr == NULL)
+                        return (Z_NOMEM);
+
+                valptr->zone_res_attr_name[0] =
+                    valptr->zone_res_attr_value[0] = '\0';
+                if (zonecfg_add_res_attr(&(tabptr->zone_nwif_attrp), valptr)
+                    != Z_OK) {
+                        free(valptr);
+                        break;
+                }
+
+                if (fetchprop(val, DTD_ATTR_NAME, valptr->zone_res_attr_name,
+                    sizeof (valptr->zone_res_attr_name)) != Z_OK)
+                        break;
+                if (fetchprop(val, DTD_ATTR_VALUE, valptr->zone_res_attr_value,
+                    sizeof (valptr->zone_res_attr_value)) != Z_OK)
+                        break;
+        }
+
         handle->zone_dh_cur = cur->next;
         return (Z_OK);
 }
 
 int
@@ -4772,11 +5012,11 @@
 }
 
 int
 zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr)
 {
-        xmlNodePtr cur;
+        xmlNodePtr cur, val;
         int err;
 
         if (handle == NULL)
                 return (Z_INVAL);
 
@@ -4795,10 +5035,35 @@
             sizeof (tabptr->zone_dev_match))) != Z_OK) {
                 handle->zone_dh_cur = handle->zone_dh_top;
                 return (err);
         }
 
+        tabptr->zone_dev_attrp = NULL;
+        for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
+                struct zone_res_attrtab *valptr;
+
+                valptr = (struct zone_res_attrtab *)malloc(
+                    sizeof (struct zone_res_attrtab));
+                if (valptr == NULL)
+                        return (Z_NOMEM);
+
+                valptr->zone_res_attr_name[0] =
+                    valptr->zone_res_attr_value[0] = '\0';
+                if (zonecfg_add_res_attr(&(tabptr->zone_dev_attrp), valptr)
+                    != Z_OK) {
+                        free(valptr);
+                        break;
+                }
+
+                if ((fetchprop(val, DTD_ATTR_NAME, valptr->zone_res_attr_name,
+                    sizeof (valptr->zone_res_attr_name)) != Z_OK))
+                        break;
+                if ((fetchprop(val, DTD_ATTR_VALUE, valptr->zone_res_attr_value,
+                    sizeof (valptr->zone_res_attr_value)) != Z_OK))
+                        break;
+        }
+
         handle->zone_dh_cur = cur->next;
         return (Z_OK);
 }
 
 int
@@ -5523,10 +5788,168 @@
         zonecfg_fini_handle(handle);
         return (err);
 }
 
 /*
+ * Atomically get a new zone_did value.  The currently allocated value
+ * is stored in /etc/zones/did.txt.  Lock the file, read the current value,
+ * increment, save the new value and unlock the file.  Return the new value
+ * or -1 if there was an error.  The ID namespace is large enough that we
+ * don't worry about recycling an ID when a zone is deleted.
+ */
+static zoneid_t
+new_zone_did()
+{
+        int fd;
+        int len;
+        int val;
+        struct flock lck;
+        char buf[80];
+
+        if ((fd = open(DEBUGID_FILE, O_RDWR | O_CREAT,
+            S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
+                perror("new_zone_did open failed");
+                return (-1);
+        }
+
+        /* Initialize the lock. */
+        lck.l_whence = SEEK_SET;
+        lck.l_start = 0;
+        lck.l_len = 0;
+
+        /* Wait until we acquire an exclusive lock on the file. */
+        lck.l_type = F_WRLCK;
+        if (fcntl(fd, F_SETLKW, &lck) == -1) {
+                perror("new_zone_did lock failed");
+                (void) close(fd);
+                return (-1);
+        }
+
+        /* Get currently allocated value */
+        len = read(fd, buf, sizeof (buf));
+        if (len == -1) {
+                perror("new_zone_did read failed");
+                val = -1;
+        } else {
+                if (lseek(fd, 0L, SEEK_SET) == -1) {
+                        perror("new_zone_did seek failed");
+                        val = -1;
+                } else {
+                        if (len == 0) {
+                                /* Just created the file, initialize at 1 */
+                                val = 1;
+                        } else {
+                                val = atoi(buf);
+                                val++;
+                        }
+
+                        (void) snprintf(buf, sizeof (buf), "%d\n", val);
+                        len = strlen(buf);
+
+                        /* Save newly allocated value */
+                        if (write(fd, buf, len) == -1) {
+                                perror("new_zone_did write failed");
+                                val = -1;
+                        }
+                }
+        }
+
+        /* Release the file lock. */
+        lck.l_type = F_UNLCK;
+        if (fcntl(fd, F_SETLK, &lck) == -1) {
+                perror("new_zone_did unlock failed");
+                val = -1;
+        }
+
+        if (close(fd) != 0)
+                perror("new_zone_did close failed");
+
+        return (val);
+}
+
+/*
+ * Called by zoneadmd to get the zone's debug ID.
+ * If the zone doesn't already have an ID, a new one is generated and
+ * persistently saved onto the zone.  Normally either zoneadm or zonecfg
+ * will assign a new ID for the zone, so zoneadmd should never have to
+ * generate one, but we also handle that here just to be paranoid.
+ */
+zoneid_t
+zone_get_did(char *zone_name)
+{
+        int res;
+        zoneid_t new_did;
+        zone_dochandle_t handle;
+        char did_str[80];
+
+        if ((handle = zonecfg_init_handle()) == NULL)
+                return (getpid());
+
+        if (zonecfg_get_handle((char *)zone_name, handle) != Z_OK)
+                return (getpid());
+
+        res = getrootattr(handle, DTD_ATTR_DID, did_str, sizeof (did_str));
+
+        /* If the zone already has an assigned debug ID, return it. */
+        if (res == Z_OK && did_str[0] != '\0') {
+                zonecfg_fini_handle(handle);
+                return (atoi(did_str));
+        }
+
+        /*
+         * The zone doesn't have an assigned debug ID yet, generate one and
+         * save it as part of the zone definition.
+         */
+        if ((new_did = new_zone_did()) == -1) {
+                /*
+                 * We should really never hit this block of code.
+                 * Generating a new ID failed for some reason.  Use the current
+                 * pid as a temporary ID so that the zone can continue to boot
+                 * but we don't persistently save this temporary ID on the zone.
+                 */
+                zonecfg_fini_handle(handle);
+                return (getpid());
+        }
+
+        /* Now persistently save this new ID onto the zone. */
+        (void) snprintf(did_str, sizeof (did_str), "%d", new_did);
+        (void) setrootattr(handle, DTD_ATTR_DID, did_str);
+        (void) zonecfg_save(handle);
+
+        zonecfg_fini_handle(handle);
+        return (new_did);
+}
+
+zoneid_t
+zonecfg_get_did(zone_dochandle_t handle)
+{
+        char did_str[80];
+        int err;
+        zoneid_t did;
+
+        err = getrootattr(handle, DTD_ATTR_DID, did_str, sizeof (did_str));
+        if (err == Z_OK && did_str[0] != '\0')
+                did = atoi(did_str);
+        else
+                did = -1;
+
+        return (did);
+}
+
+void
+zonecfg_set_did(zone_dochandle_t handle)
+{
+        zoneid_t new_did;
+        char did_str[80];
+
+        if ((new_did = new_zone_did()) == -1)
+                return;
+        (void) snprintf(did_str, sizeof (did_str), "%d", new_did);
+        (void) setrootattr(handle, DTD_ATTR_DID, did_str);
+}
+
+/*
  * Return the appropriate root for the active /dev.
  * For normal zone, the path is $ZONEPATH/root;
  * for scratch zone, the dev path is $ZONEPATH/lu.
  */
 int
@@ -6837,137 +7260,55 @@
         (void) zonecfg_endent(handle);
 
         return (err);
 }
 
-static int
-add_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
-{
-        xmlNodePtr newnode, cur = handle->zone_dh_cur;
-        int err;
-
-        newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_MCAP, NULL);
-        if ((err = newprop(newnode, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap))
-            != Z_OK)
-                return (err);
-
-        return (Z_OK);
-}
-
+/*
+ * Cleanup obsolete constructs in the configuration.
+ * Return true of the config has been updated and must be commited.
+ */
 int
-zonecfg_delete_mcap(zone_dochandle_t handle)
+zonecfg_fix_obsolete(zone_dochandle_t handle)
 {
-        int err;
-        xmlNodePtr cur = handle->zone_dh_cur;
-
-        if ((err = operation_prep(handle)) != Z_OK)
-                return (err);
-
-        for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
-                if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
-                        continue;
-
-                xmlUnlinkNode(cur);
-                xmlFreeNode(cur);
-                return (Z_OK);
-        }
-        return (Z_NO_RESOURCE_ID);
-}
-
-int
-zonecfg_modify_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
-{
-        int err;
-
-        if (tabptr == NULL)
-                return (Z_INVAL);
-
-        err = zonecfg_delete_mcap(handle);
-        /* it is ok if there is no mcap entry */
-        if (err != Z_OK && err != Z_NO_RESOURCE_ID)
-                return (err);
-
-        if ((err = add_mcap(handle, tabptr)) != Z_OK)
-                return (err);
-
-        return (Z_OK);
-}
-
-int
-zonecfg_lookup_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
-{
+        int res = 0;
+        int add_physmem_rctl = 0;
         xmlNodePtr cur;
-        int err;
+        char    zone_physmem_cap[MAXNAMELEN];
 
-        if (tabptr == NULL)
-                return (Z_INVAL);
+        if (operation_prep(handle) != Z_OK)
+                return (res);
 
-        if ((err = operation_prep(handle)) != Z_OK)
-                return (err);
-
+        /*
+         * If an obsolete mcap entry exists, convert it to the rctl.
+         */
         cur = handle->zone_dh_cur;
         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
                 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
                         continue;
-                if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP,
-                    tabptr->zone_physmem_cap,
-                    sizeof (tabptr->zone_physmem_cap))) != Z_OK) {
-                        handle->zone_dh_cur = handle->zone_dh_top;
-                        return (err);
-                }
 
-                return (Z_OK);
+                if (fetchprop(cur, DTD_ATTR_PHYSCAP,
+                    zone_physmem_cap, sizeof (zone_physmem_cap)) == Z_OK) {
+                        res = 1;
+                        add_physmem_rctl = 1;
         }
 
-        return (Z_NO_ENTRY);
-}
-
-static int
-getmcapent_core(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
-{
-        xmlNodePtr cur;
-        int err;
-
-        if (handle == NULL)
-                return (Z_INVAL);
-
-        if ((cur = handle->zone_dh_cur) == NULL)
-                return (Z_NO_ENTRY);
-
-        for (; cur != NULL; cur = cur->next)
-                if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) == 0)
+                xmlUnlinkNode(cur);
+                xmlFreeNode(cur);
                         break;
-        if (cur == NULL) {
-                handle->zone_dh_cur = handle->zone_dh_top;
-                return (Z_NO_ENTRY);
         }
 
-        if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap,
-            sizeof (tabptr->zone_physmem_cap))) != Z_OK) {
-                handle->zone_dh_cur = handle->zone_dh_top;
-                return (err);
+        if (add_physmem_rctl) {
+                uint64_t cap;
+                char *endp;
+
+                cap = strtoull(zone_physmem_cap, &endp, 10);
+                (void) zonecfg_set_aliased_rctl(handle, ALIAS_MAXPHYSMEM, cap);
         }
 
-        handle->zone_dh_cur = cur->next;
-        return (Z_OK);
+        return (res);
 }
 
-int
-zonecfg_getmcapent(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
-{
-        int err;
-
-        if ((err = zonecfg_setent(handle)) != Z_OK)
-                return (err);
-
-        err = getmcapent_core(handle, tabptr);
-
-        (void) zonecfg_endent(handle);
-
-        return (err);
-}
-
 /*
  * Get the full tree of pkg metadata in a set of nested AVL trees.
  * pkgs_avl is an AVL tree of pkgs.
  *
  * The zone xml data contains DTD_ELEM_PACKAGE elements.
@@ -7629,11 +7970,11 @@
                 zerror(zonename, gettext("could not stat file %s: %s"),
                     USERATTR_FILENAME, strerror(errno));
                 (void) fclose(uaf);
                 return (Z_MISC_FS);
         }
-        if (!config_file_path(zonename, config_file)) {
+        if (!config_file_path(zonename, config_file, sizeof (config_file))) {
                 (void) fclose(uaf);
                 return (Z_MISC_FS);
         }
 
         if ((err = stat(config_file, &config_st)) != 0) {