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>
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 VLAN_CONSUMER_OFFLINED
= 0x2,
59 /* link representation */
60 typedef struct dl_vlan
{
61 struct dl_vlan
*dv_next
; /* next VLAN on the same link */
62 struct dl_vlan
*dv_prev
; /* prev VLAN on the same link */
63 datalink_id_t dv_vlanid
;
64 vlan_flag_t dv_flags
; /* VLAN link flags */
67 /* VLAN 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_vlan_t
*vc_vlan
; /* VLAN list on this link */
85 cache_node_state_t vc_state
; /* cache state flags */
89 * Global cache for network VLANs
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 vlan_register(rcm_handle_t
*);
102 static int vlan_unregister(rcm_handle_t
*);
103 static int vlan_get_info(rcm_handle_t
*, char *, id_t
, uint_t
,
104 char **, char **, nvlist_t
*, rcm_info_t
**);
105 static int vlan_suspend(rcm_handle_t
*, char *, id_t
,
106 timespec_t
*, uint_t
, char **, rcm_info_t
**);
107 static int vlan_resume(rcm_handle_t
*, char *, id_t
, uint_t
,
108 char **, rcm_info_t
**);
109 static int vlan_offline(rcm_handle_t
*, char *, id_t
, uint_t
,
110 char **, rcm_info_t
**);
111 static int vlan_undo_offline(rcm_handle_t
*, char *, id_t
, uint_t
,
112 char **, rcm_info_t
**);
113 static int vlan_remove(rcm_handle_t
*, char *, id_t
, uint_t
,
114 char **, rcm_info_t
**);
115 static int vlan_notify_event(rcm_handle_t
*, char *, id_t
, uint_t
,
116 char **, nvlist_t
*, rcm_info_t
**);
117 static int vlan_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 vlan_consumer_offline(rcm_handle_t
*, link_cache_t
*,
127 char **, uint_t
, rcm_info_t
**);
128 static void vlan_consumer_online(rcm_handle_t
*, link_cache_t
*,
129 char **, uint_t
, rcm_info_t
**);
130 static int vlan_offline_vlan(link_cache_t
*, uint32_t,
132 static void vlan_online_vlan(link_cache_t
*);
133 static char *vlan_usage(link_cache_t
*);
134 static void vlan_log_err(datalink_id_t
, char **, char *);
135 static int vlan_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 vlan_ops
=
156 * rcm_mod_init() - Update registrations, and return the ops structure.
161 dladm_status_t status
;
162 char errmsg
[DLADM_STRSIZE
];
164 rcm_log_message(RCM_TRACE1
, "VLAN: 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 "VLAN: 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
, "VLAN: mod_info\n");
191 return ("VLAN module version 1.2");
195 * rcm_mod_fini() - Destroy the network VLAN cache.
200 rcm_log_message(RCM_TRACE1
, "VLAN: mod_fini\n");
203 * Note that vlan_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 * vlan_register() - Make sure the cache is properly sync'ed, and its
217 * registrations are in order.
220 vlan_register(rcm_handle_t
*hd
)
222 rcm_log_message(RCM_TRACE1
, "VLAN: 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 _("VLAN: failed to register %s\n"),
236 RCM_RESOURCE_LINK_NEW
);
237 return (RCM_FAILURE
);
239 rcm_log_message(RCM_DEBUG
, "VLAN: registered %s\n",
240 RCM_RESOURCE_LINK_NEW
);
245 return (RCM_SUCCESS
);
249 * vlan_unregister() - Walk the cache, unregistering all the networks.
252 vlan_unregister(rcm_handle_t
*hd
)
256 rcm_log_message(RCM_TRACE1
, "VLAN: 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 _("VLAN: 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 _("VLAN: failed to unregister %s\n"),
284 RCM_RESOURCE_LINK_NEW
);
285 return (RCM_FAILURE
);
287 rcm_log_message(RCM_DEBUG
, "VLAN: unregistered %s\n",
288 RCM_RESOURCE_LINK_NEW
);
293 return (RCM_SUCCESS
);
297 * vlan_offline() - Offline VLANs on a specific node.
300 vlan_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
, "VLAN: 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 vlan_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 VLANs to be offlined
321 if (vlan_consumer_offline(hd
, node
, errorp
, flags
, info
) ==
323 rcm_log_message(RCM_DEBUG
,
324 "VLAN: consumers agreed on offline\n");
326 vlan_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 "VLAN: offline query succeeded(%s)\n", rsrc
);
336 (void) mutex_unlock(&cache_lock
);
337 return (RCM_SUCCESS
);
340 if (vlan_offline_vlan(node
, VLAN_OFFLINED
, CACHE_NODE_OFFLINED
) !=
342 vlan_online_vlan(node
);
343 vlan_log_err(node
->vc_linkid
, errorp
, "offline failed");
344 (void) mutex_unlock(&cache_lock
);
345 return (RCM_FAILURE
);
348 rcm_log_message(RCM_TRACE1
, "VLAN: Offline succeeded(%s)\n", rsrc
);
349 (void) mutex_unlock(&cache_lock
);
350 return (RCM_SUCCESS
);
354 * vlan_undo_offline() - Undo offline of a previously offlined node.
358 vlan_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
, "VLAN: online(%s)\n", rsrc
);
365 (void) mutex_lock(&cache_lock
);
366 node
= cache_lookup(hd
, rsrc
, CACHE_NO_REFRESH
);
368 vlan_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 vlan_log_err(node
->vc_linkid
, errorp
, "link not offlined");
377 (void) mutex_unlock(&cache_lock
);
379 return (RCM_SUCCESS
);
382 vlan_online_vlan(node
);
385 * Inform IP interfaces on associated VLANs to be onlined
387 vlan_consumer_online(hd
, node
, errorp
, flags
, info
);
389 node
->vc_state
&= ~CACHE_NODE_OFFLINED
;
390 rcm_log_message(RCM_TRACE1
, "VLAN: online succeeded(%s)\n", rsrc
);
391 (void) mutex_unlock(&cache_lock
);
392 return (RCM_SUCCESS
);
396 vlan_online_vlan(link_cache_t
*node
)
399 dladm_status_t status
;
400 char errmsg
[DLADM_STRSIZE
];
403 * Try to bring on all offlined VLANs
405 for (vlan
= node
->vc_vlan
; vlan
!= NULL
; vlan
= vlan
->dv_next
) {
406 if (!(vlan
->dv_flags
& VLAN_OFFLINED
))
409 if ((status
= dladm_vlan_up(dld_handle
, vlan
->dv_vlanid
)) !=
412 * Print a warning message and continue to online
415 rcm_log_message(RCM_WARNING
,
416 _("VLAN: VLAN online failed (%u): %s\n"),
417 vlan
->dv_vlanid
, dladm_status2str(status
, errmsg
));
419 vlan
->dv_flags
&= ~VLAN_OFFLINED
;
425 vlan_offline_vlan(link_cache_t
*node
, uint32_t flags
, cache_node_state_t state
)
428 dladm_status_t status
;
429 char errmsg
[DLADM_STRSIZE
];
431 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_offline_vlan (%s %u %u)\n",
432 node
->vc_resource
, flags
, state
);
435 * Try to delete all explicit created VLAN
437 for (vlan
= node
->vc_vlan
; vlan
!= NULL
; vlan
= vlan
->dv_next
) {
438 if ((status
= dladm_vlan_delete(dld_handle
, vlan
->dv_vlanid
,
439 DLADM_OPT_ACTIVE
)) != DLADM_STATUS_OK
) {
440 rcm_log_message(RCM_WARNING
,
441 _("VLAN: VLAN offline failed (%u): %s\n"),
442 vlan
->dv_vlanid
, dladm_status2str(status
, errmsg
));
443 return (RCM_FAILURE
);
445 rcm_log_message(RCM_TRACE1
,
446 "VLAN: VLAN offline succeeded(%u)\n",
448 vlan
->dv_flags
|= flags
;
452 node
->vc_state
|= state
;
453 return (RCM_SUCCESS
);
457 * vlan_get_info() - Gather usage information for this resource.
461 vlan_get_info(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
462 char **usagep
, char **errorp
, nvlist_t
*props
, rcm_info_t
**info
)
466 rcm_log_message(RCM_TRACE1
, "VLAN: get_info(%s)\n", rsrc
);
468 (void) mutex_lock(&cache_lock
);
469 node
= cache_lookup(hd
, rsrc
, CACHE_REFRESH
);
471 rcm_log_message(RCM_INFO
,
472 _("VLAN: get_info(%s) unrecognized resource\n"), rsrc
);
473 (void) mutex_unlock(&cache_lock
);
475 return (RCM_FAILURE
);
478 *usagep
= vlan_usage(node
);
479 (void) mutex_unlock(&cache_lock
);
480 if (*usagep
== NULL
) {
481 /* most likely malloc failure */
482 rcm_log_message(RCM_ERROR
,
483 _("VLAN: get_info(%s) malloc failure\n"), rsrc
);
484 (void) mutex_unlock(&cache_lock
);
486 return (RCM_FAILURE
);
489 /* Set client/role properties */
490 (void) nvlist_add_string(props
, RCM_CLIENT_NAME
, "VLAN");
492 rcm_log_message(RCM_TRACE1
, "VLAN: get_info(%s) info = %s\n",
494 return (RCM_SUCCESS
);
498 * vlan_suspend() - Nothing to do, always okay
502 vlan_suspend(rcm_handle_t
*hd
, char *rsrc
, id_t id
, timespec_t
*interval
,
503 uint_t flags
, char **errorp
, rcm_info_t
**info
)
505 rcm_log_message(RCM_TRACE1
, "VLAN: suspend(%s)\n", rsrc
);
506 return (RCM_SUCCESS
);
510 * vlan_resume() - Nothing to do, always okay
514 vlan_resume(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
515 char **errorp
, rcm_info_t
**info
)
517 rcm_log_message(RCM_TRACE1
, "VLAN: resume(%s)\n", rsrc
);
518 return (RCM_SUCCESS
);
522 * vlan_consumer_remove()
524 * Notify VLAN consumers to remove cache.
527 vlan_consumer_remove(rcm_handle_t
*hd
, link_cache_t
*node
, uint_t flags
,
530 dl_vlan_t
*vlan
= NULL
;
531 char rsrc
[RCM_LINK_RESOURCE_MAX
];
532 int ret
= RCM_SUCCESS
;
534 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_consumer_remove (%s)\n",
537 for (vlan
= node
->vc_vlan
; vlan
!= NULL
; vlan
= vlan
->dv_next
) {
540 * This will only be called when the offline operation
541 * succeeds, so the VLAN consumers must have been offlined
544 assert(vlan
->dv_flags
& VLAN_CONSUMER_OFFLINED
);
546 (void) snprintf(rsrc
, RCM_LINK_RESOURCE_MAX
, "%s/%u",
547 RCM_LINK_PREFIX
, vlan
->dv_vlanid
);
549 ret
= rcm_notify_remove(hd
, rsrc
, flags
, info
);
550 if (ret
!= RCM_SUCCESS
) {
551 rcm_log_message(RCM_WARNING
,
552 _("VLAN: notify remove failed (%s)\n"), rsrc
);
557 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_consumer_remove done\n");
562 * vlan_remove() - remove a resource from cache
566 vlan_remove(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
567 char **errorp
, rcm_info_t
**info
)
572 rcm_log_message(RCM_TRACE1
, "VLAN: remove(%s)\n", rsrc
);
574 (void) mutex_lock(&cache_lock
);
575 node
= cache_lookup(hd
, rsrc
, CACHE_NO_REFRESH
);
577 rcm_log_message(RCM_INFO
,
578 _("VLAN: remove(%s) unrecognized resource\n"), rsrc
);
579 (void) mutex_unlock(&cache_lock
);
581 return (RCM_FAILURE
);
584 /* remove the cached entry for the resource */
586 (void) mutex_unlock(&cache_lock
);
588 rv
= vlan_consumer_remove(hd
, node
, flags
, info
);
594 * vlan_notify_event - Project private implementation to receive new resource
595 * events. It intercepts all new resource events. If the
596 * new resource is a network resource, pass up a notify
597 * for it too. The new resource need not be cached, since
598 * it is done at register again.
602 vlan_notify_event(rcm_handle_t
*hd
, char *rsrc
, id_t id
, uint_t flags
,
603 char **errorp
, nvlist_t
*nvl
, rcm_info_t
**info
)
605 nvpair_t
*nvp
= NULL
;
606 datalink_id_t linkid
;
608 int rv
= RCM_SUCCESS
;
610 rcm_log_message(RCM_TRACE1
, "VLAN: notify_event(%s)\n", rsrc
);
612 if (strcmp(rsrc
, RCM_RESOURCE_LINK_NEW
) != 0) {
613 vlan_log_err(DATALINK_INVALID_LINKID
, errorp
,
614 "unrecognized event");
616 return (RCM_FAILURE
);
619 /* Update cache to reflect latest VLANs */
620 if (cache_update(hd
) < 0) {
621 vlan_log_err(DATALINK_INVALID_LINKID
, errorp
,
622 "private Cache update failed");
623 return (RCM_FAILURE
);
627 * Try best to recover all configuration.
629 rcm_log_message(RCM_DEBUG
, "VLAN: process_nvlist\n");
630 while ((nvp
= nvlist_next_nvpair(nvl
, nvp
)) != NULL
) {
631 if (strcmp(nvpair_name(nvp
), RCM_NV_LINKID
) != 0)
634 if (nvpair_value_uint64(nvp
, &id64
) != 0) {
635 vlan_log_err(DATALINK_INVALID_LINKID
, errorp
,
636 "cannot get linkid");
641 linkid
= (datalink_id_t
)id64
;
642 if (vlan_configure(hd
, linkid
) != 0) {
643 vlan_log_err(linkid
, errorp
, "configuring failed");
648 /* Notify all VLAN consumers */
649 if (vlan_consumer_notify(hd
, linkid
, errorp
, flags
,
651 vlan_log_err(linkid
, errorp
, "consumer notify failed");
656 rcm_log_message(RCM_TRACE1
,
657 "VLAN: notify_event: link configuration complete\n");
662 * vlan_usage - Determine the usage of a link.
663 * The returned buffer is owned by caller, and the caller
664 * must free it up when done.
667 vlan_usage(link_cache_t
*node
)
674 char errmsg
[DLADM_STRSIZE
];
675 char name
[MAXLINKNAMELEN
];
676 dladm_status_t status
;
679 rcm_log_message(RCM_TRACE2
, "VLAN: usage(%s)\n", node
->vc_resource
);
681 assert(MUTEX_HELD(&cache_lock
));
682 if ((status
= dladm_datalink_id2info(dld_handle
, node
->vc_linkid
, NULL
,
683 NULL
, NULL
, name
, sizeof (name
))) != DLADM_STATUS_OK
) {
684 rcm_log_message(RCM_ERROR
,
685 _("VLAN: usage(%s) get link name failure(%s)\n"),
686 node
->vc_resource
, dladm_status2str(status
, errmsg
));
690 if (node
->vc_state
& CACHE_NODE_OFFLINED
)
691 fmt
= _("%1$s offlined");
693 fmt
= _("%1$s VLANs: ");
695 /* TRANSLATION_NOTE: separator used between VLAN linkids */
699 for (vlan
= node
->vc_vlan
; vlan
!= NULL
; vlan
= vlan
->dv_next
)
702 /* space for VLANs and separators, plus message */
703 bufsz
= nvlan
* (MAXLINKNAMELEN
+ strlen(sep
)) +
704 strlen(fmt
) + MAXLINKNAMELEN
+ 1;
705 if ((buf
= malloc(bufsz
)) == NULL
) {
706 rcm_log_message(RCM_ERROR
,
707 _("VLAN: usage(%s) malloc failure(%s)\n"),
708 node
->vc_resource
, strerror(errno
));
711 (void) snprintf(buf
, bufsz
, fmt
, name
);
713 if (node
->vc_state
& CACHE_NODE_OFFLINED
) {
714 /* Nothing else to do */
715 rcm_log_message(RCM_TRACE2
, "VLAN: usage (%s) info = %s\n",
716 node
->vc_resource
, buf
);
720 for (vlan
= node
->vc_vlan
; vlan
!= NULL
; vlan
= vlan
->dv_next
) {
721 rcm_log_message(RCM_DEBUG
, "VLAN:= %u\n", vlan
->dv_vlanid
);
723 if ((status
= dladm_datalink_id2info(dld_handle
,
724 vlan
->dv_vlanid
, NULL
, NULL
, NULL
, name
,
725 sizeof (name
))) != DLADM_STATUS_OK
) {
726 rcm_log_message(RCM_ERROR
,
727 _("VLAN: usage(%s) get vlan %u name failure(%s)\n"),
728 node
->vc_resource
, vlan
->dv_vlanid
,
729 dladm_status2str(status
, errmsg
));
734 (void) strlcat(buf
, name
, bufsz
);
735 if (vlan
->dv_next
!= NULL
)
736 (void) strlcat(buf
, sep
, bufsz
);
739 rcm_log_message(RCM_TRACE2
, "VLAN: usage (%s) info = %s\n",
740 node
->vc_resource
, buf
);
746 * Cache management routines, all cache management functions should be
747 * be called with cache_lock held.
751 * cache_lookup() - Get a cache node for a resource.
752 * Call with cache lock held.
754 * This ensures that the cache is consistent with the system state and
755 * returns a pointer to the cache element corresponding to the resource.
757 static link_cache_t
*
758 cache_lookup(rcm_handle_t
*hd
, char *rsrc
, char options
)
762 rcm_log_message(RCM_TRACE2
, "VLAN: cache lookup(%s)\n", rsrc
);
764 assert(MUTEX_HELD(&cache_lock
));
765 if (options
& CACHE_REFRESH
) {
766 /* drop lock since update locks cache again */
767 (void) mutex_unlock(&cache_lock
);
768 (void) cache_update(hd
);
769 (void) mutex_lock(&cache_lock
);
772 node
= cache_head
.vc_next
;
773 for (; node
!= &cache_tail
; node
= node
->vc_next
) {
774 if (strcmp(rsrc
, node
->vc_resource
) == 0) {
775 rcm_log_message(RCM_TRACE2
,
776 "VLAN: cache lookup succeeded(%s)\n", rsrc
);
784 * node_free - Free a node from the cache
787 node_free(link_cache_t
*node
)
789 dl_vlan_t
*vlan
, *next
;
792 free(node
->vc_resource
);
794 /* free the VLAN list */
795 for (vlan
= node
->vc_vlan
; vlan
!= NULL
; vlan
= next
) {
796 next
= vlan
->dv_next
;
804 * cache_insert - Insert a resource node in cache
807 cache_insert(link_cache_t
*node
)
809 assert(MUTEX_HELD(&cache_lock
));
811 /* insert at the head for best performance */
812 node
->vc_next
= cache_head
.vc_next
;
813 node
->vc_prev
= &cache_head
;
815 node
->vc_next
->vc_prev
= node
;
816 node
->vc_prev
->vc_next
= node
;
820 * cache_remove() - Remove a resource node from cache.
823 cache_remove(link_cache_t
*node
)
825 assert(MUTEX_HELD(&cache_lock
));
826 node
->vc_next
->vc_prev
= node
->vc_prev
;
827 node
->vc_prev
->vc_next
= node
->vc_next
;
828 node
->vc_next
= NULL
;
829 node
->vc_prev
= NULL
;
832 typedef struct vlan_update_arg_s
{
838 * vlan_update() - Update physical interface properties
841 vlan_update(dladm_handle_t handle
, datalink_id_t vlanid
, void *arg
)
843 vlan_update_arg_t
*vlan_update_argp
= arg
;
844 rcm_handle_t
*hd
= vlan_update_argp
->hd
;
848 dladm_vlan_attr_t vlan_attr
;
849 dladm_status_t status
;
850 char errmsg
[DLADM_STRSIZE
];
851 boolean_t newnode
= B_FALSE
;
854 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_update(%u)\n", vlanid
);
856 assert(MUTEX_HELD(&cache_lock
));
857 status
= dladm_vlan_info(handle
, vlanid
, &vlan_attr
, DLADM_OPT_ACTIVE
);
858 if (status
!= DLADM_STATUS_OK
) {
859 rcm_log_message(RCM_TRACE1
,
860 "VLAN: vlan_update() cannot get vlan information for "
861 "%u(%s)\n", vlanid
, dladm_status2str(status
, errmsg
));
862 return (DLADM_WALK_CONTINUE
);
865 rsrc
= malloc(RCM_LINK_RESOURCE_MAX
);
867 rcm_log_message(RCM_ERROR
, _("VLAN: malloc error(%s): %u\n"),
868 strerror(errno
), vlanid
);
872 (void) snprintf(rsrc
, RCM_LINK_RESOURCE_MAX
, "%s/%u",
873 RCM_LINK_PREFIX
, vlan_attr
.dv_linkid
);
875 node
= cache_lookup(hd
, rsrc
, CACHE_NO_REFRESH
);
877 rcm_log_message(RCM_DEBUG
,
878 "VLAN: %s already registered (vlanid:%d)\n",
879 rsrc
, vlan_attr
.dv_vid
);
882 rcm_log_message(RCM_DEBUG
,
883 "VLAN: %s is a new resource (vlanid:%d)\n",
884 rsrc
, vlan_attr
.dv_vid
);
885 if ((node
= calloc(1, sizeof (link_cache_t
))) == NULL
) {
887 rcm_log_message(RCM_ERROR
, _("VLAN: calloc: %s\n"),
892 node
->vc_resource
= rsrc
;
893 node
->vc_vlan
= NULL
;
894 node
->vc_linkid
= vlan_attr
.dv_linkid
;
895 node
->vc_state
|= CACHE_NODE_NEW
;
899 for (vlan
= node
->vc_vlan
; vlan
!= NULL
; vlan
= vlan
->dv_next
) {
900 if (vlan
->dv_vlanid
== vlanid
) {
901 vlan
->dv_flags
&= ~VLAN_STALE
;
907 if ((vlan
= calloc(1, sizeof (dl_vlan_t
))) == NULL
) {
908 rcm_log_message(RCM_ERROR
, _("VLAN: malloc: %s\n"),
916 vlan
->dv_vlanid
= vlanid
;
917 vlan
->dv_next
= node
->vc_vlan
;
918 vlan
->dv_prev
= NULL
;
919 if (node
->vc_vlan
!= NULL
)
920 node
->vc_vlan
->dv_prev
= vlan
;
921 node
->vc_vlan
= vlan
;
924 node
->vc_state
&= ~CACHE_NODE_STALE
;
929 rcm_log_message(RCM_TRACE3
, "VLAN: vlan_update: succeeded(%u)\n",
933 vlan_update_argp
->retval
= ret
;
934 return (ret
== 0 ? DLADM_WALK_CONTINUE
: DLADM_WALK_TERMINATE
);
938 * vlan_update_all() - Determine all VLAN links in the system
941 vlan_update_all(rcm_handle_t
*hd
)
943 vlan_update_arg_t arg
= {NULL
, 0};
945 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_update_all\n");
947 assert(MUTEX_HELD(&cache_lock
));
949 (void) dladm_walk_datalink_id(vlan_update
, dld_handle
, &arg
,
950 DATALINK_CLASS_VLAN
, DATALINK_ANY_MEDIATYPE
, DLADM_OPT_ACTIVE
);
955 * cache_update() - Update cache with latest interface info
958 cache_update(rcm_handle_t
*hd
)
960 link_cache_t
*node
, *nnode
;
964 rcm_log_message(RCM_TRACE2
, "VLAN: cache_update\n");
966 (void) mutex_lock(&cache_lock
);
968 /* first we walk the entire cache, marking each entry stale */
969 node
= cache_head
.vc_next
;
970 for (; node
!= &cache_tail
; node
= node
->vc_next
) {
971 node
->vc_state
|= CACHE_NODE_STALE
;
972 for (vlan
= node
->vc_vlan
; vlan
!= NULL
; vlan
= vlan
->dv_next
)
973 vlan
->dv_flags
|= VLAN_STALE
;
976 rv
= vlan_update_all(hd
);
979 * Continue to delete all stale nodes from the cache even
980 * vlan_update_all() failed. Unregister link that are not offlined
983 for (node
= cache_head
.vc_next
; node
!= &cache_tail
; node
= nnode
) {
984 dl_vlan_t
*vlan
, *next
;
986 for (vlan
= node
->vc_vlan
; vlan
!= NULL
; vlan
= next
) {
987 next
= vlan
->dv_next
;
989 /* clear stale VLANs */
990 if (vlan
->dv_flags
& VLAN_STALE
) {
991 if (vlan
->dv_prev
!= NULL
)
992 vlan
->dv_prev
->dv_next
= next
;
994 node
->vc_vlan
= next
;
997 next
->dv_prev
= vlan
->dv_prev
;
1002 nnode
= node
->vc_next
;
1003 if (node
->vc_state
& CACHE_NODE_STALE
) {
1004 (void) rcm_unregister_interest(hd
, node
->vc_resource
,
1006 rcm_log_message(RCM_DEBUG
, "VLAN: unregistered %s\n",
1008 assert(node
->vc_vlan
== NULL
);
1014 if (!(node
->vc_state
& CACHE_NODE_NEW
))
1017 if (rcm_register_interest(hd
, node
->vc_resource
, 0, NULL
) !=
1019 rcm_log_message(RCM_ERROR
,
1020 _("VLAN: failed to register %s\n"),
1024 rcm_log_message(RCM_DEBUG
, "VLAN: registered %s\n",
1026 node
->vc_state
&= ~CACHE_NODE_NEW
;
1030 (void) mutex_unlock(&cache_lock
);
1035 * cache_free() - Empty the cache
1042 rcm_log_message(RCM_TRACE2
, "VLAN: cache_free\n");
1044 (void) mutex_lock(&cache_lock
);
1045 node
= cache_head
.vc_next
;
1046 while (node
!= &cache_tail
) {
1049 node
= cache_head
.vc_next
;
1051 (void) mutex_unlock(&cache_lock
);
1055 * vlan_log_err() - RCM error log wrapper
1058 vlan_log_err(datalink_id_t linkid
, char **errorp
, char *errmsg
)
1060 char link
[MAXLINKNAMELEN
];
1061 char errstr
[DLADM_STRSIZE
];
1062 dladm_status_t status
;
1068 if (linkid
!= DATALINK_INVALID_LINKID
) {
1069 char rsrc
[RCM_LINK_RESOURCE_MAX
];
1071 (void) snprintf(rsrc
, sizeof (rsrc
), "%s/%u",
1072 RCM_LINK_PREFIX
, linkid
);
1074 rcm_log_message(RCM_ERROR
, _("VLAN: %s(%s)\n"), errmsg
, rsrc
);
1075 if ((status
= dladm_datalink_id2info(dld_handle
, linkid
, NULL
,
1076 NULL
, NULL
, link
, sizeof (link
))) != DLADM_STATUS_OK
) {
1077 rcm_log_message(RCM_WARNING
,
1078 _("VLAN: cannot get link name for (%s) %s\n"),
1079 rsrc
, dladm_status2str(status
, errstr
));
1082 rcm_log_message(RCM_ERROR
, _("VLAN: %s\n"), errmsg
);
1085 errfmt
= strlen(link
) > 0 ? _("VLAN: %s(%s)") : _("VLAN: %s");
1086 len
= strlen(errfmt
) + strlen(errmsg
) + MAXLINKNAMELEN
+ 1;
1087 if ((error
= malloc(len
)) != NULL
) {
1088 if (strlen(link
) > 0)
1089 (void) snprintf(error
, len
, errfmt
, errmsg
, link
);
1091 (void) snprintf(error
, len
, errfmt
, errmsg
);
1099 * vlan_consumer_online()
1101 * Notify online to VLAN consumers.
1105 vlan_consumer_online(rcm_handle_t
*hd
, link_cache_t
*node
, char **errorp
,
1106 uint_t flags
, rcm_info_t
**info
)
1109 char rsrc
[RCM_LINK_RESOURCE_MAX
];
1111 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_consumer_online (%s)\n",
1114 for (vlan
= node
->vc_vlan
; vlan
!= NULL
; vlan
= vlan
->dv_next
) {
1115 if (!(vlan
->dv_flags
& VLAN_CONSUMER_OFFLINED
))
1118 (void) snprintf(rsrc
, RCM_LINK_RESOURCE_MAX
, "%s/%u",
1119 RCM_LINK_PREFIX
, vlan
->dv_vlanid
);
1121 if (rcm_notify_online(hd
, rsrc
, flags
, info
) == RCM_SUCCESS
)
1122 vlan
->dv_flags
&= ~VLAN_CONSUMER_OFFLINED
;
1125 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_consumer_online done\n");
1129 * vlan_consumer_offline()
1131 * Offline VLAN consumers.
1134 vlan_consumer_offline(rcm_handle_t
*hd
, link_cache_t
*node
, char **errorp
,
1135 uint_t flags
, rcm_info_t
**info
)
1138 char rsrc
[RCM_LINK_RESOURCE_MAX
];
1139 int ret
= RCM_SUCCESS
;
1141 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_consumer_offline (%s)\n",
1144 for (vlan
= node
->vc_vlan
; vlan
!= NULL
; vlan
= vlan
->dv_next
) {
1145 (void) snprintf(rsrc
, RCM_LINK_RESOURCE_MAX
, "%s/%u",
1146 RCM_LINK_PREFIX
, vlan
->dv_vlanid
);
1148 ret
= rcm_request_offline(hd
, rsrc
, flags
, info
);
1149 if (ret
!= RCM_SUCCESS
)
1152 vlan
->dv_flags
|= VLAN_CONSUMER_OFFLINED
;
1156 vlan_consumer_online(hd
, node
, errorp
, flags
, info
);
1158 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_consumer_offline done\n");
1163 * Send RCM_RESOURCE_LINK_NEW events to other modules about new VLANs.
1164 * Return 0 on success, -1 on failure.
1167 vlan_notify_new_vlan(rcm_handle_t
*hd
, char *rsrc
)
1171 nvlist_t
*nvl
= NULL
;
1175 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_notify_new_vlan (%s)\n", rsrc
);
1177 (void) mutex_lock(&cache_lock
);
1178 if ((node
= cache_lookup(hd
, rsrc
, CACHE_REFRESH
)) == NULL
) {
1179 (void) mutex_unlock(&cache_lock
);
1183 if (nvlist_alloc(&nvl
, 0, 0) != 0) {
1184 (void) mutex_unlock(&cache_lock
);
1185 rcm_log_message(RCM_WARNING
,
1186 _("VLAN: failed to allocate nvlist\n"));
1190 for (vlan
= node
->vc_vlan
; vlan
!= NULL
; vlan
= vlan
->dv_next
) {
1191 rcm_log_message(RCM_TRACE2
,
1192 "VLAN: vlan_notify_new_vlan add (%u)\n",
1195 id
= vlan
->dv_vlanid
;
1196 if (nvlist_add_uint64(nvl
, RCM_NV_LINKID
, id
) != 0) {
1197 rcm_log_message(RCM_ERROR
,
1198 _("VLAN: failed to construct nvlist\n"));
1199 (void) mutex_unlock(&cache_lock
);
1203 (void) mutex_unlock(&cache_lock
);
1205 if (rcm_notify_event(hd
, RCM_RESOURCE_LINK_NEW
, 0, nvl
, NULL
) !=
1207 rcm_log_message(RCM_ERROR
,
1208 _("VLAN: failed to notify %s event for %s\n"),
1209 RCM_RESOURCE_LINK_NEW
, node
->vc_resource
);
1220 * vlan_consumer_notify() - Notify consumers of VLANs coming back online.
1223 vlan_consumer_notify(rcm_handle_t
*hd
, datalink_id_t linkid
, char **errorp
,
1224 uint_t flags
, rcm_info_t
**info
)
1226 char rsrc
[RCM_LINK_RESOURCE_MAX
];
1229 /* Check for the interface in the cache */
1230 (void) snprintf(rsrc
, RCM_LINK_RESOURCE_MAX
, "%s/%u", RCM_LINK_PREFIX
,
1233 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_consumer_notify(%s)\n", rsrc
);
1236 * Inform IP consumers of the new link.
1238 if (vlan_notify_new_vlan(hd
, rsrc
) != 0) {
1239 (void) mutex_lock(&cache_lock
);
1240 if ((node
= cache_lookup(hd
, rsrc
, CACHE_NO_REFRESH
)) != NULL
) {
1241 (void) vlan_offline_vlan(node
, VLAN_STALE
,
1244 (void) mutex_unlock(&cache_lock
);
1245 rcm_log_message(RCM_TRACE2
,
1246 "VLAN: vlan_notify_new_vlan failed(%s)\n", rsrc
);
1250 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_consumer_notify succeeded\n");
1254 typedef struct vlan_up_arg_s
{
1255 datalink_id_t linkid
;
1260 vlan_up(dladm_handle_t handle
, datalink_id_t vlanid
, void *arg
)
1262 vlan_up_arg_t
*vlan_up_argp
= arg
;
1263 dladm_status_t status
;
1264 dladm_vlan_attr_t vlan_attr
;
1265 char errmsg
[DLADM_STRSIZE
];
1267 status
= dladm_vlan_info(handle
, vlanid
, &vlan_attr
, DLADM_OPT_PERSIST
);
1268 if (status
!= DLADM_STATUS_OK
) {
1269 rcm_log_message(RCM_TRACE1
,
1270 "VLAN: vlan_up(): cannot get information for VLAN %u "
1271 "(%s)\n", vlanid
, dladm_status2str(status
, errmsg
));
1272 return (DLADM_WALK_CONTINUE
);
1275 if (vlan_attr
.dv_linkid
!= vlan_up_argp
->linkid
)
1276 return (DLADM_WALK_CONTINUE
);
1278 rcm_log_message(RCM_TRACE3
, "VLAN: vlan_up(%u)\n", vlanid
);
1279 if ((status
= dladm_vlan_up(handle
, vlanid
)) == DLADM_STATUS_OK
)
1280 return (DLADM_WALK_CONTINUE
);
1283 * Prompt the warning message and continue to UP other VLANs.
1285 rcm_log_message(RCM_WARNING
,
1286 _("VLAN: VLAN up failed (%u): %s\n"),
1287 vlanid
, dladm_status2str(status
, errmsg
));
1289 vlan_up_argp
->retval
= -1;
1290 return (DLADM_WALK_CONTINUE
);
1294 * vlan_configure() - Configure VLANs over a physical link after it attaches
1297 vlan_configure(rcm_handle_t
*hd
, datalink_id_t linkid
)
1299 char rsrc
[RCM_LINK_RESOURCE_MAX
];
1301 vlan_up_arg_t arg
= {DATALINK_INVALID_LINKID
, 0};
1303 /* Check for the VLANs in the cache */
1304 (void) snprintf(rsrc
, sizeof (rsrc
), "%s/%u", RCM_LINK_PREFIX
, linkid
);
1306 rcm_log_message(RCM_TRACE2
, "VLAN: vlan_configure(%s)\n", rsrc
);
1308 /* Check if the link is new or was previously offlined */
1309 (void) mutex_lock(&cache_lock
);
1310 if (((node
= cache_lookup(hd
, rsrc
, CACHE_REFRESH
)) != NULL
) &&
1311 (!(node
->vc_state
& CACHE_NODE_OFFLINED
))) {
1312 rcm_log_message(RCM_TRACE2
,
1313 "VLAN: Skipping configured interface(%s)\n", rsrc
);
1314 (void) mutex_unlock(&cache_lock
);
1317 (void) mutex_unlock(&cache_lock
);
1319 arg
.linkid
= linkid
;
1320 (void) dladm_walk_datalink_id(vlan_up
, dld_handle
, &arg
,
1321 DATALINK_CLASS_VLAN
, DATALINK_ANY_MEDIATYPE
, DLADM_OPT_PERSIST
);
1323 if (arg
.retval
== 0) {
1324 rcm_log_message(RCM_TRACE2
,
1325 "VLAN: vlan_configure succeeded(%s)\n", rsrc
);
1327 return (arg
.retval
);