Print this page
Reduce lint
dlmgmt mismerge
OS-3839 dlmgmtd clobbers its cachefile with excessive use of /native (fix lx)
OS-3839 dlmgmtd clobbers its cachefile with excessive use of /native
OS-3342 dlmgmtd needs to be mindful of lock ordering
OS-2608 dlmgmtd needs to record zone identifiers
OS-3492 zone_free asserts to its destruction when dlmgmtd has fallen
OS-3494 zoneadmd tears down networking too soon when boot fails
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
OS-3007 dlmgmtd needs to work with non-native zones


   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.

  24  */
  25 
  26 #include <assert.h>
  27 #include <ctype.h>
  28 #include <errno.h>
  29 #include <fcntl.h>
  30 #include <stdio.h>
  31 #include <stdlib.h>
  32 #include <string.h>
  33 #include <strings.h>
  34 #include <syslog.h>
  35 #include <zone.h>
  36 #include <sys/types.h>
  37 #include <sys/stat.h>
  38 #include <stropts.h>
  39 #include <sys/conf.h>
  40 #include <pthread.h>
  41 #include <unistd.h>
  42 #include <wait.h>
  43 #include <libcontract.h>
  44 #include <libcontract_priv.h>
  45 #include <sys/contract/process.h>


  46 #include "dlmgmt_impl.h"
  47 
  48 typedef enum dlmgmt_db_op {
  49         DLMGMT_DB_OP_WRITE,
  50         DLMGMT_DB_OP_DELETE,
  51         DLMGMT_DB_OP_READ
  52 } dlmgmt_db_op_t;
  53 
  54 typedef struct dlmgmt_db_req_s {
  55         struct dlmgmt_db_req_s  *ls_next;
  56         dlmgmt_db_op_t          ls_op;
  57         char                    ls_link[MAXLINKNAMELEN];
  58         datalink_id_t           ls_linkid;
  59         zoneid_t                ls_zoneid;
  60         uint32_t                ls_flags;       /* Either DLMGMT_ACTIVE or   */
  61                                                 /* DLMGMT_PERSIST, not both. */
  62 } dlmgmt_db_req_t;
  63 
  64 /*
  65  * List of pending db updates (e.g., because of a read-only filesystem).


 697                         assert(dlmgmt_db_req_head == NULL);
 698                         dlmgmt_db_req_tail = NULL;
 699                 }
 700                 free(req);
 701         }
 702 
 703         dlmgmt_table_unlock();
 704         return (NULL);
 705 }
 706 
 707 static int
 708 parse_linkprops(char *buf, dlmgmt_link_t *linkp)
 709 {
 710         boolean_t               found_type = B_FALSE;
 711         dladm_datatype_t        type = DLADM_TYPE_STR;
 712         int                     i, len;
 713         char                    *curr;
 714         char                    attr_name[MAXLINKATTRLEN];
 715         size_t                  attr_buf_len = 0;
 716         void                    *attr_buf = NULL;

 717 
 718         curr = buf;
 719         len = strlen(buf);
 720         attr_name[0] = '\0';
 721         for (i = 0; i < len; i++) {
 722                 char            c = buf[i];
 723                 boolean_t       match = (c == '=' ||
 724                     (c == ',' && !found_type) || c == ';');
 725 

 726                 /*
 727                  * Move to the next character if there is no match and
 728                  * if we have not reached the last character.
 729                  */
 730                 if (!match && i != len - 1)
 731                         continue;
 732 
 733                 if (match) {
 734                         /*
 735                          * NUL-terminate the string pointed to by 'curr'.
 736                          */
 737                         buf[i] = '\0';
 738                         if (*curr == '\0')
 739                                 goto parse_fail;
 740                 }
 741 
 742                 if (attr_name[0] != '\0' && found_type) {
 743                         /*
 744                          * We get here after we have processed the "<prop>="
 745                          * pattern. The pattern we are now interested in is


 751                         if (strcmp(attr_name, "linkid") == 0) {
 752                                 if (read_int64(curr, &attr_buf) == 0)
 753                                         goto parse_fail;
 754                                 linkp->ll_linkid =
 755                                     (datalink_class_t)*(int64_t *)attr_buf;
 756                         } else if (strcmp(attr_name, "name") == 0) {
 757                                 if (read_str(curr, &attr_buf) == 0)
 758                                         goto parse_fail;
 759                                 (void) snprintf(linkp->ll_link,
 760                                     MAXLINKNAMELEN, "%s", attr_buf);
 761                         } else if (strcmp(attr_name, "class") == 0) {
 762                                 if (read_int64(curr, &attr_buf) == 0)
 763                                         goto parse_fail;
 764                                 linkp->ll_class =
 765                                     (datalink_class_t)*(int64_t *)attr_buf;
 766                         } else if (strcmp(attr_name, "media") == 0) {
 767                                 if (read_int64(curr, &attr_buf) == 0)
 768                                         goto parse_fail;
 769                                 linkp->ll_media =
 770                                     (uint32_t)*(int64_t *)attr_buf;















 771                         } else {
 772                                 attr_buf_len = translators[type].read_func(curr,
 773                                     &attr_buf);
 774                                 if (attr_buf_len == 0)
 775                                         goto parse_fail;
 776 
 777                                 if (linkattr_set(&(linkp->ll_head), attr_name,
 778                                     attr_buf, attr_buf_len, type) != 0) {
 779                                         free(attr_buf);
 780                                         goto parse_fail;
 781                                 }
 782                         }
 783 
 784                         free(attr_buf);
 785                         attr_name[0] = '\0';
 786                         found_type = B_FALSE;
 787                 } else if (attr_name[0] != '\0') {
 788                         /*
 789                          * Non-zero length attr_name and found_type of false
 790                          * indicates that we have not found the type for this


 794                         for (type = 0; type < ntranslators; type++) {
 795                                 if (strcmp(curr,
 796                                     translators[type].type_name) == 0) {
 797                                         found_type = B_TRUE;
 798                                         break;
 799                                 }
 800                         }
 801 
 802                         if (!found_type)
 803                                 goto parse_fail;
 804                 } else {
 805                         /*
 806                          * A zero length attr_name indicates we are looking
 807                          * at the beginning of a link attribute.
 808                          */
 809                         if (c != '=')
 810                                 goto parse_fail;
 811 
 812                         (void) snprintf(attr_name, MAXLINKATTRLEN, "%s", curr);
 813                 }










 814                 curr = buf + i + 1;
 815         }
 816 
 817         /* Correct any erroneous IPTUN datalink class constant in the file */
 818         if (linkp->ll_class == 0x60) {
 819                 linkp->ll_class = DATALINK_CLASS_IPTUN;
 820                 rewrite_needed = B_TRUE;
 821         }
 822 
 823         return (0);
 824 
 825 parse_fail:
 826         /*
 827          * Free linkp->ll_head (link attribute list)
 828          */
 829         linkattr_destroy(linkp);
 830         return (-1);
 831 }
 832 
 833 static boolean_t


