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