xref: /illumos-gate/usr/src/cmd/rcm_daemon/common/vlan_rcm.c (revision 628e3cbed6489fa1db545d8524a06cd6535af456)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * This RCM module adds support to the RCM framework for VLAN links
30  */
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <sys/types.h>
37 #include <synch.h>
38 #include <assert.h>
39 #include <strings.h>
40 #include "rcm_module.h"
41 #include <libintl.h>
42 #include <libdllink.h>
43 #include <libdlvlan.h>
44 #include <libdlpi.h>
45 
46 /*
47  * Definitions
48  */
49 #ifndef lint
50 #define	_(x)	gettext(x)
51 #else
52 #define	_(x)	x
53 #endif
54 
55 /* Some generic well-knowns and defaults used in this module */
56 #define	RCM_LINK_PREFIX		"SUNW_datalink"	/* RCM datalink name prefix */
57 #define	RCM_LINK_RESOURCE_MAX	(13 + LINKID_STR_WIDTH)
58 
59 /* VLAN link flags */
60 typedef enum {
61 	VLAN_OFFLINED		= 0x1,
62 	VLAN_CONSUMER_OFFLINED	= 0x2,
63 	VLAN_STALE		= 0x4
64 } vlan_flag_t;
65 
66 /* link representation */
67 typedef struct dl_vlan {
68 	struct dl_vlan	*dv_next;		/* next VLAN on the same link */
69 	struct dl_vlan	*dv_prev;		/* prev VLAN on the same link */
70 	datalink_id_t	dv_vlanid;
71 	boolean_t	dv_implicit;
72 	vlan_flag_t	dv_flags;		/* VLAN link flags */
73 } dl_vlan_t;
74 
75 /* VLAN Cache state flags */
76 typedef enum {
77 	CACHE_NODE_STALE	= 0x1,		/* stale cached data */
78 	CACHE_NODE_NEW		= 0x2,		/* new cached nodes */
79 	CACHE_NODE_OFFLINED	= 0x4		/* nodes offlined */
80 } cache_node_state_t;
81 
82 /* Network Cache lookup options */
83 #define	CACHE_NO_REFRESH	0x1		/* cache refresh not needed */
84 #define	CACHE_REFRESH		0x2		/* refresh cache */
85 
86 /* Cache element */
87 typedef struct link_cache {
88 	struct link_cache	*vc_next;	/* next cached resource */
89 	struct link_cache	*vc_prev;	/* prev cached resource */
90 	char			*vc_resource;	/* resource name */
91 	datalink_id_t		vc_linkid;	/* linkid */
92 	dl_vlan_t		*vc_vlan;	/* VLAN list on this link */
93 	cache_node_state_t	vc_state;	/* cache state flags */
94 } link_cache_t;
95 
96 /*
97  * Global cache for network VLANs
98  */
99 static link_cache_t	cache_head;
100 static link_cache_t	cache_tail;
101 static mutex_t		cache_lock;
102 static int		events_registered = 0;
103 
104 /*
105  * RCM module interface prototypes
106  */
107 static int		vlan_register(rcm_handle_t *);
108 static int		vlan_unregister(rcm_handle_t *);
109 static int		vlan_get_info(rcm_handle_t *, char *, id_t, uint_t,
110 			    char **, char **, nvlist_t *, rcm_info_t **);
111 static int		vlan_suspend(rcm_handle_t *, char *, id_t,
112 			    timespec_t *, uint_t, char **, rcm_info_t **);
113 static int		vlan_resume(rcm_handle_t *, char *, id_t, uint_t,
114 			    char **, rcm_info_t **);
115 static int		vlan_offline(rcm_handle_t *, char *, id_t, uint_t,
116 			    char **, rcm_info_t **);
117 static int		vlan_undo_offline(rcm_handle_t *, char *, id_t, uint_t,
118 			    char **, rcm_info_t **);
119 static int		vlan_remove(rcm_handle_t *, char *, id_t, uint_t,
120 			    char **, rcm_info_t **);
121 static int		vlan_notify_event(rcm_handle_t *, char *, id_t, uint_t,
122 			    char **, nvlist_t *, rcm_info_t **);
123 static int		vlan_configure(rcm_handle_t *, datalink_id_t);
124 
125 /* Module private routines */
126 static void 		cache_free();
127 static int 		cache_update(rcm_handle_t *);
128 static void 		cache_remove(link_cache_t *);
129 static void 		node_free(link_cache_t *);
130 static void 		cache_insert(link_cache_t *);
131 static link_cache_t	*cache_lookup(rcm_handle_t *, char *, char);
132 static int		vlan_consumer_offline(rcm_handle_t *, link_cache_t *,
133 			    char **, uint_t, rcm_info_t **);
134 static void		vlan_consumer_online(rcm_handle_t *, link_cache_t *,
135 			    char **, uint_t, rcm_info_t **);
136 static int		vlan_offline_vlan(link_cache_t *, uint32_t,
137 			    cache_node_state_t);
138 static void		vlan_online_vlan(link_cache_t *);
139 static char 		*vlan_usage(link_cache_t *);
140 static void 		vlan_log_err(datalink_id_t, char **, char *);
141 static int		vlan_consumer_notify(rcm_handle_t *, datalink_id_t,
142 			    char **, uint_t, rcm_info_t **);
143 
144 /* Module-Private data */
145 static struct rcm_mod_ops vlan_ops =
146 {
147 	RCM_MOD_OPS_VERSION,
148 	vlan_register,
149 	vlan_unregister,
150 	vlan_get_info,
151 	vlan_suspend,
152 	vlan_resume,
153 	vlan_offline,
154 	vlan_undo_offline,
155 	vlan_remove,
156 	NULL,
157 	NULL,
158 	vlan_notify_event
159 };
160 
161 /*
162  * rcm_mod_init() - Update registrations, and return the ops structure.
163  */
164 struct rcm_mod_ops *
165 rcm_mod_init(void)
166 {
167 	rcm_log_message(RCM_TRACE1, "VLAN: mod_init\n");
168 
169 	cache_head.vc_next = &cache_tail;
170 	cache_head.vc_prev = NULL;
171 	cache_tail.vc_prev = &cache_head;
172 	cache_tail.vc_next = NULL;
173 	(void) mutex_init(&cache_lock, 0, NULL);
174 
175 	/* Return the ops vectors */
176 	return (&vlan_ops);
177 }
178 
179 /*
180  * rcm_mod_info() - Return a string describing this module.
181  */
182 const char *
183 rcm_mod_info(void)
184 {
185 	rcm_log_message(RCM_TRACE1, "VLAN: mod_info\n");
186 
187 	return ("VLAN module version 1.2");
188 }
189 
190 /*
191  * rcm_mod_fini() - Destroy the network VLAN cache.
192  */
193 int
194 rcm_mod_fini(void)
195 {
196 	rcm_log_message(RCM_TRACE1, "VLAN: mod_fini\n");
197 
198 	/*
199 	 * Note that vlan_unregister() does not seem to be called anywhere,
200 	 * therefore we free the cache nodes here. In theory we should call
201 	 * rcm_register_interest() for each node before we free it, the
202 	 * framework does not provide the rcm_handle to allow us to do so.
203 	 */
204 	cache_free();
205 	(void) mutex_destroy(&cache_lock);
206 	return (RCM_SUCCESS);
207 }
208 
209 /*
210  * vlan_register() - Make sure the cache is properly sync'ed, and its
211  *		 registrations are in order.
212  */
213 static int
214 vlan_register(rcm_handle_t *hd)
215 {
216 	rcm_log_message(RCM_TRACE1, "VLAN: register\n");
217 
218 	if (cache_update(hd) < 0)
219 		return (RCM_FAILURE);
220 
221 	/*
222 	 * Need to register interest in all new resources
223 	 * getting attached, so we get attach event notifications
224 	 */
225 	if (!events_registered) {
226 		if (rcm_register_event(hd, RCM_RESOURCE_LINK_NEW, 0, NULL)
227 		    != RCM_SUCCESS) {
228 			rcm_log_message(RCM_ERROR,
229 			    _("VLAN: failed to register %s\n"),
230 			    RCM_RESOURCE_LINK_NEW);
231 			return (RCM_FAILURE);
232 		} else {
233 			rcm_log_message(RCM_DEBUG, "VLAN: registered %s\n",
234 			    RCM_RESOURCE_LINK_NEW);
235 			events_registered++;
236 		}
237 	}
238 
239 	return (RCM_SUCCESS);
240 }
241 
242 /*
243  * vlan_unregister() - Walk the cache, unregistering all the networks.
244  */
245 static int
246 vlan_unregister(rcm_handle_t *hd)
247 {
248 	link_cache_t *node;
249 
250 	rcm_log_message(RCM_TRACE1, "VLAN: unregister\n");
251 
252 	/* Walk the cache, unregistering everything */
253 	(void) mutex_lock(&cache_lock);
254 	node = cache_head.vc_next;
255 	while (node != &cache_tail) {
256 		if (rcm_unregister_interest(hd, node->vc_resource, 0)
257 		    != RCM_SUCCESS) {
258 			rcm_log_message(RCM_ERROR,
259 			    _("VLAN: failed to unregister %s\n"),
260 			    node->vc_resource);
261 			(void) mutex_unlock(&cache_lock);
262 			return (RCM_FAILURE);
263 		}
264 		cache_remove(node);
265 		node_free(node);
266 		node = cache_head.vc_next;
267 	}
268 	(void) mutex_unlock(&cache_lock);
269 
270 	/*
271 	 * Unregister interest in all new resources
272 	 */
273 	if (events_registered) {
274 		if (rcm_unregister_event(hd, RCM_RESOURCE_LINK_NEW, 0)
275 		    != RCM_SUCCESS) {
276 			rcm_log_message(RCM_ERROR,
277 			    _("VLAN: failed to unregister %s\n"),
278 			    RCM_RESOURCE_LINK_NEW);
279 			return (RCM_FAILURE);
280 		} else {
281 			rcm_log_message(RCM_DEBUG, "VLAN: unregistered %s\n",
282 			    RCM_RESOURCE_LINK_NEW);
283 			events_registered--;
284 		}
285 	}
286 
287 	return (RCM_SUCCESS);
288 }
289 
290 /*
291  * vlan_offline() - Offline VLANs on a specific node.
292  */
293 static int
294 vlan_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
295     char **errorp, rcm_info_t **info)
296 {
297 	link_cache_t *node;
298 
299 	rcm_log_message(RCM_TRACE1, "VLAN: offline(%s)\n", rsrc);
300 
301 	/* Lock the cache and lookup the resource */
302 	(void) mutex_lock(&cache_lock);
303 	node = cache_lookup(hd, rsrc, CACHE_REFRESH);
304 	if (node == NULL) {
305 		/* should not happen because the resource is registered. */
306 		vlan_log_err(node->vc_linkid, errorp, "unrecognized resource");
307 		(void) mutex_unlock(&cache_lock);
308 		return (RCM_SUCCESS);
309 	}
310 
311 	/*
312 	 * Inform consumers (IP interfaces) of associated VLANs to be offlined
313 	 */
314 	if (vlan_consumer_offline(hd, node, errorp, flags, info) ==
315 	    RCM_SUCCESS) {
316 		rcm_log_message(RCM_DEBUG,
317 		    "VLAN: consumers agreed on offline\n");
318 	} else {
319 		vlan_log_err(node->vc_linkid, errorp,
320 		    "consumers failed to offline");
321 		(void) mutex_unlock(&cache_lock);
322 		return (RCM_FAILURE);
323 	}
324 
325 	/* Check if it's a query */
326 	if (flags & RCM_QUERY) {
327 		rcm_log_message(RCM_TRACE1,
328 		    "VLAN: offline query succeeded(%s)\n", rsrc);
329 		(void) mutex_unlock(&cache_lock);
330 		return (RCM_SUCCESS);
331 	}
332 
333 	if (vlan_offline_vlan(node, VLAN_OFFLINED, CACHE_NODE_OFFLINED) !=
334 	    RCM_SUCCESS) {
335 		vlan_online_vlan(node);
336 		vlan_log_err(node->vc_linkid, errorp, "offline failed");
337 		(void) mutex_unlock(&cache_lock);
338 		return (RCM_FAILURE);
339 	}
340 
341 	rcm_log_message(RCM_TRACE1, "VLAN: Offline succeeded(%s)\n", rsrc);
342 	(void) mutex_unlock(&cache_lock);
343 	return (RCM_SUCCESS);
344 }
345 
346 /*
347  * vlan_undo_offline() - Undo offline of a previously offlined node.
348  */
349 /*ARGSUSED*/
350 static int
351 vlan_undo_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
352     char **errorp, rcm_info_t **info)
353 {
354 	link_cache_t *node;
355 
356 	rcm_log_message(RCM_TRACE1, "VLAN: online(%s)\n", rsrc);
357 
358 	(void) mutex_lock(&cache_lock);
359 	node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
360 	if (node == NULL) {
361 		vlan_log_err(DATALINK_INVALID_LINKID, errorp, "no such link");
362 		(void) mutex_unlock(&cache_lock);
363 		errno = ENOENT;
364 		return (RCM_FAILURE);
365 	}
366 
367 	/* Check if no attempt should be made to online the link here */
368 	if (!(node->vc_state & CACHE_NODE_OFFLINED)) {
369 		vlan_log_err(node->vc_linkid, errorp, "link not offlined");
370 		(void) mutex_unlock(&cache_lock);
371 		errno = ENOTSUP;
372 		return (RCM_SUCCESS);
373 	}
374 
375 	vlan_online_vlan(node);
376 
377 	/*
378 	 * Inform IP interfaces on associated VLANs to be onlined
379 	 */
380 	vlan_consumer_online(hd, node, errorp, flags, info);
381 
382 	node->vc_state &= ~CACHE_NODE_OFFLINED;
383 	rcm_log_message(RCM_TRACE1, "VLAN: online succeeded(%s)\n", rsrc);
384 	(void) mutex_unlock(&cache_lock);
385 	return (RCM_SUCCESS);
386 }
387 
388 static void
389 vlan_online_vlan(link_cache_t *node)
390 {
391 	dl_vlan_t *vlan;
392 	dladm_status_t status;
393 	char errmsg[DLADM_STRSIZE];
394 
395 	/*
396 	 * Try to bring on all offlined VLANs
397 	 */
398 	for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
399 		if (!(vlan->dv_flags & VLAN_OFFLINED))
400 			continue;
401 
402 		assert(!vlan->dv_implicit);
403 		if ((status = dladm_vlan_up(vlan->dv_vlanid)) !=
404 		    DLADM_STATUS_OK) {
405 			/*
406 			 * Print a warning message and continue to online
407 			 * other VLANs.
408 			 */
409 			rcm_log_message(RCM_WARNING,
410 			    _("VLAN: VLAN online failed (%u): %s\n"),
411 			    vlan->dv_vlanid, dladm_status2str(status, errmsg));
412 		} else {
413 			vlan->dv_flags &= ~VLAN_OFFLINED;
414 		}
415 	}
416 }
417 
418 static int
419 vlan_offline_vlan(link_cache_t *node, uint32_t flags, cache_node_state_t state)
420 {
421 	dl_vlan_t *vlan;
422 	dladm_status_t status;
423 	char errmsg[DLADM_STRSIZE];
424 
425 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_offline_vlan (%s %u %u)\n",
426 	    node->vc_resource, flags, state);
427 
428 	/*
429 	 * Try to delete all explicit created VLAN
430 	 */
431 	for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
432 
433 		if (vlan->dv_implicit)
434 			continue;
435 
436 		if ((status = dladm_vlan_delete(vlan->dv_vlanid,
437 		    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
438 			rcm_log_message(RCM_WARNING,
439 			    _("VLAN: VLAN offline failed (%u): %s\n"),
440 			    vlan->dv_vlanid, dladm_status2str(status, errmsg));
441 			return (RCM_FAILURE);
442 		} else {
443 			rcm_log_message(RCM_TRACE1,
444 			    "VLAN: VLAN offline succeeded(%u)\n",
445 			    vlan->dv_vlanid);
446 			vlan->dv_flags |= flags;
447 		}
448 	}
449 
450 	node->vc_state |= state;
451 	return (RCM_SUCCESS);
452 }
453 
454 /*
455  * vlan_get_info() - Gather usage information for this resource.
456  */
457 /*ARGSUSED*/
458 int
459 vlan_get_info(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
460     char **usagep, char **errorp, nvlist_t *props, rcm_info_t **info)
461 {
462 	link_cache_t *node;
463 
464 	rcm_log_message(RCM_TRACE1, "VLAN: get_info(%s)\n", rsrc);
465 
466 	(void) mutex_lock(&cache_lock);
467 	node = cache_lookup(hd, rsrc, CACHE_REFRESH);
468 	if (node == NULL) {
469 		rcm_log_message(RCM_INFO,
470 		    _("VLAN: get_info(%s) unrecognized resource\n"), rsrc);
471 		(void) mutex_unlock(&cache_lock);
472 		errno = ENOENT;
473 		return (RCM_FAILURE);
474 	}
475 
476 	*usagep = vlan_usage(node);
477 	(void) mutex_unlock(&cache_lock);
478 	if (*usagep == NULL) {
479 		/* most likely malloc failure */
480 		rcm_log_message(RCM_ERROR,
481 		    _("VLAN: get_info(%s) malloc failure\n"), rsrc);
482 		(void) mutex_unlock(&cache_lock);
483 		errno = ENOMEM;
484 		return (RCM_FAILURE);
485 	}
486 
487 	/* Set client/role properties */
488 	(void) nvlist_add_string(props, RCM_CLIENT_NAME, "VLAN");
489 
490 	rcm_log_message(RCM_TRACE1, "VLAN: get_info(%s) info = %s\n",
491 	    rsrc, *usagep);
492 	return (RCM_SUCCESS);
493 }
494 
495 /*
496  * vlan_suspend() - Nothing to do, always okay
497  */
498 /*ARGSUSED*/
499 static int
500 vlan_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval,
501     uint_t flags, char **errorp, rcm_info_t **info)
502 {
503 	rcm_log_message(RCM_TRACE1, "VLAN: suspend(%s)\n", rsrc);
504 	return (RCM_SUCCESS);
505 }
506 
507 /*
508  * vlan_resume() - Nothing to do, always okay
509  */
510 /*ARGSUSED*/
511 static int
512 vlan_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
513     char **errorp, rcm_info_t **info)
514 {
515 	rcm_log_message(RCM_TRACE1, "VLAN: resume(%s)\n", rsrc);
516 	return (RCM_SUCCESS);
517 }
518 
519 /*
520  * vlan_consumer_remove()
521  *
522  *	Notify VLAN consumers to remove cache.
523  */
524 static int
525 vlan_consumer_remove(rcm_handle_t *hd, link_cache_t *node, uint_t flags,
526     rcm_info_t **info)
527 {
528 	dl_vlan_t *vlan = NULL;
529 	char rsrc[RCM_LINK_RESOURCE_MAX];
530 	int ret = RCM_SUCCESS;
531 
532 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_remove (%s)\n",
533 	    node->vc_resource);
534 
535 	for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
536 
537 		/*
538 		 * This will only be called when the offline operation
539 		 * succeeds, so the VLAN consumers must have been offlined
540 		 * at this point.
541 		 */
542 		assert(vlan->dv_flags & VLAN_CONSUMER_OFFLINED);
543 
544 		(void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
545 		    RCM_LINK_PREFIX, vlan->dv_vlanid);
546 
547 		ret = rcm_notify_remove(hd, rsrc, flags, info);
548 		if (ret != RCM_SUCCESS) {
549 			rcm_log_message(RCM_WARNING,
550 			    _("VLAN: notify remove failed (%s)\n"), rsrc);
551 			break;
552 		}
553 	}
554 
555 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_remove done\n");
556 	return (ret);
557 }
558 
559 /*
560  * vlan_remove() - remove a resource from cache
561  */
562 /*ARGSUSED*/
563 static int
564 vlan_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
565     char **errorp, rcm_info_t **info)
566 {
567 	link_cache_t *node;
568 	int rv;
569 
570 	rcm_log_message(RCM_TRACE1, "VLAN: remove(%s)\n", rsrc);
571 
572 	(void) mutex_lock(&cache_lock);
573 	node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
574 	if (node == NULL) {
575 		rcm_log_message(RCM_INFO,
576 		    _("VLAN: remove(%s) unrecognized resource\n"), rsrc);
577 		(void) mutex_unlock(&cache_lock);
578 		errno = ENOENT;
579 		return (RCM_FAILURE);
580 	}
581 
582 	/* remove the cached entry for the resource */
583 	cache_remove(node);
584 	(void) mutex_unlock(&cache_lock);
585 
586 	rv = vlan_consumer_remove(hd, node, flags, info);
587 	node_free(node);
588 	return (rv);
589 }
590 
591 /*
592  * vlan_notify_event - Project private implementation to receive new resource
593  *		   events. It intercepts all new resource events. If the
594  *		   new resource is a network resource, pass up a notify
595  *		   for it too. The new resource need not be cached, since
596  *		   it is done at register again.
597  */
598 /*ARGSUSED*/
599 static int
600 vlan_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
601     char **errorp, nvlist_t *nvl, rcm_info_t **info)
602 {
603 	nvpair_t	*nvp = NULL;
604 	datalink_id_t	linkid;
605 	uint64_t	id64;
606 	int		rv = RCM_SUCCESS;
607 
608 	rcm_log_message(RCM_TRACE1, "VLAN: notify_event(%s)\n", rsrc);
609 
610 	if (strcmp(rsrc, RCM_RESOURCE_LINK_NEW) != 0) {
611 		vlan_log_err(DATALINK_INVALID_LINKID, errorp,
612 		    "unrecognized event");
613 		errno = EINVAL;
614 		return (RCM_FAILURE);
615 	}
616 
617 	/* Update cache to reflect latest VLANs */
618 	if (cache_update(hd) < 0) {
619 		vlan_log_err(DATALINK_INVALID_LINKID, errorp,
620 		    "private Cache update failed");
621 		return (RCM_FAILURE);
622 	}
623 
624 	/*
625 	 * Try best to recover all configuration.
626 	 */
627 	rcm_log_message(RCM_DEBUG, "VLAN: process_nvlist\n");
628 	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
629 		if (strcmp(nvpair_name(nvp), RCM_NV_LINKID) != 0)
630 			continue;
631 
632 		if (nvpair_value_uint64(nvp, &id64) != 0) {
633 			vlan_log_err(DATALINK_INVALID_LINKID, errorp,
634 			    "cannot get linkid");
635 			rv = RCM_FAILURE;
636 			continue;
637 		}
638 
639 		linkid = (datalink_id_t)id64;
640 		if (vlan_configure(hd, linkid) != 0) {
641 			vlan_log_err(linkid, errorp, "configuring failed");
642 			rv = RCM_FAILURE;
643 			continue;
644 		}
645 
646 		/* Notify all VLAN consumers */
647 		if (vlan_consumer_notify(hd, linkid, errorp, flags,
648 		    info) != 0) {
649 			vlan_log_err(linkid, errorp, "consumer notify failed");
650 			rv = RCM_FAILURE;
651 		}
652 	}
653 
654 	rcm_log_message(RCM_TRACE1,
655 	    "VLAN: notify_event: link configuration complete\n");
656 	return (rv);
657 }
658 
659 /*
660  * vlan_usage - Determine the usage of a link.
661  *	    The returned buffer is owned by caller, and the caller
662  *	    must free it up when done.
663  */
664 static char *
665 vlan_usage(link_cache_t *node)
666 {
667 	dl_vlan_t *vlan;
668 	int nvlan;
669 	char *buf;
670 	const char *fmt;
671 	char *sep;
672 	char errmsg[DLADM_STRSIZE];
673 	char name[MAXLINKNAMELEN];
674 	dladm_status_t status;
675 	size_t bufsz;
676 
677 	rcm_log_message(RCM_TRACE2, "VLAN: usage(%s)\n", node->vc_resource);
678 
679 	assert(MUTEX_HELD(&cache_lock));
680 	if ((status = dladm_datalink_id2info(node->vc_linkid, NULL, NULL, NULL,
681 	    name, sizeof (name))) != DLADM_STATUS_OK) {
682 		rcm_log_message(RCM_ERROR,
683 		    _("VLAN: usage(%s) get link name failure(%s)\n"),
684 		    node->vc_resource, dladm_status2str(status, errmsg));
685 		return (NULL);
686 	}
687 
688 	if (node->vc_state & CACHE_NODE_OFFLINED)
689 		fmt = _("%1$s offlined");
690 	else
691 		fmt = _("%1$s VLANs: ");
692 
693 	/* TRANSLATION_NOTE: separator used between VLAN linkids */
694 	sep = _(", ");
695 
696 	nvlan = 0;
697 	for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next)
698 		nvlan++;
699 
700 	/* space for VLANs and separators, plus message */
701 	bufsz = nvlan * (MAXLINKNAMELEN + strlen(sep)) +
702 	    strlen(fmt) + MAXLINKNAMELEN + 1;
703 	if ((buf = malloc(bufsz)) == NULL) {
704 		rcm_log_message(RCM_ERROR,
705 		    _("VLAN: usage(%s) malloc failure(%s)\n"),
706 		    node->vc_resource, strerror(errno));
707 		return (NULL);
708 	}
709 	(void) snprintf(buf, bufsz, fmt, name);
710 
711 	if (node->vc_state & CACHE_NODE_OFFLINED) {
712 		/* Nothing else to do */
713 		rcm_log_message(RCM_TRACE2, "VLAN: usage (%s) info = %s\n",
714 		    node->vc_resource, buf);
715 		return (buf);
716 	}
717 
718 	for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
719 		rcm_log_message(RCM_DEBUG, "VLAN:= %u\n", vlan->dv_vlanid);
720 
721 		if ((status = dladm_datalink_id2info(vlan->dv_vlanid, NULL,
722 		    NULL, NULL, name, sizeof (name))) != DLADM_STATUS_OK) {
723 			rcm_log_message(RCM_ERROR,
724 			    _("VLAN: usage(%s) get vlan %u name failure(%s)\n"),
725 			    node->vc_resource, vlan->dv_vlanid,
726 			    dladm_status2str(status, errmsg));
727 			free(buf);
728 			return (NULL);
729 		}
730 
731 		(void) strlcat(buf, name, bufsz);
732 		if (vlan->dv_next != NULL)
733 			(void) strlcat(buf, sep, bufsz);
734 	}
735 
736 	rcm_log_message(RCM_TRACE2, "VLAN: usage (%s) info = %s\n",
737 	    node->vc_resource, buf);
738 
739 	return (buf);
740 }
741 
742 /*
743  * Cache management routines, all cache management functions should be
744  * be called with cache_lock held.
745  */
746 
747 /*
748  * cache_lookup() - Get a cache node for a resource.
749  *		  Call with cache lock held.
750  *
751  * This ensures that the cache is consistent with the system state and
752  * returns a pointer to the cache element corresponding to the resource.
753  */
754 static link_cache_t *
755 cache_lookup(rcm_handle_t *hd, char *rsrc, char options)
756 {
757 	link_cache_t *node;
758 
759 	rcm_log_message(RCM_TRACE2, "VLAN: cache lookup(%s)\n", rsrc);
760 
761 	assert(MUTEX_HELD(&cache_lock));
762 	if (options & CACHE_REFRESH) {
763 		/* drop lock since update locks cache again */
764 		(void) mutex_unlock(&cache_lock);
765 		(void) cache_update(hd);
766 		(void) mutex_lock(&cache_lock);
767 	}
768 
769 	node = cache_head.vc_next;
770 	for (; node != &cache_tail; node = node->vc_next) {
771 		if (strcmp(rsrc, node->vc_resource) == 0) {
772 			rcm_log_message(RCM_TRACE2,
773 			    "VLAN: cache lookup succeeded(%s)\n", rsrc);
774 			return (node);
775 		}
776 	}
777 	return (NULL);
778 }
779 
780 /*
781  * node_free - Free a node from the cache
782  */
783 static void
784 node_free(link_cache_t *node)
785 {
786 	dl_vlan_t *vlan, *next;
787 
788 	if (node != NULL) {
789 		free(node->vc_resource);
790 
791 		/* free the VLAN list */
792 		for (vlan = node->vc_vlan; vlan != NULL; vlan = next) {
793 			next = vlan->dv_next;
794 			free(vlan);
795 		}
796 		free(node);
797 	}
798 }
799 
800 /*
801  * cache_insert - Insert a resource node in cache
802  */
803 static void
804 cache_insert(link_cache_t *node)
805 {
806 	assert(MUTEX_HELD(&cache_lock));
807 
808 	/* insert at the head for best performance */
809 	node->vc_next = cache_head.vc_next;
810 	node->vc_prev = &cache_head;
811 
812 	node->vc_next->vc_prev = node;
813 	node->vc_prev->vc_next = node;
814 }
815 
816 /*
817  * cache_remove() - Remove a resource node from cache.
818  */
819 static void
820 cache_remove(link_cache_t *node)
821 {
822 	assert(MUTEX_HELD(&cache_lock));
823 	node->vc_next->vc_prev = node->vc_prev;
824 	node->vc_prev->vc_next = node->vc_next;
825 	node->vc_next = NULL;
826 	node->vc_prev = NULL;
827 }
828 
829 typedef struct vlan_update_arg_s {
830 	rcm_handle_t	*hd;
831 	int		retval;
832 } vlan_update_arg_t;
833 
834 /*
835  * vlan_update() - Update physical interface properties
836  */
837 static int
838 vlan_update(datalink_id_t vlanid, void *arg)
839 {
840 	vlan_update_arg_t *vlan_update_argp = arg;
841 	rcm_handle_t *hd = vlan_update_argp->hd;
842 	link_cache_t *node;
843 	dl_vlan_t *vlan;
844 	char *rsrc;
845 	dladm_vlan_attr_t vlan_attr;
846 	dladm_status_t status;
847 	char errmsg[DLADM_STRSIZE];
848 	boolean_t newnode = B_FALSE;
849 	int ret = -1;
850 
851 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_update(%u)\n", vlanid);
852 
853 	assert(MUTEX_HELD(&cache_lock));
854 	status = dladm_vlan_info(vlanid, &vlan_attr, DLADM_OPT_ACTIVE);
855 	if (status != DLADM_STATUS_OK) {
856 		rcm_log_message(RCM_TRACE1,
857 		    "VLAN: vlan_update() cannot get vlan information for "
858 		    "%u(%s)\n", vlanid, dladm_status2str(status, errmsg));
859 		return (DLADM_WALK_CONTINUE);
860 	}
861 
862 	rsrc = malloc(RCM_LINK_RESOURCE_MAX);
863 	if (rsrc == NULL) {
864 		rcm_log_message(RCM_ERROR, _("VLAN: malloc error(%s): %u\n"),
865 		    strerror(errno), vlanid);
866 		goto done;
867 	}
868 
869 	(void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
870 	    RCM_LINK_PREFIX, vlan_attr.dv_linkid);
871 
872 	node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
873 	if (node != NULL) {
874 		rcm_log_message(RCM_DEBUG,
875 		    "VLAN: %s already registered (vlanid:%d)\n",
876 		    rsrc, vlan_attr.dv_vid);
877 		free(rsrc);
878 	} else {
879 		rcm_log_message(RCM_DEBUG,
880 		    "VLAN: %s is a new resource (vlanid:%d)\n",
881 		    rsrc, vlan_attr.dv_vid);
882 		if ((node = calloc(1, sizeof (link_cache_t))) == NULL) {
883 			free(rsrc);
884 			rcm_log_message(RCM_ERROR, _("VLAN: calloc: %s\n"),
885 			    strerror(errno));
886 			goto done;
887 		}
888 
889 		node->vc_resource = rsrc;
890 		node->vc_vlan = NULL;
891 		node->vc_linkid = vlan_attr.dv_linkid;
892 		node->vc_state |= CACHE_NODE_NEW;
893 		newnode = B_TRUE;
894 	}
895 
896 	for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
897 		if (vlan->dv_vlanid == vlanid) {
898 			vlan->dv_flags &= ~VLAN_STALE;
899 			break;
900 		}
901 	}
902 
903 	if (vlan == NULL) {
904 		if ((vlan = calloc(1, sizeof (dl_vlan_t))) == NULL) {
905 			rcm_log_message(RCM_ERROR, _("VLAN: malloc: %s\n"),
906 			    strerror(errno));
907 			if (newnode) {
908 				free(rsrc);
909 				free(node);
910 			}
911 			goto done;
912 		}
913 		vlan->dv_vlanid = vlanid;
914 		vlan->dv_next = node->vc_vlan;
915 		vlan->dv_prev = NULL;
916 		if (node->vc_vlan != NULL)
917 			node->vc_vlan->dv_prev = vlan;
918 		node->vc_vlan = vlan;
919 	}
920 
921 	vlan->dv_implicit = vlan_attr.dv_implicit;
922 	node->vc_state &= ~CACHE_NODE_STALE;
923 
924 	if (newnode)
925 		cache_insert(node);
926 
927 	rcm_log_message(RCM_TRACE3, "VLAN: vlan_update: succeeded(%u)\n",
928 	    vlanid);
929 	ret = 0;
930 done:
931 	vlan_update_argp->retval = ret;
932 	return (ret == 0 ? DLADM_WALK_CONTINUE : DLADM_WALK_TERMINATE);
933 }
934 
935 /*
936  * vlan_update_all() - Determine all VLAN links in the system
937  */
938 static int
939 vlan_update_all(rcm_handle_t *hd)
940 {
941 	vlan_update_arg_t arg = {NULL, 0};
942 
943 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_update_all\n");
944 
945 	assert(MUTEX_HELD(&cache_lock));
946 	arg.hd = hd;
947 	(void) dladm_walk_datalink_id(vlan_update, &arg, DATALINK_CLASS_VLAN,
948 	    DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
949 	return (arg.retval);
950 }
951 
952 /*
953  * cache_update() - Update cache with latest interface info
954  */
955 static int
956 cache_update(rcm_handle_t *hd)
957 {
958 	link_cache_t *node, *nnode;
959 	dl_vlan_t *vlan;
960 	int rv;
961 
962 	rcm_log_message(RCM_TRACE2, "VLAN: cache_update\n");
963 
964 	(void) mutex_lock(&cache_lock);
965 
966 	/* first we walk the entire cache, marking each entry stale */
967 	node = cache_head.vc_next;
968 	for (; node != &cache_tail; node = node->vc_next) {
969 		node->vc_state |= CACHE_NODE_STALE;
970 		for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next)
971 			vlan->dv_flags |= VLAN_STALE;
972 	}
973 
974 	rv = vlan_update_all(hd);
975 
976 	/*
977 	 * Continue to delete all stale nodes from the cache even
978 	 * vlan_update_all() failed. Unregister link that are not offlined
979 	 * and still in cache
980 	 */
981 	for (node = cache_head.vc_next; node != &cache_tail; node = nnode) {
982 		dl_vlan_t *vlan, *next;
983 
984 		for (vlan = node->vc_vlan; vlan != NULL; vlan = next) {
985 			next = vlan->dv_next;
986 
987 			/* clear stale VLANs */
988 			if (vlan->dv_flags & VLAN_STALE) {
989 				if (vlan->dv_prev != NULL)
990 					vlan->dv_prev->dv_next = next;
991 				else
992 					node->vc_vlan = next;
993 
994 				if (next != NULL)
995 					next->dv_prev = vlan->dv_prev;
996 				free(vlan);
997 			}
998 		}
999 
1000 		nnode = node->vc_next;
1001 		if (node->vc_state & CACHE_NODE_STALE) {
1002 			(void) rcm_unregister_interest(hd, node->vc_resource,
1003 			    0);
1004 			rcm_log_message(RCM_DEBUG, "VLAN: unregistered %s\n",
1005 			    node->vc_resource);
1006 			assert(node->vc_vlan == NULL);
1007 			cache_remove(node);
1008 			node_free(node);
1009 			continue;
1010 		}
1011 
1012 		if (!(node->vc_state & CACHE_NODE_NEW))
1013 			continue;
1014 
1015 		if (rcm_register_interest(hd, node->vc_resource, 0, NULL) !=
1016 		    RCM_SUCCESS) {
1017 			rcm_log_message(RCM_ERROR,
1018 			    _("VLAN: failed to register %s\n"),
1019 			    node->vc_resource);
1020 			rv = -1;
1021 		} else {
1022 			rcm_log_message(RCM_DEBUG, "VLAN: registered %s\n",
1023 			    node->vc_resource);
1024 			node->vc_state &= ~CACHE_NODE_NEW;
1025 		}
1026 	}
1027 
1028 	(void) mutex_unlock(&cache_lock);
1029 	return (rv);
1030 }
1031 
1032 /*
1033  * cache_free() - Empty the cache
1034  */
1035 static void
1036 cache_free()
1037 {
1038 	link_cache_t *node;
1039 
1040 	rcm_log_message(RCM_TRACE2, "VLAN: cache_free\n");
1041 
1042 	(void) mutex_lock(&cache_lock);
1043 	node = cache_head.vc_next;
1044 	while (node != &cache_tail) {
1045 		cache_remove(node);
1046 		node_free(node);
1047 		node = cache_head.vc_next;
1048 	}
1049 	(void) mutex_unlock(&cache_lock);
1050 }
1051 
1052 /*
1053  * vlan_log_err() - RCM error log wrapper
1054  */
1055 static void
1056 vlan_log_err(datalink_id_t linkid, char **errorp, char *errmsg)
1057 {
1058 	char link[MAXLINKNAMELEN];
1059 	char errstr[DLADM_STRSIZE];
1060 	dladm_status_t status;
1061 	int len;
1062 	const char *errfmt;
1063 	char *error;
1064 
1065 	link[0] = '\0';
1066 	if (linkid != DATALINK_INVALID_LINKID) {
1067 		char rsrc[RCM_LINK_RESOURCE_MAX];
1068 
1069 		(void) snprintf(rsrc, sizeof (rsrc), "%s/%u",
1070 		    RCM_LINK_PREFIX, linkid);
1071 
1072 		rcm_log_message(RCM_ERROR, _("VLAN: %s(%s)\n"), errmsg, rsrc);
1073 		if ((status = dladm_datalink_id2info(linkid, NULL, NULL,
1074 		    NULL, link, sizeof (link))) != DLADM_STATUS_OK) {
1075 			rcm_log_message(RCM_WARNING,
1076 			    _("VLAN: cannot get link name for (%s) %s\n"),
1077 			    rsrc, dladm_status2str(status, errstr));
1078 		}
1079 	} else {
1080 		rcm_log_message(RCM_ERROR, _("VLAN: %s\n"), errmsg);
1081 	}
1082 
1083 	errfmt = strlen(link) > 0 ? _("VLAN: %s(%s)") : _("VLAN: %s");
1084 	len = strlen(errfmt) + strlen(errmsg) + MAXLINKNAMELEN + 1;
1085 	if ((error = malloc(len)) != NULL) {
1086 		if (strlen(link) > 0)
1087 			(void) snprintf(error, len, errfmt, errmsg, link);
1088 		else
1089 			(void) snprintf(error, len, errfmt, errmsg);
1090 	}
1091 
1092 	if (errorp != NULL)
1093 		*errorp = error;
1094 }
1095 
1096 /*
1097  * vlan_consumer_online()
1098  *
1099  *	Notify online to VLAN consumers.
1100  */
1101 /* ARGSUSED */
1102 static void
1103 vlan_consumer_online(rcm_handle_t *hd, link_cache_t *node, char **errorp,
1104     uint_t flags, rcm_info_t **info)
1105 {
1106 	dl_vlan_t *vlan;
1107 	char rsrc[RCM_LINK_RESOURCE_MAX];
1108 
1109 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_online (%s)\n",
1110 	    node->vc_resource);
1111 
1112 	for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
1113 		if (!(vlan->dv_flags & VLAN_CONSUMER_OFFLINED))
1114 			continue;
1115 
1116 		(void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
1117 		    RCM_LINK_PREFIX, vlan->dv_vlanid);
1118 
1119 		if (rcm_notify_online(hd, rsrc, flags, info) == RCM_SUCCESS)
1120 			vlan->dv_flags &= ~VLAN_CONSUMER_OFFLINED;
1121 	}
1122 
1123 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_online done\n");
1124 }
1125 
1126 /*
1127  * vlan_consumer_offline()
1128  *
1129  *	Offline VLAN consumers.
1130  */
1131 static int
1132 vlan_consumer_offline(rcm_handle_t *hd, link_cache_t *node, char **errorp,
1133     uint_t flags, rcm_info_t **info)
1134 {
1135 	dl_vlan_t *vlan;
1136 	char rsrc[RCM_LINK_RESOURCE_MAX];
1137 	int ret = RCM_SUCCESS;
1138 
1139 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_offline (%s)\n",
1140 	    node->vc_resource);
1141 
1142 	for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
1143 		(void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
1144 		    RCM_LINK_PREFIX, vlan->dv_vlanid);
1145 
1146 		ret = rcm_request_offline(hd, rsrc, flags, info);
1147 		if (ret != RCM_SUCCESS)
1148 			break;
1149 
1150 		vlan->dv_flags |= VLAN_CONSUMER_OFFLINED;
1151 	}
1152 
1153 	if (vlan != NULL)
1154 		vlan_consumer_online(hd, node, errorp, flags, info);
1155 
1156 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_offline done\n");
1157 	return (ret);
1158 }
1159 
1160 /*
1161  * Send RCM_RESOURCE_LINK_NEW events to other modules about new VLANs.
1162  * Return 0 on success, -1 on failure.
1163  */
1164 static int
1165 vlan_notify_new_vlan(rcm_handle_t *hd, char *rsrc)
1166 {
1167 	link_cache_t *node;
1168 	dl_vlan_t *vlan;
1169 	nvlist_t *nvl = NULL;
1170 	uint64_t id;
1171 	int ret = -1;
1172 
1173 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_notify_new_vlan (%s)\n", rsrc);
1174 
1175 	(void) mutex_lock(&cache_lock);
1176 	if ((node = cache_lookup(hd, rsrc, CACHE_REFRESH)) == NULL) {
1177 		(void) mutex_unlock(&cache_lock);
1178 		return (0);
1179 	}
1180 
1181 	if (nvlist_alloc(&nvl, 0, 0) != 0) {
1182 		(void) mutex_unlock(&cache_lock);
1183 		rcm_log_message(RCM_WARNING,
1184 		    _("VLAN: failed to allocate nvlist\n"));
1185 		goto done;
1186 	}
1187 
1188 	for (vlan = node->vc_vlan; vlan != NULL; vlan = vlan->dv_next) {
1189 		if (!vlan->dv_implicit) {
1190 			rcm_log_message(RCM_TRACE2,
1191 			    "VLAN: vlan_notify_new_vlan add (%u)\n",
1192 			    vlan->dv_vlanid);
1193 
1194 			id = vlan->dv_vlanid;
1195 			if (nvlist_add_uint64(nvl, RCM_NV_LINKID, id) != 0) {
1196 				rcm_log_message(RCM_ERROR,
1197 				    _("VLAN: failed to construct nvlist\n"));
1198 				(void) mutex_unlock(&cache_lock);
1199 				goto done;
1200 			}
1201 		}
1202 	}
1203 	(void) mutex_unlock(&cache_lock);
1204 
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;
1211 	}
1212 
1213 	ret = 0;
1214 done:
1215 	if (nvl != NULL)
1216 		nvlist_free(nvl);
1217 	return (ret);
1218 }
1219 
1220 /*
1221  * vlan_consumer_notify() - Notify consumers of VLANs coming back online.
1222  */
1223 static int
1224 vlan_consumer_notify(rcm_handle_t *hd, datalink_id_t linkid, char **errorp,
1225     uint_t flags, rcm_info_t **info)
1226 {
1227 	char rsrc[RCM_LINK_RESOURCE_MAX];
1228 	link_cache_t *node;
1229 
1230 	/* Check for the interface in the cache */
1231 	(void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u", RCM_LINK_PREFIX,
1232 	    linkid);
1233 
1234 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_notify(%s)\n", rsrc);
1235 
1236 	/*
1237 	 * Inform IP consumers of the new link.
1238 	 */
1239 	if (vlan_notify_new_vlan(hd, rsrc) != 0) {
1240 		(void) mutex_lock(&cache_lock);
1241 		if ((node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH)) != NULL) {
1242 			(void) vlan_offline_vlan(node, VLAN_STALE,
1243 			    CACHE_NODE_STALE);
1244 		}
1245 		(void) mutex_unlock(&cache_lock);
1246 		rcm_log_message(RCM_TRACE2,
1247 		    "VLAN: vlan_notify_new_vlan failed(%s)\n", rsrc);
1248 		return (-1);
1249 	}
1250 
1251 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_notify succeeded\n");
1252 	return (0);
1253 }
1254 
1255 typedef struct vlan_up_arg_s {
1256 	datalink_id_t	linkid;
1257 	int		retval;
1258 } vlan_up_arg_t;
1259 
1260 static int
1261 vlan_up(datalink_id_t vlanid, void *arg)
1262 {
1263 	vlan_up_arg_t *vlan_up_argp = arg;
1264 	dladm_status_t status;
1265 	dladm_vlan_attr_t vlan_attr;
1266 	char errmsg[DLADM_STRSIZE];
1267 
1268 	status = dladm_vlan_info(vlanid, &vlan_attr, DLADM_OPT_PERSIST);
1269 	if (status != DLADM_STATUS_OK) {
1270 		rcm_log_message(RCM_TRACE1,
1271 		    "VLAN: vlan_up(): cannot get information for VLAN %u "
1272 		    "(%s)\n", vlanid, dladm_status2str(status, errmsg));
1273 		return (DLADM_WALK_CONTINUE);
1274 	}
1275 
1276 	if (vlan_attr.dv_linkid != vlan_up_argp->linkid)
1277 		return (DLADM_WALK_CONTINUE);
1278 
1279 	rcm_log_message(RCM_TRACE3, "VLAN: vlan_up(%u)\n", vlanid);
1280 	if ((status = dladm_vlan_up(vlanid)) == DLADM_STATUS_OK)
1281 		return (DLADM_WALK_CONTINUE);
1282 
1283 	/*
1284 	 * Prompt the warning message and continue to UP other VLANs.
1285 	 */
1286 	rcm_log_message(RCM_WARNING,
1287 	    _("VLAN: VLAN up failed (%u): %s\n"),
1288 	    vlanid, dladm_status2str(status, errmsg));
1289 
1290 	vlan_up_argp->retval = -1;
1291 	return (DLADM_WALK_CONTINUE);
1292 }
1293 
1294 /*
1295  * vlan_configure() - Configure VLANs over a physical link after it attaches
1296  */
1297 static int
1298 vlan_configure(rcm_handle_t *hd, datalink_id_t linkid)
1299 {
1300 	char rsrc[RCM_LINK_RESOURCE_MAX];
1301 	link_cache_t *node;
1302 	vlan_up_arg_t arg = {DATALINK_INVALID_LINKID, 0};
1303 
1304 	/* Check for the VLANs in the cache */
1305 	(void) snprintf(rsrc, sizeof (rsrc), "%s/%u", RCM_LINK_PREFIX, linkid);
1306 
1307 	rcm_log_message(RCM_TRACE2, "VLAN: vlan_configure(%s)\n", rsrc);
1308 
1309 	/* Check if the link is new or was previously offlined */
1310 	(void) mutex_lock(&cache_lock);
1311 	if (((node = cache_lookup(hd, rsrc, CACHE_REFRESH)) != NULL) &&
1312 	    (!(node->vc_state & CACHE_NODE_OFFLINED))) {
1313 		rcm_log_message(RCM_TRACE2,
1314 		    "VLAN: Skipping configured interface(%s)\n", rsrc);
1315 		(void) mutex_unlock(&cache_lock);
1316 		return (0);
1317 	}
1318 	(void) mutex_unlock(&cache_lock);
1319 
1320 	arg.linkid = linkid;
1321 	(void) dladm_walk_datalink_id(vlan_up, &arg, DATALINK_CLASS_VLAN,
1322 	    DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
1323 
1324 	if (arg.retval == 0) {
1325 		rcm_log_message(RCM_TRACE2,
1326 		    "VLAN: vlan_configure succeeded(%s)\n", rsrc);
1327 	}
1328 	return (arg.retval);
1329 }
1330