1205 
1206         return (err);
1207 }
1208 
1209 /*
1210  * Generate an entry in the link database.
1211  * Each entry has this format:
1212  * <link name>    <prop0>=<type>,<val>;...;<propn>=<type>,<val>;
1213  */
1214 static void
1215 generate_link_line(dlmgmt_link_t *linkp, boolean_t persist, char *buf)
1216 {
1217         char                    tmpbuf[MAXLINELEN];
1218         char                    *ptr = tmpbuf;
1219         char                    *lim = tmpbuf + MAXLINELEN;
1220         dlmgmt_linkattr_t       *cur_p = NULL;
1221         uint64_t                u64;
1222 
1223         ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s\t", linkp->ll_link);
1224         if (!persist) {

1225                 /*
1226                  * We store the linkid in the active database so that dlmgmtd
1227                  * can recover in the event that it is restarted.

1228                  */
1229                 u64 = linkp->ll_linkid;
1230                 ptr += write_uint64(ptr, BUFLEN(lim, ptr), "linkid", &u64);




1231         }

1232         u64 = linkp->ll_class;
1233         ptr += write_uint64(ptr, BUFLEN(lim, ptr), "class", &u64);
1234         u64 = linkp->ll_media;
1235         ptr += write_uint64(ptr, BUFLEN(lim, ptr), "media", &u64);
1236 
1237         /*
1238          * The daemon does not keep any active link attribute. Only store the
1239          * attributes if this request is for persistent configuration,
1240          */
1241         if (persist) {
1242                 for (cur_p = linkp->ll_head; cur_p != NULL;
1243                     cur_p = cur_p->lp_next) {
1244                         ptr += translators[cur_p->lp_type].write_func(ptr,
1245                             BUFLEN(lim, ptr), cur_p->lp_name, cur_p->lp_val);
1246                 }
1247         }
1248 
1249         if (ptr <= lim)
1250                 (void) snprintf(buf, MAXLINELEN, "%s\n", tmpbuf);
1251 }


