Print this page
    
NEX-7823 ipmgmtd can't properly remove interface from the old ipadm.conf format
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Jean McCormack <jean.mccormack@nexenta.com>
NEX-6864 cannot create functional link-based IPMP interface
NEX-7793 unable to add/remove interface with existing address to/from IPMP group
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-2395: new libipadm/ipadm/ipmgmtd shall be backward compatible with old ipadm.conf format
OS-161: Integrate IPMP changes
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c
          +++ new/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  
    | 
      ↓ open down ↓ | 
    13 lines elided | 
    
      ↑ open up ↑ | 
  
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
       24 + * Copyright 2016 Nexenta Systems, Inc.
  24   25   * Copyright 2016 Argo Technologie SA.
  25   26   * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
  26   27   */
  27   28  
  28   29  /*
  29   30   * Contains DB walker functions, which are of type `db_wfunc_t';
  30   31   *
  31   32   * typedef boolean_t db_wfunc_t(void *cbarg, nvlist_t *db_nvl, char *buf,
  32   33   *                              size_t bufsize, int *errp);
  33   34   *
  34   35   * ipadm_rw_db() walks through the data store, one line at a time and calls
  35   36   * these call back functions with:
  36   37   *      `cbarg'  - callback argument
  37   38   *      `db_nvl' - representing a line from DB in nvlist_t form
  38   39   *      `buf'    - character buffer to hold modified line
  39   40   *      `bufsize'- size of the buffer
  40   41   *      `errp' - captures any error inside the walker function.
  41   42   *
  42   43   * All the 'write' callback functions modify `db_nvl' based on `cbarg' and
  43   44   * copy string representation of `db_nvl' (using ipadm_nvlist2str()) into `buf'.
  44   45   * To delete a line from the DB, buf[0] is set to `\0'. Inside ipadm_rw_db(),
  45   46   * the modified `buf' is written back into DB.
  46   47   *
  47   48   * All the 'read' callback functions, retrieve the information from the DB, by
  48   49   * reading `db_nvl' and then populate the `cbarg'.
  49   50   */
  50   51  
  51   52  #include <stdlib.h>
  52   53  #include <strings.h>
  53   54  #include <errno.h>
  54   55  #include <assert.h>
  55   56  #include <sys/types.h>
  56   57  #include <sys/socket.h>
  57   58  #include <netinet/in.h>
  58   59  #include <arpa/inet.h>
  59   60  #include <unistd.h>
  60   61  #include "ipmgmt_impl.h"
  61   62  
  62   63  /* SCF related property group names and property names */
  63   64  #define IPMGMTD_APP_PG          "ipmgmtd"
  64   65  #define IPMGMTD_PROP_FBD        "first_boot_done"
  65   66  #define IPMGMTD_PROP_DBVER      "datastore_version"
  66   67  #define IPMGMTD_TRUESTR         "true"
  67   68  
  68   69  #define ATYPE   "_atype"                /* name of the address type nvpair */
  69   70  #define FLAGS   "_flags"                /* name of the flags nvpair */
  70   71  
  71   72  /*
  
    | 
      ↓ open down ↓ | 
    38 lines elided | 
    
      ↑ open up ↑ | 
  
  72   73   * flag used by ipmgmt_persist_aobjmap() to indicate address type is
  73   74   * IPADM_ADDR_IPV6_ADDRCONF.
  74   75   */
  75   76  #define IPMGMT_ATYPE_V6ACONF    0x1
  76   77  
  77   78  extern pthread_rwlock_t ipmgmt_dbconf_lock;
  78   79  
  79   80  /* signifies whether volatile copy of data store is in use */
  80   81  static boolean_t ipmgmt_rdonly_root = B_FALSE;
  81   82  
       83 +typedef int ipmgmt_if_updater_func_t(nvlist_t *, nvpair_t *, uint_t);
       84 +
       85 +static ipmgmt_if_updater_func_t ipmgmt_if_family_updater;
       86 +static ipmgmt_if_updater_func_t ipmgmt_if_groupmembers_updater;
       87 +
       88 +static int ipmgmt_get_ifinfo_nvl(const char *ifname, nvlist_t **if_info_nvl);
       89 +
       90 +typedef struct {
       91 +        const char      *name;
       92 +        ipmgmt_if_updater_func_t        *func;
       93 +} ipmgmt_if_updater_ent_t;
       94 +
       95 +static ipmgmt_if_updater_ent_t ipmgmt_if_updater_ent[] = {
       96 +        {IPADM_NVP_FAMILIES, ipmgmt_if_family_updater},
       97 +        {IPADM_NVP_MIFNAMES, ipmgmt_if_groupmembers_updater},
       98 +        {NULL, NULL}
       99 +};
      100 +
      101 +static ipmgmt_if_updater_ent_t *
      102 +ipmgmt_find_if_field_updater(const char *field_name)
      103 +{
      104 +        int i;
      105 +
      106 +        for (i = 0; ipmgmt_if_updater_ent[i].name != NULL; i++) {
      107 +                if (strcmp(field_name, ipmgmt_if_updater_ent[i].name) == 0) {
      108 +                        break;
      109 +                }
      110 +        }
      111 +
      112 +        return (&ipmgmt_if_updater_ent[i]);
      113 +}
      114 +
      115 +static int
      116 +ipmgmt_if_groupmembers_updater(nvlist_t *db_nvl, nvpair_t *member_nvp,
      117 +    uint_t flags)
      118 +{
      119 +        char    **members;
      120 +        char    *member;
      121 +        char    *out_members[256];
      122 +        uint_t  nelem = 0, cnt = 0;
      123 +        int     err;
      124 +
      125 +        if ((err = nvpair_value_string(member_nvp, &member)) != 0)
      126 +                return (err);
      127 +
      128 +        err = nvlist_lookup_string_array(db_nvl, IPADM_NVP_MIFNAMES,
      129 +            &members, &nelem);
      130 +
      131 +        if (err != 0 && (flags & IPMGMT_REMOVE))
      132 +                return (ENOENT);
      133 +
      134 +        while (nelem-- > 0) {
      135 +                if ((flags & IPMGMT_REMOVE) &&
      136 +                    (strcmp(member, members[nelem]) == 0))
      137 +                        continue;
      138 +
      139 +                if ((out_members[cnt] = strdup(members[nelem])) == NULL) {
      140 +                        err = ENOMEM;
      141 +                        goto fail;
      142 +                }
      143 +
      144 +                cnt++;
      145 +        }
      146 +
      147 +        if (flags & IPMGMT_APPEND) {
      148 +                if ((out_members[cnt] = strdup(member)) == NULL) {
      149 +                        err = ENOMEM;
      150 +                        goto fail;
      151 +                }
      152 +                cnt++;
      153 +        }
      154 +
      155 +        if (cnt == 0) {
      156 +                err = nvlist_remove(db_nvl, IPADM_NVP_MIFNAMES,
      157 +                    DATA_TYPE_STRING_ARRAY);
      158 +        } else {
      159 +                err = nvlist_add_string_array(db_nvl, IPADM_NVP_MIFNAMES,
      160 +                    out_members, cnt);
      161 +        }
      162 +
      163 +fail:
      164 +        while (cnt--)
      165 +                free(out_members[cnt]);
      166 +
      167 +        return (err);
      168 +}
      169 +
      170 +static int
      171 +ipmgmt_if_family_updater(nvlist_t *db_nvl, nvpair_t *families_nvp, uint_t flags)
      172 +{
      173 +        uint16_t *families;
      174 +        uint_t  nelem = 0;
      175 +        int     err;
      176 +
      177 +        if ((err = nvpair_value_uint16_array(families_nvp, &families,
      178 +            &nelem)) != 0)
      179 +                return (err);
      180 +
      181 +        return (ipmgmt_update_family_nvp(db_nvl, families[0], flags));
      182 +}
      183 +
      184 +int
      185 +ipmgmt_update_family_nvp(nvlist_t *nvl, sa_family_t af, uint_t flags)
      186 +{
      187 +        uint16_t        *families = NULL;
      188 +        uint16_t        out_families[2];
      189 +        uint_t  nelem = 0, cnt;
      190 +        int     err;
      191 +
      192 +        err = nvlist_lookup_uint16_array(nvl, IPADM_NVP_FAMILIES,
      193 +            &families, &nelem);
      194 +        if (err != 0 && (flags & IPMGMT_REMOVE)) {
      195 +                return (ENOENT);
      196 +        }
      197 +
      198 +        if (flags & IPMGMT_APPEND) {
      199 +                if (families != NULL) {
      200 +                        if (nelem == 2 || families[0] == af) {
      201 +                                return (EEXIST);
      202 +                        }
      203 +                        out_families[0] = families[0];
      204 +                        out_families[1] = af;
      205 +                        cnt = 2;
      206 +                } else {
      207 +                        out_families[0] = af;
      208 +                        cnt = 1;
      209 +                }
      210 +        } else {
      211 +                assert(nelem == 1 || nelem == 2);
      212 +                cnt = 0;
      213 +                while (nelem-- > 0) {
      214 +                        if (families[nelem] != af) {
      215 +                                out_families[cnt] = families[nelem];
      216 +                                cnt++;
      217 +                        }
      218 +                }
      219 +        }
      220 +
      221 +        if (cnt != 0) {
      222 +                return (nvlist_add_uint16_array(nvl, IPADM_NVP_FAMILIES,
      223 +                    out_families, cnt));
      224 +        }
      225 +        return (nvlist_remove(nvl, IPADM_NVP_FAMILIES, DATA_TYPE_UINT16_ARRAY));
      226 +}
      227 +
  82  228  /*
  83  229   * Checks if the database nvl, `db_nvl' contains and matches ALL of the passed
  84  230   * in private nvpairs `proto', `ifname' & `aobjname'.
  85  231   */
  86  232  static boolean_t
  87  233  ipmgmt_nvlist_match(nvlist_t *db_nvl, const char *proto, const char *ifname,
  88  234      const char *aobjname)
  89  235  {
  90  236          char            *db_proto = NULL, *db_ifname = NULL;
  91  237          char            *db_aobjname = NULL;
  92  238          nvpair_t        *nvp;
  93  239          char            *name;
  94  240  
  95  241          /* walk through db_nvl and retrieve all its private nvpairs */
  96  242          for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
  97  243              nvp = nvlist_next_nvpair(db_nvl, nvp)) {
  98  244                  name = nvpair_name(nvp);
  99  245                  if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
 100  246                          (void) nvpair_value_string(nvp, &db_proto);
 101  247                  else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
 102  248                          (void) nvpair_value_string(nvp, &db_ifname);
 103  249                  else if (strcmp(IPADM_NVP_AOBJNAME, name) == 0)
 104  250                          (void) nvpair_value_string(nvp, &db_aobjname);
 105  251          }
 106  252  
 107  253          if (proto != NULL && proto[0] == '\0')
 108  254                  proto = NULL;
 109  255          if (ifname != NULL && ifname[0] == '\0')
 110  256                  ifname = NULL;
 111  257          if (aobjname != NULL && aobjname[0] == '\0')
 112  258                  aobjname = NULL;
 113  259  
 114  260          if ((proto == NULL && db_proto != NULL) ||
 115  261              (proto != NULL && db_proto == NULL) ||
 116  262              (proto != NULL && db_proto != NULL &&
 117  263              strcmp(proto, db_proto) != 0)) {
 118  264                  /* no intersection - different protocols. */
 119  265                  return (B_FALSE);
 120  266          }
 121  267          if ((ifname == NULL && db_ifname != NULL) ||
 122  268              (ifname != NULL && db_ifname == NULL) ||
 123  269              (ifname != NULL && db_ifname != NULL &&
 124  270              strcmp(ifname, db_ifname) != 0)) {
 125  271                  /* no intersection - different interfaces. */
 126  272                  return (B_FALSE);
 127  273          }
 128  274          if ((aobjname == NULL && db_aobjname != NULL) ||
 129  275              (aobjname != NULL && db_aobjname == NULL) ||
 130  276              (aobjname != NULL && db_aobjname != NULL &&
 131  277              strcmp(aobjname, db_aobjname) != 0)) {
 132  278                  /* no intersection - different address objects */
 133  279                  return (B_FALSE);
 134  280          }
 135  281  
 136  282          return (B_TRUE);
 137  283  }
 138  284  
 139  285  /*
 140  286   * Checks if the database nvl, `db_nvl' and the input nvl, `in_nvl' intersects.
 141  287   */
 142  288  static boolean_t
 143  289  ipmgmt_nvlist_intersects(nvlist_t *db_nvl, nvlist_t *in_nvl)
 144  290  {
 145  291          nvpair_t        *nvp;
 146  292          char            *name;
 147  293          char            *proto = NULL, *ifname = NULL, *aobjname = NULL;
 148  294  
 149  295          /* walk through in_nvl and retrieve all its private nvpairs */
 150  296          for (nvp = nvlist_next_nvpair(in_nvl, NULL); nvp != NULL;
 151  297              nvp = nvlist_next_nvpair(in_nvl, nvp)) {
 152  298                  name = nvpair_name(nvp);
 153  299                  if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
 154  300                          (void) nvpair_value_string(nvp, &proto);
 155  301                  else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
 156  302                          (void) nvpair_value_string(nvp, &ifname);
 157  303                  else if (strcmp(IPADM_NVP_AOBJNAME, name) == 0)
 158  304                          (void) nvpair_value_string(nvp, &aobjname);
 159  305          }
 160  306  
 161  307          return (ipmgmt_nvlist_match(db_nvl, proto, ifname, aobjname));
 162  308  }
 163  309  
 164  310  /*
 165  311   * Checks if the database nvl, `db_nvl', contains and matches ANY of the passed
 166  312   * in private nvpairs `proto', `ifname' & `aobjname'.
 167  313   */
 168  314  static boolean_t
 169  315  ipmgmt_nvlist_contains(nvlist_t *db_nvl, const char *proto,
 170  316      const char *ifname, char *aobjname)
 171  317  {
 172  318          char            *db_ifname = NULL, *db_proto = NULL;
 173  319          char            *db_aobjname = NULL;
 174  320          nvpair_t        *nvp;
 175  321          char            *name;
 176  322  
 177  323          /* walk through db_nvl and retrieve all private nvpairs */
 178  324          for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
 179  325              nvp = nvlist_next_nvpair(db_nvl, nvp)) {
 180  326                  name = nvpair_name(nvp);
 181  327                  if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
 182  328                          (void) nvpair_value_string(nvp, &db_proto);
 183  329                  else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
 184  330                          (void) nvpair_value_string(nvp, &db_ifname);
 185  331                  else if (strcmp(IPADM_NVP_AOBJNAME, name) == 0)
 186  332                          (void) nvpair_value_string(nvp, &db_aobjname);
 187  333          }
 188  334  
 189  335          if (proto != NULL && proto[0] != '\0') {
 190  336                  if ((db_proto == NULL || strcmp(proto, db_proto) != 0))
 191  337                          return (B_FALSE);
 192  338          }
 193  339          if (ifname != NULL && ifname[0] != '\0') {
 194  340                  if ((db_ifname == NULL || strcmp(ifname, db_ifname) != 0))
 195  341                          return (B_FALSE);
 196  342          }
 197  343          if (aobjname != NULL && aobjname[0] != '\0') {
 198  344                  if ((db_aobjname == NULL || strcmp(aobjname, db_aobjname) != 0))
 199  345                          return (B_FALSE);
 200  346          }
 201  347  
 202  348          return (B_TRUE);
 203  349  }
 204  350  
 205  351  /*
 206  352   * Retrieves the property value from the DB. The property whose value is to be
 207  353   * retrieved is in `pargp->ia_pname'.
 208  354   */
 209  355  /* ARGSUSED */
 210  356  boolean_t
 211  357  ipmgmt_db_getprop(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 212  358      int *errp)
 213  359  {
 214  360          ipmgmt_prop_arg_t       *pargp = arg;
 215  361          boolean_t               cont = B_TRUE;
 216  362          char                    *pval;
 217  363          int                     err = 0;
 218  364  
 219  365          *errp = 0;
 220  366  
 221  367          if (!ipmgmt_nvlist_match(db_nvl, pargp->ia_module,
 222  368              pargp->ia_ifname, pargp->ia_aobjname))
 223  369                  return (B_TRUE);
 224  370  
 225  371          if ((err = nvlist_lookup_string(db_nvl, pargp->ia_pname,
 226  372              &pval)) == 0) {
 227  373                  (void) strlcpy(pargp->ia_pval, pval, sizeof (pargp->ia_pval));
 228  374                  /*
 229  375                   * We have retrieved what we are looking for.
 230  376                   * Stop the walker.
 231  377                   */
 232  378                  cont = B_FALSE;
 233  379          } else {
 234  380                  if (err == ENOENT)
 235  381                          err = 0;
 236  382                  *errp = err;
 237  383          }
 238  384  
 239  385          return (cont);
 240  386  }
 241  387  
 242  388  /*
 243  389   * Removes the property value from the DB. The property whose value is to be
 244  390   * removed is in `pargp->ia_pname'.
 245  391   */
 246  392  /* ARGSUSED */
 247  393  boolean_t
 248  394  ipmgmt_db_resetprop(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 249  395      int *errp)
 250  396  {
 251  397          ipmgmt_prop_arg_t       *pargp = arg;
 252  398  
 253  399          *errp = 0;
 254  400          if (!ipmgmt_nvlist_match(db_nvl, pargp->ia_module,
 255  401              pargp->ia_ifname, pargp->ia_aobjname))
 256  402                  return (B_TRUE);
 257  403  
 258  404          if (!nvlist_exists(db_nvl, pargp->ia_pname))
 259  405                  return (B_TRUE);
 260  406  
 261  407          /*
 262  408           * We found the property in the DB. If IPMGMT_REMOVE is not set then
 263  409           * delete the entry from the db. If it is set, then the property is a
 264  410           * multi-valued property so just remove the specified values from DB.
 265  411           */
 266  412          if (pargp->ia_flags & IPMGMT_REMOVE) {
 267  413                  char    *dbpval = NULL;
 268  414                  char    *inpval = pargp->ia_pval;
 269  415                  char    pval[MAXPROPVALLEN];
 270  416                  char    *val, *lasts;
 271  417  
 272  418                  *errp = nvlist_lookup_string(db_nvl, pargp->ia_pname, &dbpval);
 273  419                  if (*errp != 0)
 274  420                          return (B_FALSE);
 275  421  
 276  422                  /*
 277  423                   * multi-valued properties are represented as comma separated
 278  424                   * values. Use string tokenizer functions to split them and
 279  425                   * search for the value to be removed.
 280  426                   */
 281  427                  bzero(pval, sizeof (pval));
 282  428                  if ((val = strtok_r(dbpval, ",", &lasts)) != NULL) {
 283  429                          if (strcmp(val, inpval) != 0)
 284  430                                  (void) strlcat(pval, val, MAXPROPVALLEN);
 285  431                          while ((val = strtok_r(NULL, ",", &lasts)) != NULL) {
 286  432                                  if (strcmp(val, inpval) != 0) {
 287  433                                          if (pval[0] != '\0')
 288  434                                                  (void) strlcat(pval, ",",
 289  435                                                      MAXPROPVALLEN);
 290  436                                          (void) strlcat(pval, val,
 291  437                                              MAXPROPVALLEN);
 292  438                                  }
 293  439                          }
 294  440                  } else {
 295  441                          if (strcmp(dbpval, inpval) != 0)
 296  442                                  *errp = ENOENT;
 297  443                          else
 298  444                                  buf[0] =  '\0';
 299  445                          return (B_FALSE);
 300  446                  }
 301  447                  *errp = nvlist_add_string(db_nvl, pargp->ia_pname, pval);
 302  448                  if (*errp != 0)
 303  449                          return (B_FALSE);
 304  450  
 305  451                  (void) memset(buf, 0, buflen);
 306  452                  if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
 307  453                          /* buffer overflow */
 308  454                          *errp = ENOBUFS;
 309  455                  }
 310  456          } else {
 311  457                  buf[0] = '\0';
 312  458          }
 313  459  
 314  460          /* stop the search */
 315  461          return (B_FALSE);
 316  462  }
 317  463  
 318  464  /*
 319  465   * Input arguments can have IPADM_NVP_AOBJNAME or IPADM_NVP_IFNAME. A match is
  
    | 
      ↓ open down ↓ | 
    228 lines elided | 
    
      ↑ open up ↑ | 
  
 320  466   * found, when one of the following occurs first.
 321  467   * - the input aobjname matches the db aobjname. Return the db address.
 322  468   * - the input interface matches the db interface. Return all the
 323  469   *   matching db lines with addresses.
 324  470   */
 325  471  /* ARGSUSED */
 326  472  boolean_t
 327  473  ipmgmt_db_getaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 328  474      int *errp)
 329  475  {
 330      -        ipmgmt_getaddr_cbarg_t  *cbarg = arg;
      476 +        ipmgmt_get_cbarg_t      *cbarg = arg;
 331  477          char            *db_aobjname = NULL;
 332  478          char            *db_ifname = NULL;
 333  479          nvlist_t        *db_addr = NULL;
 334  480          char            name[IPMGMT_STRSIZE];
 335  481          nvpair_t        *nvp;
 336  482          boolean_t       add_nvl = B_FALSE;
 337  483  
 338  484          /* Parse db nvlist */
 339  485          for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
 340  486              nvp = nvlist_next_nvpair(db_nvl, nvp)) {
 341  487                  if (nvpair_type(nvp) == DATA_TYPE_NVLIST)
 342  488                          (void) nvpair_value_nvlist(nvp, &db_addr);
 343  489                  else if (strcmp(nvpair_name(nvp), IPADM_NVP_IFNAME) == 0)
 344  490                          (void) nvpair_value_string(nvp, &db_ifname);
 345  491                  else if (strcmp(nvpair_name(nvp), IPADM_NVP_AOBJNAME) == 0)
 346  492                          (void) nvpair_value_string(nvp, &db_aobjname);
 347  493          }
 348  494  
 349  495          if (db_aobjname == NULL) /* Not an address */
 350  496                  return (B_TRUE);
 351  497  
 352  498          /* Check for a match between the aobjnames or the interface name */
 353  499          if (cbarg->cb_aobjname[0] != '\0') {
 354  500                  if (strcmp(cbarg->cb_aobjname, db_aobjname) == 0)
 355  501                          add_nvl = B_TRUE;
 356  502          } else if (cbarg->cb_ifname[0] != '\0') {
 357  503                  if (strcmp(cbarg->cb_ifname, db_ifname) == 0)
 358  504                          add_nvl = B_TRUE;
 359  505          } else {
 360  506                  add_nvl = B_TRUE;
 361  507          }
 362  508  
 363  509          if (add_nvl) {
 364  510                  (void) snprintf(name, sizeof (name), "%s_%d", db_ifname,
 365  511                      cbarg->cb_ocnt);
 366  512                  *errp = nvlist_add_nvlist(cbarg->cb_onvl, name, db_nvl);
 367  513                  if (*errp == 0)
 368  514                          cbarg->cb_ocnt++;
 369  515          }
 370  516          return (B_TRUE);
 371  517  }
 372  518  
 373  519  /*
 374  520   * This function only gets called if a volatile filesystem version
 375  521   * of the configuration file has been created. This only happens in the
 376  522   * extremely rare case that a request has been made to update the configuration
 377  523   * file at boottime while the root filesystem was read-only. This is
 378  524   * really a rare occurrence now that we don't support UFS root filesystems
 379  525   * any longer. This function will periodically attempt to write the
 380  526   * configuration back to its location on the root filesystem. Success
 381  527   * will indicate that the filesystem is no longer read-only.
 382  528   */
 383  529  /* ARGSUSED */
 384  530  static void *
 385  531  ipmgmt_db_restore_thread(void *arg)
 386  532  {
 387  533          int err;
 388  534  
 389  535          for (;;) {
 390  536                  (void) sleep(5);
 391  537                  (void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock);
 392  538                  if (!ipmgmt_rdonly_root)
 393  539                          break;
 394  540                  err = ipmgmt_cpfile(IPADM_VOL_DB_FILE, IPADM_DB_FILE, B_FALSE);
 395  541                  if (err == 0) {
 396  542                          ipmgmt_rdonly_root = B_FALSE;
 397  543                          break;
 398  544                  }
 399  545                  (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
 400  546          }
 401  547          (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
 402  548          return (NULL);
 403  549  }
 404  550  
 405  551  /*
 406  552   * This function takes the appropriate lock, read or write, based on the
 407  553   * `db_op' and then calls DB walker ipadm_rw_db(). The code is complicated
 408  554   * by the fact that we are not always guaranteed to have a writable root
 409  555   * filesystem since it is possible that we are reading or writing during
 410  556   * bootime while the root filesystem is still read-only. This is, by far,
 411  557   * the exception case. Normally, this function will be called when the
 412  558   * root filesystem is writable. In the unusual case where this is not
 413  559   * true, the configuration file is copied to the volatile file system
 414  560   * and is updated there until the root filesystem becomes writable. At
 415  561   * that time the file will be moved back to its proper location by
 416  562   * ipmgmt_db_restore_thread().
 417  563   */
 418  564  extern int
 419  565  ipmgmt_db_walk(db_wfunc_t *db_walk_func, void *db_warg, ipadm_db_op_t db_op)
 420  566  {
 421  567          int             err;
 422  568          boolean_t       writeop;
 423  569          mode_t          mode;
 424  570          pthread_t       tid;
 425  571          pthread_attr_t  attr;
 426  572  
 427  573          writeop = (db_op != IPADM_DB_READ);
 428  574          if (writeop) {
 429  575                  (void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock);
 430  576                  mode = IPADM_FILE_MODE;
 431  577          } else {
 432  578                  (void) pthread_rwlock_rdlock(&ipmgmt_dbconf_lock);
 433  579                  mode = 0;
 434  580          }
 435  581  
 436  582          /*
 437  583           * Did a previous write attempt fail? If so, don't even try to
 438  584           * read/write to IPADM_DB_FILE.
 439  585           */
 440  586          if (!ipmgmt_rdonly_root) {
 441  587                  err = ipadm_rw_db(db_walk_func, db_warg, IPADM_DB_FILE,
 442  588                      mode, db_op);
 443  589                  if (err != EROFS)
 444  590                          goto done;
 445  591          }
 446  592  
 447  593          /*
 448  594           * If we haven't already copied the file to the volatile
 449  595           * file system, do so. This should only happen on a failed
 450  596           * writeop(i.e., we have acquired the write lock above).
 451  597           */
 452  598          if (access(IPADM_VOL_DB_FILE, F_OK) != 0) {
 453  599                  assert(writeop);
 454  600                  err = ipmgmt_cpfile(IPADM_DB_FILE, IPADM_VOL_DB_FILE, B_TRUE);
 455  601                  if (err != 0)
 456  602                          goto done;
 457  603                  (void) pthread_attr_init(&attr);
 458  604                  (void) pthread_attr_setdetachstate(&attr,
 459  605                      PTHREAD_CREATE_DETACHED);
 460  606                  err = pthread_create(&tid, &attr, ipmgmt_db_restore_thread,
 461  607                      NULL);
 462  608                  (void) pthread_attr_destroy(&attr);
 463  609                  if (err != 0) {
 464  610                          (void) unlink(IPADM_VOL_DB_FILE);
 465  611                          goto done;
 466  612                  }
 467  613                  ipmgmt_rdonly_root = B_TRUE;
 468  614          }
 469  615  
 470  616          /*
 471  617           * Read/write from the volatile copy.
 472  618           */
 473  619          err = ipadm_rw_db(db_walk_func, db_warg, IPADM_VOL_DB_FILE,
 474  620              mode, db_op);
 475  621  done:
 476  622          (void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
 477  623          return (err);
 478  624  }
 479  625  
 480  626  /*
 481  627   * Used to add an entry towards the end of DB. It just returns B_TRUE for
 482  628   * every line of the DB. When we reach the end, ipadm_rw_db() adds the
 483  629   * line at the end.
 484  630   */
 485  631  /* ARGSUSED */
 486  632  boolean_t
 487  633  ipmgmt_db_add(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen, int *errp)
 488  634  {
 489  635          return (B_TRUE);
 490  636  }
 491  637  
 492  638  /*
 493  639   * This function is used to update or create an entry in DB. The nvlist_t,
 494  640   * `in_nvl', represents the line we are looking for. Once we ensure the right
 495  641   * line from DB, we update that entry.
 496  642   */
 497  643  boolean_t
 498  644  ipmgmt_db_update(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 499  645      int *errp)
 500  646  {
 501  647          ipadm_dbwrite_cbarg_t   *cb = arg;
 502  648          uint_t                  flags = cb->dbw_flags;
 503  649          nvlist_t                *in_nvl = cb->dbw_nvl;
 504  650          nvpair_t                *nvp;
 505  651          char                    *name, *instrval = NULL, *dbstrval = NULL;
 506  652          char                    pval[MAXPROPVALLEN];
 507  653  
 508  654          *errp = 0;
 509  655          if (!ipmgmt_nvlist_intersects(db_nvl, in_nvl))
 510  656                  return (B_TRUE);
 511  657  
 512  658          for (nvp = nvlist_next_nvpair(in_nvl, NULL); nvp != NULL;
 513  659              nvp = nvlist_next_nvpair(in_nvl, nvp)) {
 514  660                  name = nvpair_name(nvp);
 515  661                  if (!IPADM_PRIV_NVP(name) && nvlist_exists(db_nvl, name))
 516  662                          break;
 517  663          }
 518  664  
 519  665          if (nvp == NULL)
 520  666                  return (B_TRUE);
 521  667  
 522  668          assert(nvpair_type(nvp) == DATA_TYPE_STRING);
 523  669  
 524  670          if ((*errp = nvpair_value_string(nvp, &instrval)) != 0)
 525  671                  return (B_FALSE);
 526  672  
 527  673          /*
 528  674           * If IPMGMT_APPEND is set then we are dealing with multi-valued
 529  675           * properties. We append to the entry from the db, with the new value.
 530  676           */
 531  677          if (flags & IPMGMT_APPEND) {
 532  678                  if ((*errp = nvlist_lookup_string(db_nvl, name,
 533  679                      &dbstrval)) != 0)
 534  680                          return (B_FALSE);
 535  681                  (void) snprintf(pval, MAXPROPVALLEN, "%s,%s", dbstrval,
 536  682                      instrval);
 537  683                  if ((*errp = nvlist_add_string(db_nvl, name, pval)) != 0)
 538  684                          return (B_FALSE);
 539  685          } else {
 540  686                  /* case of in-line update of a db entry */
 541  687                  if ((*errp = nvlist_add_string(db_nvl, name, instrval)) != 0)
 542  688                          return (B_FALSE);
 543  689          }
 544  690  
 545  691          (void) memset(buf, 0, buflen);
  
    | 
      ↓ open down ↓ | 
    205 lines elided | 
    
      ↑ open up ↑ | 
  
 546  692          if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
 547  693                  /* buffer overflow */
 548  694                  *errp = ENOBUFS;
 549  695          }
 550  696  
 551  697          /* we updated the DB entry, so do not continue */
 552  698          return (B_FALSE);
 553  699  }
 554  700  
 555  701  /*
 556      - * For the given `cbarg->cb_ifname' interface, retrieves any persistent
 557      - * interface information (used in 'ipadm show-if')
      702 + * This function is used to update a DB line that describes
      703 + * an interface, its family and group interface
      704 + *
 558  705   */
 559      -/* ARGSUSED */
 560  706  boolean_t
 561      -ipmgmt_db_getif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
      707 +ipmgmt_db_update_if(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 562  708      int *errp)
 563  709  {
 564      -        ipmgmt_getif_cbarg_t    *cbarg = arg;
 565      -        char                    *ifname = cbarg->cb_ifname;
 566      -        char                    *intf = NULL;
 567      -        ipadm_if_info_t         *ifp = NULL;
 568      -        sa_family_t             af;
 569      -        char                    *afstr;
      710 +        ipadm_dbwrite_cbarg_t *cb = arg;
      711 +        ipmgmt_if_updater_ent_t *updater;
      712 +        nvlist_t        *in_nvl = cb->dbw_nvl;
      713 +        uint_t          flags = cb->dbw_flags;
      714 +        nvpair_t        *nvp;
      715 +        char            *name;
      716 +        char            *db_ifname;
      717 +        char            *gifname = NULL;
      718 +        char            *mifname = NULL;
 570  719  
 571  720          *errp = 0;
 572      -        if (nvlist_lookup_string(db_nvl, IPADM_NVP_FAMILY, &afstr) != 0 ||
 573      -            nvlist_lookup_string(db_nvl, IPADM_NVP_IFNAME, &intf) != 0 ||
 574      -            (ifname[0] != '\0' && strcmp(ifname, intf) != 0)) {
      721 +
      722 +        /* Only one flag */
      723 +        if ((flags & (IPMGMT_APPEND | IPMGMT_REMOVE)) == 0 ||
      724 +            ((flags & IPMGMT_APPEND) && (flags & IPMGMT_REMOVE))) {
      725 +                *errp = EINVAL;
      726 +                return (B_FALSE);
      727 +        }
      728 +
      729 +        if (!nvlist_exists(db_nvl, IPADM_NVP_FAMILIES))
 575  730                  return (B_TRUE);
      731 +
      732 +        if (nvlist_exists(db_nvl, IPADM_NVP_IFCLASS) &&
      733 +            nvlist_lookup_string(db_nvl, IPADM_NVP_IFNAME, &db_ifname) == 0 &&
      734 +            nvlist_lookup_string(in_nvl, IPADM_NVP_GIFNAME, &gifname) == 0 &&
      735 +            nvlist_lookup_string(in_nvl, IPADM_NVP_MIFNAMES, &mifname) == 0 &&
      736 +            strcmp(db_ifname, mifname) == 0) {
      737 +                if (flags & IPMGMT_APPEND) {
      738 +                        if ((*errp = nvlist_add_string(db_nvl,
      739 +                            IPADM_NVP_GIFNAME, gifname)) != 0)
      740 +                                return (B_FALSE);
      741 +                } else {
      742 +                        if ((*errp = nvlist_remove(db_nvl, IPADM_NVP_GIFNAME,
      743 +                            DATA_TYPE_STRING)) != 0)
      744 +                                return (B_FALSE);
      745 +                }
      746 +                cb->dbw_flags &= ~IPMGMT_UPDATE_IPMP;
      747 +                goto done;
 576  748          }
 577      -        af = atoi(afstr);
 578      -        for (ifp = cbarg->cb_ifinfo; ifp != NULL; ifp = ifp->ifi_next) {
 579      -                if (strcmp(ifp->ifi_name, intf) == 0)
 580      -                        break;
      749 +
      750 +        if (!ipmgmt_nvlist_intersects(db_nvl, in_nvl))
      751 +                return (B_TRUE);
      752 +
      753 +        for (nvp = nvlist_next_nvpair(in_nvl, NULL); nvp != NULL;
      754 +            nvp = nvlist_next_nvpair(in_nvl, nvp)) {
      755 +                name = nvpair_name(nvp);
      756 +                if (strcmp(name, IPADM_NVP_FAMILIES) != 0 &&
      757 +                    strcmp(name, IPADM_NVP_MIFNAMES) != 0)
      758 +                        continue;
      759 +
      760 +                updater = ipmgmt_find_if_field_updater(name);
      761 +                assert(updater != NULL);
      762 +                *errp = (*updater->func)(db_nvl, nvp, flags);
      763 +                if (*errp != 0)
      764 +                        return (B_FALSE);
 581  765          }
 582      -        if (ifp == NULL) {
 583      -                ipadm_if_info_t *new;
 584  766  
 585      -                if ((new = calloc(1, sizeof (*new))) == NULL) {
 586      -                        *errp = ENOMEM;
 587      -                        return (B_FALSE); /* don't continue the walk */
 588      -                }
 589      -                new->ifi_next = cbarg->cb_ifinfo;
 590      -                cbarg->cb_ifinfo = new;
 591      -                ifp = new;
 592      -                (void) strlcpy(ifp->ifi_name, intf, sizeof (ifp->ifi_name));
      767 +        cb->dbw_flags &= ~IPMGMT_UPDATE_IF;
      768 +
      769 +done:
      770 +        (void) memset(buf, 0, buflen);
      771 +        if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
      772 +                *errp = ENOBUFS;
      773 +                return (B_FALSE);
 593  774          }
 594  775  
 595      -        if (af == AF_INET) {
 596      -                ifp->ifi_pflags |= IFIF_IPV4;
 597      -        } else {
 598      -                assert(af == AF_INET6);
 599      -                ifp->ifi_pflags |= IFIF_IPV6;
      776 +        /* we finished all operations, so do not continue */
      777 +        if ((cb->dbw_flags & (IPMGMT_UPDATE_IF | IPMGMT_UPDATE_IPMP)) == 0)
      778 +                return (B_FALSE);
      779 +
      780 +        return (B_TRUE);
      781 +}
      782 +
      783 +/*
      784 + * For the given `cbarg->cb_ifname' interface retrieves
      785 + * the nvlist that represents the persistent interface information
      786 + * The nvlist contains:
      787 + *      IPADM_NVP_IFNAME
      788 + *      IPADM_NVP_FAMILIES
      789 + *      IPADM_NVP_IF_CLASS
      790 + *
      791 + * (used in 'ipadm show-if')
      792 + */
      793 +/* ARGSUSED */
      794 +boolean_t
      795 +ipmgmt_db_getif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
      796 +    int *errp)
      797 +{
      798 +        ipmgmt_get_cbarg_t *cbarg = arg;
      799 +        char            *ifname = cbarg->cb_ifname;
      800 +        nvpair_t        *nvp;
      801 +        char            *db_ifname = NULL;
      802 +        uint16_t        *db_families = NULL;
      803 +        uint_t          nelem = 0;
      804 +
      805 +        /* Parse db nvlist */
      806 +        for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
      807 +            nvp = nvlist_next_nvpair(db_nvl, nvp)) {
      808 +                if (strcmp(nvpair_name(nvp), IPADM_NVP_IFNAME) == 0) {
      809 +                        (void) nvpair_value_string(nvp, &db_ifname);
      810 +                } else if (strcmp(nvpair_name(nvp), IPADM_NVP_FAMILIES) == 0) {
      811 +                        (void) nvpair_value_uint16_array(nvp,
      812 +                            &db_families, &nelem);
      813 +                }
 600  814          }
 601  815  
 602      -        /* Terminate the walk if we found both v4 and v6 interfaces. */
 603      -        if (ifname[0] != '\0' && (ifp->ifi_pflags & IFIF_IPV4) &&
 604      -            (ifp->ifi_pflags & IFIF_IPV6))
      816 +        if (db_ifname == NULL || db_families == NULL)
      817 +                return (B_TRUE);
      818 +
      819 +        if (ifname != NULL && ifname[0] != '\0' &&
      820 +            strcmp(ifname, db_ifname) != 0)
      821 +                return (B_TRUE);
      822 +
      823 +        *errp = nvlist_add_nvlist(cbarg->cb_onvl, db_ifname, db_nvl);
      824 +        if (*errp == 0)
      825 +                cbarg->cb_ocnt++;
      826 +
      827 +        if (ifname != NULL && ifname[0] != '\0')
 605  828                  return (B_FALSE);
 606  829  
 607  830          return (B_TRUE);
 608  831  }
 609  832  
 610  833  /*
 611  834   * Deletes those entries from the database for which interface name
 612  835   * matches with the given `cbarg->cb_ifname'
 613  836   */
 614  837  /* ARGSUSED */
 615  838  boolean_t
 616  839  ipmgmt_db_resetif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 617  840      int *errp)
 618  841  {
 619  842          ipmgmt_if_cbarg_t *cbarg = arg;
 620  843          boolean_t       isv6 = (cbarg->cb_family == AF_INET6);
 621  844          char            *ifname = cbarg->cb_ifname;
 622  845          char            *modstr = NULL;
 623      -        char            *afstr;
 624  846          char            *aobjname;
 625  847          uint_t          proto;
 626  848          ipmgmt_aobjmap_t *head;
 627  849          boolean_t       aobjfound = B_FALSE;
 628  850  
 629  851          *errp = 0;
 630  852  
 631  853          if (!ipmgmt_nvlist_contains(db_nvl, NULL, ifname, NULL))
 632  854                  return (B_TRUE);
 633  855  
 634      -        if (nvlist_lookup_string(db_nvl, IPADM_NVP_FAMILY, &afstr) == 0) {
 635      -                if (atoi(afstr) == cbarg->cb_family)
      856 +        if (nvlist_exists(db_nvl, IPADM_NVP_FAMILIES)) {
      857 +
      858 +                if ((*errp = ipmgmt_update_family_nvp(db_nvl, cbarg->cb_family,
      859 +                    IPMGMT_REMOVE)) != 0) {
      860 +                        return (B_FALSE);
      861 +                }
      862 +
      863 +                if (cbarg->cb_family == AF_INET) {
      864 +                        cbarg->cb_ipv4exists = B_FALSE;
      865 +                } else {
      866 +                        assert(cbarg->cb_family == AF_INET6);
      867 +                        cbarg->cb_ipv6exists = B_FALSE;
      868 +                }
      869 +                if (!nvlist_exists(db_nvl, IPADM_NVP_FAMILIES)) {
      870 +                        cbarg->cb_ipv4exists = B_FALSE;
      871 +                        cbarg->cb_ipv6exists = B_FALSE;
 636  872                          goto delete;
      873 +                }
      874 +                /* Otherwise need to reconstruct this string */
      875 +                (void) memset(buf, 0, buflen);
      876 +                if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
      877 +                        /* buffer overflow */
      878 +                        *errp = ENOBUFS;
      879 +                        return (B_FALSE);
      880 +                }
 637  881                  return (B_TRUE);
 638  882          }
 639  883  
 640  884          /* Reset all the interface configurations for 'ifname' */
 641  885          if (isv6 && (nvlist_exists(db_nvl, IPADM_NVP_IPV6ADDR) ||
 642  886              nvlist_exists(db_nvl, IPADM_NVP_INTFID))) {
 643  887                  goto delete;
 644  888          }
 645  889          if (!isv6 &&
 646  890              (nvlist_exists(db_nvl, IPADM_NVP_IPV4ADDR) ||
 647  891              nvlist_exists(db_nvl, IPADM_NVP_DHCP))) {
 648  892                  goto delete;
 649  893          }
 650  894  
 651  895          if (nvlist_lookup_string(db_nvl, IPADM_NVP_AOBJNAME, &aobjname) == 0) {
 652  896                  /*
 653  897                   * This must be an address property. Delete this
 654  898                   * line if there is a match in the address family.
 655  899                   */
 656  900                  head = aobjmap.aobjmap_head;
 657  901                  while (head != NULL) {
 658  902                          if (strcmp(head->am_aobjname, aobjname) == 0) {
 659  903                                  aobjfound = B_TRUE;
 660  904                                  if (head->am_family == cbarg->cb_family)
 661  905                                          goto delete;
 662  906                          }
 663  907                          head = head->am_next;
 664  908                  }
 665  909                  /*
 666  910                   * If aobjfound = B_FALSE, then this address is not
 667  911                   * available in active configuration. We should go ahead
 668  912                   * and delete it.
 669  913                   */
 670  914                  if (!aobjfound)
 671  915                          goto delete;
 672  916          }
 673  917  
 674  918          /*
 675  919           * If we are removing both v4 and v6 interface, then we get rid of
 676  920           * all the properties for that interface. On the other hand, if we
 677  921           * are deleting only v4 instance of an interface, then we delete v4
 678  922           * properties only.
 679  923           */
 680  924          if (nvlist_lookup_string(db_nvl, IPADM_NVP_PROTONAME, &modstr) == 0) {
 681  925                  proto = ipadm_str2proto(modstr);
  
    | 
      ↓ open down ↓ | 
    35 lines elided | 
    
      ↑ open up ↑ | 
  
 682  926                  switch (proto) {
 683  927                  case MOD_PROTO_IPV6:
 684  928                          if (isv6)
 685  929                                  goto delete;
 686  930                          break;
 687  931                  case MOD_PROTO_IPV4:
 688  932                          if (!isv6)
 689  933                                  goto delete;
 690  934                          break;
 691  935                  case MOD_PROTO_IP:
 692      -                        /* this should never be the case, today */
 693      -                        assert(0);
      936 +                        if (!cbarg->cb_ipv4exists && !cbarg->cb_ipv6exists)
      937 +                                goto delete;
 694  938                          break;
 695  939                  }
 696  940          }
 697  941          /* Not found a match yet. Continue processing the db */
 698  942          return (B_TRUE);
 699  943  delete:
 700  944          /* delete the line from the db */
 701  945          buf[0] = '\0';
 702  946          return (B_TRUE);
 703  947  }
 704  948  
 705  949  /*
 706  950   * Deletes those entries from the database for which address object name
 707  951   * matches with the given `cbarg->cb_aobjname'
 708  952   */
 709  953  /* ARGSUSED */
 710  954  boolean_t
 711  955  ipmgmt_db_resetaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 712  956      int *errp)
 713  957  {
 714  958          ipmgmt_resetaddr_cbarg_t *cbarg = arg;
 715  959          char            *aobjname = cbarg->cb_aobjname;
 716  960  
 717  961          *errp = 0;
 718  962          if (!ipmgmt_nvlist_contains(db_nvl, NULL, NULL, aobjname))
 719  963                  return (B_TRUE);
 720  964  
 721  965          /* delete the line from the db */
 722  966          buf[0] = '\0';
 723  967          return (B_TRUE);
 724  968  }
 725  969  
 726  970  /*
 727  971   * Retrieves all interface props, including addresses, for given interface(s).
 728  972   * `invl' contains the list of interfaces, for which information need to be
 729  973   * retrieved.
 730  974   */
 731  975  /* ARGSUSED */
 732  976  boolean_t
 733  977  ipmgmt_db_initif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 734  978      int *errp)
 735  979  {
 736  980          ipmgmt_initif_cbarg_t   *cbarg = arg;
 737  981          nvlist_t                *onvl = cbarg->cb_onvl;
 738  982          nvlist_t                *invl = cbarg->cb_invl;
 739  983          sa_family_t             in_af = cbarg->cb_family;
 740  984          char                    *db_ifname;
 741  985  
 742  986          *errp = 0;
 743  987          if (nvlist_lookup_string(db_nvl, IPADM_NVP_IFNAME, &db_ifname) == 0 &&
 744  988              nvlist_exists(invl, db_ifname)) {
 745  989                  char            name[IPMGMT_STRSIZE];
 746  990                  sa_family_t     db_af = in_af;
 747  991                  uint_t          proto;
 748  992                  char            *pstr;
 749  993  
 750  994                  if (in_af != AF_UNSPEC) {
 751  995                          if (nvlist_lookup_string(db_nvl, IPADM_NVP_PROTONAME,
 752  996                              &pstr) == 0) {
 753  997                                  proto = ipadm_str2proto(pstr);
 754  998                                  if (proto == MOD_PROTO_IPV4)
 755  999                                          db_af = AF_INET;
 756 1000                                  else if (proto == MOD_PROTO_IPV6)
 757 1001                                          db_af = AF_INET6;
 758 1002                                  else
 759 1003                                          db_af = in_af;
 760 1004                          } else {
 761 1005                                  if (nvlist_exists(db_nvl, IPADM_NVP_IPV4ADDR) ||
 762 1006                                      nvlist_exists(db_nvl, IPADM_NVP_DHCP))
 763 1007                                          db_af = AF_INET;
 764 1008                                  else
 765 1009                                          db_af = AF_INET6;
 766 1010                          }
 767 1011                  }
 768 1012                  if (in_af == db_af) {
 769 1013                          (void) snprintf(name, sizeof (name), "%s_%d", db_ifname,
 770 1014                              cbarg->cb_ocnt);
 771 1015                          *errp = nvlist_add_nvlist(onvl, name, db_nvl);
 772 1016                          if (*errp == 0)
 773 1017                                  cbarg->cb_ocnt++;
 774 1018                  }
 775 1019          }
 776 1020          return (B_TRUE);
 777 1021  }
 778 1022  
 779 1023  /*
 780 1024   * helper function for ipmgmt_aobjmap_op(). Adds the node pointed by `nodep'
 781 1025   * into `aobjmap' structure.
 782 1026   */
 783 1027  static int
 784 1028  i_ipmgmt_add_amnode(ipmgmt_aobjmap_t *nodep)
 785 1029  {
 786 1030          ipmgmt_aobjmap_t        *new, *head;
 787 1031  
 788 1032          head = aobjmap.aobjmap_head;
 789 1033          if ((new = malloc(sizeof (ipmgmt_aobjmap_t))) == NULL)
 790 1034                  return (ENOMEM);
 791 1035          *new = *nodep;
 792 1036          new->am_next = NULL;
 793 1037  
 794 1038          /* Add the node at the beginning of the list */
 795 1039          if (head == NULL) {
 796 1040                  aobjmap.aobjmap_head = new;
 797 1041          } else {
 798 1042                  new->am_next = aobjmap.aobjmap_head;
 799 1043                  aobjmap.aobjmap_head = new;
 800 1044          }
 801 1045          return (0);
 802 1046  }
 803 1047  
 804 1048  /*
 805 1049   * A recursive function to generate alphabetized number given a decimal number.
 806 1050   * Decimal 0 to 25 maps to 'a' to 'z' and then the counting continues with 'aa',
 807 1051   * 'ab', 'ac', et al.
 808 1052   */
 809 1053  static void
 810 1054  i_ipmgmt_num2priv_aobjname(uint32_t num, char **cp, char *endp)
 811 1055  {
 812 1056          if (num >= 26)
 813 1057                  i_ipmgmt_num2priv_aobjname(num / 26 - 1, cp, endp);
 814 1058          if (*cp != endp) {
 815 1059                  *cp[0] = 'a' + (num % 26);
 816 1060                  (*cp)++;
 817 1061          }
 818 1062  }
 819 1063  
 820 1064  /*
 821 1065   * This function generates an `aobjname', when required, and then does
 822 1066   * lookup-add. If `nodep->am_aobjname' is not an empty string, then it walks
 823 1067   * through the `aobjmap' to check if an address object with the same
 824 1068   * `nodep->am_aobjname' exists. If it exists, EEXIST is returned as duplicate
 825 1069   * `aobjname's are not allowed.
 826 1070   *
 827 1071   * If `nodep->am_aobjname' is an empty string then the daemon generates an
 828 1072   * `aobjname' using the `am_nextnum', which contains the next number to be
 829 1073   * used to generate `aobjname'. `am_nextnum' is converted to base26 using
 830 1074   * `a-z' alphabets in i_ipmgmt_num2priv_aobjname().
 831 1075   *
 832 1076   * `am_nextnum' will be 0 to begin with. Every time an address object that
 833 1077   * needs `aobjname' is added it's incremented by 1. So for the first address
 834 1078   * object on net0 the `am_aobjname' will be net0/_a and `am_nextnum' will be 1.
 835 1079   * For the second address object on that interface `am_aobjname' will be net0/_b
 836 1080   * and  `am_nextnum' will incremented to 2.
 837 1081   */
 838 1082  static int
 839 1083  i_ipmgmt_lookupadd_amnode(ipmgmt_aobjmap_t *nodep)
 840 1084  {
 841 1085          ipmgmt_aobjmap_t        *head;
 842 1086          uint32_t                nextnum;
 843 1087  
 844 1088          for (head = aobjmap.aobjmap_head; head != NULL; head = head->am_next)
 845 1089                  if (strcmp(head->am_ifname, nodep->am_ifname) == 0)
 846 1090                          break;
 847 1091          nextnum = (head == NULL ? 0 : head->am_nextnum);
 848 1092  
 849 1093          /*
 850 1094           * if `aobjname' is empty, then the daemon has to generate the
 851 1095           * next `aobjname' for the given interface and family.
 852 1096           */
 853 1097          if (nodep->am_aobjname[0] == '\0') {
 854 1098                  char tmpstr[IPADM_AOBJ_USTRSIZ - 1];  /* 1 for leading  '_' */
 855 1099                  char *cp = tmpstr;
 856 1100                  char *endp = tmpstr + sizeof (tmpstr);
 857 1101  
 858 1102                  i_ipmgmt_num2priv_aobjname(nextnum, &cp, endp);
 859 1103  
 860 1104                  if (cp == endp)
 861 1105                          return (EINVAL);
 862 1106                  cp[0] = '\0';
 863 1107  
 864 1108                  if (snprintf(nodep->am_aobjname, IPADM_AOBJSIZ, "%s/_%s",
 865 1109                      nodep->am_ifname, tmpstr) >= IPADM_AOBJSIZ) {
 866 1110                          return (EINVAL);
 867 1111                  }
 868 1112                  nodep->am_nextnum = ++nextnum;
 869 1113          } else {
 870 1114                  for (head = aobjmap.aobjmap_head; head != NULL;
 871 1115                      head = head->am_next) {
 872 1116                          if (strcmp(head->am_aobjname, nodep->am_aobjname) == 0)
 873 1117                                  return (EEXIST);
 874 1118                  }
 875 1119                  nodep->am_nextnum = nextnum;
 876 1120          }
 877 1121          return (i_ipmgmt_add_amnode(nodep));
 878 1122  }
 879 1123  
 880 1124  /*
 881 1125   * Performs following operations on the global `aobjmap' linked list.
 882 1126   * (a) ADDROBJ_ADD: add or update address object in `aobjmap'
  
    | 
      ↓ open down ↓ | 
    179 lines elided | 
    
      ↑ open up ↑ | 
  
 883 1127   * (b) ADDROBJ_DELETE: delete address object from `aobjmap'
 884 1128   * (c) ADDROBJ_LOOKUPADD: place a stub address object in `aobjmap'
 885 1129   * (d) ADDROBJ_SETLIFNUM: Sets the lifnum for an address object in `aobjmap'
 886 1130   */
 887 1131  int
 888 1132  ipmgmt_aobjmap_op(ipmgmt_aobjmap_t *nodep, uint32_t op)
 889 1133  {
 890 1134          ipmgmt_aobjmap_t        *head, *prev, *matched = NULL;
 891 1135          boolean_t               update = B_TRUE;
 892 1136          int                     err = 0;
 893      -        ipadm_db_op_t           db_op;
     1137 +        ipadm_db_op_t           db_op = IPADM_DB_READ;
 894 1138  
 895 1139          (void) pthread_rwlock_wrlock(&aobjmap.aobjmap_rwlock);
 896 1140  
 897 1141          head = aobjmap.aobjmap_head;
 898 1142          switch (op) {
 899 1143          case ADDROBJ_ADD:
 900 1144                  /*
 901 1145                   * check for stub nodes (added by ADDROBJ_LOOKUPADD) and
 902 1146                   * update, else add the new node.
 903 1147                   */
 904 1148                  for (; head != NULL; head = head->am_next) {
 905 1149                          /*
 906 1150                           * For IPv6, we need to distinguish between the
 907 1151                           * linklocal and non-linklocal nodes
 908 1152                           */
 909 1153                          if (strcmp(head->am_aobjname,
 910 1154                              nodep->am_aobjname) == 0 &&
 911 1155                              (head->am_atype != IPADM_ADDR_IPV6_ADDRCONF ||
 912 1156                              head->ipmgmt_am_linklocal ==
 913 1157                              nodep->ipmgmt_am_linklocal))
 914 1158                                  break;
 915 1159                  }
 916 1160  
 917 1161                  if (head != NULL) {
 918 1162                          /* update the node */
 919 1163                          (void) strlcpy(head->am_ifname, nodep->am_ifname,
 920 1164                              sizeof (head->am_ifname));
 921 1165                          head->am_lnum = nodep->am_lnum;
 922 1166                          head->am_family = nodep->am_family;
 923 1167                          head->am_flags = nodep->am_flags;
 924 1168                          head->am_atype = nodep->am_atype;
 925 1169                          head->am_atype_cache = nodep->am_atype_cache;
 926 1170                  } else {
 927 1171                          for (head = aobjmap.aobjmap_head; head != NULL;
 928 1172                              head = head->am_next) {
 929 1173                                  if (strcmp(head->am_ifname,
 930 1174                                      nodep->am_ifname) == 0)
 931 1175                                          break;
 932 1176                          }
 933 1177                          nodep->am_nextnum = (head == NULL ? 0 :
 934 1178                              head->am_nextnum);
 935 1179                          err = i_ipmgmt_add_amnode(nodep);
 936 1180                  }
 937 1181                  db_op = IPADM_DB_WRITE;
 938 1182                  break;
 939 1183          case ADDROBJ_DELETE:
 940 1184                  prev = head;
 941 1185                  while (head != NULL) {
 942 1186                          if (strcmp(head->am_aobjname,
 943 1187                              nodep->am_aobjname) == 0) {
 944 1188                                  nodep->am_atype = head->am_atype;
 945 1189                                  /*
 946 1190                                   * There could be multiple IPV6_ADDRCONF nodes,
 947 1191                                   * with same address object name, so check for
 948 1192                                   * logical number also.
 949 1193                                   */
 950 1194                                  if (head->am_atype !=
 951 1195                                      IPADM_ADDR_IPV6_ADDRCONF ||
 952 1196                                      nodep->am_lnum == head->am_lnum)
 953 1197                                          break;
 954 1198                          }
 955 1199                          prev = head;
 956 1200                          head = head->am_next;
 957 1201                  }
 958 1202                  if (head != NULL) {
 959 1203                          /*
 960 1204                           * If the address object is in both active and
 961 1205                           * persistent configuration and the user is deleting it
 962 1206                           * only from active configuration then mark this node
 963 1207                           * for deletion by reseting IPMGMT_ACTIVE bit.
 964 1208                           * With this the same address object name cannot
 965 1209                           * be reused until it is permanently removed.
 966 1210                           */
 967 1211                          if (head->am_flags == (IPMGMT_ACTIVE|IPMGMT_PERSIST) &&
 968 1212                              nodep->am_flags == IPMGMT_ACTIVE) {
 969 1213                                  /* Update flags in the in-memory map. */
 970 1214                                  head->am_flags &= ~IPMGMT_ACTIVE;
 971 1215                                  head->am_lnum = -1;
 972 1216  
 973 1217                                  /* Update info in file. */
 974 1218                                  db_op = IPADM_DB_WRITE;
 975 1219                                  *nodep = *head;
 976 1220                          } else {
 977 1221                                  (void) strlcpy(nodep->am_ifname,
 978 1222                                      head->am_ifname,
 979 1223                                      sizeof (nodep->am_ifname));
 980 1224                                  /* otherwise delete the node */
 981 1225                                  if (head == aobjmap.aobjmap_head)
 982 1226                                          aobjmap.aobjmap_head = head->am_next;
 983 1227                                  else
 984 1228                                          prev->am_next = head->am_next;
 985 1229                                  free(head);
 986 1230                                  db_op = IPADM_DB_DELETE;
 987 1231                          }
 988 1232                  } else {
 989 1233                          err = ENOENT;
 990 1234                  }
 991 1235                  break;
 992 1236          case ADDROBJ_LOOKUPADD:
 993 1237                  err = i_ipmgmt_lookupadd_amnode(nodep);
 994 1238                  update = B_FALSE;
 995 1239                  break;
 996 1240          case ADDROBJ_SETLIFNUM:
 997 1241                  update = B_FALSE;
 998 1242                  for (; head != NULL; head = head->am_next) {
 999 1243                          if (strcmp(head->am_ifname,
1000 1244                              nodep->am_ifname) == 0 &&
1001 1245                              head->am_family == nodep->am_family &&
1002 1246                              head->am_lnum == nodep->am_lnum) {
1003 1247                                  err = EEXIST;
1004 1248                                  break;
1005 1249                          }
1006 1250                          if (strcmp(head->am_aobjname,
1007 1251                              nodep->am_aobjname) == 0) {
1008 1252                                  matched = head;
1009 1253                          }
1010 1254                  }
1011 1255                  if (err == EEXIST)
1012 1256                          break;
1013 1257                  if (matched != NULL) {
1014 1258                          /* update the lifnum */
1015 1259                          matched->am_lnum = nodep->am_lnum;
1016 1260                  } else {
1017 1261                          err = ENOENT;
1018 1262                  }
1019 1263                  break;
1020 1264          default:
1021 1265                  assert(0);
1022 1266          }
1023 1267  
1024 1268          if (err == 0 && update)
1025 1269                  err = ipmgmt_persist_aobjmap(nodep, db_op);
1026 1270  
1027 1271          (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
1028 1272  
1029 1273          return (err);
1030 1274  }
1031 1275  
1032 1276  /*
1033 1277   * Given a node in `aobjmap', this function converts it into nvlist_t structure.
1034 1278   * The content to be written to DB must be represented as nvlist_t.
1035 1279   */
1036 1280  static int
1037 1281  i_ipmgmt_node2nvl(nvlist_t **nvl, ipmgmt_aobjmap_t *np)
1038 1282  {
1039 1283          int     err;
1040 1284          char    strval[IPMGMT_STRSIZE];
1041 1285  
1042 1286          *nvl = NULL;
1043 1287          if ((err = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0)) != 0)
1044 1288                  goto fail;
1045 1289  
1046 1290          if ((err = nvlist_add_string(*nvl, IPADM_NVP_AOBJNAME,
1047 1291              np->am_aobjname)) != 0)
1048 1292                  goto fail;
1049 1293  
1050 1294          if ((err = nvlist_add_string(*nvl, IPADM_NVP_IFNAME,
1051 1295              np->am_ifname)) != 0)
1052 1296                  goto fail;
1053 1297  
1054 1298          (void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_lnum);
1055 1299          if ((err = nvlist_add_string(*nvl, IPADM_NVP_LIFNUM, strval)) != 0)
1056 1300                  goto fail;
1057 1301  
1058 1302          (void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_family);
1059 1303          if ((err = nvlist_add_string(*nvl, IPADM_NVP_FAMILY, strval)) != 0)
1060 1304                  goto fail;
1061 1305  
1062 1306          (void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_flags);
1063 1307          if ((err = nvlist_add_string(*nvl, FLAGS, strval)) != 0)
1064 1308                  goto fail;
1065 1309  
1066 1310          (void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_atype);
1067 1311          if ((err = nvlist_add_string(*nvl, ATYPE, strval)) != 0)
1068 1312                  goto fail;
1069 1313  
1070 1314          switch (np->am_atype) {
1071 1315                  case IPADM_ADDR_IPV6_ADDRCONF: {
1072 1316                          struct sockaddr_in6     *in6;
1073 1317  
1074 1318                          in6 = &np->ipmgmt_am_ifid;
1075 1319                          if (np->ipmgmt_am_linklocal &&
1076 1320                              IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr)) {
1077 1321                                  if ((err = nvlist_add_string(*nvl,
1078 1322                                      IPADM_NVP_IPNUMADDR, "default")) != 0) {
1079 1323                                          goto fail;
1080 1324                                  }
1081 1325                          } else {
1082 1326                                  if (inet_ntop(AF_INET6, &in6->sin6_addr, strval,
1083 1327                                      IPMGMT_STRSIZE) == NULL) {
1084 1328                                          err = errno;
1085 1329                                          goto fail;
1086 1330                                  }
1087 1331                                  if ((err = nvlist_add_string(*nvl,
1088 1332                                      IPADM_NVP_IPNUMADDR, strval)) != 0) {
1089 1333                                          goto fail;
1090 1334                                  }
1091 1335                          }
1092 1336                  }
1093 1337                          break;
1094 1338                  case IPADM_ADDR_DHCP: {
1095 1339                          if (np->ipmgmt_am_reqhost &&
1096 1340                              *np->ipmgmt_am_reqhost != '\0' &&
1097 1341                              (err = nvlist_add_string(*nvl, IPADM_NVP_REQHOST,
1098 1342                              np->ipmgmt_am_reqhost)) != 0)
1099 1343                                  goto fail;
1100 1344                  }
1101 1345                          /* FALLTHRU */
1102 1346                  default:
1103 1347                          if ((err = nvlist_add_string(*nvl, IPADM_NVP_IPNUMADDR,
1104 1348                              "")) != 0)
1105 1349                                  goto fail;
1106 1350                          break;
1107 1351          }
1108 1352          return (err);
1109 1353  fail:
1110 1354          nvlist_free(*nvl);
1111 1355          return (err);
1112 1356  }
1113 1357  
1114 1358  /*
1115 1359   * Read the aobjmap data store and build the in-memory representation
1116 1360   * of the aobjmap. We don't need to hold any locks while building this as
1117 1361   * we do this in very early stage of daemon coming up, even before the door
1118 1362   * is opened.
1119 1363   */
1120 1364  /* ARGSUSED */
1121 1365  extern boolean_t
1122 1366  ipmgmt_aobjmap_init(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
1123 1367      int *errp)
1124 1368  {
1125 1369          nvpair_t                *nvp = NULL;
1126 1370          char                    *name, *strval = NULL;
1127 1371          ipmgmt_aobjmap_t        node;
1128 1372          struct sockaddr_in6     *in6;
1129 1373  
1130 1374          *errp = 0;
1131 1375          node.am_next = NULL;
1132 1376          for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
1133 1377              nvp = nvlist_next_nvpair(db_nvl, nvp)) {
1134 1378                  name = nvpair_name(nvp);
1135 1379  
1136 1380                  if ((*errp = nvpair_value_string(nvp, &strval)) != 0)
1137 1381                          return (B_TRUE);
1138 1382                  if (strcmp(IPADM_NVP_AOBJNAME, name) == 0) {
1139 1383                          (void) strlcpy(node.am_aobjname, strval,
1140 1384                              sizeof (node.am_aobjname));
1141 1385                  } else if (strcmp(IPADM_NVP_IFNAME, name) == 0) {
1142 1386                          (void) strlcpy(node.am_ifname, strval,
1143 1387                              sizeof (node.am_ifname));
1144 1388                  } else if (strcmp(IPADM_NVP_LIFNUM, name) == 0) {
1145 1389                          node.am_lnum = atoi(strval);
1146 1390                  } else if (strcmp(IPADM_NVP_FAMILY, name) == 0) {
1147 1391                          node.am_family = (sa_family_t)atoi(strval);
1148 1392                  } else if (strcmp(FLAGS, name) == 0) {
1149 1393                          node.am_flags = atoi(strval);
1150 1394                  } else if (strcmp(ATYPE, name) == 0) {
1151 1395                          node.am_atype = (ipadm_addr_type_t)atoi(strval);
1152 1396                  } else if (strcmp(IPADM_NVP_IPNUMADDR, name) == 0) {
1153 1397                          if (node.am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
1154 1398                                  in6 = &node.ipmgmt_am_ifid;
1155 1399                                  if (strcmp(strval, "default") == 0) {
1156 1400                                          bzero(in6,
1157 1401                                              sizeof (node.ipmgmt_am_ifid));
1158 1402                                          node.ipmgmt_am_linklocal = B_TRUE;
1159 1403                                  } else {
1160 1404                                          (void) inet_pton(AF_INET6, strval,
1161 1405                                              &in6->sin6_addr);
1162 1406                                          if (IN6_IS_ADDR_UNSPECIFIED(
1163 1407                                              &in6->sin6_addr))
1164 1408                                                  node.ipmgmt_am_linklocal =
1165 1409                                                      B_TRUE;
1166 1410                                  }
1167 1411                          }
1168 1412                  }
1169 1413          }
1170 1414  
1171 1415          /* we have all the information we need, add the node */
1172 1416          *errp = i_ipmgmt_add_amnode(&node);
1173 1417  
1174 1418          return (B_TRUE);
1175 1419  }
1176 1420  
1177 1421  /*
1178 1422   * Updates an entry from the temporary cache file, which matches the given
1179 1423   * address object name.
1180 1424   */
1181 1425  /* ARGSUSED */
1182 1426  static boolean_t
1183 1427  ipmgmt_update_aobjmap(void *arg, nvlist_t *db_nvl, char *buf,
1184 1428      size_t buflen, int *errp)
1185 1429  {
1186 1430          ipadm_dbwrite_cbarg_t   *cb = arg;
1187 1431          nvlist_t                *in_nvl = cb->dbw_nvl;
1188 1432          uint32_t                flags = cb->dbw_flags;
1189 1433          char                    *db_lifnumstr = NULL, *in_lifnumstr = NULL;
1190 1434  
1191 1435          *errp = 0;
1192 1436          if (!ipmgmt_nvlist_intersects(db_nvl, in_nvl))
1193 1437                  return (B_TRUE);
1194 1438  
1195 1439          if (flags & IPMGMT_ATYPE_V6ACONF) {
1196 1440                  if (nvlist_lookup_string(db_nvl, IPADM_NVP_LIFNUM,
1197 1441                      &db_lifnumstr) != 0 ||
1198 1442                      nvlist_lookup_string(in_nvl, IPADM_NVP_LIFNUM,
1199 1443                      &in_lifnumstr) != 0 ||
1200 1444                      (atoi(db_lifnumstr) != -1 && atoi(in_lifnumstr) != -1 &&
1201 1445                      strcmp(db_lifnumstr, in_lifnumstr) != 0))
1202 1446                          return (B_TRUE);
1203 1447          }
1204 1448  
1205 1449          /* we found the match */
1206 1450          (void) memset(buf, 0, buflen);
1207 1451          if (ipadm_nvlist2str(in_nvl, buf, buflen) == 0) {
1208 1452                  /* buffer overflow */
1209 1453                  *errp = ENOBUFS;
1210 1454          }
1211 1455  
1212 1456          /* stop the walker */
1213 1457          return (B_FALSE);
1214 1458  }
1215 1459  
1216 1460  /*
1217 1461   * Deletes an entry from the temporary cache file, which matches the given
1218 1462   * address object name.
1219 1463   */
1220 1464  /* ARGSUSED */
1221 1465  static boolean_t
1222 1466  ipmgmt_delete_aobjmap(void *arg, nvlist_t *db_nvl, char *buf,
1223 1467      size_t buflen, int *errp)
1224 1468  {
1225 1469          ipmgmt_aobjmap_t        *nodep = arg;
1226 1470          char                    *db_lifnumstr = NULL;
1227 1471  
1228 1472          *errp = 0;
1229 1473          if (!ipmgmt_nvlist_match(db_nvl, NULL, nodep->am_ifname,
1230 1474              nodep->am_aobjname))
1231 1475                  return (B_TRUE);
1232 1476  
1233 1477          if (nodep->am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
1234 1478                  if (nvlist_lookup_string(db_nvl, IPADM_NVP_LIFNUM,
1235 1479                      &db_lifnumstr) != 0 || atoi(db_lifnumstr) != nodep->am_lnum)
1236 1480                          return (B_TRUE);
1237 1481          }
1238 1482  
1239 1483          /* we found the match, delete the line from the db */
1240 1484          buf[0] = '\0';
1241 1485  
1242 1486          /* stop the walker */
1243 1487          return (B_FALSE);
1244 1488  }
1245 1489  
1246 1490  /*
1247 1491   * Adds or deletes aobjmap node information into a temporary cache file.
1248 1492   */
1249 1493  extern int
1250 1494  ipmgmt_persist_aobjmap(ipmgmt_aobjmap_t *nodep, ipadm_db_op_t op)
1251 1495  {
1252 1496          int                     err;
1253 1497          ipadm_dbwrite_cbarg_t   cb;
1254 1498          nvlist_t                *nvl = NULL;
1255 1499  
1256 1500          if (op == IPADM_DB_WRITE) {
1257 1501                  if ((err = i_ipmgmt_node2nvl(&nvl, nodep)) != 0)
1258 1502                          return (err);
1259 1503                  cb.dbw_nvl = nvl;
1260 1504                  if (nodep->am_atype == IPADM_ADDR_IPV6_ADDRCONF)
1261 1505                          cb.dbw_flags = IPMGMT_ATYPE_V6ACONF;
1262 1506                  else
1263 1507                          cb.dbw_flags = 0;
1264 1508  
1265 1509                  err = ipadm_rw_db(ipmgmt_update_aobjmap, &cb,
1266 1510                      ADDROBJ_MAPPING_DB_FILE, IPADM_FILE_MODE, IPADM_DB_WRITE);
1267 1511                  nvlist_free(nvl);
1268 1512          } else {
1269 1513                  assert(op == IPADM_DB_DELETE);
1270 1514  
1271 1515                  err = ipadm_rw_db(ipmgmt_delete_aobjmap, nodep,
1272 1516                      ADDROBJ_MAPPING_DB_FILE, IPADM_FILE_MODE, IPADM_DB_DELETE);
1273 1517          }
1274 1518          return (err);
1275 1519  }
1276 1520  
1277 1521  /*
1278 1522   * upgrades the ipadm data-store. It renames all the old private protocol
1279 1523   * property names which start with leading protocol names to begin with
1280 1524   * IPADM_PRIV_PROP_PREFIX.
1281 1525   */
1282 1526  /* ARGSUSED */
1283 1527  boolean_t
1284 1528  ipmgmt_db_upgrade(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
1285 1529      int *errp)
1286 1530  {
1287 1531          nvpair_t        *nvp;
1288 1532          char            *name, *pname = NULL, *protostr = NULL, *pval = NULL;
1289 1533          uint_t          proto, nproto;
1290 1534          char            nname[IPMGMT_STRSIZE], tmpstr[IPMGMT_STRSIZE];
1291 1535  
1292 1536          *errp = 0;
1293 1537          /*
1294 1538           * We are interested in lines which contain protocol properties. We
1295 1539           * walk through other lines in the DB.
1296 1540           */
1297 1541          if (nvlist_exists(db_nvl, IPADM_NVP_IFNAME) ||
1298 1542              nvlist_exists(db_nvl, IPADM_NVP_AOBJNAME)) {
1299 1543                  return (B_TRUE);
1300 1544          }
1301 1545          assert(nvlist_exists(db_nvl, IPADM_NVP_PROTONAME));
1302 1546  
1303 1547          /*
1304 1548           * extract the propname from the `db_nvl' and also extract the
1305 1549           * protocol from the `db_nvl'.
1306 1550           */
1307 1551          for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
1308 1552              nvp = nvlist_next_nvpair(db_nvl, nvp)) {
1309 1553                  name = nvpair_name(nvp);
1310 1554                  if (strcmp(name, IPADM_NVP_PROTONAME) == 0) {
1311 1555                          if (nvpair_value_string(nvp, &protostr) != 0)
1312 1556                                  return (B_TRUE);
1313 1557                  } else {
1314 1558                          assert(!IPADM_PRIV_NVP(name));
1315 1559                          pname = name;
1316 1560                          if (nvpair_value_string(nvp, &pval) != 0)
1317 1561                                  return (B_TRUE);
1318 1562                  }
1319 1563          }
1320 1564  
1321 1565          /* if the private property is in the right format return */
1322 1566          if (strncmp(pname, IPADM_PERSIST_PRIVPROP_PREFIX,
1323 1567              strlen(IPADM_PERSIST_PRIVPROP_PREFIX)) == 0) {
1324 1568                  return (B_TRUE);
1325 1569          }
1326 1570          /* if it's a public property move onto the next property */
1327 1571          nproto = proto = ipadm_str2proto(protostr);
1328 1572          if (ipadm_legacy2new_propname(pname, nname, sizeof (nname),
1329 1573              &nproto) != 0) {
1330 1574                  return (B_TRUE);
1331 1575          }
1332 1576  
1333 1577          /* replace the old protocol with new protocol, if required */
1334 1578          if (nproto != proto) {
1335 1579                  protostr = ipadm_proto2str(nproto);
1336 1580                  if (nvlist_add_string(db_nvl, IPADM_NVP_PROTONAME,
1337 1581                      protostr) != 0) {
1338 1582                          return (B_TRUE);
1339 1583                  }
1340 1584          }
1341 1585  
1342 1586          /* replace the old property name with new property name, if required */
1343 1587          /* add the prefix to property name */
1344 1588          (void) snprintf(tmpstr, sizeof (tmpstr), "_%s", nname);
1345 1589          if (nvlist_add_string(db_nvl, tmpstr, pval) != 0 ||
1346 1590              nvlist_remove(db_nvl, pname, DATA_TYPE_STRING) != 0) {
1347 1591                  return (B_TRUE);
1348 1592          }
1349 1593          (void) memset(buf, 0, buflen);
1350 1594          if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
1351 1595                  /* buffer overflow */
1352 1596                  *errp = ENOBUFS;
1353 1597          }
1354 1598          return (B_TRUE);
1355 1599  }
1356 1600  
1357 1601  /*
1358 1602   * Called during boot.
  
    | 
      ↓ open down ↓ | 
    455 lines elided | 
    
      ↑ open up ↑ | 
  
1359 1603   *
1360 1604   * Walk through the DB and apply all the global module properties. We plow
1361 1605   * through the DB even if we fail to apply property.
1362 1606   */
1363 1607  /* ARGSUSED */
1364 1608  static boolean_t
1365 1609  ipmgmt_db_init(void *cbarg, nvlist_t *db_nvl, char *buf, size_t buflen,
1366 1610      int *errp)
1367 1611  {
1368 1612          ipadm_handle_t  iph = cbarg;
1369      -        nvpair_t        *nvp, *pnvp;
     1613 +        nvpair_t        *nvp, *pnvp = NULL;
1370 1614          char            *strval = NULL, *name, *mod = NULL, *pname;
1371 1615          char            tmpstr[IPMGMT_STRSIZE];
1372 1616          uint_t          proto;
1373 1617  
1374 1618          /*
1375 1619           * We could have used nvl_exists() directly, however we need several
1376 1620           * calls to it and each call traverses the list. Since this codepath
1377 1621           * is exercised during boot, let's traverse the list ourselves and do
1378 1622           * the necessary checks.
1379 1623           */
1380 1624          for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
1381 1625              nvp = nvlist_next_nvpair(db_nvl, nvp)) {
1382 1626                  name = nvpair_name(nvp);
1383 1627                  if (IPADM_PRIV_NVP(name)) {
1384 1628                          if (strcmp(name, IPADM_NVP_IFNAME) == 0 ||
1385 1629                              strcmp(name, IPADM_NVP_AOBJNAME) == 0)
  
    | 
      ↓ open down ↓ | 
    6 lines elided | 
    
      ↑ open up ↑ | 
  
1386 1630                                  return (B_TRUE);
1387 1631                          else if (strcmp(name, IPADM_NVP_PROTONAME) == 0 &&
1388 1632                              nvpair_value_string(nvp, &mod) != 0)
1389 1633                                  return (B_TRUE);
1390 1634                  } else {
1391 1635                          /* possible a property */
1392 1636                          pnvp = nvp;
1393 1637                  }
1394 1638          }
1395 1639  
1396      -        /* if we are here than we found a global property */
     1640 +        /* If we are here then we have found a global property */
