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