1365 static void
1366 dlmgmt_db_phys_activate(dlmgmt_link_t *linkp)
1367 {
1368         linkp->ll_flags |= DLMGMT_ACTIVE;
1369         (void) dlmgmt_write_db_entry(linkp->ll_link, linkp, DLMGMT_ACTIVE);
1370 }
1371 
1372 static void
1373 dlmgmt_db_walk(zoneid_t zoneid, datalink_class_t class, db_walk_func_t *func)
1374 {
1375         dlmgmt_link_t *linkp;
1376 
1377         for (linkp = avl_first(&dlmgmt_id_avl); linkp != NULL;
1378             linkp = AVL_NEXT(&dlmgmt_id_avl, linkp)) {
1379                 if (linkp->ll_zoneid == zoneid && (linkp->ll_class & class))
1380                         func(linkp);
1381         }
1382 }
1383 
1384 /*




































1385  * Initialize the datalink <link name, linkid> mapping and the link's
1386  * attributes list based on the configuration file /etc/dladm/datalink.conf
1387  * and the active configuration cache file
1388  * /etc/svc/volatile/dladm/datalink-management:default.cache.
1389  */
1390 int
1391 dlmgmt_db_init(zoneid_t zoneid)
1392 {
1393         dlmgmt_db_req_t *req;
1394         int             err;
1395         boolean_t       boot = B_FALSE;


1396 
1397         if ((req = dlmgmt_db_req_alloc(DLMGMT_DB_OP_READ, NULL,
1398             DATALINK_INVALID_LINKID, zoneid, DLMGMT_ACTIVE, &err)) == NULL)
1399                 return (err);
1400 







1401         if ((err = dlmgmt_process_db_req(req)) != 0) {
1402                 /*
1403                  * If we get back ENOENT, that means that the active
1404                  * configuration file doesn't exist yet, and is not an error.
1405                  * We'll create it down below after we've loaded the
1406                  * persistent configuration.
1407                  */
1408                 if (err != ENOENT)
1409                         goto done;
1410                 boot = B_TRUE;
1411         }



1412 
1413         req->ls_flags = DLMGMT_PERSIST;
1414         err = dlmgmt_process_db_req(req);
1415         if (err != 0 && err != ENOENT)
1416                 goto done;
1417         err = 0;
1418         if (rewrite_needed) {
1419                 /*
1420                  * First update links in memory, then dump the entire db to
1421                  * disk.
1422                  */
1423                 dlmgmt_db_walk(zoneid, DATALINK_CLASS_ALL, dlmgmt_db_upgrade);
1424                 req->ls_op = DLMGMT_DB_OP_WRITE;
1425                 req->ls_linkid = DATALINK_ALL_LINKID;
1426                 if ((err = dlmgmt_process_db_req(req)) != 0 &&
1427                     err != EINPROGRESS)
1428                         goto done;
1429         }
1430         if (boot) {
1431                 dlmgmt_db_walk(zoneid, DATALINK_CLASS_PHYS,
1432                     dlmgmt_db_phys_activate);
1433         }
1434 
1435 done:
1436         if (err == EINPROGRESS)
1437                 err = 0;
1438         else
1439                 free(req);
1440         return (err);
1441 }
1442 
1443 /*
1444  * Remove all links in the given zoneid.





1445  */
1446 void
1447 dlmgmt_db_fini(zoneid_t zoneid)
1448 {
1449         dlmgmt_link_t *linkp = avl_first(&dlmgmt_name_avl), *next_linkp;
1450 
1451         while (linkp != NULL) {
1452                 next_linkp = AVL_NEXT(&dlmgmt_name_avl, linkp);
1453                 if (linkp->ll_zoneid == zoneid) {












1454                         (void) dlmgmt_destroy_common(linkp,
1455                             DLMGMT_ACTIVE | DLMGMT_PERSIST);
1456                 }

1457                 linkp = next_linkp;
1458         }











































1459 }


   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2015, Joyent Inc.
  25  */
  26 
  27 #include <assert.h>
  28 #include <ctype.h>
  29 #include <errno.h>
  30 #include <fcntl.h>
  31 #include <stdio.h>
  32 #include <stdlib.h>
  33 #include <string.h>
  34 #include <strings.h>
  35 #include <syslog.h>
  36 #include <zone.h>
  37 #include <sys/types.h>
  38 #include <sys/stat.h>
  39 #include <stropts.h>
  40 #include <sys/conf.h>
  41 #include <pthread.h>
  42 #include <unistd.h>
  43 #include <wait.h>
  44 #include <libcontract.h>
  45 #include <libcontract_priv.h>
  46 #include <sys/contract/process.h>
  47 #include <sys/vnic.h>
  48 #include <zone.h>
  49 #include "dlmgmt_impl.h"
  50 
  51 typedef enum dlmgmt_db_op {
  52         DLMGMT_DB_OP_WRITE,
  53         DLMGMT_DB_OP_DELETE,
  54         DLMGMT_DB_OP_READ
  55 } dlmgmt_db_op_t;
  56 
  57 typedef struct dlmgmt_db_req_s {
  58         struct dlmgmt_db_req_s  *ls_next;
  59         dlmgmt_db_op_t          ls_op;
  60         char                    ls_link[MAXLINKNAMELEN];
  61         datalink_id_t           ls_linkid;
  62         zoneid_t                ls_zoneid;
  63         uint32_t                ls_flags;       /* Either DLMGMT_ACTIVE or   */
  64                                                 /* DLMGMT_PERSIST, not both. */
  65 } dlmgmt_db_req_t;
  66 
  67 /*
  68  * List of pending db updates (e.g., because of a read-only filesystem).


 700                         assert(dlmgmt_db_req_head == NULL);
 701                         dlmgmt_db_req_tail = NULL;
 702                 }
 703                 free(req);
 704         }
 705 
 706         dlmgmt_table_unlock();
 707         return (NULL);
 708 }
 709 
 710 static int
 711 parse_linkprops(char *buf, dlmgmt_link_t *linkp)
 712 {
 713         boolean_t               found_type = B_FALSE;
 714         dladm_datatype_t        type = DLADM_TYPE_STR;
 715         int                     i, len;
 716         char                    *curr;
 717         char                    attr_name[MAXLINKATTRLEN];
 718         size_t                  attr_buf_len = 0;
 719         void                    *attr_buf = NULL;
 720         boolean_t               rename;
 721 
 722         curr = buf;
 723         len = strlen(buf);
 724         attr_name[0] = '\0';
 725         for (i = 0; i < len; i++) {
 726                 char            c = buf[i];
 727                 boolean_t       match = (c == '=' ||
 728                     (c == ',' && !found_type) || c == ';');
 729 
 730                 rename = B_FALSE;
 731                 /*
 732                  * Move to the next character if there is no match and
 733                  * if we have not reached the last character.
 734                  */
 735                 if (!match && i != len - 1)
 736                         continue;
 737 
 738                 if (match) {
 739                         /*
 740                          * NUL-terminate the string pointed to by 'curr'.
 741                          */
 742                         buf[i] = '\0';
 743                         if (*curr == '\0')
 744                                 goto parse_fail;
 745                 }
 746 
 747                 if (attr_name[0] != '\0' && found_type) {
 748                         /*
 749                          * We get here after we have processed the "<prop>="
 750                          * pattern. The pattern we are now interested in is


 756                         if (strcmp(attr_name, "linkid") == 0) {
 757                                 if (read_int64(curr, &attr_buf) == 0)
 758                                         goto parse_fail;
 759                                 linkp->ll_linkid =
 760                                     (datalink_class_t)*(int64_t *)attr_buf;
 761                         } else if (strcmp(attr_name, "name") == 0) {
 762                                 if (read_str(curr, &attr_buf) == 0)
 763                                         goto parse_fail;
 764                                 (void) snprintf(linkp->ll_link,
 765                                     MAXLINKNAMELEN, "%s", attr_buf);
 766                         } else if (strcmp(attr_name, "class") == 0) {
 767                                 if (read_int64(curr, &attr_buf) == 0)
 768                                         goto parse_fail;
 769                                 linkp->ll_class =
 770                                     (datalink_class_t)*(int64_t *)attr_buf;
 771                         } else if (strcmp(attr_name, "media") == 0) {
 772                                 if (read_int64(curr, &attr_buf) == 0)
 773                                         goto parse_fail;
 774                                 linkp->ll_media =
 775                                     (uint32_t)*(int64_t *)attr_buf;
 776                         } else if (strcmp(attr_name, "zone") == 0) {
 777                                 if (read_str(curr, &attr_buf) == 0)
 778                                         goto parse_fail;
 779                                 linkp->ll_zoneid = getzoneidbyname(attr_buf);
 780                                 if (linkp->ll_zoneid == -1) {
 781                                         if (errno == EFAULT)
 782                                                 abort();
 783                                         /*
 784                                          * If we can't find the zone, assign the
 785                                          * link to the GZ and mark it for being
 786                                          * renamed.
 787                                          */
 788                                         linkp->ll_zoneid = 0;
 789                                         rename = B_TRUE;
 790                                 }
 791                         } else {
 792                                 attr_buf_len = translators[type].read_func(curr,
 793                                     &attr_buf);
 794                                 if (attr_buf_len == 0)
 795                                         goto parse_fail;
 796 
 797                                 if (linkattr_set(&(linkp->ll_head), attr_name,
 798                                     attr_buf, attr_buf_len, type) != 0) {
 799                                         free(attr_buf);
 800                                         goto parse_fail;
 801                                 }
 802                         }
 803 
 804                         free(attr_buf);
 805                         attr_name[0] = '\0';
 806                         found_type = B_FALSE;
 807                 } else if (attr_name[0] != '\0') {
 808                         /*
 809                          * Non-zero length attr_name and found_type of false
 810                          * indicates that we have not found the type for this


 814                         for (type = 0; type < ntranslators; type++) {
 815                                 if (strcmp(curr,
 816                                     translators[type].type_name) == 0) {
 817                                         found_type = B_TRUE;
 818                                         break;
 819                                 }
 820                         }
 821 
 822                         if (!found_type)
 823                                 goto parse_fail;
 824                 } else {
 825                         /*
 826                          * A zero length attr_name indicates we are looking
 827                          * at the beginning of a link attribute.
 828                          */
 829                         if (c != '=')
 830                                 goto parse_fail;
 831 
 832                         (void) snprintf(attr_name, MAXLINKATTRLEN, "%s", curr);
 833                 }
 834 
 835                 /*
 836                  * The zone that this link belongs to has died, we are
 837                  * reparenting it to the GZ and renaming it to avoid name
 838                  * collisions.
 839                  */
 840                 if (rename == B_TRUE) {
 841                         (void) snprintf(linkp->ll_link, MAXLINKNAMELEN,
 842                             "SUNWorphan%u", (uint16_t)(gethrtime() / 1000));
 843                 }
 844                 curr = buf + i + 1;
 845         }
 846 
 847         /* Correct any erroneous IPTUN datalink class constant in the file */
 848         if (linkp->ll_class == 0x60) {
 849                 linkp->ll_class = DATALINK_CLASS_IPTUN;
 850                 rewrite_needed = B_TRUE;
 851         }
 852 
 853         return (0);
 854 
 855 parse_fail:
 856         /*
 857          * Free linkp->ll_head (link attribute list)
 858          */
 859         linkattr_destroy(linkp);
 860         return (-1);
 861 }
 862 
 863 static boolean_t


