dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / rcm_daemon / common / vlan_rcm.c
blob55c698f85229619797caaa0f5b83fcd659f8140b
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
26 * This RCM module adds support to the RCM framework for VLAN links
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <synch.h>
35 #include <assert.h>
36 #include <strings.h>
37 #include "rcm_module.h"
38 #include <libintl.h>
39 #include <libdllink.h>
40 #include <libdlvlan.h>
41 #include <libdlpi.h>
44 * Definitions
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)
52 /* VLAN link flags */
53 typedef enum {
54 VLAN_OFFLINED = 0x1,
55 VLAN_CONSUMER_OFFLINED = 0x2,
56 VLAN_STALE = 0x4
57 } vlan_flag_t;
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 */
65 } dl_vlan_t;
67 /* VLAN Cache state flags */
68 typedef enum {
69 CACHE_NODE_STALE = 0x1, /* stale cached data */
70 CACHE_NODE_NEW = 0x2, /* new cached nodes */
71 CACHE_NODE_OFFLINED = 0x4 /* nodes offlined */
72 } cache_node_state_t;
74 /* Network Cache lookup options */
75 #define CACHE_NO_REFRESH 0x1 /* cache refresh not needed */
76 #define CACHE_REFRESH 0x2 /* refresh cache */
78 /* Cache element */
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 */
86 } link_cache_t;
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,
131 cache_node_state_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 =
141 RCM_MOD_OPS_VERSION,
142 vlan_register,
143 vlan_unregister,
144 vlan_get_info,
145 vlan_suspend,
146 vlan_resume,
147 vlan_offline,
148 vlan_undo_offline,
149 vlan_remove,
150 NULL,
151 NULL,
152 vlan_notify_event
156 * rcm_mod_init() - Update registrations, and return the ops structure.
158 struct rcm_mod_ops *
159 rcm_mod_init(void)
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));
176 return (NULL);
179 /* Return the ops vectors */
180 return (&vlan_ops);
184 * rcm_mod_info() - Return a string describing this module.
186 const char *
187 rcm_mod_info(void)
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.
198 rcm_mod_fini(void)
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.
208 cache_free();
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.
219 static int
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)
233 != RCM_SUCCESS) {
234 rcm_log_message(RCM_ERROR,
235 _("VLAN: failed to register %s\n"),
236 RCM_RESOURCE_LINK_NEW);
237 return (RCM_FAILURE);
238 } else {
239 rcm_log_message(RCM_DEBUG, "VLAN: registered %s\n",
240 RCM_RESOURCE_LINK_NEW);
241 events_registered++;
245 return (RCM_SUCCESS);
249 * vlan_unregister() - Walk the cache, unregistering all the networks.
251 static int
252 vlan_unregister(rcm_handle_t *hd)
254 link_cache_t *node;
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)
263 != RCM_SUCCESS) {
264 rcm_log_message(RCM_ERROR,
265 _("VLAN: failed to unregister %s\n"),
266 node->vc_resource);
267 (void) mutex_unlock(&cache_lock);
268 return (RCM_FAILURE);
270 cache_remove(node);
271 node_free(node);
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)
281 != RCM_SUCCESS) {
282 rcm_log_message(RCM_ERROR,
283 _("VLAN: failed to unregister %s\n"),
284 RCM_RESOURCE_LINK_NEW);
285 return (RCM_FAILURE);
286 } else {
287 rcm_log_message(RCM_DEBUG, "VLAN: unregistered %s\n",
288 RCM_RESOURCE_LINK_NEW);
289 events_registered--;
293 return (RCM_SUCCESS);
297 * vlan_offline() - Offline VLANs on a specific node.
299 static int
300 vlan_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
301 char **errorp, rcm_info_t **info)
303 link_cache_t *node;
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);
310 if (node == NULL) {
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) ==
322 RCM_SUCCESS) {
323 rcm_log_message(RCM_DEBUG,
324 "VLAN: consumers agreed on offline\n");
325 } else {
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) !=
341 RCM_SUCCESS) {
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.
356 /*ARGSUSED*/
357 static int
358 vlan_undo_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
359 char **errorp, rcm_info_t **info)
361 link_cache_t *node;
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);
367 if (node == NULL) {
368 vlan_log_err(DATALINK_INVALID_LINKID, errorp, "no such link");
369 (void) mutex_unlock(&cache_lock);
370 errno = ENOENT;
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);
378 errno = ENOTSUP;
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);
395 static void
396 vlan_online_vlan(link_cache_t *node)
398 dl_vlan_t *vlan;
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))
407 continue;
409 if ((status = dladm_vlan_up(dld_handle, vlan->dv_vlanid)) !=
410 DLADM_STATUS_OK) {
412 * Print a warning message and continue to online
413 * other VLANs.
415 rcm_log_message(RCM_WARNING,
416 _("VLAN: VLAN online failed (%u): %s\n"),
417 vlan->dv_vlanid, dladm_status2str(status, errmsg));
418 } else {
419 vlan->dv_flags &= ~VLAN_OFFLINED;
424 static int
425 vlan_offline_vlan(link_cache_t *node, uint32_t flags, cache_node_state_t state)
427 dl_vlan_t *vlan;
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);
444 } else {
445 rcm_log_message(RCM_TRACE1,
446 "VLAN: VLAN offline succeeded(%u)\n",
447 vlan->dv_vlanid);
448 vlan->dv_flags |= flags;
452 node->vc_state |= state;
453 return (RCM_SUCCESS);
457 * vlan_get_info() - Gather usage information for this resource.
459 /*ARGSUSED*/
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)
464 link_cache_t *node;
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);
470 if (node == NULL) {
471 rcm_log_message(RCM_INFO,
472 _("VLAN: get_info(%s) unrecognized resource\n"), rsrc);
473 (void) mutex_unlock(&cache_lock);
474 errno = ENOENT;
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);
485 errno = ENOMEM;
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",
493 rsrc, *usagep);
494 return (RCM_SUCCESS);
498 * vlan_suspend() - Nothing to do, always okay
500 /*ARGSUSED*/
501 static int
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
512 /*ARGSUSED*/
513 static int
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.
526 static int
527 vlan_consumer_remove(rcm_handle_t *hd, link_cache_t *node, uint_t flags,
528 rcm_info_t **info)
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",
535 node->vc_resource);
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
542 * at this point.
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);
553 break;
557 rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_remove done\n");
558 return (ret);
562 * vlan_remove() - remove a resource from cache
564 /*ARGSUSED*/
565 static int
566 vlan_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
567 char **errorp, rcm_info_t **info)
569 link_cache_t *node;
570 int rv;
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);
576 if (node == NULL) {
577 rcm_log_message(RCM_INFO,
578 _("VLAN: remove(%s) unrecognized resource\n"), rsrc);
579 (void) mutex_unlock(&cache_lock);
580 errno = ENOENT;
581 return (RCM_FAILURE);
584 /* remove the cached entry for the resource */
585 cache_remove(node);
586 (void) mutex_unlock(&cache_lock);
588 rv = vlan_consumer_remove(hd, node, flags, info);
589 node_free(node);
590 return (rv);
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.
600 /*ARGSUSED*/
601 static int
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;
607 uint64_t id64;
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");
615 errno = EINVAL;
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)
632 continue;
634 if (nvpair_value_uint64(nvp, &id64) != 0) {
635 vlan_log_err(DATALINK_INVALID_LINKID, errorp,
636 "cannot get linkid");
637 rv = RCM_FAILURE;
638 continue;
641 linkid = (datalink_id_t)id64;
642 if (vlan_configure(hd, linkid) != 0) {
643 vlan_log_err(linkid, errorp, "configuring failed");
644 rv = RCM_FAILURE;
645 continue;
648 /* Notify all VLAN consumers */
649 if (vlan_consumer_notify(hd, linkid, errorp, flags,
650 info) != 0) {
651 vlan_log_err(linkid, errorp, "consumer notify failed");
652 rv = RCM_FAILURE;
656 rcm_log_message(RCM_TRACE1,
657 "VLAN: notify_event: link configuration complete\n");
658 return (rv);
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.
666 static char *
667 vlan_usage(link_cache_t *node)
669 dl_vlan_t *vlan;
670 int nvlan;
671 char *buf;
672 const char *fmt;
673 char *sep;
674 char errmsg[DLADM_STRSIZE];
675 char name[MAXLINKNAMELEN];
676 dladm_status_t status;
677 size_t bufsz;
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));
687 return (NULL);
690 if (node->vc_state & CACHE_NODE_OFFLINED)
691 fmt = _("%1$s offlined");
692 else
693 fmt = _("%1$s VLANs: ");
695 /* TRANSLATION_NOTE: separator used between VLAN linkids */
696 sep = _(", ");
698 nvlan = 0;
699 for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next)
700 nvlan++;
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));
709 return (NULL);
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);
717 return (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));
730 free(buf);
731 return (NULL);
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);
742 return (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)
760 link_cache_t *node;
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);
777 return (node);
780 return (NULL);
784 * node_free - Free a node from the cache
786 static void
787 node_free(link_cache_t *node)
789 dl_vlan_t *vlan, *next;
791 if (node != NULL) {
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;
797 free(vlan);
799 free(node);
804 * cache_insert - Insert a resource node in cache
806 static void
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.
822 static void
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 {
833 rcm_handle_t *hd;
834 int retval;
835 } vlan_update_arg_t;
838 * vlan_update() - Update physical interface properties
840 static int
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;
845 link_cache_t *node;
846 dl_vlan_t *vlan;
847 char *rsrc;
848 dladm_vlan_attr_t vlan_attr;
849 dladm_status_t status;
850 char errmsg[DLADM_STRSIZE];
851 boolean_t newnode = B_FALSE;
852 int ret = -1;
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);
866 if (rsrc == NULL) {
867 rcm_log_message(RCM_ERROR, _("VLAN: malloc error(%s): %u\n"),
868 strerror(errno), vlanid);
869 goto done;
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);
876 if (node != NULL) {
877 rcm_log_message(RCM_DEBUG,
878 "VLAN: %s already registered (vlanid:%d)\n",
879 rsrc, vlan_attr.dv_vid);
880 free(rsrc);
881 } else {
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) {
886 free(rsrc);
887 rcm_log_message(RCM_ERROR, _("VLAN: calloc: %s\n"),
888 strerror(errno));
889 goto done;
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;
896 newnode = B_TRUE;
899 for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
900 if (vlan->dv_vlanid == vlanid) {
901 vlan->dv_flags &= ~VLAN_STALE;
902 break;
906 if (vlan == NULL) {
907 if ((vlan = calloc(1, sizeof (dl_vlan_t))) == NULL) {
908 rcm_log_message(RCM_ERROR, _("VLAN: malloc: %s\n"),
909 strerror(errno));
910 if (newnode) {
911 free(rsrc);
912 free(node);
914 goto done;
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;
926 if (newnode)
927 cache_insert(node);
929 rcm_log_message(RCM_TRACE3, "VLAN: vlan_update: succeeded(%u)\n",
930 vlanid);
931 ret = 0;
932 done:
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
940 static int
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));
948 arg.hd = hd;
949 (void) dladm_walk_datalink_id(vlan_update, dld_handle, &arg,
950 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
951 return (arg.retval);
955 * cache_update() - Update cache with latest interface info
957 static int
958 cache_update(rcm_handle_t *hd)
960 link_cache_t *node, *nnode;
961 dl_vlan_t *vlan;
962 int rv;
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
981 * and still in cache
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;
993 else
994 node->vc_vlan = next;
996 if (next != NULL)
997 next->dv_prev = vlan->dv_prev;
998 free(vlan);
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",
1007 node->vc_resource);
1008 assert(node->vc_vlan == NULL);
1009 cache_remove(node);
1010 node_free(node);
1011 continue;
1014 if (!(node->vc_state & CACHE_NODE_NEW))
1015 continue;
1017 if (rcm_register_interest(hd, node->vc_resource, 0, NULL) !=
1018 RCM_SUCCESS) {
1019 rcm_log_message(RCM_ERROR,
1020 _("VLAN: failed to register %s\n"),
1021 node->vc_resource);
1022 rv = -1;
1023 } else {
1024 rcm_log_message(RCM_DEBUG, "VLAN: registered %s\n",
1025 node->vc_resource);
1026 node->vc_state &= ~CACHE_NODE_NEW;
1030 (void) mutex_unlock(&cache_lock);
1031 return (rv);
1035 * cache_free() - Empty the cache
1037 static void
1038 cache_free()
1040 link_cache_t *node;
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) {
1047 cache_remove(node);
1048 node_free(node);
1049 node = cache_head.vc_next;
1051 (void) mutex_unlock(&cache_lock);
1055 * vlan_log_err() - RCM error log wrapper
1057 static void
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;
1063 int len;
1064 const char *errfmt;
1065 char *error;
1067 link[0] = '\0';
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));
1081 } else {
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);
1090 else
1091 (void) snprintf(error, len, errfmt, errmsg);
1094 if (errorp != NULL)
1095 *errorp = error;
1099 * vlan_consumer_online()
1101 * Notify online to VLAN consumers.
1103 /* ARGSUSED */
1104 static void
1105 vlan_consumer_online(rcm_handle_t *hd, link_cache_t *node, char **errorp,
1106 uint_t flags, rcm_info_t **info)
1108 dl_vlan_t *vlan;
1109 char rsrc[RCM_LINK_RESOURCE_MAX];
1111 rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_online (%s)\n",
1112 node->vc_resource);
1114 for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
1115 if (!(vlan->dv_flags & VLAN_CONSUMER_OFFLINED))
1116 continue;
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.
1133 static int
1134 vlan_consumer_offline(rcm_handle_t *hd, link_cache_t *node, char **errorp,
1135 uint_t flags, rcm_info_t **info)
1137 dl_vlan_t *vlan;
1138 char rsrc[RCM_LINK_RESOURCE_MAX];
1139 int ret = RCM_SUCCESS;
1141 rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_offline (%s)\n",
1142 node->vc_resource);
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)
1150 break;
1152 vlan->dv_flags |= VLAN_CONSUMER_OFFLINED;
1155 if (vlan != NULL)
1156 vlan_consumer_online(hd, node, errorp, flags, info);
1158 rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_offline done\n");
1159 return (ret);
1163 * Send RCM_RESOURCE_LINK_NEW events to other modules about new VLANs.
1164 * Return 0 on success, -1 on failure.
1166 static int
1167 vlan_notify_new_vlan(rcm_handle_t *hd, char *rsrc)
1169 link_cache_t *node;
1170 dl_vlan_t *vlan;
1171 nvlist_t *nvl = NULL;
1172 uint64_t id;
1173 int ret = -1;
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);
1180 return (0);
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"));
1187 goto done;
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",
1193 vlan->dv_vlanid);
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);
1200 goto done;
1203 (void) mutex_unlock(&cache_lock);
1205 if (rcm_notify_event(hd, RCM_RESOURCE_LINK_NEW, 0, nvl, NULL) !=
1206 RCM_SUCCESS) {
1207 rcm_log_message(RCM_ERROR,
1208 _("VLAN: failed to notify %s event for %s\n"),
1209 RCM_RESOURCE_LINK_NEW, node->vc_resource);
1210 goto done;
1213 ret = 0;
1214 done:
1215 nvlist_free(nvl);
1216 return (ret);
1220 * vlan_consumer_notify() - Notify consumers of VLANs coming back online.
1222 static int
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];
1227 link_cache_t *node;
1229 /* Check for the interface in the cache */
1230 (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u", RCM_LINK_PREFIX,
1231 linkid);
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,
1242 CACHE_NODE_STALE);
1244 (void) mutex_unlock(&cache_lock);
1245 rcm_log_message(RCM_TRACE2,
1246 "VLAN: vlan_notify_new_vlan failed(%s)\n", rsrc);
1247 return (-1);
1250 rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_notify succeeded\n");
1251 return (0);
1254 typedef struct vlan_up_arg_s {
1255 datalink_id_t linkid;
1256 int retval;
1257 } vlan_up_arg_t;
1259 static int
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
1296 static int
1297 vlan_configure(rcm_handle_t *hd, datalink_id_t linkid)
1299 char rsrc[RCM_LINK_RESOURCE_MAX];
1300 link_cache_t *node;
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);
1315 return (0);
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);