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 Bridge links 28 */ 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <errno.h> 34 #include <sys/types.h> 35 #include <synch.h> 36 #include <assert.h> 37 #include <strings.h> 38 #include "rcm_module.h" 39 #include <libintl.h> 40 #include <libdllink.h> 41 #include <libdlbridge.h> 42 #include <libdlpi.h> 43 44 /* 45 * Definitions 46 */ 47 #ifndef lint 48 #define _(x) gettext(x) 49 #else 50 #define _(x) x 51 #endif 52 53 /* Some generic well-knowns and defaults used in this module */ 54 #define RCM_LINK_PREFIX "SUNW_datalink" /* RCM datalink name prefix */ 55 #define RCM_LINK_RESOURCE_MAX (13 + LINKID_STR_WIDTH) 56 57 /* Bridge Cache state flags */ 58 typedef enum { 59 CACHE_NODE_STALE = 0x1, /* stale cached data */ 60 CACHE_NODE_NEW = 0x2, /* new cached nodes */ 61 CACHE_NODE_OFFLINED = 0x4 /* nodes offlined */ 62 } cache_node_state_t; 63 64 /* Network Cache lookup options */ 65 #define CACHE_NO_REFRESH 0x1 /* cache refresh not needed */ 66 #define CACHE_REFRESH 0x2 /* refresh cache */ 67 68 /* Cache element */ 69 typedef struct link_cache { 70 struct link_cache *vc_next; /* next cached resource */ 71 struct link_cache *vc_prev; /* prev cached resource */ 72 char *vc_resource; /* resource name */ 73 datalink_id_t vc_linkid; /* linkid */ 74 cache_node_state_t vc_state; /* cache state flags */ 75 char vc_bridge[MAXLINKNAMELEN]; 76 } link_cache_t; 77 78 /* 79 * Global cache for network Bridges 80 */ 81 static link_cache_t cache_head; 82 static link_cache_t cache_tail; 83 static mutex_t cache_lock; 84 static boolean_t events_registered = B_FALSE; 85 86 static dladm_handle_t dld_handle = NULL; 87 88 /* 89 * RCM module interface prototypes 90 */ 91 static int bridge_register(rcm_handle_t *); 92 static int bridge_unregister(rcm_handle_t *); 93 static int bridge_get_info(rcm_handle_t *, char *, id_t, uint_t, 94 char **, char **, nvlist_t *, rcm_info_t **); 95 static int bridge_suspend(rcm_handle_t *, char *, id_t, 96 timespec_t *, uint_t, char **, rcm_info_t **); 97 static int bridge_resume(rcm_handle_t *, char *, id_t, uint_t, 98 char **, rcm_info_t **); 99 static int bridge_offline(rcm_handle_t *, char *, id_t, uint_t, 100 char **, rcm_info_t **); 101 static int bridge_undo_offline(rcm_handle_t *, char *, id_t, 102 uint_t, char **, rcm_info_t **); 103 static int bridge_remove(rcm_handle_t *, char *, id_t, uint_t, 104 char **, rcm_info_t **); 105 static int bridge_notify_event(rcm_handle_t *, char *, id_t, 106 uint_t, char **, nvlist_t *, rcm_info_t **); 107 static int bridge_configure(rcm_handle_t *, datalink_id_t); 108 109 /* Module private routines */ 110 static void cache_free(void); 111 static int cache_update(rcm_handle_t *); 112 static void cache_remove(link_cache_t *); 113 static void node_free(link_cache_t *); 114 static void cache_insert(link_cache_t *); 115 static link_cache_t *cache_lookup(rcm_handle_t *, char *, uint_t); 116 static char *bridge_usage(link_cache_t *); 117 static void bridge_log_err(datalink_id_t, char **, char *); 118 119 /* Module-Private data */ 120 static struct rcm_mod_ops bridge_ops = 121 { 122 RCM_MOD_OPS_VERSION, 123 bridge_register, 124 bridge_unregister, 125 bridge_get_info, 126 bridge_suspend, 127 bridge_resume, 128 bridge_offline, 129 bridge_undo_offline, 130 bridge_remove, 131 NULL, 132 NULL, 133 bridge_notify_event 134 }; 135 136 /* 137 * rcm_mod_init() - Update registrations, and return the ops structure. 138 */ 139 struct rcm_mod_ops * 140 rcm_mod_init(void) 141 { 142 dladm_status_t status; 143 char errmsg[DLADM_STRSIZE]; 144 145 rcm_log_message(RCM_TRACE1, "Bridge: mod_init\n"); 146 147 cache_head.vc_next = &cache_tail; 148 cache_head.vc_prev = NULL; 149 cache_tail.vc_prev = &cache_head; 150 cache_tail.vc_next = NULL; 151 (void) mutex_init(&cache_lock, 0, NULL); 152 153 if ((status = dladm_open(&dld_handle)) != DLADM_STATUS_OK) { 154 rcm_log_message(RCM_WARNING, 155 "Bridge: cannot open datalink handle: %s\n", 156 dladm_status2str(status, errmsg)); 157 return (NULL); 158 } 159 160 /* Return the ops vectors */ 161 return (&bridge_ops); 162 } 163 164 /* 165 * rcm_mod_info() - Return a string describing this module. 166 */ 167 const char * 168 rcm_mod_info(void) 169 { 170 rcm_log_message(RCM_TRACE1, "Bridge: mod_info\n"); 171 172 return ("Bridge module version 1.0"); 173 } 174 175 /* 176 * rcm_mod_fini() - Destroy the network Bridge cache. 177 */ 178 int 179 rcm_mod_fini(void) 180 { 181 rcm_log_message(RCM_TRACE1, "Bridge: mod_fini\n"); 182 183 /* 184 * Note that bridge_unregister() does not seem to be called anywhere, 185 * therefore we free the cache nodes here. In theory we should call 186 * rcm_register_interest() for each node before we free it, but the 187 * framework does not provide the rcm_handle to allow us to do so. 188 */ 189 cache_free(); 190 (void) mutex_destroy(&cache_lock); 191 192 dladm_close(dld_handle); 193 return (RCM_SUCCESS); 194 } 195 196 /* 197 * bridge_register() - Make sure the cache is properly sync'ed, and its 198 * registrations are in order. 199 */ 200 static int 201 bridge_register(rcm_handle_t *hd) 202 { 203 int retv; 204 205 rcm_log_message(RCM_TRACE1, "Bridge: register\n"); 206 207 if ((retv = cache_update(hd)) != RCM_SUCCESS) 208 return (retv); 209 210 /* 211 * Need to register interest in all new resources 212 * getting attached, so we get attach event notifications 213 */ 214 if (!events_registered) { 215 retv = rcm_register_event(hd, RCM_RESOURCE_LINK_NEW, 0, NULL); 216 if (retv != RCM_SUCCESS) { 217 rcm_log_message(RCM_ERROR, 218 _("Bridge: failed to register %s\n"), 219 RCM_RESOURCE_LINK_NEW); 220 } else { 221 rcm_log_message(RCM_DEBUG, "Bridge: registered %s\n", 222 RCM_RESOURCE_LINK_NEW); 223 events_registered = B_TRUE; 224 } 225 } 226 227 return (retv); 228 } 229 230 /* 231 * bridge_unregister() - Walk the cache, unregistering all the links. 232 */ 233 static int 234 bridge_unregister(rcm_handle_t *hd) 235 { 236 link_cache_t *node; 237 int retv = RCM_SUCCESS; 238 239 rcm_log_message(RCM_TRACE1, "Bridge: unregister\n"); 240 241 /* Walk the cache, unregistering everything */ 242 (void) mutex_lock(&cache_lock); 243 node = cache_head.vc_next; 244 while (node != &cache_tail) { 245 retv = rcm_unregister_interest(hd, node->vc_resource, 0); 246 if (retv != RCM_SUCCESS) 247 break; 248 cache_remove(node); 249 node_free(node); 250 node = cache_head.vc_next; 251 } 252 (void) mutex_unlock(&cache_lock); 253 if (retv != RCM_SUCCESS) { 254 rcm_log_message(RCM_ERROR, 255 _("Bridge: failed to unregister %s\n"), node->vc_resource); 256 return (retv); 257 } 258 259 /* 260 * Unregister interest in all new resources 261 */ 262 if (events_registered) { 263 retv = rcm_unregister_event(hd, RCM_RESOURCE_LINK_NEW, 0); 264 if (retv != RCM_SUCCESS) { 265 rcm_log_message(RCM_ERROR, 266 _("Bridge: failed to unregister %s\n"), 267 RCM_RESOURCE_LINK_NEW); 268 } else { 269 rcm_log_message(RCM_DEBUG, "Bridge: unregistered %s\n", 270 RCM_RESOURCE_LINK_NEW); 271 events_registered = B_FALSE; 272 } 273 } 274 275 return (retv); 276 } 277 278 /* 279 * bridge_offline() - Offline the bridge on a specific link. 280 */ 281 static int 282 bridge_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 283 char **errorp, rcm_info_t **info) 284 { 285 link_cache_t *node; 286 dladm_status_t status; 287 288 rcm_log_message(RCM_TRACE1, "Bridge: offline(%s)\n", rsrc); 289 290 /* Lock the cache and lookup the resource */ 291 (void) mutex_lock(&cache_lock); 292 node = cache_lookup(hd, rsrc, CACHE_REFRESH); 293 if (node == NULL) { 294 /* should not happen because the resource is registered. */ 295 bridge_log_err(DATALINK_INVALID_LINKID, errorp, 296 "unrecognized resource"); 297 (void) mutex_unlock(&cache_lock); 298 return (RCM_SUCCESS); 299 } 300 301 /* Check if it's a query */ 302 if (flags & RCM_QUERY) { 303 rcm_log_message(RCM_TRACE1, 304 "Bridge: offline query succeeded(%s)\n", rsrc); 305 (void) mutex_unlock(&cache_lock); 306 return (RCM_SUCCESS); 307 } 308 309 status = dladm_bridge_setlink(dld_handle, node->vc_linkid, ""); 310 if (status != DLADM_STATUS_OK) { 311 bridge_log_err(node->vc_linkid, errorp, "offline failed"); 312 (void) mutex_unlock(&cache_lock); 313 return (RCM_FAILURE); 314 } 315 316 node->vc_state |= CACHE_NODE_OFFLINED; 317 318 rcm_log_message(RCM_TRACE1, "Bridge: Offline succeeded(%s %s)\n", rsrc, 319 node->vc_bridge); 320 (void) mutex_unlock(&cache_lock); 321 return (RCM_SUCCESS); 322 } 323 324 /* 325 * bridge_undo_offline() - Undo offline of a previously offlined node. 326 */ 327 /*ARGSUSED*/ 328 static int 329 bridge_undo_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 330 char **errorp, rcm_info_t **info) 331 { 332 link_cache_t *node; 333 dladm_status_t status; 334 char errmsg[DLADM_STRSIZE]; 335 336 rcm_log_message(RCM_TRACE1, "Bridge: online(%s)\n", rsrc); 337 338 (void) mutex_lock(&cache_lock); 339 node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH); 340 if (node == NULL) { 341 bridge_log_err(DATALINK_INVALID_LINKID, errorp, "no such link"); 342 (void) mutex_unlock(&cache_lock); 343 errno = ENOENT; 344 return (RCM_FAILURE); 345 } 346 347 /* Check if no attempt should be made to online the link here */ 348 if (!(node->vc_state & CACHE_NODE_OFFLINED)) { 349 bridge_log_err(node->vc_linkid, errorp, "link not offlined"); 350 (void) mutex_unlock(&cache_lock); 351 errno = ENOTSUP; 352 return (RCM_SUCCESS); 353 } 354 355 /* 356 * Try to bring on an offlined bridge link. 357 */ 358 status = dladm_bridge_setlink(dld_handle, node->vc_linkid, 359 node->vc_bridge); 360 if (status != DLADM_STATUS_OK) { 361 /* 362 * Print a warning message. 363 */ 364 rcm_log_message(RCM_WARNING, 365 _("Bridge: Bridge online failed %u %s: %s\n"), 366 node->vc_linkid, node->vc_bridge, 367 dladm_status2str(status, errmsg)); 368 } 369 370 node->vc_state &= ~CACHE_NODE_OFFLINED; 371 rcm_log_message(RCM_TRACE1, "Bridge: online succeeded(%s)\n", rsrc); 372 (void) mutex_unlock(&cache_lock); 373 return (RCM_SUCCESS); 374 } 375 376 /* 377 * bridge_get_info() - Gather usage information for this resource. 378 */ 379 /*ARGSUSED*/ 380 int 381 bridge_get_info(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 382 char **usagep, char **errorp, nvlist_t *props, rcm_info_t **info) 383 { 384 link_cache_t *node; 385 386 rcm_log_message(RCM_TRACE1, "Bridge: get_info(%s)\n", rsrc); 387 388 (void) mutex_lock(&cache_lock); 389 node = cache_lookup(hd, rsrc, CACHE_REFRESH); 390 if (node == NULL) { 391 rcm_log_message(RCM_INFO, 392 _("Bridge: get_info(%s) unrecognized resource\n"), rsrc); 393 (void) mutex_unlock(&cache_lock); 394 errno = ENOENT; 395 return (RCM_FAILURE); 396 } 397 398 *usagep = bridge_usage(node); 399 (void) mutex_unlock(&cache_lock); 400 if (*usagep == NULL) { 401 /* most likely malloc failure */ 402 rcm_log_message(RCM_ERROR, 403 _("Bridge: get_info(%s) malloc failure\n"), rsrc); 404 (void) mutex_unlock(&cache_lock); 405 errno = ENOMEM; 406 return (RCM_FAILURE); 407 } 408 409 /* Set client/role properties */ 410 (void) nvlist_add_string(props, RCM_CLIENT_NAME, "Bridge"); 411 412 rcm_log_message(RCM_TRACE1, "Bridge: get_info(%s) info = %s\n", 413 rsrc, *usagep); 414 return (RCM_SUCCESS); 415 } 416 417 /* 418 * bridge_suspend() - Nothing to do, always okay 419 */ 420 /*ARGSUSED*/ 421 static int 422 bridge_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval, 423 uint_t flags, char **errorp, rcm_info_t **info) 424 { 425 rcm_log_message(RCM_TRACE1, "Bridge: suspend(%s)\n", rsrc); 426 return (RCM_SUCCESS); 427 } 428 429 /* 430 * bridge_resume() - Nothing to do, always okay 431 */ 432 /*ARGSUSED*/ 433 static int 434 bridge_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 435 char **errorp, rcm_info_t **info) 436 { 437 rcm_log_message(RCM_TRACE1, "Bridge: resume(%s)\n", rsrc); 438 return (RCM_SUCCESS); 439 } 440 441 /* 442 * bridge_remove() - remove a resource from cache 443 */ 444 /*ARGSUSED*/ 445 static int 446 bridge_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 447 char **errorp, rcm_info_t **info) 448 { 449 link_cache_t *node; 450 451 rcm_log_message(RCM_TRACE1, "Bridge: remove(%s)\n", rsrc); 452 453 (void) mutex_lock(&cache_lock); 454 node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH); 455 if (node == NULL) { 456 rcm_log_message(RCM_INFO, 457 _("Bridge: remove(%s) unrecognized resource\n"), rsrc); 458 (void) mutex_unlock(&cache_lock); 459 errno = ENOENT; 460 return (RCM_FAILURE); 461 } 462 463 /* remove the cached entry for the resource */ 464 rcm_log_message(RCM_TRACE2, 465 "Bridge: remove succeeded(%s, %s)\n", rsrc, node->vc_bridge); 466 cache_remove(node); 467 (void) mutex_unlock(&cache_lock); 468 469 node_free(node); 470 return (RCM_SUCCESS); 471 } 472 473 /* 474 * bridge_notify_event - Project private implementation to receive new resource 475 * events. It intercepts all new resource events. If the 476 * new resource is a network resource, pass up a notify 477 * for it too. The new resource need not be cached, since 478 * it is done at register again. 479 */ 480 /*ARGSUSED*/ 481 static int 482 bridge_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 483 char **errorp, nvlist_t *nvl, rcm_info_t **info) 484 { 485 nvpair_t *nvp = NULL; 486 datalink_id_t linkid; 487 uint64_t id64; 488 int rv, lastrv; 489 490 rcm_log_message(RCM_TRACE1, "Bridge: notify_event(%s)\n", rsrc); 491 492 if (strcmp(rsrc, RCM_RESOURCE_LINK_NEW) != 0) { 493 bridge_log_err(DATALINK_INVALID_LINKID, errorp, 494 "unrecognized event"); 495 errno = EINVAL; 496 return (RCM_FAILURE); 497 } 498 499 /* Update cache to reflect latest Bridges */ 500 if ((lastrv = cache_update(hd)) != RCM_SUCCESS) { 501 bridge_log_err(DATALINK_INVALID_LINKID, errorp, 502 "private Cache update failed"); 503 return (lastrv); 504 } 505 506 /* 507 * Try best to recover all configuration. 508 */ 509 rcm_log_message(RCM_DEBUG, "Bridge: process_nvlist\n"); 510 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 511 if (strcmp(nvpair_name(nvp), RCM_NV_LINKID) != 0) 512 continue; 513 514 if (nvpair_value_uint64(nvp, &id64) != 0) { 515 bridge_log_err(DATALINK_INVALID_LINKID, errorp, 516 "cannot get linkid"); 517 lastrv = RCM_FAILURE; 518 continue; 519 } 520 521 linkid = (datalink_id_t)id64; 522 if ((rv = bridge_configure(hd, linkid)) != RCM_SUCCESS) { 523 bridge_log_err(linkid, errorp, "configuring failed"); 524 lastrv = rv; 525 } 526 } 527 528 rcm_log_message(RCM_TRACE1, 529 "Bridge: notify_event: link configuration complete\n"); 530 return (lastrv); 531 } 532 533 /* 534 * bridge_usage - Determine the usage of a link. 535 * The returned buffer is owned by caller, and the caller 536 * must free it up when done. 537 */ 538 static char * 539 bridge_usage(link_cache_t *node) 540 { 541 char *buf; 542 const char *fmt; 543 char errmsg[DLADM_STRSIZE]; 544 char name[MAXLINKNAMELEN]; 545 char bridge[MAXLINKNAMELEN]; 546 dladm_status_t status; 547 548 rcm_log_message(RCM_TRACE2, "Bridge: usage(%s)\n", node->vc_resource); 549 550 assert(MUTEX_HELD(&cache_lock)); 551 552 status = dladm_datalink_id2info(dld_handle, node->vc_linkid, NULL, 553 NULL, NULL, name, sizeof (name)); 554 555 if (status != DLADM_STATUS_OK) { 556 rcm_log_message(RCM_ERROR, 557 _("Bridge: usage(%s) get link name failure(%s)\n"), 558 node->vc_resource, dladm_status2str(status, errmsg)); 559 return (NULL); 560 } 561 562 (void) dladm_bridge_getlink(dld_handle, node->vc_linkid, bridge, 563 sizeof (bridge)); 564 565 if (node->vc_state & CACHE_NODE_OFFLINED) 566 fmt = _("%1$s offlined"); 567 else if (bridge[0] == '\0') 568 fmt = _("%1$s not bridged"); 569 else 570 fmt = _("%1$s bridge: %2$s"); 571 572 (void) asprintf(&buf, fmt, name, bridge); 573 574 rcm_log_message(RCM_TRACE2, "Bridge: usage (%s) info = %s\n", 575 node->vc_resource, buf); 576 577 return (buf); 578 } 579 580 /* 581 * Cache management routines, all cache management functions should be 582 * be called with cache_lock held. 583 */ 584 585 /* 586 * cache_lookup() - Get a cache node for a resource. 587 * Call with cache lock held. 588 * 589 * This ensures that the cache is consistent with the system state and 590 * returns a pointer to the cache element corresponding to the resource. 591 */ 592 static link_cache_t * 593 cache_lookup(rcm_handle_t *hd, char *rsrc, uint_t options) 594 { 595 link_cache_t *node; 596 597 rcm_log_message(RCM_TRACE2, "Bridge: cache lookup(%s)\n", rsrc); 598 599 assert(MUTEX_HELD(&cache_lock)); 600 if (options & CACHE_REFRESH) { 601 /* drop lock since update locks cache again */ 602 (void) mutex_unlock(&cache_lock); 603 (void) cache_update(hd); 604 (void) mutex_lock(&cache_lock); 605 } 606 607 node = cache_head.vc_next; 608 for (; node != &cache_tail; node = node->vc_next) { 609 if (strcmp(rsrc, node->vc_resource) == 0) { 610 rcm_log_message(RCM_TRACE2, 611 "Bridge: cache lookup succeeded(%s, %s)\n", rsrc, 612 node->vc_bridge); 613 return (node); 614 } 615 } 616 return (NULL); 617 } 618 619 /* 620 * node_free - Free a node from the cache 621 */ 622 static void 623 node_free(link_cache_t *node) 624 { 625 if (node != NULL) { 626 free(node->vc_resource); 627 free(node); 628 } 629 } 630 631 /* 632 * cache_insert - Insert a resource node in cache 633 */ 634 static void 635 cache_insert(link_cache_t *node) 636 { 637 assert(MUTEX_HELD(&cache_lock)); 638 639 /* insert at the head for best performance */ 640 node->vc_next = cache_head.vc_next; 641 node->vc_prev = &cache_head; 642 643 node->vc_next->vc_prev = node; 644 node->vc_prev->vc_next = node; 645 } 646 647 /* 648 * cache_remove() - Remove a resource node from cache. 649 */ 650 static void 651 cache_remove(link_cache_t *node) 652 { 653 assert(MUTEX_HELD(&cache_lock)); 654 node->vc_next->vc_prev = node->vc_prev; 655 node->vc_prev->vc_next = node->vc_next; 656 node->vc_next = NULL; 657 node->vc_prev = NULL; 658 } 659 660 typedef struct bridge_update_arg_s { 661 rcm_handle_t *hd; 662 int retval; 663 } bridge_update_arg_t; 664 665 /* 666 * bridge_update() - Update physical interface properties 667 */ 668 static int 669 bridge_update(dladm_handle_t handle, datalink_id_t linkid, void *arg) 670 { 671 bridge_update_arg_t *bua = arg; 672 rcm_handle_t *hd = bua->hd; 673 link_cache_t *node; 674 char *rsrc; 675 dladm_status_t status; 676 char errmsg[DLADM_STRSIZE]; 677 char bridge[MAXLINKNAMELEN]; 678 int ret = RCM_FAILURE; 679 680 rcm_log_message(RCM_TRACE2, "Bridge: bridge_update(%u)\n", linkid); 681 682 assert(MUTEX_HELD(&cache_lock)); 683 status = dladm_bridge_getlink(dld_handle, linkid, bridge, 684 sizeof (bridge)); 685 if (status != DLADM_STATUS_OK) { 686 rcm_log_message(RCM_TRACE1, 687 "Bridge: no bridge information for %u (%s)\n", 688 linkid, dladm_status2str(status, errmsg)); 689 return (DLADM_WALK_CONTINUE); 690 } 691 692 (void) asprintf(&rsrc, "%s/%u", RCM_LINK_PREFIX, linkid); 693 if (rsrc == NULL) { 694 rcm_log_message(RCM_ERROR, 695 _("Bridge: allocation failure: %s %u: %s\n"), 696 bridge, linkid, strerror(errno)); 697 goto done; 698 } 699 700 node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH); 701 if (node != NULL) { 702 rcm_log_message(RCM_DEBUG, "Bridge: %s already registered\n", 703 rsrc); 704 free(rsrc); 705 node->vc_state &= ~CACHE_NODE_STALE; 706 } else { 707 rcm_log_message(RCM_DEBUG, 708 "Bridge: %s is a new resource (bridge %s)\n", 709 rsrc, bridge); 710 if ((node = calloc(1, sizeof (link_cache_t))) == NULL) { 711 free(rsrc); 712 rcm_log_message(RCM_ERROR, _("Bridge: calloc: %s\n"), 713 strerror(errno)); 714 goto done; 715 } 716 717 node->vc_resource = rsrc; 718 node->vc_linkid = linkid; 719 (void) strlcpy(node->vc_bridge, bridge, 720 sizeof (node->vc_bridge)); 721 node->vc_state |= CACHE_NODE_NEW; 722 cache_insert(node); 723 } 724 725 rcm_log_message(RCM_TRACE3, "Bridge: bridge_update: succeeded(%u %s)\n", 726 linkid, node->vc_bridge); 727 ret = RCM_SUCCESS; 728 done: 729 bua->retval = ret; 730 return (ret == RCM_SUCCESS ? DLADM_WALK_CONTINUE : 731 DLADM_WALK_TERMINATE); 732 } 733 734 /* 735 * cache_update() - Update cache with latest interface info 736 */ 737 static int 738 cache_update(rcm_handle_t *hd) 739 { 740 link_cache_t *node, *nnode; 741 int rv, lastrv; 742 bridge_update_arg_t bua; 743 744 rcm_log_message(RCM_TRACE2, "Bridge: cache_update\n"); 745 746 (void) mutex_lock(&cache_lock); 747 748 /* first we walk the entire cache, marking each entry stale */ 749 node = cache_head.vc_next; 750 for (; node != &cache_tail; node = node->vc_next) 751 node->vc_state |= CACHE_NODE_STALE; 752 753 /* now walk the links and update all of the entries */ 754 bua.hd = hd; 755 bua.retval = RCM_SUCCESS; 756 (void) dladm_walk_datalink_id(bridge_update, dld_handle, &bua, 757 DATALINK_CLASS_AGGR | DATALINK_CLASS_PHYS | 758 DATALINK_CLASS_ETHERSTUB, DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 759 lastrv = bua.retval; 760 761 /* 762 * Continue to delete all stale nodes from the cache even if the walk 763 * above failed. Unregister links that are not offlined and still in 764 * the cache. 765 */ 766 for (node = cache_head.vc_next; node != &cache_tail; node = nnode) { 767 nnode = node->vc_next; 768 769 if (node->vc_state & CACHE_NODE_STALE) { 770 (void) rcm_unregister_interest(hd, node->vc_resource, 771 0); 772 rcm_log_message(RCM_DEBUG, 773 "Bridge: unregistered %s %s\n", 774 node->vc_resource, node->vc_bridge); 775 cache_remove(node); 776 node_free(node); 777 continue; 778 } 779 780 if (!(node->vc_state & CACHE_NODE_NEW)) 781 continue; 782 783 rv = rcm_register_interest(hd, node->vc_resource, 0, NULL); 784 if (rv != RCM_SUCCESS) { 785 rcm_log_message(RCM_ERROR, 786 _("Bridge: failed to register %s\n"), 787 node->vc_resource); 788 lastrv = rv; 789 } else { 790 rcm_log_message(RCM_DEBUG, "Bridge: registered %s\n", 791 node->vc_resource); 792 node->vc_state &= ~CACHE_NODE_NEW; 793 } 794 } 795 796 (void) mutex_unlock(&cache_lock); 797 return (lastrv); 798 } 799 800 /* 801 * cache_free() - Empty the cache 802 */ 803 static void 804 cache_free(void) 805 { 806 link_cache_t *node; 807 808 rcm_log_message(RCM_TRACE2, "Bridge: cache_free\n"); 809 810 (void) mutex_lock(&cache_lock); 811 node = cache_head.vc_next; 812 while (node != &cache_tail) { 813 cache_remove(node); 814 node_free(node); 815 node = cache_head.vc_next; 816 } 817 (void) mutex_unlock(&cache_lock); 818 } 819 820 /* 821 * bridge_log_err() - RCM error log wrapper 822 */ 823 static void 824 bridge_log_err(datalink_id_t linkid, char **errorp, char *errmsg) 825 { 826 char link[MAXLINKNAMELEN]; 827 char errstr[DLADM_STRSIZE]; 828 dladm_status_t status; 829 char *error; 830 831 link[0] = '\0'; 832 if (linkid != DATALINK_INVALID_LINKID) { 833 char rsrc[RCM_LINK_RESOURCE_MAX]; 834 835 (void) snprintf(rsrc, sizeof (rsrc), "%s/%u", 836 RCM_LINK_PREFIX, linkid); 837 838 rcm_log_message(RCM_ERROR, _("Bridge: %s(%s)\n"), errmsg, rsrc); 839 if ((status = dladm_datalink_id2info(dld_handle, linkid, NULL, 840 NULL, NULL, link, sizeof (link))) != DLADM_STATUS_OK) { 841 rcm_log_message(RCM_WARNING, 842 _("Bridge: cannot get link name for (%s) %s\n"), 843 rsrc, dladm_status2str(status, errstr)); 844 } 845 } else { 846 rcm_log_message(RCM_ERROR, _("Bridge: %s\n"), errmsg); 847 } 848 849 if (link[0] != '\0') 850 (void) asprintf(&error, _("Bridge: %s(%s)"), errmsg, link); 851 else 852 (void) asprintf(&error, _("Bridge: %s"), errmsg); 853 854 if (errorp != NULL) 855 *errorp = error; 856 } 857 858 /* 859 * bridge_configure() - Configure bridge on a physical link after it attaches 860 */ 861 static int 862 bridge_configure(rcm_handle_t *hd, datalink_id_t linkid) 863 { 864 char rsrc[RCM_LINK_RESOURCE_MAX]; 865 link_cache_t *node; 866 char bridge[MAXLINKNAMELEN]; 867 868 /* Check for the bridge links in the cache */ 869 (void) snprintf(rsrc, sizeof (rsrc), "%s/%u", RCM_LINK_PREFIX, linkid); 870 871 rcm_log_message(RCM_TRACE2, "Bridge: bridge_configure(%s)\n", rsrc); 872 873 /* Check if the link is new or was previously offlined */ 874 (void) mutex_lock(&cache_lock); 875 if (((node = cache_lookup(hd, rsrc, CACHE_REFRESH)) != NULL) && 876 (!(node->vc_state & CACHE_NODE_OFFLINED))) { 877 rcm_log_message(RCM_TRACE2, 878 "Bridge: Skipping configured interface(%s)\n", rsrc); 879 (void) mutex_unlock(&cache_lock); 880 return (RCM_SUCCESS); 881 } 882 (void) mutex_unlock(&cache_lock); 883 884 /* clear out previous bridge, if any */ 885 if (dladm_bridge_getlink(dld_handle, linkid, bridge, sizeof (bridge)) == 886 DLADM_STATUS_OK) { 887 if (bridge[0] != '\0') 888 (void) dladm_bridge_setlink(dld_handle, linkid, ""); 889 } 890 891 /* now set up the new one */ 892 if (node != NULL && node->vc_bridge[0] != '\0' && 893 dladm_bridge_setlink(dld_handle, linkid, node->vc_bridge) != 894 DLADM_STATUS_OK) 895 return (RCM_FAILURE); 896 else 897 return (RCM_SUCCESS); 898 } 899