1235 
1236         return (err);
1237 }
1238 
1239 /*
1240  * Generate an entry in the link database.
1241  * Each entry has this format:
1242  * <link name>    <prop0>=<type>,<val>;...;<propn>=<type>,<val>;
1243  */
1244 static void
1245 generate_link_line(dlmgmt_link_t *linkp, boolean_t persist, char *buf)
1246 {
1247         char                    tmpbuf[MAXLINELEN];
1248         char                    *ptr = tmpbuf;
1249         char                    *lim = tmpbuf + MAXLINELEN;
1250         dlmgmt_linkattr_t       *cur_p = NULL;
1251         uint64_t                u64;
1252 
1253         ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s\t", linkp->ll_link);
1254         if (!persist) {
1255                 char zname[ZONENAME_MAX];
1256                 /*
1257                  * We store the linkid and the zone name in the active database
1258                  * so that dlmgmtd can recover in the event that it is
1259                  * restarted.
1260                  */
1261                 u64 = linkp->ll_linkid;
1262                 ptr += write_uint64(ptr, BUFLEN(lim, ptr), "linkid", &u64);
1263 
1264                 if (getzonenamebyid(linkp->ll_zoneid, zname,
1265                     sizeof (zname)) != -1) {
1266                         ptr += write_str(ptr, BUFLEN(lim, ptr), "zone", zname);
1267                 }
1268         }
1269         u64 = linkp->ll_class;
1270         ptr += write_uint64(ptr, BUFLEN(lim, ptr), "class", &u64);
1271         u64 = linkp->ll_media;
1272         ptr += write_uint64(ptr, BUFLEN(lim, ptr), "media", &u64);
1273 
1274         /*
1275          * The daemon does not keep any active link attribute. Only store the
1276          * attributes if this request is for persistent configuration,
1277          */
1278         if (persist) {
1279                 for (cur_p = linkp->ll_head; cur_p != NULL;
1280                     cur_p = cur_p->lp_next) {
1281                         ptr += translators[cur_p->lp_type].write_func(ptr,
1282                             BUFLEN(lim, ptr), cur_p->lp_name, cur_p->lp_val);
1283                 }
1284         }
1285 
1286         if (ptr <= lim)
1287                 (void) snprintf(buf, MAXLINELEN, "%s\n", tmpbuf);
1288 }


