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