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