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