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>
46 #define _(x) gettext(x)
48 /* Some generic well-knowns and defaults used in this module */
49 #define RCM_LINK_PREFIX "SUNW_datalink" /* RCM datalink name prefix */
50 #define RCM_LINK_RESOURCE_MAX (13 + LINKID_STR_WIDTH)
55 VNIC_CONSUMER_OFFLINED
= 0x2,
59 /* link representation */
60 typedef struct dl_vnic
{
61 struct dl_vnic
*dlv_next
; /* next VNIC on the same link */
62 struct dl_vnic
*dlv_prev
; /* prev VNIC on the same link */
63 datalink_id_t dlv_vnic_id
;
64 vnic_flag_t dlv_flags
; /* VNIC link flags */
67 /* VNIC Cache state flags */
69 CACHE_NODE_STALE
= 0x1, /* stale cached data */
70 CACHE_NODE_NEW
= 0x2, /* new cached nodes */
71 CACHE_NODE_OFFLINED
= 0x4 /* nodes offlined */
74 /* Network Cache lookup options */
75 #define CACHE_NO_REFRESH 0x1 /* cache refresh not needed */
76 #define CACHE_REFRESH 0x2 /* refresh cache */
79 typedef struct link_cache
{
80 struct link_cache
*vc_next
; /* next cached resource */
81 struct link_cache
*vc_prev
; /* prev cached resource */
82 char *vc_resource
; /* resource name */
83 datalink_id_t vc_linkid
; /* linkid */
84 dl_vnic_t
*vc_vnic
; /* VNIC list on this link */
85 cache_node_state_t vc_state
; /* cache state flags */
89 * Global cache for network VNICs
91 static link_cache_t cache_head
;
92 static link_cache_t cache_tail
;
93 static mutex_t cache_lock
;
94 static int events_registered
= 0;
96 static dladm_handle_t dld_handle
= NULL
;
99 * RCM module interface prototypes
101 static int vnic_register(rcm_handle_t
*);
102 static int vnic_unregister(rcm_handle_t
*);
103 static int vnic_get_info(rcm_handle_t
*, char *, id_t
, uint_t
,
104 char **, char **, nvlist_t
*, rcm_info_t
**);
105 static int vnic_suspend(rcm_handle_t
*, char *, id_t
,
106 timespec_t
*, uint_t
, char **, rcm_info_t
**);
107 static int vnic_resume(rcm_handle_t
*, char *, id_t
, uint_t
,
108 char **, rcm_info_t
**);
109 static int vnic_offline(rcm_handle_t
*, char *, id_t
, uint_t
,
110 char **, rcm_info_t
**);
111 static int vnic_undo_offline(rcm_handle_t
*, char *, id_t
, uint_t
,
112 char **, rcm_info_t
**);
113 static int vnic_remove(rcm_handle_t
*, char *, id_t
, uint_t
,
114 char **, rcm_info_t
**);
115 static int vnic_notify_event(rcm_handle_t
*, char *, id_t
, uint_t
,
116 char **, nvlist_t
*, rcm_info_t
**);
117 static int vnic_configure(rcm_handle_t
*, datalink_id_t
);
119 /* Module private routines */
120 static void cache_free();
121 static int cache_update(rcm_handle_t
*);
122 static void cache_remove(link_cache_t
*);
123 static void node_free(link_cache_t
*);
124 static void cache_insert(link_cache_t
*);
125 static link_cache_t
*cache_lookup(rcm_handle_t
*, char *, char);
126 static int vnic_consumer_offline(rcm_handle_t
*, link_cache_t
*,
127 char **, uint_t
, rcm_info_t
**);
128 static void vnic_consumer_online(rcm_handle_t
*, link_cache_t
*,
129 char **, uint_t
, rcm_info_t
**);
130 static int vnic_offline_vnic(link_cache_t
*, uint32_t,
132 static void vnic_online_vnic(link_cache_t
*);
133 static char *vnic_usage(link_cache_t
*);
134 static void vnic_log_err(datalink_id_t
, char **, char *);
135 static int vnic_consumer_notify(rcm_handle_t
*, datalink_id_t
,
136 char **, uint_t
, rcm_info_t
**);
138 /* Module-Private data */
139 static struct rcm_mod_ops vnic_ops
=
156 * rcm_mod_init() - Update registrations, and return the ops structure.
161 char errmsg
[DLADM_STRSIZE
];
162 dladm_status_t status
;
164 rcm_log_message(RCM_TRACE1
, "VNIC: mod_init\n");
166 cache_head
.vc_next
= &cache_tail
;
167 cache_head
.vc_prev
= NULL
;
168 cache_tail
.vc_prev
= &cache_head
;
169 cache_tail
.vc_next
= NULL
;
170 (void) mutex_init(&cache_lock
, 0, NULL
);
172 if ((status
= dladm_open(&dld_handle
)) != DLADM_STATUS_OK
) {
173 rcm_log_message(RCM_WARNING
,
174 "VNIC: mod_init failed: cannot open datalink handle: %s\n",
175 dladm_status2str(status
, errmsg
));
179 /* Return the ops vectors */
184 * rcm_mod_info() - Return a string describing this module.
189 rcm_log_message(RCM_TRACE1
, "VNIC: mod_info\n");
191 return ("VNIC module");
195 * rcm_mod_fini() - Destroy the network VNIC cache.
200 rcm_log_message(RCM_TRACE1
, "VNIC: mod_fini\n");
203 * Note that vnic_unregister() does not seem to be called anywhere,
204 * therefore we free the cache nodes here. In theory we should call
205 * rcm_register_interest() for each node before we free it, the
206 * framework does not provide the rcm_handle to allow us to do so.
209 (void) mutex_destroy(&cache_lock
);
211 dladm_close(dld_handle
);
212 return (RCM_SUCCESS
);
216 * vnic_register() - Make sure the cache is properly sync'ed, and its
217 * registrations are in order.
220 vnic_register(rcm_handle_t
*hd
)
222 rcm_log_message(RCM_TRACE1
, "VNIC: register\n");
224 if (cache_update(hd
) < 0)
225 return (RCM_FAILURE
);
228 * Need to register interest in all new resources
229 * getting attached, so we get attach event notifications
231 if (!events_registered
) {
232 if (rcm_register_event(hd
, RCM_RESOURCE_LINK_NEW
, 0, NULL
)
234 rcm_log_message(RCM_ERROR
,
235 _("VNIC: failed to register %s\n"),
236 RCM_RESOURCE_LINK_NEW
);
237 return (RCM_FAILURE
);
239 rcm_log_message(RCM_DEBUG
, "VNIC: registered %s\n",
240 RCM_RESOURCE_LINK_NEW
);
245 return (RCM_SUCCESS
);
249 * vnic_unregister() - Walk the cache, unregistering all the networks.
252 vnic_unregister(rcm_handle_t
*hd
)
256 rcm_log_message(RCM_TRACE1
, "VNIC: unregister\n");
258 /* Walk the cache, unregistering everything */
259 (void) mutex_lock(&cache_lock
);
260 node
= cache_head
.vc_next
;
261 while (node
!= &cache_tail
) {
262 if (rcm_unregister_interest(hd
, node
->vc_resource
, 0)
264 rcm_log_message(RCM_ERROR
,
265 _("VNIC: failed to unregister %s\n"),
267 (void) mutex_unlock(&cache_lock
);
268 return (RCM_FAILURE
);
272 node
= cache_head
.vc_next
;
274 (void) mutex_unlock(&cache_lock
);
277 * Unregister interest in all new resources
279 if (events_registered
) {
280 if (rcm_unregister_event(hd
, RCM_RESOURCE_LINK_NEW
, 0)
282 rcm_log_message(RCM_ERROR
,
283 _("VNIC: failed to unregister %s\n"),
284 RCM_RESOURCE_LINK_NEW
);
285 return (RCM_FAILURE
);
287 rcm_log_message(RCM_DEBUG
, "VNIC: unregistered %s\n",
288 RCM_RESOURCE_LINK_NEW
);
293 return (RCM_SUCCESS
);
297 * vnic_offline() - Offline VNICs on a specific node.
300 vnic_offline(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
301 char **errorp
, rcm_info_t
**info
)
305 rcm_log_message(RCM_TRACE1
, "VNIC: offline(%s)\n", rsrc
);
307 /* Lock the cache and lookup the resource */
308 (void) mutex_lock(&cache_lock
);
309 node
= cache_lookup(hd
, rsrc
, CACHE_REFRESH
);
311 /* should not happen because the resource is registered. */
312 vnic_log_err(DATALINK_INVALID_LINKID
, errorp
,
313 "unrecognized resource");
314 (void) mutex_unlock(&cache_lock
);
315 return (RCM_SUCCESS
);
319 * Inform consumers (IP interfaces) of associated VNICs to be offlined
321 if (vnic_consumer_offline(hd
, node
, errorp
, flags
, info
) ==
323 rcm_log_message(RCM_DEBUG
,
324 "VNIC: consumers agreed on offline\n");
326 vnic_log_err(node
->vc_linkid
, errorp
,
327 "consumers failed to offline");
328 (void) mutex_unlock(&cache_lock
);
329 return (RCM_FAILURE
);
332 /* Check if it's a query */
333 if (flags
& RCM_QUERY
) {
334 rcm_log_message(RCM_TRACE1
,
335 "VNIC: offline query succeeded(%s)\n", rsrc
);
336 (void) mutex_unlock(&cache_lock
);
337 return (RCM_SUCCESS
);
340 if (vnic_offline_vnic(node
, VNIC_OFFLINED
, CACHE_NODE_OFFLINED
) !=
342 vnic_online_vnic(node
);
343 vnic_log_err(node
->vc_linkid
, errorp
, "offline failed");
344 (void) mutex_unlock(&cache_lock
);
345 return (RCM_FAILURE
);
348 rcm_log_message(RCM_TRACE1
, "VNIC: Offline succeeded(%s)\n", rsrc
);
349 (void) mutex_unlock(&cache_lock
);
350 return (RCM_SUCCESS
);
354 * vnic_undo_offline() - Undo offline of a previously offlined node.
358 vnic_undo_offline(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
359 char **errorp
, rcm_info_t
**info
)
363 rcm_log_message(RCM_TRACE1
, "VNIC: online(%s)\n", rsrc
);
365 (void) mutex_lock(&cache_lock
);
366 node
= cache_lookup(hd
, rsrc
, CACHE_NO_REFRESH
);
368 vnic_log_err(DATALINK_INVALID_LINKID
, errorp
, "no such link");
369 (void) mutex_unlock(&cache_lock
);
371 return (RCM_FAILURE
);
374 /* Check if no attempt should be made to online the link here */
375 if (!(node
->vc_state
& CACHE_NODE_OFFLINED
)) {
376 vnic_log_err(node
->vc_linkid
, errorp
, "link not offlined");
377 (void) mutex_unlock(&cache_lock
);
379 return (RCM_SUCCESS
);
382 vnic_online_vnic(node
);
385 * Inform IP interfaces on associated VNICs to be onlined
387 vnic_consumer_online(hd
, node
, errorp
, flags
, info
);
389 node
->vc_state
&= ~CACHE_NODE_OFFLINED
;
390 rcm_log_message(RCM_TRACE1
, "VNIC: online succeeded(%s)\n", rsrc
);
391 (void) mutex_unlock(&cache_lock
);
392 return (RCM_SUCCESS
);
396 vnic_online_vnic(link_cache_t
*node
)
399 dladm_status_t status
;
400 char errmsg
[DLADM_STRSIZE
];
403 * Try to bring on all offlined VNICs
405 for (vnic
= node
->vc_vnic
; vnic
!= NULL
; vnic
= vnic
->dlv_next
) {
406 if (!(vnic
->dlv_flags
& VNIC_OFFLINED
))
409 if ((status
= dladm_vnic_up(dld_handle
, vnic
->dlv_vnic_id
, 0))
410 != DLADM_STATUS_OK
) {
412 * Print a warning message and continue to online
415 rcm_log_message(RCM_WARNING
,
416 _("VNIC: VNIC online failed (%u): %s\n"),
418 dladm_status2str(status
, errmsg
));
420 vnic
->dlv_flags
&= ~VNIC_OFFLINED
;
426 vnic_offline_vnic(link_cache_t
*node
, uint32_t flags
, cache_node_state_t state
)
429 dladm_status_t status
;
430 char errmsg
[DLADM_STRSIZE
];
432 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_offline_vnic (%s %u %u)\n",
433 node
->vc_resource
, flags
, state
);
436 * Try to delete all explicit created VNIC
438 for (vnic
= node
->vc_vnic
; vnic
!= NULL
; vnic
= vnic
->dlv_next
) {
440 if ((status
= dladm_vnic_delete(dld_handle
, vnic
->dlv_vnic_id
,
441 DLADM_OPT_ACTIVE
)) != DLADM_STATUS_OK
) {
442 rcm_log_message(RCM_WARNING
,
443 _("VNIC: VNIC offline failed (%u): %s\n"),
445 dladm_status2str(status
, errmsg
));
446 return (RCM_FAILURE
);
448 rcm_log_message(RCM_TRACE1
,
449 "VNIC: VNIC offline succeeded(%u)\n",
451 vnic
->dlv_flags
|= flags
;
455 node
->vc_state
|= state
;
456 return (RCM_SUCCESS
);
460 * vnic_get_info() - Gather usage information for this resource.
464 vnic_get_info(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
465 char **usagep
, char **errorp
, nvlist_t
*props
, rcm_info_t
**info
)
469 rcm_log_message(RCM_TRACE1
, "VNIC: get_info(%s)\n", rsrc
);
471 (void) mutex_lock(&cache_lock
);
472 node
= cache_lookup(hd
, rsrc
, CACHE_REFRESH
);
474 rcm_log_message(RCM_INFO
,
475 _("VNIC: get_info(%s) unrecognized resource\n"), rsrc
);
476 (void) mutex_unlock(&cache_lock
);
478 return (RCM_FAILURE
);
481 *usagep
= vnic_usage(node
);
482 (void) mutex_unlock(&cache_lock
);
483 if (*usagep
== NULL
) {
484 /* most likely malloc failure */
485 rcm_log_message(RCM_ERROR
,
486 _("VNIC: get_info(%s) malloc failure\n"), rsrc
);
487 (void) mutex_unlock(&cache_lock
);
489 return (RCM_FAILURE
);
492 /* Set client/role properties */
493 (void) nvlist_add_string(props
, RCM_CLIENT_NAME
, "VNIC");
495 rcm_log_message(RCM_TRACE1
, "VNIC: get_info(%s) info = %s\n",
497 return (RCM_SUCCESS
);
501 * vnic_suspend() - Nothing to do, always okay
505 vnic_suspend(rcm_handle_t
*hd
, char *rsrc
, id_t id
, timespec_t
*interval
,
506 uint_t flags
, char **errorp
, rcm_info_t
**info
)
508 rcm_log_message(RCM_TRACE1
, "VNIC: suspend(%s)\n", rsrc
);
509 return (RCM_SUCCESS
);
513 * vnic_resume() - Nothing to do, always okay
517 vnic_resume(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
518 char **errorp
, rcm_info_t
**info
)
520 rcm_log_message(RCM_TRACE1
, "VNIC: resume(%s)\n", rsrc
);
521 return (RCM_SUCCESS
);
525 * vnic_consumer_remove()
527 * Notify VNIC consumers to remove cache.
530 vnic_consumer_remove(rcm_handle_t
*hd
, link_cache_t
*node
, uint_t flags
,
533 dl_vnic_t
*vnic
= NULL
;
534 char rsrc
[RCM_LINK_RESOURCE_MAX
];
535 int ret
= RCM_SUCCESS
;
537 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_consumer_remove (%s)\n",
540 for (vnic
= node
->vc_vnic
; vnic
!= NULL
; vnic
= vnic
->dlv_next
) {
543 * This will only be called when the offline operation
544 * succeeds, so the VNIC consumers must have been offlined
547 assert(vnic
->dlv_flags
& VNIC_CONSUMER_OFFLINED
);
549 (void) snprintf(rsrc
, RCM_LINK_RESOURCE_MAX
, "%s/%u",
550 RCM_LINK_PREFIX
, vnic
->dlv_vnic_id
);
552 ret
= rcm_notify_remove(hd
, rsrc
, flags
, info
);
553 if (ret
!= RCM_SUCCESS
) {
554 rcm_log_message(RCM_WARNING
,
555 _("VNIC: notify remove failed (%s)\n"), rsrc
);
560 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_consumer_remove done\n");
565 * vnic_remove() - remove a resource from cache
569 vnic_remove(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
570 char **errorp
, rcm_info_t
**info
)
575 rcm_log_message(RCM_TRACE1
, "VNIC: remove(%s)\n", rsrc
);
577 (void) mutex_lock(&cache_lock
);
578 node
= cache_lookup(hd
, rsrc
, CACHE_NO_REFRESH
);
580 rcm_log_message(RCM_INFO
,
581 _("VNIC: remove(%s) unrecognized resource\n"), rsrc
);
582 (void) mutex_unlock(&cache_lock
);
584 return (RCM_FAILURE
);
587 /* remove the cached entry for the resource */
589 (void) mutex_unlock(&cache_lock
);
591 rv
= vnic_consumer_remove(hd
, node
, flags
, info
);
597 * vnic_notify_event - Project private implementation to receive new resource
598 * events. It intercepts all new resource events. If the
599 * new resource is a network resource, pass up a notify
600 * for it too. The new resource need not be cached, since
601 * it is done at register again.
605 vnic_notify_event(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
606 char **errorp
, nvlist_t
*nvl
, rcm_info_t
**info
)
608 nvpair_t
*nvp
= NULL
;
609 datalink_id_t linkid
;
611 int rv
= RCM_SUCCESS
;
613 rcm_log_message(RCM_TRACE1
, "VNIC: notify_event(%s)\n", rsrc
);
615 if (strcmp(rsrc
, RCM_RESOURCE_LINK_NEW
) != 0) {
616 vnic_log_err(DATALINK_INVALID_LINKID
, errorp
,
617 "unrecognized event");
619 return (RCM_FAILURE
);
622 /* Update cache to reflect latest VNICs */
623 if (cache_update(hd
) < 0) {
624 vnic_log_err(DATALINK_INVALID_LINKID
, errorp
,
625 "private Cache update failed");
626 return (RCM_FAILURE
);
630 * Try best to recover all configuration.
632 rcm_log_message(RCM_DEBUG
, "VNIC: process_nvlist\n");
633 while ((nvp
= nvlist_next_nvpair(nvl
, nvp
)) != NULL
) {
634 if (strcmp(nvpair_name(nvp
), RCM_NV_LINKID
) != 0)
637 if (nvpair_value_uint64(nvp
, &id64
) != 0) {
638 vnic_log_err(DATALINK_INVALID_LINKID
, errorp
,
639 "cannot get linkid");
644 linkid
= (datalink_id_t
)id64
;
645 if (vnic_configure(hd
, linkid
) != 0) {
646 vnic_log_err(linkid
, errorp
, "configuring failed");
651 /* Notify all VNIC consumers */
652 if (vnic_consumer_notify(hd
, linkid
, errorp
, flags
,
654 vnic_log_err(linkid
, errorp
, "consumer notify failed");
659 rcm_log_message(RCM_TRACE1
,
660 "VNIC: notify_event: link configuration complete\n");
665 * vnic_usage - Determine the usage of a link.
666 * The returned buffer is owned by caller, and the caller
667 * must free it up when done.
670 vnic_usage(link_cache_t
*node
)
677 char errmsg
[DLADM_STRSIZE
];
678 char name
[MAXLINKNAMELEN
];
679 dladm_status_t status
;
682 rcm_log_message(RCM_TRACE2
, "VNIC: usage(%s)\n", node
->vc_resource
);
684 assert(MUTEX_HELD(&cache_lock
));
685 if ((status
= dladm_datalink_id2info(dld_handle
, node
->vc_linkid
, NULL
,
686 NULL
, NULL
, name
, sizeof (name
))) != DLADM_STATUS_OK
) {
687 rcm_log_message(RCM_ERROR
,
688 _("VNIC: usage(%s) get link name failure(%s)\n"),
689 node
->vc_resource
, dladm_status2str(status
, errmsg
));
693 if (node
->vc_state
& CACHE_NODE_OFFLINED
)
694 fmt
= _("%1$s offlined");
696 fmt
= _("%1$s VNICs: ");
698 /* TRANSLATION_NOTE: separator used between VNIC linkids */
702 for (vnic
= node
->vc_vnic
; vnic
!= NULL
; vnic
= vnic
->dlv_next
)
705 /* space for VNICs and separators, plus message */
706 bufsz
= nvnic
* (MAXLINKNAMELEN
+ strlen(sep
)) +
707 strlen(fmt
) + MAXLINKNAMELEN
+ 1;
708 if ((buf
= malloc(bufsz
)) == NULL
) {
709 rcm_log_message(RCM_ERROR
,
710 _("VNIC: usage(%s) malloc failure(%s)\n"),
711 node
->vc_resource
, strerror(errno
));
714 (void) snprintf(buf
, bufsz
, fmt
, name
);
716 if (node
->vc_state
& CACHE_NODE_OFFLINED
) {
717 /* Nothing else to do */
718 rcm_log_message(RCM_TRACE2
, "VNIC: usage (%s) info = %s\n",
719 node
->vc_resource
, buf
);
723 for (vnic
= node
->vc_vnic
; vnic
!= NULL
; vnic
= vnic
->dlv_next
) {
724 rcm_log_message(RCM_DEBUG
, "VNIC:= %u\n", vnic
->dlv_vnic_id
);
726 if ((status
= dladm_datalink_id2info(dld_handle
,
727 vnic
->dlv_vnic_id
, NULL
, NULL
, NULL
, name
, sizeof (name
)))
728 != DLADM_STATUS_OK
) {
729 rcm_log_message(RCM_ERROR
,
730 _("VNIC: usage(%s) get vnic %u name failure(%s)\n"),
731 node
->vc_resource
, vnic
->dlv_vnic_id
,
732 dladm_status2str(status
, errmsg
));
737 (void) strlcat(buf
, name
, bufsz
);
738 if (vnic
->dlv_next
!= NULL
)
739 (void) strlcat(buf
, sep
, bufsz
);
742 rcm_log_message(RCM_TRACE2
, "VNIC: usage (%s) info = %s\n",
743 node
->vc_resource
, buf
);
749 * Cache management routines, all cache management functions should be
750 * be called with cache_lock held.
754 * cache_lookup() - Get a cache node for a resource.
755 * Call with cache lock held.
757 * This ensures that the cache is consistent with the system state and
758 * returns a pointer to the cache element corresponding to the resource.
760 static link_cache_t
*
761 cache_lookup(rcm_handle_t
*hd
, char *rsrc
, char options
)
765 rcm_log_message(RCM_TRACE2
, "VNIC: cache lookup(%s)\n", rsrc
);
767 assert(MUTEX_HELD(&cache_lock
));
768 if (options
& CACHE_REFRESH
) {
769 /* drop lock since update locks cache again */
770 (void) mutex_unlock(&cache_lock
);
771 (void) cache_update(hd
);
772 (void) mutex_lock(&cache_lock
);
775 node
= cache_head
.vc_next
;
776 for (; node
!= &cache_tail
; node
= node
->vc_next
) {
777 if (strcmp(rsrc
, node
->vc_resource
) == 0) {
778 rcm_log_message(RCM_TRACE2
,
779 "VNIC: cache lookup succeeded(%s)\n", rsrc
);
787 * node_free - Free a node from the cache
790 node_free(link_cache_t
*node
)
792 dl_vnic_t
*vnic
, *next
;
795 free(node
->vc_resource
);
797 /* free the VNIC list */
798 for (vnic
= node
->vc_vnic
; vnic
!= NULL
; vnic
= next
) {
799 next
= vnic
->dlv_next
;
807 * cache_insert - Insert a resource node in cache
810 cache_insert(link_cache_t
*node
)
812 assert(MUTEX_HELD(&cache_lock
));
814 /* insert at the head for best performance */
815 node
->vc_next
= cache_head
.vc_next
;
816 node
->vc_prev
= &cache_head
;
818 node
->vc_next
->vc_prev
= node
;
819 node
->vc_prev
->vc_next
= node
;
823 * cache_remove() - Remove a resource node from cache.
826 cache_remove(link_cache_t
*node
)
828 assert(MUTEX_HELD(&cache_lock
));
829 node
->vc_next
->vc_prev
= node
->vc_prev
;
830 node
->vc_prev
->vc_next
= node
->vc_next
;
831 node
->vc_next
= NULL
;
832 node
->vc_prev
= NULL
;
835 typedef struct vnic_update_arg_s
{
841 * vnic_update() - Update physical interface properties
844 vnic_update(dladm_handle_t handle
, datalink_id_t vnicid
, void *arg
)
846 vnic_update_arg_t
*vnic_update_argp
= arg
;
847 rcm_handle_t
*hd
= vnic_update_argp
->hd
;
851 dladm_vnic_attr_t vnic_attr
;
852 dladm_status_t status
;
853 char errmsg
[DLADM_STRSIZE
];
854 boolean_t newnode
= B_FALSE
;
857 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_update(%u)\n", vnicid
);
859 assert(MUTEX_HELD(&cache_lock
));
860 status
= dladm_vnic_info(handle
, vnicid
, &vnic_attr
, DLADM_OPT_ACTIVE
);
861 if (status
!= DLADM_STATUS_OK
) {
862 rcm_log_message(RCM_TRACE1
,
863 "VNIC: vnic_update() cannot get vnic information for "
864 "%u(%s)\n", vnicid
, dladm_status2str(status
, errmsg
));
865 return (DLADM_WALK_CONTINUE
);
868 if (vnic_attr
.va_link_id
== DATALINK_INVALID_LINKID
) {
870 * Skip the etherstubs.
872 rcm_log_message(RCM_TRACE1
,
873 "VNIC: vnic_update(): skip the etherstub %u\n", vnicid
);
874 return (DLADM_WALK_CONTINUE
);
877 rsrc
= malloc(RCM_LINK_RESOURCE_MAX
);
879 rcm_log_message(RCM_ERROR
, _("VNIC: malloc error(%s): %u\n"),
880 strerror(errno
), vnicid
);
884 (void) snprintf(rsrc
, RCM_LINK_RESOURCE_MAX
, "%s/%u",
885 RCM_LINK_PREFIX
, vnic_attr
.va_link_id
);
887 node
= cache_lookup(hd
, rsrc
, CACHE_NO_REFRESH
);
889 rcm_log_message(RCM_DEBUG
,
890 "VNIC: %s already registered (vnicid:%d)\n",
891 rsrc
, vnic_attr
.va_vnic_id
);
894 rcm_log_message(RCM_DEBUG
,
895 "VNIC: %s is a new resource (vnicid:%d)\n",
896 rsrc
, vnic_attr
.va_vnic_id
);
897 if ((node
= calloc(1, sizeof (link_cache_t
))) == NULL
) {
899 rcm_log_message(RCM_ERROR
, _("VNIC: calloc: %s\n"),
904 node
->vc_resource
= rsrc
;
905 node
->vc_vnic
= NULL
;
906 node
->vc_linkid
= vnic_attr
.va_link_id
;
907 node
->vc_state
|= CACHE_NODE_NEW
;
911 for (vnic
= node
->vc_vnic
; vnic
!= NULL
; vnic
= vnic
->dlv_next
) {
912 if (vnic
->dlv_vnic_id
== vnicid
) {
913 vnic
->dlv_flags
&= ~VNIC_STALE
;
919 if ((vnic
= calloc(1, sizeof (dl_vnic_t
))) == NULL
) {
920 rcm_log_message(RCM_ERROR
, _("VNIC: malloc: %s\n"),
928 vnic
->dlv_vnic_id
= vnicid
;
929 vnic
->dlv_next
= node
->vc_vnic
;
930 vnic
->dlv_prev
= NULL
;
931 if (node
->vc_vnic
!= NULL
)
932 node
->vc_vnic
->dlv_prev
= vnic
;
933 node
->vc_vnic
= vnic
;
936 node
->vc_state
&= ~CACHE_NODE_STALE
;
941 rcm_log_message(RCM_TRACE3
, "VNIC: vnic_update: succeeded(%u)\n",
945 vnic_update_argp
->retval
= ret
;
946 return (ret
== 0 ? DLADM_WALK_CONTINUE
: DLADM_WALK_TERMINATE
);
950 * vnic_update_all() - Determine all VNIC links in the system
953 vnic_update_all(rcm_handle_t
*hd
)
955 vnic_update_arg_t arg
= {NULL
, 0};
957 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_update_all\n");
959 assert(MUTEX_HELD(&cache_lock
));
961 (void) dladm_walk_datalink_id(vnic_update
, dld_handle
, &arg
,
962 DATALINK_CLASS_VNIC
, DATALINK_ANY_MEDIATYPE
, DLADM_OPT_ACTIVE
);
967 * cache_update() - Update cache with latest interface info
970 cache_update(rcm_handle_t
*hd
)
972 link_cache_t
*node
, *nnode
;
976 rcm_log_message(RCM_TRACE2
, "VNIC: cache_update\n");
978 (void) mutex_lock(&cache_lock
);
980 /* first we walk the entire cache, marking each entry stale */
981 node
= cache_head
.vc_next
;
982 for (; node
!= &cache_tail
; node
= node
->vc_next
) {
983 node
->vc_state
|= CACHE_NODE_STALE
;
984 for (vnic
= node
->vc_vnic
; vnic
!= NULL
; vnic
= vnic
->dlv_next
)
985 vnic
->dlv_flags
|= VNIC_STALE
;
988 rv
= vnic_update_all(hd
);
991 * Continue to delete all stale nodes from the cache even
992 * vnic_update_all() failed. Unregister link that are not offlined
995 for (node
= cache_head
.vc_next
; node
!= &cache_tail
; node
= nnode
) {
996 dl_vnic_t
*vnic
, *next
;
998 for (vnic
= node
->vc_vnic
; vnic
!= NULL
; vnic
= next
) {
999 next
= vnic
->dlv_next
;
1001 /* clear stale VNICs */
1002 if (vnic
->dlv_flags
& VNIC_STALE
) {
1003 if (vnic
->dlv_prev
!= NULL
)
1004 vnic
->dlv_prev
->dlv_next
= next
;
1006 node
->vc_vnic
= next
;
1009 next
->dlv_prev
= vnic
->dlv_prev
;
1014 nnode
= node
->vc_next
;
1015 if (node
->vc_state
& CACHE_NODE_STALE
) {
1016 (void) rcm_unregister_interest(hd
, node
->vc_resource
,
1018 rcm_log_message(RCM_DEBUG
, "VNIC: unregistered %s\n",
1020 assert(node
->vc_vnic
== NULL
);
1026 if (!(node
->vc_state
& CACHE_NODE_NEW
))
1029 if (rcm_register_interest(hd
, node
->vc_resource
, 0, NULL
) !=
1031 rcm_log_message(RCM_ERROR
,
1032 _("VNIC: failed to register %s\n"),
1036 rcm_log_message(RCM_DEBUG
, "VNIC: registered %s\n",
1038 node
->vc_state
&= ~CACHE_NODE_NEW
;
1042 (void) mutex_unlock(&cache_lock
);
1047 * cache_free() - Empty the cache
1054 rcm_log_message(RCM_TRACE2
, "VNIC: cache_free\n");
1056 (void) mutex_lock(&cache_lock
);
1057 node
= cache_head
.vc_next
;
1058 while (node
!= &cache_tail
) {
1061 node
= cache_head
.vc_next
;
1063 (void) mutex_unlock(&cache_lock
);
1067 * vnic_log_err() - RCM error log wrapper
1070 vnic_log_err(datalink_id_t linkid
, char **errorp
, char *errmsg
)
1072 char link
[MAXLINKNAMELEN
];
1073 char errstr
[DLADM_STRSIZE
];
1074 dladm_status_t status
;
1080 if (linkid
!= DATALINK_INVALID_LINKID
) {
1081 char rsrc
[RCM_LINK_RESOURCE_MAX
];
1083 (void) snprintf(rsrc
, sizeof (rsrc
), "%s/%u",
1084 RCM_LINK_PREFIX
, linkid
);
1086 rcm_log_message(RCM_ERROR
, _("VNIC: %s(%s)\n"), errmsg
, rsrc
);
1087 if ((status
= dladm_datalink_id2info(dld_handle
, linkid
, NULL
,
1088 NULL
, NULL
, link
, sizeof (link
))) != DLADM_STATUS_OK
) {
1089 rcm_log_message(RCM_WARNING
,
1090 _("VNIC: cannot get link name for (%s) %s\n"),
1091 rsrc
, dladm_status2str(status
, errstr
));
1094 rcm_log_message(RCM_ERROR
, _("VNIC: %s\n"), errmsg
);
1097 errfmt
= strlen(link
) > 0 ? _("VNIC: %s(%s)") : _("VNIC: %s");
1098 len
= strlen(errfmt
) + strlen(errmsg
) + MAXLINKNAMELEN
+ 1;
1099 if ((error
= malloc(len
)) != NULL
) {
1100 if (strlen(link
) > 0)
1101 (void) snprintf(error
, len
, errfmt
, errmsg
, link
);
1103 (void) snprintf(error
, len
, errfmt
, errmsg
);
1111 * vnic_consumer_online()
1113 * Notify online to VNIC consumers.
1117 vnic_consumer_online(rcm_handle_t
*hd
, link_cache_t
*node
, char **errorp
,
1118 uint_t flags
, rcm_info_t
**info
)
1121 char rsrc
[RCM_LINK_RESOURCE_MAX
];
1123 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_consumer_online (%s)\n",
1126 for (vnic
= node
->vc_vnic
; vnic
!= NULL
; vnic
= vnic
->dlv_next
) {
1127 if (!(vnic
->dlv_flags
& VNIC_CONSUMER_OFFLINED
))
1130 (void) snprintf(rsrc
, RCM_LINK_RESOURCE_MAX
, "%s/%u",
1131 RCM_LINK_PREFIX
, vnic
->dlv_vnic_id
);
1133 if (rcm_notify_online(hd
, rsrc
, flags
, info
) == RCM_SUCCESS
)
1134 vnic
->dlv_flags
&= ~VNIC_CONSUMER_OFFLINED
;
1137 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_consumer_online done\n");
1141 * vnic_consumer_offline()
1143 * Offline VNIC consumers.
1146 vnic_consumer_offline(rcm_handle_t
*hd
, link_cache_t
*node
, char **errorp
,
1147 uint_t flags
, rcm_info_t
**info
)
1150 char rsrc
[RCM_LINK_RESOURCE_MAX
];
1151 int ret
= RCM_SUCCESS
;
1153 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_consumer_offline (%s)\n",
1156 for (vnic
= node
->vc_vnic
; vnic
!= NULL
; vnic
= vnic
->dlv_next
) {
1157 (void) snprintf(rsrc
, RCM_LINK_RESOURCE_MAX
, "%s/%u",
1158 RCM_LINK_PREFIX
, vnic
->dlv_vnic_id
);
1160 ret
= rcm_request_offline(hd
, rsrc
, flags
, info
);
1161 if (ret
!= RCM_SUCCESS
)
1164 vnic
->dlv_flags
|= VNIC_CONSUMER_OFFLINED
;
1168 vnic_consumer_online(hd
, node
, errorp
, flags
, info
);
1170 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_consumer_offline done\n");
1175 * Send RCM_RESOURCE_LINK_NEW events to other modules about new VNICs.
1176 * Return 0 on success, -1 on failure.
1179 vnic_notify_new_vnic(rcm_handle_t
*hd
, char *rsrc
)
1183 nvlist_t
*nvl
= NULL
;
1187 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_notify_new_vnic (%s)\n", rsrc
);
1189 (void) mutex_lock(&cache_lock
);
1190 if ((node
= cache_lookup(hd
, rsrc
, CACHE_REFRESH
)) == NULL
) {
1191 (void) mutex_unlock(&cache_lock
);
1195 if (nvlist_alloc(&nvl
, 0, 0) != 0) {
1196 (void) mutex_unlock(&cache_lock
);
1197 rcm_log_message(RCM_WARNING
,
1198 _("VNIC: failed to allocate nvlist\n"));
1202 for (vnic
= node
->vc_vnic
; vnic
!= NULL
; vnic
= vnic
->dlv_next
) {
1203 rcm_log_message(RCM_TRACE2
,
1204 "VNIC: vnic_notify_new_vnic add (%u)\n", vnic
->dlv_vnic_id
);
1206 id
= vnic
->dlv_vnic_id
;
1207 if (nvlist_add_uint64(nvl
, RCM_NV_LINKID
, id
) != 0) {
1208 rcm_log_message(RCM_ERROR
,
1209 _("VNIC: failed to construct nvlist\n"));
1210 (void) mutex_unlock(&cache_lock
);
1214 (void) mutex_unlock(&cache_lock
);
1216 if (rcm_notify_event(hd
, RCM_RESOURCE_LINK_NEW
, 0, nvl
, NULL
) !=
1218 rcm_log_message(RCM_ERROR
,
1219 _("VNIC: failed to notify %s event for %s\n"),
1220 RCM_RESOURCE_LINK_NEW
, node
->vc_resource
);
1231 * vnic_consumer_notify() - Notify consumers of VNICs coming back online.
1234 vnic_consumer_notify(rcm_handle_t
*hd
, datalink_id_t linkid
, char **errorp
,
1235 uint_t flags
, rcm_info_t
**info
)
1237 char rsrc
[RCM_LINK_RESOURCE_MAX
];
1240 /* Check for the interface in the cache */
1241 (void) snprintf(rsrc
, RCM_LINK_RESOURCE_MAX
, "%s/%u", RCM_LINK_PREFIX
,
1244 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_consumer_notify(%s)\n", rsrc
);
1247 * Inform IP consumers of the new link.
1249 if (vnic_notify_new_vnic(hd
, rsrc
) != 0) {
1250 (void) mutex_lock(&cache_lock
);
1251 if ((node
= cache_lookup(hd
, rsrc
, CACHE_NO_REFRESH
)) != NULL
) {
1252 (void) vnic_offline_vnic(node
, VNIC_STALE
,
1255 (void) mutex_unlock(&cache_lock
);
1256 rcm_log_message(RCM_TRACE2
,
1257 "VNIC: vnic_notify_new_vnic failed(%s)\n", rsrc
);
1261 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_consumer_notify succeeded\n");
1265 typedef struct vnic_up_arg_s
{
1266 datalink_id_t linkid
;
1271 vnic_up(dladm_handle_t handle
, datalink_id_t vnicid
, void *arg
)
1273 vnic_up_arg_t
*vnic_up_argp
= arg
;
1274 dladm_status_t status
;
1275 dladm_vnic_attr_t vnic_attr
;
1276 char errmsg
[DLADM_STRSIZE
];
1278 status
= dladm_vnic_info(handle
, vnicid
, &vnic_attr
, DLADM_OPT_PERSIST
);
1279 if (status
!= DLADM_STATUS_OK
) {
1280 rcm_log_message(RCM_TRACE1
,
1281 "VNIC: vnic_up(): cannot get information for VNIC %u "
1282 "(%s)\n", vnicid
, dladm_status2str(status
, errmsg
));
1283 return (DLADM_WALK_CONTINUE
);
1286 if (vnic_attr
.va_link_id
!= vnic_up_argp
->linkid
)
1287 return (DLADM_WALK_CONTINUE
);
1289 rcm_log_message(RCM_TRACE3
, "VNIC: vnic_up(%u)\n", vnicid
);
1290 if ((status
= dladm_vnic_up(handle
, vnicid
, 0)) == DLADM_STATUS_OK
)
1291 return (DLADM_WALK_CONTINUE
);
1294 * Prompt the warning message and continue to UP other VNICs.
1296 rcm_log_message(RCM_WARNING
,
1297 _("VNIC: VNIC up failed (%u): %s\n"),
1298 vnicid
, dladm_status2str(status
, errmsg
));
1300 vnic_up_argp
->retval
= -1;
1301 return (DLADM_WALK_CONTINUE
);
1305 * vnic_configure() - Configure VNICs over a physical link after it attaches
1308 vnic_configure(rcm_handle_t
*hd
, datalink_id_t linkid
)
1310 char rsrc
[RCM_LINK_RESOURCE_MAX
];
1312 vnic_up_arg_t arg
= {DATALINK_INVALID_LINKID
, 0};
1314 /* Check for the VNICs in the cache */
1315 (void) snprintf(rsrc
, sizeof (rsrc
), "%s/%u", RCM_LINK_PREFIX
, linkid
);
1317 rcm_log_message(RCM_TRACE2
, "VNIC: vnic_configure(%s)\n", rsrc
);
1319 /* Check if the link is new or was previously offlined */
1320 (void) mutex_lock(&cache_lock
);
1321 if (((node
= cache_lookup(hd
, rsrc
, CACHE_REFRESH
)) != NULL
) &&
1322 (!(node
->vc_state
& CACHE_NODE_OFFLINED
))) {
1323 rcm_log_message(RCM_TRACE2
,
1324 "VNIC: Skipping configured interface(%s)\n", rsrc
);
1325 (void) mutex_unlock(&cache_lock
);
1328 (void) mutex_unlock(&cache_lock
);
1330 arg
.linkid
= linkid
;
1331 (void) dladm_walk_datalink_id(vnic_up
, dld_handle
, &arg
,
1332 DATALINK_CLASS_VNIC
, DATALINK_ANY_MEDIATYPE
, DLADM_OPT_PERSIST
);
1334 if (arg
.retval
== 0) {
1335 rcm_log_message(RCM_TRACE2
,
1336 "VNIC: vnic_configure succeeded(%s)\n", rsrc
);
1338 return (arg
.retval
);