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 VNIC 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 <libdlvnic.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 /* VNIC link flags */ 58 typedef enum { 59 VNIC_OFFLINED = 0x1, 60 VNIC_CONSUMER_OFFLINED = 0x2, 61 VNIC_STALE = 0x4 62 } vnic_flag_t; 63 64 /* link representation */ 65 typedef struct dl_vnic { 66 struct dl_vnic *dlv_next; /* next VNIC on the same link */ 67 struct dl_vnic *dlv_prev; /* prev VNIC on the same link */ 68 datalink_id_t dlv_vnic_id; 69 vnic_flag_t dlv_flags; /* VNIC link flags */ 70 } dl_vnic_t; 71 72 /* VNIC 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_vnic_t *vc_vnic; /* VNIC 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 VNICs 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 vnic_register(rcm_handle_t *); 105 static int vnic_unregister(rcm_handle_t *); 106 static int vnic_get_info(rcm_handle_t *, char *, id_t, uint_t, 107 char **, char **, nvlist_t *, rcm_info_t **); 108 static int vnic_suspend(rcm_handle_t *, char *, id_t, 109 timespec_t *, uint_t, char **, rcm_info_t **); 110 static int vnic_resume(rcm_handle_t *, char *, id_t, uint_t, 111 char **, rcm_info_t **); 112 static int vnic_offline(rcm_handle_t *, char *, id_t, uint_t, 113 char **, rcm_info_t **); 114 static int vnic_undo_offline(rcm_handle_t *, char *, id_t, uint_t, 115 char **, rcm_info_t **); 116 static int vnic_remove(rcm_handle_t *, char *, id_t, uint_t, 117 char **, rcm_info_t **); 118 static int vnic_notify_event(rcm_handle_t *, char *, id_t, uint_t, 119 char **, nvlist_t *, rcm_info_t **); 120 static int vnic_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 vnic_consumer_offline(rcm_handle_t *, link_cache_t *, 130 char **, uint_t, rcm_info_t **); 131 static void vnic_consumer_online(rcm_handle_t *, link_cache_t *, 132 char **, uint_t, rcm_info_t **); 133 static int vnic_offline_vnic(link_cache_t *, uint32_t, 134 cache_node_state_t); 135 static void vnic_online_vnic(link_cache_t *); 136 static char *vnic_usage(link_cache_t *); 137 static void vnic_log_err(datalink_id_t, char **, char *); 138 static int vnic_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 vnic_ops = 143 { 144 RCM_MOD_OPS_VERSION, 145 vnic_register, 146 vnic_unregister, 147 vnic_get_info, 148 vnic_suspend, 149 vnic_resume, 150 vnic_offline, 151 vnic_undo_offline, 152 vnic_remove, 153 NULL, 154 NULL, 155 vnic_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, "VNIC: 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 (&vnic_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, "VNIC: mod_info\n"); 183 184 return ("VNIC module"); 185 } 186 187 /* 188 * rcm_mod_fini() - Destroy the network VNIC cache. 189 */ 190 int 191 rcm_mod_fini(void) 192 { 193 rcm_log_message(RCM_TRACE1, "VNIC: mod_fini\n"); 194 195 /* 196 * Note that vnic_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 * vnic_register() - Make sure the cache is properly sync'ed, and its 208 * registrations are in order. 209 */ 210 static int 211 vnic_register(rcm_handle_t *hd) 212 { 213 rcm_log_message(RCM_TRACE1, "VNIC: 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 _("VNIC: failed to register %s\n"), 227 RCM_RESOURCE_LINK_NEW); 228 return (RCM_FAILURE); 229 } else { 230 rcm_log_message(RCM_DEBUG, "VNIC: registered %s\n", 231 RCM_RESOURCE_LINK_NEW); 232 events_registered++; 233 } 234 } 235 236 return (RCM_SUCCESS); 237 } 238 239 /* 240 * vnic_unregister() - Walk the cache, unregistering all the networks. 241 */ 242 static int 243 vnic_unregister(rcm_handle_t *hd) 244 { 245 link_cache_t *node; 246 247 rcm_log_message(RCM_TRACE1, "VNIC: 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 _("VNIC: 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 _("VNIC: failed to unregister %s\n"), 275 RCM_RESOURCE_LINK_NEW); 276 return (RCM_FAILURE); 277 } else { 278 rcm_log_message(RCM_DEBUG, "VNIC: unregistered %s\n", 279 RCM_RESOURCE_LINK_NEW); 280 events_registered--; 281 } 282 } 283 284 return (RCM_SUCCESS); 285 } 286 287 /* 288 * vnic_offline() - Offline VNICs on a specific node. 289 */ 290 static int 291 vnic_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, "VNIC: 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 vnic_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 VNICs to be offlined 310 */ 311 if (vnic_consumer_offline(hd, node, errorp, flags, info) == 312 RCM_SUCCESS) { 313 rcm_log_message(RCM_DEBUG, 314 "VNIC: consumers agreed on offline\n"); 315 } else { 316 vnic_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 "VNIC: offline query succeeded(%s)\n", rsrc); 326 (void) mutex_unlock(&cache_lock); 327 return (RCM_SUCCESS); 328 } 329 330 if (vnic_offline_vnic(node, VNIC_OFFLINED, CACHE_NODE_OFFLINED) != 331 RCM_SUCCESS) { 332 vnic_online_vnic(node); 333 vnic_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, "VNIC: Offline succeeded(%s)\n", rsrc); 339 (void) mutex_unlock(&cache_lock); 340 return (RCM_SUCCESS); 341 } 342 343 /* 344 * vnic_undo_offline() - Undo offline of a previously offlined node. 345 */ 346 /*ARGSUSED*/ 347 static int 348 vnic_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, "VNIC: 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 vnic_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 vnic_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 vnic_online_vnic(node); 373 374 /* 375 * Inform IP interfaces on associated VNICs to be onlined 376 */ 377 vnic_consumer_online(hd, node, errorp, flags, info); 378 379 node->vc_state &= ~CACHE_NODE_OFFLINED; 380 rcm_log_message(RCM_TRACE1, "VNIC: online succeeded(%s)\n", rsrc); 381 (void) mutex_unlock(&cache_lock); 382 return (RCM_SUCCESS); 383 } 384 385 static void 386 vnic_online_vnic(link_cache_t *node) 387 { 388 dl_vnic_t *vnic; 389 dladm_status_t status; 390 char errmsg[DLADM_STRSIZE]; 391 392 /* 393 * Try to bring on all offlined VNICs 394 */ 395 for (vnic = node->vc_vnic; vnic != NULL; vnic = vnic->dlv_next) { 396 if (!(vnic->dlv_flags & VNIC_OFFLINED)) 397 continue; 398 399 if ((status = dladm_vnic_up(vnic->dlv_vnic_id, 0)) != 400 DLADM_STATUS_OK) { 401 /* 402 * Print a warning message and continue to online 403 * other VNICs. 404 */ 405 rcm_log_message(RCM_WARNING, 406 _("VNIC: VNIC online failed (%u): %s\n"), 407 vnic->dlv_vnic_id, 408 dladm_status2str(status, errmsg)); 409 } else { 410 vnic->dlv_flags &= ~VNIC_OFFLINED; 411 } 412 } 413 } 414 415 static int 416 vnic_offline_vnic(link_cache_t *node, uint32_t flags, cache_node_state_t state) 417 { 418 dl_vnic_t *vnic; 419 dladm_status_t status; 420 char errmsg[DLADM_STRSIZE]; 421 422 rcm_log_message(RCM_TRACE2, "VNIC: vnic_offline_vnic (%s %u %u)\n", 423 node->vc_resource, flags, state); 424 425 /* 426 * Try to delete all explicit created VNIC 427 */ 428 for (vnic = node->vc_vnic; vnic != NULL; vnic = vnic->dlv_next) { 429 430 if ((status = dladm_vnic_delete(vnic->dlv_vnic_id, 431 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 432 rcm_log_message(RCM_WARNING, 433 _("VNIC: VNIC offline failed (%u): %s\n"), 434 vnic->dlv_vnic_id, 435 dladm_status2str(status, errmsg)); 436 return (RCM_FAILURE); 437 } else { 438 rcm_log_message(RCM_TRACE1, 439 "VNIC: VNIC offline succeeded(%u)\n", 440 vnic->dlv_vnic_id); 441 vnic->dlv_flags |= flags; 442 } 443 } 444 445 node->vc_state |= state; 446 return (RCM_SUCCESS); 447 } 448 449 /* 450 * vnic_get_info() - Gather usage information for this resource. 451 */ 452 /*ARGSUSED*/ 453 int 454 vnic_get_info(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 455 char **usagep, char **errorp, nvlist_t *props, rcm_info_t **info) 456 { 457 link_cache_t *node; 458 459 rcm_log_message(RCM_TRACE1, "VNIC: get_info(%s)\n", rsrc); 460 461 (void) mutex_lock(&cache_lock); 462 node = cache_lookup(hd, rsrc, CACHE_REFRESH); 463 if (node == NULL) { 464 rcm_log_message(RCM_INFO, 465 _("VNIC: get_info(%s) unrecognized resource\n"), rsrc); 466 (void) mutex_unlock(&cache_lock); 467 errno = ENOENT; 468 return (RCM_FAILURE); 469 } 470 471 *usagep = vnic_usage(node); 472 (void) mutex_unlock(&cache_lock); 473 if (*usagep == NULL) { 474 /* most likely malloc failure */ 475 rcm_log_message(RCM_ERROR, 476 _("VNIC: get_info(%s) malloc failure\n"), rsrc); 477 (void) mutex_unlock(&cache_lock); 478 errno = ENOMEM; 479 return (RCM_FAILURE); 480 } 481 482 /* Set client/role properties */ 483 (void) nvlist_add_string(props, RCM_CLIENT_NAME, "VNIC"); 484 485 rcm_log_message(RCM_TRACE1, "VNIC: get_info(%s) info = %s\n", 486 rsrc, *usagep); 487 return (RCM_SUCCESS); 488 } 489 490 /* 491 * vnic_suspend() - Nothing to do, always okay 492 */ 493 /*ARGSUSED*/ 494 static int 495 vnic_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval, 496 uint_t flags, char **errorp, rcm_info_t **info) 497 { 498 rcm_log_message(RCM_TRACE1, "VNIC: suspend(%s)\n", rsrc); 499 return (RCM_SUCCESS); 500 } 501 502 /* 503 * vnic_resume() - Nothing to do, always okay 504 */ 505 /*ARGSUSED*/ 506 static int 507 vnic_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 508 char **errorp, rcm_info_t **info) 509 { 510 rcm_log_message(RCM_TRACE1, "VNIC: resume(%s)\n", rsrc); 511 return (RCM_SUCCESS); 512 } 513 514 /* 515 * vnic_consumer_remove() 516 * 517 * Notify VNIC consumers to remove cache. 518 */ 519 static int 520 vnic_consumer_remove(rcm_handle_t *hd, link_cache_t *node, uint_t flags, 521 rcm_info_t **info) 522 { 523 dl_vnic_t *vnic = NULL; 524 char rsrc[RCM_LINK_RESOURCE_MAX]; 525 int ret = RCM_SUCCESS; 526 527 rcm_log_message(RCM_TRACE2, "VNIC: vnic_consumer_remove (%s)\n", 528 node->vc_resource); 529 530 for (vnic = node->vc_vnic; vnic != NULL; vnic = vnic->dlv_next) { 531 532 /* 533 * This will only be called when the offline operation 534 * succeeds, so the VNIC consumers must have been offlined 535 * at this point. 536 */ 537 assert(vnic->dlv_flags & VNIC_CONSUMER_OFFLINED); 538 539 (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u", 540 RCM_LINK_PREFIX, vnic->dlv_vnic_id); 541 542 ret = rcm_notify_remove(hd, rsrc, flags, info); 543 if (ret != RCM_SUCCESS) { 544 rcm_log_message(RCM_WARNING, 545 _("VNIC: notify remove failed (%s)\n"), rsrc); 546 break; 547 } 548 } 549 550 rcm_log_message(RCM_TRACE2, "VNIC: vnic_consumer_remove done\n"); 551 return (ret); 552 } 553 554 /* 555 * vnic_remove() - remove a resource from cache 556 */ 557 /*ARGSUSED*/ 558 static int 559 vnic_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 560 char **errorp, rcm_info_t **info) 561 { 562 link_cache_t *node; 563 int rv; 564 565 rcm_log_message(RCM_TRACE1, "VNIC: remove(%s)\n", rsrc); 566 567 (void) mutex_lock(&cache_lock); 568 node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH); 569 if (node == NULL) { 570 rcm_log_message(RCM_INFO, 571 _("VNIC: remove(%s) unrecognized resource\n"), rsrc); 572 (void) mutex_unlock(&cache_lock); 573 errno = ENOENT; 574 return (RCM_FAILURE); 575 } 576 577 /* remove the cached entry for the resource */ 578 cache_remove(node); 579 (void) mutex_unlock(&cache_lock); 580 581 rv = vnic_consumer_remove(hd, node, flags, info); 582 node_free(node); 583 return (rv); 584 } 585 586 /* 587 * vnic_notify_event - Project private implementation to receive new resource 588 * events. It intercepts all new resource events. If the 589 * new resource is a network resource, pass up a notify 590 * for it too. The new resource need not be cached, since 591 * it is done at register again. 592 */ 593 /*ARGSUSED*/ 594 static int 595 vnic_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 596 char **errorp, nvlist_t *nvl, rcm_info_t **info) 597 { 598 nvpair_t *nvp = NULL; 599 datalink_id_t linkid; 600 uint64_t id64; 601 int rv = RCM_SUCCESS; 602 603 rcm_log_message(RCM_TRACE1, "VNIC: notify_event(%s)\n", rsrc); 604 605 if (strcmp(rsrc, RCM_RESOURCE_LINK_NEW) != 0) { 606 vnic_log_err(DATALINK_INVALID_LINKID, errorp, 607 "unrecognized event"); 608 errno = EINVAL; 609 return (RCM_FAILURE); 610 } 611 612 /* Update cache to reflect latest VNICs */ 613 if (cache_update(hd) < 0) { 614 vnic_log_err(DATALINK_INVALID_LINKID, errorp, 615 "private Cache update failed"); 616 return (RCM_FAILURE); 617 } 618 619 /* 620 * Try best to recover all configuration. 621 */ 622 rcm_log_message(RCM_DEBUG, "VNIC: process_nvlist\n"); 623 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 624 if (strcmp(nvpair_name(nvp), RCM_NV_LINKID) != 0) 625 continue; 626 627 if (nvpair_value_uint64(nvp, &id64) != 0) { 628 vnic_log_err(DATALINK_INVALID_LINKID, errorp, 629 "cannot get linkid"); 630 rv = RCM_FAILURE; 631 continue; 632 } 633 634 linkid = (datalink_id_t)id64; 635 if (vnic_configure(hd, linkid) != 0) { 636 vnic_log_err(linkid, errorp, "configuring failed"); 637 rv = RCM_FAILURE; 638 continue; 639 } 640 641 /* Notify all VNIC consumers */ 642 if (vnic_consumer_notify(hd, linkid, errorp, flags, 643 info) != 0) { 644 vnic_log_err(linkid, errorp, "consumer notify failed"); 645 rv = RCM_FAILURE; 646 } 647 } 648 649 rcm_log_message(RCM_TRACE1, 650 "VNIC: notify_event: link configuration complete\n"); 651 return (rv); 652 } 653 654 /* 655 * vnic_usage - Determine the usage of a link. 656 * The returned buffer is owned by caller, and the caller 657 * must free it up when done. 658 */ 659 static char * 660 vnic_usage(link_cache_t *node) 661 { 662 dl_vnic_t *vnic; 663 int nvnic; 664 char *buf; 665 const char *fmt; 666 char *sep; 667 char errmsg[DLADM_STRSIZE]; 668 char name[MAXLINKNAMELEN]; 669 dladm_status_t status; 670 size_t bufsz; 671 672 rcm_log_message(RCM_TRACE2, "VNIC: usage(%s)\n", node->vc_resource); 673 674 assert(MUTEX_HELD(&cache_lock)); 675 if ((status = dladm_datalink_id2info(node->vc_linkid, NULL, NULL, NULL, 676 name, sizeof (name))) != DLADM_STATUS_OK) { 677 rcm_log_message(RCM_ERROR, 678 _("VNIC: usage(%s) get link name failure(%s)\n"), 679 node->vc_resource, dladm_status2str(status, errmsg)); 680 return (NULL); 681 } 682 683 if (node->vc_state & CACHE_NODE_OFFLINED) 684 fmt = _("%1$s offlined"); 685 else 686 fmt = _("%1$s VNICs: "); 687 688 /* TRANSLATION_NOTE: separator used between VNIC linkids */ 689 sep = _(", "); 690 691 nvnic = 0; 692 for (vnic = node->vc_vnic; vnic != NULL; vnic = vnic->dlv_next) 693 nvnic++; 694 695 /* space for VNICs and separators, plus message */ 696 bufsz = nvnic * (MAXLINKNAMELEN + strlen(sep)) + 697 strlen(fmt) + MAXLINKNAMELEN + 1; 698 if ((buf = malloc(bufsz)) == NULL) { 699 rcm_log_message(RCM_ERROR, 700 _("VNIC: usage(%s) malloc failure(%s)\n"), 701 node->vc_resource, strerror(errno)); 702 return (NULL); 703 } 704 (void) snprintf(buf, bufsz, fmt, name); 705 706 if (node->vc_state & CACHE_NODE_OFFLINED) { 707 /* Nothing else to do */ 708 rcm_log_message(RCM_TRACE2, "VNIC: usage (%s) info = %s\n", 709 node->vc_resource, buf); 710 return (buf); 711 } 712 713 for (vnic = node->vc_vnic; vnic != NULL; vnic = vnic->dlv_next) { 714 rcm_log_message(RCM_DEBUG, "VNIC:= %u\n", vnic->dlv_vnic_id); 715 716 if ((status = dladm_datalink_id2info(vnic->dlv_vnic_id, NULL, 717 NULL, NULL, name, sizeof (name))) != DLADM_STATUS_OK) { 718 rcm_log_message(RCM_ERROR, 719 _("VNIC: usage(%s) get vnic %u name failure(%s)\n"), 720 node->vc_resource, vnic->dlv_vnic_id, 721 dladm_status2str(status, errmsg)); 722 free(buf); 723 return (NULL); 724 } 725 726 (void) strlcat(buf, name, bufsz); 727 if (vnic->dlv_next != NULL) 728 (void) strlcat(buf, sep, bufsz); 729 } 730 731 rcm_log_message(RCM_TRACE2, "VNIC: usage (%s) info = %s\n", 732 node->vc_resource, buf); 733 734 return (buf); 735 } 736 737 /* 738 * Cache management routines, all cache management functions should be 739 * be called with cache_lock held. 740 */ 741 742 /* 743 * cache_lookup() - Get a cache node for a resource. 744 * Call with cache lock held. 745 * 746 * This ensures that the cache is consistent with the system state and 747 * returns a pointer to the cache element corresponding to the resource. 748 */ 749 static link_cache_t * 750 cache_lookup(rcm_handle_t *hd, char *rsrc, char options) 751 { 752 link_cache_t *node; 753 754 rcm_log_message(RCM_TRACE2, "VNIC: cache lookup(%s)\n", rsrc); 755 756 assert(MUTEX_HELD(&cache_lock)); 757 if (options & CACHE_REFRESH) { 758 /* drop lock since update locks cache again */ 759 (void) mutex_unlock(&cache_lock); 760 (void) cache_update(hd); 761 (void) mutex_lock(&cache_lock); 762 } 763 764 node = cache_head.vc_next; 765 for (; node != &cache_tail; node = node->vc_next) { 766 if (strcmp(rsrc, node->vc_resource) == 0) { 767 rcm_log_message(RCM_TRACE2, 768 "VNIC: cache lookup succeeded(%s)\n", rsrc); 769 return (node); 770 } 771 } 772 return (NULL); 773 } 774 775 /* 776 * node_free - Free a node from the cache 777 */ 778 static void 779 node_free(link_cache_t *node) 780 { 781 dl_vnic_t *vnic, *next; 782 783 if (node != NULL) { 784 free(node->vc_resource); 785 786 /* free the VNIC list */ 787 for (vnic = node->vc_vnic; vnic != NULL; vnic = next) { 788 next = vnic->dlv_next; 789 free(vnic); 790 } 791 free(node); 792 } 793 } 794 795 /* 796 * cache_insert - Insert a resource node in cache 797 */ 798 static void 799 cache_insert(link_cache_t *node) 800 { 801 assert(MUTEX_HELD(&cache_lock)); 802 803 /* insert at the head for best performance */ 804 node->vc_next = cache_head.vc_next; 805 node->vc_prev = &cache_head; 806 807 node->vc_next->vc_prev = node; 808 node->vc_prev->vc_next = node; 809 } 810 811 /* 812 * cache_remove() - Remove a resource node from cache. 813 */ 814 static void 815 cache_remove(link_cache_t *node) 816 { 817 assert(MUTEX_HELD(&cache_lock)); 818 node->vc_next->vc_prev = node->vc_prev; 819 node->vc_prev->vc_next = node->vc_next; 820 node->vc_next = NULL; 821 node->vc_prev = NULL; 822 } 823 824 typedef struct vnic_update_arg_s { 825 rcm_handle_t *hd; 826 int retval; 827 } vnic_update_arg_t; 828 829 /* 830 * vnic_update() - Update physical interface properties 831 */ 832 static int 833 vnic_update(datalink_id_t vnicid, void *arg) 834 { 835 vnic_update_arg_t *vnic_update_argp = arg; 836 rcm_handle_t *hd = vnic_update_argp->hd; 837 link_cache_t *node; 838 dl_vnic_t *vnic; 839 char *rsrc; 840 dladm_vnic_attr_t vnic_attr; 841 dladm_status_t status; 842 char errmsg[DLADM_STRSIZE]; 843 boolean_t newnode = B_FALSE; 844 int ret = -1; 845 846 rcm_log_message(RCM_TRACE2, "VNIC: vnic_update(%u)\n", vnicid); 847 848 assert(MUTEX_HELD(&cache_lock)); 849 status = dladm_vnic_info(vnicid, &vnic_attr, DLADM_OPT_ACTIVE); 850 if (status != DLADM_STATUS_OK) { 851 rcm_log_message(RCM_TRACE1, 852 "VNIC: vnic_update() cannot get vnic information for " 853 "%u(%s)\n", vnicid, dladm_status2str(status, errmsg)); 854 return (DLADM_WALK_CONTINUE); 855 } 856 857 if (vnic_attr.va_link_id == DATALINK_INVALID_LINKID) { 858 /* 859 * Skip the etherstubs. 860 */ 861 rcm_log_message(RCM_TRACE1, 862 "VNIC: vnic_update(): skip the etherstub %u\n", vnicid); 863 return (DLADM_WALK_CONTINUE); 864 } 865 866 rsrc = malloc(RCM_LINK_RESOURCE_MAX); 867 if (rsrc == NULL) { 868 rcm_log_message(RCM_ERROR, _("VNIC: malloc error(%s): %u\n"), 869 strerror(errno), vnicid); 870 goto done; 871 } 872 873 (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u", 874 RCM_LINK_PREFIX, vnic_attr.va_link_id); 875 876 node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH); 877 if (node != NULL) { 878 rcm_log_message(RCM_DEBUG, 879 "VNIC: %s already registered (vnicid:%d)\n", 880 rsrc, vnic_attr.va_vnic_id); 881 free(rsrc); 882 } else { 883 rcm_log_message(RCM_DEBUG, 884 "VNIC: %s is a new resource (vnicid:%d)\n", 885 rsrc, vnic_attr.va_vnic_id); 886 if ((node = calloc(1, sizeof (link_cache_t))) == NULL) { 887 free(rsrc); 888 rcm_log_message(RCM_ERROR, _("VNIC: calloc: %s\n"), 889 strerror(errno)); 890 goto done; 891 } 892 893 node->vc_resource = rsrc; 894 node->vc_vnic = NULL; 895 node->vc_linkid = vnic_attr.va_link_id; 896 node->vc_state |= CACHE_NODE_NEW; 897 newnode = B_TRUE; 898 } 899 900 for (vnic = node->vc_vnic; vnic != NULL; vnic = vnic->dlv_next) { 901 if (vnic->dlv_vnic_id == vnicid) { 902 vnic->dlv_flags &= ~VNIC_STALE; 903 break; 904 } 905 } 906 907 if (vnic == NULL) { 908 if ((vnic = calloc(1, sizeof (dl_vnic_t))) == NULL) { 909 rcm_log_message(RCM_ERROR, _("VNIC: malloc: %s\n"), 910 strerror(errno)); 911 if (newnode) { 912 free(rsrc); 913 free(node); 914 } 915 goto done; 916 } 917 vnic->dlv_vnic_id = vnicid; 918 vnic->dlv_next = node->vc_vnic; 919 vnic->dlv_prev = NULL; 920 if (node->vc_vnic != NULL) 921 node->vc_vnic->dlv_prev = vnic; 922 node->vc_vnic = vnic; 923 } 924 925 node->vc_state &= ~CACHE_NODE_STALE; 926 927 if (newnode) 928 cache_insert(node); 929 930 rcm_log_message(RCM_TRACE3, "VNIC: vnic_update: succeeded(%u)\n", 931 vnicid); 932 ret = 0; 933 done: 934 vnic_update_argp->retval = ret; 935 return (ret == 0 ? DLADM_WALK_CONTINUE : DLADM_WALK_TERMINATE); 936 } 937 938 /* 939 * vnic_update_all() - Determine all VNIC links in the system 940 */ 941 static int 942 vnic_update_all(rcm_handle_t *hd) 943 { 944 vnic_update_arg_t arg = {NULL, 0}; 945 946 rcm_log_message(RCM_TRACE2, "VNIC: vnic_update_all\n"); 947 948 assert(MUTEX_HELD(&cache_lock)); 949 arg.hd = hd; 950 (void) dladm_walk_datalink_id(vnic_update, &arg, DATALINK_CLASS_VNIC, 951 DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 952 return (arg.retval); 953 } 954 955 /* 956 * cache_update() - Update cache with latest interface info 957 */ 958 static int 959 cache_update(rcm_handle_t *hd) 960 { 961 link_cache_t *node, *nnode; 962 dl_vnic_t *vnic; 963 int rv; 964 965 rcm_log_message(RCM_TRACE2, "VNIC: cache_update\n"); 966 967 (void) mutex_lock(&cache_lock); 968 969 /* first we walk the entire cache, marking each entry stale */ 970 node = cache_head.vc_next; 971 for (; node != &cache_tail; node = node->vc_next) { 972 node->vc_state |= CACHE_NODE_STALE; 973 for (vnic = node->vc_vnic; vnic != NULL; vnic = vnic->dlv_next) 974 vnic->dlv_flags |= VNIC_STALE; 975 } 976 977 rv = vnic_update_all(hd); 978 979 /* 980 * Continue to delete all stale nodes from the cache even 981 * vnic_update_all() failed. Unregister link that are not offlined 982 * and still in cache 983 */ 984 for (node = cache_head.vc_next; node != &cache_tail; node = nnode) { 985 dl_vnic_t *vnic, *next; 986 987 for (vnic = node->vc_vnic; vnic != NULL; vnic = next) { 988 next = vnic->dlv_next; 989 990 /* clear stale VNICs */ 991 if (vnic->dlv_flags & VNIC_STALE) { 992 if (vnic->dlv_prev != NULL) 993 vnic->dlv_prev->dlv_next = next; 994 else 995 node->vc_vnic = next; 996 997 if (next != NULL) 998 next->dlv_prev = vnic->dlv_prev; 999 free(vnic); 1000 } 1001 } 1002 1003 nnode = node->vc_next; 1004 if (node->vc_state & CACHE_NODE_STALE) { 1005 (void) rcm_unregister_interest(hd, node->vc_resource, 1006 0); 1007 rcm_log_message(RCM_DEBUG, "VNIC: unregistered %s\n", 1008 node->vc_resource); 1009 assert(node->vc_vnic == NULL); 1010 cache_remove(node); 1011 node_free(node); 1012 continue; 1013 } 1014 1015 if (!(node->vc_state & CACHE_NODE_NEW)) 1016 continue; 1017 1018 if (rcm_register_interest(hd, node->vc_resource, 0, NULL) != 1019 RCM_SUCCESS) { 1020 rcm_log_message(RCM_ERROR, 1021 _("VNIC: failed to register %s\n"), 1022 node->vc_resource); 1023 rv = -1; 1024 } else { 1025 rcm_log_message(RCM_DEBUG, "VNIC: registered %s\n", 1026 node->vc_resource); 1027 node->vc_state &= ~CACHE_NODE_NEW; 1028 } 1029 } 1030 1031 (void) mutex_unlock(&cache_lock); 1032 return (rv); 1033 } 1034 1035 /* 1036 * cache_free() - Empty the cache 1037 */ 1038 static void 1039 cache_free() 1040 { 1041 link_cache_t *node; 1042 1043 rcm_log_message(RCM_TRACE2, "VNIC: cache_free\n"); 1044 1045 (void) mutex_lock(&cache_lock); 1046 node = cache_head.vc_next; 1047 while (node != &cache_tail) { 1048 cache_remove(node); 1049 node_free(node); 1050 node = cache_head.vc_next; 1051 } 1052 (void) mutex_unlock(&cache_lock); 1053 } 1054 1055 /* 1056 * vnic_log_err() - RCM error log wrapper 1057 */ 1058 static void 1059 vnic_log_err(datalink_id_t linkid, char **errorp, char *errmsg) 1060 { 1061 char link[MAXLINKNAMELEN]; 1062 char errstr[DLADM_STRSIZE]; 1063 dladm_status_t status; 1064 int len; 1065 const char *errfmt; 1066 char *error; 1067 1068 link[0] = '\0'; 1069 if (linkid != DATALINK_INVALID_LINKID) { 1070 char rsrc[RCM_LINK_RESOURCE_MAX]; 1071 1072 (void) snprintf(rsrc, sizeof (rsrc), "%s/%u", 1073 RCM_LINK_PREFIX, linkid); 1074 1075 rcm_log_message(RCM_ERROR, _("VNIC: %s(%s)\n"), errmsg, rsrc); 1076 if ((status = dladm_datalink_id2info(linkid, NULL, NULL, 1077 NULL, link, sizeof (link))) != DLADM_STATUS_OK) { 1078 rcm_log_message(RCM_WARNING, 1079 _("VNIC: cannot get link name for (%s) %s\n"), 1080 rsrc, dladm_status2str(status, errstr)); 1081 } 1082 } else { 1083 rcm_log_message(RCM_ERROR, _("VNIC: %s\n"), errmsg); 1084 } 1085 1086 errfmt = strlen(link) > 0 ? _("VNIC: %s(%s)") : _("VNIC: %s"); 1087 len = strlen(errfmt) + strlen(errmsg) + MAXLINKNAMELEN + 1; 1088 if ((error = malloc(len)) != NULL) { 1089 if (strlen(link) > 0) 1090 (void) snprintf(error, len, errfmt, errmsg, link); 1091 else 1092 (void) snprintf(error, len, errfmt, errmsg); 1093 } 1094 1095 if (errorp != NULL) 1096 *errorp = error; 1097 } 1098 1099 /* 1100 * vnic_consumer_online() 1101 * 1102 * Notify online to VNIC consumers. 1103 */ 1104 /* ARGSUSED */ 1105 static void 1106 vnic_consumer_online(rcm_handle_t *hd, link_cache_t *node, char **errorp, 1107 uint_t flags, rcm_info_t **info) 1108 { 1109 dl_vnic_t *vnic; 1110 char rsrc[RCM_LINK_RESOURCE_MAX]; 1111 1112 rcm_log_message(RCM_TRACE2, "VNIC: vnic_consumer_online (%s)\n", 1113 node->vc_resource); 1114 1115 for (vnic = node->vc_vnic; vnic != NULL; vnic = vnic->dlv_next) { 1116 if (!(vnic->dlv_flags & VNIC_CONSUMER_OFFLINED)) 1117 continue; 1118 1119 (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u", 1120 RCM_LINK_PREFIX, vnic->dlv_vnic_id); 1121 1122 if (rcm_notify_online(hd, rsrc, flags, info) == RCM_SUCCESS) 1123 vnic->dlv_flags &= ~VNIC_CONSUMER_OFFLINED; 1124 } 1125 1126 rcm_log_message(RCM_TRACE2, "VNIC: vnic_consumer_online done\n"); 1127 } 1128 1129 /* 1130 * vnic_consumer_offline() 1131 * 1132 * Offline VNIC consumers. 1133 */ 1134 static int 1135 vnic_consumer_offline(rcm_handle_t *hd, link_cache_t *node, char **errorp, 1136 uint_t flags, rcm_info_t **info) 1137 { 1138 dl_vnic_t *vnic; 1139 char rsrc[RCM_LINK_RESOURCE_MAX]; 1140 int ret = RCM_SUCCESS; 1141 1142 rcm_log_message(RCM_TRACE2, "VNIC: vnic_consumer_offline (%s)\n", 1143 node->vc_resource); 1144 1145 for (vnic = node->vc_vnic; vnic != NULL; vnic = vnic->dlv_next) { 1146 (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u", 1147 RCM_LINK_PREFIX, vnic->dlv_vnic_id); 1148 1149 ret = rcm_request_offline(hd, rsrc, flags, info); 1150 if (ret != RCM_SUCCESS) 1151 break; 1152 1153 vnic->dlv_flags |= VNIC_CONSUMER_OFFLINED; 1154 } 1155 1156 if (vnic != NULL) 1157 vnic_consumer_online(hd, node, errorp, flags, info); 1158 1159 rcm_log_message(RCM_TRACE2, "VNIC: vnic_consumer_offline done\n"); 1160 return (ret); 1161 } 1162 1163 /* 1164 * Send RCM_RESOURCE_LINK_NEW events to other modules about new VNICs. 1165 * Return 0 on success, -1 on failure. 1166 */ 1167 static int 1168 vnic_notify_new_vnic(rcm_handle_t *hd, char *rsrc) 1169 { 1170 link_cache_t *node; 1171 dl_vnic_t *vnic; 1172 nvlist_t *nvl = NULL; 1173 uint64_t id; 1174 int ret = -1; 1175 1176 rcm_log_message(RCM_TRACE2, "VNIC: vnic_notify_new_vnic (%s)\n", rsrc); 1177 1178 (void) mutex_lock(&cache_lock); 1179 if ((node = cache_lookup(hd, rsrc, CACHE_REFRESH)) == NULL) { 1180 (void) mutex_unlock(&cache_lock); 1181 return (0); 1182 } 1183 1184 if (nvlist_alloc(&nvl, 0, 0) != 0) { 1185 (void) mutex_unlock(&cache_lock); 1186 rcm_log_message(RCM_WARNING, 1187 _("VNIC: failed to allocate nvlist\n")); 1188 goto done; 1189 } 1190 1191 for (vnic = node->vc_vnic; vnic != NULL; vnic = vnic->dlv_next) { 1192 rcm_log_message(RCM_TRACE2, 1193 "VNIC: vnic_notify_new_vnic add (%u)\n", vnic->dlv_vnic_id); 1194 1195 id = vnic->dlv_vnic_id; 1196 if (nvlist_add_uint64(nvl, RCM_NV_LINKID, id) != 0) { 1197 rcm_log_message(RCM_ERROR, 1198 _("VNIC: failed to construct nvlist\n")); 1199 (void) mutex_unlock(&cache_lock); 1200 goto done; 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 _("VNIC: 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 * vnic_consumer_notify() - Notify consumers of VNICs coming back online. 1222 */ 1223 static int 1224 vnic_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, "VNIC: vnic_consumer_notify(%s)\n", rsrc); 1235 1236 /* 1237 * Inform IP consumers of the new link. 1238 */ 1239 if (vnic_notify_new_vnic(hd, rsrc) != 0) { 1240 (void) mutex_lock(&cache_lock); 1241 if ((node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH)) != NULL) { 1242 (void) vnic_offline_vnic(node, VNIC_STALE, 1243 CACHE_NODE_STALE); 1244 } 1245 (void) mutex_unlock(&cache_lock); 1246 rcm_log_message(RCM_TRACE2, 1247 "VNIC: vnic_notify_new_vnic failed(%s)\n", rsrc); 1248 return (-1); 1249 } 1250 1251 rcm_log_message(RCM_TRACE2, "VNIC: vnic_consumer_notify succeeded\n"); 1252 return (0); 1253 } 1254 1255 typedef struct vnic_up_arg_s { 1256 datalink_id_t linkid; 1257 int retval; 1258 } vnic_up_arg_t; 1259 1260 static int 1261 vnic_up(datalink_id_t vnicid, void *arg) 1262 { 1263 vnic_up_arg_t *vnic_up_argp = arg; 1264 dladm_status_t status; 1265 dladm_vnic_attr_t vnic_attr; 1266 char errmsg[DLADM_STRSIZE]; 1267 1268 status = dladm_vnic_info(vnicid, &vnic_attr, DLADM_OPT_PERSIST); 1269 if (status != DLADM_STATUS_OK) { 1270 rcm_log_message(RCM_TRACE1, 1271 "VNIC: vnic_up(): cannot get information for VNIC %u " 1272 "(%s)\n", vnicid, dladm_status2str(status, errmsg)); 1273 return (DLADM_WALK_CONTINUE); 1274 } 1275 1276 if (vnic_attr.va_link_id != vnic_up_argp->linkid) 1277 return (DLADM_WALK_CONTINUE); 1278 1279 rcm_log_message(RCM_TRACE3, "VNIC: vnic_up(%u)\n", vnicid); 1280 if ((status = dladm_vnic_up(vnicid, 0)) == DLADM_STATUS_OK) 1281 return (DLADM_WALK_CONTINUE); 1282 1283 /* 1284 * Prompt the warning message and continue to UP other VNICs. 1285 */ 1286 rcm_log_message(RCM_WARNING, 1287 _("VNIC: VNIC up failed (%u): %s\n"), 1288 vnicid, dladm_status2str(status, errmsg)); 1289 1290 vnic_up_argp->retval = -1; 1291 return (DLADM_WALK_CONTINUE); 1292 } 1293 1294 /* 1295 * vnic_configure() - Configure VNICs over a physical link after it attaches 1296 */ 1297 static int 1298 vnic_configure(rcm_handle_t *hd, datalink_id_t linkid) 1299 { 1300 char rsrc[RCM_LINK_RESOURCE_MAX]; 1301 link_cache_t *node; 1302 vnic_up_arg_t arg = {DATALINK_INVALID_LINKID, 0}; 1303 1304 /* Check for the VNICs in the cache */ 1305 (void) snprintf(rsrc, sizeof (rsrc), "%s/%u", RCM_LINK_PREFIX, linkid); 1306 1307 rcm_log_message(RCM_TRACE2, "VNIC: vnic_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 "VNIC: 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(vnic_up, &arg, DATALINK_CLASS_VNIC, 1322 DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 1323 1324 if (arg.retval == 0) { 1325 rcm_log_message(RCM_TRACE2, 1326 "VNIC: vnic_configure succeeded(%s)\n", rsrc); 1327 } 1328 return (arg.retval); 1329 } 1330