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