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