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