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

@@ -80,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"

@@ -106,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"

@@ -131,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"
 

@@ -2088,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)

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

@@ -2143,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)))

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

@@ -2195,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,

@@ -2217,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)

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

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

@@ -2310,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)

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

@@ -2504,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)

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

@@ -4752,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

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

@@ -4801,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

@@ -5528,10 +5787,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.
  */