1402 static void
1403 dlmgmt_db_phys_activate(dlmgmt_link_t *linkp)
1404 {
1405         linkp->ll_flags |= DLMGMT_ACTIVE;
1406         (void) dlmgmt_write_db_entry(linkp->ll_link, linkp, DLMGMT_ACTIVE);
1407 }
1408 
1409 static void
1410 dlmgmt_db_walk(zoneid_t zoneid, datalink_class_t class, db_walk_func_t *func)
1411 {
1412         dlmgmt_link_t *linkp;
1413 
1414         for (linkp = avl_first(&dlmgmt_id_avl); linkp != NULL;
1415             linkp = AVL_NEXT(&dlmgmt_id_avl, linkp)) {
1416                 if (linkp->ll_zoneid == zoneid && (linkp->ll_class & class))
1417                         func(linkp);
1418         }
1419 }
1420 
1421 /*
1422  * Attempt to mitigate one of the deadlocks in the dlmgmtd architecture.
1423  *
1424  * dlmgmt_db_init() calls dlmgmt_process_db_req() which eventually gets to
1425  * dlmgmt_zfop() which tries to fork, enter the zone and read the file.
1426  * Because of the upcall architecture of dlmgmtd this can lead to deadlock
1427  * with the following scenario:
1428  *    a) the thread preparing to fork will have acquired the malloc locks
1429  *       then attempt to suspend every thread in preparation to fork.
1430  *    b) all of the upcalls will be blocked in door_ucred() trying to malloc()
1431  *       and get the credentials of their caller.
1432  *    c) we can't suspend the in-kernel thread making the upcall.
1433  *
1434  * Thus, we cannot serve door requests because we're blocked in malloc()
1435  * which fork() owns, but fork() is in turn blocked on the in-kernel thread
1436  * making the door upcall.  This is a fundamental architectural problem with
1437  * any server handling upcalls and also trying to fork().
1438  *
1439  * To minimize the chance of this deadlock occuring, we check ahead of time to
1440  * see if the file we want to read actually exists in the zone (which it almost
1441  * never does), so we don't need fork in that case (i.e. rarely to never).
1442  */
1443 static boolean_t
1444 zone_file_exists(char *zoneroot, char *filename)
1445 {
1446         struct stat     sb;
1447         char            fname[MAXPATHLEN];
1448 
1449         (void) snprintf(fname, sizeof (fname), "%s/%s", zoneroot, filename);
1450 
1451         if (stat(fname, &sb) == -1)
1452                 return (B_FALSE);
1453 
1454         return (B_TRUE);
1455 }
1456 
1457 /*
1458  * Initialize the datalink <link name, linkid> mapping and the link's
1459  * attributes list based on the configuration file /etc/dladm/datalink.conf
1460  * and the active configuration cache file
1461  * /etc/svc/volatile/dladm/datalink-management:default.cache.
1462  */
1463 int
1464 dlmgmt_db_init(zoneid_t zoneid, char *zoneroot)
1465 {
1466         dlmgmt_db_req_t *req;
1467         int             err;
1468         boolean_t       boot = B_FALSE;
1469         char            tdir[MAXPATHLEN];
1470         char            *path = cachefile;
1471 
1472         if ((req = dlmgmt_db_req_alloc(DLMGMT_DB_OP_READ, NULL,
1473             DATALINK_INVALID_LINKID, zoneid, DLMGMT_ACTIVE, &err)) == NULL)
1474                 return (err);
1475 
1476         /* Handle running in a non-native branded zone (i.e. has /native) */
1477         if (zone_file_exists(zoneroot, "/native" DLMGMT_TMPFS_DIR)) {
1478                 (void) snprintf(tdir, sizeof (tdir), "/native%s", cachefile);
1479                 path = tdir;
1480         }
1481 
1482         if (zone_file_exists(zoneroot, path)) {
1483                 if ((err = dlmgmt_process_db_req(req)) != 0) {
1484                         /*
1485                          * If we get back ENOENT, that means that the active
1486                          * configuration file doesn't exist yet, and is not an
1487                          * error.  We'll create it down below after we've
1488                          * loaded the persistent configuration.
1489                          */
1490                         if (err != ENOENT)
1491                                 goto done;
1492                         boot = B_TRUE;
1493                 }
1494         } else {
1495                 boot = B_TRUE;
1496         }
1497 
1498         req->ls_flags = DLMGMT_PERSIST;
1499         err = dlmgmt_process_db_req(req);
1500         if (err != 0 && err != ENOENT)
1501                 goto done;
1502         err = 0;
1503         if (rewrite_needed) {
1504                 /*
1505                  * First update links in memory, then dump the entire db to
1506                  * disk.
1507                  */
1508                 dlmgmt_db_walk(zoneid, DATALINK_CLASS_ALL, dlmgmt_db_upgrade);
1509                 req->ls_op = DLMGMT_DB_OP_WRITE;
1510                 req->ls_linkid = DATALINK_ALL_LINKID;
1511                 if ((err = dlmgmt_process_db_req(req)) != 0 &&
1512                     err != EINPROGRESS)
1513                         goto done;
1514         }
1515         if (boot) {
1516                 dlmgmt_db_walk(zoneid, DATALINK_CLASS_PHYS,
1517                     dlmgmt_db_phys_activate);
1518         }
1519 
1520 done:
1521         if (err == EINPROGRESS)
1522                 err = 0;
1523         else
1524                 free(req);
1525         return (err);
1526 }
1527 
1528 /*
1529  * Remove all links in the given zoneid.
1530  *
1531  * We do this work in two different passes. In the first pass, we remove any
1532  * entry that hasn't been loaned and mark every entry that has been loaned as
1533  * something that is going to be tombstomed. In the second pass, we drop the
1534  * table lock for every entry and remove the tombstombed entry for our zone.
1535  */
1536 void
1537 dlmgmt_db_fini(zoneid_t zoneid)
1538 {
1539         dlmgmt_link_t *linkp = avl_first(&dlmgmt_name_avl), *next_linkp;
1540 
1541         while (linkp != NULL) {
1542                 next_linkp = AVL_NEXT(&dlmgmt_name_avl, linkp);
1543                 if (linkp->ll_zoneid == zoneid) {
1544                         boolean_t onloan = linkp->ll_onloan;
1545 
1546                         /*
1547                          * Cleanup any VNICs that were loaned to the zone
1548                          * before the zone goes away and we can no longer
1549                          * refer to the VNIC by the name/zoneid.
1550                          */
1551                         if (onloan) {
1552                                 (void) dlmgmt_delete_db_entry(linkp,
1553                                     DLMGMT_ACTIVE);
1554                                 linkp->ll_tomb = B_TRUE;
1555                         } else {
1556                                 (void) dlmgmt_destroy_common(linkp,
1557                                     DLMGMT_ACTIVE | DLMGMT_PERSIST);
1558                         }
1559                 }
1560                 linkp = next_linkp;
1561         }
1562 
1563 again:
1564         linkp = avl_first(&dlmgmt_name_avl);
1565         while (linkp != NULL) {
1566                 vnic_ioc_delete_t ioc;
1567 
1568                 next_linkp = AVL_NEXT(&dlmgmt_name_avl, linkp);
1569 
1570                 if (linkp->ll_zoneid != zoneid) {
1571                         linkp = next_linkp;
1572                         continue;
1573                 }
1574                 ioc.vd_vnic_id = linkp->ll_linkid;
1575                 if (linkp->ll_tomb != B_TRUE)
1576                         abort();
1577 
1578                 /*
1579                  * We have to drop the table lock while going up into the
1580                  * kernel. If we hold the table lock while deleting a vnic, we
1581                  * may get blocked on the mac perimeter and the holder of it may
1582                  * want something from dlmgmtd.
1583                  */
1584                 dlmgmt_table_unlock();
1585 
1586                 if (ioctl(dladm_dld_fd(dld_handle),
1587                     VNIC_IOC_DELETE, &ioc) < 0)
1588                         dlmgmt_log(LOG_WARNING, "dlmgmt_db_fini "
1589                             "delete VNIC ioctl failed %d %d",
1590                             ioc.vd_vnic_id, errno);
1591 
1592                 /*
1593                  * Even though we've dropped the lock, we know that nothing else
1594                  * could have removed us. Therefore, it should be safe to go
1595                  * through and delete ourselves, but do nothing else. We'll have
1596                  * to restart iteration from the beginning. This can be painful.
1597                  */
1598                 dlmgmt_table_lock(B_TRUE);
1599 
1600                 (void) dlmgmt_destroy_common(linkp,
1601                     DLMGMT_ACTIVE | DLMGMT_PERSIST);
1602                 goto again;
1603         }
1604 
1605 }