Print this page
Commit IPMP changes


   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) 2010, Oracle and/or its affiliates. All rights reserved.

  24  */
  25 
  26 /*
  27  * Contains DB walker functions, which are of type `db_wfunc_t';
  28  *
  29  * typedef boolean_t db_wfunc_t(void *cbarg, nvlist_t *db_nvl, char *buf,
  30  *                              size_t bufsize, int *errp);
  31  *
  32  * ipadm_rw_db() walks through the data store, one line at a time and calls
  33  * these call back functions with:
  34  *      `cbarg'  - callback argument
  35  *      `db_nvl' - representing a line from DB in nvlist_t form
  36  *      `buf'    - character buffer to hold modified line
  37  *      `bufsize'- size of the buffer
  38  *      `errp' - captures any error inside the walker function.
  39  *
  40  * All the 'write' callback functions modify `db_nvl' based on `cbarg' and
  41  * copy string representation of `db_nvl' (using ipadm_nvlist2str()) into `buf'.
  42  * To delete a line from the DB, buf[0] is set to `\0'. Inside ipadm_rw_db(),
  43  * the modified `buf' is written back into DB.


  60 /* SCF related property group names and property names */
  61 #define IPMGMTD_APP_PG          "ipmgmtd"
  62 #define IPMGMTD_PROP_FBD        "first_boot_done"
  63 #define IPMGMTD_PROP_DBVER      "datastore_version"
  64 #define IPMGMTD_TRUESTR         "true"
  65 
  66 #define ATYPE   "_atype"                /* name of the address type nvpair */
  67 #define FLAGS   "_flags"                /* name of the flags nvpair */
  68 
  69 /*
  70  * flag used by ipmgmt_persist_aobjmap() to indicate address type is
  71  * IPADM_ADDR_IPV6_ADDRCONF.
  72  */
  73 #define IPMGMT_ATYPE_V6ACONF    0x1
  74 
  75 extern pthread_rwlock_t ipmgmt_dbconf_lock;
  76 
  77 /* signifies whether volatile copy of data store is in use */
  78 static boolean_t ipmgmt_rdonly_root = B_FALSE;
  79 

















































































































































  80 /*
  81  * Checks if the database nvl, `db_nvl' contains and matches ALL of the passed
  82  * in private nvpairs `proto', `ifname' & `aobjname'.
  83  */
  84 static boolean_t
  85 ipmgmt_nvlist_match(nvlist_t *db_nvl, const char *proto, const char *ifname,
  86     const char *aobjname)
  87 {
  88         char            *db_proto = NULL, *db_ifname = NULL;
  89         char            *db_aobjname = NULL;
  90         nvpair_t        *nvp;
  91         char            *name;
  92 
  93         /* walk through db_nvl and retrieve all its private nvpairs */
  94         for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
  95             nvp = nvlist_next_nvpair(db_nvl, nvp)) {
  96                 name = nvpair_name(nvp);
  97                 if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
  98                         (void) nvpair_value_string(nvp, &db_proto);
  99                 else if (strcmp(IPADM_NVP_IFNAME, name) == 0)


 305         } else {
 306                 buf[0] = '\0';
 307         }
 308 
 309         /* stop the search */
 310         return (B_FALSE);
 311 }
 312 
 313 /*
 314  * Input arguments can have IPADM_NVP_AOBJNAME or IPADM_NVP_IFNAME. A match is
 315  * found, when one of the following occurs first.
 316  * - the input aobjname matches the db aobjname. Return the db address.
 317  * - the input interface matches the db interface. Return all the
 318  *   matching db lines with addresses.
 319  */
 320 /* ARGSUSED */
 321 boolean_t
 322 ipmgmt_db_getaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 323     int *errp)
 324 {
 325         ipmgmt_getaddr_cbarg_t  *cbarg = arg;
 326         char            *db_aobjname = NULL;
 327         char            *db_ifname = NULL;
 328         nvlist_t        *db_addr = NULL;
 329         char            name[IPMGMT_STRSIZE];
 330         nvpair_t        *nvp;
 331         boolean_t       add_nvl = B_FALSE;
 332 
 333         /* Parse db nvlist */
 334         for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
 335             nvp = nvlist_next_nvpair(db_nvl, nvp)) {
 336                 if (nvpair_type(nvp) == DATA_TYPE_NVLIST)
 337                         (void) nvpair_value_nvlist(nvp, &db_addr);
 338                 else if (strcmp(nvpair_name(nvp), IPADM_NVP_IFNAME) == 0)
 339                         (void) nvpair_value_string(nvp, &db_ifname);
 340                 else if (strcmp(nvpair_name(nvp), IPADM_NVP_AOBJNAME) == 0)
 341                         (void) nvpair_value_string(nvp, &db_aobjname);
 342         }
 343 
 344         if (db_aobjname == NULL) /* Not an address */
 345                 return (B_TRUE);


 531                     instrval);
 532                 if ((*errp = nvlist_add_string(db_nvl, name, pval)) != 0)
 533                         return (B_FALSE);
 534         } else {
 535                 /* case of in-line update of a db entry */
 536                 if ((*errp = nvlist_add_string(db_nvl, name, instrval)) != 0)
 537                         return (B_FALSE);
 538         }
 539 
 540         (void) memset(buf, 0, buflen);
 541         if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
 542                 /* buffer overflow */
 543                 *errp = ENOBUFS;
 544         }
 545 
 546         /* we updated the DB entry, so do not continue */
 547         return (B_FALSE);
 548 }
 549 
 550 /*
 551  * For the given `cbarg->cb_ifname' interface, retrieves any persistent
 552  * interface information (used in 'ipadm show-if')

 553  */
 554 /* ARGSUSED */
 555 boolean_t
 556 ipmgmt_db_getif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 557     int *errp)
 558 {
 559         ipmgmt_getif_cbarg_t    *cbarg = arg;
 560         char                    *ifname = cbarg->cb_ifname;
 561         char                    *intf = NULL;
 562         ipadm_if_info_t         *ifp = NULL;
 563         sa_family_t             af;
 564         char                    *afstr;



 565 

 566         *errp = 0;
 567         if (nvlist_lookup_string(db_nvl, IPADM_NVP_FAMILY, &afstr) != 0 ||
 568             nvlist_lookup_string(db_nvl, IPADM_NVP_IFNAME, &intf) != 0 ||
 569             (ifname[0] != '\0' && strcmp(ifname, intf) != 0)) {






 570                 return (B_TRUE);














 571         }
 572         af = atoi(afstr);
 573         for (ifp = cbarg->cb_ifinfo; ifp != NULL; ifp = ifp->ifi_next) {
 574                 if (strcmp(ifp->ifi_name, intf) == 0)
 575                         break;
 576         }
 577         if (ifp == NULL) {
 578                 ipadm_if_info_t *new;
 579 
 580                 if ((new = calloc(1, sizeof (*new))) == NULL) {
 581                         *errp = ENOMEM;
 582                         return (B_FALSE); /* don't continue the walk */














 583                 }
 584                 new->ifi_next = cbarg->cb_ifinfo;
 585                 cbarg->cb_ifinfo = new;
 586                 ifp = new;
 587                 (void) strlcpy(ifp->ifi_name, intf, sizeof (ifp->ifi_name));




 588         }
 589 
 590         if (af == AF_INET) {
 591                 ifp->ifi_pflags |= IFIF_IPV4;
 592         } else {
 593                 assert(af == AF_INET6);
 594                 ifp->ifi_pflags |= IFIF_IPV6;

































 595         }
 596 
 597         /* Terminate the walk if we found both v4 and v6 interfaces. */
 598         if (ifname[0] != '\0' && (ifp->ifi_pflags & IFIF_IPV4) &&
 599             (ifp->ifi_pflags & IFIF_IPV6))









 600                 return (B_FALSE);
 601 
 602         return (B_TRUE);
 603 }
 604 
 605 /*
 606  * Deletes those entries from the database for which interface name
 607  * matches with the given `cbarg->cb_ifname'
 608  */
 609 /* ARGSUSED */
 610 boolean_t
 611 ipmgmt_db_resetif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 612     int *errp)
 613 {
 614         ipmgmt_if_cbarg_t *cbarg = arg;
 615         boolean_t       isv6 = (cbarg->cb_family == AF_INET6);
 616         char            *ifname = cbarg->cb_ifname;
 617         char            *modstr = NULL;
 618         char            *afstr;
 619         char            *aobjname;
 620         uint_t          proto;
 621         ipmgmt_aobjmap_t *head;
 622         boolean_t       aobjfound = B_FALSE;
 623 
 624         *errp = 0;
 625 
 626         if (!ipmgmt_nvlist_contains(db_nvl, NULL, ifname, NULL))
 627                 return (B_TRUE);
 628 
 629         if (nvlist_lookup_string(db_nvl, IPADM_NVP_FAMILY, &afstr) == 0) {
 630                 if (atoi(afstr) == cbarg->cb_family)














 631                         goto delete;








 632                 return (B_TRUE);
 633         }
 634 
 635         /* Reset all the interface configurations for 'ifname' */
 636         if (isv6 && (nvlist_exists(db_nvl, IPADM_NVP_IPV6ADDR) ||
 637             nvlist_exists(db_nvl, IPADM_NVP_INTFID))) {
 638                 goto delete;
 639         }
 640         if (!isv6 &&
 641             (nvlist_exists(db_nvl, IPADM_NVP_IPV4ADDR) ||
 642             nvlist_exists(db_nvl, IPADM_NVP_DHCP))) {
 643                 goto delete;
 644         }
 645 
 646         if (nvlist_lookup_string(db_nvl, IPADM_NVP_AOBJNAME, &aobjname) == 0) {
 647                 /*
 648                  * This must be an address property. Delete this
 649                  * line if there is a match in the address family.
 650                  */
 651                 head = aobjmap.aobjmap_head;


 667         }
 668 
 669         /*
 670          * If we are removing both v4 and v6 interface, then we get rid of
 671          * all the properties for that interface. On the other hand, if we
 672          * are deleting only v4 instance of an interface, then we delete v4
 673          * properties only.
 674          */
 675         if (nvlist_lookup_string(db_nvl, IPADM_NVP_PROTONAME, &modstr) == 0) {
 676                 proto = ipadm_str2proto(modstr);
 677                 switch (proto) {
 678                 case MOD_PROTO_IPV6:
 679                         if (isv6)
 680                                 goto delete;
 681                         break;
 682                 case MOD_PROTO_IPV4:
 683                         if (!isv6)
 684                                 goto delete;
 685                         break;
 686                 case MOD_PROTO_IP:
 687                         /* this should never be the case, today */
 688                         assert(0);
 689                         break;
 690                 }
 691         }
 692         /* Not found a match yet. Continue processing the db */
 693         return (B_TRUE);
 694 delete:
 695         /* delete the line from the db */
 696         buf[0] = '\0';
 697         return (B_TRUE);
 698 }
 699 
 700 /*
 701  * Deletes those entries from the database for which address object name
 702  * matches with the given `cbarg->cb_aobjname'
 703  */
 704 /* ARGSUSED */
 705 boolean_t
 706 ipmgmt_db_resetaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 707     int *errp)
 708 {


1668         /*
1669          * 'datastore_version' doesn't exist. Which means that we need to
1670          * upgrade the datastore. We will create 'datastore_version' and set
1671          * the version value to IPADM_DB_VERSION, after we upgrade the file.
1672          */
1673         return (bval);
1674 }
1675 
1676 /*
1677  * This is called after the successful upgrade of the local data-store. With
1678  * the data-store upgraded to recent version we don't have to do anything on
1679  * subsequent reboots.
1680  */
1681 void
1682 ipmgmt_update_dbver(scf_resources_t *res)
1683 {
1684         int64_t         version = IPADM_DB_VERSION;
1685 
1686         (void) ipmgmt_set_scfprop(res, IPMGMTD_APP_PG,
1687             IPMGMTD_PROP_DBVER, &version, SCF_TYPE_INTEGER);










































































































1688 }


   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) 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
  25  */
  26 
  27 /*
  28  * Contains DB walker functions, which are of type `db_wfunc_t';
  29  *
  30  * typedef boolean_t db_wfunc_t(void *cbarg, nvlist_t *db_nvl, char *buf,
  31  *                              size_t bufsize, int *errp);
  32  *
  33  * ipadm_rw_db() walks through the data store, one line at a time and calls
  34  * these call back functions with:
  35  *      `cbarg'  - callback argument
  36  *      `db_nvl' - representing a line from DB in nvlist_t form
  37  *      `buf'    - character buffer to hold modified line
  38  *      `bufsize'- size of the buffer
  39  *      `errp' - captures any error inside the walker function.
  40  *
  41  * All the 'write' callback functions modify `db_nvl' based on `cbarg' and
  42  * copy string representation of `db_nvl' (using ipadm_nvlist2str()) into `buf'.
  43  * To delete a line from the DB, buf[0] is set to `\0'. Inside ipadm_rw_db(),
  44  * the modified `buf' is written back into DB.


  61 /* SCF related property group names and property names */
  62 #define IPMGMTD_APP_PG          "ipmgmtd"
  63 #define IPMGMTD_PROP_FBD        "first_boot_done"
  64 #define IPMGMTD_PROP_DBVER      "datastore_version"
  65 #define IPMGMTD_TRUESTR         "true"
  66 
  67 #define ATYPE   "_atype"                /* name of the address type nvpair */
  68 #define FLAGS   "_flags"                /* name of the flags nvpair */
  69 
  70 /*
  71  * flag used by ipmgmt_persist_aobjmap() to indicate address type is
  72  * IPADM_ADDR_IPV6_ADDRCONF.
  73  */
  74 #define IPMGMT_ATYPE_V6ACONF    0x1
  75 
  76 extern pthread_rwlock_t ipmgmt_dbconf_lock;
  77 
  78 /* signifies whether volatile copy of data store is in use */
  79 static boolean_t ipmgmt_rdonly_root = B_FALSE;
  80 
  81 typedef int ipmgmt_if_updater_func_t(nvlist_t *, nvpair_t *, uint_t);
  82 
  83 static ipmgmt_if_updater_func_t ipmgmt_if_family_updater;
  84 static ipmgmt_if_updater_func_t ipmgmt_if_groupmembers_updater;
  85 
  86 static int ipmgmt_get_ifinfo_nvl(const char *ifname, nvlist_t **if_info_nvl);
  87 
  88 typedef struct {
  89         const char      *name;
  90         ipmgmt_if_updater_func_t        *func;
  91 } ipmgmt_if_updater_ent_t;
  92 
  93 static ipmgmt_if_updater_ent_t ipmgmt_if_updater_ent[] = {
  94         {IPADM_NVP_FAMILIES, ipmgmt_if_family_updater},
  95         {IPADM_NVP_MIFNAMES, ipmgmt_if_groupmembers_updater},
  96         {NULL, NULL}
  97 };
  98 
  99 static ipmgmt_if_updater_ent_t *
 100 ipmgmt_find_if_field_updater(const char *field_name)
 101 {
 102         int i;
 103 
 104         for (i = 0; ipmgmt_if_updater_ent[i].name != NULL; i++) {
 105                 if (strcmp(field_name, ipmgmt_if_updater_ent[i].name) == 0) {
 106                         break;
 107                 }
 108         }
 109 
 110         return (&ipmgmt_if_updater_ent[i]);
 111 }
 112 
 113 static int
 114 ipmgmt_if_groupmembers_updater(nvlist_t *db_nvl, nvpair_t *member_nvp,
 115         uint_t flags)
 116 {
 117         char    **members;
 118         char    *member;
 119         char    *out_memebers[256];
 120         uint_t  nelem = 0, cnt = 0;
 121         int     err;
 122 
 123         if ((err = nvpair_value_string(member_nvp, &member)) != 0)
 124                 return (err);
 125 
 126         err = nvlist_lookup_string_array(db_nvl, IPADM_NVP_MIFNAMES,
 127             &members, &nelem);
 128 
 129         if (err != 0 && (flags & IPMGMT_REMOVE))
 130                 return (ENOENT);
 131 
 132         while (nelem--) {
 133                 if ((flags & IPMGMT_REMOVE) &&
 134                     (strcmp(member, members[nelem]) == 0))
 135                         continue;
 136 
 137                 if ((out_memebers[cnt] = strdup(members[nelem])) == NULL) {
 138                         err = ENOMEM;
 139                         goto fail;
 140                 }
 141 
 142                 cnt++;
 143         }
 144 
 145         if (flags & IPMGMT_APPEND) {
 146                 if ((out_memebers[cnt] = strdup(member)) == NULL) {
 147                         err = ENOMEM;
 148                         goto fail;
 149                 }
 150                 cnt++;
 151         }
 152 
 153         if (cnt == 0) {
 154                 err = nvlist_remove(db_nvl, IPADM_NVP_MIFNAMES,
 155                     DATA_TYPE_STRING_ARRAY);
 156         } else {
 157                 err = nvlist_add_string_array(db_nvl, IPADM_NVP_MIFNAMES,
 158                     out_memebers, cnt);
 159         }
 160 
 161 fail:
 162         while (cnt--)
 163                 free(out_memebers[cnt]);
 164 
 165         return (err);
 166 }
 167 
 168 static int
 169 ipmgmt_if_family_updater(nvlist_t *db_nvl, nvpair_t *families_nvp, uint_t flags)
 170 {
 171         uint16_t *families;
 172         uint_t  nelem = 0;
 173         int     err;
 174 
 175         if ((err = nvpair_value_uint16_array(families_nvp, &families,
 176             &nelem)) != 0)
 177                 return (err);
 178 
 179         return (ipmgmt_update_family_nvp(db_nvl, families[0], flags));
 180 }
 181 
 182 int
 183 ipmgmt_update_family_nvp(nvlist_t *nvl, sa_family_t af, uint_t flags)
 184 {
 185         uint16_t        *families = NULL;
 186         uint16_t        out_families[2];
 187         uint_t  nelem = 0, cnt;
 188         int     err;
 189 
 190         err = nvlist_lookup_uint16_array(nvl, IPADM_NVP_FAMILIES,
 191             &families, &nelem);
 192         if (err != 0 && (flags & IPMGMT_REMOVE)) {
 193                 return (ENOENT);
 194         }
 195 
 196         if (flags & IPMGMT_APPEND) {
 197                 if (families != NULL) {
 198                         if (nelem == 2 || families[0] == af) {
 199                                 return (EEXIST);
 200                         }
 201                         out_families[0] = families[0];
 202                         out_families[1] = af;
 203                         cnt = 2;
 204                 } else {
 205                         out_families[0] = af;
 206                         cnt = 1;
 207                 }
 208         } else {
 209                 assert(nelem == 1 || nelem == 2);
 210                 cnt = 0;
 211                 while (nelem--) {
 212                         if (families[nelem] != af) {
 213                                 out_families[cnt] = families[nelem];
 214                                 cnt++;
 215                         }
 216                 }
 217         }
 218 
 219         if (cnt != 0) {
 220                 return (nvlist_add_uint16_array(nvl, IPADM_NVP_FAMILIES,
 221                     out_families, cnt));
 222         }
 223         return (nvlist_remove(nvl, IPADM_NVP_FAMILIES, DATA_TYPE_UINT16_ARRAY));
 224 }
 225 
 226 /*
 227  * Checks if the database nvl, `db_nvl' contains and matches ALL of the passed
 228  * in private nvpairs `proto', `ifname' & `aobjname'.
 229  */
 230 static boolean_t
 231 ipmgmt_nvlist_match(nvlist_t *db_nvl, const char *proto, const char *ifname,
 232     const char *aobjname)
 233 {
 234         char            *db_proto = NULL, *db_ifname = NULL;
 235         char            *db_aobjname = NULL;
 236         nvpair_t        *nvp;
 237         char            *name;
 238 
 239         /* walk through db_nvl and retrieve all its private nvpairs */
 240         for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
 241             nvp = nvlist_next_nvpair(db_nvl, nvp)) {
 242                 name = nvpair_name(nvp);
 243                 if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
 244                         (void) nvpair_value_string(nvp, &db_proto);
 245                 else if (strcmp(IPADM_NVP_IFNAME, name) == 0)


 451         } else {
 452                 buf[0] = '\0';
 453         }
 454 
 455         /* stop the search */
 456         return (B_FALSE);
 457 }
 458 
 459 /*
 460  * Input arguments can have IPADM_NVP_AOBJNAME or IPADM_NVP_IFNAME. A match is
 461  * found, when one of the following occurs first.
 462  * - the input aobjname matches the db aobjname. Return the db address.
 463  * - the input interface matches the db interface. Return all the
 464  *   matching db lines with addresses.
 465  */
 466 /* ARGSUSED */
 467 boolean_t
 468 ipmgmt_db_getaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 469     int *errp)
 470 {
 471         ipmgmt_get_cbarg_t      *cbarg = arg;
 472         char            *db_aobjname = NULL;
 473         char            *db_ifname = NULL;
 474         nvlist_t        *db_addr = NULL;
 475         char            name[IPMGMT_STRSIZE];
 476         nvpair_t        *nvp;
 477         boolean_t       add_nvl = B_FALSE;
 478 
 479         /* Parse db nvlist */
 480         for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
 481             nvp = nvlist_next_nvpair(db_nvl, nvp)) {
 482                 if (nvpair_type(nvp) == DATA_TYPE_NVLIST)
 483                         (void) nvpair_value_nvlist(nvp, &db_addr);
 484                 else if (strcmp(nvpair_name(nvp), IPADM_NVP_IFNAME) == 0)
 485                         (void) nvpair_value_string(nvp, &db_ifname);
 486                 else if (strcmp(nvpair_name(nvp), IPADM_NVP_AOBJNAME) == 0)
 487                         (void) nvpair_value_string(nvp, &db_aobjname);
 488         }
 489 
 490         if (db_aobjname == NULL) /* Not an address */
 491                 return (B_TRUE);


 677                     instrval);
 678                 if ((*errp = nvlist_add_string(db_nvl, name, pval)) != 0)
 679                         return (B_FALSE);
 680         } else {
 681                 /* case of in-line update of a db entry */
 682                 if ((*errp = nvlist_add_string(db_nvl, name, instrval)) != 0)
 683                         return (B_FALSE);
 684         }
 685 
 686         (void) memset(buf, 0, buflen);
 687         if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
 688                 /* buffer overflow */
 689                 *errp = ENOBUFS;
 690         }
 691 
 692         /* we updated the DB entry, so do not continue */
 693         return (B_FALSE);
 694 }
 695 
 696 /*
 697  * This function is used to update a DB line that describes
 698  * an interface, its family and group interface
 699  *
 700  */

 701 boolean_t
 702 ipmgmt_db_update_if(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 703                 int *errp)
 704 {
 705         ipadm_dbwrite_cbarg_t   *cb = arg;
 706         nvlist_t        *in_nvl = cb->dbw_nvl;
 707         uint_t  flags = cb->dbw_flags;
 708         nvpair_t        *nvp;
 709         char    *name;
 710         ipmgmt_if_updater_ent_t *updater;
 711         char    *member = NULL;
 712         char    *gifname = NULL;
 713         char    *db_line_if_name;
 714 
 715 
 716         *errp = 0;
 717 
 718         /* Only one flag */
 719         if ((flags & (IPMGMT_APPEND | IPMGMT_REMOVE)) == 0 ||
 720             ((flags & IPMGMT_APPEND) && (flags & IPMGMT_REMOVE))) {
 721                 *errp = EINVAL;
 722                 return (B_FALSE);
 723         }
 724 
 725         if (!nvlist_exists(db_nvl, IPADM_NVP_FAMILIES))
 726                 return (B_TRUE);
 727 
 728         if (nvlist_lookup_string(db_nvl,
 729             IPADM_NVP_IFNAME, &db_line_if_name) == 0 &&
 730             nvlist_lookup_string(in_nvl, IPADM_NVP_GIFNAME, &gifname) == 0 &&
 731             nvlist_lookup_string(in_nvl, IPADM_NVP_MIFNAMES, &member) == 0 &&
 732             strcmp(db_line_if_name, member) == 0) {
 733                 if (flags & IPMGMT_APPEND) {
 734                         if ((*errp = nvlist_add_string(db_nvl,
 735                             IPADM_NVP_GIFNAME, gifname)) != 0)
 736                                 return (B_FALSE);
 737                 } else {
 738                         if ((*errp = nvlist_remove(db_nvl, IPADM_NVP_GIFNAME,
 739                             DATA_TYPE_STRING)) != 0)
 740                                 return (B_FALSE);
 741                 }
 742                 cb->dbw_flags &= ~IPMGMT_UPDATE_IPMP;
 743                 goto done;


 744         }


 745 
 746         if (!ipmgmt_nvlist_intersects(db_nvl, in_nvl))
 747                 return (B_TRUE);
 748 
 749 
 750         for (nvp = nvlist_next_nvpair(in_nvl, NULL); nvp != NULL;
 751             nvp = nvlist_next_nvpair(in_nvl, nvp)) {
 752 
 753                 name = nvpair_name(nvp);
 754                 if (strcmp(name, IPADM_NVP_FAMILIES) != 0 &&
 755                     strcmp(name, IPADM_NVP_MIFNAMES) != 0)
 756                         continue;
 757 
 758                 updater = ipmgmt_find_if_field_updater(name);
 759                 assert(updater != NULL);
 760                 *errp = (*updater->func)(db_nvl, nvp, flags);
 761                 if (*errp != 0)
 762                         return (B_FALSE);
 763         }
 764 
 765         cb->dbw_flags &= ~IPMGMT_UPDATE_IF;
 766 
 767 done:
 768         (void) memset(buf, 0, buflen);
 769         if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
 770                 *errp = ENOBUFS;
 771                 return (B_FALSE);
 772         }
 773 
 774         /* we finished all operations ???, so do not continue */
 775         if ((cb->dbw_flags & (IPMGMT_UPDATE_IF | IPMGMT_UPDATE_IPMP)) == 0)
 776                 return (B_FALSE);
 777 
 778         return (B_TRUE);
 779 }
 780 
 781 /*
 782  * For the given `cbarg->cb_ifname' interface retrieves
 783  * the nvlist that represents the persistent interface information
 784  * The nvlist contains:
 785  *      IPADM_NVP_IFNAME
 786  *      IPADM_NVP_FAMILIES
 787  *      IPADM_NVP_IF_CLASS
 788  *
 789  * (used in 'ipadm show-if')
 790  */
 791 /* ARGSUSED */
 792 boolean_t
 793 ipmgmt_db_getif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 794     int *errp)
 795 {
 796         ipmgmt_get_cbarg_t      *cbarg = arg;
 797         char    *ifname = cbarg->cb_ifname;
 798         nvpair_t        *nvp;
 799         char    *db_ifname = NULL;
 800         uint16_t        *db_families = NULL;
 801         uint_t  nelem = 0;
 802 
 803         /* Parse db nvlist */
 804         for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
 805             nvp = nvlist_next_nvpair(db_nvl, nvp)) {
 806 
 807                 if (strcmp(nvpair_name(nvp), IPADM_NVP_IFNAME) == 0)
 808                         (void) nvpair_value_string(nvp, &db_ifname);
 809                 else if (strcmp(nvpair_name(nvp), IPADM_NVP_FAMILIES) == 0)
 810                         (void) nvpair_value_uint16_array(nvp,
 811                             &db_families, &nelem);
 812         }
 813 
 814         if (db_ifname == NULL || db_families == NULL)
 815                 return (B_TRUE);
 816 
 817         if (ifname != NULL && ifname[0] != '\0' &&
 818             strcmp(ifname, db_ifname) != 0)
 819                 return (B_TRUE);
 820 
 821         *errp = nvlist_add_nvlist(cbarg->cb_onvl, db_ifname, db_nvl);
 822         if (*errp == 0)
 823                 cbarg->cb_ocnt++;
 824 
 825         if (ifname != NULL && ifname[0] != '\0')
 826                 return (B_FALSE);
 827 
 828         return (B_TRUE);
 829 }
 830 
 831 /*
 832  * Deletes those entries from the database for which interface name
 833  * matches with the given `cbarg->cb_ifname'
 834  */
 835 /* ARGSUSED */
 836 boolean_t
 837 ipmgmt_db_resetif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 838     int *errp)
 839 {
 840         ipmgmt_if_cbarg_t *cbarg = arg;
 841         boolean_t       isv6 = (cbarg->cb_family == AF_INET6);
 842         char            *ifname = cbarg->cb_ifname;
 843         char            *modstr = NULL;

 844         char            *aobjname;
 845         uint_t          proto;
 846         ipmgmt_aobjmap_t *head;
 847         boolean_t       aobjfound = B_FALSE;
 848 
 849         *errp = 0;
 850 
 851         if (!ipmgmt_nvlist_contains(db_nvl, NULL, ifname, NULL))
 852                 return (B_TRUE);
 853 
 854         if (nvlist_exists(db_nvl, IPADM_NVP_FAMILIES)) {
 855 
 856                 if ((*errp = ipmgmt_update_family_nvp(db_nvl, cbarg->cb_family,
 857                     IPMGMT_REMOVE)) != 0) {
 858                         return (B_FALSE);
 859                 }
 860 
 861                 if (cbarg->cb_family == AF_INET) {
 862                         cbarg->cb_ipv4exists = B_FALSE;
 863                 } else {
 864                         assert(cbarg->cb_family == AF_INET6);
 865                         cbarg->cb_ipv6exists = B_FALSE;
 866                 }
 867                 if (!nvlist_exists(db_nvl, IPADM_NVP_FAMILIES)) {
 868                         cbarg->cb_ipv4exists = B_FALSE;
 869                         cbarg->cb_ipv6exists = B_FALSE;
 870                         goto delete;
 871                 }
 872                 /* Otherwise need to reconstruct this string */
 873                 (void) memset(buf, 0, buflen);
 874                 if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
 875                         /* buffer overflow */
 876                         *errp = ENOBUFS;
 877                         return (B_FALSE);
 878                 }
 879                 return (B_TRUE);
 880         }
 881 
 882         /* Reset all the interface configurations for 'ifname' */
 883         if (isv6 && (nvlist_exists(db_nvl, IPADM_NVP_IPV6ADDR) ||
 884             nvlist_exists(db_nvl, IPADM_NVP_INTFID))) {
 885                 goto delete;
 886         }
 887         if (!isv6 &&
 888             (nvlist_exists(db_nvl, IPADM_NVP_IPV4ADDR) ||
 889             nvlist_exists(db_nvl, IPADM_NVP_DHCP))) {
 890                 goto delete;
 891         }
 892 
 893         if (nvlist_lookup_string(db_nvl, IPADM_NVP_AOBJNAME, &aobjname) == 0) {
 894                 /*
 895                  * This must be an address property. Delete this
 896                  * line if there is a match in the address family.
 897                  */
 898                 head = aobjmap.aobjmap_head;


 914         }
 915 
 916         /*
 917          * If we are removing both v4 and v6 interface, then we get rid of
 918          * all the properties for that interface. On the other hand, if we
 919          * are deleting only v4 instance of an interface, then we delete v4
 920          * properties only.
 921          */
 922         if (nvlist_lookup_string(db_nvl, IPADM_NVP_PROTONAME, &modstr) == 0) {
 923                 proto = ipadm_str2proto(modstr);
 924                 switch (proto) {
 925                 case MOD_PROTO_IPV6:
 926                         if (isv6)
 927                                 goto delete;
 928                         break;
 929                 case MOD_PROTO_IPV4:
 930                         if (!isv6)
 931                                 goto delete;
 932                         break;
 933                 case MOD_PROTO_IP:
 934                 if (!cbarg->cb_ipv4exists && !cbarg->cb_ipv6exists)
 935                 goto delete;
 936                         break;
 937                 }
 938         }
 939         /* Not found a match yet. Continue processing the db */
 940         return (B_TRUE);
 941 delete:
 942         /* delete the line from the db */
 943         buf[0] = '\0';
 944         return (B_TRUE);
 945 }
 946 
 947 /*
 948  * Deletes those entries from the database for which address object name
 949  * matches with the given `cbarg->cb_aobjname'
 950  */
 951 /* ARGSUSED */
 952 boolean_t
 953 ipmgmt_db_resetaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 954     int *errp)
 955 {


1915         /*
1916          * 'datastore_version' doesn't exist. Which means that we need to
1917          * upgrade the datastore. We will create 'datastore_version' and set
1918          * the version value to IPADM_DB_VERSION, after we upgrade the file.
1919          */
1920         return (bval);
1921 }
1922 
1923 /*
1924  * This is called after the successful upgrade of the local data-store. With
1925  * the data-store upgraded to recent version we don't have to do anything on
1926  * subsequent reboots.
1927  */
1928 void
1929 ipmgmt_update_dbver(scf_resources_t *res)
1930 {
1931         int64_t         version = IPADM_DB_VERSION;
1932 
1933         (void) ipmgmt_set_scfprop(res, IPMGMTD_APP_PG,
1934             IPMGMTD_PROP_DBVER, &version, SCF_TYPE_INTEGER);
1935 }
1936 
1937 /*
1938  * Return TRUE if `ifname' has persistent configuration for the `af' address
1939  * family in the datastore.
1940  * It is possible to call the function with af == AF_UNSPEC, so in this case
1941  * the function returns TRUE if either AF_INET or AF_INET6 interface exists
1942  */
1943 boolean_t
1944 ipmgmt_persist_if_exists(const char *ifname, sa_family_t af)
1945 {
1946         boolean_t exists = B_FALSE;
1947         nvlist_t    *if_info_nvl;
1948         uint16_t    *families = NULL;
1949         sa_family_t af_db;
1950         uint_t  nelem = 0;
1951 
1952         if (ipmgmt_get_ifinfo_nvl(ifname, &if_info_nvl) != 0)
1953                 goto done;
1954 
1955         if (nvlist_lookup_uint16_array(if_info_nvl, IPADM_NVP_FAMILIES,
1956             &families, &nelem) != 0)
1957                 goto done;
1958 
1959         while (nelem--) {
1960                 af_db = families[nelem];
1961                 if (af_db == af || (af == AF_UNSPEC &&
1962                     (af_db == AF_INET || af_db == AF_INET6))) {
1963                         exists = B_TRUE;
1964                         break;
1965                 }
1966         }
1967 
1968 done:
1969         if (if_info_nvl != NULL)
1970                 nvlist_free(if_info_nvl);
1971 
1972         return (exists);
1973 }
1974 
1975 /*
1976  * Retrieves the membership information for the requested mif_name
1977  * if mif_name is a memeber of a IPMP group, then gif_name will contain
1978  * the name of IPMP group interface, otherwise the variable will be empty
1979  */
1980 void
1981 ipmgmt_get_group_interface(const char *mif_name, char *gif_name, size_t size)
1982 {
1983         char    *gif_name_from_nvl;
1984         nvlist_t        *if_info_nvl;
1985 
1986         gif_name[0] = '\0';
1987 
1988         if (ipmgmt_get_ifinfo_nvl(mif_name, &if_info_nvl) != 0)
1989                 goto done;
1990 
1991         if (nvlist_lookup_string(if_info_nvl, IPADM_NVP_GIFNAME,
1992             &gif_name_from_nvl) != 0)
1993                 goto done;
1994 
1995         (void) strlcpy(gif_name, gif_name_from_nvl, size);
1996 
1997 done:
1998         if (if_info_nvl != NULL)
1999                 nvlist_free(if_info_nvl);
2000 }
2001 
2002 static int
2003 ipmgmt_get_ifinfo_nvl(const char *ifname, nvlist_t **if_info_nvl)
2004 {
2005         ipmgmt_get_cbarg_t cbarg;
2006         nvpair_t    *nvp;
2007         nvlist_t    *nvl;
2008         int     err;
2009 
2010         cbarg.cb_ifname = NULL;
2011         cbarg.cb_aobjname = NULL;
2012         cbarg.cb_ocnt = 0;
2013 
2014         if ((err = nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0)) != 0)
2015                 goto done;
2016 
2017         err = ipmgmt_db_walk(ipmgmt_db_getif, &cbarg, IPADM_DB_READ);
2018         if (err == ENOENT && cbarg.cb_ocnt > 0)
2019                 err = 0;
2020 
2021         if (err != 0)
2022                 goto done;
2023 
2024         for (nvp = nvlist_next_nvpair(cbarg.cb_onvl, NULL); nvp != NULL;
2025             nvp = nvlist_next_nvpair(cbarg.cb_onvl, nvp)) {
2026 
2027                 if (strcmp(nvpair_name(nvp), ifname) != 0)
2028                         continue;
2029 
2030                 if ((err = nvpair_value_nvlist(nvp, &nvl)) != 0 ||
2031                     (err = nvlist_dup(nvl, if_info_nvl, NV_UNIQUE_NAME)) != 0)
2032                         *if_info_nvl = NULL;
2033 
2034                 break;
2035         }
2036 
2037 done:
2038         nvlist_free(cbarg.cb_onvl);
2039 
2040         return (err);
2041 }