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