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).
 
 535         return (req);
 536 }
 537 
 538 /*
 539  * Update the db entry with name "entryname" using information from "linkp".
 540  */
 541 static int
 542 dlmgmt_db_update(dlmgmt_db_op_t op, const char *entryname, dlmgmt_link_t *linkp,
 543     uint32_t flags)
 544 {
 545         dlmgmt_db_req_t *req;
 546         int             err;
 547 
 548         /* It is either a persistent request or an active request, not both. */
 549         assert((flags == DLMGMT_PERSIST) || (flags == DLMGMT_ACTIVE));
 550 
 551         if ((req = dlmgmt_db_req_alloc(op, entryname, linkp->ll_linkid,
 552             linkp->ll_zoneid, flags, &err)) == NULL)
 553                 return (err);
 554 
 555         /*
 556          * If the return error is EINPROGRESS, this request is handled
 557          * asynchronously; return success.
 558          */
 559         err = dlmgmt_process_db_req(req);
 560         if (err != EINPROGRESS)
 561                 free(req);
 562         else
 563                 err = 0;
 564         return (err);
 565 }
 566 
 567 #define DLMGMT_DB_OP_STR(op)                                    \
 568         (((op) == DLMGMT_DB_OP_READ) ? "read" :                 \
 569         (((op) == DLMGMT_DB_OP_WRITE) ? "write" : "delete"))
 570 
 571 #define DLMGMT_DB_CONF_STR(flag)                                \
 572         (((flag) == DLMGMT_ACTIVE) ? "active" :                 \
 573         (((flag) == DLMGMT_PERSIST) ? "persistent" : ""))
 574 
 
 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 2014, Joyent Inc. All rights reserved.
  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).
 
 538         return (req);
 539 }
 540 
 541 /*
 542  * Update the db entry with name "entryname" using information from "linkp".
 543  */
 544 static int
 545 dlmgmt_db_update(dlmgmt_db_op_t op, const char *entryname, dlmgmt_link_t *linkp,
 546     uint32_t flags)
 547 {
 548         dlmgmt_db_req_t *req;
 549         int             err;
 550 
 551         /* It is either a persistent request or an active request, not both. */
 552         assert((flags == DLMGMT_PERSIST) || (flags == DLMGMT_ACTIVE));
 553 
 554         if ((req = dlmgmt_db_req_alloc(op, entryname, linkp->ll_linkid,
 555             linkp->ll_zoneid, flags, &err)) == NULL)
 556                 return (err);
 557 
 558         /* If transient op and onloan, use the global zone cache file. */
 559         if (flags == DLMGMT_ACTIVE && linkp->ll_onloan)
 560                 req->ls_zoneid = GLOBAL_ZONEID;
 561 
 562         /*
 563          * If the return error is EINPROGRESS, this request is handled
 564          * asynchronously; return success.
 565          */
 566         err = dlmgmt_process_db_req(req);
 567         if (err != EINPROGRESS)
 568                 free(req);
 569         else
 570                 err = 0;
 571         return (err);
 572 }
 573 
 574 #define DLMGMT_DB_OP_STR(op)                                    \
 575         (((op) == DLMGMT_DB_OP_READ) ? "read" :                 \
 576         (((op) == DLMGMT_DB_OP_WRITE) ? "write" : "delete"))
 577 
 578 #define DLMGMT_DB_CONF_STR(flag)                                \
 579         (((flag) == DLMGMT_ACTIVE) ? "active" :                 \
 580         (((flag) == DLMGMT_PERSIST) ? "persistent" : ""))
 581 
 
 704                         assert(dlmgmt_db_req_head == NULL);
 705                         dlmgmt_db_req_tail = NULL;
 706                 }
 707                 free(req);
 708         }
 709 
 710         dlmgmt_table_unlock();
 711         return (NULL);
 712 }
 713 
 714 static int
 715 parse_linkprops(char *buf, dlmgmt_link_t *linkp)
 716 {
 717         boolean_t               found_type = B_FALSE;
 718         dladm_datatype_t        type = DLADM_TYPE_STR;
 719         int                     i, len;
 720         char                    *curr;
 721         char                    attr_name[MAXLINKATTRLEN];
 722         size_t                  attr_buf_len = 0;
 723         void                    *attr_buf = NULL;
 724         boolean_t               rename;
 725 
 726         curr = buf;
 727         len = strlen(buf);
 728         attr_name[0] = '\0';
 729         for (i = 0; i < len; i++) {
 730                 char            c = buf[i];
 731                 boolean_t       match = (c == '=' ||
 732                     (c == ',' && !found_type) || c == ';');
 733 
 734                 rename = B_FALSE;
 735 
 736                 /*
 737                  * Move to the next character if there is no match and
 738                  * if we have not reached the last character.
 739                  */
 740                 if (!match && i != len - 1)
 741                         continue;
 742 
 743                 if (match) {
 744                         /*
 745                          * NUL-terminate the string pointed to by 'curr'.
 746                          */
 747                         buf[i] = '\0';
 748                         if (*curr == '\0')
 749                                 goto parse_fail;
 750                 }
 751 
 752                 if (attr_name[0] != '\0' && found_type) {
 753                         /*
 754                          * We get here after we have processed the "<prop>="
 755                          * pattern. The pattern we are now interested in is
 
 761                         if (strcmp(attr_name, "linkid") == 0) {
 762                                 if (read_int64(curr, &attr_buf) == 0)
 763                                         goto parse_fail;
 764                                 linkp->ll_linkid =
 765                                     (datalink_class_t)*(int64_t *)attr_buf;
 766                         } else if (strcmp(attr_name, "name") == 0) {
 767                                 if (read_str(curr, &attr_buf) == 0)
 768                                         goto parse_fail;
 769                                 (void) snprintf(linkp->ll_link,
 770                                     MAXLINKNAMELEN, "%s", attr_buf);
 771                         } else if (strcmp(attr_name, "class") == 0) {
 772                                 if (read_int64(curr, &attr_buf) == 0)
 773                                         goto parse_fail;
 774                                 linkp->ll_class =
 775                                     (datalink_class_t)*(int64_t *)attr_buf;
 776                         } else if (strcmp(attr_name, "media") == 0) {
 777                                 if (read_int64(curr, &attr_buf) == 0)
 778                                         goto parse_fail;
 779                                 linkp->ll_media =
 780                                     (uint32_t)*(int64_t *)attr_buf;
 781                         } else if (strcmp(attr_name, "zone") == 0) {
 782                                 if (read_str(curr, &attr_buf) == 0)
 783                                         goto parse_fail;
 784                                 linkp->ll_zoneid = getzoneidbyname(attr_buf);
 785                                 if (linkp->ll_zoneid == -1) {
 786                                         if (errno == EFAULT)
 787                                                 abort();
 788                                         /*
 789                                          * If we can't find the zone, assign the
 790                                          * link to the GZ and mark it for being
 791                                          * renamed.
 792                                          */
 793                                         linkp->ll_zoneid = 0;
 794                                         rename = B_TRUE;
 795                                 }
 796                         } else {
 797                                 attr_buf_len = translators[type].read_func(curr,
 798                                     &attr_buf);
 799                                 if (attr_buf_len == 0)
 800                                         goto parse_fail;
 801 
 802                                 if (linkattr_set(&(linkp->ll_head), attr_name,
 803                                     attr_buf, attr_buf_len, type) != 0) {
 804                                         free(attr_buf);
 805                                         goto parse_fail;
 806                                 }
 807                         }
 808 
 809                         free(attr_buf);
 810                         attr_name[0] = '\0';
 811                         found_type = B_FALSE;
 812                 } else if (attr_name[0] != '\0') {
 813                         /*
 814                          * Non-zero length attr_name and found_type of false
 815                          * indicates that we have not found the type for this
 
 819                         for (type = 0; type < ntranslators; type++) {
 820                                 if (strcmp(curr,
 821                                     translators[type].type_name) == 0) {
 822                                         found_type = B_TRUE;
 823                                         break;
 824                                 }
 825                         }
 826 
 827                         if (!found_type)
 828                                 goto parse_fail;
 829                 } else {
 830                         /*
 831                          * A zero length attr_name indicates we are looking
 832                          * at the beginning of a link attribute.
 833                          */
 834                         if (c != '=')
 835                                 goto parse_fail;
 836 
 837                         (void) snprintf(attr_name, MAXLINKATTRLEN, "%s", curr);
 838                 }
 839 
 840                 /*
 841                  * The zone that this link belongs to has died, we are
 842                  * reparenting it to the GZ and renaming it to avoid name
 843                  * collisions.
 844                  */
 845                 if (rename == B_TRUE) {
 846                         (void) snprintf(linkp->ll_link, MAXLINKNAMELEN,
 847                             "SUNWorphan%u", (uint16_t)(gethrtime() / 1000));
 848                 }
 849                 curr = buf + i + 1;
 850         }
 851 
 852         /* Correct any erroneous IPTUN datalink class constant in the file */
 853         if (linkp->ll_class == 0x60) {
 854                 linkp->ll_class = DATALINK_CLASS_IPTUN;
 855                 rewrite_needed = B_TRUE;
 856         }
 857 
 858         return (0);
 859 
 860 parse_fail:
 861         /*
 862          * Free linkp->ll_head (link attribute list)
 863          */
 864         linkattr_destroy(linkp);
 865         return (-1);
 866 }
 867 
 868 static boolean_t
 
1240 
1241         return (err);
1242 }
1243 
1244 /*
1245  * Generate an entry in the link database.
1246  * Each entry has this format:
1247  * <link name>    <prop0>=<type>,<val>;...;<propn>=<type>,<val>;
1248  */
1249 static void
1250 generate_link_line(dlmgmt_link_t *linkp, boolean_t persist, char *buf)
1251 {
1252         char                    tmpbuf[MAXLINELEN];
1253         char                    *ptr = tmpbuf;
1254         char                    *lim = tmpbuf + MAXLINELEN;
1255         dlmgmt_linkattr_t       *cur_p = NULL;
1256         uint64_t                u64;
1257 
1258         ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s\t", linkp->ll_link);
1259         if (!persist) {
1260                 char zname[ZONENAME_MAX];
1261                 /*
1262                  * We store the linkid and the zone name in the active database
1263                  * so that dlmgmtd can recover in the event that it is
1264                  * restarted.
1265                  */
1266                 u64 = linkp->ll_linkid;
1267                 ptr += write_uint64(ptr, BUFLEN(lim, ptr), "linkid", &u64);
1268 
1269                 if (getzonenamebyid(linkp->ll_zoneid, zname,
1270                     sizeof (zname)) != -1) {
1271                         ptr += write_str(ptr, BUFLEN(lim, ptr), "zone", zname);
1272                 }
1273         }
1274         u64 = linkp->ll_class;
1275         ptr += write_uint64(ptr, BUFLEN(lim, ptr), "class", &u64);
1276         u64 = linkp->ll_media;
1277         ptr += write_uint64(ptr, BUFLEN(lim, ptr), "media", &u64);
1278 
1279         /*
1280          * The daemon does not keep any active link attribute. Only store the
1281          * attributes if this request is for persistent configuration,
1282          */
1283         if (persist) {
1284                 for (cur_p = linkp->ll_head; cur_p != NULL;
1285                     cur_p = cur_p->lp_next) {
1286                         ptr += translators[cur_p->lp_type].write_func(ptr,
1287                             BUFLEN(lim, ptr), cur_p->lp_name, cur_p->lp_val);
1288                 }
1289         }
1290 
1291         if (ptr <= lim)
1292                 (void) snprintf(buf, MAXLINELEN, "%s\n", tmpbuf);
1293 }
 
