1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  25 /*
  26  * This RCM module adds support to the RCM framework for VLAN links
  27  */
  28 
  29 #include <stdio.h>
  30 #include <stdlib.h>
  31 #include <string.h>
  32 #include <errno.h>
  33 #include <sys/types.h>
  34 #include <synch.h>
  35 #include <assert.h>
  36 #include <strings.h>
  37 #include "rcm_module.h"
  38 #include <libintl.h>
  39 #include <libdllink.h>
  40 #include <libdlvlan.h>
  41 #include <libdlpi.h>
  42 
  43 /*
  44  * Definitions
  45  */
  46 #ifndef lint
  47 #define _(x)    gettext(x)
  48 #else
  49 #define _(x)    x
  50 #endif
  51 
  52 /* Some generic well-knowns and defaults used in this module */
  53 #define RCM_LINK_PREFIX         "SUNW_datalink" /* RCM datalink name prefix */
  54 #define RCM_LINK_RESOURCE_MAX   (13 + LINKID_STR_WIDTH)
  55 
  56 /* VLAN link flags */
  57 typedef enum {
  58         VLAN_OFFLINED           = 0x1,
  59         VLAN_CONSUMER_OFFLINED  = 0x2,
  60         VLAN_STALE              = 0x4
  61 } vlan_flag_t;
  62 
  63 /* link representation */
  64 typedef struct dl_vlan {
  65         struct dl_vlan  *dv_next;               /* next VLAN on the same link */
  66         struct dl_vlan  *dv_prev;               /* prev VLAN on the same link */
  67         datalink_id_t   dv_vlanid;
  68         vlan_flag_t     dv_flags;               /* VLAN link flags */
  69 } dl_vlan_t;
  70 
  71 /* VLAN Cache state flags */
  72 typedef enum {
  73         CACHE_NODE_STALE        = 0x1,          /* stale cached data */
  74         CACHE_NODE_NEW          = 0x2,          /* new cached nodes */
  75         CACHE_NODE_OFFLINED     = 0x4           /* nodes offlined */
  76 } cache_node_state_t;
  77 
  78 /* Network Cache lookup options */
  79 #define CACHE_NO_REFRESH        0x1             /* cache refresh not needed */
  80 #define CACHE_REFRESH           0x2             /* refresh cache */
  81 
  82 /* Cache element */
  83 typedef struct link_cache {
  84         struct link_cache       *vc_next;       /* next cached resource */
  85         struct link_cache       *vc_prev;       /* prev cached resource */
  86         char                    *vc_resource;   /* resource name */
  87         datalink_id_t           vc_linkid;      /* linkid */
  88         dl_vlan_t               *vc_vlan;       /* VLAN list on this link */
  89         cache_node_state_t      vc_state;       /* cache state flags */
  90 } link_cache_t;
  91 
  92 /*
  93  * Global cache for network VLANs
  94  */
  95 static link_cache_t     cache_head;
  96 static link_cache_t     cache_tail;
  97 static mutex_t          cache_lock;
  98 static int              events_registered = 0;
  99 
 100 static dladm_handle_t   dld_handle = NULL;
 101 
 102 /*
 103  * RCM module interface prototypes
 104  */
 105 static int              vlan_register(rcm_handle_t *);
 106 static int              vlan_unregister(rcm_handle_t *);
 107 static int              vlan_get_info(rcm_handle_t *, char *, id_t, uint_t,
 108                             char **, char **, nvlist_t *, rcm_info_t **);
 109 static int              vlan_suspend(rcm_handle_t *, char *, id_t,
 110                             timespec_t *, uint_t, char **, rcm_info_t **);
 111 static int              vlan_resume(rcm_handle_t *, char *, id_t, uint_t,
 112                             char **, rcm_info_t **);
 113 static int              vlan_offline(rcm_handle_t *, char *, id_t, uint_t,
 114                             char **, rcm_info_t **);
 115 static int              vlan_undo_offline(rcm_handle_t *, char *, id_t, uint_t,
 116                             char **, rcm_info_t **);
 117 static int              vlan_remove(rcm_handle_t *, char *, id_t, uint_t,
 118                             char **, rcm_info_t **);
 119 static int              vlan_notify_event(rcm_handle_t *, char *, id_t, uint_t,
 120                             char **, nvlist_t *, rcm_info_t **);
 121 static int              vlan_configure(rcm_handle_t *, datalink_id_t);
 122 
 123 /* Module private routines */
 124 static void             cache_free();
 125 static int              cache_update(rcm_handle_t *);
 126 static void             cache_remove(link_cache_t *);
 127 static void             node_free(link_cache_t *);
 128 static void             cache_insert(link_cache_t *);
 129 static link_cache_t     *cache_lookup(rcm_handle_t *, char *, char);
 130 static int              vlan_consumer_offline(rcm_handle_t *, link_cache_t *,
 131                             char **, uint_t, rcm_info_t **);
 132 static void             vlan_consumer_online(rcm_handle_t *, link_cache_t *,
 133                             char **, uint_t, rcm_info_t **);
 134 static int              vlan_offline_vlan(link_cache_t *, uint32_t,
 135                             cache_node_state_t);
 136 static void             vlan_online_vlan(link_cache_t *);
 137 static char             *vlan_usage(link_cache_t *);
 138 static void             vlan_log_err(datalink_id_t, char **, char *);
 139 static int              vlan_consumer_notify(rcm_handle_t *, datalink_id_t,
 140                             char **, uint_t, rcm_info_t **);
 141 
 142 /* Module-Private data */
 143 static struct rcm_mod_ops vlan_ops =
 144 {
 145         RCM_MOD_OPS_VERSION,
 146         vlan_register,
 147         vlan_unregister,
 148         vlan_get_info,
 149         vlan_suspend,
 150         vlan_resume,
 151         vlan_offline,
 152         vlan_undo_offline,
 153         vlan_remove,
 154         NULL,
 155         NULL,
 156         vlan_notify_event
 157 };
 158 
 159 /*
 160  * rcm_mod_init() - Update registrations, and return the ops structure.
 161  */
 162 struct rcm_mod_ops *
 163 rcm_mod_init(void)
 164 {
 165         dladm_status_t status;
 166         char errmsg[DLADM_STRSIZE];
 167 
 168         rcm_log_message(RCM_TRACE1, "VLAN: mod_init\n");
 169 
 170         cache_head.vc_next = &cache_tail;
 171         cache_head.vc_prev = NULL;
 172         cache_tail.vc_prev = &cache_head;
 173         cache_tail.vc_next = NULL;
 174         (void) mutex_init(&cache_lock, 0, NULL);
 175 
 176         if ((status = dladm_open(&dld_handle)) != DLADM_STATUS_OK) {
 177                 rcm_log_message(RCM_WARNING,
 178                     "VLAN: mod_init failed: cannot open datalink handle: %s\n",
 179                     dladm_status2str(status, errmsg));
 180                 return (NULL);
 181         }
 182 
 183         /* Return the ops vectors */
 184         return (&vlan_ops);
 185 }
 186 
 187 /*
 188  * rcm_mod_info() - Return a string describing this module.
 189  */
 190 const char *
 191 rcm_mod_info(void)
 192 {
 193         rcm_log_message(RCM_TRACE1, "VLAN: mod_info\n");
 194 
 195         return ("VLAN module version 1.2");
 196 }
 197 
 198 /*
 199  * rcm_mod_fini() - Destroy the network VLAN cache.
 200  */
 201 int
 202 rcm_mod_fini(void)
 203 {
 204         rcm_log_message(RCM_TRACE1, "VLAN: mod_fini\n");
 205 
 206         /*
 207          * Note that vlan_unregister() does not seem to be called anywhere,
 208          * therefore we free the cache nodes here. In theory we should call
 209          * rcm_register_interest() for each node before we free it, the
 210          * framework does not provide the rcm_handle to allow us to do so.
 211          */
 212         cache_free();
 213         (void) mutex_destroy(&cache_lock);
 214 
 215         dladm_close(dld_handle);
 216         return (RCM_SUCCESS);
 217 }
 218 
 219 /*
 220  * vlan_register() - Make sure the cache is properly sync'ed, and its
 221  *               registrations are in order.
 222  */
 223 static int
 224 vlan_register(rcm_handle_t *hd)
 225 {
 226         rcm_log_message(RCM_TRACE1, "VLAN: register\n");
 227 
 228         if (cache_update(hd) < 0)
 229                 return (RCM_FAILURE);
 230 
 231         /*
 232          * Need to register interest in all new resources
 233          * getting attached, so we get attach event notifications
 234          */
 235         if (!events_registered) {
 236                 if (rcm_register_event(hd, RCM_RESOURCE_LINK_NEW, 0, NULL)
 237                     != RCM_SUCCESS) {
 238                         rcm_log_message(RCM_ERROR,
 239                             _("VLAN: failed to register %s\n"),
 240                             RCM_RESOURCE_LINK_NEW);
 241                         return (RCM_FAILURE);
 242                 } else {
 243                         rcm_log_message(RCM_DEBUG, "VLAN: registered %s\n",
 244                             RCM_RESOURCE_LINK_NEW);
 245                         events_registered++;
 246                 }
 247         }
 248 
 249         return (RCM_SUCCESS);
 250 }
 251 
 252 /*
 253  * vlan_unregister() - Walk the cache, unregistering all the networks.
 254  */
 255 static int
 256 vlan_unregister(rcm_handle_t *hd)
 257 {
 258         link_cache_t *node;
 259 
 260         rcm_log_message(RCM_TRACE1, "VLAN: unregister\n");
 261 
 262         /* Walk the cache, unregistering everything */
 263         (void) mutex_lock(&cache_lock);
 264         node = cache_head.vc_next;
 265         while (node != &cache_tail) {
 266                 if (rcm_unregister_interest(hd, node->vc_resource, 0)
 267                     != RCM_SUCCESS) {
 268                         rcm_log_message(RCM_ERROR,
 269                             _("VLAN: failed to unregister %s\n"),
 270                             node->vc_resource);
 271                         (void) mutex_unlock(&cache_lock);
 272                         return (RCM_FAILURE);
 273                 }
 274                 cache_remove(node);
 275                 node_free(node);
 276                 node = cache_head.vc_next;
 277         }
 278         (void) mutex_unlock(&cache_lock);
 279 
 280         /*
 281          * Unregister interest in all new resources
 282          */
 283         if (events_registered) {
 284                 if (rcm_unregister_event(hd, RCM_RESOURCE_LINK_NEW, 0)
 285                     != RCM_SUCCESS) {
 286                         rcm_log_message(RCM_ERROR,
 287                             _("VLAN: failed to unregister %s\n"),
 288                             RCM_RESOURCE_LINK_NEW);
 289                         return (RCM_FAILURE);
 290                 } else {
 291                         rcm_log_message(RCM_DEBUG, "VLAN: unregistered %s\n",
 292                             RCM_RESOURCE_LINK_NEW);
 293                         events_registered--;
 294                 }
 295         }
 296 
 297         return (RCM_SUCCESS);
 298 }
 299 
 300 /*
 301  * vlan_offline() - Offline VLANs on a specific node.
 302  */
 303 static int
 304 vlan_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
 305     char **errorp, rcm_info_t **info)
 306 {
 307         link_cache_t *node;
 308 
 309         rcm_log_message(RCM_TRACE1, "VLAN: offline(%s)\n", rsrc);
 310 
 311         /* Lock the cache and lookup the resource */
 312         (void) mutex_lock(&cache_lock);
 313         node = cache_lookup(hd, rsrc, CACHE_REFRESH);
 314         if (node == NULL) {
 315                 /* should not happen because the resource is registered. */
 316                 vlan_log_err(DATALINK_INVALID_LINKID, errorp,
 317                     "unrecognized resource");
 318                 (void) mutex_unlock(&cache_lock);
 319                 return (RCM_SUCCESS);
 320         }
 321 
 322         /*
 323          * Inform consumers (IP interfaces) of associated VLANs to be offlined
 324          */
 325         if (vlan_consumer_offline(hd, node, errorp, flags, info) ==
 326             RCM_SUCCESS) {
 327                 rcm_log_message(RCM_DEBUG,
 328                     "VLAN: consumers agreed on offline\n");
 329         } else {
 330                 vlan_log_err(node->vc_linkid, errorp,
 331                     "consumers failed to offline");
 332                 (void) mutex_unlock(&cache_lock);
 333                 return (RCM_FAILURE);
 334         }
 335 
 336         /* Check if it's a query */
 337         if (flags & RCM_QUERY) {
 338                 rcm_log_message(RCM_TRACE1,
 339                     "VLAN: offline query succeeded(%s)\n", rsrc);
 340                 (void) mutex_unlock(&cache_lock);
 341                 return (RCM_SUCCESS);
 342         }
 343 
 344         if (vlan_offline_vlan(node, VLAN_OFFLINED, CACHE_NODE_OFFLINED) !=
 345             RCM_SUCCESS) {
 346                 vlan_online_vlan(node);
 347                 vlan_log_err(node->vc_linkid, errorp, "offline failed");
 348                 (void) mutex_unlock(&cache_lock);
 349                 return (RCM_FAILURE);
 350         }
 351 
 352         rcm_log_message(RCM_TRACE1, "VLAN: Offline succeeded(%s)\n", rsrc);
 353         (void) mutex_unlock(&cache_lock);
 354         return (RCM_SUCCESS);
 355 }
 356 
 357 /*
 358  * vlan_undo_offline() - Undo offline of a previously offlined node.
 359  */
 360 /*ARGSUSED*/
 361 static int
 362 vlan_undo_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
 363     char **errorp, rcm_info_t **info)
 364 {
 365         link_cache_t *node;
 366 
 367         rcm_log_message(RCM_TRACE1, "VLAN: online(%s)\n", rsrc);
 368 
 369         (void) mutex_lock(&cache_lock);
 370         node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
 371         if (node == NULL) {
 372                 vlan_log_err(DATALINK_INVALID_LINKID, errorp, "no such link");
 373                 (void) mutex_unlock(&cache_lock);
 374                 errno = ENOENT;
 375                 return (RCM_FAILURE);
 376         }
 377 
 378         /* Check if no attempt should be made to online the link here */
 379         if (!(node->vc_state & CACHE_NODE_OFFLINED)) {
 380                 vlan_log_err(node->vc_linkid, errorp, "link not offlined");
 381                 (void) mutex_unlock(&cache_lock);
 382                 errno = ENOTSUP;
 383                 return (RCM_SUCCESS);
 384         }
 385 
 386         vlan_online_vlan(node);
 387 
 388         /*
 389          * Inform IP interfaces on associated VLANs to be onlined
 390          */
 391         vlan_consumer_online(hd, node, errorp, flags, info);
 392 
 393         node->vc_state &= ~CACHE_NODE_OFFLINED;
 394         rcm_log_message(RCM_TRACE1, "VLAN: online succeeded(%s)\n", rsrc);
 395         (void) mutex_unlock(&cache_lock);
 396         return (RCM_SUCCESS);
 397 }
 398 
 399 static void
 400 vlan_online_vlan(link_cache_t *node)
 401 {
 402         dl_vlan_t *vlan;
 403         dladm_status_t status;
 404         char errmsg[DLADM_STRSIZE];
 405 
 406         /*
 407          * Try to bring on all offlined VLANs
 408          */
 409         for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
 410                 if (!(vlan->dv_flags & VLAN_OFFLINED))
 411                         continue;
 412 
 413                 if ((status = dladm_vlan_up(dld_handle, vlan->dv_vlanid)) !=
 414                     DLADM_STATUS_OK) {
 415                         /*
 416                          * Print a warning message and continue to online
 417                          * other VLANs.
 418                          */
 419                         rcm_log_message(RCM_WARNING,
 420                             _("VLAN: VLAN online failed (%u): %s\n"),
 421                             vlan->dv_vlanid, dladm_status2str(status, errmsg));
 422                 } else {
 423                         vlan->dv_flags &= ~VLAN_OFFLINED;
 424                 }
 425         }
 426 }
 427 
 428 static int
 429 vlan_offline_vlan(link_cache_t *node, uint32_t flags, cache_node_state_t state)
 430 {
 431         dl_vlan_t *vlan;
 432         dladm_status_t status;
 433         char errmsg[DLADM_STRSIZE];
 434 
 435         rcm_log_message(RCM_TRACE2, "VLAN: vlan_offline_vlan (%s %u %u)\n",
 436             node->vc_resource, flags, state);
 437 
 438         /*
 439          * Try to delete all explicit created VLAN
 440          */
 441         for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
 442                 if ((status = dladm_vlan_delete(dld_handle, vlan->dv_vlanid,
 443                     DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
 444                         rcm_log_message(RCM_WARNING,
 445                             _("VLAN: VLAN offline failed (%u): %s\n"),
 446                             vlan->dv_vlanid, dladm_status2str(status, errmsg));
 447                         return (RCM_FAILURE);
 448                 } else {
 449                         rcm_log_message(RCM_TRACE1,
 450                             "VLAN: VLAN offline succeeded(%u)\n",
 451                             vlan->dv_vlanid);
 452                         vlan->dv_flags |= flags;
 453                 }
 454         }
 455 
 456         node->vc_state |= state;
 457         return (RCM_SUCCESS);
 458 }
 459 
 460 /*
 461  * vlan_get_info() - Gather usage information for this resource.
 462  */
 463 /*ARGSUSED*/
 464 int
 465 vlan_get_info(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
 466     char **usagep, char **errorp, nvlist_t *props, rcm_info_t **info)
 467 {
 468         link_cache_t *node;
 469 
 470         rcm_log_message(RCM_TRACE1, "VLAN: get_info(%s)\n", rsrc);
 471 
 472         (void) mutex_lock(&cache_lock);
 473         node = cache_lookup(hd, rsrc, CACHE_REFRESH);
 474         if (node == NULL) {
 475                 rcm_log_message(RCM_INFO,
 476                     _("VLAN: get_info(%s) unrecognized resource\n"), rsrc);
 477                 (void) mutex_unlock(&cache_lock);
 478                 errno = ENOENT;
 479                 return (RCM_FAILURE);
 480         }
 481 
 482         *usagep = vlan_usage(node);
 483         (void) mutex_unlock(&cache_lock);
 484         if (*usagep == NULL) {
 485                 /* most likely malloc failure */
 486                 rcm_log_message(RCM_ERROR,
 487                     _("VLAN: get_info(%s) malloc failure\n"), rsrc);
 488                 (void) mutex_unlock(&cache_lock);
 489                 errno = ENOMEM;
 490                 return (RCM_FAILURE);
 491         }
 492 
 493         /* Set client/role properties */
 494         (void) nvlist_add_string(props, RCM_CLIENT_NAME, "VLAN");
 495 
 496         rcm_log_message(RCM_TRACE1, "VLAN: get_info(%s) info = %s\n",
 497             rsrc, *usagep);
 498         return (RCM_SUCCESS);
 499 }
 500 
 501 /*
 502  * vlan_suspend() - Nothing to do, always okay
 503  */
 504 /*ARGSUSED*/
 505 static int
 506 vlan_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval,
 507     uint_t flags, char **errorp, rcm_info_t **info)
 508 {
 509         rcm_log_message(RCM_TRACE1, "VLAN: suspend(%s)\n", rsrc);
 510         return (RCM_SUCCESS);
 511 }
 512 
 513 /*
 514  * vlan_resume() - Nothing to do, always okay
 515  */
 516 /*ARGSUSED*/
 517 static int
 518 vlan_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
 519     char **errorp, rcm_info_t **info)
 520 {
 521         rcm_log_message(RCM_TRACE1, "VLAN: resume(%s)\n", rsrc);
 522         return (RCM_SUCCESS);
 523 }
 524 
 525 /*
 526  * vlan_consumer_remove()
 527  *
 528  *      Notify VLAN consumers to remove cache.
 529  */
 530 static int
 531 vlan_consumer_remove(rcm_handle_t *hd, link_cache_t *node, uint_t flags,
 532     rcm_info_t **info)
 533 {
 534         dl_vlan_t *vlan = NULL;
 535         char rsrc[RCM_LINK_RESOURCE_MAX];
 536         int ret = RCM_SUCCESS;
 537 
 538         rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_remove (%s)\n",
 539             node->vc_resource);
 540 
 541         for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
 542 
 543                 /*
 544                  * This will only be called when the offline operation
 545                  * succeeds, so the VLAN consumers must have been offlined
 546                  * at this point.
 547                  */
 548                 assert(vlan->dv_flags & VLAN_CONSUMER_OFFLINED);
 549 
 550                 (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
 551                     RCM_LINK_PREFIX, vlan->dv_vlanid);
 552 
 553                 ret = rcm_notify_remove(hd, rsrc, flags, info);
 554                 if (ret != RCM_SUCCESS) {
 555                         rcm_log_message(RCM_WARNING,
 556                             _("VLAN: notify remove failed (%s)\n"), rsrc);
 557                         break;
 558                 }
 559         }
 560 
 561         rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_remove done\n");
 562         return (ret);
 563 }
 564 
 565 /*
 566  * vlan_remove() - remove a resource from cache
 567  */
 568 /*ARGSUSED*/
 569 static int
 570 vlan_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
 571     char **errorp, rcm_info_t **info)
 572 {
 573         link_cache_t *node;
 574         int rv;
 575 
 576         rcm_log_message(RCM_TRACE1, "VLAN: remove(%s)\n", rsrc);
 577 
 578         (void) mutex_lock(&cache_lock);
 579         node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
 580         if (node == NULL) {
 581                 rcm_log_message(RCM_INFO,
 582                     _("VLAN: remove(%s) unrecognized resource\n"), rsrc);
 583                 (void) mutex_unlock(&cache_lock);
 584                 errno = ENOENT;
 585                 return (RCM_FAILURE);
 586         }
 587 
 588         /* remove the cached entry for the resource */
 589         cache_remove(node);
 590         (void) mutex_unlock(&cache_lock);
 591 
 592         rv = vlan_consumer_remove(hd, node, flags, info);
 593         node_free(node);
 594         return (rv);
 595 }
 596 
 597 /*
 598  * vlan_notify_event - Project private implementation to receive new resource
 599  *                 events. It intercepts all new resource events. If the
 600  *                 new resource is a network resource, pass up a notify
 601  *                 for it too. The new resource need not be cached, since
 602  *                 it is done at register again.
 603  */
 604 /*ARGSUSED*/
 605 static int
 606 vlan_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
 607     char **errorp, nvlist_t *nvl, rcm_info_t **info)
 608 {
 609         nvpair_t        *nvp = NULL;
 610         datalink_id_t   linkid;
 611         uint64_t        id64;
 612         int             rv = RCM_SUCCESS;
 613 
 614         rcm_log_message(RCM_TRACE1, "VLAN: notify_event(%s)\n", rsrc);
 615 
 616         if (strcmp(rsrc, RCM_RESOURCE_LINK_NEW) != 0) {
 617                 vlan_log_err(DATALINK_INVALID_LINKID, errorp,
 618                     "unrecognized event");
 619                 errno = EINVAL;
 620                 return (RCM_FAILURE);
 621         }
 622 
 623         /* Update cache to reflect latest VLANs */
 624         if (cache_update(hd) < 0) {
 625                 vlan_log_err(DATALINK_INVALID_LINKID, errorp,
 626                     "private Cache update failed");
 627                 return (RCM_FAILURE);
 628         }
 629 
 630         /*
 631          * Try best to recover all configuration.
 632          */
 633         rcm_log_message(RCM_DEBUG, "VLAN: process_nvlist\n");
 634         while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
 635                 if (strcmp(nvpair_name(nvp), RCM_NV_LINKID) != 0)
 636                         continue;
 637 
 638                 if (nvpair_value_uint64(nvp, &id64) != 0) {
 639                         vlan_log_err(DATALINK_INVALID_LINKID, errorp,
 640                             "cannot get linkid");
 641                         rv = RCM_FAILURE;
 642                         continue;
 643                 }
 644 
 645                 linkid = (datalink_id_t)id64;
 646                 if (vlan_configure(hd, linkid) != 0) {
 647                         vlan_log_err(linkid, errorp, "configuring failed");
 648                         rv = RCM_FAILURE;
 649                         continue;
 650                 }
 651 
 652                 /* Notify all VLAN consumers */
 653                 if (vlan_consumer_notify(hd, linkid, errorp, flags,
 654                     info) != 0) {
 655                         vlan_log_err(linkid, errorp, "consumer notify failed");
 656                         rv = RCM_FAILURE;
 657                 }
 658         }
 659 
 660         rcm_log_message(RCM_TRACE1,
 661             "VLAN: notify_event: link configuration complete\n");
 662         return (rv);
 663 }
 664 
 665 /*
 666  * vlan_usage - Determine the usage of a link.
 667  *          The returned buffer is owned by caller, and the caller
 668  *          must free it up when done.
 669  */
 670 static char *
 671 vlan_usage(link_cache_t *node)
 672 {
 673         dl_vlan_t *vlan;
 674         int nvlan;
 675         char *buf;
 676         const char *fmt;
 677         char *sep;
 678         char errmsg[DLADM_STRSIZE];
 679         char name[MAXLINKNAMELEN];
 680         dladm_status_t status;
 681         size_t bufsz;
 682 
 683         rcm_log_message(RCM_TRACE2, "VLAN: usage(%s)\n", node->vc_resource);
 684 
 685         assert(MUTEX_HELD(&cache_lock));
 686         if ((status = dladm_datalink_id2info(dld_handle, node->vc_linkid, NULL,
 687             NULL, NULL, name, sizeof (name))) != DLADM_STATUS_OK) {
 688                 rcm_log_message(RCM_ERROR,
 689                     _("VLAN: usage(%s) get link name failure(%s)\n"),
 690                     node->vc_resource, dladm_status2str(status, errmsg));
 691                 return (NULL);
 692         }
 693 
 694         if (node->vc_state & CACHE_NODE_OFFLINED)
 695                 fmt = _("%1$s offlined");
 696         else
 697                 fmt = _("%1$s VLANs: ");
 698 
 699         /* TRANSLATION_NOTE: separator used between VLAN linkids */
 700         sep = _(", ");
 701 
 702         nvlan = 0;
 703         for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next)
 704                 nvlan++;
 705 
 706         /* space for VLANs and separators, plus message */
 707         bufsz = nvlan * (MAXLINKNAMELEN + strlen(sep)) +
 708             strlen(fmt) + MAXLINKNAMELEN + 1;
 709         if ((buf = malloc(bufsz)) == NULL) {
 710                 rcm_log_message(RCM_ERROR,
 711                     _("VLAN: usage(%s) malloc failure(%s)\n"),
 712                     node->vc_resource, strerror(errno));
 713                 return (NULL);
 714         }
 715         (void) snprintf(buf, bufsz, fmt, name);
 716 
 717         if (node->vc_state & CACHE_NODE_OFFLINED) {
 718                 /* Nothing else to do */
 719                 rcm_log_message(RCM_TRACE2, "VLAN: usage (%s) info = %s\n",
 720                     node->vc_resource, buf);
 721                 return (buf);
 722         }
 723 
 724         for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
 725                 rcm_log_message(RCM_DEBUG, "VLAN:= %u\n", vlan->dv_vlanid);
 726 
 727                 if ((status = dladm_datalink_id2info(dld_handle,
 728                     vlan->dv_vlanid, NULL, NULL, NULL, name,
 729                     sizeof (name))) != DLADM_STATUS_OK) {
 730                         rcm_log_message(RCM_ERROR,
 731                             _("VLAN: usage(%s) get vlan %u name failure(%s)\n"),
 732                             node->vc_resource, vlan->dv_vlanid,
 733                             dladm_status2str(status, errmsg));
 734                         free(buf);
 735                         return (NULL);
 736                 }
 737 
 738                 (void) strlcat(buf, name, bufsz);
 739                 if (vlan->dv_next != NULL)
 740                         (void) strlcat(buf, sep, bufsz);
 741         }
 742 
 743         rcm_log_message(RCM_TRACE2, "VLAN: usage (%s) info = %s\n",
 744             node->vc_resource, buf);
 745 
 746         return (buf);
 747 }
 748 
 749 /*
 750  * Cache management routines, all cache management functions should be
 751  * be called with cache_lock held.
 752  */
 753 
 754 /*
 755  * cache_lookup() - Get a cache node for a resource.
 756  *                Call with cache lock held.
 757  *
 758  * This ensures that the cache is consistent with the system state and
 759  * returns a pointer to the cache element corresponding to the resource.
 760  */
 761 static link_cache_t *
 762 cache_lookup(rcm_handle_t *hd, char *rsrc, char options)
 763 {
 764         link_cache_t *node;
 765 
 766         rcm_log_message(RCM_TRACE2, "VLAN: cache lookup(%s)\n", rsrc);
 767 
 768         assert(MUTEX_HELD(&cache_lock));
 769         if (options & CACHE_REFRESH) {
 770                 /* drop lock since update locks cache again */
 771                 (void) mutex_unlock(&cache_lock);
 772                 (void) cache_update(hd);
 773                 (void) mutex_lock(&cache_lock);
 774         }
 775 
 776         node = cache_head.vc_next;
 777         for (; node != &cache_tail; node = node->vc_next) {
 778                 if (strcmp(rsrc, node->vc_resource) == 0) {
 779                         rcm_log_message(RCM_TRACE2,
 780                             "VLAN: cache lookup succeeded(%s)\n", rsrc);
 781                         return (node);
 782                 }
 783         }
 784         return (NULL);
 785 }
 786 
 787 /*
 788  * node_free - Free a node from the cache
 789  */
 790 static void
 791 node_free(link_cache_t *node)
 792 {
 793         dl_vlan_t *vlan, *next;
 794 
 795         if (node != NULL) {
 796                 free(node->vc_resource);
 797 
 798                 /* free the VLAN list */
 799                 for (vlan = node->vc_vlan; vlan != NULL; vlan = next) {
 800                         next = vlan->dv_next;
 801                         free(vlan);
 802                 }
 803                 free(node);
 804         }
 805 }
 806 
 807 /*
 808  * cache_insert - Insert a resource node in cache
 809  */
 810 static void
 811 cache_insert(link_cache_t *node)
 812 {
 813         assert(MUTEX_HELD(&cache_lock));
 814 
 815         /* insert at the head for best performance */
 816         node->vc_next = cache_head.vc_next;
 817         node->vc_prev = &cache_head;
 818 
 819         node->vc_next->vc_prev = node;
 820         node->vc_prev->vc_next = node;
 821 }
 822 
 823 /*
 824  * cache_remove() - Remove a resource node from cache.
 825  */
 826 static void
 827 cache_remove(link_cache_t *node)
 828 {
 829         assert(MUTEX_HELD(&cache_lock));
 830         node->vc_next->vc_prev = node->vc_prev;
 831         node->vc_prev->vc_next = node->vc_next;
 832         node->vc_next = NULL;
 833         node->vc_prev = NULL;
 834 }
 835 
 836 typedef struct vlan_update_arg_s {
 837         rcm_handle_t    *hd;
 838         int             retval;
 839 } vlan_update_arg_t;
 840 
 841 /*
 842  * vlan_update() - Update physical interface properties
 843  */
 844 static int
 845 vlan_update(dladm_handle_t handle, datalink_id_t vlanid, void *arg)
 846 {
 847         vlan_update_arg_t *vlan_update_argp = arg;
 848         rcm_handle_t *hd = vlan_update_argp->hd;
 849         link_cache_t *node;
 850         dl_vlan_t *vlan;
 851         char *rsrc;
 852         dladm_vlan_attr_t vlan_attr;
 853         dladm_status_t status;
 854         char errmsg[DLADM_STRSIZE];
 855         boolean_t newnode = B_FALSE;
 856         int ret = -1;
 857 
 858         rcm_log_message(RCM_TRACE2, "VLAN: vlan_update(%u)\n", vlanid);
 859 
 860         assert(MUTEX_HELD(&cache_lock));
 861         status = dladm_vlan_info(handle, vlanid, &vlan_attr, DLADM_OPT_ACTIVE);
 862         if (status != DLADM_STATUS_OK) {
 863                 rcm_log_message(RCM_TRACE1,
 864                     "VLAN: vlan_update() cannot get vlan information for "
 865                     "%u(%s)\n", vlanid, dladm_status2str(status, errmsg));
 866                 return (DLADM_WALK_CONTINUE);
 867         }
 868 
 869         rsrc = malloc(RCM_LINK_RESOURCE_MAX);
 870         if (rsrc == NULL) {
 871                 rcm_log_message(RCM_ERROR, _("VLAN: malloc error(%s): %u\n"),
 872                     strerror(errno), vlanid);
 873                 goto done;
 874         }
 875 
 876         (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
 877             RCM_LINK_PREFIX, vlan_attr.dv_linkid);
 878 
 879         node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
 880         if (node != NULL) {
 881                 rcm_log_message(RCM_DEBUG,
 882                     "VLAN: %s already registered (vlanid:%d)\n",
 883                     rsrc, vlan_attr.dv_vid);
 884                 free(rsrc);
 885         } else {
 886                 rcm_log_message(RCM_DEBUG,
 887                     "VLAN: %s is a new resource (vlanid:%d)\n",
 888                     rsrc, vlan_attr.dv_vid);
 889                 if ((node = calloc(1, sizeof (link_cache_t))) == NULL) {
 890                         free(rsrc);
 891                         rcm_log_message(RCM_ERROR, _("VLAN: calloc: %s\n"),
 892                             strerror(errno));
 893                         goto done;
 894                 }
 895 
 896                 node->vc_resource = rsrc;
 897                 node->vc_vlan = NULL;
 898                 node->vc_linkid = vlan_attr.dv_linkid;
 899                 node->vc_state |= CACHE_NODE_NEW;
 900                 newnode = B_TRUE;
 901         }
 902 
 903         for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
 904                 if (vlan->dv_vlanid == vlanid) {
 905                         vlan->dv_flags &= ~VLAN_STALE;
 906                         break;
 907                 }
 908         }
 909 
 910         if (vlan == NULL) {
 911                 if ((vlan = calloc(1, sizeof (dl_vlan_t))) == NULL) {
 912                         rcm_log_message(RCM_ERROR, _("VLAN: malloc: %s\n"),
 913                             strerror(errno));
 914                         if (newnode) {
 915                                 free(rsrc);
 916                                 free(node);
 917                         }
 918                         goto done;
 919                 }
 920                 vlan->dv_vlanid = vlanid;
 921                 vlan->dv_next = node->vc_vlan;
 922                 vlan->dv_prev = NULL;
 923                 if (node->vc_vlan != NULL)
 924                         node->vc_vlan->dv_prev = vlan;
 925                 node->vc_vlan = vlan;
 926         }
 927 
 928         node->vc_state &= ~CACHE_NODE_STALE;
 929 
 930         if (newnode)
 931                 cache_insert(node);
 932 
 933         rcm_log_message(RCM_TRACE3, "VLAN: vlan_update: succeeded(%u)\n",
 934             vlanid);
 935         ret = 0;
 936 done:
 937         vlan_update_argp->retval = ret;
 938         return (ret == 0 ? DLADM_WALK_CONTINUE : DLADM_WALK_TERMINATE);
 939 }
 940 
 941 /*
 942  * vlan_update_all() - Determine all VLAN links in the system
 943  */
 944 static int
 945 vlan_update_all(rcm_handle_t *hd)
 946 {
 947         vlan_update_arg_t arg = {NULL, 0};
 948 
 949         rcm_log_message(RCM_TRACE2, "VLAN: vlan_update_all\n");
 950 
 951         assert(MUTEX_HELD(&cache_lock));
 952         arg.hd = hd;
 953         (void) dladm_walk_datalink_id(vlan_update, dld_handle, &arg,
 954             DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
 955         return (arg.retval);
 956 }
 957 
 958 /*
 959  * cache_update() - Update cache with latest interface info
 960  */
 961 static int
 962 cache_update(rcm_handle_t *hd)
 963 {
 964         link_cache_t *node, *nnode;
 965         dl_vlan_t *vlan;
 966         int rv;
 967 
 968         rcm_log_message(RCM_TRACE2, "VLAN: cache_update\n");
 969 
 970         (void) mutex_lock(&cache_lock);
 971 
 972         /* first we walk the entire cache, marking each entry stale */
 973         node = cache_head.vc_next;
 974         for (; node != &cache_tail; node = node->vc_next) {
 975                 node->vc_state |= CACHE_NODE_STALE;
 976                 for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next)
 977                         vlan->dv_flags |= VLAN_STALE;
 978         }
 979 
 980         rv = vlan_update_all(hd);
 981 
 982         /*
 983          * Continue to delete all stale nodes from the cache even
 984          * vlan_update_all() failed. Unregister link that are not offlined
 985          * and still in cache
 986          */
 987         for (node = cache_head.vc_next; node != &cache_tail; node = nnode) {
 988                 dl_vlan_t *vlan, *next;
 989 
 990                 for (vlan = node->vc_vlan; vlan != NULL; vlan = next) {
 991                         next = vlan->dv_next;
 992 
 993                         /* clear stale VLANs */
 994                         if (vlan->dv_flags & VLAN_STALE) {
 995                                 if (vlan->dv_prev != NULL)
 996                                         vlan->dv_prev->dv_next = next;
 997                                 else
 998                                         node->vc_vlan = next;
 999 
1000                                 if (next != NULL)
1001                                         next->dv_prev = vlan->dv_prev;
1002                                 free(vlan);
1003                         }
1004                 }
1005 
1006                 nnode = node->vc_next;
1007                 if (node->vc_state & CACHE_NODE_STALE) {
1008                         (void) rcm_unregister_interest(hd, node->vc_resource,
1009                             0);
1010                         rcm_log_message(RCM_DEBUG, "VLAN: unregistered %s\n",
1011                             node->vc_resource);
1012                         assert(node->vc_vlan == NULL);
1013                         cache_remove(node);
1014                         node_free(node);
1015                         continue;
1016                 }
1017 
1018                 if (!(node->vc_state & CACHE_NODE_NEW))
1019                         continue;
1020 
1021                 if (rcm_register_interest(hd, node->vc_resource, 0, NULL) !=
1022                     RCM_SUCCESS) {
1023                         rcm_log_message(RCM_ERROR,
1024                             _("VLAN: failed to register %s\n"),
1025                             node->vc_resource);
1026                         rv = -1;
1027                 } else {
1028                         rcm_log_message(RCM_DEBUG, "VLAN: registered %s\n",
1029                             node->vc_resource);
1030                         node->vc_state &= ~CACHE_NODE_NEW;
1031                 }
1032         }
1033 
1034         (void) mutex_unlock(&cache_lock);
1035         return (rv);
1036 }
1037 
1038 /*
1039  * cache_free() - Empty the cache
1040  */
1041 static void
1042 cache_free()
1043 {
1044         link_cache_t *node;
1045 
1046         rcm_log_message(RCM_TRACE2, "VLAN: cache_free\n");
1047 
1048         (void) mutex_lock(&cache_lock);
1049         node = cache_head.vc_next;
1050         while (node != &cache_tail) {
1051                 cache_remove(node);
1052                 node_free(node);
1053                 node = cache_head.vc_next;
1054         }
1055         (void) mutex_unlock(&cache_lock);
1056 }
1057 
1058 /*
1059  * vlan_log_err() - RCM error log wrapper
1060  */
1061 static void
1062 vlan_log_err(datalink_id_t linkid, char **errorp, char *errmsg)
1063 {
1064         char link[MAXLINKNAMELEN];
1065         char errstr[DLADM_STRSIZE];
1066         dladm_status_t status;
1067         int len;
1068         const char *errfmt;
1069         char *error;
1070 
1071         link[0] = '\0';
1072         if (linkid != DATALINK_INVALID_LINKID) {
1073                 char rsrc[RCM_LINK_RESOURCE_MAX];
1074 
1075                 (void) snprintf(rsrc, sizeof (rsrc), "%s/%u",
1076                     RCM_LINK_PREFIX, linkid);
1077 
1078                 rcm_log_message(RCM_ERROR, _("VLAN: %s(%s)\n"), errmsg, rsrc);
1079                 if ((status = dladm_datalink_id2info(dld_handle, linkid, NULL,
1080                     NULL, NULL, link, sizeof (link))) != DLADM_STATUS_OK) {
1081                         rcm_log_message(RCM_WARNING,
1082                             _("VLAN: cannot get link name for (%s) %s\n"),
1083                             rsrc, dladm_status2str(status, errstr));
1084                 }
1085         } else {
1086                 rcm_log_message(RCM_ERROR, _("VLAN: %s\n"), errmsg);
1087         }
1088 
1089         errfmt = strlen(link) > 0 ? _("VLAN: %s(%s)") : _("VLAN: %s");
1090         len = strlen(errfmt) + strlen(errmsg) + MAXLINKNAMELEN + 1;
1091         if ((error = malloc(len)) != NULL) {
1092                 if (strlen(link) > 0)
1093                         (void) snprintf(error, len, errfmt, errmsg, link);
1094                 else
1095                         (void) snprintf(error, len, errfmt, errmsg);
1096         }
1097 
1098         if (errorp != NULL)
1099                 *errorp = error;
1100 }
1101 
1102 /*
1103  * vlan_consumer_online()
1104  *
1105  *      Notify online to VLAN consumers.
1106  */
1107 /* ARGSUSED */
1108 static void
1109 vlan_consumer_online(rcm_handle_t *hd, link_cache_t *node, char **errorp,
1110     uint_t flags, rcm_info_t **info)
1111 {
1112         dl_vlan_t *vlan;
1113         char rsrc[RCM_LINK_RESOURCE_MAX];
1114 
1115         rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_online (%s)\n",
1116             node->vc_resource);
1117 
1118         for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
1119                 if (!(vlan->dv_flags & VLAN_CONSUMER_OFFLINED))
1120                         continue;
1121 
1122                 (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
1123                     RCM_LINK_PREFIX, vlan->dv_vlanid);
1124 
1125                 if (rcm_notify_online(hd, rsrc, flags, info) == RCM_SUCCESS)
1126                         vlan->dv_flags &= ~VLAN_CONSUMER_OFFLINED;
1127         }
1128 
1129         rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_online done\n");
1130 }
1131 
1132 /*
1133  * vlan_consumer_offline()
1134  *
1135  *      Offline VLAN consumers.
1136  */
1137 static int
1138 vlan_consumer_offline(rcm_handle_t *hd, link_cache_t *node, char **errorp,
1139     uint_t flags, rcm_info_t **info)
1140 {
1141         dl_vlan_t *vlan;
1142         char rsrc[RCM_LINK_RESOURCE_MAX];
1143         int ret = RCM_SUCCESS;
1144 
1145         rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_offline (%s)\n",
1146             node->vc_resource);
1147 
1148         for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
1149                 (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
1150                     RCM_LINK_PREFIX, vlan->dv_vlanid);
1151 
1152                 ret = rcm_request_offline(hd, rsrc, flags, info);
1153                 if (ret != RCM_SUCCESS)
1154                         break;
1155 
1156                 vlan->dv_flags |= VLAN_CONSUMER_OFFLINED;
1157         }
1158 
1159         if (vlan != NULL)
1160                 vlan_consumer_online(hd, node, errorp, flags, info);
1161 
1162         rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_offline done\n");
1163         return (ret);
1164 }
1165 
1166 /*
1167  * Send RCM_RESOURCE_LINK_NEW events to other modules about new VLANs.
1168  * Return 0 on success, -1 on failure.
1169  */
1170 static int
1171 vlan_notify_new_vlan(rcm_handle_t *hd, char *rsrc)
1172 {
1173         link_cache_t *node;
1174         dl_vlan_t *vlan;
1175         nvlist_t *nvl = NULL;
1176         uint64_t id;
1177         int ret = -1;
1178 
1179         rcm_log_message(RCM_TRACE2, "VLAN: vlan_notify_new_vlan (%s)\n", rsrc);
1180 
1181         (void) mutex_lock(&cache_lock);
1182         if ((node = cache_lookup(hd, rsrc, CACHE_REFRESH)) == NULL) {
1183                 (void) mutex_unlock(&cache_lock);
1184                 return (0);
1185         }
1186 
1187         if (nvlist_alloc(&nvl, 0, 0) != 0) {
1188                 (void) mutex_unlock(&cache_lock);
1189                 rcm_log_message(RCM_WARNING,
1190                     _("VLAN: failed to allocate nvlist\n"));
1191                 goto done;
1192         }
1193 
1194         for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
1195                 rcm_log_message(RCM_TRACE2,
1196                     "VLAN: vlan_notify_new_vlan add (%u)\n",
1197                     vlan->dv_vlanid);
1198 
1199                 id = vlan->dv_vlanid;
1200                 if (nvlist_add_uint64(nvl, RCM_NV_LINKID, id) != 0) {
1201                         rcm_log_message(RCM_ERROR,
1202                             _("VLAN: failed to construct nvlist\n"));
1203                         (void) mutex_unlock(&cache_lock);
1204                         goto done;
1205                 }
1206         }
1207         (void) mutex_unlock(&cache_lock);
1208 
1209         if (rcm_notify_event(hd, RCM_RESOURCE_LINK_NEW, 0, nvl, NULL) !=
1210             RCM_SUCCESS) {
1211                 rcm_log_message(RCM_ERROR,
1212                     _("VLAN: failed to notify %s event for %s\n"),
1213                     RCM_RESOURCE_LINK_NEW, node->vc_resource);
1214                 goto done;
1215         }
1216 
1217         ret = 0;
1218 done:
1219         if (nvl != NULL)
1220                 nvlist_free(nvl);
1221         return (ret);
1222 }
1223 
1224 /*
1225  * vlan_consumer_notify() - Notify consumers of VLANs coming back online.
1226  */
1227 static int
1228 vlan_consumer_notify(rcm_handle_t *hd, datalink_id_t linkid, char **errorp,
1229     uint_t flags, rcm_info_t **info)
1230 {
1231         char rsrc[RCM_LINK_RESOURCE_MAX];
1232         link_cache_t *node;
1233 
1234         /* Check for the interface in the cache */
1235         (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u", RCM_LINK_PREFIX,
1236             linkid);
1237 
1238         rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_notify(%s)\n", rsrc);
1239 
1240         /*
1241          * Inform IP consumers of the new link.
1242          */
1243         if (vlan_notify_new_vlan(hd, rsrc) != 0) {
1244                 (void) mutex_lock(&cache_lock);
1245                 if ((node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH)) != NULL) {
1246                         (void) vlan_offline_vlan(node, VLAN_STALE,
1247                             CACHE_NODE_STALE);
1248                 }
1249                 (void) mutex_unlock(&cache_lock);
1250                 rcm_log_message(RCM_TRACE2,
1251                     "VLAN: vlan_notify_new_vlan failed(%s)\n", rsrc);
1252                 return (-1);
1253         }
1254 
1255         rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_notify succeeded\n");
1256         return (0);
1257 }
1258 
1259 typedef struct vlan_up_arg_s {
1260         datalink_id_t   linkid;
1261         int             retval;
1262 } vlan_up_arg_t;
1263 
1264 static int
1265 vlan_up(dladm_handle_t handle, datalink_id_t vlanid, void *arg)
1266 {
1267         vlan_up_arg_t *vlan_up_argp = arg;
1268         dladm_status_t status;
1269         dladm_vlan_attr_t vlan_attr;
1270         char errmsg[DLADM_STRSIZE];
1271 
1272         status = dladm_vlan_info(handle, vlanid, &vlan_attr, DLADM_OPT_PERSIST);
1273         if (status != DLADM_STATUS_OK) {
1274                 rcm_log_message(RCM_TRACE1,
1275                     "VLAN: vlan_up(): cannot get information for VLAN %u "
1276                     "(%s)\n", vlanid, dladm_status2str(status, errmsg));
1277                 return (DLADM_WALK_CONTINUE);
1278         }
1279 
1280         if (vlan_attr.dv_linkid != vlan_up_argp->linkid)
1281                 return (DLADM_WALK_CONTINUE);
1282 
1283         rcm_log_message(RCM_TRACE3, "VLAN: vlan_up(%u)\n", vlanid);
1284         if ((status = dladm_vlan_up(handle, vlanid)) == DLADM_STATUS_OK)
1285                 return (DLADM_WALK_CONTINUE);
1286 
1287         /*
1288          * Prompt the warning message and continue to UP other VLANs.
1289          */
1290         rcm_log_message(RCM_WARNING,
1291             _("VLAN: VLAN up failed (%u): %s\n"),
1292             vlanid, dladm_status2str(status, errmsg));
1293 
1294         vlan_up_argp->retval = -1;
1295         return (DLADM_WALK_CONTINUE);
1296 }
1297 
1298 /*
1299  * vlan_configure() - Configure VLANs over a physical link after it attaches
1300  */
1301 static int
1302 vlan_configure(rcm_handle_t *hd, datalink_id_t linkid)
1303 {
1304         char rsrc[RCM_LINK_RESOURCE_MAX];
1305         link_cache_t *node;
1306         vlan_up_arg_t arg = {DATALINK_INVALID_LINKID, 0};
1307 
1308         /* Check for the VLANs in the cache */
1309         (void) snprintf(rsrc, sizeof (rsrc), "%s/%u", RCM_LINK_PREFIX, linkid);
1310 
1311         rcm_log_message(RCM_TRACE2, "VLAN: vlan_configure(%s)\n", rsrc);
1312 
1313         /* Check if the link is new or was previously offlined */
1314         (void) mutex_lock(&cache_lock);
1315         if (((node = cache_lookup(hd, rsrc, CACHE_REFRESH)) != NULL) &&
1316             (!(node->vc_state & CACHE_NODE_OFFLINED))) {
1317                 rcm_log_message(RCM_TRACE2,
1318                     "VLAN: Skipping configured interface(%s)\n", rsrc);
1319                 (void) mutex_unlock(&cache_lock);
1320                 return (0);
1321         }
1322         (void) mutex_unlock(&cache_lock);
1323 
1324         arg.linkid = linkid;
1325         (void) dladm_walk_datalink_id(vlan_up, dld_handle, &arg,
1326             DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
1327 
1328         if (arg.retval == 0) {
1329                 rcm_log_message(RCM_TRACE2,
1330                     "VLAN: vlan_configure succeeded(%s)\n", rsrc);
1331         }
1332         return (arg.retval);
1333 }