1397 1641          assert(mod != NULL);
1398 1642          assert(nvpair_type(pnvp) == DATA_TYPE_STRING);
1399 1643  
1400 1644          proto = ipadm_str2proto(mod);
1401 1645          name = nvpair_name(pnvp);
1402 1646          if (nvpair_value_string(pnvp, &strval) == 0) {
1403 1647                  if (strncmp(name, IPADM_PERSIST_PRIVPROP_PREFIX,
1404 1648                      strlen(IPADM_PERSIST_PRIVPROP_PREFIX)) == 0) {
1405 1649                          /* private protocol property */
1406 1650                          pname = &name[1];
1407 1651                  } else if (ipadm_legacy2new_propname(name, tmpstr,
1408 1652                      sizeof (tmpstr), &proto) == 0) {
1409 1653                          pname = tmpstr;
1410 1654                  } else {
1411 1655                          pname = name;
1412 1656                  }
1413 1657                  if (ipadm_set_prop(iph, pname, strval, proto,
1414 1658                      IPADM_OPT_ACTIVE) != IPADM_SUCCESS) {
1415 1659                          ipmgmt_log(LOG_WARNING, "Failed to reapply property %s",
1416 1660                              pname);
1417 1661                  }
1418 1662          }
1419 1663  
1420 1664          return (B_TRUE);
1421 1665  }
1422 1666  
1423 1667  /* initialize global module properties */
1424 1668  void
1425 1669  ipmgmt_init_prop()
1426 1670  {
1427 1671          ipadm_handle_t  iph = NULL;
1428 1672  
1429 1673          if (ipadm_open(&iph, IPH_INIT) != IPADM_SUCCESS) {
1430 1674                  ipmgmt_log(LOG_WARNING, "Could not reapply any of the "
1431 1675                      "persisted protocol properties");
1432 1676                  return;
1433 1677          }
1434 1678          /* ipmgmt_db_init() logs warnings if there are any issues */
1435 1679          (void) ipmgmt_db_walk(ipmgmt_db_init, iph, IPADM_DB_READ);
1436 1680          ipadm_close(iph);
1437 1681  }
1438 1682  
1439 1683  void
1440 1684  ipmgmt_release_scf_resources(scf_resources_t *res)
1441 1685  {
1442 1686          scf_entry_destroy(res->sr_ent);
1443 1687          scf_transaction_destroy(res->sr_tx);
1444 1688          scf_value_destroy(res->sr_val);
1445 1689          scf_property_destroy(res->sr_prop);
1446 1690          scf_pg_destroy(res->sr_pg);
1447 1691          scf_instance_destroy(res->sr_inst);
1448 1692          (void) scf_handle_unbind(res->sr_handle);
1449 1693          scf_handle_destroy(res->sr_handle);
1450 1694  }
1451 1695  
1452 1696  /*
1453 1697   * It creates the necessary SCF handles and binds the given `fmri' to an
1454 1698   * instance. These resources are required for retrieving property value,
1455 1699   * creating property groups and modifying property values.
1456 1700   */
1457 1701  int
1458 1702  ipmgmt_create_scf_resources(const char *fmri, scf_resources_t *res)
1459 1703  {
1460 1704          res->sr_tx = NULL;
1461 1705          res->sr_ent = NULL;
1462 1706          res->sr_inst = NULL;
1463 1707          res->sr_pg = NULL;
1464 1708          res->sr_prop = NULL;
1465 1709          res->sr_val = NULL;
1466 1710  
1467 1711          if ((res->sr_handle = scf_handle_create(SCF_VERSION)) == NULL)
1468 1712                  return (-1);
1469 1713  
1470 1714          if (scf_handle_bind(res->sr_handle) != 0) {
1471 1715                  scf_handle_destroy(res->sr_handle);
1472 1716                  return (-1);
1473 1717          }
1474 1718          if ((res->sr_inst = scf_instance_create(res->sr_handle)) == NULL)
1475 1719                  goto failure;
1476 1720          if (scf_handle_decode_fmri(res->sr_handle, fmri, NULL, NULL,
1477 1721              res->sr_inst, NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
1478 1722                  goto failure;
1479 1723          }
1480 1724          /* we will create the rest of the resources on demand */
1481 1725          return (0);
1482 1726  
1483 1727  failure:
1484 1728          ipmgmt_log(LOG_WARNING, "failed to create scf resources: %s",
1485 1729              scf_strerror(scf_error()));
1486 1730          ipmgmt_release_scf_resources(res);
1487 1731          return (-1);
1488 1732  }
1489 1733  
1490 1734  /*
1491 1735   * persists the `pval' for a given property `pname' in SCF. The only supported
1492 1736   * SCF property types are INTEGER and ASTRING.
1493 1737   */
1494 1738  static int
1495 1739  ipmgmt_set_scfprop_value(scf_resources_t *res, const char *pname, void *pval,
1496 1740      scf_type_t ptype)
1497 1741  {
1498 1742          int result = -1;
1499 1743          boolean_t new;
1500 1744  
1501 1745          if ((res->sr_val = scf_value_create(res->sr_handle)) == NULL)
1502 1746                  goto failure;
1503 1747          switch (ptype) {
1504 1748          case SCF_TYPE_INTEGER:
1505 1749                  scf_value_set_integer(res->sr_val, *(int64_t *)pval);
1506 1750                  break;
1507 1751          case SCF_TYPE_ASTRING:
1508 1752                  if (scf_value_set_astring(res->sr_val, (char *)pval) != 0) {
1509 1753                          ipmgmt_log(LOG_WARNING, "Error setting string value %s "
1510 1754                              "for property %s: %s", pval, pname,
1511 1755                              scf_strerror(scf_error()));
1512 1756                          goto failure;
1513 1757                  }
1514 1758                  break;
1515 1759          default:
1516 1760                  goto failure;
1517 1761          }
1518 1762  
1519 1763          if ((res->sr_tx = scf_transaction_create(res->sr_handle)) == NULL)
1520 1764                  goto failure;
1521 1765          if ((res->sr_ent = scf_entry_create(res->sr_handle)) == NULL)
1522 1766                  goto failure;
1523 1767          if ((res->sr_prop = scf_property_create(res->sr_handle)) == NULL)
1524 1768                  goto failure;
1525 1769  
1526 1770  retry:
1527 1771          new = (scf_pg_get_property(res->sr_pg, pname, res->sr_prop) != 0);
1528 1772          if (scf_transaction_start(res->sr_tx, res->sr_pg) == -1)
1529 1773                  goto failure;
1530 1774          if (new) {
1531 1775                  if (scf_transaction_property_new(res->sr_tx, res->sr_ent,
1532 1776                      pname, ptype) == -1) {
1533 1777                          goto failure;
1534 1778                  }
1535 1779          } else {
1536 1780                  if (scf_transaction_property_change(res->sr_tx, res->sr_ent,
1537 1781                      pname, ptype) == -1) {
1538 1782                          goto failure;
1539 1783                  }
1540 1784          }
1541 1785  
1542 1786          if (scf_entry_add_value(res->sr_ent, res->sr_val) != 0)
1543 1787                  goto failure;
1544 1788  
1545 1789          result = scf_transaction_commit(res->sr_tx);
1546 1790          if (result == 0) {
1547 1791                  scf_transaction_reset(res->sr_tx);
1548 1792                  if (scf_pg_update(res->sr_pg) == -1) {
1549 1793                          goto failure;
1550 1794                  }
1551 1795                  goto retry;
1552 1796          }
1553 1797          if (result == -1)
1554 1798                  goto failure;
1555 1799          return (0);
1556 1800  
1557 1801  failure:
1558 1802          ipmgmt_log(LOG_WARNING, "failed to save the data in SCF: %s",
1559 1803              scf_strerror(scf_error()));
1560 1804          return (-1);
1561 1805  }
1562 1806  
1563 1807  /*
1564 1808   * Given a `pgname'/`pname', it retrieves the value based on `ptype' and
1565 1809   * places it in `pval'.
1566 1810   */
1567 1811  static int
1568 1812  ipmgmt_get_scfprop(scf_resources_t *res, const char *pgname, const char *pname,
1569 1813      void *pval, scf_type_t ptype)
1570 1814  {
1571 1815          ssize_t         numvals;
1572 1816          scf_simple_prop_t *prop;
1573 1817  
1574 1818          prop = scf_simple_prop_get(res->sr_handle, IPMGMTD_FMRI, pgname, pname);
  
    | 
      ↓ open down ↓ | 
    168 lines elided | 
    
      ↑ open up ↑ | 
  
1575 1819          numvals = scf_simple_prop_numvalues(prop);
1576 1820          if (numvals <= 0)
1577 1821                  goto ret;
1578 1822          switch (ptype) {
1579 1823          case SCF_TYPE_INTEGER:
1580 1824                  *(int64_t **)pval = scf_simple_prop_next_integer(prop);
1581 1825                  break;
1582 1826          case SCF_TYPE_ASTRING:
1583 1827                  *(char **)pval = scf_simple_prop_next_astring(prop);
1584 1828                  break;
     1829 +        default:
     1830 +                break;
1585 1831          }
1586 1832  ret:
1587 1833          scf_simple_prop_free(prop);
1588 1834          return (numvals);
1589 1835  }
1590 1836  
1591 1837  /*
1592 1838   * It stores the `pval' for given `pgname'/`pname' property group in SCF.
1593 1839   */
1594 1840  static int
1595 1841  ipmgmt_set_scfprop(scf_resources_t *res, const char *pgname, const char *pname,
1596 1842      void *pval, scf_type_t ptype)
1597 1843  {
1598 1844          scf_error_t             err;
1599 1845  
1600 1846          if ((res->sr_pg = scf_pg_create(res->sr_handle)) == NULL) {
1601 1847                  ipmgmt_log(LOG_WARNING, "failed to create property group: %s",
1602 1848                      scf_strerror(scf_error()));
1603 1849                  return (-1);
1604 1850          }
1605 1851  
1606 1852          if (scf_instance_add_pg(res->sr_inst, pgname, SCF_GROUP_APPLICATION,
1607 1853              0, res->sr_pg) != 0) {
1608 1854                  if ((err = scf_error()) != SCF_ERROR_EXISTS) {
1609 1855                          ipmgmt_log(LOG_WARNING,
1610 1856                              "Error adding property group '%s/%s': %s",
1611 1857                              pgname, pname, scf_strerror(err));
1612 1858                          return (-1);
1613 1859                  }
1614 1860                  /*
1615 1861                   * if the property group already exists, then we get the
1616 1862                   * composed view of the property group for the given instance.
1617 1863                   */
1618 1864                  if (scf_instance_get_pg_composed(res->sr_inst, NULL, pgname,
1619 1865                      res->sr_pg) != 0) {
1620 1866                          ipmgmt_log(LOG_WARNING, "Error getting composed view "
1621 1867                              "of the property group '%s/%s': %s", pgname, pname,
1622 1868                              scf_strerror(scf_error()));
1623 1869                          return (-1);
1624 1870                  }
1625 1871          }
1626 1872  
1627 1873          return (ipmgmt_set_scfprop_value(res, pname, pval, ptype));
1628 1874  }
1629 1875  
1630 1876  /*
1631 1877   * Returns B_TRUE, if the non-global zone is being booted for the first time
1632 1878   * after being installed. This is required to setup the ipadm data-store for
1633 1879   * the first boot of the non-global zone. Please see, PSARC 2010/166,
1634 1880   * for more info.
1635 1881   *
1636 1882   * Note that, this API cannot be used to determine first boot post image-update.
1637 1883   * 'pkg image-update' clones the current BE and the existing value of
1638 1884   * ipmgmtd/first_boot_done will be carried forward and obviously it will be set
1639 1885   * to B_TRUE.
1640 1886   */
1641 1887  boolean_t
1642 1888  ipmgmt_ngz_firstboot_postinstall()
1643 1889  {
1644 1890          scf_resources_t res;
1645 1891          boolean_t       bval = B_TRUE;
1646 1892          char            *strval;
1647 1893  
1648 1894          /* we always err on the side of caution */
1649 1895          if (ipmgmt_create_scf_resources(IPMGMTD_FMRI, &res) != 0)
1650 1896                  return (bval);
1651 1897  
1652 1898          if (ipmgmt_get_scfprop(&res, IPMGMTD_APP_PG, IPMGMTD_PROP_FBD, &strval,
1653 1899              SCF_TYPE_ASTRING) > 0) {
1654 1900                  bval = (strcmp(strval, IPMGMTD_TRUESTR) == 0 ?
1655 1901                      B_FALSE : B_TRUE);
1656 1902          } else {
1657 1903                  /*
1658 1904                   * IPMGMTD_PROP_FBD does not exist in the SCF. Lets create it.
1659 1905                   * Since we err on the side of caution, we ignore the return
1660 1906                   * error and return B_TRUE.
1661 1907                   */
1662 1908                  (void) ipmgmt_set_scfprop(&res, IPMGMTD_APP_PG,
1663 1909                      IPMGMTD_PROP_FBD, IPMGMTD_TRUESTR, SCF_TYPE_ASTRING);
1664 1910          }
1665 1911          ipmgmt_release_scf_resources(&res);
1666 1912          return (bval);
1667 1913  }
1668 1914  
1669 1915  /*
1670 1916   * Returns B_TRUE, if the data-store needs upgrade otherwise returns B_FALSE.
1671 1917   * Today we have to take care of, one case of, upgrading from version 0 to
1672 1918   * version 1, so we will use boolean_t as means to decide if upgrade is needed
1673 1919   * or not. Further, the upcoming projects might completely move the flatfile
1674 1920   * data-store into SCF and hence we shall keep this interface simple.
1675 1921   */
1676 1922  boolean_t
1677 1923  ipmgmt_needs_upgrade(scf_resources_t *res)
1678 1924  {
1679 1925          boolean_t       bval = B_TRUE;
1680 1926          int64_t         *verp;
1681 1927  
1682 1928          if (ipmgmt_get_scfprop(res, IPMGMTD_APP_PG, IPMGMTD_PROP_DBVER,
1683 1929              &verp, SCF_TYPE_INTEGER) > 0) {
1684 1930                  if (*verp == IPADM_DB_VERSION)
1685 1931                          bval = B_FALSE;
1686 1932          }
1687 1933          /*
1688 1934           * 'datastore_version' doesn't exist. Which means that we need to
1689 1935           * upgrade the datastore. We will create 'datastore_version' and set
1690 1936           * the version value to IPADM_DB_VERSION, after we upgrade the file.
1691 1937           */
1692 1938          return (bval);
1693 1939  }
1694 1940  
1695 1941  /*
1696 1942   * This is called after the successful upgrade of the local data-store. With
  
    | 
      ↓ open down ↓ | 
    102 lines elided | 
    
      ↑ open up ↑ | 
  
1697 1943   * the data-store upgraded to recent version we don't have to do anything on
1698 1944   * subsequent reboots.
1699 1945   */
1700 1946  void
1701 1947  ipmgmt_update_dbver(scf_resources_t *res)
1702 1948  {
1703 1949          int64_t         version = IPADM_DB_VERSION;
1704 1950  
1705 1951          (void) ipmgmt_set_scfprop(res, IPMGMTD_APP_PG,
1706 1952              IPMGMTD_PROP_DBVER, &version, SCF_TYPE_INTEGER);
     1953 +}
     1954 +
     1955 +/*
     1956 + * Return TRUE if `ifname' has persistent configuration for the `af' address
     1957 + * family in the datastore.
     1958 + * It is possible to call the function with af == AF_UNSPEC, so in this case
     1959 + * the function returns TRUE if either AF_INET or AF_INET6 interface exists
     1960 + */
     1961 +boolean_t
     1962 +ipmgmt_persist_if_exists(const char *ifname, sa_family_t af)
     1963 +{
     1964 +        boolean_t exists = B_FALSE;
     1965 +        nvlist_t    *if_info_nvl;
     1966 +        uint16_t    *families = NULL;
     1967 +        sa_family_t af_db;
     1968 +        uint_t  nelem = 0;
     1969 +
     1970 +        if (ipmgmt_get_ifinfo_nvl(ifname, &if_info_nvl) != 0)
     1971 +                goto done;
     1972 +
     1973 +        if (nvlist_lookup_uint16_array(if_info_nvl, IPADM_NVP_FAMILIES,
     1974 +            &families, &nelem) != 0)
     1975 +                goto done;
     1976 +
     1977 +        while (nelem-- > 0) {
     1978 +                af_db = families[nelem];
     1979 +                if (af_db == af || (af == AF_UNSPEC &&
     1980 +                    (af_db == AF_INET || af_db == AF_INET6))) {
     1981 +                        exists = B_TRUE;
     1982 +                        break;
     1983 +                }
     1984 +        }
     1985 +
     1986 +done:
     1987 +        if (if_info_nvl != NULL)
     1988 +                nvlist_free(if_info_nvl);
     1989 +
     1990 +        return (exists);
     1991 +}
     1992 +
     1993 +/*
     1994 + * Retrieves the membership information for the requested mif_name
     1995 + * if mif_name is a memeber of a IPMP group, then gif_name will contain
     1996 + * the name of IPMP group interface, otherwise the variable will be empty
     1997 + */
     1998 +void
     1999 +ipmgmt_get_group_interface(const char *mif_name, char *gif_name, size_t size)
     2000 +{
     2001 +        char    *gif_name_from_nvl;
     2002 +        nvlist_t        *if_info_nvl;
     2003 +
     2004 +        gif_name[0] = '\0';
     2005 +
     2006 +        if (ipmgmt_get_ifinfo_nvl(mif_name, &if_info_nvl) != 0)
     2007 +                goto done;
     2008 +
     2009 +        if (nvlist_lookup_string(if_info_nvl, IPADM_NVP_GIFNAME,
     2010 +            &gif_name_from_nvl) != 0)
     2011 +                goto done;
     2012 +
     2013 +        (void) strlcpy(gif_name, gif_name_from_nvl, size);
     2014 +
     2015 +done:
     2016 +        if (if_info_nvl != NULL)
     2017 +                nvlist_free(if_info_nvl);
     2018 +}
     2019 +
     2020 +static int
     2021 +ipmgmt_get_ifinfo_nvl(const char *ifname, nvlist_t **if_info_nvl)
     2022 +{
     2023 +        ipmgmt_get_cbarg_t cbarg;
     2024 +        nvpair_t    *nvp;
     2025 +        nvlist_t    *nvl;
     2026 +        int     err;
     2027 +
     2028 +        cbarg.cb_ifname = NULL;
     2029 +        cbarg.cb_aobjname = NULL;
     2030 +        cbarg.cb_ocnt = 0;
     2031 +
     2032 +        if ((err = nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0)) != 0)
     2033 +                goto done;
     2034 +
     2035 +        err = ipmgmt_db_walk(ipmgmt_db_getif, &cbarg, IPADM_DB_READ);
     2036 +        if (err == ENOENT && cbarg.cb_ocnt > 0)
     2037 +                err = 0;
     2038 +
     2039 +        if (err != 0)
     2040 +                goto done;
     2041 +
     2042 +        for (nvp = nvlist_next_nvpair(cbarg.cb_onvl, NULL); nvp != NULL;
     2043 +            nvp = nvlist_next_nvpair(cbarg.cb_onvl, nvp)) {
     2044 +
     2045 +                if (strcmp(nvpair_name(nvp), ifname) != 0)
     2046 +                        continue;
     2047 +
     2048 +                if ((err = nvpair_value_nvlist(nvp, &nvl)) != 0 ||
     2049 +                    (err = nvlist_dup(nvl, if_info_nvl, NV_UNIQUE_NAME)) != 0)
     2050 +                        *if_info_nvl = NULL;
     2051 +
     2052 +                break;
     2053 +        }
     2054 +
     2055 +done:
     2056 +        nvlist_free(cbarg.cb_onvl);
     2057 +
     2058 +        return (err);
1707 2059  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX