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]
22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
26 * This RCM module adds support to the RCM framework for VNIC links
33 #include <sys/types.h>
37 #include "rcm_module.h"
39 #include <libdllink.h>
40 #include <libdlvnic.h>
47 #define _(x) gettext(x)
52 /* Some generic well-knowns and defaults used in this module */
53 #define RCM_LINK_PREFIX "SUNW_datalink" /* RCM datalink name prefix */
54 #define RCM_LINK_RESOURCE_MAX (13 + LINKID_STR_WIDTH)
59 VNIC_CONSUMER_OFFLINED
= 0x2,
63 /* link representation */
64 typedef struct dl_vnic
{
65 struct dl_vnic
*dlv_next
; /* next VNIC on the same link */
66 struct dl_vnic
*dlv_prev
; /* prev VNIC on the same link */
67 datalink_id_t dlv_vnic_id
;
68 vnic_flag_t dlv_flags
; /* VNIC link flags */
71 /* VNIC Cache state flags */
73 CACHE_NODE_STALE
= 0x1, /* stale cached data */
74 CACHE_NODE_NEW
= 0x2, /* new cached nodes */
75 CACHE_NODE_OFFLINED
= 0x4 /* nodes offlined */
78 /* Network Cache lookup options */
79 #define CACHE_NO_REFRESH 0x1 /* cache refresh not needed */
80 #define CACHE_REFRESH 0x2 /* refresh cache */
83 typedef struct link_cache
{
84 struct link_cache
*vc_next
; /* next cached resource */
85 struct link_cache
*vc_prev
; /* prev cached resource */
86 char *vc_resource
; /* resource name */
87 datalink_id_t vc_linkid
; /* linkid */
88 dl_vnic_t
*vc_vnic
; /* VNIC list on this link */
89 cache_node_state_t vc_state
; /* cache state flags */
93 * Global cache for network VNICs
95 static link_cache_t cache_head
;
96 static link_cache_t cache_tail
;
97 static mutex_t cache_lock
;
98 static int events_registered
= 0;
100 static dladm_handle_t dld_handle
= NULL
;
103 * RCM module interface prototypes
105 static int vnic_register(rcm_handle_t
*);
106 static int vnic_unregister(rcm_handle_t
*);
107 static int vnic_get_info(rcm_handle_t
*, char *, id_t
, uint_t
,
108 char **, char **, nvlist_t
*, rcm_info_t
**);
109 static int vnic_suspend(rcm_handle_t
*, char *, id_t
,
110 timespec_t
*, uint_t
, char **, rcm_info_t
**);
111 static int vnic_resume(rcm_handle_t
*, char *, id_t
, uint_t
,
112 char **, rcm_info_t
**);
113 static int vnic_offline(rcm_handle_t
*, char *, id_t
, uint_t
,
114 char **, rcm_info_t
**);
115 static int vnic_undo_offline(rcm_handle_t
*, char *, id_t
, uint_t
,
116 char **, rcm_info_t
**);
117 static int vnic_remove(rcm_handle_t
*, char *, id_t
, uint_t
,
118 char **, rcm_info_t
**);
119 static int vnic_notify_event(rcm_handle_t
*, char *, id_t
, uint_t
,
120 char **, nvlist_t
*, rcm_info_t
**);
121 static int vnic_configure(rcm_handle_t
*, datalink_id_t
);
123 /* Module private routines */
124 static void cache_free();
125 static int cache_update(rcm_handle_t
*);
126 static void cache_remove(link_cache_t
*);
127 static void node_free(link_cache_t
*);
128 static void cache_insert(link_cache_t
*);
129 static link_cache_t
*cache_lookup(rcm_handle_t
*, char *, char);
130 static int vnic_consumer_offline(rcm_handle_t
*, link_cache_t
*,
131 char **, uint_t
, rcm_info_t
**);
132 static void vnic_consumer_online(rcm_handle_t
*, link_cache_t
*,
133 char **, uint_t
, rcm_info_t
**);
134 static int vnic_offline_vnic(link_cache_t
*, uint32_t,
136 static void vnic_online_vnic(link_cache_t
*);
137 static char *vnic_usage(link_cache_t
*);
138 static void vnic_log_err(datalink_id_t
, char **, char *);
139 static int vnic_consumer_notify(rcm_handle_t
*, datalink_id_t
,
140 char **, uint_t
, rcm_info_t
**);
142 /* Module-Private data */
143 static struct rcm_mod_ops vnic_ops
=
160 * rcm_mod_init() - Update registrations, and return the ops structure.
165 char errmsg
[DLADM_STRSIZE
];
166 dladm_status_t status
;
168 rcm_log_message(RCM_TRACE1
, "VNIC: mod_init\n");
170 cache_head
.vc_next
= &cache_tail
;
171 cache_head
.vc_prev
= NULL
;
172 cache_tail
.vc_prev
= &cache_head
;
173 cache_tail
.vc_next
= NULL
;
174 (void) mutex_init(&cache_lock
, 0, NULL
);
176 if ((status
= dladm_open(&dld_handle
)) != DLADM_STATUS_OK
) {
177 rcm_log_message(RCM_WARNING
,
178 "VNIC: mod_init failed: cannot open datalink handle: %s\n",
179 dladm_status2str(status
, errmsg
));
183 /* Return the ops vectors */
188 * rcm_mod_info() - Return a string describing this module.
193 rcm_log_message(RCM_TRACE1
, "VNIC: mod_info\n");
195 return ("VNIC module");
199 * rcm_mod_fini() - Destroy the network VNIC cache.
204 rcm_log_message(RCM_TRACE1
, "VNIC: mod_fini\n");
207 * Note that vnic_unregister() does not seem to be called anywhere,
208 * therefore we free the cache nodes here. In theory we should call
209 * rcm_register_interest() for each node before we free it, the
210 * framework does not provide the rcm_handle to allow us to do so.
213 (void) mutex_destroy(&cache_lock
);
215 dladm_close(dld_handle
);
216 return (RCM_SUCCESS
);
220 * vnic_register() - Make sure the cache is properly sync'ed, and its
221 * registrations are in order.
224 vnic_register(rcm_handle_t
*hd
)
226 rcm_log_message(RCM_TRACE1
, "VNIC: register\n");
228 if (cache_update(hd
) < 0)
229 return (RCM_FAILURE
);
232 * Need to register interest in all new resources
233 * getting attached, so we get attach event notifications
235 if (!events_registered
) {
236 if (rcm_register_event(hd
, RCM_RESOURCE_LINK_NEW
, 0, NULL
)
238 rcm_log_message(RCM_ERROR
,
239 _("VNIC: failed to register %s\n"),
240 RCM_RESOURCE_LINK_NEW
);
241 return (RCM_FAILURE
);
243 rcm_log_message(RCM_DEBUG
, "VNIC: registered %s\n",
244 RCM_RESOURCE_LINK_NEW
);
249 return (RCM_SUCCESS
);
253 * vnic_unregister() - Walk the cache, unregistering all the networks.
256 vnic_unregister(rcm_handle_t
*hd
)
260 rcm_log_message(RCM_TRACE1
, "VNIC: unregister\n");
262 /* Walk the cache, unregistering everything */
263 (void) mutex_lock(&cache_lock
);
264 node
= cache_head
.vc_next
;
265 while (node
!= &cache_tail
) {
266 if (rcm_unregister_interest(hd
, node
->vc_resource
, 0)
268 rcm_log_message(RCM_ERROR
,
269 _("VNIC: failed to unregister %s\n"),
271 (void) mutex_unlock(&cache_lock
);
272 return (RCM_FAILURE
);
276 node
= cache_head
.vc_next
;
278 (void) mutex_unlock(&cache_lock
);
281 * Unregister interest in all new resources
283 if (events_registered
) {
284 if (rcm_unregister_event(hd
, RCM_RESOURCE_LINK_NEW
, 0)
286 rcm_log_message(RCM_ERROR
,
287 _("VNIC: failed to unregister %s\n"),
288 RCM_RESOURCE_LINK_NEW
);
289 return (RCM_FAILURE
);
291 rcm_log_message(RCM_DEBUG
, "VNIC: unregistered %s\n",
292 RCM_RESOURCE_LINK_NEW
);
297 return (RCM_SUCCESS
);
301 * vnic_offline() - Offline VNICs on a specific node.
304 vnic_offline(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
305 char **errorp
, rcm_info_t
**info
)
309 rcm_log_message(RCM_TRACE1
, "VNIC: offline(%s)\n", rsrc
);
311 /* Lock the cache and lookup the resource */
312 (void) mutex_lock(&cache_lock
);
313 node
= cache_lookup(hd
, rsrc
, CACHE_REFRESH
);
315 /* should not happen because the resource is registered. */
316 vnic_log_err(DATALINK_INVALID_LINKID
, errorp
,
317 "unrecognized resource");
318 (void) mutex_unlock(&cache_lock
);
319 return (RCM_SUCCESS
);
323 * Inform consumers (IP interfaces) of associated VNICs to be offlined
325 if (vnic_consumer_offline(hd
, node
, errorp
, flags
, info
) ==
327 rcm_log_message(RCM_DEBUG
,
328 "VNIC: consumers agreed on offline\n");
330 vnic_log_err(node
->vc_linkid
, errorp
,
331 "consumers failed to offline");
332 (void) mutex_unlock(&cache_lock
);
333 return (RCM_FAILURE
);
336 /* Check if it's a query */
337 if (flags
& RCM_QUERY
) {
338 rcm_log_message(RCM_TRACE1
,
339 "VNIC: offline query succeeded(%s)\n", rsrc
);
340 (void) mutex_unlock(&cache_lock
);
341 return (RCM_SUCCESS
);
344 if (vnic_offline_vnic(node
, VNIC_OFFLINED
, CACHE_NODE_OFFLINED
) !=
346 vnic_online_vnic(node
);
347 vnic_log_err(node
->vc_linkid
, errorp
, "offline failed");
348 (void) mutex_unlock(&cache_lock
);
349 return (RCM_FAILURE
);
352 rcm_log_message(RCM_TRACE1
, "VNIC: Offline succeeded(%s)\n", rsrc
);
353 (void) mutex_unlock(&cache_lock
);
354 return (RCM_SUCCESS
);
358 * vnic_undo_offline() - Undo offline of a previously offlined node.
362 vnic_undo_offline(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
363 char **errorp
, rcm_info_t
**info
)
367 rcm_log_message(RCM_TRACE1
, "VNIC: online(%s)\n", rsrc
);
369 (void) mutex_lock(&cache_lock
);
370 node
= cache_lookup(hd
, rsrc
, CACHE_NO_REFRESH
);
372 vnic_log_err(DATALINK_INVALID_LINKID
, errorp
, "no such link");
373 (void) mutex_unlock(&cache_lock
);
375 return (RCM_FAILURE
);
378 /* Check if no attempt should be made to online the link here */
379 if (!(node
->vc_state
& CACHE_NODE_OFFLINED
)) {
380 vnic_log_err(node
->vc_linkid
, errorp
, "link not offlined");
381 (void) mutex_unlock(&cache_lock
);
383 return (RCM_SUCCESS
);
386 vnic_online_vnic(node
);
389 * Inform IP interfaces on associated VNICs to be onlined
391 vnic_consumer_online(hd
, node
, errorp
, flags
, info
);
393 node
->vc_state
&= ~CACHE_NODE_OFFLINED
;
394 rcm_log_message(RCM_TRACE1
, "VNIC: online succeeded(%s)\n", rsrc
);
395 (void) mutex_unlock(&cache_lock
);
396 return (RCM_SUCCESS
);
400 vnic_online_vnic(link_cache_t
*node
)
403 dladm_status_t status
;
404 char errmsg
[DLADM_STRSIZE
];
407 * Try to bring on all offlined VNICs
409 for (vnic
= node
->vc_vnic
; vnic
!= NULL
; vnic
= vnic
->dlv_next
) {
410 if (!(vnic
->dlv_flags
& VNIC_OFFLINED
))
413 if ((status
= dladm_vnic_up(dld_handle
, vnic
->dlv_vnic_id
, 0))
414 != DLADM_STATUS_OK
) {
416 * Print a warning message and continue to online
419 rcm_log_message(RCM_WARNING
,
420 _("VNIC: VNIC online failed (%u): %s\n"),
422 dladm_status2str(status
, errmsg
));
424 vnic
->dlv_flags
&= ~VNIC_OFFLINED
;
430 vnic_offline_vnic(link_cache_t
*node
, uint32_t flags
, cache_node_state_t state
)
433 dladm_status_t status
;
434 char errmsg
[DLADM_STRSIZE
];
436 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_offline_vnic (%s %u %u)\n",
437 node
->vc_resource
, flags
, state
);
440 * Try to delete all explicit created VNIC
442 for (vnic
= node
->vc_vnic
; vnic
!= NULL
; vnic
= vnic
->dlv_next
) {
444 if ((status
= dladm_vnic_delete(dld_handle
, vnic
->dlv_vnic_id
,
445 DLADM_OPT_ACTIVE
)) != DLADM_STATUS_OK
) {
446 rcm_log_message(RCM_WARNING
,
447 _("VNIC: VNIC offline failed (%u): %s\n"),
449 dladm_status2str(status
, errmsg
));
450 return (RCM_FAILURE
);
452 rcm_log_message(RCM_TRACE1
,
453 "VNIC: VNIC offline succeeded(%u)\n",
455 vnic
->dlv_flags
|= flags
;
459 node
->vc_state
|= state
;
460 return (RCM_SUCCESS
);
464 * vnic_get_info() - Gather usage information for this resource.
468 vnic_get_info(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
469 char **usagep
, char **errorp
, nvlist_t
*props
, rcm_info_t
**info
)
473 rcm_log_message(RCM_TRACE1
, "VNIC: get_info(%s)\n", rsrc
);
475 (void) mutex_lock(&cache_lock
);
476 node
= cache_lookup(hd
, rsrc
, CACHE_REFRESH
);
478 rcm_log_message(RCM_INFO
,
479 _("VNIC: get_info(%s) unrecognized resource\n"), rsrc
);
480 (void) mutex_unlock(&cache_lock
);
482 return (RCM_FAILURE
);
485 *usagep
= vnic_usage(node
);
486 (void) mutex_unlock(&cache_lock
);
487 if (*usagep
== NULL
) {
488 /* most likely malloc failure */
489 rcm_log_message(RCM_ERROR
,
490 _("VNIC: get_info(%s) malloc failure\n"), rsrc
);
491 (void) mutex_unlock(&cache_lock
);
493 return (RCM_FAILURE
);
496 /* Set client/role properties */
497 (void) nvlist_add_string(props
, RCM_CLIENT_NAME
, "VNIC");
499 rcm_log_message(RCM_TRACE1
, "VNIC: get_info(%s) info = %s\n",
501 return (RCM_SUCCESS
);
505 * vnic_suspend() - Nothing to do, always okay
509 vnic_suspend(rcm_handle_t
*hd
, char *rsrc
, id_t id
, timespec_t
*interval
,
510 uint_t flags
, char **errorp
, rcm_info_t
**info
)
512 rcm_log_message(RCM_TRACE1
, "VNIC: suspend(%s)\n", rsrc
);
513 return (RCM_SUCCESS
);
517 * vnic_resume() - Nothing to do, always okay
521 vnic_resume(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
522 char **errorp
, rcm_info_t
**info
)
524 rcm_log_message(RCM_TRACE1
, "VNIC: resume(%s)\n", rsrc
);
525 return (RCM_SUCCESS
);
529 * vnic_consumer_remove()
531 * Notify VNIC consumers to remove cache.
534 vnic_consumer_remove(rcm_handle_t
*hd
, link_cache_t
*node
, uint_t flags
,
537 dl_vnic_t
*vnic
= NULL
;
538 char rsrc
[RCM_LINK_RESOURCE_MAX
];
539 int ret
= RCM_SUCCESS
;
541 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_consumer_remove (%s)\n",
544 for (vnic
= node
->vc_vnic
; vnic
!= NULL
; vnic
= vnic
->dlv_next
) {
547 * This will only be called when the offline operation
548 * succeeds, so the VNIC consumers must have been offlined
551 assert(vnic
->dlv_flags
& VNIC_CONSUMER_OFFLINED
);
553 (void) snprintf(rsrc
, RCM_LINK_RESOURCE_MAX
, "%s/%u",
554 RCM_LINK_PREFIX
, vnic
->dlv_vnic_id
);
556 ret
= rcm_notify_remove(hd
, rsrc
, flags
, info
);
557 if (ret
!= RCM_SUCCESS
) {
558 rcm_log_message(RCM_WARNING
,
559 _("VNIC: notify remove failed (%s)\n"), rsrc
);
564 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_consumer_remove done\n");
569 * vnic_remove() - remove a resource from cache
573 vnic_remove(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
574 char **errorp
, rcm_info_t
**info
)
579 rcm_log_message(RCM_TRACE1
, "VNIC: remove(%s)\n", rsrc
);
581 (void) mutex_lock(&cache_lock
);
582 node
= cache_lookup(hd
, rsrc
, CACHE_NO_REFRESH
);
584 rcm_log_message(RCM_INFO
,
585 _("VNIC: remove(%s) unrecognized resource\n"), rsrc
);
586 (void) mutex_unlock(&cache_lock
);
588 return (RCM_FAILURE
);
591 /* remove the cached entry for the resource */
593 (void) mutex_unlock(&cache_lock
);
595 rv
= vnic_consumer_remove(hd
, node
, flags
, info
);
601 * vnic_notify_event - Project private implementation to receive new resource
602 * events. It intercepts all new resource events. If the
603 * new resource is a network resource, pass up a notify
604 * for it too. The new resource need not be cached, since
605 * it is done at register again.
609 vnic_notify_event(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
610 char **errorp
, nvlist_t
*nvl
, rcm_info_t
**info
)
612 nvpair_t
*nvp
= NULL
;
613 datalink_id_t linkid
;
615 int rv
= RCM_SUCCESS
;
617 rcm_log_message(RCM_TRACE1
, "VNIC: notify_event(%s)\n", rsrc
);
619 if (strcmp(rsrc
, RCM_RESOURCE_LINK_NEW
) != 0) {
620 vnic_log_err(DATALINK_INVALID_LINKID
, errorp
,
621 "unrecognized event");
623 return (RCM_FAILURE
);
626 /* Update cache to reflect latest VNICs */
627 if (cache_update(hd
) < 0) {
628 vnic_log_err(DATALINK_INVALID_LINKID
, errorp
,
629 "private Cache update failed");
630 return (RCM_FAILURE
);
634 * Try best to recover all configuration.
636 rcm_log_message(RCM_DEBUG
, "VNIC: process_nvlist\n");
637 while ((nvp
= nvlist_next_nvpair(nvl
, nvp
)) != NULL
) {
638 if (strcmp(nvpair_name(nvp
), RCM_NV_LINKID
) != 0)
641 if (nvpair_value_uint64(nvp
, &id64
) != 0) {
642 vnic_log_err(DATALINK_INVALID_LINKID
, errorp
,
643 "cannot get linkid");
648 linkid
= (datalink_id_t
)id64
;
649 if (vnic_configure(hd
, linkid
) != 0) {
650 vnic_log_err(linkid
, errorp
, "configuring failed");
655 /* Notify all VNIC consumers */
656 if (vnic_consumer_notify(hd
, linkid
, errorp
, flags
,
658 vnic_log_err(linkid
, errorp
, "consumer notify failed");
663 rcm_log_message(RCM_TRACE1
,
664 "VNIC: notify_event: link configuration complete\n");
669 * vnic_usage - Determine the usage of a link.
670 * The returned buffer is owned by caller, and the caller
671 * must free it up when done.
674 vnic_usage(link_cache_t
*node
)
681 char errmsg
[DLADM_STRSIZE
];
682 char name
[MAXLINKNAMELEN
];
683 dladm_status_t status
;
686 rcm_log_message(RCM_TRACE2
, "VNIC: usage(%s)\n", node
->vc_resource
);
688 assert(MUTEX_HELD(&cache_lock
));
689 if ((status
= dladm_datalink_id2info(dld_handle
, node
->vc_linkid
, NULL
,
690 NULL
, NULL
, name
, sizeof (name
))) != DLADM_STATUS_OK
) {
691 rcm_log_message(RCM_ERROR
,
692 _("VNIC: usage(%s) get link name failure(%s)\n"),
693 node
->vc_resource
, dladm_status2str(status
, errmsg
));
697 if (node
->vc_state
& CACHE_NODE_OFFLINED
)
698 fmt
= _("%1$s offlined");
700 fmt
= _("%1$s VNICs: ");
702 /* TRANSLATION_NOTE: separator used between VNIC linkids */
706 for (vnic
= node
->vc_vnic
; vnic
!= NULL
; vnic
= vnic
->dlv_next
)
709 /* space for VNICs and separators, plus message */
710 bufsz
= nvnic
* (MAXLINKNAMELEN
+ strlen(sep
)) +
711 strlen(fmt
) + MAXLINKNAMELEN
+ 1;
712 if ((buf
= malloc(bufsz
)) == NULL
) {
713 rcm_log_message(RCM_ERROR
,
714 _("VNIC: usage(%s) malloc failure(%s)\n"),
715 node
->vc_resource
, strerror(errno
));
718 (void) snprintf(buf
, bufsz
, fmt
, name
);
720 if (node
->vc_state
& CACHE_NODE_OFFLINED
) {
721 /* Nothing else to do */
722 rcm_log_message(RCM_TRACE2
, "VNIC: usage (%s) info = %s\n",
723 node
->vc_resource
, buf
);
727 for (vnic
= node
->vc_vnic
; vnic
!= NULL
; vnic
= vnic
->dlv_next
) {
728 rcm_log_message(RCM_DEBUG
, "VNIC:= %u\n", vnic
->dlv_vnic_id
);
730 if ((status
= dladm_datalink_id2info(dld_handle
,
731 vnic
->dlv_vnic_id
, NULL
, NULL
, NULL
, name
, sizeof (name
)))
732 != DLADM_STATUS_OK
) {
733 rcm_log_message(RCM_ERROR
,
734 _("VNIC: usage(%s) get vnic %u name failure(%s)\n"),
735 node
->vc_resource
, vnic
->dlv_vnic_id
,
736 dladm_status2str(status
, errmsg
));
741 (void) strlcat(buf
, name
, bufsz
);
742 if (vnic
->dlv_next
!= NULL
)
743 (void) strlcat(buf
, sep
, bufsz
);
746 rcm_log_message(RCM_TRACE2
, "VNIC: usage (%s) info = %s\n",
747 node
->vc_resource
, buf
);
753 * Cache management routines, all cache management functions should be
754 * be called with cache_lock held.
758 * cache_lookup() - Get a cache node for a resource.
759 * Call with cache lock held.
761 * This ensures that the cache is consistent with the system state and
762 * returns a pointer to the cache element corresponding to the resource.
764 static link_cache_t
*
765 cache_lookup(rcm_handle_t
*hd
, char *rsrc
, char options
)
769 rcm_log_message(RCM_TRACE2
, "VNIC: cache lookup(%s)\n", rsrc
);
771 assert(MUTEX_HELD(&cache_lock
));
772 if (options
& CACHE_REFRESH
) {
773 /* drop lock since update locks cache again */
774 (void) mutex_unlock(&cache_lock
);
775 (void) cache_update(hd
);
776 (void) mutex_lock(&cache_lock
);
779 node
= cache_head
.vc_next
;
780 for (; node
!= &cache_tail
; node
= node
->vc_next
) {
781 if (strcmp(rsrc
, node
->vc_resource
) == 0) {
782 rcm_log_message(RCM_TRACE2
,
783 "VNIC: cache lookup succeeded(%s)\n", rsrc
);
791 * node_free - Free a node from the cache
794 node_free(link_cache_t
*node
)
796 dl_vnic_t
*vnic
, *next
;
799 free(node
->vc_resource
);
801 /* free the VNIC list */
802 for (vnic
= node
->vc_vnic
; vnic
!= NULL
; vnic
= next
) {
803 next
= vnic
->dlv_next
;
811 * cache_insert - Insert a resource node in cache
814 cache_insert(link_cache_t
*node
)
816 assert(MUTEX_HELD(&cache_lock
));
818 /* insert at the head for best performance */
819 node
->vc_next
= cache_head
.vc_next
;
820 node
->vc_prev
= &cache_head
;
822 node
->vc_next
->vc_prev
= node
;
823 node
->vc_prev
->vc_next
= node
;
827 * cache_remove() - Remove a resource node from cache.
830 cache_remove(link_cache_t
*node
)
832 assert(MUTEX_HELD(&cache_lock
));
833 node
->vc_next
->vc_prev
= node
->vc_prev
;
834 node
->vc_prev
->vc_next
= node
->vc_next
;
835 node
->vc_next
= NULL
;
836 node
->vc_prev
= NULL
;
839 typedef struct vnic_update_arg_s
{
845 * vnic_update() - Update physical interface properties
848 vnic_update(dladm_handle_t handle
, datalink_id_t vnicid
, void *arg
)
850 vnic_update_arg_t
*vnic_update_argp
= arg
;
851 rcm_handle_t
*hd
= vnic_update_argp
->hd
;
855 dladm_vnic_attr_t vnic_attr
;
856 dladm_status_t status
;
857 char errmsg
[DLADM_STRSIZE
];
858 boolean_t newnode
= B_FALSE
;
861 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_update(%u)\n", vnicid
);
863 assert(MUTEX_HELD(&cache_lock
));
864 status
= dladm_vnic_info(handle
, vnicid
, &vnic_attr
, DLADM_OPT_ACTIVE
);
865 if (status
!= DLADM_STATUS_OK
) {
866 rcm_log_message(RCM_TRACE1
,
867 "VNIC: vnic_update() cannot get vnic information for "
868 "%u(%s)\n", vnicid
, dladm_status2str(status
, errmsg
));
869 return (DLADM_WALK_CONTINUE
);
872 if (vnic_attr
.va_link_id
== DATALINK_INVALID_LINKID
) {
874 * Skip the etherstubs.
876 rcm_log_message(RCM_TRACE1
,
877 "VNIC: vnic_update(): skip the etherstub %u\n", vnicid
);
878 return (DLADM_WALK_CONTINUE
);
881 rsrc
= malloc(RCM_LINK_RESOURCE_MAX
);
883 rcm_log_message(RCM_ERROR
, _("VNIC: malloc error(%s): %u\n"),
884 strerror(errno
), vnicid
);
888 (void) snprintf(rsrc
, RCM_LINK_RESOURCE_MAX
, "%s/%u",
889 RCM_LINK_PREFIX
, vnic_attr
.va_link_id
);
891 node
= cache_lookup(hd
, rsrc
, CACHE_NO_REFRESH
);
893 rcm_log_message(RCM_DEBUG
,
894 "VNIC: %s already registered (vnicid:%d)\n",
895 rsrc
, vnic_attr
.va_vnic_id
);
898 rcm_log_message(RCM_DEBUG
,
899 "VNIC: %s is a new resource (vnicid:%d)\n",
900 rsrc
, vnic_attr
.va_vnic_id
);
901 if ((node
= calloc(1, sizeof (link_cache_t
))) == NULL
) {
903 rcm_log_message(RCM_ERROR
, _("VNIC: calloc: %s\n"),
908 node
->vc_resource
= rsrc
;
909 node
->vc_vnic
= NULL
;
910 node
->vc_linkid
= vnic_attr
.va_link_id
;
911 node
->vc_state
|= CACHE_NODE_NEW
;
915 for (vnic
= node
->vc_vnic
; vnic
!= NULL
; vnic
= vnic
->dlv_next
) {
916 if (vnic
->dlv_vnic_id
== vnicid
) {
917 vnic
->dlv_flags
&= ~VNIC_STALE
;
923 if ((vnic
= calloc(1, sizeof (dl_vnic_t
))) == NULL
) {
924 rcm_log_message(RCM_ERROR
, _("VNIC: malloc: %s\n"),
932 vnic
->dlv_vnic_id
= vnicid
;
933 vnic
->dlv_next
= node
->vc_vnic
;
934 vnic
->dlv_prev
= NULL
;
935 if (node
->vc_vnic
!= NULL
)
936 node
->vc_vnic
->dlv_prev
= vnic
;
937 node
->vc_vnic
= vnic
;
940 node
->vc_state
&= ~CACHE_NODE_STALE
;
945 rcm_log_message(RCM_TRACE3
, "VNIC: vnic_update: succeeded(%u)\n",
949 vnic_update_argp
->retval
= ret
;
950 return (ret
== 0 ? DLADM_WALK_CONTINUE
: DLADM_WALK_TERMINATE
);
954 * vnic_update_all() - Determine all VNIC links in the system
957 vnic_update_all(rcm_handle_t
*hd
)
959 vnic_update_arg_t arg
= {NULL
, 0};
961 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_update_all\n");
963 assert(MUTEX_HELD(&cache_lock
));
965 (void) dladm_walk_datalink_id(vnic_update
, dld_handle
, &arg
,
966 DATALINK_CLASS_VNIC
, DATALINK_ANY_MEDIATYPE
, DLADM_OPT_ACTIVE
);
971 * cache_update() - Update cache with latest interface info
974 cache_update(rcm_handle_t
*hd
)
976 link_cache_t
*node
, *nnode
;
980 rcm_log_message(RCM_TRACE2
, "VNIC: cache_update\n");
982 (void) mutex_lock(&cache_lock
);
984 /* first we walk the entire cache, marking each entry stale */
985 node
= cache_head
.vc_next
;
986 for (; node
!= &cache_tail
; node
= node
->vc_next
) {
987 node
->vc_state
|= CACHE_NODE_STALE
;
988 for (vnic
= node
->vc_vnic
; vnic
!= NULL
; vnic
= vnic
->dlv_next
)
989 vnic
->dlv_flags
|= VNIC_STALE
;
992 rv
= vnic_update_all(hd
);
995 * Continue to delete all stale nodes from the cache even
996 * vnic_update_all() failed. Unregister link that are not offlined
999 for (node
= cache_head
.vc_next
; node
!= &cache_tail
; node
= nnode
) {
1000 dl_vnic_t
*vnic
, *next
;
1002 for (vnic
= node
->vc_vnic
; vnic
!= NULL
; vnic
= next
) {
1003 next
= vnic
->dlv_next
;
1005 /* clear stale VNICs */
1006 if (vnic
->dlv_flags
& VNIC_STALE
) {
1007 if (vnic
->dlv_prev
!= NULL
)
1008 vnic
->dlv_prev
->dlv_next
= next
;
1010 node
->vc_vnic
= next
;
1013 next
->dlv_prev
= vnic
->dlv_prev
;
1018 nnode
= node
->vc_next
;
1019 if (node
->vc_state
& CACHE_NODE_STALE
) {
1020 (void) rcm_unregister_interest(hd
, node
->vc_resource
,
1022 rcm_log_message(RCM_DEBUG
, "VNIC: unregistered %s\n",
1024 assert(node
->vc_vnic
== NULL
);
1030 if (!(node
->vc_state
& CACHE_NODE_NEW
))
1033 if (rcm_register_interest(hd
, node
->vc_resource
, 0, NULL
) !=
1035 rcm_log_message(RCM_ERROR
,
1036 _("VNIC: failed to register %s\n"),
1040 rcm_log_message(RCM_DEBUG
, "VNIC: registered %s\n",
1042 node
->vc_state
&= ~CACHE_NODE_NEW
;
1046 (void) mutex_unlock(&cache_lock
);
1051 * cache_free() - Empty the cache
1058 rcm_log_message(RCM_TRACE2
, "VNIC: cache_free\n");
1060 (void) mutex_lock(&cache_lock
);
1061 node
= cache_head
.vc_next
;
1062 while (node
!= &cache_tail
) {
1065 node
= cache_head
.vc_next
;
1067 (void) mutex_unlock(&cache_lock
);
1071 * vnic_log_err() - RCM error log wrapper
1074 vnic_log_err(datalink_id_t linkid
, char **errorp
, char *errmsg
)
1076 char link
[MAXLINKNAMELEN
];
1077 char errstr
[DLADM_STRSIZE
];
1078 dladm_status_t status
;
1084 if (linkid
!= DATALINK_INVALID_LINKID
) {
1085 char rsrc
[RCM_LINK_RESOURCE_MAX
];
1087 (void) snprintf(rsrc
, sizeof (rsrc
), "%s/%u",
1088 RCM_LINK_PREFIX
, linkid
);
1090 rcm_log_message(RCM_ERROR
, _("VNIC: %s(%s)\n"), errmsg
, rsrc
);
1091 if ((status
= dladm_datalink_id2info(dld_handle
, linkid
, NULL
,
1092 NULL
, NULL
, link
, sizeof (link
))) != DLADM_STATUS_OK
) {
1093 rcm_log_message(RCM_WARNING
,
1094 _("VNIC: cannot get link name for (%s) %s\n"),
1095 rsrc
, dladm_status2str(status
, errstr
));
1098 rcm_log_message(RCM_ERROR
, _("VNIC: %s\n"), errmsg
);
1101 errfmt
= strlen(link
) > 0 ? _("VNIC: %s(%s)") : _("VNIC: %s");
1102 len
= strlen(errfmt
) + strlen(errmsg
) + MAXLINKNAMELEN
+ 1;
1103 if ((error
= malloc(len
)) != NULL
) {
1104 if (strlen(link
) > 0)
1105 (void) snprintf(error
, len
, errfmt
, errmsg
, link
);
1107 (void) snprintf(error
, len
, errfmt
, errmsg
);
1115 * vnic_consumer_online()
1117 * Notify online to VNIC consumers.
1121 vnic_consumer_online(rcm_handle_t
*hd
, link_cache_t
*node
, char **errorp
,
1122 uint_t flags
, rcm_info_t
**info
)
1125 char rsrc
[RCM_LINK_RESOURCE_MAX
];
1127 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_consumer_online (%s)\n",
1130 for (vnic
= node
->vc_vnic
; vnic
!= NULL
; vnic
= vnic
->dlv_next
) {
1131 if (!(vnic
->dlv_flags
& VNIC_CONSUMER_OFFLINED
))
1134 (void) snprintf(rsrc
, RCM_LINK_RESOURCE_MAX
, "%s/%u",
1135 RCM_LINK_PREFIX
, vnic
->dlv_vnic_id
);
1137 if (rcm_notify_online(hd
, rsrc
, flags
, info
) == RCM_SUCCESS
)
1138 vnic
->dlv_flags
&= ~VNIC_CONSUMER_OFFLINED
;
1141 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_consumer_online done\n");
1145 * vnic_consumer_offline()
1147 * Offline VNIC consumers.
1150 vnic_consumer_offline(rcm_handle_t
*hd
, link_cache_t
*node
, char **errorp
,
1151 uint_t flags
, rcm_info_t
**info
)
1154 char rsrc
[RCM_LINK_RESOURCE_MAX
];
1155 int ret
= RCM_SUCCESS
;
1157 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_consumer_offline (%s)\n",
1160 for (vnic
= node
->vc_vnic
; vnic
!= NULL
; vnic
= vnic
->dlv_next
) {
1161 (void) snprintf(rsrc
, RCM_LINK_RESOURCE_MAX
, "%s/%u",
1162 RCM_LINK_PREFIX
, vnic
->dlv_vnic_id
);
1164 ret
= rcm_request_offline(hd
, rsrc
, flags
, info
);
1165 if (ret
!= RCM_SUCCESS
)
1168 vnic
->dlv_flags
|= VNIC_CONSUMER_OFFLINED
;
1172 vnic_consumer_online(hd
, node
, errorp
, flags
, info
);
1174 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_consumer_offline done\n");
1179 * Send RCM_RESOURCE_LINK_NEW events to other modules about new VNICs.
1180 * Return 0 on success, -1 on failure.
1183 vnic_notify_new_vnic(rcm_handle_t
*hd
, char *rsrc
)
1187 nvlist_t
*nvl
= NULL
;
1191 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_notify_new_vnic (%s)\n", rsrc
);
1193 (void) mutex_lock(&cache_lock
);
1194 if ((node
= cache_lookup(hd
, rsrc
, CACHE_REFRESH
)) == NULL
) {
1195 (void) mutex_unlock(&cache_lock
);
1199 if (nvlist_alloc(&nvl
, 0, 0) != 0) {
1200 (void) mutex_unlock(&cache_lock
);
1201 rcm_log_message(RCM_WARNING
,
1202 _("VNIC: failed to allocate nvlist\n"));
1206 for (vnic
= node
->vc_vnic
; vnic
!= NULL
; vnic
= vnic
->dlv_next
) {
1207 rcm_log_message(RCM_TRACE2
,
1208 "VNIC: vnic_notify_new_vnic add (%u)\n", vnic
->dlv_vnic_id
);
1210 id
= vnic
->dlv_vnic_id
;
1211 if (nvlist_add_uint64(nvl
, RCM_NV_LINKID
, id
) != 0) {
1212 rcm_log_message(RCM_ERROR
,
1213 _("VNIC: failed to construct nvlist\n"));
1214 (void) mutex_unlock(&cache_lock
);
1218 (void) mutex_unlock(&cache_lock
);
1220 if (rcm_notify_event(hd
, RCM_RESOURCE_LINK_NEW
, 0, nvl
, NULL
) !=
1222 rcm_log_message(RCM_ERROR
,
1223 _("VNIC: failed to notify %s event for %s\n"),
1224 RCM_RESOURCE_LINK_NEW
, node
->vc_resource
);
1235 * vnic_consumer_notify() - Notify consumers of VNICs coming back online.
1238 vnic_consumer_notify(rcm_handle_t
*hd
, datalink_id_t linkid
, char **errorp
,
1239 uint_t flags
, rcm_info_t
**info
)
1241 char rsrc
[RCM_LINK_RESOURCE_MAX
];
1244 /* Check for the interface in the cache */
1245 (void) snprintf(rsrc
, RCM_LINK_RESOURCE_MAX
, "%s/%u", RCM_LINK_PREFIX
,
1248 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_consumer_notify(%s)\n", rsrc
);
1251 * Inform IP consumers of the new link.
1253 if (vnic_notify_new_vnic(hd
, rsrc
) != 0) {
1254 (void) mutex_lock(&cache_lock
);
1255 if ((node
= cache_lookup(hd
, rsrc
, CACHE_NO_REFRESH
)) != NULL
) {
1256 (void) vnic_offline_vnic(node
, VNIC_STALE
,
1259 (void) mutex_unlock(&cache_lock
);
1260 rcm_log_message(RCM_TRACE2
,
1261 "VNIC: vnic_notify_new_vnic failed(%s)\n", rsrc
);
1265 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_consumer_notify succeeded\n");
1269 typedef struct vnic_up_arg_s
{
1270 datalink_id_t linkid
;
1275 vnic_up(dladm_handle_t handle
, datalink_id_t vnicid
, void *arg
)
1277 vnic_up_arg_t
*vnic_up_argp
= arg
;
1278 dladm_status_t status
;
1279 dladm_vnic_attr_t vnic_attr
;
1280 char errmsg
[DLADM_STRSIZE
];
1282 status
= dladm_vnic_info(handle
, vnicid
, &vnic_attr
, DLADM_OPT_PERSIST
);
1283 if (status
!= DLADM_STATUS_OK
) {
1284 rcm_log_message(RCM_TRACE1
,
1285 "VNIC: vnic_up(): cannot get information for VNIC %u "
1286 "(%s)\n", vnicid
, dladm_status2str(status
, errmsg
));
1287 return (DLADM_WALK_CONTINUE
);
1290 if (vnic_attr
.va_link_id
!= vnic_up_argp
->linkid
)
1291 return (DLADM_WALK_CONTINUE
);
1293 rcm_log_message(RCM_TRACE3
, "VNIC: vnic_up(%u)\n", vnicid
);
1294 if ((status
= dladm_vnic_up(handle
, vnicid
, 0)) == DLADM_STATUS_OK
)
1295 return (DLADM_WALK_CONTINUE
);
1298 * Prompt the warning message and continue to UP other VNICs.
1300 rcm_log_message(RCM_WARNING
,
1301 _("VNIC: VNIC up failed (%u): %s\n"),
1302 vnicid
, dladm_status2str(status
, errmsg
));
1304 vnic_up_argp
->retval
= -1;
1305 return (DLADM_WALK_CONTINUE
);
1309 * vnic_configure() - Configure VNICs over a physical link after it attaches
1312 vnic_configure(rcm_handle_t
*hd
, datalink_id_t linkid
)
1314 char rsrc
[RCM_LINK_RESOURCE_MAX
];
1316 vnic_up_arg_t arg
= {DATALINK_INVALID_LINKID
, 0};
1318 /* Check for the VNICs in the cache */
1319 (void) snprintf(rsrc
, sizeof (rsrc
), "%s/%u", RCM_LINK_PREFIX
, linkid
);
1321 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_configure(%s)\n", rsrc
);
1323 /* Check if the link is new or was previously offlined */
1324 (void) mutex_lock(&cache_lock
);
1325 if (((node
= cache_lookup(hd
, rsrc
, CACHE_REFRESH
)) != NULL
) &&
1326 (!(node
->vc_state
& CACHE_NODE_OFFLINED
))) {
1327 rcm_log_message(RCM_TRACE2
,
1328 "VNIC: Skipping configured interface(%s)\n", rsrc
);
1329 (void) mutex_unlock(&cache_lock
);
1332 (void) mutex_unlock(&cache_lock
);
1334 arg
.linkid
= linkid
;
1335 (void) dladm_walk_datalink_id(vnic_up
, dld_handle
, &arg
,
1336 DATALINK_CLASS_VNIC
, DATALINK_ANY_MEDIATYPE
, DLADM_OPT_PERSIST
);
1338 if (arg
.retval
== 0) {
1339 rcm_log_message(RCM_TRACE2
,
1340 "VNIC: vnic_configure succeeded(%s)\n", rsrc
);
1342 return (arg
.retval
);