1407 static void
1408 dlmgmt_db_phys_activate(dlmgmt_link_t *linkp)
1409 {
1410         linkp->ll_flags |= DLMGMT_ACTIVE;
1411         (void) dlmgmt_write_db_entry(linkp->ll_link, linkp, DLMGMT_ACTIVE);
1412 }
1413 
1414 static void
1415 dlmgmt_db_walk(zoneid_t zoneid, datalink_class_t class, db_walk_func_t *func)
1416 {
1417         dlmgmt_link_t *linkp;
1418 
1419         for (linkp = avl_first(&dlmgmt_id_avl); linkp != NULL;
1420             linkp = AVL_NEXT(&dlmgmt_id_avl, linkp)) {
1421                 if (linkp->ll_zoneid == zoneid && (linkp->ll_class & class))
1422                         func(linkp);
1423         }
1424 }
1425 
1426 /*
1427  * Attempt to mitigate one of the deadlocks in the dlmgmtd architecture.
1428  *
1429  * dlmgmt_db_init() calls dlmgmt_process_db_req() which eventually gets to
1430  * dlmgmt_zfop() which tries to fork, enter the zone and read the file.
1431  * Because of the upcall architecture of dlmgmtd this can lead to deadlock
1432  * with the following scenario:
1433  *    a) the thread preparing to fork will have acquired the malloc locks
1434  *       then attempt to suspend every thread in preparation to fork.
1435  *    b) all of the upcalls will be blocked in door_ucred() trying to malloc()
1436  *       and get the credentials of their caller.
1437  *    c) we can't suspend the in-kernel thread making the upcall.
1438  *
1439  * Thus, we cannot serve door requests because we're blocked in malloc()
1440  * which fork() owns, but fork() is in turn blocked on the in-kernel thread
1441  * making the door upcall.  This is a fundamental architectural problem with
1442  * any server handling upcalls and also trying to fork().
1443  *
1444  * To minimize the chance of this deadlock occuring, we check ahead of time to
1445  * see if the file we want to read actually exists in the zone (which it almost
1446  * never does), so we don't need fork in that case (i.e. rarely to never).
1447  */
1448 static boolean_t
1449 zone_file_exists(char *zoneroot, char *filename)
1450 {
1451         struct stat     sb;
1452         char            fname[MAXPATHLEN];
1453 
1454         (void) snprintf(fname, sizeof (fname), "%s/%s", zoneroot, filename);
1455 
1456         if (stat(fname, &sb) == -1)
1457                 return (B_FALSE);
1458 
1459         return (B_TRUE);
1460 }
1461 
1462 /*
1463  * Initialize the datalink <link name, linkid> mapping and the link's
1464  * attributes list based on the configuration file /etc/dladm/datalink.conf
1465  * and the active configuration cache file
1466  * /etc/svc/volatile/dladm/datalink-management:default.cache.
1467  */
1468 int
1469 dlmgmt_db_init(zoneid_t zoneid, char *zoneroot)
1470 {
1471         dlmgmt_db_req_t *req;
1472         int             err;
1473         boolean_t       boot = B_FALSE;
1474 
1475         if ((req = dlmgmt_db_req_alloc(DLMGMT_DB_OP_READ, NULL,
1476             DATALINK_INVALID_LINKID, zoneid, DLMGMT_ACTIVE, &err)) == NULL)
1477                 return (err);
1478 
1479         /* Handle running in a non-native branded zone (i.e. has /native) */
1480         if (zone_file_exists(zoneroot, "/native" DLMGMT_TMPFS_DIR)) {
1481                 char tdir[MAXPATHLEN];
1482 
1483                 (void) snprintf(tdir, sizeof (tdir), "/native%s", cachefile);
1484                 (void) strlcpy(cachefile, tdir, sizeof (cachefile));
1485         }
1486 
1487         if (zone_file_exists(zoneroot, cachefile)) {
1488                 if ((err = dlmgmt_process_db_req(req)) != 0) {
1489                         /*
1490                          * If we get back ENOENT, that means that the active
1491                          * configuration file doesn't exist yet, and is not an
1492                          * error.  We'll create it down below after we've
1493                          * loaded the persistent configuration.
1494                          */
1495                         if (err != ENOENT)
1496                                 goto done;
1497                         boot = B_TRUE;
1498                 }
1499         } else {
1500                 boot = B_TRUE;
1501         }
1502 
1503         if (zone_file_exists(zoneroot, DLMGMT_PERSISTENT_DB_PATH)) {
1504                 req->ls_flags = DLMGMT_PERSIST;
1505                 err = dlmgmt_process_db_req(req);
1506                 if (err != 0 && err != ENOENT)
1507                         goto done;
1508         }
1509         err = 0;
1510         if (rewrite_needed) {
1511                 /*
1512                  * First update links in memory, then dump the entire db to
1513                  * disk.
1514                  */
1515                 dlmgmt_db_walk(zoneid, DATALINK_CLASS_ALL, dlmgmt_db_upgrade);
1516                 req->ls_op = DLMGMT_DB_OP_WRITE;
1517                 req->ls_linkid = DATALINK_ALL_LINKID;
1518                 if ((err = dlmgmt_process_db_req(req)) != 0 &&
1519                     err != EINPROGRESS)
1520                         goto done;
1521         }
1522         if (boot) {
1523                 dlmgmt_db_walk(zoneid, DATALINK_CLASS_PHYS,
1524                     dlmgmt_db_phys_activate);
1525         }
1526 
1527 done:
1528         if (err == EINPROGRESS)
1529                 err = 0;
1530         else
1531                 free(req);
1532         return (err);
1533 }
1534 
1535 /*
1536  * Remove all links in the given zoneid.
1537  *
1538  * We do this work in two different passes. In the first pass, we remove any
1539  * entry that hasn't been loaned and mark every entry that has been loaned as
1540  * something that is going to be tombstomed. In the second pass, we drop the
1541  * table lock for every entry and remove the tombstombed entry for our zone.
1542  */
1543 void
1544 dlmgmt_db_fini(zoneid_t zoneid)
1545 {
1546         dlmgmt_link_t *linkp = avl_first(&dlmgmt_name_avl), *next_linkp;
1547 
1548         while (linkp != NULL) {
1549                 next_linkp = AVL_NEXT(&dlmgmt_name_avl, linkp);
1550                 if (linkp->ll_zoneid == zoneid) {
1551                         boolean_t onloan = linkp->ll_onloan;
1552 
1553                         /*
1554                          * Cleanup any VNICs that were loaned to the zone
1555                          * before the zone goes away and we can no longer
1556                          * refer to the VNIC by the name/zoneid.
1557                          */
1558                         if (onloan) {
1559                                 (void) dlmgmt_delete_db_entry(linkp,
1560                                     DLMGMT_ACTIVE);
1561                                 linkp->ll_tomb = B_TRUE;
1562                         } else {
1563                                 (void) dlmgmt_destroy_common(linkp,
1564                                     DLMGMT_ACTIVE | DLMGMT_PERSIST);
1565                         }
1566 
1567                 }
1568                 linkp = next_linkp;
1569         }
1570 
1571 again:
1572         linkp = avl_first(&dlmgmt_name_avl);
1573         while (linkp != NULL) {
1574                 vnic_ioc_delete_t ioc;
1575 
1576                 next_linkp = AVL_NEXT(&dlmgmt_name_avl, linkp);
1577 
1578                 if (linkp->ll_zoneid != zoneid) {
1579                         linkp = next_linkp;
1580                         continue;
1581                 }
1582                 ioc.vd_vnic_id = linkp->ll_linkid;
1583                 if (linkp->ll_tomb != B_TRUE)
1584                         abort();
1585 
1586                 /*
1587                  * We have to drop the table lock while going up into the
1588                  * kernel. If we hold the table lock while deleting a vnic, we
1589                  * may get blocked on the mac perimeter and the holder of it may
1590                  * want something from dlmgmtd.
1591                  */
1592                 dlmgmt_table_unlock();
1593 
1594                 if (ioctl(dladm_dld_fd(dld_handle),
1595                     VNIC_IOC_DELETE, &ioc) < 0)
1596                         dlmgmt_log(LOG_WARNING, "dlmgmt_db_fini "
1597                             "delete VNIC ioctl failed %d %d",
1598                             ioc.vd_vnic_id, errno);
1599 
1600                 /*
1601                  * Even though we've dropped the lock, we know that nothing else
1602                  * could have removed us. Therefore, it should be safe to go
1603                  * through and delete ourselves, but do nothing else. We'll have
1604                  * to restart iteration from the beginning. This can be painful.
1605                  */
1606                 dlmgmt_table_lock(B_TRUE);
1607 
1608                 (void) dlmgmt_destroy_common(linkp,
1609                     DLMGMT_ACTIVE | DLMGMT_PERSIST);
1610                 goto again;
1611         }
1612 
1613 }
 |