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