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