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