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 an abstract 28 * namespace for network devices (DLPI providers). 29 */ 30 #include <alloca.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <unistd.h> 34 #include <assert.h> 35 #include <string.h> 36 #include <synch.h> 37 #include <libintl.h> 38 #include <errno.h> 39 #include <libdevinfo.h> 40 #include <sys/types.h> 41 #include <net/if.h> 42 #include <libdllink.h> 43 #include "rcm_module.h" 44 45 /* 46 * Definitions 47 */ 48 #ifndef lint 49 #define _(x) gettext(x) 50 #else 51 #define _(x) x 52 #endif 53 54 #define CACHE_STALE 1 /* flags */ 55 #define CACHE_NEW 2 /* flags */ 56 57 /* operations */ 58 #define NET_OFFLINE 1 59 #define NET_ONLINE 2 60 #define NET_REMOVE 3 61 #define NET_SUSPEND 4 62 #define NET_RESUME 5 63 64 typedef struct net_cache 65 { 66 char *resource; 67 datalink_id_t linkid; 68 int flags; 69 struct net_cache *next; 70 struct net_cache *prev; 71 } net_cache_t; 72 73 static net_cache_t cache_head; 74 static net_cache_t cache_tail; 75 static mutex_t cache_lock; 76 static int events_registered = 0; 77 78 static dladm_handle_t dld_handle = NULL; 79 80 /* module interface routines */ 81 static int net_register(rcm_handle_t *); 82 static int net_unregister(rcm_handle_t *); 83 static int net_getinfo(rcm_handle_t *, char *, id_t, uint_t, char **, 84 char **, nvlist_t *, rcm_info_t **); 85 static int net_suspend(rcm_handle_t *, char *, id_t, timespec_t *, 86 uint_t, char **, rcm_info_t **); 87 static int net_resume(rcm_handle_t *, char *, id_t, uint_t, char **, 88 rcm_info_t **); 89 static int net_offline(rcm_handle_t *, char *, id_t, uint_t, char **, 90 rcm_info_t **); 91 static int net_online(rcm_handle_t *, char *, id_t, uint_t, char **, 92 rcm_info_t **); 93 static int net_remove(rcm_handle_t *, char *, id_t, uint_t, char **, 94 rcm_info_t **); 95 static int net_notify_event(rcm_handle_t *, char *, id_t, uint_t, 96 char **, nvlist_t *, rcm_info_t **); 97 98 /* module private routines */ 99 static void free_cache(void); 100 static void update_cache(rcm_handle_t *hd); 101 static int devfs_entry(di_node_t node, di_minor_t minor, void *arg); 102 static void cache_remove(net_cache_t *node); 103 static net_cache_t *cache_lookup(const char *resource); 104 static void free_node(net_cache_t *); 105 static void cache_insert(net_cache_t *); 106 107 /* 108 * Module-Private data 109 */ 110 static struct rcm_mod_ops net_ops = { 111 RCM_MOD_OPS_VERSION, 112 net_register, 113 net_unregister, 114 net_getinfo, 115 net_suspend, 116 net_resume, 117 net_offline, 118 net_online, 119 net_remove, 120 NULL, 121 NULL, 122 net_notify_event 123 }; 124 125 /* 126 * Module Interface Routines 127 */ 128 129 /* 130 * rcm_mod_init() 131 * 132 * Update registrations, and return the ops structure. 133 */ 134 struct rcm_mod_ops * 135 rcm_mod_init(void) 136 { 137 dladm_status_t status; 138 char errmsg[DLADM_STRSIZE]; 139 140 cache_head.next = &cache_tail; 141 cache_head.prev = NULL; 142 cache_tail.prev = &cache_head; 143 cache_tail.next = NULL; 144 (void) mutex_init(&cache_lock, USYNC_THREAD, NULL); 145 146 if ((status = dladm_open(&dld_handle)) != DLADM_STATUS_OK) { 147 rcm_log_message(RCM_WARNING, 148 "NET: mod_init failed: cannot open datalink handle: %s\n", 149 dladm_status2str(status, errmsg)); 150 return (NULL); 151 } 152 153 /* Return the ops vectors */ 154 return (&net_ops); 155 } 156 157 /* 158 * rcm_mod_info() 159 * 160 * Return a string describing this module. 161 */ 162 const char * 163 rcm_mod_info(void) 164 { 165 return ("Network namespace module 1.13"); 166 } 167 168 /* 169 * rcm_mod_fini() 170 * 171 * Destroy the cache. 172 */ 173 int 174 rcm_mod_fini(void) 175 { 176 free_cache(); 177 (void) mutex_destroy(&cache_lock); 178 179 dladm_close(dld_handle); 180 return (RCM_SUCCESS); 181 } 182 183 /* 184 * net_register() 185 * 186 * Make sure the cache is properly sync'ed, and its registrations 187 * are in order. 188 * 189 * Locking: the cache is locked by update_cache, and is held 190 * throughout update_cache's execution because it reads and 191 * possibly modifies cache links continuously. 192 */ 193 static int 194 net_register(rcm_handle_t *hd) 195 { 196 update_cache(hd); 197 /* 198 * Need to register interest in all new resources 199 * getting attached, so we get attach event notifications 200 */ 201 if (!events_registered) { 202 if (rcm_register_event(hd, RCM_RESOURCE_PHYSLINK_NEW, 0, NULL) 203 != RCM_SUCCESS) { 204 rcm_log_message(RCM_ERROR, 205 _("NET: failed to register %s\n"), 206 RCM_RESOURCE_PHYSLINK_NEW); 207 return (RCM_FAILURE); 208 } else { 209 rcm_log_message(RCM_DEBUG, _("NET: registered %s \n"), 210 RCM_RESOURCE_PHYSLINK_NEW); 211 events_registered++; 212 } 213 } 214 215 return (RCM_SUCCESS); 216 } 217 218 /* 219 * net_unregister() 220 * 221 * Manually walk through the cache, unregistering all the networks. 222 * 223 * Locking: the cache is locked throughout the execution of this routine 224 * because it reads and modifies cache links continuously. 225 */ 226 static int 227 net_unregister(rcm_handle_t *hd) 228 { 229 net_cache_t *probe; 230 231 assert(hd != NULL); 232 233 /* Walk the cache, unregistering everything */ 234 (void) mutex_lock(&cache_lock); 235 probe = cache_head.next; 236 while (probe != &cache_tail) { 237 (void) rcm_unregister_interest(hd, probe->resource, 0); 238 cache_remove(probe); 239 free_node(probe); 240 probe = cache_head.next; 241 } 242 (void) mutex_unlock(&cache_lock); 243 244 /* 245 * Need to unregister interest in all new resources 246 */ 247 if (events_registered) { 248 if (rcm_unregister_event(hd, RCM_RESOURCE_PHYSLINK_NEW, 0) 249 != RCM_SUCCESS) { 250 rcm_log_message(RCM_ERROR, 251 _("NET: failed to unregister %s\n"), 252 RCM_RESOURCE_PHYSLINK_NEW); 253 return (RCM_FAILURE); 254 } else { 255 rcm_log_message(RCM_DEBUG, _("NET: unregistered %s\n"), 256 RCM_RESOURCE_PHYSLINK_NEW); 257 events_registered--; 258 } 259 } 260 261 return (RCM_SUCCESS); 262 } 263 264 /* 265 * Since all we do is pass operations thru, we provide a general 266 * routine for passing through operations. 267 */ 268 /*ARGSUSED*/ 269 static int 270 net_passthru(rcm_handle_t *hd, int op, const char *rsrc, uint_t flag, 271 char **reason, rcm_info_t **dependent_reason, void *arg) 272 { 273 net_cache_t *node; 274 char *exported; 275 datalink_id_t linkid; 276 int len; 277 int rv; 278 279 /* 280 * Lock the cache just long enough to extract information about this 281 * resource. 282 */ 283 (void) mutex_lock(&cache_lock); 284 node = cache_lookup(rsrc); 285 if (!node) { 286 rcm_log_message(RCM_WARNING, 287 _("NET: unrecognized resource %s\n"), rsrc); 288 (void) mutex_unlock(&cache_lock); 289 return (RCM_SUCCESS); 290 } 291 292 /* 293 * Since node could be freed after we drop cache_lock, allocate a 294 * stack-local copy. We don't use malloc() because some of the 295 * operations (such as NET_REMOVE) are not allowed to fail. Note 296 * that exported is never more than MAXPATHLEN bytes. 297 */ 298 len = strlen("SUNW_datalink/") + LINKID_STR_WIDTH + 1; 299 exported = alloca(len); 300 linkid = node->linkid; 301 (void) snprintf(exported, len, "SUNW_datalink/%u", linkid); 302 303 /* 304 * Remove notifications are unconditional in the RCM state model, 305 * so it's safe to remove the node from the cache at this point. 306 * And we need to remove it so that we will recognize it as a new 307 * resource following the reattachment of the resource. 308 */ 309 if (op == NET_REMOVE) { 310 cache_remove(node); 311 free_node(node); 312 } 313 (void) mutex_unlock(&cache_lock); 314 315 switch (op) { 316 case NET_SUSPEND: 317 rv = rcm_request_suspend(hd, exported, flag, 318 (timespec_t *)arg, dependent_reason); 319 break; 320 case NET_OFFLINE: 321 rv = rcm_request_offline(hd, exported, flag, dependent_reason); 322 break; 323 case NET_ONLINE: 324 rv = rcm_notify_online(hd, exported, flag, dependent_reason); 325 break; 326 case NET_REMOVE: 327 rv = rcm_notify_remove(hd, exported, flag, dependent_reason); 328 if (rv == RCM_SUCCESS) { 329 rcm_log_message(RCM_DEBUG, 330 _("NET: mark link %d as removed\n"), linkid); 331 332 /* 333 * Delete active linkprop before this active link 334 * is deleted. 335 */ 336 (void) dladm_set_linkprop(dld_handle, linkid, NULL, 337 NULL, 0, DLADM_OPT_ACTIVE); 338 (void) dladm_destroy_datalink_id(dld_handle, linkid, 339 DLADM_OPT_ACTIVE); 340 } 341 break; 342 case NET_RESUME: 343 rv = rcm_notify_resume(hd, exported, flag, dependent_reason); 344 break; 345 default: 346 rcm_log_message(RCM_WARNING, 347 _("NET: bad RCM operation %1$d for %2$s\n"), op, exported); 348 errno = EINVAL; 349 return (RCM_FAILURE); 350 } 351 352 if (rv != RCM_SUCCESS) { 353 char format[256]; 354 (void) snprintf(format, sizeof (format), 355 _("RCM operation on dependent %s did not succeed"), 356 exported); 357 rcm_log_message(RCM_WARNING, "NET: %s\n", format); 358 } 359 return (rv); 360 } 361 362 363 /* 364 * net_offline() 365 * 366 * Determine dependents of the resource being offlined, and offline 367 * them all. 368 */ 369 static int 370 net_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 371 char **reason, rcm_info_t **dependent_reason) 372 { 373 assert(hd != NULL); 374 assert(rsrc != NULL); 375 assert(id == (id_t)0); 376 assert(reason != NULL); 377 assert(dependent_reason != NULL); 378 379 rcm_log_message(RCM_TRACE1, _("NET: offline(%s)\n"), rsrc); 380 381 return (net_passthru(hd, NET_OFFLINE, rsrc, flags, reason, 382 dependent_reason, NULL)); 383 } 384 385 /* 386 * net_online() 387 * 388 * Online the previously offlined resource, and online its dependents. 389 */ 390 static int 391 net_online(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flag, char **reason, 392 rcm_info_t **dependent_reason) 393 { 394 assert(hd != NULL); 395 assert(rsrc != NULL); 396 assert(id == (id_t)0); 397 398 rcm_log_message(RCM_TRACE1, _("NET: online(%s)\n"), rsrc); 399 400 return (net_passthru(hd, NET_ONLINE, rsrc, flag, reason, 401 dependent_reason, NULL)); 402 } 403 404 /* 405 * net_getinfo() 406 * 407 * Gather usage information for this resource. 408 * 409 * Locking: the cache is locked while this routine looks up the 410 * resource and extracts copies of any piece of information it needs. 411 * The cache is then unlocked, and this routine performs the rest of 412 * its functions without touching any part of the cache. 413 */ 414 /*ARGSUSED*/ 415 static int 416 net_getinfo(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flag, 417 char **info, char **errstr, nvlist_t *proplist, rcm_info_t **depend_info) 418 { 419 int len; 420 dladm_status_t status; 421 char link[MAXLINKNAMELEN]; 422 char errmsg[DLADM_STRSIZE]; 423 char *exported; 424 const char *info_fmt; 425 net_cache_t *node; 426 427 assert(hd != NULL); 428 assert(rsrc != NULL); 429 assert(id == (id_t)0); 430 assert(info != NULL); 431 assert(depend_info != NULL); 432 433 rcm_log_message(RCM_TRACE1, _("NET: getinfo(%s)\n"), rsrc); 434 435 info_fmt = _("Network interface %s"); 436 437 (void) mutex_lock(&cache_lock); 438 node = cache_lookup(rsrc); 439 if (!node) { 440 rcm_log_message(RCM_WARNING, 441 _("NET: unrecognized resource %s\n"), rsrc); 442 (void) mutex_unlock(&cache_lock); 443 errno = ENOENT; 444 return (RCM_FAILURE); 445 } 446 447 len = strlen(info_fmt) + MAXLINKNAMELEN + 1; 448 if ((status = dladm_datalink_id2info(dld_handle, node->linkid, NULL, 449 NULL, NULL, link, sizeof (link))) != DLADM_STATUS_OK) { 450 rcm_log_message(RCM_ERROR, 451 _("NET: usage(%s) get link name failure(%s)\n"), 452 node->resource, dladm_status2str(status, errmsg)); 453 (void) mutex_unlock(&cache_lock); 454 return (RCM_FAILURE); 455 } else if ((*info = (char *)malloc(len)) == NULL) { 456 rcm_log_message(RCM_ERROR, _("NET: malloc failure")); 457 (void) mutex_unlock(&cache_lock); 458 return (RCM_FAILURE); 459 } 460 461 /* Fill in the string */ 462 (void) snprintf(*info, len, info_fmt, link); 463 464 len = strlen("SUNW_datalink/") + LINKID_STR_WIDTH + 1; 465 exported = malloc(len); 466 if (!exported) { 467 rcm_log_message(RCM_ERROR, _("NET: allocation failure")); 468 free(*info); 469 (void) mutex_unlock(&cache_lock); 470 return (RCM_FAILURE); 471 } 472 (void) snprintf(exported, len, "SUNW_datalink/%u", node->linkid); 473 (void) mutex_unlock(&cache_lock); 474 475 /* Get dependent info if requested */ 476 if ((flag & RCM_INCLUDE_DEPENDENT) || (flag & RCM_INCLUDE_SUBTREE)) { 477 (void) rcm_get_info(hd, exported, flag, depend_info); 478 } 479 480 (void) nvlist_add_string(proplist, RCM_CLIENT_NAME, "SunOS"); 481 (void) nvlist_add_string_array(proplist, RCM_CLIENT_EXPORTS, 482 &exported, 1); 483 484 free(exported); 485 return (RCM_SUCCESS); 486 } 487 488 /* 489 * net_suspend() 490 * 491 * Notify all dependents that the resource is being suspended. 492 * Since no real operation is involved, QUERY or not doesn't matter. 493 * 494 * Locking: the cache is only used to retrieve some information about 495 * this resource, so it is only locked during that retrieval. 496 */ 497 static int 498 net_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval, 499 uint_t flag, char **reason, rcm_info_t **dependent_reason) 500 { 501 assert(hd != NULL); 502 assert(rsrc != NULL); 503 assert(id == (id_t)0); 504 assert(interval != NULL); 505 assert(reason != NULL); 506 assert(dependent_reason != NULL); 507 508 rcm_log_message(RCM_TRACE1, _("NET: suspend(%s)\n"), rsrc); 509 510 return (net_passthru(hd, NET_SUSPEND, rsrc, flag, reason, 511 dependent_reason, (void *)interval)); 512 } 513 514 /* 515 * net_resume() 516 * 517 * Resume all the dependents of a suspended network. 518 * 519 * Locking: the cache is only used to retrieve some information about 520 * this resource, so it is only locked during that retrieval. 521 */ 522 static int 523 net_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flag, char **info, 524 rcm_info_t **dependent_info) 525 { 526 assert(hd != NULL); 527 assert(rsrc != NULL); 528 assert(id == (id_t)0); 529 assert(info != NULL); 530 assert(dependent_info != NULL); 531 532 rcm_log_message(RCM_TRACE1, _("NET: resume(%s)\n"), rsrc); 533 534 return (net_passthru(hd, NET_RESUME, rsrc, flag, info, dependent_info, 535 NULL)); 536 } 537 538 /* 539 * net_remove() 540 * 541 * This is another NO-OP for us, we just passthru the information. We 542 * don't need to remove it from our cache. We don't unregister 543 * interest at this point either; the network device name is still 544 * around. This way we don't have to change this logic when we 545 * gain the ability to learn about DR attach operations. 546 */ 547 static int 548 net_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flag, char **info, 549 rcm_info_t **dependent_info) 550 { 551 assert(hd != NULL); 552 assert(rsrc != NULL); 553 assert(id == (id_t)0); 554 assert(info != NULL); 555 assert(dependent_info != NULL); 556 557 rcm_log_message(RCM_TRACE1, _("NET: remove(%s)\n"), rsrc); 558 559 return (net_passthru(hd, NET_REMOVE, rsrc, flag, info, dependent_info, 560 NULL)); 561 } 562 563 /* 564 * Cache management routines. Note that the cache is implemented as a 565 * trivial linked list, and is only required because RCM doesn't 566 * provide enough state about our own registrations back to us. This 567 * linked list implementation probably clobbers the CPU cache pretty 568 * well. 569 */ 570 571 /* 572 * cache_lookup() 573 * 574 * Get a cache node for a resource. Call with cache lock held. 575 */ 576 static net_cache_t * 577 cache_lookup(const char *resource) 578 { 579 net_cache_t *probe; 580 probe = cache_head.next; 581 while (probe != &cache_tail) { 582 if (probe->resource && 583 (strcmp(resource, probe->resource) == 0)) { 584 return (probe); 585 } 586 probe = probe->next; 587 } 588 return (NULL); 589 } 590 591 /* 592 * free_node() 593 * 594 * Free a node. Make sure it isn't in the list! 595 */ 596 static void 597 free_node(net_cache_t *node) 598 { 599 if (node) { 600 free(node->resource); 601 free(node); 602 } 603 } 604 605 /* 606 * cache_insert() 607 * 608 * Call with the cache_lock held. 609 */ 610 static void 611 cache_insert(net_cache_t *node) 612 { 613 /* insert at the head for best performance */ 614 node->next = cache_head.next; 615 node->prev = &cache_head; 616 617 node->next->prev = node; 618 node->prev->next = node; 619 } 620 621 /* 622 * cache_remove() 623 * 624 * Call with the cache_lock held. 625 */ 626 static void 627 cache_remove(net_cache_t *node) 628 { 629 node->next->prev = node->prev; 630 node->prev->next = node->next; 631 node->next = NULL; 632 node->prev = NULL; 633 } 634 635 /* 636 * devfs_entry() 637 * 638 * Call with the cache_lock held. 639 */ 640 /*ARGSUSED*/ 641 static int 642 devfs_entry(di_node_t node, di_minor_t minor, void *arg) 643 { 644 char *devfspath; 645 char resource[MAXPATHLEN]; 646 char dev[MAXNAMELEN]; 647 datalink_id_t linkid; 648 char *drv; 649 char *cp; 650 net_cache_t *probe; 651 652 cp = di_minor_nodetype(minor); 653 if ((cp == NULL) || (strcmp(cp, DDI_NT_NET))) { 654 /* doesn't look like a network device */ 655 return (DI_WALK_CONTINUE); 656 } 657 658 drv = di_driver_name(node); 659 if (drv == NULL) { 660 /* what else can we do? */ 661 return (DI_WALK_CONTINUE); 662 } 663 664 devfspath = di_devfs_path(node); 665 if (!devfspath) { 666 /* no devfs path?!? */ 667 rcm_log_message(RCM_DEBUG, _("NET: missing devfs path\n")); 668 return (DI_WALK_CONTINUE); 669 } 670 671 if (strncmp("/pseudo", devfspath, strlen("/pseudo")) == 0) { 672 /* ignore pseudo devices, probably not really NICs */ 673 rcm_log_message(RCM_DEBUG, 674 _("NET: ignoring pseudo device %s\n"), devfspath); 675 di_devfs_path_free(devfspath); 676 return (DI_WALK_CONTINUE); 677 } 678 679 (void) snprintf(resource, sizeof (resource), "/devices%s", devfspath); 680 di_devfs_path_free(devfspath); 681 682 (void) snprintf(dev, sizeof (dev), "%s%d", drv, di_instance(node)); 683 if (dladm_dev2linkid(dld_handle, dev, &linkid) != DLADM_STATUS_OK) { 684 rcm_log_message(RCM_DEBUG, 685 _("NET: failed to find the linkid for %s\n"), dev); 686 return (DI_WALK_CONTINUE); 687 } 688 689 probe = cache_lookup(resource); 690 if (probe != NULL) { 691 rcm_log_message(RCM_DEBUG, 692 _("NET: %s already registered (linkid %u)\n"), 693 resource, linkid); 694 probe->linkid = linkid; 695 probe->flags &= ~(CACHE_STALE); 696 } else { 697 rcm_log_message(RCM_DEBUG, 698 _("NET: %s is new resource (linkid %u)\n"), 699 resource, linkid); 700 probe = calloc(1, sizeof (net_cache_t)); 701 if (!probe) { 702 rcm_log_message(RCM_ERROR, _("NET: malloc failure")); 703 return (DI_WALK_CONTINUE); 704 } 705 706 probe->resource = strdup(resource); 707 probe->linkid = linkid; 708 709 if (!probe->resource) { 710 free_node(probe); 711 return (DI_WALK_CONTINUE); 712 } 713 714 probe->flags |= CACHE_NEW; 715 cache_insert(probe); 716 } 717 718 return (DI_WALK_CONTINUE); 719 } 720 721 /* 722 * update_cache() 723 * 724 * The devinfo tree walking code is lifted from ifconfig.c. 725 */ 726 static void 727 update_cache(rcm_handle_t *hd) 728 { 729 net_cache_t *probe; 730 di_node_t root; 731 int rv; 732 733 (void) mutex_lock(&cache_lock); 734 735 /* first we walk the entire cache, marking each entry stale */ 736 probe = cache_head.next; 737 while (probe != &cache_tail) { 738 probe->flags |= CACHE_STALE; 739 probe = probe->next; 740 } 741 742 root = di_init("/", DINFOSUBTREE | DINFOMINOR); 743 if (root == DI_NODE_NIL) { 744 goto done; 745 } 746 747 (void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, NULL, 748 devfs_entry); 749 750 di_fini(root); 751 752 probe = cache_head.next; 753 while (probe != &cache_tail) { 754 net_cache_t *freeit; 755 if (probe->flags & CACHE_STALE) { 756 (void) rcm_unregister_interest(hd, probe->resource, 0); 757 rcm_log_message(RCM_DEBUG, _("NET: unregistered %s\n"), 758 probe->resource); 759 freeit = probe; 760 probe = probe->next; 761 cache_remove(freeit); 762 free_node(freeit); 763 continue; 764 } 765 766 if (!(probe->flags & CACHE_NEW)) { 767 probe = probe->next; 768 continue; 769 } 770 771 rcm_log_message(RCM_DEBUG, _("NET: registering %s\n"), 772 probe->resource); 773 rv = rcm_register_interest(hd, probe->resource, 0, NULL); 774 if (rv != RCM_SUCCESS) { 775 rcm_log_message(RCM_ERROR, 776 _("NET: failed to register %s\n"), 777 probe->resource); 778 } else { 779 rcm_log_message(RCM_DEBUG, 780 _("NET: registered %s as SUNW_datalink/%u\n"), 781 probe->resource, probe->linkid); 782 probe->flags &= ~(CACHE_NEW); 783 } 784 probe = probe->next; 785 } 786 787 done: 788 (void) mutex_unlock(&cache_lock); 789 } 790 791 /* 792 * free_cache() 793 */ 794 static void 795 free_cache(void) 796 { 797 net_cache_t *probe; 798 799 (void) mutex_lock(&cache_lock); 800 probe = cache_head.next; 801 while (probe != &cache_tail) { 802 cache_remove(probe); 803 free_node(probe); 804 probe = cache_head.next; 805 } 806 (void) mutex_unlock(&cache_lock); 807 } 808 809 /* 810 * net_notify_event - Project private implementation to receive new 811 * resource events. It intercepts all new resource 812 * events. If the new resource is a network resource, 813 * update the physical link cache. 814 */ 815 /*ARGSUSED*/ 816 static int 817 net_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags, 818 char **errorp, nvlist_t *nvl, rcm_info_t **depend_info) 819 { 820 nvpair_t *nvp = NULL; 821 uint64_t id64 = (uint64_t)DATALINK_INVALID_LINKID; 822 boolean_t reconfigured = B_FALSE; 823 824 rcm_log_message(RCM_TRACE1, _("NET: notify_event(%s)\n"), rsrc); 825 826 if (strcmp(rsrc, RCM_RESOURCE_PHYSLINK_NEW) != 0) { 827 rcm_log_message(RCM_INFO, 828 _("NET: unrecognized event for %s\n"), rsrc); 829 errno = EINVAL; 830 return (RCM_FAILURE); 831 } 832 833 /* Update cache to reflect latest physical links */ 834 update_cache(hd); 835 836 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 837 if (strcmp(nvpair_name(nvp), RCM_NV_RECONFIGURED) == 0) { 838 if (nvpair_value_boolean_value(nvp, 839 &reconfigured) != 0) { 840 rcm_log_message(RCM_INFO, 841 _("NET: unrecognized %s event data\n"), 842 RCM_NV_RECONFIGURED); 843 errno = EINVAL; 844 return (RCM_FAILURE); 845 } 846 847 rcm_log_message(RCM_TRACE1, 848 "NET: %s event data (%sreconfiguration)\n", 849 RCM_NV_RECONFIGURED, reconfigured ? "" : "not "); 850 } 851 852 if (strcmp(nvpair_name(nvp), RCM_NV_LINKID) == 0) { 853 if (nvpair_value_uint64(nvp, &id64) != 0) { 854 rcm_log_message(RCM_INFO, 855 _("NET: unrecognized %s event data\n"), 856 RCM_NV_LINKID); 857 errno = EINVAL; 858 return (RCM_FAILURE); 859 } 860 861 rcm_log_message(RCM_TRACE1, 862 "NET: %s event data (linkid %d)\n", RCM_NV_LINKID, 863 (datalink_id_t)id64); 864 } 865 } 866 867 if ((datalink_id_t)id64 == DATALINK_INVALID_LINKID) { 868 rcm_log_message(RCM_INFO, _("NET: invalid datalink\n")); 869 errno = EINVAL; 870 return (RCM_FAILURE); 871 } 872 873 /* 874 * If this is device reconfiguration, populate the LINK_NEW event 875 * to start the DR process. 876 */ 877 if (reconfigured) { 878 nvlist_t *nnvl = NULL; 879 880 rcm_log_message(RCM_TRACE1, 881 "NET: reconfigured data-link (id %d)\n", 882 (datalink_id_t)id64); 883 884 if ((nvlist_alloc(&nnvl, 0, 0) != 0) || (nvlist_add_uint64(nnvl, 885 RCM_NV_LINKID, id64) != 0) || (rcm_notify_event(hd, 886 RCM_RESOURCE_LINK_NEW, 0, nnvl, NULL) != RCM_SUCCESS)) { 887 nvlist_free(nnvl); 888 rcm_log_message(RCM_INFO, 889 _("NET: notify %s event failed\n"), 890 RCM_RESOURCE_LINK_NEW); 891 errno = EINVAL; 892 return (RCM_FAILURE); 893 } 894 nvlist_free(nnvl); 895 } 896 897 rcm_log_message(RCM_TRACE1, 898 _("NET: notify_event: device configuration complete\n")); 899 900 return (RCM_SUCCESS); 901 } 902