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 VLAN links
33 #include <sys/types.h>
37 #include "rcm_module.h"
39 #include <libdllink.h>
40 #include <libdlvlan.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 VLAN_CONSUMER_OFFLINED
= 0x2,
63 /* link representation */
64 typedef struct dl_vlan
{
65 struct dl_vlan
*dv_next
; /* next VLAN on the same link */
66 struct dl_vlan
*dv_prev
; /* prev VLAN on the same link */
67 datalink_id_t dv_vlanid
;
68 vlan_flag_t dv_flags
; /* VLAN link flags */
71 /* VLAN 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_vlan_t
*vc_vlan
; /* VLAN list on this link */
89 cache_node_state_t vc_state
; /* cache state flags */
93 * Global cache for network VLANs
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 vlan_register(rcm_handle_t
*);
106 static int vlan_unregister(rcm_handle_t
*);
107 static int vlan_get_info(rcm_handle_t
*, char *, id_t
, uint_t
,
108 char **, char **, nvlist_t
*, rcm_info_t
**);
109 static int vlan_suspend(rcm_handle_t
*, char *, id_t
,
110 timespec_t
*, uint_t
, char **, rcm_info_t
**);
111 static int vlan_resume(rcm_handle_t
*, char *, id_t
, uint_t
,
112 char **, rcm_info_t
**);
113 static int vlan_offline(rcm_handle_t
*, char *, id_t
, uint_t
,
114 char **, rcm_info_t
**);
115 static int vlan_undo_offline(rcm_handle_t
*, char *, id_t
, uint_t
,
116 char **, rcm_info_t
**);
117 static int vlan_remove(rcm_handle_t
*, char *, id_t
, uint_t
,
118 char **, rcm_info_t
**);
119 static int vlan_notify_event(rcm_handle_t
*, char *, id_t
, uint_t
,
120 char **, nvlist_t
*, rcm_info_t
**);
121 static int vlan_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 vlan_consumer_offline(rcm_handle_t
*, link_cache_t
*,
131 char **, uint_t
, rcm_info_t
**);
132 static void vlan_consumer_online(rcm_handle_t
*, link_cache_t
*,
133 char **, uint_t
, rcm_info_t
**);
134 static int vlan_offline_vlan(link_cache_t
*, uint32_t,
136 static void vlan_online_vlan(link_cache_t
*);
137 static char *vlan_usage(link_cache_t
*);
138 static void vlan_log_err(datalink_id_t
, char **, char *);
139 static int vlan_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 vlan_ops
=
160 * rcm_mod_init() - Update registrations, and return the ops structure.
165 dladm_status_t status
;
166 char errmsg
[DLADM_STRSIZE
];
168 rcm_log_message(RCM_TRACE1
, "VLAN: 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 "VLAN: 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
, "VLAN: mod_info\n");
195 return ("VLAN module version 1.2");
199 * rcm_mod_fini() - Destroy the network VLAN cache.
204 rcm_log_message(RCM_TRACE1
, "VLAN: mod_fini\n");
207 * Note that vlan_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 * vlan_register() - Make sure the cache is properly sync'ed, and its
221 * registrations are in order.
224 vlan_register(rcm_handle_t
*hd
)
226 rcm_log_message(RCM_TRACE1
, "VLAN: 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 _("VLAN: failed to register %s\n"),
240 RCM_RESOURCE_LINK_NEW
);
241 return (RCM_FAILURE
);
243 rcm_log_message(RCM_DEBUG
, "VLAN: registered %s\n",
244 RCM_RESOURCE_LINK_NEW
);
249 return (RCM_SUCCESS
);
253 * vlan_unregister() - Walk the cache, unregistering all the networks.
256 vlan_unregister(rcm_handle_t
*hd
)
260 rcm_log_message(RCM_TRACE1
, "VLAN: 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 _("VLAN: 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 _("VLAN: failed to unregister %s\n"),
288 RCM_RESOURCE_LINK_NEW
);
289 return (RCM_FAILURE
);
291 rcm_log_message(RCM_DEBUG
, "VLAN: unregistered %s\n",
292 RCM_RESOURCE_LINK_NEW
);
297 return (RCM_SUCCESS
);
301 * vlan_offline() - Offline VLANs on a specific node.
304 vlan_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
, "VLAN: 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 vlan_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 VLANs to be offlined
325 if (vlan_consumer_offline(hd
, node
, errorp
, flags
, info
) ==
327 rcm_log_message(RCM_DEBUG
,
328 "VLAN: consumers agreed on offline\n");
330 vlan_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 "VLAN: offline query succeeded(%s)\n", rsrc
);
340 (void) mutex_unlock(&cache_lock
);
341 return (RCM_SUCCESS
);
344 if (vlan_offline_vlan(node
, VLAN_OFFLINED
, CACHE_NODE_OFFLINED
) !=
346 vlan_online_vlan(node
);
347 vlan_log_err(node
->vc_linkid
, errorp
, "offline failed");
348 (void) mutex_unlock(&cache_lock
);
349 return (RCM_FAILURE
);
352 rcm_log_message(RCM_TRACE1
, "VLAN: Offline succeeded(%s)\n", rsrc
);
353 (void) mutex_unlock(&cache_lock
);
354 return (RCM_SUCCESS
);
358 * vlan_undo_offline() - Undo offline of a previously offlined node.
362 vlan_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
, "VLAN: online(%s)\n", rsrc
);
369 (void) mutex_lock(&cache_lock
);
370 node
= cache_lookup(hd
, rsrc
, CACHE_NO_REFRESH
);
372 vlan_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 vlan_log_err(node
->vc_linkid
, errorp
, "link not offlined");
381 (void) mutex_unlock(&cache_lock
);
383 return (RCM_SUCCESS
);
386 vlan_online_vlan(node
);
389 * Inform IP interfaces on associated VLANs to be onlined
391 vlan_consumer_online(hd
, node
, errorp
, flags
, info
);
393 node
->vc_state
&= ~CACHE_NODE_OFFLINED
;
394 rcm_log_message(RCM_TRACE1
, "VLAN: online succeeded(%s)\n", rsrc
);
395 (void) mutex_unlock(&cache_lock
);
396 return (RCM_SUCCESS
);
400 vlan_online_vlan(link_cache_t
*node
)
403 dladm_status_t status
;
404 char errmsg
[DLADM_STRSIZE
];
407 * Try to bring on all offlined VLANs
409 for (vlan
= node
->vc_vlan
; vlan
!= NULL
; vlan
= vlan
->dv_next
) {
410 if (!(vlan
->dv_flags
& VLAN_OFFLINED
))
413 if ((status
= dladm_vlan_up(dld_handle
, vlan
->dv_vlanid
)) !=
416 * Print a warning message and continue to online
419 rcm_log_message(RCM_WARNING
,
420 _("VLAN: VLAN online failed (%u): %s\n"),
421 vlan
->dv_vlanid
, dladm_status2str(status
, errmsg
));
423 vlan
->dv_flags
&= ~VLAN_OFFLINED
;
429 vlan_offline_vlan(link_cache_t
*node
, uint32_t flags
, cache_node_state_t state
)
432 dladm_status_t status
;
433 char errmsg
[DLADM_STRSIZE
];
435 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_offline_vlan (%s %u %u)\n",
436 node
->vc_resource
, flags
, state
);
439 * Try to delete all explicit created VLAN
441 for (vlan
= node
->vc_vlan
; vlan
!= NULL
; vlan
= vlan
->dv_next
) {
442 if ((status
= dladm_vlan_delete(dld_handle
, vlan
->dv_vlanid
,
443 DLADM_OPT_ACTIVE
)) != DLADM_STATUS_OK
) {
444 rcm_log_message(RCM_WARNING
,
445 _("VLAN: VLAN offline failed (%u): %s\n"),
446 vlan
->dv_vlanid
, dladm_status2str(status
, errmsg
));
447 return (RCM_FAILURE
);
449 rcm_log_message(RCM_TRACE1
,
450 "VLAN: VLAN offline succeeded(%u)\n",
452 vlan
->dv_flags
|= flags
;
456 node
->vc_state
|= state
;
457 return (RCM_SUCCESS
);
461 * vlan_get_info() - Gather usage information for this resource.
465 vlan_get_info(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
466 char **usagep
, char **errorp
, nvlist_t
*props
, rcm_info_t
**info
)
470 rcm_log_message(RCM_TRACE1
, "VLAN: get_info(%s)\n", rsrc
);
472 (void) mutex_lock(&cache_lock
);
473 node
= cache_lookup(hd
, rsrc
, CACHE_REFRESH
);
475 rcm_log_message(RCM_INFO
,
476 _("VLAN: get_info(%s) unrecognized resource\n"), rsrc
);
477 (void) mutex_unlock(&cache_lock
);
479 return (RCM_FAILURE
);
482 *usagep
= vlan_usage(node
);
483 (void) mutex_unlock(&cache_lock
);
484 if (*usagep
== NULL
) {
485 /* most likely malloc failure */
486 rcm_log_message(RCM_ERROR
,
487 _("VLAN: get_info(%s) malloc failure\n"), rsrc
);
488 (void) mutex_unlock(&cache_lock
);
490 return (RCM_FAILURE
);
493 /* Set client/role properties */
494 (void) nvlist_add_string(props
, RCM_CLIENT_NAME
, "VLAN");
496 rcm_log_message(RCM_TRACE1
, "VLAN: get_info(%s) info = %s\n",
498 return (RCM_SUCCESS
);
502 * vlan_suspend() - Nothing to do, always okay
506 vlan_suspend(rcm_handle_t
*hd
, char *rsrc
, id_t id
, timespec_t
*interval
,
507 uint_t flags
, char **errorp
, rcm_info_t
**info
)
509 rcm_log_message(RCM_TRACE1
, "VLAN: suspend(%s)\n", rsrc
);
510 return (RCM_SUCCESS
);
514 * vlan_resume() - Nothing to do, always okay
518 vlan_resume(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
519 char **errorp
, rcm_info_t
**info
)
521 rcm_log_message(RCM_TRACE1
, "VLAN: resume(%s)\n", rsrc
);
522 return (RCM_SUCCESS
);
526 * vlan_consumer_remove()
528 * Notify VLAN consumers to remove cache.
531 vlan_consumer_remove(rcm_handle_t
*hd
, link_cache_t
*node
, uint_t flags
,
534 dl_vlan_t
*vlan
= NULL
;
535 char rsrc
[RCM_LINK_RESOURCE_MAX
];
536 int ret
= RCM_SUCCESS
;
538 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_consumer_remove (%s)\n",
541 for (vlan
= node
->vc_vlan
; vlan
!= NULL
; vlan
= vlan
->dv_next
) {
544 * This will only be called when the offline operation
545 * succeeds, so the VLAN consumers must have been offlined
548 assert(vlan
->dv_flags
& VLAN_CONSUMER_OFFLINED
);
550 (void) snprintf(rsrc
, RCM_LINK_RESOURCE_MAX
, "%s/%u",
551 RCM_LINK_PREFIX
, vlan
->dv_vlanid
);
553 ret
= rcm_notify_remove(hd
, rsrc
, flags
, info
);
554 if (ret
!= RCM_SUCCESS
) {
555 rcm_log_message(RCM_WARNING
,
556 _("VLAN: notify remove failed (%s)\n"), rsrc
);
561 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_consumer_remove done\n");
566 * vlan_remove() - remove a resource from cache
570 vlan_remove(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
571 char **errorp
, rcm_info_t
**info
)
576 rcm_log_message(RCM_TRACE1
, "VLAN: remove(%s)\n", rsrc
);
578 (void) mutex_lock(&cache_lock
);
579 node
= cache_lookup(hd
, rsrc
, CACHE_NO_REFRESH
);
581 rcm_log_message(RCM_INFO
,
582 _("VLAN: remove(%s) unrecognized resource\n"), rsrc
);
583 (void) mutex_unlock(&cache_lock
);
585 return (RCM_FAILURE
);
588 /* remove the cached entry for the resource */
590 (void) mutex_unlock(&cache_lock
);
592 rv
= vlan_consumer_remove(hd
, node
, flags
, info
);
598 * vlan_notify_event - Project private implementation to receive new resource
599 * events. It intercepts all new resource events. If the
600 * new resource is a network resource, pass up a notify
601 * for it too. The new resource need not be cached, since
602 * it is done at register again.
606 vlan_notify_event(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
607 char **errorp
, nvlist_t
*nvl
, rcm_info_t
**info
)
609 nvpair_t
*nvp
= NULL
;
610 datalink_id_t linkid
;
612 int rv
= RCM_SUCCESS
;
614 rcm_log_message(RCM_TRACE1
, "VLAN: notify_event(%s)\n", rsrc
);
616 if (strcmp(rsrc
, RCM_RESOURCE_LINK_NEW
) != 0) {
617 vlan_log_err(DATALINK_INVALID_LINKID
, errorp
,
618 "unrecognized event");
620 return (RCM_FAILURE
);
623 /* Update cache to reflect latest VLANs */
624 if (cache_update(hd
) < 0) {
625 vlan_log_err(DATALINK_INVALID_LINKID
, errorp
,
626 "private Cache update failed");
627 return (RCM_FAILURE
);
631 * Try best to recover all configuration.
633 rcm_log_message(RCM_DEBUG
, "VLAN: process_nvlist\n");
634 while ((nvp
= nvlist_next_nvpair(nvl
, nvp
)) != NULL
) {
635 if (strcmp(nvpair_name(nvp
), RCM_NV_LINKID
) != 0)
638 if (nvpair_value_uint64(nvp
, &id64
) != 0) {
639 vlan_log_err(DATALINK_INVALID_LINKID
, errorp
,
640 "cannot get linkid");
645 linkid
= (datalink_id_t
)id64
;
646 if (vlan_configure(hd
, linkid
) != 0) {
647 vlan_log_err(linkid
, errorp
, "configuring failed");
652 /* Notify all VLAN consumers */
653 if (vlan_consumer_notify(hd
, linkid
, errorp
, flags
,
655 vlan_log_err(linkid
, errorp
, "consumer notify failed");
660 rcm_log_message(RCM_TRACE1
,
661 "VLAN: notify_event: link configuration complete\n");
666 * vlan_usage - Determine the usage of a link.
667 * The returned buffer is owned by caller, and the caller
668 * must free it up when done.
671 vlan_usage(link_cache_t
*node
)
678 char errmsg
[DLADM_STRSIZE
];
679 char name
[MAXLINKNAMELEN
];
680 dladm_status_t status
;
683 rcm_log_message(RCM_TRACE2
, "VLAN: usage(%s)\n", node
->vc_resource
);
685 assert(MUTEX_HELD(&cache_lock
));
686 if ((status
= dladm_datalink_id2info(dld_handle
, node
->vc_linkid
, NULL
,
687 NULL
, NULL
, name
, sizeof (name
))) != DLADM_STATUS_OK
) {
688 rcm_log_message(RCM_ERROR
,
689 _("VLAN: usage(%s) get link name failure(%s)\n"),
690 node
->vc_resource
, dladm_status2str(status
, errmsg
));
694 if (node
->vc_state
& CACHE_NODE_OFFLINED
)
695 fmt
= _("%1$s offlined");
697 fmt
= _("%1$s VLANs: ");
699 /* TRANSLATION_NOTE: separator used between VLAN linkids */
703 for (vlan
= node
->vc_vlan
; vlan
!= NULL
; vlan
= vlan
->dv_next
)
706 /* space for VLANs and separators, plus message */
707 bufsz
= nvlan
* (MAXLINKNAMELEN
+ strlen(sep
)) +
708 strlen(fmt
) + MAXLINKNAMELEN
+ 1;
709 if ((buf
= malloc(bufsz
)) == NULL
) {
710 rcm_log_message(RCM_ERROR
,
711 _("VLAN: usage(%s) malloc failure(%s)\n"),
712 node
->vc_resource
, strerror(errno
));
715 (void) snprintf(buf
, bufsz
, fmt
, name
);
717 if (node
->vc_state
& CACHE_NODE_OFFLINED
) {
718 /* Nothing else to do */
719 rcm_log_message(RCM_TRACE2
, "VLAN: usage (%s) info = %s\n",
720 node
->vc_resource
, buf
);
724 for (vlan
= node
->vc_vlan
; vlan
!= NULL
; vlan
= vlan
->dv_next
) {
725 rcm_log_message(RCM_DEBUG
, "VLAN:= %u\n", vlan
->dv_vlanid
);
727 if ((status
= dladm_datalink_id2info(dld_handle
,
728 vlan
->dv_vlanid
, NULL
, NULL
, NULL
, name
,
729 sizeof (name
))) != DLADM_STATUS_OK
) {
730 rcm_log_message(RCM_ERROR
,
731 _("VLAN: usage(%s) get vlan %u name failure(%s)\n"),
732 node
->vc_resource
, vlan
->dv_vlanid
,
733 dladm_status2str(status
, errmsg
));
738 (void) strlcat(buf
, name
, bufsz
);
739 if (vlan
->dv_next
!= NULL
)
740 (void) strlcat(buf
, sep
, bufsz
);
743 rcm_log_message(RCM_TRACE2
, "VLAN: usage (%s) info = %s\n",
744 node
->vc_resource
, buf
);
750 * Cache management routines, all cache management functions should be
751 * be called with cache_lock held.
755 * cache_lookup() - Get a cache node for a resource.
756 * Call with cache lock held.
758 * This ensures that the cache is consistent with the system state and
759 * returns a pointer to the cache element corresponding to the resource.
761 static link_cache_t
*
762 cache_lookup(rcm_handle_t
*hd
, char *rsrc
, char options
)
766 rcm_log_message(RCM_TRACE2
, "VLAN: cache lookup(%s)\n", rsrc
);
768 assert(MUTEX_HELD(&cache_lock
));
769 if (options
& CACHE_REFRESH
) {
770 /* drop lock since update locks cache again */
771 (void) mutex_unlock(&cache_lock
);
772 (void) cache_update(hd
);
773 (void) mutex_lock(&cache_lock
);
776 node
= cache_head
.vc_next
;
777 for (; node
!= &cache_tail
; node
= node
->vc_next
) {
778 if (strcmp(rsrc
, node
->vc_resource
) == 0) {
779 rcm_log_message(RCM_TRACE2
,
780 "VLAN: cache lookup succeeded(%s)\n", rsrc
);
788 * node_free - Free a node from the cache
791 node_free(link_cache_t
*node
)
793 dl_vlan_t
*vlan
, *next
;
796 free(node
->vc_resource
);
798 /* free the VLAN list */
799 for (vlan
= node
->vc_vlan
; vlan
!= NULL
; vlan
= next
) {
800 next
= vlan
->dv_next
;
808 * cache_insert - Insert a resource node in cache
811 cache_insert(link_cache_t
*node
)
813 assert(MUTEX_HELD(&cache_lock
));
815 /* insert at the head for best performance */
816 node
->vc_next
= cache_head
.vc_next
;
817 node
->vc_prev
= &cache_head
;
819 node
->vc_next
->vc_prev
= node
;
820 node
->vc_prev
->vc_next
= node
;
824 * cache_remove() - Remove a resource node from cache.
827 cache_remove(link_cache_t
*node
)
829 assert(MUTEX_HELD(&cache_lock
));
830 node
->vc_next
->vc_prev
= node
->vc_prev
;
831 node
->vc_prev
->vc_next
= node
->vc_next
;
832 node
->vc_next
= NULL
;
833 node
->vc_prev
= NULL
;
836 typedef struct vlan_update_arg_s
{
842 * vlan_update() - Update physical interface properties
845 vlan_update(dladm_handle_t handle
, datalink_id_t vlanid
, void *arg
)
847 vlan_update_arg_t
*vlan_update_argp
= arg
;
848 rcm_handle_t
*hd
= vlan_update_argp
->hd
;
852 dladm_vlan_attr_t vlan_attr
;
853 dladm_status_t status
;
854 char errmsg
[DLADM_STRSIZE
];
855 boolean_t newnode
= B_FALSE
;
858 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_update(%u)\n", vlanid
);
860 assert(MUTEX_HELD(&cache_lock
));
861 status
= dladm_vlan_info(handle
, vlanid
, &vlan_attr
, DLADM_OPT_ACTIVE
);
862 if (status
!= DLADM_STATUS_OK
) {
863 rcm_log_message(RCM_TRACE1
,
864 "VLAN: vlan_update() cannot get vlan information for "
865 "%u(%s)\n", vlanid
, dladm_status2str(status
, errmsg
));
866 return (DLADM_WALK_CONTINUE
);
869 rsrc
= malloc(RCM_LINK_RESOURCE_MAX
);
871 rcm_log_message(RCM_ERROR
, _("VLAN: malloc error(%s): %u\n"),
872 strerror(errno
), vlanid
);
876 (void) snprintf(rsrc
, RCM_LINK_RESOURCE_MAX
, "%s/%u",
877 RCM_LINK_PREFIX
, vlan_attr
.dv_linkid
);
879 node
= cache_lookup(hd
, rsrc
, CACHE_NO_REFRESH
);
881 rcm_log_message(RCM_DEBUG
,
882 "VLAN: %s already registered (vlanid:%d)\n",
883 rsrc
, vlan_attr
.dv_vid
);
886 rcm_log_message(RCM_DEBUG
,
887 "VLAN: %s is a new resource (vlanid:%d)\n",
888 rsrc
, vlan_attr
.dv_vid
);
889 if ((node
= calloc(1, sizeof (link_cache_t
))) == NULL
) {
891 rcm_log_message(RCM_ERROR
, _("VLAN: calloc: %s\n"),
896 node
->vc_resource
= rsrc
;
897 node
->vc_vlan
= NULL
;
898 node
->vc_linkid
= vlan_attr
.dv_linkid
;
899 node
->vc_state
|= CACHE_NODE_NEW
;
903 for (vlan
= node
->vc_vlan
; vlan
!= NULL
; vlan
= vlan
->dv_next
) {
904 if (vlan
->dv_vlanid
== vlanid
) {
905 vlan
->dv_flags
&= ~VLAN_STALE
;
911 if ((vlan
= calloc(1, sizeof (dl_vlan_t
))) == NULL
) {
912 rcm_log_message(RCM_ERROR
, _("VLAN: malloc: %s\n"),
920 vlan
->dv_vlanid
= vlanid
;
921 vlan
->dv_next
= node
->vc_vlan
;
922 vlan
->dv_prev
= NULL
;
923 if (node
->vc_vlan
!= NULL
)
924 node
->vc_vlan
->dv_prev
= vlan
;
925 node
->vc_vlan
= vlan
;
928 node
->vc_state
&= ~CACHE_NODE_STALE
;
933 rcm_log_message(RCM_TRACE3
, "VLAN: vlan_update: succeeded(%u)\n",
937 vlan_update_argp
->retval
= ret
;
938 return (ret
== 0 ? DLADM_WALK_CONTINUE
: DLADM_WALK_TERMINATE
);
942 * vlan_update_all() - Determine all VLAN links in the system
945 vlan_update_all(rcm_handle_t
*hd
)
947 vlan_update_arg_t arg
= {NULL
, 0};
949 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_update_all\n");
951 assert(MUTEX_HELD(&cache_lock
));
953 (void) dladm_walk_datalink_id(vlan_update
, dld_handle
, &arg
,
954 DATALINK_CLASS_VLAN
, DATALINK_ANY_MEDIATYPE
, DLADM_OPT_ACTIVE
);
959 * cache_update() - Update cache with latest interface info
962 cache_update(rcm_handle_t
*hd
)
964 link_cache_t
*node
, *nnode
;
968 rcm_log_message(RCM_TRACE2
, "VLAN: cache_update\n");
970 (void) mutex_lock(&cache_lock
);
972 /* first we walk the entire cache, marking each entry stale */
973 node
= cache_head
.vc_next
;
974 for (; node
!= &cache_tail
; node
= node
->vc_next
) {
975 node
->vc_state
|= CACHE_NODE_STALE
;
976 for (vlan
= node
->vc_vlan
; vlan
!= NULL
; vlan
= vlan
->dv_next
)
977 vlan
->dv_flags
|= VLAN_STALE
;
980 rv
= vlan_update_all(hd
);
983 * Continue to delete all stale nodes from the cache even
984 * vlan_update_all() failed. Unregister link that are not offlined
987 for (node
= cache_head
.vc_next
; node
!= &cache_tail
; node
= nnode
) {
988 dl_vlan_t
*vlan
, *next
;
990 for (vlan
= node
->vc_vlan
; vlan
!= NULL
; vlan
= next
) {
991 next
= vlan
->dv_next
;
993 /* clear stale VLANs */
994 if (vlan
->dv_flags
& VLAN_STALE
) {
995 if (vlan
->dv_prev
!= NULL
)
996 vlan
->dv_prev
->dv_next
= next
;
998 node
->vc_vlan
= next
;
1001 next
->dv_prev
= vlan
->dv_prev
;
1006 nnode
= node
->vc_next
;
1007 if (node
->vc_state
& CACHE_NODE_STALE
) {
1008 (void) rcm_unregister_interest(hd
, node
->vc_resource
,
1010 rcm_log_message(RCM_DEBUG
, "VLAN: unregistered %s\n",
1012 assert(node
->vc_vlan
== NULL
);
1018 if (!(node
->vc_state
& CACHE_NODE_NEW
))
1021 if (rcm_register_interest(hd
, node
->vc_resource
, 0, NULL
) !=
1023 rcm_log_message(RCM_ERROR
,
1024 _("VLAN: failed to register %s\n"),
1028 rcm_log_message(RCM_DEBUG
, "VLAN: registered %s\n",
1030 node
->vc_state
&= ~CACHE_NODE_NEW
;
1034 (void) mutex_unlock(&cache_lock
);
1039 * cache_free() - Empty the cache
1046 rcm_log_message(RCM_TRACE2
, "VLAN: cache_free\n");
1048 (void) mutex_lock(&cache_lock
);
1049 node
= cache_head
.vc_next
;
1050 while (node
!= &cache_tail
) {
1053 node
= cache_head
.vc_next
;
1055 (void) mutex_unlock(&cache_lock
);
1059 * vlan_log_err() - RCM error log wrapper
1062 vlan_log_err(datalink_id_t linkid
, char **errorp
, char *errmsg
)
1064 char link
[MAXLINKNAMELEN
];
1065 char errstr
[DLADM_STRSIZE
];
1066 dladm_status_t status
;
1072 if (linkid
!= DATALINK_INVALID_LINKID
) {
1073 char rsrc
[RCM_LINK_RESOURCE_MAX
];
1075 (void) snprintf(rsrc
, sizeof (rsrc
), "%s/%u",
1076 RCM_LINK_PREFIX
, linkid
);
1078 rcm_log_message(RCM_ERROR
, _("VLAN: %s(%s)\n"), errmsg
, rsrc
);
1079 if ((status
= dladm_datalink_id2info(dld_handle
, linkid
, NULL
,
1080 NULL
, NULL
, link
, sizeof (link
))) != DLADM_STATUS_OK
) {
1081 rcm_log_message(RCM_WARNING
,
1082 _("VLAN: cannot get link name for (%s) %s\n"),
1083 rsrc
, dladm_status2str(status
, errstr
));
1086 rcm_log_message(RCM_ERROR
, _("VLAN: %s\n"), errmsg
);
1089 errfmt
= strlen(link
) > 0 ? _("VLAN: %s(%s)") : _("VLAN: %s");
1090 len
= strlen(errfmt
) + strlen(errmsg
) + MAXLINKNAMELEN
+ 1;
1091 if ((error
= malloc(len
)) != NULL
) {
1092 if (strlen(link
) > 0)
1093 (void) snprintf(error
, len
, errfmt
, errmsg
, link
);
1095 (void) snprintf(error
, len
, errfmt
, errmsg
);
1103 * vlan_consumer_online()
1105 * Notify online to VLAN consumers.
1109 vlan_consumer_online(rcm_handle_t
*hd
, link_cache_t
*node
, char **errorp
,
1110 uint_t flags
, rcm_info_t
**info
)
1113 char rsrc
[RCM_LINK_RESOURCE_MAX
];
1115 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_consumer_online (%s)\n",
1118 for (vlan
= node
->vc_vlan
; vlan
!= NULL
; vlan
= vlan
->dv_next
) {
1119 if (!(vlan
->dv_flags
& VLAN_CONSUMER_OFFLINED
))
1122 (void) snprintf(rsrc
, RCM_LINK_RESOURCE_MAX
, "%s/%u",
1123 RCM_LINK_PREFIX
, vlan
->dv_vlanid
);
1125 if (rcm_notify_online(hd
, rsrc
, flags
, info
) == RCM_SUCCESS
)
1126 vlan
->dv_flags
&= ~VLAN_CONSUMER_OFFLINED
;
1129 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_consumer_online done\n");
1133 * vlan_consumer_offline()
1135 * Offline VLAN consumers.
1138 vlan_consumer_offline(rcm_handle_t
*hd
, link_cache_t
*node
, char **errorp
,
1139 uint_t flags
, rcm_info_t
**info
)
1142 char rsrc
[RCM_LINK_RESOURCE_MAX
];
1143 int ret
= RCM_SUCCESS
;
1145 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_consumer_offline (%s)\n",
1148 for (vlan
= node
->vc_vlan
; vlan
!= NULL
; vlan
= vlan
->dv_next
) {
1149 (void) snprintf(rsrc
, RCM_LINK_RESOURCE_MAX
, "%s/%u",
1150 RCM_LINK_PREFIX
, vlan
->dv_vlanid
);
1152 ret
= rcm_request_offline(hd
, rsrc
, flags
, info
);
1153 if (ret
!= RCM_SUCCESS
)
1156 vlan
->dv_flags
|= VLAN_CONSUMER_OFFLINED
;
1160 vlan_consumer_online(hd
, node
, errorp
, flags
, info
);
1162 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_consumer_offline done\n");
1167 * Send RCM_RESOURCE_LINK_NEW events to other modules about new VLANs.
1168 * Return 0 on success, -1 on failure.
1171 vlan_notify_new_vlan(rcm_handle_t
*hd
, char *rsrc
)
1175 nvlist_t
*nvl
= NULL
;
1179 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_notify_new_vlan (%s)\n", rsrc
);
1181 (void) mutex_lock(&cache_lock
);
1182 if ((node
= cache_lookup(hd
, rsrc
, CACHE_REFRESH
)) == NULL
) {
1183 (void) mutex_unlock(&cache_lock
);
1187 if (nvlist_alloc(&nvl
, 0, 0) != 0) {
1188 (void) mutex_unlock(&cache_lock
);
1189 rcm_log_message(RCM_WARNING
,
1190 _("VLAN: failed to allocate nvlist\n"));
1194 for (vlan
= node
->vc_vlan
; vlan
!= NULL
; vlan
= vlan
->dv_next
) {
1195 rcm_log_message(RCM_TRACE2
,
1196 "VLAN: vlan_notify_new_vlan add (%u)\n",
1199 id
= vlan
->dv_vlanid
;
1200 if (nvlist_add_uint64(nvl
, RCM_NV_LINKID
, id
) != 0) {
1201 rcm_log_message(RCM_ERROR
,
1202 _("VLAN: failed to construct nvlist\n"));
1203 (void) mutex_unlock(&cache_lock
);
1207 (void) mutex_unlock(&cache_lock
);
1209 if (rcm_notify_event(hd
, RCM_RESOURCE_LINK_NEW
, 0, nvl
, NULL
) !=
1211 rcm_log_message(RCM_ERROR
,
1212 _("VLAN: failed to notify %s event for %s\n"),
1213 RCM_RESOURCE_LINK_NEW
, node
->vc_resource
);
1224 * vlan_consumer_notify() - Notify consumers of VLANs coming back online.
1227 vlan_consumer_notify(rcm_handle_t
*hd
, datalink_id_t linkid
, char **errorp
,
1228 uint_t flags
, rcm_info_t
**info
)
1230 char rsrc
[RCM_LINK_RESOURCE_MAX
];
1233 /* Check for the interface in the cache */
1234 (void) snprintf(rsrc
, RCM_LINK_RESOURCE_MAX
, "%s/%u", RCM_LINK_PREFIX
,
1237 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_consumer_notify(%s)\n", rsrc
);
1240 * Inform IP consumers of the new link.
1242 if (vlan_notify_new_vlan(hd
, rsrc
) != 0) {
1243 (void) mutex_lock(&cache_lock
);
1244 if ((node
= cache_lookup(hd
, rsrc
, CACHE_NO_REFRESH
)) != NULL
) {
1245 (void) vlan_offline_vlan(node
, VLAN_STALE
,
1248 (void) mutex_unlock(&cache_lock
);
1249 rcm_log_message(RCM_TRACE2
,
1250 "VLAN: vlan_notify_new_vlan failed(%s)\n", rsrc
);
1254 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_consumer_notify succeeded\n");
1258 typedef struct vlan_up_arg_s
{
1259 datalink_id_t linkid
;
1264 vlan_up(dladm_handle_t handle
, datalink_id_t vlanid
, void *arg
)
1266 vlan_up_arg_t
*vlan_up_argp
= arg
;
1267 dladm_status_t status
;
1268 dladm_vlan_attr_t vlan_attr
;
1269 char errmsg
[DLADM_STRSIZE
];
1271 status
= dladm_vlan_info(handle
, vlanid
, &vlan_attr
, DLADM_OPT_PERSIST
);
1272 if (status
!= DLADM_STATUS_OK
) {
1273 rcm_log_message(RCM_TRACE1
,
1274 "VLAN: vlan_up(): cannot get information for VLAN %u "
1275 "(%s)\n", vlanid
, dladm_status2str(status
, errmsg
));
1276 return (DLADM_WALK_CONTINUE
);
1279 if (vlan_attr
.dv_linkid
!= vlan_up_argp
->linkid
)
1280 return (DLADM_WALK_CONTINUE
);
1282 rcm_log_message(RCM_TRACE3
, "VLAN: vlan_up(%u)\n", vlanid
);
1283 if ((status
= dladm_vlan_up(handle
, vlanid
)) == DLADM_STATUS_OK
)
1284 return (DLADM_WALK_CONTINUE
);
1287 * Prompt the warning message and continue to UP other VLANs.
1289 rcm_log_message(RCM_WARNING
,
1290 _("VLAN: VLAN up failed (%u): %s\n"),
1291 vlanid
, dladm_status2str(status
, errmsg
));
1293 vlan_up_argp
->retval
= -1;
1294 return (DLADM_WALK_CONTINUE
);
1298 * vlan_configure() - Configure VLANs over a physical link after it attaches
1301 vlan_configure(rcm_handle_t
*hd
, datalink_id_t linkid
)
1303 char rsrc
[RCM_LINK_RESOURCE_MAX
];
1305 vlan_up_arg_t arg
= {DATALINK_INVALID_LINKID
, 0};
1307 /* Check for the VLANs in the cache */
1308 (void) snprintf(rsrc
, sizeof (rsrc
), "%s/%u", RCM_LINK_PREFIX
, linkid
);
1310 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_configure(%s)\n", rsrc
);
1312 /* Check if the link is new or was previously offlined */
1313 (void) mutex_lock(&cache_lock
);
1314 if (((node
= cache_lookup(hd
, rsrc
, CACHE_REFRESH
)) != NULL
) &&
1315 (!(node
->vc_state
& CACHE_NODE_OFFLINED
))) {
1316 rcm_log_message(RCM_TRACE2
,
1317 "VLAN: Skipping configured interface(%s)\n", rsrc
);
1318 (void) mutex_unlock(&cache_lock
);
1321 (void) mutex_unlock(&cache_lock
);
1323 arg
.linkid
= linkid
;
1324 (void) dladm_walk_datalink_id(vlan_up
, dld_handle
, &arg
,
1325 DATALINK_CLASS_VLAN
, DATALINK_ANY_MEDIATYPE
, DLADM_OPT_PERSIST
);
1327 if (arg
.retval
== 0) {
1328 rcm_log_message(RCM_TRACE2
,
1329 "VLAN: vlan_configure succeeded(%s)\n", rsrc
);
1331 return (arg
.retval
);