xref: /illumos-gate/usr/src/cmd/rcm_daemon/common/vlan_rcm.c (revision bc1f688b4872ace323eaddbb1a6365d054e7bf56)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 /*
26  * This RCM module adds support to the RCM framework for VLAN links
27  */
28 
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>
42 
43 /*
44  * Definitions
45  */
46 #ifndef lint
47 #define	_(x)	gettext(x)
48 #else
49 #define	_(x)	x
50 #endif
51 
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)
55 
56 /* VLAN link flags */
57 typedef enum {
58 	VLAN_OFFLINED		= 0x1,
59 	VLAN_CONSUMER_OFFLINED	= 0x2,
60 	VLAN_STALE		= 0x4
61 } vlan_flag_t;
62 
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 */
69 } dl_vlan_t;
70 
71 /* VLAN Cache state flags */
72 typedef enum {
73 	CACHE_NODE_STALE	= 0x1,		/* stale cached data */
74 	CACHE_NODE_NEW		= 0x2,		/* new cached nodes */
75 	CACHE_NODE_OFFLINED	= 0x4		/* nodes offlined */
76 } cache_node_state_t;
77 
78 /* Network Cache lookup options */
79 #define	CACHE_NO_REFRESH	0x1		/* cache refresh not needed */
80 #define	CACHE_REFRESH		0x2		/* refresh cache */
81 
82 /* Cache element */
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 */
90 } link_cache_t;
91 
92 /*
93  * Global cache for network VLANs
94  */
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;
99 
100 static dladm_handle_t	dld_handle = NULL;
101 
102 /*
103  * RCM module interface prototypes
104  */
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);
122 
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,
135 			    cache_node_state_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 **);
141 
142 /* Module-Private data */
143 static struct rcm_mod_ops vlan_ops =
144 {
145 	RCM_MOD_OPS_VERSION,
146 	vlan_register,
147 	vlan_unregister,
148 	vlan_get_info,
149 	vlan_suspend,
150 	vlan_resume,
151 	vlan_offline,
152 	vlan_undo_offline,
153 	vlan_remove,
154 	NULL,
155 	NULL,
156 	vlan_notify_event
157 };
158 
159 /*
160  * rcm_mod_init() - Update registrations, and return the ops structure.
161  */
162 struct rcm_mod_ops *
163 rcm_mod_init(void)
164 {
165 	dladm_status_t status;
166 	char errmsg[DLADM_STRSIZE];
167 
168 	rcm_log_message(RCM_TRACE1, "VLAN: mod_init\n");
169 
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);
175 
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));
180 		return (NULL);
181 	}
182 
183 	/* Return the ops vectors */
184 	return (&vlan_ops);
185 }
186 
187 /*
188  * rcm_mod_info() - Return a string describing this module.
189  */
190 const char *
191 rcm_mod_info(void)
192 {
193 	rcm_log_message(RCM_TRACE1, "VLAN: mod_info\n");
194 
195 	return ("VLAN module version 1.2");
196 }
197 
198 /*
199  * rcm_mod_fini() - Destroy the network VLAN cache.
200  */
201 int
202 rcm_mod_fini(void)
203 {
204 	rcm_log_message(RCM_TRACE1, "VLAN: mod_fini\n");
205 
206 	/*
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.
211 	 */
212 	cache_free();
213 	(void) mutex_destroy(&cache_lock);
214 
215 	dladm_close(dld_handle);
216 	return (RCM_SUCCESS);
217 }
218 
219 /*
220  * vlan_register() - Make sure the cache is properly sync'ed, and its
221  *		 registrations are in order.
222  */
223 static int
224 vlan_register(rcm_handle_t *hd)
225 {
226 	rcm_log_message(RCM_TRACE1, "VLAN: register\n");
227 
228 	if (cache_update(hd) < 0)
229 		return (RCM_FAILURE);
230 
231 	/*
232 	 * Need to register interest in all new resources
233 	 * getting attached, so we get attach event notifications
234 	 */
235 	if (!events_registered) {
236 		if (rcm_register_event(hd, RCM_RESOURCE_LINK_NEW, 0, NULL)
237 		    != RCM_SUCCESS) {
238 			rcm_log_message(RCM_ERROR,
239 			    _("VLAN: failed to register %s\n"),
240 			    RCM_RESOURCE_LINK_NEW);
241 			return (RCM_FAILURE);
242 		} else {
243 			rcm_log_message(RCM_DEBUG, "VLAN: registered %s\n",
244 			    RCM_RESOURCE_LINK_NEW);
245 			events_registered++;
246 		}
247 	}
248 
249 	return (RCM_SUCCESS);
250 }
251 
252 /*
253  * vlan_unregister() - Walk the cache, unregistering all the networks.
254  */
255 static int
256 vlan_unregister(rcm_handle_t *hd)
257 {
258 	link_cache_t *node;
259 
260 	rcm_log_message(RCM_TRACE1, "VLAN: unregister\n");
261 
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)
267 		    != RCM_SUCCESS) {
268 			rcm_log_message(RCM_ERROR,
269 			    _("VLAN: failed to unregister %s\n"),
270 			    node->vc_resource);
271 			(void) mutex_unlock(&cache_lock);
272 			return (RCM_FAILURE);
273 		}
274 		cache_remove(node);
275 		node_free(node);
276 		node = cache_head.vc_next;
277 	}
278 	(void) mutex_unlock(&cache_lock);
279 
280 	/*
281 	 * Unregister interest in all new resources
282 	 */
283 	if (events_registered) {
284 		if (rcm_unregister_event(hd, RCM_RESOURCE_LINK_NEW, 0)
285 		    != RCM_SUCCESS) {
286 			rcm_log_message(RCM_ERROR,
287 			    _("VLAN: failed to unregister %s\n"),
288 			    RCM_RESOURCE_LINK_NEW);
289 			return (RCM_FAILURE);
290 		} else {
291 			rcm_log_message(RCM_DEBUG, "VLAN: unregistered %s\n",
292 			    RCM_RESOURCE_LINK_NEW);
293 			events_registered--;
294 		}
295 	}
296 
297 	return (RCM_SUCCESS);
298 }
299 
300 /*
301  * vlan_offline() - Offline VLANs on a specific node.
302  */
303 static int
304 vlan_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
305     char **errorp, rcm_info_t **info)
306 {
307 	link_cache_t *node;
308 
309 	rcm_log_message(RCM_TRACE1, "VLAN: offline(%s)\n", rsrc);
310 
311 	/* Lock the cache and lookup the resource */
312 	(void) mutex_lock(&cache_lock);
313 	node = cache_lookup(hd, rsrc, CACHE_REFRESH);
314 	if (node == NULL) {
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);
320 	}
321 
322 	/*
323 	 * Inform consumers (IP interfaces) of associated VLANs to be offlined
324 	 */
325 	if (vlan_consumer_offline(hd, node, errorp, flags, info) ==
326 	    RCM_SUCCESS) {
327 		rcm_log_message(RCM_DEBUG,
328 		    "VLAN: consumers agreed on offline\n");
329 	} else {
330 		vlan_log_err(node->vc_linkid, errorp,
331 		    "consumers failed to offline");
332 		(void) mutex_unlock(&cache_lock);
333 		return (RCM_FAILURE);
334 	}
335 
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);
342 	}
343 
344 	if (vlan_offline_vlan(node, VLAN_OFFLINED, CACHE_NODE_OFFLINED) !=
345 	    RCM_SUCCESS) {
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);
350 	}
351 
352 	rcm_log_message(RCM_TRACE1, "VLAN: Offline succeeded(%s)\n", rsrc);
353 	(void) mutex_unlock(&cache_lock);
354 	return (RCM_SUCCESS);
355 }
356 
357 /*
358  * vlan_undo_offline() - Undo offline of a previously offlined node.
359  */
360 /*ARGSUSED*/
361 static int
362 vlan_undo_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
363     char **errorp, rcm_info_t **info)
364 {
365 	link_cache_t *node;
366 
367 	rcm_log_message(RCM_TRACE1, "VLAN: online(%s)\n", rsrc);
368 
369 	(void) mutex_lock(&cache_lock);
370 	node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
371 	if (node == NULL) {
372 		vlan_log_err(DATALINK_INVALID_LINKID, errorp, "no such link");
373 		(void) mutex_unlock(&cache_lock);
374 		errno = ENOENT;
375 		return (RCM_FAILURE);
376 	}
377 
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);
382 		errno = ENOTSUP;
383 		return (RCM_SUCCESS);
384 	}
385 
386 	vlan_online_vlan(node);
387 
388 	/*
389 	 * Inform IP interfaces on associated VLANs to be onlined
390 	 */
391 	vlan_consumer_online(hd, node, errorp, flags, info);
392 
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);
397 }
398 
399 static void
400 vlan_online_vlan(link_cache_t *node)
401 {
402 	dl_vlan_t *vlan;
403 	dladm_status_t status;
404 	char errmsg[DLADM_STRSIZE];
405 
406 	/*
407 	 * Try to bring on all offlined VLANs
408 	 */
409 	for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
410 		if (!(vlan->dv_flags & VLAN_OFFLINED))
411 			continue;
412 
413 		if ((status = dladm_vlan_up(dld_handle, vlan->dv_vlanid)) !=
414 		    DLADM_STATUS_OK) {
415 			/*
416 			 * Print a warning message and continue to online
417 			 * other VLANs.
418 			 */
419 			rcm_log_message(RCM_WARNING,
420 			    _("VLAN: VLAN online failed (%u): %s\n"),
421 			    vlan->dv_vlanid, dladm_status2str(status, errmsg));
422 		} else {
423 			vlan->dv_flags &= ~VLAN_OFFLINED;
424 		}
425 	}
426 }
427 
428 static int
429 vlan_offline_vlan(link_cache_t *node, uint32_t flags, cache_node_state_t state)
430 {
431 	dl_vlan_t *vlan;
432 	dladm_status_t status;
433 	char errmsg[DLADM_STRSIZE];
434 
435 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_offline_vlan (%s %u %u)\n",
436 	    node->vc_resource, flags, state);
437 
438 	/*
439 	 * Try to delete all explicit created VLAN
440 	 */
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);
448 		} else {
449 			rcm_log_message(RCM_TRACE1,
450 			    "VLAN: VLAN offline succeeded(%u)\n",
451 			    vlan->dv_vlanid);
452 			vlan->dv_flags |= flags;
453 		}
454 	}
455 
456 	node->vc_state |= state;
457 	return (RCM_SUCCESS);
458 }
459 
460 /*
461  * vlan_get_info() - Gather usage information for this resource.
462  */
463 /*ARGSUSED*/
464 int
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)
467 {
468 	link_cache_t *node;
469 
470 	rcm_log_message(RCM_TRACE1, "VLAN: get_info(%s)\n", rsrc);
471 
472 	(void) mutex_lock(&cache_lock);
473 	node = cache_lookup(hd, rsrc, CACHE_REFRESH);
474 	if (node == NULL) {
475 		rcm_log_message(RCM_INFO,
476 		    _("VLAN: get_info(%s) unrecognized resource\n"), rsrc);
477 		(void) mutex_unlock(&cache_lock);
478 		errno = ENOENT;
479 		return (RCM_FAILURE);
480 	}
481 
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);
489 		errno = ENOMEM;
490 		return (RCM_FAILURE);
491 	}
492 
493 	/* Set client/role properties */
494 	(void) nvlist_add_string(props, RCM_CLIENT_NAME, "VLAN");
495 
496 	rcm_log_message(RCM_TRACE1, "VLAN: get_info(%s) info = %s\n",
497 	    rsrc, *usagep);
498 	return (RCM_SUCCESS);
499 }
500 
501 /*
502  * vlan_suspend() - Nothing to do, always okay
503  */
504 /*ARGSUSED*/
505 static int
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)
508 {
509 	rcm_log_message(RCM_TRACE1, "VLAN: suspend(%s)\n", rsrc);
510 	return (RCM_SUCCESS);
511 }
512 
513 /*
514  * vlan_resume() - Nothing to do, always okay
515  */
516 /*ARGSUSED*/
517 static int
518 vlan_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
519     char **errorp, rcm_info_t **info)
520 {
521 	rcm_log_message(RCM_TRACE1, "VLAN: resume(%s)\n", rsrc);
522 	return (RCM_SUCCESS);
523 }
524 
525 /*
526  * vlan_consumer_remove()
527  *
528  *	Notify VLAN consumers to remove cache.
529  */
530 static int
531 vlan_consumer_remove(rcm_handle_t *hd, link_cache_t *node, uint_t flags,
532     rcm_info_t **info)
533 {
534 	dl_vlan_t *vlan = NULL;
535 	char rsrc[RCM_LINK_RESOURCE_MAX];
536 	int ret = RCM_SUCCESS;
537 
538 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_remove (%s)\n",
539 	    node->vc_resource);
540 
541 	for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
542 
543 		/*
544 		 * This will only be called when the offline operation
545 		 * succeeds, so the VLAN consumers must have been offlined
546 		 * at this point.
547 		 */
548 		assert(vlan->dv_flags & VLAN_CONSUMER_OFFLINED);
549 
550 		(void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
551 		    RCM_LINK_PREFIX, vlan->dv_vlanid);
552 
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);
557 			break;
558 		}
559 	}
560 
561 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_remove done\n");
562 	return (ret);
563 }
564 
565 /*
566  * vlan_remove() - remove a resource from cache
567  */
568 /*ARGSUSED*/
569 static int
570 vlan_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
571     char **errorp, rcm_info_t **info)
572 {
573 	link_cache_t *node;
574 	int rv;
575 
576 	rcm_log_message(RCM_TRACE1, "VLAN: remove(%s)\n", rsrc);
577 
578 	(void) mutex_lock(&cache_lock);
579 	node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
580 	if (node == NULL) {
581 		rcm_log_message(RCM_INFO,
582 		    _("VLAN: remove(%s) unrecognized resource\n"), rsrc);
583 		(void) mutex_unlock(&cache_lock);
584 		errno = ENOENT;
585 		return (RCM_FAILURE);
586 	}
587 
588 	/* remove the cached entry for the resource */
589 	cache_remove(node);
590 	(void) mutex_unlock(&cache_lock);
591 
592 	rv = vlan_consumer_remove(hd, node, flags, info);
593 	node_free(node);
594 	return (rv);
595 }
596 
597 /*
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.
603  */
604 /*ARGSUSED*/
605 static int
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)
608 {
609 	nvpair_t	*nvp = NULL;
610 	datalink_id_t	linkid;
611 	uint64_t	id64;
612 	int		rv = RCM_SUCCESS;
613 
614 	rcm_log_message(RCM_TRACE1, "VLAN: notify_event(%s)\n", rsrc);
615 
616 	if (strcmp(rsrc, RCM_RESOURCE_LINK_NEW) != 0) {
617 		vlan_log_err(DATALINK_INVALID_LINKID, errorp,
618 		    "unrecognized event");
619 		errno = EINVAL;
620 		return (RCM_FAILURE);
621 	}
622 
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);
628 	}
629 
630 	/*
631 	 * Try best to recover all configuration.
632 	 */
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)
636 			continue;
637 
638 		if (nvpair_value_uint64(nvp, &id64) != 0) {
639 			vlan_log_err(DATALINK_INVALID_LINKID, errorp,
640 			    "cannot get linkid");
641 			rv = RCM_FAILURE;
642 			continue;
643 		}
644 
645 		linkid = (datalink_id_t)id64;
646 		if (vlan_configure(hd, linkid) != 0) {
647 			vlan_log_err(linkid, errorp, "configuring failed");
648 			rv = RCM_FAILURE;
649 			continue;
650 		}
651 
652 		/* Notify all VLAN consumers */
653 		if (vlan_consumer_notify(hd, linkid, errorp, flags,
654 		    info) != 0) {
655 			vlan_log_err(linkid, errorp, "consumer notify failed");
656 			rv = RCM_FAILURE;
657 		}
658 	}
659 
660 	rcm_log_message(RCM_TRACE1,
661 	    "VLAN: notify_event: link configuration complete\n");
662 	return (rv);
663 }
664 
665 /*
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.
669  */
670 static char *
671 vlan_usage(link_cache_t *node)
672 {
673 	dl_vlan_t *vlan;
674 	int nvlan;
675 	char *buf;
676 	const char *fmt;
677 	char *sep;
678 	char errmsg[DLADM_STRSIZE];
679 	char name[MAXLINKNAMELEN];
680 	dladm_status_t status;
681 	size_t bufsz;
682 
683 	rcm_log_message(RCM_TRACE2, "VLAN: usage(%s)\n", node->vc_resource);
684 
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));
691 		return (NULL);
692 	}
693 
694 	if (node->vc_state & CACHE_NODE_OFFLINED)
695 		fmt = _("%1$s offlined");
696 	else
697 		fmt = _("%1$s VLANs: ");
698 
699 	/* TRANSLATION_NOTE: separator used between VLAN linkids */
700 	sep = _(", ");
701 
702 	nvlan = 0;
703 	for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next)
704 		nvlan++;
705 
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));
713 		return (NULL);
714 	}
715 	(void) snprintf(buf, bufsz, fmt, name);
716 
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);
721 		return (buf);
722 	}
723 
724 	for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
725 		rcm_log_message(RCM_DEBUG, "VLAN:= %u\n", vlan->dv_vlanid);
726 
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));
734 			free(buf);
735 			return (NULL);
736 		}
737 
738 		(void) strlcat(buf, name, bufsz);
739 		if (vlan->dv_next != NULL)
740 			(void) strlcat(buf, sep, bufsz);
741 	}
742 
743 	rcm_log_message(RCM_TRACE2, "VLAN: usage (%s) info = %s\n",
744 	    node->vc_resource, buf);
745 
746 	return (buf);
747 }
748 
749 /*
750  * Cache management routines, all cache management functions should be
751  * be called with cache_lock held.
752  */
753 
754 /*
755  * cache_lookup() - Get a cache node for a resource.
756  *		  Call with cache lock held.
757  *
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.
760  */
761 static link_cache_t *
762 cache_lookup(rcm_handle_t *hd, char *rsrc, char options)
763 {
764 	link_cache_t *node;
765 
766 	rcm_log_message(RCM_TRACE2, "VLAN: cache lookup(%s)\n", rsrc);
767 
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);
774 	}
775 
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);
781 			return (node);
782 		}
783 	}
784 	return (NULL);
785 }
786 
787 /*
788  * node_free - Free a node from the cache
789  */
790 static void
791 node_free(link_cache_t *node)
792 {
793 	dl_vlan_t *vlan, *next;
794 
795 	if (node != NULL) {
796 		free(node->vc_resource);
797 
798 		/* free the VLAN list */
799 		for (vlan = node->vc_vlan; vlan != NULL; vlan = next) {
800 			next = vlan->dv_next;
801 			free(vlan);
802 		}
803 		free(node);
804 	}
805 }
806 
807 /*
808  * cache_insert - Insert a resource node in cache
809  */
810 static void
811 cache_insert(link_cache_t *node)
812 {
813 	assert(MUTEX_HELD(&cache_lock));
814 
815 	/* insert at the head for best performance */
816 	node->vc_next = cache_head.vc_next;
817 	node->vc_prev = &cache_head;
818 
819 	node->vc_next->vc_prev = node;
820 	node->vc_prev->vc_next = node;
821 }
822 
823 /*
824  * cache_remove() - Remove a resource node from cache.
825  */
826 static void
827 cache_remove(link_cache_t *node)
828 {
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;
834 }
835 
836 typedef struct vlan_update_arg_s {
837 	rcm_handle_t	*hd;
838 	int		retval;
839 } vlan_update_arg_t;
840 
841 /*
842  * vlan_update() - Update physical interface properties
843  */
844 static int
845 vlan_update(dladm_handle_t handle, datalink_id_t vlanid, void *arg)
846 {
847 	vlan_update_arg_t *vlan_update_argp = arg;
848 	rcm_handle_t *hd = vlan_update_argp->hd;
849 	link_cache_t *node;
850 	dl_vlan_t *vlan;
851 	char *rsrc;
852 	dladm_vlan_attr_t vlan_attr;
853 	dladm_status_t status;
854 	char errmsg[DLADM_STRSIZE];
855 	boolean_t newnode = B_FALSE;
856 	int ret = -1;
857 
858 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_update(%u)\n", vlanid);
859 
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);
867 	}
868 
869 	rsrc = malloc(RCM_LINK_RESOURCE_MAX);
870 	if (rsrc == NULL) {
871 		rcm_log_message(RCM_ERROR, _("VLAN: malloc error(%s): %u\n"),
872 		    strerror(errno), vlanid);
873 		goto done;
874 	}
875 
876 	(void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
877 	    RCM_LINK_PREFIX, vlan_attr.dv_linkid);
878 
879 	node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
880 	if (node != NULL) {
881 		rcm_log_message(RCM_DEBUG,
882 		    "VLAN: %s already registered (vlanid:%d)\n",
883 		    rsrc, vlan_attr.dv_vid);
884 		free(rsrc);
885 	} else {
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) {
890 			free(rsrc);
891 			rcm_log_message(RCM_ERROR, _("VLAN: calloc: %s\n"),
892 			    strerror(errno));
893 			goto done;
894 		}
895 
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;
900 		newnode = B_TRUE;
901 	}
902 
903 	for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
904 		if (vlan->dv_vlanid == vlanid) {
905 			vlan->dv_flags &= ~VLAN_STALE;
906 			break;
907 		}
908 	}
909 
910 	if (vlan == NULL) {
911 		if ((vlan = calloc(1, sizeof (dl_vlan_t))) == NULL) {
912 			rcm_log_message(RCM_ERROR, _("VLAN: malloc: %s\n"),
913 			    strerror(errno));
914 			if (newnode) {
915 				free(rsrc);
916 				free(node);
917 			}
918 			goto done;
919 		}
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;
926 	}
927 
928 	node->vc_state &= ~CACHE_NODE_STALE;
929 
930 	if (newnode)
931 		cache_insert(node);
932 
933 	rcm_log_message(RCM_TRACE3, "VLAN: vlan_update: succeeded(%u)\n",
934 	    vlanid);
935 	ret = 0;
936 done:
937 	vlan_update_argp->retval = ret;
938 	return (ret == 0 ? DLADM_WALK_CONTINUE : DLADM_WALK_TERMINATE);
939 }
940 
941 /*
942  * vlan_update_all() - Determine all VLAN links in the system
943  */
944 static int
945 vlan_update_all(rcm_handle_t *hd)
946 {
947 	vlan_update_arg_t arg = {NULL, 0};
948 
949 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_update_all\n");
950 
951 	assert(MUTEX_HELD(&cache_lock));
952 	arg.hd = hd;
953 	(void) dladm_walk_datalink_id(vlan_update, dld_handle, &arg,
954 	    DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
955 	return (arg.retval);
956 }
957 
958 /*
959  * cache_update() - Update cache with latest interface info
960  */
961 static int
962 cache_update(rcm_handle_t *hd)
963 {
964 	link_cache_t *node, *nnode;
965 	dl_vlan_t *vlan;
966 	int rv;
967 
968 	rcm_log_message(RCM_TRACE2, "VLAN: cache_update\n");
969 
970 	(void) mutex_lock(&cache_lock);
971 
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;
978 	}
979 
980 	rv = vlan_update_all(hd);
981 
982 	/*
983 	 * Continue to delete all stale nodes from the cache even
984 	 * vlan_update_all() failed. Unregister link that are not offlined
985 	 * and still in cache
986 	 */
987 	for (node = cache_head.vc_next; node != &cache_tail; node = nnode) {
988 		dl_vlan_t *vlan, *next;
989 
990 		for (vlan = node->vc_vlan; vlan != NULL; vlan = next) {
991 			next = vlan->dv_next;
992 
993 			/* clear stale VLANs */
994 			if (vlan->dv_flags & VLAN_STALE) {
995 				if (vlan->dv_prev != NULL)
996 					vlan->dv_prev->dv_next = next;
997 				else
998 					node->vc_vlan = next;
999 
1000 				if (next != NULL)
1001 					next->dv_prev = vlan->dv_prev;
1002 				free(vlan);
1003 			}
1004 		}
1005 
1006 		nnode = node->vc_next;
1007 		if (node->vc_state & CACHE_NODE_STALE) {
1008 			(void) rcm_unregister_interest(hd, node->vc_resource,
1009 			    0);
1010 			rcm_log_message(RCM_DEBUG, "VLAN: unregistered %s\n",
1011 			    node->vc_resource);
1012 			assert(node->vc_vlan == NULL);
1013 			cache_remove(node);
1014 			node_free(node);
1015 			continue;
1016 		}
1017 
1018 		if (!(node->vc_state & CACHE_NODE_NEW))
1019 			continue;
1020 
1021 		if (rcm_register_interest(hd, node->vc_resource, 0, NULL) !=
1022 		    RCM_SUCCESS) {
1023 			rcm_log_message(RCM_ERROR,
1024 			    _("VLAN: failed to register %s\n"),
1025 			    node->vc_resource);
1026 			rv = -1;
1027 		} else {
1028 			rcm_log_message(RCM_DEBUG, "VLAN: registered %s\n",
1029 			    node->vc_resource);
1030 			node->vc_state &= ~CACHE_NODE_NEW;
1031 		}
1032 	}
1033 
1034 	(void) mutex_unlock(&cache_lock);
1035 	return (rv);
1036 }
1037 
1038 /*
1039  * cache_free() - Empty the cache
1040  */
1041 static void
1042 cache_free()
1043 {
1044 	link_cache_t *node;
1045 
1046 	rcm_log_message(RCM_TRACE2, "VLAN: cache_free\n");
1047 
1048 	(void) mutex_lock(&cache_lock);
1049 	node = cache_head.vc_next;
1050 	while (node != &cache_tail) {
1051 		cache_remove(node);
1052 		node_free(node);
1053 		node = cache_head.vc_next;
1054 	}
1055 	(void) mutex_unlock(&cache_lock);
1056 }
1057 
1058 /*
1059  * vlan_log_err() - RCM error log wrapper
1060  */
1061 static void
1062 vlan_log_err(datalink_id_t linkid, char **errorp, char *errmsg)
1063 {
1064 	char link[MAXLINKNAMELEN];
1065 	char errstr[DLADM_STRSIZE];
1066 	dladm_status_t status;
1067 	int len;
1068 	const char *errfmt;
1069 	char *error;
1070 
1071 	link[0] = '\0';
1072 	if (linkid != DATALINK_INVALID_LINKID) {
1073 		char rsrc[RCM_LINK_RESOURCE_MAX];
1074 
1075 		(void) snprintf(rsrc, sizeof (rsrc), "%s/%u",
1076 		    RCM_LINK_PREFIX, linkid);
1077 
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));
1084 		}
1085 	} else {
1086 		rcm_log_message(RCM_ERROR, _("VLAN: %s\n"), errmsg);
1087 	}
1088 
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);
1094 		else
1095 			(void) snprintf(error, len, errfmt, errmsg);
1096 	}
1097 
1098 	if (errorp != NULL)
1099 		*errorp = error;
1100 }
1101 
1102 /*
1103  * vlan_consumer_online()
1104  *
1105  *	Notify online to VLAN consumers.
1106  */
1107 /* ARGSUSED */
1108 static void
1109 vlan_consumer_online(rcm_handle_t *hd, link_cache_t *node, char **errorp,
1110     uint_t flags, rcm_info_t **info)
1111 {
1112 	dl_vlan_t *vlan;
1113 	char rsrc[RCM_LINK_RESOURCE_MAX];
1114 
1115 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_online (%s)\n",
1116 	    node->vc_resource);
1117 
1118 	for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
1119 		if (!(vlan->dv_flags & VLAN_CONSUMER_OFFLINED))
1120 			continue;
1121 
1122 		(void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
1123 		    RCM_LINK_PREFIX, vlan->dv_vlanid);
1124 
1125 		if (rcm_notify_online(hd, rsrc, flags, info) == RCM_SUCCESS)
1126 			vlan->dv_flags &= ~VLAN_CONSUMER_OFFLINED;
1127 	}
1128 
1129 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_online done\n");
1130 }
1131 
1132 /*
1133  * vlan_consumer_offline()
1134  *
1135  *	Offline VLAN consumers.
1136  */
1137 static int
1138 vlan_consumer_offline(rcm_handle_t *hd, link_cache_t *node, char **errorp,
1139     uint_t flags, rcm_info_t **info)
1140 {
1141 	dl_vlan_t *vlan;
1142 	char rsrc[RCM_LINK_RESOURCE_MAX];
1143 	int ret = RCM_SUCCESS;
1144 
1145 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_offline (%s)\n",
1146 	    node->vc_resource);
1147 
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);
1151 
1152 		ret = rcm_request_offline(hd, rsrc, flags, info);
1153 		if (ret != RCM_SUCCESS)
1154 			break;
1155 
1156 		vlan->dv_flags |= VLAN_CONSUMER_OFFLINED;
1157 	}
1158 
1159 	if (vlan != NULL)
1160 		vlan_consumer_online(hd, node, errorp, flags, info);
1161 
1162 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_offline done\n");
1163 	return (ret);
1164 }
1165 
1166 /*
1167  * Send RCM_RESOURCE_LINK_NEW events to other modules about new VLANs.
1168  * Return 0 on success, -1 on failure.
1169  */
1170 static int
1171 vlan_notify_new_vlan(rcm_handle_t *hd, char *rsrc)
1172 {
1173 	link_cache_t *node;
1174 	dl_vlan_t *vlan;
1175 	nvlist_t *nvl = NULL;
1176 	uint64_t id;
1177 	int ret = -1;
1178 
1179 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_notify_new_vlan (%s)\n", rsrc);
1180 
1181 	(void) mutex_lock(&cache_lock);
1182 	if ((node = cache_lookup(hd, rsrc, CACHE_REFRESH)) == NULL) {
1183 		(void) mutex_unlock(&cache_lock);
1184 		return (0);
1185 	}
1186 
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"));
1191 		goto done;
1192 	}
1193 
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",
1197 		    vlan->dv_vlanid);
1198 
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);
1204 			goto done;
1205 		}
1206 	}
1207 	(void) mutex_unlock(&cache_lock);
1208 
1209 	if (rcm_notify_event(hd, RCM_RESOURCE_LINK_NEW, 0, nvl, NULL) !=
1210 	    RCM_SUCCESS) {
1211 		rcm_log_message(RCM_ERROR,
1212 		    _("VLAN: failed to notify %s event for %s\n"),
1213 		    RCM_RESOURCE_LINK_NEW, node->vc_resource);
1214 		goto done;
1215 	}
1216 
1217 	ret = 0;
1218 done:
1219 	nvlist_free(nvl);
1220 	return (ret);
1221 }
1222 
1223 /*
1224  * vlan_consumer_notify() - Notify consumers of VLANs coming back online.
1225  */
1226 static int
1227 vlan_consumer_notify(rcm_handle_t *hd, datalink_id_t linkid, char **errorp,
1228     uint_t flags, rcm_info_t **info)
1229 {
1230 	char rsrc[RCM_LINK_RESOURCE_MAX];
1231 	link_cache_t *node;
1232 
1233 	/* Check for the interface in the cache */
1234 	(void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u", RCM_LINK_PREFIX,
1235 	    linkid);
1236 
1237 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_notify(%s)\n", rsrc);
1238 
1239 	/*
1240 	 * Inform IP consumers of the new link.
1241 	 */
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,
1246 			    CACHE_NODE_STALE);
1247 		}
1248 		(void) mutex_unlock(&cache_lock);
1249 		rcm_log_message(RCM_TRACE2,
1250 		    "VLAN: vlan_notify_new_vlan failed(%s)\n", rsrc);
1251 		return (-1);
1252 	}
1253 
1254 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_notify succeeded\n");
1255 	return (0);
1256 }
1257 
1258 typedef struct vlan_up_arg_s {
1259 	datalink_id_t	linkid;
1260 	int		retval;
1261 } vlan_up_arg_t;
1262 
1263 static int
1264 vlan_up(dladm_handle_t handle, datalink_id_t vlanid, void *arg)
1265 {
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];
1270 
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);
1277 	}
1278 
1279 	if (vlan_attr.dv_linkid != vlan_up_argp->linkid)
1280 		return (DLADM_WALK_CONTINUE);
1281 
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);
1285 
1286 	/*
1287 	 * Prompt the warning message and continue to UP other VLANs.
1288 	 */
1289 	rcm_log_message(RCM_WARNING,
1290 	    _("VLAN: VLAN up failed (%u): %s\n"),
1291 	    vlanid, dladm_status2str(status, errmsg));
1292 
1293 	vlan_up_argp->retval = -1;
1294 	return (DLADM_WALK_CONTINUE);
1295 }
1296 
1297 /*
1298  * vlan_configure() - Configure VLANs over a physical link after it attaches
1299  */
1300 static int
1301 vlan_configure(rcm_handle_t *hd, datalink_id_t linkid)
1302 {
1303 	char rsrc[RCM_LINK_RESOURCE_MAX];
1304 	link_cache_t *node;
1305 	vlan_up_arg_t arg = {DATALINK_INVALID_LINKID, 0};
1306 
1307 	/* Check for the VLANs in the cache */
1308 	(void) snprintf(rsrc, sizeof (rsrc), "%s/%u", RCM_LINK_PREFIX, linkid);
1309 
1310 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_configure(%s)\n", rsrc);
1311 
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);
1319 		return (0);
1320 	}
1321 	(void) mutex_unlock(&cache_lock);
1322 
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);
1326 
1327 	if (arg.retval == 0) {
1328 		rcm_log_message(RCM_TRACE2,
1329 		    "VLAN: vlan_configure succeeded(%s)\n", rsrc);
1330 	}
1331 	return (arg.retval);
1332 }
1333