xref: /illumos-gate/usr/src/uts/common/io/dls/dls_mgmt.c (revision 024b0a258461f282a92b1b1283c3b8b083f9f33f)
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  * Datalink management routines.
30  */
31 
32 #include <sys/types.h>
33 #include <sys/door.h>
34 #include <sys/zone.h>
35 #include <sys/modctl.h>
36 #include <sys/file.h>
37 #include <sys/modhash.h>
38 #include <sys/kstat.h>
39 #include <sys/vnode.h>
40 #include <sys/cmn_err.h>
41 #include <sys/vlan.h>
42 #include <sys/softmac.h>
43 #include <sys/dls.h>
44 #include <sys/dls_impl.h>
45 
46 static kmem_cache_t	*i_dls_devnet_cachep;
47 static kmutex_t		i_dls_mgmt_lock;
48 static krwlock_t	i_dls_devnet_lock;
49 static mod_hash_t	*i_dls_devnet_id_hash;
50 static mod_hash_t	*i_dls_devnet_hash;
51 
52 boolean_t		devnet_need_rebuild;
53 
54 #define	VLAN_HASHSZ	67	/* prime */
55 
56 /* Upcall door handle */
57 static door_handle_t	dls_mgmt_dh = NULL;
58 
59 /*
60  * This structure is used to keep the <linkid, macname, vid> mapping.
61  */
62 typedef struct dls_devnet_s {
63 	datalink_id_t	dd_vlanid;
64 	datalink_id_t	dd_linkid;
65 	char		dd_mac[MAXNAMELEN];
66 	uint16_t	dd_vid;
67 	char		dd_spa[MAXSPALEN];
68 	boolean_t	dd_explicit;
69 	kstat_t		*dd_ksp;
70 
71 	uint32_t	dd_ref;
72 
73 	kmutex_t	dd_mutex;
74 	kcondvar_t	dd_cv;
75 	uint32_t	dd_tref;
76 
77 	kmutex_t	dd_zid_mutex;
78 	zoneid_t	dd_zid;
79 } dls_devnet_t;
80 
81 /*ARGSUSED*/
82 static int
83 i_dls_devnet_constructor(void *buf, void *arg, int kmflag)
84 {
85 	dls_devnet_t	*ddp = buf;
86 
87 	bzero(buf, sizeof (dls_devnet_t));
88 	mutex_init(&ddp->dd_mutex, NULL, MUTEX_DEFAULT, NULL);
89 	mutex_init(&ddp->dd_zid_mutex, NULL, MUTEX_DEFAULT, NULL);
90 	cv_init(&ddp->dd_cv, NULL, CV_DEFAULT, NULL);
91 	return (0);
92 }
93 
94 /*ARGSUSED*/
95 static void
96 i_dls_devnet_destructor(void *buf, void *arg)
97 {
98 	dls_devnet_t	*ddp = buf;
99 
100 	ASSERT(ddp->dd_ksp == NULL);
101 	ASSERT(ddp->dd_ref == 0);
102 	ASSERT(ddp->dd_tref == 0);
103 	ASSERT(!ddp->dd_explicit);
104 	mutex_destroy(&ddp->dd_mutex);
105 	mutex_destroy(&ddp->dd_zid_mutex);
106 	cv_destroy(&ddp->dd_cv);
107 }
108 
109 /*
110  * Module initialization and finalization functions.
111  */
112 void
113 dls_mgmt_init(void)
114 {
115 	mutex_init(&i_dls_mgmt_lock, NULL, MUTEX_DEFAULT, NULL);
116 	rw_init(&i_dls_devnet_lock, NULL, RW_DEFAULT, NULL);
117 
118 	/*
119 	 * Create a kmem_cache of dls_devnet_t structures.
120 	 */
121 	i_dls_devnet_cachep = kmem_cache_create("dls_devnet_cache",
122 	    sizeof (dls_devnet_t), 0, i_dls_devnet_constructor,
123 	    i_dls_devnet_destructor, NULL, NULL, NULL, 0);
124 	ASSERT(i_dls_devnet_cachep != NULL);
125 
126 	/*
127 	 * Create a hash table, keyed by dd_vlanid, of dls_devnet_t.
128 	 */
129 	i_dls_devnet_id_hash = mod_hash_create_idhash("dls_devnet_id_hash",
130 	    VLAN_HASHSZ, mod_hash_null_valdtor);
131 
132 	/*
133 	 * Create a hash table, keyed by dd_spa.
134 	 */
135 	i_dls_devnet_hash = mod_hash_create_extended("dls_devnet_hash",
136 	    VLAN_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
137 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
138 
139 	devnet_need_rebuild = B_FALSE;
140 }
141 
142 void
143 dls_mgmt_fini(void)
144 {
145 	mod_hash_destroy_hash(i_dls_devnet_hash);
146 	mod_hash_destroy_hash(i_dls_devnet_id_hash);
147 	kmem_cache_destroy(i_dls_devnet_cachep);
148 	rw_destroy(&i_dls_devnet_lock);
149 	mutex_destroy(&i_dls_mgmt_lock);
150 }
151 
152 int
153 dls_mgmt_door_set(boolean_t start)
154 {
155 	int	err;
156 
157 	/* handle daemon restart */
158 	mutex_enter(&i_dls_mgmt_lock);
159 	if (dls_mgmt_dh != NULL) {
160 		door_ki_rele(dls_mgmt_dh);
161 		dls_mgmt_dh = NULL;
162 	}
163 
164 	if (start && ((err = door_ki_open(DLMGMT_DOOR, &dls_mgmt_dh)) != 0)) {
165 		mutex_exit(&i_dls_mgmt_lock);
166 		return (err);
167 	}
168 
169 	mutex_exit(&i_dls_mgmt_lock);
170 
171 	/*
172 	 * Create and associate <link name, linkid> mapping for network devices
173 	 * which are already attached before the daemon is started.
174 	 */
175 	if (start)
176 		softmac_recreate();
177 	return (0);
178 }
179 
180 static boolean_t
181 i_dls_mgmt_door_revoked(door_handle_t dh)
182 {
183 	struct door_info info;
184 	extern int sys_shutdown;
185 
186 	ASSERT(dh != NULL);
187 
188 	if (sys_shutdown) {
189 		cmn_err(CE_NOTE, "dls_mgmt_door: shutdown observed\n");
190 		return (B_TRUE);
191 	}
192 
193 	if (door_ki_info(dh, &info) != 0)
194 		return (B_TRUE);
195 
196 	return ((info.di_attributes & DOOR_REVOKED) != 0);
197 }
198 
199 /*
200  * Upcall to the datalink management daemon (dlmgmtd).
201  */
202 static int
203 i_dls_mgmt_upcall(void *arg, size_t asize, void *rbuf, size_t rsize)
204 {
205 	door_arg_t			darg, save_arg;
206 	door_handle_t			dh;
207 	int				err;
208 	int				retry = 0;
209 
210 #define	MAXRETRYNUM	3
211 
212 	ASSERT(arg);
213 	darg.data_ptr = arg;
214 	darg.data_size = asize;
215 	darg.desc_ptr = NULL;
216 	darg.desc_num = 0;
217 	darg.rbuf = rbuf;
218 	darg.rsize = rsize;
219 	save_arg = darg;
220 
221 retry:
222 	mutex_enter(&i_dls_mgmt_lock);
223 	dh = dls_mgmt_dh;
224 	if ((dh == NULL) || i_dls_mgmt_door_revoked(dh)) {
225 		mutex_exit(&i_dls_mgmt_lock);
226 		return (EBADF);
227 	}
228 	door_ki_hold(dh);
229 	mutex_exit(&i_dls_mgmt_lock);
230 
231 	for (;;) {
232 		retry++;
233 		if ((err = door_ki_upcall_cred(dh, &darg, kcred)) == 0)
234 			break;
235 
236 		/*
237 		 * handle door call errors
238 		 */
239 		darg = save_arg;
240 		switch (err) {
241 		case EINTR:
242 			/*
243 			 * If the operation which caused this door upcall gets
244 			 * interrupted, return directly.
245 			 */
246 			goto done;
247 		case EAGAIN:
248 			/*
249 			 * Repeat upcall if the maximum attempt limit has not
250 			 * been reached.
251 			 */
252 			if (retry < MAXRETRYNUM) {
253 				delay(2 * hz);
254 				break;
255 			}
256 			cmn_err(CE_WARN, "dls: dlmgmtd fatal error %d\n", err);
257 			goto done;
258 		default:
259 			/* A fatal door error */
260 			if (i_dls_mgmt_door_revoked(dh)) {
261 				cmn_err(CE_NOTE,
262 				    "dls: dlmgmtd door service revoked\n");
263 
264 				if (retry < MAXRETRYNUM) {
265 					door_ki_rele(dh);
266 					goto retry;
267 				}
268 			}
269 			cmn_err(CE_WARN, "dls: dlmgmtd fatal error %d\n", err);
270 			goto done;
271 		}
272 	}
273 
274 	if (darg.rbuf != rbuf) {
275 		/*
276 		 * The size of the input rbuf was not big enough, so the
277 		 * upcall allocated the rbuf itself.  If this happens, assume
278 		 * that this was an invalid door call request.
279 		 */
280 		kmem_free(darg.rbuf, darg.rsize);
281 		err = ENOSPC;
282 		goto done;
283 	}
284 
285 	if (darg.rsize != rsize) {
286 		err = EINVAL;
287 		goto done;
288 	}
289 
290 	err = ((dlmgmt_retval_t *)rbuf)->lr_err;
291 
292 done:
293 	door_ki_rele(dh);
294 	return (err);
295 }
296 
297 /*
298  * Request the datalink management daemon to create a link with the attributes
299  * below.  Upon success, zero is returned and linkidp contains the linkid for
300  * the new link; otherwise, an errno is returned.
301  *
302  *     - dev		physical dev_t.  required for all physical links,
303  *		        including GLDv3 links.  It will be used to force the
304  *		        attachment of a physical device, hence the
305  *		        registration of its mac
306  *     - class		datalink class
307  *     - media type	media type; DL_OTHER means unknown
308  *     - vid		VLAN ID (for VLANs)
309  *     - persist	whether to persist the datalink
310  */
311 int
312 dls_mgmt_create(const char *devname, dev_t dev, datalink_class_t class,
313     uint32_t media, boolean_t persist, datalink_id_t *linkidp)
314 {
315 	dlmgmt_upcall_arg_create_t	create;
316 	dlmgmt_create_retval_t		retval;
317 	int				err;
318 
319 	create.ld_cmd = DLMGMT_CMD_DLS_CREATE;
320 	create.ld_class = class;
321 	create.ld_media = media;
322 	create.ld_phymaj = getmajor(dev);
323 	create.ld_phyinst = getminor(dev);
324 	create.ld_persist = persist;
325 	if (strlcpy(create.ld_devname, devname, MAXNAMELEN) >= MAXNAMELEN)
326 		return (EINVAL);
327 
328 	if ((err = i_dls_mgmt_upcall(&create, sizeof (create), &retval,
329 	    sizeof (retval))) == 0) {
330 		*linkidp = retval.lr_linkid;
331 	}
332 	return (err);
333 }
334 
335 /*
336  * Request the datalink management daemon to destroy the specified link.
337  * Returns zero upon success, or an errno upon failure.
338  */
339 int
340 dls_mgmt_destroy(datalink_id_t linkid, boolean_t persist)
341 {
342 	dlmgmt_upcall_arg_destroy_t	destroy;
343 	dlmgmt_destroy_retval_t		retval;
344 
345 	destroy.ld_cmd = DLMGMT_CMD_DLS_DESTROY;
346 	destroy.ld_linkid = linkid;
347 	destroy.ld_persist = persist;
348 
349 	return (i_dls_mgmt_upcall(&destroy, sizeof (destroy),
350 	    &retval, sizeof (retval)));
351 }
352 
353 /*
354  * Request the datalink management daemon to verify/update the information
355  * for a physical link.  Upon success, get its linkid.
356  *
357  *     - media type	media type
358  *     - novanity	whether this physical datalink supports vanity naming.
359  *			physical links that do not use the GLDv3 MAC plugin
360  *			cannot suport vanity naming
361  *
362  * This function could fail with ENOENT or EEXIST.  Two cases return EEXIST:
363  *
364  * 1. A link with devname already exists, but the media type does not match.
365  *    In this case, mediap will bee set to the media type of the existing link.
366  * 2. A link with devname already exists, but its link name does not match
367  *    the device name, although this link does not support vanity naming.
368  */
369 int
370 dls_mgmt_update(const char *devname, uint32_t media, boolean_t novanity,
371     uint32_t *mediap, datalink_id_t *linkidp)
372 {
373 	dlmgmt_upcall_arg_update_t	update;
374 	dlmgmt_update_retval_t		retval;
375 	int				err;
376 
377 	update.ld_cmd = DLMGMT_CMD_DLS_UPDATE;
378 
379 	if (strlcpy(update.ld_devname, devname, MAXNAMELEN) >= MAXNAMELEN)
380 		return (EINVAL);
381 
382 	update.ld_media = media;
383 	update.ld_novanity = novanity;
384 
385 	if ((err = i_dls_mgmt_upcall(&update, sizeof (update), &retval,
386 	    sizeof (retval))) == EEXIST) {
387 		*linkidp = retval.lr_linkid;
388 		*mediap = retval.lr_media;
389 	} else if (err == 0) {
390 		*linkidp = retval.lr_linkid;
391 	}
392 
393 	return (err);
394 }
395 
396 /*
397  * Request the datalink management daemon to get the information for a link.
398  * Returns zero upon success, or an errno upon failure.
399  *
400  * Only fills in information for argument pointers that are non-NULL.
401  * Note that the link argument is expected to be MAXLINKNAMELEN bytes.
402  */
403 int
404 dls_mgmt_get_linkinfo(datalink_id_t linkid, char *link,
405     datalink_class_t *classp, uint32_t *mediap, uint32_t *flagsp)
406 {
407 	dlmgmt_door_getname_t	getname;
408 	dlmgmt_getname_retval_t	retval;
409 	int			err, len;
410 
411 	getname.ld_cmd = DLMGMT_CMD_GETNAME;
412 	getname.ld_linkid = linkid;
413 
414 	if ((err = i_dls_mgmt_upcall(&getname, sizeof (getname), &retval,
415 	    sizeof (retval))) != 0) {
416 		return (err);
417 	}
418 
419 	len = strlen(retval.lr_link);
420 	if (len <= 1 || len >= MAXLINKNAMELEN)
421 		return (EINVAL);
422 
423 	if (link != NULL)
424 		(void) strlcpy(link, retval.lr_link, MAXLINKNAMELEN);
425 	if (classp != NULL)
426 		*classp = retval.lr_class;
427 	if (mediap != NULL)
428 		*mediap = retval.lr_media;
429 	if (flagsp != NULL)
430 		*flagsp = retval.lr_flags;
431 	return (0);
432 }
433 
434 /*
435  * Request the datalink management daemon to get the linkid for a link.
436  * Returns a non-zero error code on failure.  The linkid argument is only
437  * set on success (when zero is returned.)
438  */
439 int
440 dls_mgmt_get_linkid(const char *link, datalink_id_t *linkid)
441 {
442 	dlmgmt_door_getlinkid_t		getlinkid;
443 	dlmgmt_getlinkid_retval_t	retval;
444 	int				err;
445 
446 	getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID;
447 	(void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN);
448 
449 	if ((err = i_dls_mgmt_upcall(&getlinkid, sizeof (getlinkid), &retval,
450 	    sizeof (retval))) == 0) {
451 		*linkid = retval.lr_linkid;
452 	}
453 	return (err);
454 }
455 
456 datalink_id_t
457 dls_mgmt_get_next(datalink_id_t linkid, datalink_class_t class,
458     datalink_media_t dmedia, uint32_t flags)
459 {
460 	dlmgmt_door_getnext_t	getnext;
461 	dlmgmt_getnext_retval_t	retval;
462 
463 	getnext.ld_cmd = DLMGMT_CMD_GETNEXT;
464 	getnext.ld_class = class;
465 	getnext.ld_dmedia = dmedia;
466 	getnext.ld_flags = flags;
467 	getnext.ld_linkid = linkid;
468 
469 	if (i_dls_mgmt_upcall(&getnext, sizeof (getnext), &retval,
470 	    sizeof (retval)) != 0) {
471 		return (DATALINK_INVALID_LINKID);
472 	}
473 
474 	return (retval.lr_linkid);
475 }
476 
477 static int
478 i_dls_mgmt_get_linkattr(const datalink_id_t linkid, const char *attr,
479     void *attrval, size_t *attrszp)
480 {
481 	dlmgmt_upcall_arg_getattr_t	getattr;
482 	dlmgmt_getattr_retval_t		retval;
483 	int				err;
484 
485 	getattr.ld_cmd = DLMGMT_CMD_DLS_GETATTR;
486 	getattr.ld_linkid = linkid;
487 	(void) strlcpy(getattr.ld_attr, attr, MAXLINKATTRLEN);
488 
489 	if ((err = i_dls_mgmt_upcall(&getattr, sizeof (getattr), &retval,
490 	    sizeof (retval))) == 0) {
491 		if (*attrszp < retval.lr_attrsz)
492 			return (EINVAL);
493 		*attrszp = retval.lr_attrsz;
494 		bcopy(retval.lr_attrval, attrval, retval.lr_attrsz);
495 	}
496 
497 	return (err);
498 }
499 
500 /*
501  * Note that this function can only get devp successfully for non-VLAN link.
502  */
503 int
504 dls_mgmt_get_phydev(datalink_id_t linkid, dev_t *devp)
505 {
506 	uint64_t	maj, inst;
507 	size_t		attrsz = sizeof (uint64_t);
508 
509 	if (i_dls_mgmt_get_linkattr(linkid, FPHYMAJ, &maj, &attrsz) != 0 ||
510 	    attrsz != sizeof (uint64_t) ||
511 	    i_dls_mgmt_get_linkattr(linkid, FPHYINST, &inst, &attrsz) != 0 ||
512 	    attrsz != sizeof (uint64_t)) {
513 		return (EINVAL);
514 	}
515 
516 	*devp = makedevice((major_t)maj, (minor_t)inst);
517 	return (0);
518 }
519 
520 /*
521  * Hold the vanity naming structure (dls_devnet_t) temporarily.  The request to
522  * delete the dls_devnet_t will wait until the temporary reference is released.
523  */
524 int
525 dls_devnet_hold_tmp(datalink_id_t linkid, dls_dl_handle_t *ddhp)
526 {
527 	dls_devnet_t		*ddp;
528 	dls_dev_handle_t	ddh = NULL;
529 	dev_t			phydev = 0;
530 	int			err;
531 
532 	/*
533 	 * Hold this link to prevent it being detached (if physical link).
534 	 */
535 	if (dls_mgmt_get_phydev(linkid, &phydev) == 0)
536 		(void) softmac_hold_device(phydev, &ddh);
537 
538 	rw_enter(&i_dls_devnet_lock, RW_READER);
539 	if ((err = mod_hash_find(i_dls_devnet_id_hash,
540 	    (mod_hash_key_t)(uintptr_t)linkid, (mod_hash_val_t *)&ddp)) != 0) {
541 		ASSERT(err == MH_ERR_NOTFOUND);
542 		rw_exit(&i_dls_devnet_lock);
543 		softmac_rele_device(ddh);
544 		return (ENOENT);
545 	}
546 
547 	/*
548 	 * At least one reference was held when this datalink was created.
549 	 */
550 	ASSERT(ddp->dd_ref > 0);
551 	mutex_enter(&ddp->dd_mutex);
552 	ddp->dd_tref++;
553 	mutex_exit(&ddp->dd_mutex);
554 	rw_exit(&i_dls_devnet_lock);
555 	softmac_rele_device(ddh);
556 
557 done:
558 	*ddhp = ddp;
559 	return (0);
560 }
561 
562 void
563 dls_devnet_rele_tmp(dls_dl_handle_t dlh)
564 {
565 	dls_devnet_t		*ddp = dlh;
566 
567 	mutex_enter(&ddp->dd_mutex);
568 	ASSERT(ddp->dd_tref != 0);
569 	if (--ddp->dd_tref == 0)
570 		cv_signal(&ddp->dd_cv);
571 	mutex_exit(&ddp->dd_mutex);
572 }
573 
574 /*
575  * "link" kstats related functions.
576  */
577 
578 /*
579  * Query the "link" kstats.
580  */
581 static int
582 dls_devnet_stat_update(kstat_t *ksp, int rw)
583 {
584 	dls_devnet_t	*ddp = ksp->ks_private;
585 	dls_vlan_t	*dvp;
586 	int		err;
587 
588 	err = dls_vlan_hold(ddp->dd_mac, ddp->dd_vid, &dvp, B_FALSE, B_FALSE);
589 	if (err != 0)
590 		return (err);
591 
592 	err = dls_stat_update(ksp, dvp, rw);
593 	dls_vlan_rele(dvp);
594 	return (err);
595 }
596 
597 /*
598  * Create the "link" kstats.
599  */
600 static void
601 dls_devnet_stat_create(dls_devnet_t *ddp)
602 {
603 	char	link[MAXLINKNAMELEN];
604 	kstat_t	*ksp;
605 
606 	if ((dls_mgmt_get_linkinfo(ddp->dd_vlanid, link,
607 	    NULL, NULL, NULL)) != 0) {
608 		return;
609 	}
610 
611 	if (dls_stat_create("link", 0, link, dls_devnet_stat_update,
612 	    ddp, &ksp) != 0) {
613 		return;
614 	}
615 
616 	ASSERT(ksp != NULL);
617 	ddp->dd_ksp = ksp;
618 }
619 
620 /*
621  * Destroy the "link" kstats.
622  */
623 static void
624 dls_devnet_stat_destroy(dls_devnet_t *ddp)
625 {
626 	if (ddp->dd_ksp == NULL)
627 		return;
628 
629 	kstat_delete(ddp->dd_ksp);
630 	ddp->dd_ksp = NULL;
631 }
632 
633 /*
634  * The link has been renamed. Destroy the old non-legacy kstats ("link kstats")
635  * and create the new set using the new name.
636  */
637 static void
638 dls_devnet_stat_rename(dls_devnet_t *ddp, const char *link)
639 {
640 	kstat_t	 *ksp;
641 
642 	if (ddp->dd_ksp != NULL) {
643 		kstat_delete(ddp->dd_ksp);
644 		ddp->dd_ksp = NULL;
645 	}
646 
647 	if (dls_stat_create("link", 0, link, dls_devnet_stat_update,
648 	    ddp, &ksp) != 0) {
649 		return;
650 	}
651 
652 	ASSERT(ksp != NULL);
653 	ddp->dd_ksp = ksp;
654 }
655 
656 /*
657  * Associate a linkid with a given link (identified by <macname/vid>)
658  *
659  * Several cases:
660  * a. implicit VLAN creation: (non-NULL "vlan")
661  * b. explicit VLAN creation: (NULL "vlan")
662  * c. explicit non-VLAN creation:
663  *    (NULL "vlan" and linkid could be INVALID_LINKID if the physical device
664  *    was created before the daemon was started)
665  */
666 static int
667 dls_devnet_set(const char *macname, uint16_t vid,
668     datalink_id_t vlan_linkid, datalink_id_t linkid, const char *vlan,
669     dls_devnet_t **ddpp)
670 {
671 	dls_devnet_t		*ddp = NULL;
672 	char			spa[MAXSPALEN];
673 	boolean_t		explicit = (vlan == NULL);
674 	datalink_class_t	class;
675 	int			err;
676 
677 	ASSERT(vid != VLAN_ID_NONE || explicit);
678 	ASSERT(vlan_linkid != DATALINK_INVALID_LINKID || !explicit ||
679 	    vid == VLAN_ID_NONE);
680 
681 	(void) snprintf(spa, MAXSPALEN, "%s/%d", macname, vid);
682 	rw_enter(&i_dls_devnet_lock, RW_WRITER);
683 	if ((err = mod_hash_find(i_dls_devnet_hash,
684 	    (mod_hash_key_t)spa, (mod_hash_val_t *)&ddp)) == 0) {
685 		char	link[MAXLINKNAMELEN];
686 
687 		if (explicit) {
688 			if ((vid != VLAN_ID_NONE) ||
689 			    (ddp->dd_vlanid != DATALINK_INVALID_LINKID)) {
690 				err = EEXIST;
691 				goto done;
692 			}
693 
694 			/*
695 			 * This might be a physical link that has already
696 			 * been created, but which does not have a vlan_linkid
697 			 * because dlmgmtd was not running when it was created.
698 			 */
699 			if ((err = dls_mgmt_get_linkinfo(vlan_linkid, NULL,
700 			    &class, NULL, NULL)) != 0) {
701 				goto done;
702 			}
703 
704 			if (class != DATALINK_CLASS_PHYS) {
705 				err = EINVAL;
706 				goto done;
707 			}
708 
709 			goto newphys;
710 		}
711 
712 		/*
713 		 * Implicit VLAN, but the same name has already
714 		 * been associated with another linkid.  Check if the name
715 		 * of that link matches the given VLAN name.
716 		 */
717 		ASSERT(vid != VLAN_ID_NONE);
718 		if ((err = dls_mgmt_get_linkinfo(ddp->dd_vlanid, link,
719 		    NULL, NULL, NULL)) != 0) {
720 			goto done;
721 		}
722 
723 		if (strcmp(link, vlan) != 0) {
724 			err = EEXIST;
725 			goto done;
726 		}
727 
728 		/*
729 		 * This is not an implicit created VLAN any more, return
730 		 * this existing datalink.
731 		 */
732 		ASSERT(ddp->dd_ref > 0);
733 		ddp->dd_ref++;
734 		goto done;
735 	}
736 
737 	/*
738 	 * Request the daemon to create a new vlan_linkid for this implicitly
739 	 * created vlan.
740 	 */
741 	if (!explicit && ((err = dls_mgmt_create(vlan, 0,
742 	    DATALINK_CLASS_VLAN, DL_ETHER, B_FALSE, &vlan_linkid)) != 0)) {
743 		goto done;
744 	}
745 
746 	ddp = kmem_cache_alloc(i_dls_devnet_cachep, KM_SLEEP);
747 	ddp->dd_vid = vid;
748 	ddp->dd_explicit = explicit;
749 	ddp->dd_tref = 0;
750 	ddp->dd_ref++;
751 	ddp->dd_zid = GLOBAL_ZONEID;
752 	(void) strncpy(ddp->dd_mac, macname, MAXNAMELEN);
753 	(void) snprintf(ddp->dd_spa, MAXSPALEN, "%s/%d", macname, vid);
754 	VERIFY(mod_hash_insert(i_dls_devnet_hash,
755 	    (mod_hash_key_t)ddp->dd_spa, (mod_hash_val_t)ddp) == 0);
756 
757 newphys:
758 
759 	ddp->dd_vlanid = vlan_linkid;
760 	if (ddp->dd_vlanid != DATALINK_INVALID_LINKID) {
761 		ddp->dd_linkid = linkid;
762 
763 		VERIFY(mod_hash_insert(i_dls_devnet_id_hash,
764 		    (mod_hash_key_t)(uintptr_t)vlan_linkid,
765 		    (mod_hash_val_t)ddp) == 0);
766 		devnet_need_rebuild = B_TRUE;
767 		dls_devnet_stat_create(ddp);
768 	}
769 	err = 0;
770 done:
771 	rw_exit(&i_dls_devnet_lock);
772 	if (err == 0 && ddpp != NULL)
773 		*ddpp = ddp;
774 	return (err);
775 }
776 
777 static void
778 dls_devnet_unset_common(dls_devnet_t *ddp)
779 {
780 	mod_hash_val_t	val;
781 
782 	ASSERT(RW_WRITE_HELD(&i_dls_devnet_lock));
783 
784 	ASSERT(ddp->dd_ref == 0);
785 
786 	/*
787 	 * Remove this dls_devnet_t from the hash table.
788 	 */
789 	VERIFY(mod_hash_remove(i_dls_devnet_hash,
790 	    (mod_hash_key_t)ddp->dd_spa, &val) == 0);
791 
792 	if (ddp->dd_vlanid != DATALINK_INVALID_LINKID) {
793 		VERIFY(mod_hash_remove(i_dls_devnet_id_hash,
794 		    (mod_hash_key_t)(uintptr_t)ddp->dd_vlanid, &val) == 0);
795 
796 		dls_devnet_stat_destroy(ddp);
797 		devnet_need_rebuild = B_TRUE;
798 	}
799 
800 	/*
801 	 * Wait until all temporary references are released.
802 	 */
803 	mutex_enter(&ddp->dd_mutex);
804 	while (ddp->dd_tref != 0)
805 		cv_wait(&ddp->dd_cv, &ddp->dd_mutex);
806 	mutex_exit(&ddp->dd_mutex);
807 
808 	if (!ddp->dd_explicit) {
809 		ASSERT(ddp->dd_vid != VLAN_ID_NONE);
810 		ASSERT(ddp->dd_vlanid != DATALINK_INVALID_LINKID);
811 		(void) dls_mgmt_destroy(ddp->dd_vlanid, B_FALSE);
812 	}
813 
814 	ddp->dd_vlanid = DATALINK_INVALID_LINKID;
815 	ddp->dd_zid = GLOBAL_ZONEID;
816 	ddp->dd_explicit = B_FALSE;
817 	kmem_cache_free(i_dls_devnet_cachep, ddp);
818 }
819 
820 /*
821  * Disassociate a linkid with a given link (identified by <macname/vid>)
822  */
823 static int
824 dls_devnet_unset(const char *macname, uint16_t vid, datalink_id_t *id)
825 {
826 	dls_devnet_t	*ddp;
827 	char		spa[MAXSPALEN];
828 	int		err;
829 
830 	(void) snprintf(spa, MAXSPALEN, "%s/%d", macname, vid);
831 
832 	rw_enter(&i_dls_devnet_lock, RW_WRITER);
833 	if ((err = mod_hash_find(i_dls_devnet_hash,
834 	    (mod_hash_key_t)spa, (mod_hash_val_t *)&ddp)) != 0) {
835 		ASSERT(err == MH_ERR_NOTFOUND);
836 		rw_exit(&i_dls_devnet_lock);
837 		return (ENOENT);
838 	}
839 
840 	ASSERT(ddp->dd_ref != 0);
841 
842 	if (ddp->dd_ref != 1) {
843 		rw_exit(&i_dls_devnet_lock);
844 		return (EBUSY);
845 	}
846 
847 	ddp->dd_ref--;
848 
849 	if (id != NULL)
850 		*id = ddp->dd_vlanid;
851 
852 	dls_devnet_unset_common(ddp);
853 	rw_exit(&i_dls_devnet_lock);
854 	return (0);
855 }
856 
857 static int
858 dls_devnet_hold(datalink_id_t linkid, dls_devnet_t **ddpp)
859 {
860 	dls_devnet_t		*ddp;
861 	dev_t			phydev = 0;
862 	dls_dev_handle_t	ddh = NULL;
863 	int			err;
864 
865 	/*
866 	 * Hold this link to prevent it being detached in case of a
867 	 * physical link.
868 	 */
869 	if (dls_mgmt_get_phydev(linkid, &phydev) == 0)
870 		(void) softmac_hold_device(phydev, &ddh);
871 
872 	rw_enter(&i_dls_devnet_lock, RW_WRITER);
873 	if ((err = mod_hash_find(i_dls_devnet_id_hash,
874 	    (mod_hash_key_t)(uintptr_t)linkid, (mod_hash_val_t *)&ddp)) != 0) {
875 		ASSERT(err == MH_ERR_NOTFOUND);
876 		rw_exit(&i_dls_devnet_lock);
877 		softmac_rele_device(ddh);
878 		return (ENOENT);
879 	}
880 
881 	ASSERT(ddp->dd_ref > 0);
882 	ddp->dd_ref++;
883 	rw_exit(&i_dls_devnet_lock);
884 	softmac_rele_device(ddh);
885 
886 done:
887 	*ddpp = ddp;
888 	return (0);
889 }
890 
891 /*
892  * This funtion is called when a DLS client tries to open a device node.
893  * This dev_t could a result of a /dev/net node access (returned by
894  * devnet_create_rvp->dls_devnet_open()) or a direct /dev node access.
895  * In both cases, this function returns 0. In the first case, bump the
896  * reference count of the dls_devnet_t structure, so that it will not be
897  * freed when devnet_inactive_callback->dls_devnet_close() is called
898  * (Note that devnet_inactive_callback() is called right after dld_open,
899  * not when the /dev/net access is done). In the second case, ddhp would
900  * be NULL.
901  *
902  * To undo this function, call dls_devnet_close() in the first case, and call
903  * dls_vlan_rele() in the second case.
904  */
905 int
906 dls_devnet_open_by_dev(dev_t dev, dls_vlan_t **dvpp, dls_dl_handle_t *ddhp)
907 {
908 	dls_dev_handle_t	ddh = NULL;
909 	char			spa[MAXSPALEN];
910 	dls_devnet_t		*ddp;
911 	dls_vlan_t		*dvp;
912 	int			err;
913 
914 	/*
915 	 * Hold this link to prevent it being detached in case of a
916 	 * GLDv3 physical link.
917 	 */
918 	if (getminor(dev) - 1 < MAC_MAX_MINOR)
919 		(void) softmac_hold_device(dev, &ddh);
920 
921 	/*
922 	 * Found the dls_vlan_t with the given dev.
923 	 */
924 	err = dls_vlan_hold_by_dev(dev, &dvp);
925 	softmac_rele_device(ddh);
926 
927 	if (err != 0)
928 		return (err);
929 
930 	(void) snprintf(spa, MAXSPALEN, "%s/%d",
931 	    dvp->dv_dlp->dl_name, dvp->dv_id);
932 
933 	rw_enter(&i_dls_devnet_lock, RW_WRITER);
934 	if ((err = mod_hash_find(i_dls_devnet_hash,
935 	    (mod_hash_key_t)spa, (mod_hash_val_t *)&ddp)) != 0) {
936 		ASSERT(err == MH_ERR_NOTFOUND);
937 		rw_exit(&i_dls_devnet_lock);
938 		*ddhp = NULL;
939 		*dvpp = dvp;
940 		return (0);
941 	}
942 
943 	ASSERT(ddp->dd_ref > 0);
944 	ddp->dd_ref++;
945 	rw_exit(&i_dls_devnet_lock);
946 	*ddhp = ddp;
947 	*dvpp = dvp;
948 	return (0);
949 }
950 
951 static void
952 dls_devnet_rele(dls_devnet_t *ddp)
953 {
954 	rw_enter(&i_dls_devnet_lock, RW_WRITER);
955 	ASSERT(ddp->dd_ref != 0);
956 	if (--ddp->dd_ref != 0) {
957 		rw_exit(&i_dls_devnet_lock);
958 		return;
959 	}
960 	/*
961 	 * This should only happen for implicitly-created VLAN.
962 	 */
963 	ASSERT(ddp->dd_vid != VLAN_ID_NONE);
964 	dls_devnet_unset_common(ddp);
965 	rw_exit(&i_dls_devnet_lock);
966 }
967 
968 static int
969 dls_devnet_hold_by_name(const char *link, dls_devnet_t **ddpp, zoneid_t zid)
970 {
971 	char			link_under[MAXLINKNAMELEN];
972 	char			drv[MAXLINKNAMELEN];
973 	uint_t			ppa;
974 	major_t			major;
975 	dev_t			phy_dev, tmp_dev;
976 	uint_t			vid;
977 	datalink_id_t		linkid;
978 	dls_devnet_t		*ddp;
979 	dls_dev_handle_t	ddh;
980 	int			err;
981 
982 	if ((err = dls_mgmt_get_linkid(link, &linkid)) == 0)
983 		return (dls_devnet_hold(linkid, ddpp));
984 
985 	/*
986 	 * If we failed to get the link's linkid because the dlmgmtd daemon
987 	 * has not been started, return ENOENT so that the application can
988 	 * fallback to open the /dev node.
989 	 */
990 	if (err == EBADF)
991 		return (ENOENT);
992 
993 	if (err != ENOENT)
994 		return (err);
995 
996 	if (ddi_parse(link, drv, &ppa) != DDI_SUCCESS)
997 		return (ENOENT);
998 
999 	if ((vid = DLS_PPA2VID(ppa)) > VLAN_ID_MAX)
1000 		return (ENOENT);
1001 
1002 	ppa = (uint_t)DLS_PPA2INST(ppa);
1003 	(void) snprintf(link_under, sizeof (link_under), "%s%d", drv, ppa);
1004 
1005 	if (vid != VLAN_ID_NONE) {
1006 		/*
1007 		 * Only global zone can implicitly create a VLAN.
1008 		 */
1009 		if (zid != GLOBAL_ZONEID)
1010 			return (ENOENT);
1011 
1012 		/*
1013 		 * This is potentially an implicitly-created VLAN. Hold the
1014 		 * link this VLAN is created on.
1015 		 */
1016 		if (dls_mgmt_get_linkid(link_under, &linkid) == 0 &&
1017 		    dls_devnet_hold_tmp(linkid, &ddp) == 0) {
1018 			if (ddp->dd_vid != VLAN_ID_NONE) {
1019 				dls_devnet_rele_tmp(ddp);
1020 				return (ENOENT);
1021 			}
1022 			goto implicit;
1023 		}
1024 	}
1025 
1026 	/*
1027 	 * If this link (or the link that an implicit vlan is created on)
1028 	 * (a) is a physical device, (b) this is the first boot, (c) the MAC
1029 	 * is not registered yet, and (d) we cannot find its linkid, then the
1030 	 * linkname is the same as the devname.
1031 	 *
1032 	 * First filter out invalid names.
1033 	 */
1034 	if ((major = ddi_name_to_major(drv)) == (major_t)-1)
1035 		return (ENOENT);
1036 
1037 	phy_dev = makedevice(major, (minor_t)ppa + 1);
1038 	if (softmac_hold_device(phy_dev, &ddh) != 0)
1039 		return (ENOENT);
1040 
1041 	/*
1042 	 * At this time, the MAC should be registered, check its phy_dev using
1043 	 * the given name.
1044 	 */
1045 	if ((err = dls_mgmt_get_linkid(link_under, &linkid)) != 0 ||
1046 	    (err = dls_mgmt_get_phydev(linkid, &tmp_dev)) != 0) {
1047 		softmac_rele_device(ddh);
1048 		return (err);
1049 	}
1050 	if (tmp_dev != phy_dev) {
1051 		softmac_rele_device(ddh);
1052 		return (ENOENT);
1053 	}
1054 
1055 	if (vid == VLAN_ID_NONE) {
1056 		/*
1057 		 * For non-VLAN, we are done.
1058 		 */
1059 		err = dls_devnet_hold(linkid, ddpp);
1060 		softmac_rele_device(ddh);
1061 		return (err);
1062 	}
1063 
1064 	/*
1065 	 * If this is an implicit VLAN, temporarily hold this non-VLAN.
1066 	 */
1067 	VERIFY(dls_devnet_hold_tmp(linkid, &ddp) == 0);
1068 	softmac_rele_device(ddh);
1069 	ASSERT(ddp->dd_vid == VLAN_ID_NONE);
1070 
1071 	/*
1072 	 * Again, this is potentially an implicitly-created VLAN.
1073 	 */
1074 
1075 implicit:
1076 	ASSERT(vid != VLAN_ID_NONE);
1077 	err = dls_devnet_set(ddp->dd_mac, vid, DATALINK_INVALID_LINKID,
1078 	    linkid, link, ddpp);
1079 	dls_devnet_rele_tmp(ddp);
1080 	return (err);
1081 }
1082 
1083 /*
1084  * Get linkid for the given dev.
1085  */
1086 int
1087 dls_devnet_dev2linkid(dev_t dev, datalink_id_t *linkidp)
1088 {
1089 	dls_vlan_t	*dvp;
1090 	dls_devnet_t	*ddp;
1091 	char		spa[MAXSPALEN];
1092 	int		err;
1093 
1094 	if ((err = dls_vlan_hold_by_dev(dev, &dvp)) != 0)
1095 		return (err);
1096 
1097 	(void) snprintf(spa, MAXSPALEN, "%s/%d",
1098 	    dvp->dv_dlp->dl_name, dvp->dv_id);
1099 
1100 	rw_enter(&i_dls_devnet_lock, RW_READER);
1101 	if (mod_hash_find(i_dls_devnet_hash, (mod_hash_key_t)spa,
1102 	    (mod_hash_val_t *)&ddp) != 0) {
1103 		rw_exit(&i_dls_devnet_lock);
1104 		dls_vlan_rele(dvp);
1105 		return (ENOENT);
1106 	}
1107 
1108 	*linkidp = ddp->dd_vlanid;
1109 	rw_exit(&i_dls_devnet_lock);
1110 	dls_vlan_rele(dvp);
1111 	return (0);
1112 }
1113 
1114 /*
1115  * Get the link's physical dev_t. It this is a VLAN, get the dev_t of the
1116  * link this VLAN is created on.
1117  */
1118 int
1119 dls_devnet_phydev(datalink_id_t vlanid, dev_t *devp)
1120 {
1121 	dls_devnet_t	*ddp;
1122 	int		err;
1123 
1124 	if ((err = dls_devnet_hold_tmp(vlanid, &ddp)) != 0)
1125 		return (err);
1126 
1127 	err = dls_mgmt_get_phydev(ddp->dd_linkid, devp);
1128 	dls_devnet_rele_tmp(ddp);
1129 	return (err);
1130 }
1131 
1132 /*
1133  * Handle the renaming requests.  There are two rename cases:
1134  *
1135  * 1. Request to rename a valid link (id1) to an non-existent link name
1136  *    (id2). In this case id2 is DATALINK_INVALID_LINKID.  Just check whether
1137  *    id1 is held by any applications.
1138  *
1139  *    In this case, the link's kstats need to be updated using the given name.
1140  *
1141  * 2. Request to rename a valid link (id1) to the name of a REMOVED
1142  *    physical link (id2). In this case, check htat id1 and its associated
1143  *    mac is not held by any application, and update the link's linkid to id2.
1144  *
1145  *    This case does not change the <link name, linkid> mapping, so the link's
1146  *    kstats need to be updated with using name associated the given id2.
1147  */
1148 int
1149 dls_devnet_rename(datalink_id_t id1, datalink_id_t id2, const char *link)
1150 {
1151 	dls_dev_handle_t	ddh = NULL;
1152 	char			linkname[MAXLINKNAMELEN];
1153 	int			err = 0;
1154 	dev_t			phydev = 0;
1155 	dls_devnet_t		*ddp;
1156 	mac_handle_t		mh;
1157 	mod_hash_val_t		val;
1158 
1159 	/*
1160 	 * In the second case, id2 must be a REMOVED physical link.
1161 	 */
1162 	if ((id2 != DATALINK_INVALID_LINKID) &&
1163 	    (dls_mgmt_get_phydev(id2, &phydev) == 0) &&
1164 	    softmac_hold_device(phydev, &ddh) == 0) {
1165 		softmac_rele_device(ddh);
1166 		return (EEXIST);
1167 	}
1168 
1169 	/*
1170 	 * Hold id1 to prevent it from being detached (if a physical link).
1171 	 */
1172 	if (dls_mgmt_get_phydev(id1, &phydev) == 0)
1173 		(void) softmac_hold_device(phydev, &ddh);
1174 
1175 	rw_enter(&i_dls_devnet_lock, RW_WRITER);
1176 	if ((err = mod_hash_find(i_dls_devnet_id_hash,
1177 	    (mod_hash_key_t)(uintptr_t)id1, (mod_hash_val_t *)&ddp)) != 0) {
1178 		ASSERT(err == MH_ERR_NOTFOUND);
1179 		err = ENOENT;
1180 		goto done;
1181 	}
1182 
1183 	/*
1184 	 * Return EBUSY if any applications have this link open.
1185 	 */
1186 	if ((ddp->dd_explicit && ddp->dd_ref > 1) ||
1187 	    (!ddp->dd_explicit && ddp->dd_ref > 0)) {
1188 		err = EBUSY;
1189 		goto done;
1190 	}
1191 
1192 	if (id2 == DATALINK_INVALID_LINKID) {
1193 		(void) strlcpy(linkname, link, sizeof (linkname));
1194 		goto done;
1195 	}
1196 
1197 	/*
1198 	 * The second case, check whether the MAC is used by any MAC
1199 	 * user.  This must be a physical link so ddh must not be NULL.
1200 	 */
1201 	if (ddh == NULL) {
1202 		err = EINVAL;
1203 		goto done;
1204 	}
1205 
1206 	if ((err = mac_open(ddp->dd_mac, &mh)) != 0)
1207 		goto done;
1208 
1209 	/*
1210 	 * We release the reference of the MAC which mac_open() is
1211 	 * holding. Note that this mac will not be unregistered
1212 	 * because the physical device is hold.
1213 	 */
1214 	mac_close(mh);
1215 
1216 	/*
1217 	 * Check if there is any other MAC clients, if not, hold this mac
1218 	 * exclusively until we are done.
1219 	 */
1220 	if ((err = mac_hold_exclusive(mh)) != 0)
1221 		goto done;
1222 
1223 	/*
1224 	 * Update the link's linkid.
1225 	 */
1226 	if ((err = mod_hash_find(i_dls_devnet_id_hash,
1227 	    (mod_hash_key_t)(uintptr_t)id2, &val)) != MH_ERR_NOTFOUND) {
1228 		mac_rele_exclusive(mh);
1229 		err = EEXIST;
1230 		goto done;
1231 	}
1232 
1233 	err = dls_mgmt_get_linkinfo(id2, linkname, NULL, NULL, NULL);
1234 	if (err != 0) {
1235 		mac_rele_exclusive(mh);
1236 		goto done;
1237 	}
1238 
1239 	(void) mod_hash_remove(i_dls_devnet_id_hash,
1240 	    (mod_hash_key_t)(uintptr_t)id1, &val);
1241 
1242 	ddp->dd_vlanid = id2;
1243 	(void) mod_hash_insert(i_dls_devnet_id_hash,
1244 	    (mod_hash_key_t)(uintptr_t)ddp->dd_vlanid, (mod_hash_val_t)ddp);
1245 
1246 	mac_rele_exclusive(mh);
1247 
1248 done:
1249 	/*
1250 	 * Change the name of the kstat based on the new link name.
1251 	 */
1252 	if (err == 0)
1253 		dls_devnet_stat_rename(ddp, linkname);
1254 
1255 	rw_exit(&i_dls_devnet_lock);
1256 	softmac_rele_device(ddh);
1257 	return (err);
1258 }
1259 
1260 int
1261 dls_devnet_setzid(const char *link, zoneid_t zid)
1262 {
1263 	dls_devnet_t	*ddp;
1264 	int		err;
1265 	zoneid_t	old_zid;
1266 
1267 	if ((err = dls_devnet_hold_by_name(link, &ddp, GLOBAL_ZONEID)) != 0)
1268 		return (err);
1269 
1270 	mutex_enter(&ddp->dd_zid_mutex);
1271 	if ((old_zid = ddp->dd_zid) == zid) {
1272 		mutex_exit(&ddp->dd_zid_mutex);
1273 		dls_devnet_rele(ddp);
1274 		return (0);
1275 	}
1276 
1277 	if ((err = dls_vlan_setzid(ddp->dd_mac, ddp->dd_vid, zid)) != 0) {
1278 		mutex_exit(&ddp->dd_zid_mutex);
1279 		dls_devnet_rele(ddp);
1280 		return (err);
1281 	}
1282 
1283 	ddp->dd_zid = zid;
1284 	devnet_need_rebuild = B_TRUE;
1285 	mutex_exit(&ddp->dd_zid_mutex);
1286 
1287 	/*
1288 	 * Keep this open reference only if it belonged to the global zone
1289 	 * and is now assigned to a non-global zone.
1290 	 */
1291 	if (old_zid != GLOBAL_ZONEID || zid == GLOBAL_ZONEID)
1292 		dls_devnet_rele(ddp);
1293 
1294 	/*
1295 	 * Then release this link if it belonged to an non-global zone
1296 	 * but is now assigned back to the global zone.
1297 	 */
1298 	if (old_zid != GLOBAL_ZONEID && zid == GLOBAL_ZONEID)
1299 		dls_devnet_rele(ddp);
1300 
1301 	return (0);
1302 }
1303 
1304 int
1305 dls_devnet_getzid(datalink_id_t linkid, zoneid_t *zidp)
1306 {
1307 	dls_devnet_t	*ddp;
1308 	int		err;
1309 
1310 	if ((err = dls_devnet_hold_tmp(linkid, &ddp)) != 0)
1311 		return (err);
1312 
1313 	mutex_enter(&ddp->dd_zid_mutex);
1314 	*zidp = ddp->dd_zid;
1315 	mutex_exit(&ddp->dd_zid_mutex);
1316 
1317 	dls_devnet_rele_tmp(ddp);
1318 	return (0);
1319 }
1320 
1321 /*
1322  * Access a vanity naming node.
1323  */
1324 int
1325 dls_devnet_open(const char *link, dls_dl_handle_t *dhp, dev_t *devp)
1326 {
1327 	dls_devnet_t	*ddp;
1328 	dls_vlan_t	*dvp;
1329 	zoneid_t	zid = getzoneid();
1330 	int		err;
1331 
1332 	if ((err = dls_devnet_hold_by_name(link, &ddp, zid)) != 0)
1333 		return (err);
1334 
1335 	/*
1336 	 * Opening a link that does not belong to the current non-global zone
1337 	 * is not allowed.
1338 	 */
1339 	if (zid != GLOBAL_ZONEID && ddp->dd_zid != zid) {
1340 		dls_devnet_rele(ddp);
1341 		return (ENOENT);
1342 	}
1343 
1344 	err = dls_vlan_hold(ddp->dd_mac, ddp->dd_vid, &dvp, B_FALSE, B_TRUE);
1345 	if (err != 0) {
1346 		dls_devnet_rele(ddp);
1347 		return (err);
1348 	}
1349 
1350 	*dhp = ddp;
1351 	*devp = dvp->dv_dev;
1352 	return (0);
1353 }
1354 
1355 /*
1356  * Close access to a vanity naming node.
1357  */
1358 void
1359 dls_devnet_close(dls_dl_handle_t dlh)
1360 {
1361 	dls_devnet_t	*ddp = dlh;
1362 	dls_vlan_t	*dvp;
1363 
1364 	/*
1365 	 * The VLAN is hold in dls_open_devnet_link().
1366 	 */
1367 	VERIFY((dls_vlan_hold(ddp->dd_mac, ddp->dd_vid, &dvp, B_FALSE,
1368 	    B_FALSE)) == 0);
1369 	dls_vlan_rele(dvp);
1370 	dls_vlan_rele(dvp);
1371 	dls_devnet_rele(ddp);
1372 }
1373 
1374 /*
1375  * This is used by /dev/net to rebuild the nodes for readdir().  It is not
1376  * critical and no protection is needed.
1377  */
1378 boolean_t
1379 dls_devnet_rebuild()
1380 {
1381 	boolean_t updated = devnet_need_rebuild;
1382 
1383 	devnet_need_rebuild = B_FALSE;
1384 	return (updated);
1385 }
1386 
1387 int
1388 dls_devnet_create(mac_handle_t mh, datalink_id_t linkid)
1389 {
1390 	int		err;
1391 
1392 	if ((err = dls_vlan_create(mac_name(mh), 0, B_FALSE)) != 0)
1393 		return (err);
1394 
1395 	err = dls_devnet_set(mac_name(mh), 0, linkid, linkid, NULL, NULL);
1396 	if (err != 0)
1397 		(void) dls_vlan_destroy(mac_name(mh), 0);
1398 
1399 	return (err);
1400 }
1401 
1402 /*
1403  * Set the linkid of the dls_devnet_t and add it into the i_dls_devnet_id_hash.
1404  * This is called in the case that the dlmgmtd daemon is started later than
1405  * the physical devices get attached, and the linkid is only known after the
1406  * daemon starts.
1407  */
1408 int
1409 dls_devnet_recreate(mac_handle_t mh, datalink_id_t linkid)
1410 {
1411 	ASSERT(linkid != DATALINK_INVALID_LINKID);
1412 	return (dls_devnet_set(mac_name(mh), 0, linkid, linkid, NULL, NULL));
1413 }
1414 
1415 int
1416 dls_devnet_destroy(mac_handle_t mh, datalink_id_t *idp)
1417 {
1418 	int		err;
1419 
1420 	*idp = DATALINK_INVALID_LINKID;
1421 	err = dls_devnet_unset(mac_name(mh), 0, idp);
1422 	if (err != 0 && err != ENOENT)
1423 		return (err);
1424 
1425 	if ((err = dls_vlan_destroy(mac_name(mh), 0)) == 0)
1426 		return (0);
1427 
1428 	(void) dls_devnet_set(mac_name(mh), 0, *idp, *idp, NULL, NULL);
1429 	return (err);
1430 }
1431 
1432 int
1433 dls_devnet_create_vlan(datalink_id_t vlanid, datalink_id_t linkid,
1434     uint16_t vid, boolean_t force)
1435 {
1436 	dls_devnet_t	*lnddp, *ddp;
1437 	dls_vlan_t	*dvp;
1438 	int		err;
1439 
1440 	/*
1441 	 * Hold the link the VLAN is being created on (which must not be a
1442 	 * VLAN).
1443 	 */
1444 	ASSERT(vid != VLAN_ID_NONE);
1445 	if ((err = dls_devnet_hold_tmp(linkid, &lnddp)) != 0)
1446 		return (err);
1447 
1448 	if (lnddp->dd_vid != VLAN_ID_NONE) {
1449 		err = EINVAL;
1450 		goto done;
1451 	}
1452 
1453 	/*
1454 	 * A new link.
1455 	 */
1456 	err = dls_devnet_set(lnddp->dd_mac, vid, vlanid, linkid, NULL, &ddp);
1457 	if (err != 0)
1458 		goto done;
1459 
1460 	/*
1461 	 * Hold the dls_vlan_t (and create it if needed).
1462 	 */
1463 	err = dls_vlan_hold(ddp->dd_mac, ddp->dd_vid, &dvp, force, B_TRUE);
1464 	if (err != 0)
1465 		VERIFY(dls_devnet_unset(lnddp->dd_mac, vid, NULL) == 0);
1466 
1467 done:
1468 	dls_devnet_rele_tmp(lnddp);
1469 	return (err);
1470 }
1471 
1472 int
1473 dls_devnet_destroy_vlan(datalink_id_t vlanid)
1474 {
1475 	char		macname[MAXNAMELEN];
1476 	uint16_t	vid;
1477 	dls_devnet_t	*ddp;
1478 	dls_vlan_t	*dvp;
1479 	int		err;
1480 
1481 	if ((err = dls_devnet_hold_tmp(vlanid, &ddp)) != 0)
1482 		return (err);
1483 
1484 	if (ddp->dd_vid == VLAN_ID_NONE) {
1485 		dls_devnet_rele_tmp(ddp);
1486 		return (EINVAL);
1487 	}
1488 
1489 	if (!ddp->dd_explicit) {
1490 		dls_devnet_rele_tmp(ddp);
1491 		return (EBUSY);
1492 	}
1493 
1494 	(void) strncpy(macname, ddp->dd_mac, MAXNAMELEN);
1495 	vid = ddp->dd_vid;
1496 
1497 	/*
1498 	 * It is safe to release the temporary reference we just held, as the
1499 	 * reference from VLAN creation is still held.
1500 	 */
1501 	dls_devnet_rele_tmp(ddp);
1502 
1503 	if ((err = dls_devnet_unset(macname, vid, NULL)) != 0)
1504 		return (err);
1505 
1506 	/*
1507 	 * This VLAN has already been held as the result of VLAN creation.
1508 	 */
1509 	VERIFY(dls_vlan_hold(macname, vid, &dvp, B_FALSE, B_FALSE) == 0);
1510 
1511 	/*
1512 	 * Release the reference which was held when this VLAN was created,
1513 	 * and the reference which was just held.
1514 	 */
1515 	dls_vlan_rele(dvp);
1516 	dls_vlan_rele(dvp);
1517 	return (0);
1518 }
1519 
1520 const char *
1521 dls_devnet_mac(dls_dl_handle_t ddh)
1522 {
1523 	return (ddh->dd_mac);
1524 }
1525 
1526 uint16_t
1527 dls_devnet_vid(dls_dl_handle_t ddh)
1528 {
1529 	return (ddh->dd_vid);
1530 }
1531 
1532 datalink_id_t
1533 dls_devnet_linkid(dls_dl_handle_t ddh)
1534 {
1535 	return (ddh->dd_linkid);
1536 }
1537 
1538 boolean_t
1539 dls_devnet_is_explicit(dls_dl_handle_t ddh)
1540 {
1541 	return (ddh->dd_explicit);
1542 }
1543