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