8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / rcm_daemon / common / network_rcm.c
blobdbb60775fa15fe9ef18391e5e6ae2ec379a6edc9
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * This RCM module adds support to the RCM framework for an abstract
28 * namespace for network devices (DLPI providers).
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"
46 * Definitions
48 #ifndef lint
49 #define _(x) gettext(x)
50 #else
51 #define _(x) x
52 #endif
54 #define CACHE_STALE 1 /* flags */
55 #define CACHE_NEW 2 /* flags */
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
64 typedef struct net_cache
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;
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;
78 static dladm_handle_t dld_handle = NULL;
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 **);
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 *);
108 * Module-Private data
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
126 * Module Interface Routines
130 * rcm_mod_init()
132 * Update registrations, and return the ops structure.
134 struct rcm_mod_ops *
135 rcm_mod_init(void)
137 dladm_status_t status;
138 char errmsg[DLADM_STRSIZE];
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, NULL, NULL);
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);
153 /* Return the ops vectors */
154 return (&net_ops);
158 * rcm_mod_info()
160 * Return a string describing this module.
162 const char *
163 rcm_mod_info(void)
165 return ("Network namespace module 1.13");
169 * rcm_mod_fini()
171 * Destroy the cache.
174 rcm_mod_fini(void)
176 free_cache();
177 (void) mutex_destroy(&cache_lock);
179 dladm_close(dld_handle);
180 return (RCM_SUCCESS);
184 * net_register()
186 * Make sure the cache is properly sync'ed, and its registrations
187 * are in order.
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.
193 static int
194 net_register(rcm_handle_t *hd)
196 update_cache(hd);
198 * Need to register interest in all new resources
199 * getting attached, so we get attach event notifications
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++;
215 return (RCM_SUCCESS);
219 * net_unregister()
221 * Manually walk through the cache, unregistering all the networks.
223 * Locking: the cache is locked throughout the execution of this routine
224 * because it reads and modifies cache links continuously.
226 static int
227 net_unregister(rcm_handle_t *hd)
229 net_cache_t *probe;
231 assert(hd != NULL);
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;
242 (void) mutex_unlock(&cache_lock);
245 * Need to unregister interest in all new resources
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--;
261 return (RCM_SUCCESS);
265 * Since all we do is pass operations thru, we provide a general
266 * routine for passing through operations.
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)
273 net_cache_t *node;
274 char *exported;
275 datalink_id_t linkid;
276 int len;
277 int rv;
280 * Lock the cache just long enough to extract information about this
281 * resource.
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);
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.
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);
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.
309 if (op == NET_REMOVE) {
310 cache_remove(node);
311 free_node(node);
313 (void) mutex_unlock(&cache_lock);
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);
333 * Delete active linkprop before this active link
334 * is deleted.
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);
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);
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);
359 return (rv);
364 * net_offline()
366 * Determine dependents of the resource being offlined, and offline
367 * them all.
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)
373 assert(hd != NULL);
374 assert(rsrc != NULL);
375 assert(id == (id_t)0);
376 assert(reason != NULL);
377 assert(dependent_reason != NULL);
379 rcm_log_message(RCM_TRACE1, _("NET: offline(%s)\n"), rsrc);
381 return (net_passthru(hd, NET_OFFLINE, rsrc, flags, reason,
382 dependent_reason, NULL));
386 * net_online()
388 * Online the previously offlined resource, and online its dependents.
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)
394 assert(hd != NULL);
395 assert(rsrc != NULL);
396 assert(id == (id_t)0);
398 rcm_log_message(RCM_TRACE1, _("NET: online(%s)\n"), rsrc);
400 return (net_passthru(hd, NET_ONLINE, rsrc, flag, reason,
401 dependent_reason, NULL));
405 * net_getinfo()
407 * Gather usage information for this resource.
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.
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)
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;
427 assert(hd != NULL);
428 assert(rsrc != NULL);
429 assert(id == (id_t)0);
430 assert(info != NULL);
431 assert(depend_info != NULL);
433 rcm_log_message(RCM_TRACE1, _("NET: getinfo(%s)\n"), rsrc);
435 info_fmt = _("Network interface %s");
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);
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);
461 /* Fill in the string */
462 (void) snprintf(*info, len, info_fmt, link);
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);
472 (void) snprintf(exported, len, "SUNW_datalink/%u", node->linkid);
473 (void) mutex_unlock(&cache_lock);
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);
480 (void) nvlist_add_string(proplist, RCM_CLIENT_NAME, "SunOS");
481 (void) nvlist_add_string_array(proplist, RCM_CLIENT_EXPORTS,
482 &exported, 1);
484 free(exported);
485 return (RCM_SUCCESS);
489 * net_suspend()
491 * Notify all dependents that the resource is being suspended.
492 * Since no real operation is involved, QUERY or not doesn't matter.
494 * Locking: the cache is only used to retrieve some information about
495 * this resource, so it is only locked during that retrieval.
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)
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);
508 rcm_log_message(RCM_TRACE1, _("NET: suspend(%s)\n"), rsrc);
510 return (net_passthru(hd, NET_SUSPEND, rsrc, flag, reason,
511 dependent_reason, (void *)interval));
515 * net_resume()
517 * Resume all the dependents of a suspended network.
519 * Locking: the cache is only used to retrieve some information about
520 * this resource, so it is only locked during that retrieval.
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)
526 assert(hd != NULL);
527 assert(rsrc != NULL);
528 assert(id == (id_t)0);
529 assert(info != NULL);
530 assert(dependent_info != NULL);
532 rcm_log_message(RCM_TRACE1, _("NET: resume(%s)\n"), rsrc);
534 return (net_passthru(hd, NET_RESUME, rsrc, flag, info, dependent_info,
535 NULL));
539 * net_remove()
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.
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)
551 assert(hd != NULL);
552 assert(rsrc != NULL);
553 assert(id == (id_t)0);
554 assert(info != NULL);
555 assert(dependent_info != NULL);
557 rcm_log_message(RCM_TRACE1, _("NET: remove(%s)\n"), rsrc);
559 return (net_passthru(hd, NET_REMOVE, rsrc, flag, info, dependent_info,
560 NULL));
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.
572 * cache_lookup()
574 * Get a cache node for a resource. Call with cache lock held.
576 static net_cache_t *
577 cache_lookup(const char *resource)
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);
586 probe = probe->next;
588 return (NULL);
592 * free_node()
594 * Free a node. Make sure it isn't in the list!
596 static void
597 free_node(net_cache_t *node)
599 if (node) {
600 free(node->resource);
601 free(node);
606 * cache_insert()
608 * Call with the cache_lock held.
610 static void
611 cache_insert(net_cache_t *node)
613 /* insert at the head for best performance */
614 node->next = cache_head.next;
615 node->prev = &cache_head;
617 node->next->prev = node;
618 node->prev->next = node;
622 * cache_remove()
624 * Call with the cache_lock held.
626 static void
627 cache_remove(net_cache_t *node)
629 node->next->prev = node->prev;
630 node->prev->next = node->next;
631 node->next = NULL;
632 node->prev = NULL;
636 * devfs_entry()
638 * Call with the cache_lock held.
640 /*ARGSUSED*/
641 static int
642 devfs_entry(di_node_t node, di_minor_t minor, void *arg)
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;
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);
658 drv = di_driver_name(node);
659 if (drv == NULL) {
660 /* what else can we do? */
661 return (DI_WALK_CONTINUE);
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);
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);
679 (void) snprintf(resource, sizeof (resource), "/devices%s", devfspath);
680 di_devfs_path_free(devfspath);
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);
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);
706 probe->resource = strdup(resource);
707 probe->linkid = linkid;
709 if (!probe->resource) {
710 free_node(probe);
711 return (DI_WALK_CONTINUE);
714 probe->flags |= CACHE_NEW;
715 cache_insert(probe);
718 return (DI_WALK_CONTINUE);
722 * update_cache()
724 * The devinfo tree walking code is lifted from ifconfig.c.
726 static void
727 update_cache(rcm_handle_t *hd)
729 net_cache_t *probe;
730 di_node_t root;
731 int rv;
733 (void) mutex_lock(&cache_lock);
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;
742 root = di_init("/", DINFOSUBTREE | DINFOMINOR);
743 if (root == DI_NODE_NIL) {
744 goto done;
747 (void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, NULL,
748 devfs_entry);
750 di_fini(root);
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;
766 if (!(probe->flags & CACHE_NEW)) {
767 probe = probe->next;
768 continue;
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);
784 probe = probe->next;
787 done:
788 (void) mutex_unlock(&cache_lock);
792 * free_cache()
794 static void
795 free_cache(void)
797 net_cache_t *probe;
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;
806 (void) mutex_unlock(&cache_lock);
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.
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)
820 nvpair_t *nvp = NULL;
821 uint64_t id64 = (uint64_t)DATALINK_INVALID_LINKID;
822 boolean_t reconfigured = B_FALSE;
824 rcm_log_message(RCM_TRACE1, _("NET: notify_event(%s)\n"), rsrc);
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);
833 /* Update cache to reflect latest physical links */
834 update_cache(hd);
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);
847 rcm_log_message(RCM_TRACE1,
848 "NET: %s event data (%sreconfiguration)\n",
849 RCM_NV_RECONFIGURED, reconfigured ? "" : "not ");
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);
861 rcm_log_message(RCM_TRACE1,
862 "NET: %s event data (linkid %d)\n", RCM_NV_LINKID,
863 (datalink_id_t)id64);
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);
874 * If this is device reconfiguration, populate the LINK_NEW event
875 * to start the DR process.
877 if (reconfigured) {
878 nvlist_t *nnvl = NULL;
880 rcm_log_message(RCM_TRACE1,
881 "NET: reconfigured data-link (id %d)\n",
882 (datalink_id_t)id64);
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);
894 nvlist_free(nnvl);
897 rcm_log_message(RCM_TRACE1,
898 _("NET: notify_event: device configuration complete\n"));
900 return (RCM_SUCCESS);