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