8149 deadlock between datalink deletion and kstat read
[unleashed.git] / usr / src / uts / common / io / dls / dls_mgmt.c
blob44732662421118e908c9b0a96af1c574c30ad8b8
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 * Copyright (c) 2016 by Delphix. All rights reserved.
30 * Datalink management routines.
33 #include <sys/types.h>
34 #include <sys/door.h>
35 #include <sys/zone.h>
36 #include <sys/modctl.h>
37 #include <sys/file.h>
38 #include <sys/modhash.h>
39 #include <sys/kstat.h>
40 #include <sys/vnode.h>
41 #include <sys/cmn_err.h>
42 #include <sys/softmac.h>
43 #include <sys/dls.h>
44 #include <sys/dls_impl.h>
45 #include <sys/stropts.h>
46 #include <sys/netstack.h>
47 #include <inet/iptun/iptun_impl.h>
50 * This vanity name management module is treated as part of the GLD framework
51 * and we don't hold any GLD framework lock across a call to any mac
52 * function that needs to acquire the mac perimeter. The hierarchy is
53 * mac perimeter -> framework locks
56 typedef struct dls_stack {
57 zoneid_t dlss_zoneid;
58 } dls_stack_t;
60 static kmem_cache_t *i_dls_devnet_cachep;
61 static kmutex_t i_dls_mgmt_lock;
62 static krwlock_t i_dls_devnet_lock;
63 static mod_hash_t *i_dls_devnet_id_hash;
64 static mod_hash_t *i_dls_devnet_hash;
66 boolean_t devnet_need_rebuild;
68 #define VLAN_HASHSZ 67 /* prime */
71 * The following macros take a link name without the trailing PPA as input.
72 * Opening a /dev/net node with one of these names causes a tunnel link to be
73 * implicitly created in dls_devnet_hold_by_name() for backward compatibility
74 * with Solaris 10 and prior.
76 #define IS_IPV4_TUN(name) (strcmp((name), "ip.tun") == 0)
77 #define IS_IPV6_TUN(name) (strcmp((name), "ip6.tun") == 0)
78 #define IS_6TO4_TUN(name) (strcmp((name), "ip.6to4tun") == 0)
79 #define IS_IPTUN_LINK(name) ( \
80 IS_IPV4_TUN(name) || IS_IPV6_TUN(name) || IS_6TO4_TUN(name))
82 /* Upcall door handle */
83 static door_handle_t dls_mgmt_dh = NULL;
85 /* dls_devnet_t dd_flags */
86 #define DD_CONDEMNED 0x1
87 #define DD_IMPLICIT_IPTUN 0x2 /* Implicitly-created ip*.*tun* tunnel */
90 * This structure is used to keep the <linkid, macname> mapping.
91 * This structure itself is not protected by the mac perimeter, but is
92 * protected by the dd_mutex and i_dls_devnet_lock. Thus most of the
93 * functions manipulating this structure such as dls_devnet_set/unset etc.
94 * may be called while not holding the mac perimeter.
96 typedef struct dls_devnet_s {
97 datalink_id_t dd_linkid;
98 char dd_linkname[MAXLINKNAMELEN];
99 char dd_mac[MAXNAMELEN];
100 kstat_t *dd_ksp; /* kstat in owner_zid */
101 kstat_t *dd_zone_ksp; /* in dd_zid if != owner_zid */
102 uint32_t dd_ref;
103 kmutex_t dd_mutex;
104 kcondvar_t dd_cv;
105 uint32_t dd_tref;
106 uint_t dd_flags;
107 zoneid_t dd_owner_zid; /* zone where node was created */
108 zoneid_t dd_zid; /* current zone */
109 boolean_t dd_prop_loaded;
110 taskqid_t dd_prop_taskid;
111 } dls_devnet_t;
113 static int i_dls_devnet_create_iptun(const char *, const char *,
114 datalink_id_t *);
115 static int i_dls_devnet_destroy_iptun(datalink_id_t);
116 static int i_dls_devnet_setzid(dls_devnet_t *, zoneid_t, boolean_t);
117 static int dls_devnet_unset(const char *, datalink_id_t *, boolean_t);
119 /*ARGSUSED*/
120 static int
121 i_dls_devnet_constructor(void *buf, void *arg, int kmflag)
123 dls_devnet_t *ddp = buf;
125 bzero(buf, sizeof (dls_devnet_t));
126 mutex_init(&ddp->dd_mutex, NULL, MUTEX_DEFAULT, NULL);
127 cv_init(&ddp->dd_cv, NULL, CV_DEFAULT, NULL);
128 return (0);
131 /*ARGSUSED*/
132 static void
133 i_dls_devnet_destructor(void *buf, void *arg)
135 dls_devnet_t *ddp = buf;
137 ASSERT(ddp->dd_ksp == NULL);
138 ASSERT(ddp->dd_ref == 0);
139 ASSERT(ddp->dd_tref == 0);
140 mutex_destroy(&ddp->dd_mutex);
141 cv_destroy(&ddp->dd_cv);
144 /* ARGSUSED */
145 static int
146 dls_zone_remove(datalink_id_t linkid, void *arg)
148 dls_devnet_t *ddp;
150 if (dls_devnet_hold_tmp(linkid, &ddp) == 0) {
151 (void) dls_devnet_setzid(ddp, GLOBAL_ZONEID);
152 dls_devnet_rele_tmp(ddp);
154 return (0);
157 /* ARGSUSED */
158 static void *
159 dls_stack_init(netstackid_t stackid, netstack_t *ns)
161 dls_stack_t *dlss;
163 dlss = kmem_zalloc(sizeof (*dlss), KM_SLEEP);
164 dlss->dlss_zoneid = netstackid_to_zoneid(stackid);
165 return (dlss);
168 /* ARGSUSED */
169 static void
170 dls_stack_shutdown(netstackid_t stackid, void *arg)
172 dls_stack_t *dlss = (dls_stack_t *)arg;
174 /* Move remaining datalinks in this zone back to the global zone. */
175 (void) zone_datalink_walk(dlss->dlss_zoneid, dls_zone_remove, NULL);
178 /* ARGSUSED */
179 static void
180 dls_stack_fini(netstackid_t stackid, void *arg)
182 dls_stack_t *dlss = (dls_stack_t *)arg;
184 kmem_free(dlss, sizeof (*dlss));
188 * Module initialization and finalization functions.
190 void
191 dls_mgmt_init(void)
193 mutex_init(&i_dls_mgmt_lock, NULL, MUTEX_DEFAULT, NULL);
194 rw_init(&i_dls_devnet_lock, NULL, RW_DEFAULT, NULL);
197 * Create a kmem_cache of dls_devnet_t structures.
199 i_dls_devnet_cachep = kmem_cache_create("dls_devnet_cache",
200 sizeof (dls_devnet_t), 0, i_dls_devnet_constructor,
201 i_dls_devnet_destructor, NULL, NULL, NULL, 0);
202 ASSERT(i_dls_devnet_cachep != NULL);
205 * Create a hash table, keyed by dd_linkid, of dls_devnet_t.
207 i_dls_devnet_id_hash = mod_hash_create_idhash("dls_devnet_id_hash",
208 VLAN_HASHSZ, mod_hash_null_valdtor);
211 * Create a hash table, keyed by dd_mac
213 i_dls_devnet_hash = mod_hash_create_extended("dls_devnet_hash",
214 VLAN_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
215 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
217 devnet_need_rebuild = B_FALSE;
219 netstack_register(NS_DLS, dls_stack_init, dls_stack_shutdown,
220 dls_stack_fini);
223 void
224 dls_mgmt_fini(void)
226 netstack_unregister(NS_DLS);
227 mod_hash_destroy_hash(i_dls_devnet_hash);
228 mod_hash_destroy_hash(i_dls_devnet_id_hash);
229 kmem_cache_destroy(i_dls_devnet_cachep);
230 rw_destroy(&i_dls_devnet_lock);
231 mutex_destroy(&i_dls_mgmt_lock);
235 dls_mgmt_door_set(boolean_t start)
237 int err;
239 /* handle daemon restart */
240 mutex_enter(&i_dls_mgmt_lock);
241 if (dls_mgmt_dh != NULL) {
242 door_ki_rele(dls_mgmt_dh);
243 dls_mgmt_dh = NULL;
246 if (start && ((err = door_ki_open(DLMGMT_DOOR, &dls_mgmt_dh)) != 0)) {
247 mutex_exit(&i_dls_mgmt_lock);
248 return (err);
251 mutex_exit(&i_dls_mgmt_lock);
254 * Create and associate <link name, linkid> mapping for network devices
255 * which are already attached before the daemon is started.
257 if (start)
258 softmac_recreate();
259 return (0);
262 static boolean_t
263 i_dls_mgmt_door_revoked(door_handle_t dh)
265 struct door_info info;
266 extern int sys_shutdown;
268 ASSERT(dh != NULL);
270 if (sys_shutdown) {
271 cmn_err(CE_NOTE, "dls_mgmt_door: shutdown observed\n");
272 return (B_TRUE);
275 if (door_ki_info(dh, &info) != 0)
276 return (B_TRUE);
278 return ((info.di_attributes & DOOR_REVOKED) != 0);
282 * Upcall to the datalink management daemon (dlmgmtd).
284 static int
285 i_dls_mgmt_upcall(void *arg, size_t asize, void *rbuf, size_t rsize)
287 door_arg_t darg, save_arg;
288 door_handle_t dh;
289 int err;
290 int retry = 0;
292 #define MAXRETRYNUM 3
294 ASSERT(arg);
295 darg.data_ptr = arg;
296 darg.data_size = asize;
297 darg.desc_ptr = NULL;
298 darg.desc_num = 0;
299 darg.rbuf = rbuf;
300 darg.rsize = rsize;
301 save_arg = darg;
303 retry:
304 mutex_enter(&i_dls_mgmt_lock);
305 dh = dls_mgmt_dh;
306 if ((dh == NULL) || i_dls_mgmt_door_revoked(dh)) {
307 mutex_exit(&i_dls_mgmt_lock);
308 return (EBADF);
310 door_ki_hold(dh);
311 mutex_exit(&i_dls_mgmt_lock);
313 for (;;) {
314 retry++;
315 if ((err = door_ki_upcall_limited(dh, &darg, zone_kcred(),
316 SIZE_MAX, 0)) == 0)
317 break;
320 * handle door call errors
322 darg = save_arg;
323 switch (err) {
324 case EINTR:
326 * If the operation which caused this door upcall gets
327 * interrupted, return directly.
329 goto done;
330 case EAGAIN:
332 * Repeat upcall if the maximum attempt limit has not
333 * been reached.
335 if (retry < MAXRETRYNUM) {
336 delay(2 * hz);
337 break;
339 cmn_err(CE_WARN, "dls: dlmgmtd fatal error %d\n", err);
340 goto done;
341 default:
342 /* A fatal door error */
343 if (i_dls_mgmt_door_revoked(dh)) {
344 cmn_err(CE_NOTE,
345 "dls: dlmgmtd door service revoked\n");
347 if (retry < MAXRETRYNUM) {
348 door_ki_rele(dh);
349 goto retry;
352 cmn_err(CE_WARN, "dls: dlmgmtd fatal error %d\n", err);
353 goto done;
357 if (darg.rbuf != rbuf) {
359 * The size of the input rbuf was not big enough, so the
360 * upcall allocated the rbuf itself. If this happens, assume
361 * that this was an invalid door call request.
363 kmem_free(darg.rbuf, darg.rsize);
364 err = ENOSPC;
365 goto done;
368 if (darg.rsize != rsize) {
369 err = EINVAL;
370 goto done;
373 err = ((dlmgmt_retval_t *)rbuf)->lr_err;
375 done:
376 door_ki_rele(dh);
377 return (err);
381 * Request the datalink management daemon to create a link with the attributes
382 * below. Upon success, zero is returned and linkidp contains the linkid for
383 * the new link; otherwise, an errno is returned.
385 * - dev physical dev_t. required for all physical links,
386 * including GLDv3 links. It will be used to force the
387 * attachment of a physical device, hence the
388 * registration of its mac
389 * - class datalink class
390 * - media type media type; DL_OTHER means unknown
391 * - persist whether to persist the datalink
394 dls_mgmt_create(const char *devname, dev_t dev, datalink_class_t class,
395 uint32_t media, boolean_t persist, datalink_id_t *linkidp)
397 dlmgmt_upcall_arg_create_t create;
398 dlmgmt_create_retval_t retval;
399 int err;
401 create.ld_cmd = DLMGMT_CMD_DLS_CREATE;
402 create.ld_class = class;
403 create.ld_media = media;
404 create.ld_phymaj = getmajor(dev);
405 create.ld_phyinst = getminor(dev);
406 create.ld_persist = persist;
407 if (strlcpy(create.ld_devname, devname, sizeof (create.ld_devname)) >=
408 sizeof (create.ld_devname))
409 return (EINVAL);
411 if ((err = i_dls_mgmt_upcall(&create, sizeof (create), &retval,
412 sizeof (retval))) == 0) {
413 *linkidp = retval.lr_linkid;
415 return (err);
419 * Request the datalink management daemon to destroy the specified link.
420 * Returns zero upon success, or an errno upon failure.
423 dls_mgmt_destroy(datalink_id_t linkid, boolean_t persist)
425 dlmgmt_upcall_arg_destroy_t destroy;
426 dlmgmt_destroy_retval_t retval;
428 destroy.ld_cmd = DLMGMT_CMD_DLS_DESTROY;
429 destroy.ld_linkid = linkid;
430 destroy.ld_persist = persist;
432 return (i_dls_mgmt_upcall(&destroy, sizeof (destroy),
433 &retval, sizeof (retval)));
437 * Request the datalink management daemon to verify/update the information
438 * for a physical link. Upon success, get its linkid.
440 * - media type media type
441 * - novanity whether this physical datalink supports vanity naming.
442 * physical links that do not use the GLDv3 MAC plugin
443 * cannot suport vanity naming
445 * This function could fail with ENOENT or EEXIST. Two cases return EEXIST:
447 * 1. A link with devname already exists, but the media type does not match.
448 * In this case, mediap will bee set to the media type of the existing link.
449 * 2. A link with devname already exists, but its link name does not match
450 * the device name, although this link does not support vanity naming.
453 dls_mgmt_update(const char *devname, uint32_t media, boolean_t novanity,
454 uint32_t *mediap, datalink_id_t *linkidp)
456 dlmgmt_upcall_arg_update_t update;
457 dlmgmt_update_retval_t retval;
458 int err;
460 update.ld_cmd = DLMGMT_CMD_DLS_UPDATE;
462 if (strlcpy(update.ld_devname, devname, sizeof (update.ld_devname)) >=
463 sizeof (update.ld_devname))
464 return (EINVAL);
466 update.ld_media = media;
467 update.ld_novanity = novanity;
469 if ((err = i_dls_mgmt_upcall(&update, sizeof (update), &retval,
470 sizeof (retval))) == EEXIST) {
471 *linkidp = retval.lr_linkid;
472 *mediap = retval.lr_media;
473 } else if (err == 0) {
474 *linkidp = retval.lr_linkid;
477 return (err);
481 * Request the datalink management daemon to get the information for a link.
482 * Returns zero upon success, or an errno upon failure.
484 * Only fills in information for argument pointers that are non-NULL.
485 * Note that the link argument is expected to be MAXLINKNAMELEN bytes.
488 dls_mgmt_get_linkinfo(datalink_id_t linkid, char *link,
489 datalink_class_t *classp, uint32_t *mediap, uint32_t *flagsp)
491 dlmgmt_door_getname_t getname;
492 dlmgmt_getname_retval_t retval;
493 int err, len;
495 getname.ld_cmd = DLMGMT_CMD_GETNAME;
496 getname.ld_linkid = linkid;
498 if ((err = i_dls_mgmt_upcall(&getname, sizeof (getname), &retval,
499 sizeof (retval))) != 0) {
500 return (err);
503 len = strlen(retval.lr_link);
504 if (len <= 1 || len >= MAXLINKNAMELEN)
505 return (EINVAL);
507 if (link != NULL)
508 (void) strlcpy(link, retval.lr_link, MAXLINKNAMELEN);
509 if (classp != NULL)
510 *classp = retval.lr_class;
511 if (mediap != NULL)
512 *mediap = retval.lr_media;
513 if (flagsp != NULL)
514 *flagsp = retval.lr_flags;
515 return (0);
519 * Request the datalink management daemon to get the linkid for a link.
520 * Returns a non-zero error code on failure. The linkid argument is only
521 * set on success (when zero is returned.)
524 dls_mgmt_get_linkid(const char *link, datalink_id_t *linkid)
526 dlmgmt_door_getlinkid_t getlinkid;
527 dlmgmt_getlinkid_retval_t retval;
528 int err;
530 getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID;
531 (void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN);
533 if ((err = i_dls_mgmt_upcall(&getlinkid, sizeof (getlinkid), &retval,
534 sizeof (retval))) == 0) {
535 *linkid = retval.lr_linkid;
537 return (err);
540 datalink_id_t
541 dls_mgmt_get_next(datalink_id_t linkid, datalink_class_t class,
542 datalink_media_t dmedia, uint32_t flags)
544 dlmgmt_door_getnext_t getnext;
545 dlmgmt_getnext_retval_t retval;
547 getnext.ld_cmd = DLMGMT_CMD_GETNEXT;
548 getnext.ld_class = class;
549 getnext.ld_dmedia = dmedia;
550 getnext.ld_flags = flags;
551 getnext.ld_linkid = linkid;
553 if (i_dls_mgmt_upcall(&getnext, sizeof (getnext), &retval,
554 sizeof (retval)) != 0) {
555 return (DATALINK_INVALID_LINKID);
558 return (retval.lr_linkid);
561 static int
562 i_dls_mgmt_get_linkattr(const datalink_id_t linkid, const char *attr,
563 void *attrval, size_t *attrszp)
565 dlmgmt_upcall_arg_getattr_t getattr;
566 dlmgmt_getattr_retval_t retval;
567 int err;
569 getattr.ld_cmd = DLMGMT_CMD_DLS_GETATTR;
570 getattr.ld_linkid = linkid;
571 (void) strlcpy(getattr.ld_attr, attr, MAXLINKATTRLEN);
573 if ((err = i_dls_mgmt_upcall(&getattr, sizeof (getattr), &retval,
574 sizeof (retval))) == 0) {
575 if (*attrszp < retval.lr_attrsz)
576 return (EINVAL);
577 *attrszp = retval.lr_attrsz;
578 bcopy(retval.lr_attrval, attrval, retval.lr_attrsz);
581 return (err);
585 * Note that this function can only get devp successfully for non-VLAN link.
588 dls_mgmt_get_phydev(datalink_id_t linkid, dev_t *devp)
590 uint64_t maj, inst;
591 size_t attrsz = sizeof (uint64_t);
593 if (i_dls_mgmt_get_linkattr(linkid, FPHYMAJ, &maj, &attrsz) != 0 ||
594 attrsz != sizeof (uint64_t) ||
595 i_dls_mgmt_get_linkattr(linkid, FPHYINST, &inst, &attrsz) != 0 ||
596 attrsz != sizeof (uint64_t)) {
597 return (EINVAL);
600 *devp = makedevice((major_t)maj, (minor_t)inst);
601 return (0);
605 * Request the datalink management daemon to push in
606 * all properties associated with the link.
607 * Returns a non-zero error code on failure.
610 dls_mgmt_linkprop_init(datalink_id_t linkid)
612 dlmgmt_door_linkprop_init_t li;
613 dlmgmt_linkprop_init_retval_t retval;
614 int err;
616 li.ld_cmd = DLMGMT_CMD_LINKPROP_INIT;
617 li.ld_linkid = linkid;
619 err = i_dls_mgmt_upcall(&li, sizeof (li), &retval, sizeof (retval));
620 return (err);
623 static void
624 dls_devnet_prop_task(void *arg)
626 dls_devnet_t *ddp = arg;
628 (void) dls_mgmt_linkprop_init(ddp->dd_linkid);
630 mutex_enter(&ddp->dd_mutex);
631 ddp->dd_prop_loaded = B_TRUE;
632 ddp->dd_prop_taskid = NULL;
633 cv_broadcast(&ddp->dd_cv);
634 mutex_exit(&ddp->dd_mutex);
638 * Ensure property loading task is completed.
640 void
641 dls_devnet_prop_task_wait(dls_dl_handle_t ddp)
643 mutex_enter(&ddp->dd_mutex);
644 while (ddp->dd_prop_taskid != NULL)
645 cv_wait(&ddp->dd_cv, &ddp->dd_mutex);
646 mutex_exit(&ddp->dd_mutex);
649 void
650 dls_devnet_rele_tmp(dls_dl_handle_t dlh)
652 dls_devnet_t *ddp = dlh;
654 mutex_enter(&ddp->dd_mutex);
655 ASSERT(ddp->dd_tref != 0);
656 if (--ddp->dd_tref == 0)
657 cv_signal(&ddp->dd_cv);
658 mutex_exit(&ddp->dd_mutex);
662 dls_devnet_hold_link(datalink_id_t linkid, dls_dl_handle_t *ddhp,
663 dls_link_t **dlpp)
665 dls_dl_handle_t dlh;
666 dls_link_t *dlp;
667 int err;
669 if ((err = dls_devnet_hold_tmp(linkid, &dlh)) != 0)
670 return (err);
672 if ((err = dls_link_hold(dls_devnet_mac(dlh), &dlp)) != 0) {
673 dls_devnet_rele_tmp(dlh);
674 return (err);
677 ASSERT(MAC_PERIM_HELD(dlp->dl_mh));
679 *ddhp = dlh;
680 *dlpp = dlp;
681 return (0);
684 void
685 dls_devnet_rele_link(dls_dl_handle_t dlh, dls_link_t *dlp)
687 ASSERT(MAC_PERIM_HELD(dlp->dl_mh));
689 dls_link_rele(dlp);
690 dls_devnet_rele_tmp(dlh);
694 * "link" kstats related functions.
698 * Query the "link" kstats.
700 * We may be called from the kstat subsystem in an arbitrary context.
701 * If the caller is the stack, the context could be an upcall data
702 * thread. Hence we can't acquire the mac perimeter in this function
703 * for fear of deadlock.
705 static int
706 dls_devnet_stat_update(kstat_t *ksp, int rw)
708 datalink_id_t linkid = (datalink_id_t)(uintptr_t)ksp->ks_private;
709 dls_devnet_t *ddp;
710 dls_link_t *dlp;
711 int err;
713 if ((err = dls_devnet_hold_tmp(linkid, &ddp)) != 0) {
714 return (err);
718 * If a device detach happens at this time, it will block in
719 * dls_devnet_unset since the dd_tref has been bumped in
720 * dls_devnet_hold_tmp(). So the access to 'dlp' is safe even though
721 * we don't hold the mac perimeter.
723 if (mod_hash_find(i_dls_link_hash, (mod_hash_key_t)ddp->dd_mac,
724 (mod_hash_val_t *)&dlp) != 0) {
725 dls_devnet_rele_tmp(ddp);
726 return (ENOENT);
729 err = dls_stat_update(ksp, dlp, rw);
731 dls_devnet_rele_tmp(ddp);
732 return (err);
736 * Create the "link" kstats.
738 static void
739 dls_devnet_stat_create(dls_devnet_t *ddp, zoneid_t zoneid)
741 kstat_t *ksp;
743 if (dls_stat_create("link", 0, ddp->dd_linkname, zoneid,
744 dls_devnet_stat_update, (void *)(uintptr_t)ddp->dd_linkid,
745 &ksp) == 0) {
746 ASSERT(ksp != NULL);
747 if (zoneid == ddp->dd_owner_zid) {
748 ASSERT(ddp->dd_ksp == NULL);
749 ddp->dd_ksp = ksp;
750 } else {
751 ASSERT(ddp->dd_zone_ksp == NULL);
752 ddp->dd_zone_ksp = ksp;
758 * Destroy the "link" kstats.
760 static void
761 dls_devnet_stat_destroy(dls_devnet_t *ddp, zoneid_t zoneid)
763 if (zoneid == ddp->dd_owner_zid) {
764 if (ddp->dd_ksp != NULL) {
765 kstat_delete(ddp->dd_ksp);
766 ddp->dd_ksp = NULL;
768 } else {
769 if (ddp->dd_zone_ksp != NULL) {
770 kstat_delete(ddp->dd_zone_ksp);
771 ddp->dd_zone_ksp = NULL;
777 * The link has been renamed. Destroy the old non-legacy kstats ("link kstats")
778 * and create the new set using the new name.
780 static void
781 dls_devnet_stat_rename(dls_devnet_t *ddp)
783 if (ddp->dd_ksp != NULL) {
784 kstat_delete(ddp->dd_ksp);
785 ddp->dd_ksp = NULL;
787 /* We can't rename a link while it's assigned to a non-global zone. */
788 ASSERT(ddp->dd_zone_ksp == NULL);
789 dls_devnet_stat_create(ddp, ddp->dd_owner_zid);
793 * Associate a linkid with a given link (identified by macname)
795 static int
796 dls_devnet_set(const char *macname, datalink_id_t linkid, zoneid_t zoneid,
797 dls_devnet_t **ddpp)
799 dls_devnet_t *ddp = NULL;
800 datalink_class_t class;
801 int err;
802 boolean_t stat_create = B_FALSE;
803 char linkname[MAXLINKNAMELEN];
805 rw_enter(&i_dls_devnet_lock, RW_WRITER);
808 * Don't allow callers to set a link name with a linkid that already
809 * has a name association (that's what rename is for).
811 if (linkid != DATALINK_INVALID_LINKID) {
812 if (mod_hash_find(i_dls_devnet_id_hash,
813 (mod_hash_key_t)(uintptr_t)linkid,
814 (mod_hash_val_t *)&ddp) == 0) {
815 err = EEXIST;
816 goto done;
818 if ((err = dls_mgmt_get_linkinfo(linkid, linkname, &class,
819 NULL, NULL)) != 0)
820 goto done;
823 if ((err = mod_hash_find(i_dls_devnet_hash,
824 (mod_hash_key_t)macname, (mod_hash_val_t *)&ddp)) == 0) {
825 if (ddp->dd_linkid != DATALINK_INVALID_LINKID) {
826 err = EEXIST;
827 goto done;
831 * This might be a physical link that has already
832 * been created, but which does not have a linkid
833 * because dlmgmtd was not running when it was created.
835 if (linkid == DATALINK_INVALID_LINKID ||
836 class != DATALINK_CLASS_PHYS) {
837 err = EINVAL;
838 goto done;
840 } else {
841 ddp = kmem_cache_alloc(i_dls_devnet_cachep, KM_SLEEP);
842 ddp->dd_tref = 0;
843 ddp->dd_ref++;
844 ddp->dd_owner_zid = zoneid;
845 (void) strlcpy(ddp->dd_mac, macname, sizeof (ddp->dd_mac));
846 VERIFY(mod_hash_insert(i_dls_devnet_hash,
847 (mod_hash_key_t)ddp->dd_mac, (mod_hash_val_t)ddp) == 0);
850 if (linkid != DATALINK_INVALID_LINKID) {
851 ddp->dd_linkid = linkid;
852 (void) strlcpy(ddp->dd_linkname, linkname,
853 sizeof (ddp->dd_linkname));
854 VERIFY(mod_hash_insert(i_dls_devnet_id_hash,
855 (mod_hash_key_t)(uintptr_t)linkid,
856 (mod_hash_val_t)ddp) == 0);
857 devnet_need_rebuild = B_TRUE;
858 stat_create = B_TRUE;
859 mutex_enter(&ddp->dd_mutex);
860 if (!ddp->dd_prop_loaded && (ddp->dd_prop_taskid == NULL)) {
861 ddp->dd_prop_taskid = taskq_dispatch(system_taskq,
862 dls_devnet_prop_task, ddp, TQ_SLEEP);
864 mutex_exit(&ddp->dd_mutex);
866 err = 0;
867 done:
869 * It is safe to drop the i_dls_devnet_lock at this point. In the case
870 * of physical devices, the softmac framework will fail the device
871 * detach based on the smac_state or smac_hold_cnt. Other cases like
872 * vnic and aggr use their own scheme to serialize creates and deletes
873 * and ensure that *ddp is valid.
875 rw_exit(&i_dls_devnet_lock);
876 if (err == 0) {
877 if (zoneid != GLOBAL_ZONEID &&
878 (err = i_dls_devnet_setzid(ddp, zoneid, B_FALSE)) != 0)
879 (void) dls_devnet_unset(macname, &linkid, B_TRUE);
881 * The kstat subsystem holds its own locks (rather perimeter)
882 * before calling the ks_update (dls_devnet_stat_update) entry
883 * point which in turn grabs the i_dls_devnet_lock. So the
884 * lock hierarchy is kstat locks -> i_dls_devnet_lock.
886 if (stat_create)
887 dls_devnet_stat_create(ddp, zoneid);
888 if (ddpp != NULL)
889 *ddpp = ddp;
891 return (err);
895 * Disassociate a linkid with a given link (identified by macname)
896 * This waits until temporary references to the dls_devnet_t are gone.
898 static int
899 dls_devnet_unset(const char *macname, datalink_id_t *id, boolean_t wait)
901 dls_devnet_t *ddp;
902 int err;
903 mod_hash_val_t val;
905 rw_enter(&i_dls_devnet_lock, RW_WRITER);
906 if ((err = mod_hash_find(i_dls_devnet_hash,
907 (mod_hash_key_t)macname, (mod_hash_val_t *)&ddp)) != 0) {
908 ASSERT(err == MH_ERR_NOTFOUND);
909 rw_exit(&i_dls_devnet_lock);
910 return (ENOENT);
913 mutex_enter(&ddp->dd_mutex);
916 * Make sure downcalls into softmac_create or softmac_destroy from
917 * devfs don't cv_wait on any devfs related condition for fear of
918 * deadlock. Return EBUSY if the asynchronous thread started for
919 * property loading as part of the post attach hasn't yet completed.
921 ASSERT(ddp->dd_ref != 0);
922 if ((ddp->dd_ref != 1) || (!wait &&
923 (ddp->dd_tref != 0 || ddp->dd_prop_taskid != NULL))) {
924 mutex_exit(&ddp->dd_mutex);
925 rw_exit(&i_dls_devnet_lock);
926 return (EBUSY);
929 ddp->dd_flags |= DD_CONDEMNED;
930 ddp->dd_ref--;
931 *id = ddp->dd_linkid;
933 if (ddp->dd_zid != GLOBAL_ZONEID)
934 (void) i_dls_devnet_setzid(ddp, GLOBAL_ZONEID, B_FALSE);
937 * Remove this dls_devnet_t from the hash table.
939 VERIFY(mod_hash_remove(i_dls_devnet_hash,
940 (mod_hash_key_t)ddp->dd_mac, &val) == 0);
942 if (ddp->dd_linkid != DATALINK_INVALID_LINKID) {
943 VERIFY(mod_hash_remove(i_dls_devnet_id_hash,
944 (mod_hash_key_t)(uintptr_t)ddp->dd_linkid, &val) == 0);
946 devnet_need_rebuild = B_TRUE;
948 rw_exit(&i_dls_devnet_lock);
950 if (wait) {
952 * Wait until all temporary references are released.
954 while ((ddp->dd_tref != 0) || (ddp->dd_prop_taskid != NULL))
955 cv_wait(&ddp->dd_cv, &ddp->dd_mutex);
956 } else {
957 ASSERT(ddp->dd_tref == 0 && ddp->dd_prop_taskid == NULL);
960 if (ddp->dd_linkid != DATALINK_INVALID_LINKID)
961 dls_devnet_stat_destroy(ddp, ddp->dd_owner_zid);
963 ddp->dd_prop_loaded = B_FALSE;
964 ddp->dd_linkid = DATALINK_INVALID_LINKID;
965 ddp->dd_flags = 0;
966 mutex_exit(&ddp->dd_mutex);
967 kmem_cache_free(i_dls_devnet_cachep, ddp);
969 return (0);
972 static int
973 dls_devnet_hold_common(datalink_id_t linkid, dls_devnet_t **ddpp,
974 boolean_t tmp_hold)
976 dls_devnet_t *ddp;
977 dev_t phydev = 0;
978 dls_dev_handle_t ddh = NULL;
979 int err;
982 * Hold this link to prevent it being detached in case of a
983 * physical link.
985 if (dls_mgmt_get_phydev(linkid, &phydev) == 0)
986 (void) softmac_hold_device(phydev, &ddh);
988 rw_enter(&i_dls_devnet_lock, RW_READER);
989 if ((err = mod_hash_find(i_dls_devnet_id_hash,
990 (mod_hash_key_t)(uintptr_t)linkid, (mod_hash_val_t *)&ddp)) != 0) {
991 ASSERT(err == MH_ERR_NOTFOUND);
992 rw_exit(&i_dls_devnet_lock);
993 softmac_rele_device(ddh);
994 return (ENOENT);
997 mutex_enter(&ddp->dd_mutex);
998 ASSERT(ddp->dd_ref > 0);
999 if (ddp->dd_flags & DD_CONDEMNED) {
1000 mutex_exit(&ddp->dd_mutex);
1001 rw_exit(&i_dls_devnet_lock);
1002 softmac_rele_device(ddh);
1003 return (ENOENT);
1005 if (tmp_hold)
1006 ddp->dd_tref++;
1007 else
1008 ddp->dd_ref++;
1009 mutex_exit(&ddp->dd_mutex);
1010 rw_exit(&i_dls_devnet_lock);
1012 softmac_rele_device(ddh);
1014 *ddpp = ddp;
1015 return (0);
1019 dls_devnet_hold(datalink_id_t linkid, dls_devnet_t **ddpp)
1021 return (dls_devnet_hold_common(linkid, ddpp, B_FALSE));
1025 * Hold the vanity naming structure (dls_devnet_t) temporarily. The request to
1026 * delete the dls_devnet_t will wait until the temporary reference is released.
1029 dls_devnet_hold_tmp(datalink_id_t linkid, dls_devnet_t **ddpp)
1031 return (dls_devnet_hold_common(linkid, ddpp, B_TRUE));
1035 * This funtion is called when a DLS client tries to open a device node.
1036 * This dev_t could a result of a /dev/net node access (returned by
1037 * devnet_create_rvp->dls_devnet_open()) or a direct /dev node access.
1038 * In both cases, this function bumps up the reference count of the
1039 * dls_devnet_t structure. The reference is held as long as the device node
1040 * is open. In the case of /dev/net while it is true that the initial reference
1041 * is held when the devnet_create_rvp->dls_devnet_open call happens, this
1042 * initial reference is released immediately in devnet_inactive_callback ->
1043 * dls_devnet_close(). (Note that devnet_inactive_callback() is called right
1044 * after dld_open completes, not when the /dev/net node is being closed).
1045 * To undo this function, call dls_devnet_rele()
1048 dls_devnet_hold_by_dev(dev_t dev, dls_dl_handle_t *ddhp)
1050 char name[MAXNAMELEN];
1051 char *drv;
1052 dls_dev_handle_t ddh = NULL;
1053 dls_devnet_t *ddp;
1054 int err;
1056 if ((drv = ddi_major_to_name(getmajor(dev))) == NULL)
1057 return (EINVAL);
1059 (void) snprintf(name, sizeof (name), "%s%d", drv,
1060 DLS_MINOR2INST(getminor(dev)));
1063 * Hold this link to prevent it being detached in case of a
1064 * GLDv3 physical link.
1066 if (DLS_MINOR2INST(getminor(dev)) <= DLS_MAX_PPA)
1067 (void) softmac_hold_device(dev, &ddh);
1069 rw_enter(&i_dls_devnet_lock, RW_READER);
1070 if ((err = mod_hash_find(i_dls_devnet_hash,
1071 (mod_hash_key_t)name, (mod_hash_val_t *)&ddp)) != 0) {
1072 ASSERT(err == MH_ERR_NOTFOUND);
1073 rw_exit(&i_dls_devnet_lock);
1074 softmac_rele_device(ddh);
1075 return (ENOENT);
1077 mutex_enter(&ddp->dd_mutex);
1078 ASSERT(ddp->dd_ref > 0);
1079 if (ddp->dd_flags & DD_CONDEMNED) {
1080 mutex_exit(&ddp->dd_mutex);
1081 rw_exit(&i_dls_devnet_lock);
1082 softmac_rele_device(ddh);
1083 return (ENOENT);
1085 ddp->dd_ref++;
1086 mutex_exit(&ddp->dd_mutex);
1087 rw_exit(&i_dls_devnet_lock);
1089 softmac_rele_device(ddh);
1091 *ddhp = ddp;
1092 return (0);
1095 void
1096 dls_devnet_rele(dls_devnet_t *ddp)
1098 mutex_enter(&ddp->dd_mutex);
1099 ASSERT(ddp->dd_ref > 1);
1100 ddp->dd_ref--;
1101 if ((ddp->dd_flags & DD_IMPLICIT_IPTUN) && ddp->dd_ref == 1) {
1102 mutex_exit(&ddp->dd_mutex);
1103 if (i_dls_devnet_destroy_iptun(ddp->dd_linkid) != 0)
1104 ddp->dd_flags |= DD_IMPLICIT_IPTUN;
1105 return;
1107 mutex_exit(&ddp->dd_mutex);
1110 static int
1111 dls_devnet_hold_by_name(const char *link, dls_devnet_t **ddpp)
1113 char drv[MAXLINKNAMELEN];
1114 uint_t ppa;
1115 major_t major;
1116 dev_t phy_dev, tmp_dev;
1117 datalink_id_t linkid;
1118 dls_dev_handle_t ddh;
1119 int err;
1121 if ((err = dls_mgmt_get_linkid(link, &linkid)) == 0)
1122 return (dls_devnet_hold(linkid, ddpp));
1125 * If we failed to get the link's linkid because the dlmgmtd daemon
1126 * has not been started, return ENOENT so that the application can
1127 * fallback to open the /dev node.
1129 if (err == EBADF)
1130 return (ENOENT);
1132 if (err != ENOENT)
1133 return (err);
1135 if (ddi_parse(link, drv, &ppa) != DDI_SUCCESS)
1136 return (ENOENT);
1138 if (IS_IPTUN_LINK(drv)) {
1139 if ((err = i_dls_devnet_create_iptun(link, drv, &linkid)) != 0)
1140 return (err);
1142 * At this point, an IP tunnel MAC has registered, which
1143 * resulted in a link being created.
1145 err = dls_devnet_hold(linkid, ddpp);
1146 ASSERT(err == 0);
1147 if (err != 0) {
1148 VERIFY(i_dls_devnet_destroy_iptun(linkid) == 0);
1149 return (err);
1152 * dls_devnet_rele() will know to destroy the implicit IP
1153 * tunnel on last reference release if DD_IMPLICIT_IPTUN is
1154 * set.
1156 (*ddpp)->dd_flags |= DD_IMPLICIT_IPTUN;
1157 return (0);
1161 * If this link:
1162 * (a) is a physical device, (b) this is the first boot, (c) the MAC
1163 * is not registered yet, and (d) we cannot find its linkid, then the
1164 * linkname is the same as the devname.
1166 * First filter out invalid names.
1168 if ((major = ddi_name_to_major(drv)) == (major_t)-1)
1169 return (ENOENT);
1171 phy_dev = makedevice(major, DLS_PPA2MINOR(ppa));
1172 if (softmac_hold_device(phy_dev, &ddh) != 0)
1173 return (ENOENT);
1176 * At this time, the MAC should be registered, check its phy_dev using
1177 * the given name.
1179 if ((err = dls_mgmt_get_linkid(link, &linkid)) != 0 ||
1180 (err = dls_mgmt_get_phydev(linkid, &tmp_dev)) != 0) {
1181 softmac_rele_device(ddh);
1182 return (err);
1184 if (tmp_dev != phy_dev) {
1185 softmac_rele_device(ddh);
1186 return (ENOENT);
1189 err = dls_devnet_hold(linkid, ddpp);
1190 softmac_rele_device(ddh);
1191 return (err);
1195 dls_devnet_macname2linkid(const char *macname, datalink_id_t *linkidp)
1197 dls_devnet_t *ddp;
1199 rw_enter(&i_dls_devnet_lock, RW_READER);
1200 if (mod_hash_find(i_dls_devnet_hash, (mod_hash_key_t)macname,
1201 (mod_hash_val_t *)&ddp) != 0) {
1202 rw_exit(&i_dls_devnet_lock);
1203 return (ENOENT);
1206 *linkidp = ddp->dd_linkid;
1207 rw_exit(&i_dls_devnet_lock);
1208 return (0);
1212 * Get linkid for the given dev.
1215 dls_devnet_dev2linkid(dev_t dev, datalink_id_t *linkidp)
1217 char macname[MAXNAMELEN];
1218 char *drv;
1220 if ((drv = ddi_major_to_name(getmajor(dev))) == NULL)
1221 return (EINVAL);
1223 (void) snprintf(macname, sizeof (macname), "%s%d", drv,
1224 DLS_MINOR2INST(getminor(dev)));
1225 return (dls_devnet_macname2linkid(macname, linkidp));
1229 * Get the link's physical dev_t. It this is a VLAN, get the dev_t of the
1230 * link this VLAN is created on.
1233 dls_devnet_phydev(datalink_id_t vlanid, dev_t *devp)
1235 dls_devnet_t *ddp;
1236 int err;
1238 if ((err = dls_devnet_hold_tmp(vlanid, &ddp)) != 0)
1239 return (err);
1241 err = dls_mgmt_get_phydev(ddp->dd_linkid, devp);
1242 dls_devnet_rele_tmp(ddp);
1243 return (err);
1247 * Handle the renaming requests. There are two rename cases:
1249 * 1. Request to rename a valid link (id1) to an non-existent link name
1250 * (id2). In this case id2 is DATALINK_INVALID_LINKID. Just check whether
1251 * id1 is held by any applications.
1253 * In this case, the link's kstats need to be updated using the given name.
1255 * 2. Request to rename a valid link (id1) to the name of a REMOVED
1256 * physical link (id2). In this case, check that id1 and its associated
1257 * mac is not held by any application, and update the link's linkid to id2.
1259 * This case does not change the <link name, linkid> mapping, so the link's
1260 * kstats need to be updated with using name associated the given id2.
1263 dls_devnet_rename(datalink_id_t id1, datalink_id_t id2, const char *link)
1265 dls_dev_handle_t ddh = NULL;
1266 int err = 0;
1267 dev_t phydev = 0;
1268 dls_devnet_t *ddp;
1269 mac_perim_handle_t mph = NULL;
1270 mac_handle_t mh;
1271 mod_hash_val_t val;
1274 * In the second case, id2 must be a REMOVED physical link.
1276 if ((id2 != DATALINK_INVALID_LINKID) &&
1277 (dls_mgmt_get_phydev(id2, &phydev) == 0) &&
1278 softmac_hold_device(phydev, &ddh) == 0) {
1279 softmac_rele_device(ddh);
1280 return (EEXIST);
1284 * Hold id1 to prevent it from being detached (if a physical link).
1286 if (dls_mgmt_get_phydev(id1, &phydev) == 0)
1287 (void) softmac_hold_device(phydev, &ddh);
1290 * The framework does not hold hold locks across calls to the
1291 * mac perimeter, hence enter the perimeter first. This also waits
1292 * for the property loading to finish.
1294 if ((err = mac_perim_enter_by_linkid(id1, &mph)) != 0) {
1295 softmac_rele_device(ddh);
1296 return (err);
1299 rw_enter(&i_dls_devnet_lock, RW_WRITER);
1300 if ((err = mod_hash_find(i_dls_devnet_id_hash,
1301 (mod_hash_key_t)(uintptr_t)id1, (mod_hash_val_t *)&ddp)) != 0) {
1302 ASSERT(err == MH_ERR_NOTFOUND);
1303 err = ENOENT;
1304 goto done;
1307 mutex_enter(&ddp->dd_mutex);
1308 if (ddp->dd_ref > 1) {
1309 mutex_exit(&ddp->dd_mutex);
1310 err = EBUSY;
1311 goto done;
1313 mutex_exit(&ddp->dd_mutex);
1315 if (id2 == DATALINK_INVALID_LINKID) {
1316 (void) strlcpy(ddp->dd_linkname, link,
1317 sizeof (ddp->dd_linkname));
1319 /* rename mac client name and its flow if exists */
1320 if ((err = mac_open(ddp->dd_mac, &mh)) != 0)
1321 goto done;
1322 (void) mac_rename_primary(mh, link);
1323 mac_close(mh);
1324 goto done;
1328 * The second case, check whether the MAC is used by any MAC
1329 * user. This must be a physical link so ddh must not be NULL.
1331 if (ddh == NULL) {
1332 err = EINVAL;
1333 goto done;
1336 if ((err = mac_open(ddp->dd_mac, &mh)) != 0)
1337 goto done;
1340 * We release the reference of the MAC which mac_open() is
1341 * holding. Note that this mac will not be unregistered
1342 * because the physical device is held.
1344 mac_close(mh);
1347 * Check if there is any other MAC clients, if not, hold this mac
1348 * exclusively until we are done.
1350 if ((err = mac_mark_exclusive(mh)) != 0)
1351 goto done;
1354 * Update the link's linkid.
1356 if ((err = mod_hash_find(i_dls_devnet_id_hash,
1357 (mod_hash_key_t)(uintptr_t)id2, &val)) != MH_ERR_NOTFOUND) {
1358 mac_unmark_exclusive(mh);
1359 err = EEXIST;
1360 goto done;
1363 err = dls_mgmt_get_linkinfo(id2, ddp->dd_linkname, NULL, NULL, NULL);
1364 if (err != 0) {
1365 mac_unmark_exclusive(mh);
1366 goto done;
1369 (void) mod_hash_remove(i_dls_devnet_id_hash,
1370 (mod_hash_key_t)(uintptr_t)id1, &val);
1372 ddp->dd_linkid = id2;
1373 (void) mod_hash_insert(i_dls_devnet_id_hash,
1374 (mod_hash_key_t)(uintptr_t)ddp->dd_linkid, (mod_hash_val_t)ddp);
1376 mac_unmark_exclusive(mh);
1378 /* load properties for new id */
1379 mutex_enter(&ddp->dd_mutex);
1380 ddp->dd_prop_loaded = B_FALSE;
1381 ddp->dd_prop_taskid = taskq_dispatch(system_taskq,
1382 dls_devnet_prop_task, ddp, TQ_SLEEP);
1383 mutex_exit(&ddp->dd_mutex);
1385 done:
1386 rw_exit(&i_dls_devnet_lock);
1388 if (err == 0)
1389 dls_devnet_stat_rename(ddp);
1391 if (mph != NULL)
1392 mac_perim_exit(mph);
1393 softmac_rele_device(ddh);
1394 return (err);
1397 static int
1398 i_dls_devnet_setzid(dls_devnet_t *ddp, zoneid_t new_zoneid, boolean_t setprop)
1400 int err;
1401 mac_perim_handle_t mph;
1402 boolean_t upcall_done = B_FALSE;
1403 datalink_id_t linkid = ddp->dd_linkid;
1404 zoneid_t old_zoneid = ddp->dd_zid;
1405 dlmgmt_door_setzoneid_t setzid;
1406 dlmgmt_setzoneid_retval_t retval;
1408 if (old_zoneid == new_zoneid)
1409 return (0);
1411 if ((err = mac_perim_enter_by_macname(ddp->dd_mac, &mph)) != 0)
1412 return (err);
1415 * When changing the zoneid of an existing link, we need to tell
1416 * dlmgmtd about it. dlmgmtd already knows the zoneid associated with
1417 * newly created links.
1419 if (setprop) {
1420 setzid.ld_cmd = DLMGMT_CMD_SETZONEID;
1421 setzid.ld_linkid = linkid;
1422 setzid.ld_zoneid = new_zoneid;
1423 err = i_dls_mgmt_upcall(&setzid, sizeof (setzid), &retval,
1424 sizeof (retval));
1425 if (err != 0)
1426 goto done;
1427 upcall_done = B_TRUE;
1429 if ((err = dls_link_setzid(ddp->dd_mac, new_zoneid)) == 0) {
1430 ddp->dd_zid = new_zoneid;
1431 devnet_need_rebuild = B_TRUE;
1434 done:
1435 if (err != 0 && upcall_done) {
1436 setzid.ld_zoneid = old_zoneid;
1437 (void) i_dls_mgmt_upcall(&setzid, sizeof (setzid), &retval,
1438 sizeof (retval));
1440 mac_perim_exit(mph);
1441 return (err);
1445 dls_devnet_setzid(dls_dl_handle_t ddh, zoneid_t new_zid)
1447 dls_devnet_t *ddp;
1448 int err;
1449 zoneid_t old_zid;
1450 boolean_t refheld = B_FALSE;
1452 old_zid = ddh->dd_zid;
1454 if (old_zid == new_zid)
1455 return (0);
1458 * Acquire an additional reference to the link if it is being assigned
1459 * to a non-global zone from the global zone.
1461 if (old_zid == GLOBAL_ZONEID && new_zid != GLOBAL_ZONEID) {
1462 if ((err = dls_devnet_hold(ddh->dd_linkid, &ddp)) != 0)
1463 return (err);
1464 refheld = B_TRUE;
1467 if ((err = i_dls_devnet_setzid(ddh, new_zid, B_TRUE)) != 0) {
1468 if (refheld)
1469 dls_devnet_rele(ddp);
1470 return (err);
1474 * Release the additional reference if the link is returning to the
1475 * global zone from a non-global zone.
1477 if (old_zid != GLOBAL_ZONEID && new_zid == GLOBAL_ZONEID)
1478 dls_devnet_rele(ddh);
1480 /* Re-create kstats in the appropriate zones. */
1481 if (old_zid != GLOBAL_ZONEID)
1482 dls_devnet_stat_destroy(ddh, old_zid);
1483 if (new_zid != GLOBAL_ZONEID)
1484 dls_devnet_stat_create(ddh, new_zid);
1486 return (0);
1489 zoneid_t
1490 dls_devnet_getzid(dls_dl_handle_t ddh)
1492 return (((dls_devnet_t *)ddh)->dd_zid);
1495 zoneid_t
1496 dls_devnet_getownerzid(dls_dl_handle_t ddh)
1498 return (((dls_devnet_t *)ddh)->dd_owner_zid);
1502 * Is linkid visible from zoneid? A link is visible if it was created in the
1503 * zone, or if it is currently assigned to the zone.
1505 boolean_t
1506 dls_devnet_islinkvisible(datalink_id_t linkid, zoneid_t zoneid)
1508 dls_devnet_t *ddp;
1509 boolean_t result;
1511 if (dls_devnet_hold_tmp(linkid, &ddp) != 0)
1512 return (B_FALSE);
1513 result = (ddp->dd_owner_zid == zoneid || ddp->dd_zid == zoneid);
1514 dls_devnet_rele_tmp(ddp);
1515 return (result);
1519 * Access a vanity naming node.
1522 dls_devnet_open(const char *link, dls_dl_handle_t *dhp, dev_t *devp)
1524 dls_devnet_t *ddp;
1525 dls_link_t *dlp;
1526 zoneid_t zid = getzoneid();
1527 int err;
1528 mac_perim_handle_t mph;
1530 if ((err = dls_devnet_hold_by_name(link, &ddp)) != 0)
1531 return (err);
1533 dls_devnet_prop_task_wait(ddp);
1536 * Opening a link that does not belong to the current non-global zone
1537 * is not allowed.
1539 if (zid != GLOBAL_ZONEID && ddp->dd_zid != zid) {
1540 dls_devnet_rele(ddp);
1541 return (ENOENT);
1544 err = mac_perim_enter_by_macname(ddp->dd_mac, &mph);
1545 if (err != 0) {
1546 dls_devnet_rele(ddp);
1547 return (err);
1550 err = dls_link_hold_create(ddp->dd_mac, &dlp);
1551 mac_perim_exit(mph);
1553 if (err != 0) {
1554 dls_devnet_rele(ddp);
1555 return (err);
1558 *dhp = ddp;
1559 *devp = dls_link_dev(dlp);
1560 return (0);
1564 * Close access to a vanity naming node.
1566 void
1567 dls_devnet_close(dls_dl_handle_t dlh)
1569 dls_devnet_t *ddp = dlh;
1570 dls_link_t *dlp;
1571 mac_perim_handle_t mph;
1573 VERIFY(mac_perim_enter_by_macname(ddp->dd_mac, &mph) == 0);
1574 VERIFY(dls_link_hold(ddp->dd_mac, &dlp) == 0);
1577 * One rele for the hold placed in dls_devnet_open, another for
1578 * the hold done just above
1580 dls_link_rele(dlp);
1581 dls_link_rele(dlp);
1582 mac_perim_exit(mph);
1584 dls_devnet_rele(ddp);
1588 * This is used by /dev/net to rebuild the nodes for readdir(). It is not
1589 * critical and no protection is needed.
1591 boolean_t
1592 dls_devnet_rebuild()
1594 boolean_t updated = devnet_need_rebuild;
1596 devnet_need_rebuild = B_FALSE;
1597 return (updated);
1601 dls_devnet_create(mac_handle_t mh, datalink_id_t linkid, zoneid_t zoneid)
1603 dls_link_t *dlp;
1604 dls_devnet_t *ddp;
1605 int err;
1606 mac_perim_handle_t mph;
1609 * Holding the mac perimeter ensures that the downcall from the
1610 * dlmgmt daemon which does the property loading does not proceed
1611 * until we relinquish the perimeter.
1613 mac_perim_enter_by_mh(mh, &mph);
1615 * Make this association before we call dls_link_hold_create as
1616 * we need to use the linkid to get the user name for the link
1617 * when we create the MAC client.
1619 if ((err = dls_devnet_set(mac_name(mh), linkid, zoneid, &ddp)) == 0) {
1620 if ((err = dls_link_hold_create(mac_name(mh), &dlp)) != 0) {
1621 mac_perim_exit(mph);
1622 (void) dls_devnet_unset(mac_name(mh), &linkid, B_TRUE);
1623 return (err);
1626 mac_perim_exit(mph);
1627 return (err);
1631 * Set the linkid of the dls_devnet_t and add it into the i_dls_devnet_id_hash.
1632 * This is called in the case that the dlmgmtd daemon is started later than
1633 * the physical devices get attached, and the linkid is only known after the
1634 * daemon starts.
1637 dls_devnet_recreate(mac_handle_t mh, datalink_id_t linkid)
1639 ASSERT(linkid != DATALINK_INVALID_LINKID);
1640 return (dls_devnet_set(mac_name(mh), linkid, GLOBAL_ZONEID, NULL));
1644 dls_devnet_destroy(mac_handle_t mh, datalink_id_t *idp, boolean_t wait)
1646 int err;
1647 mac_perim_handle_t mph;
1649 *idp = DATALINK_INVALID_LINKID;
1650 err = dls_devnet_unset(mac_name(mh), idp, wait);
1651 if (err != 0 && err != ENOENT)
1652 return (err);
1654 mac_perim_enter_by_mh(mh, &mph);
1655 err = dls_link_rele_by_name(mac_name(mh));
1656 mac_perim_exit(mph);
1658 if (err != 0) {
1660 * XXX It is a general GLDv3 bug that dls_devnet_set() has to
1661 * be called to re-set the link when destroy fails. The
1662 * zoneid below will be incorrect if this function is ever
1663 * called from kernel context or from a zone other than that
1664 * which initially created the link.
1666 (void) dls_devnet_set(mac_name(mh), *idp, crgetzoneid(CRED()),
1667 NULL);
1669 return (err);
1673 * Implicitly create an IP tunnel link.
1675 static int
1676 i_dls_devnet_create_iptun(const char *linkname, const char *drvname,
1677 datalink_id_t *linkid)
1679 int err;
1680 iptun_kparams_t ik;
1681 uint32_t media;
1682 netstack_t *ns;
1683 major_t iptun_major;
1684 dev_info_t *iptun_dip;
1686 /* First ensure that the iptun device is attached. */
1687 if ((iptun_major = ddi_name_to_major(IPTUN_DRIVER_NAME)) == (major_t)-1)
1688 return (EINVAL);
1689 if ((iptun_dip = ddi_hold_devi_by_instance(iptun_major, 0, 0)) == NULL)
1690 return (EINVAL);
1692 if (IS_IPV4_TUN(drvname)) {
1693 ik.iptun_kparam_type = IPTUN_TYPE_IPV4;
1694 media = DL_IPV4;
1695 } else if (IS_6TO4_TUN(drvname)) {
1696 ik.iptun_kparam_type = IPTUN_TYPE_6TO4;
1697 media = DL_6TO4;
1698 } else if (IS_IPV6_TUN(drvname)) {
1699 ik.iptun_kparam_type = IPTUN_TYPE_IPV6;
1700 media = DL_IPV6;
1702 ik.iptun_kparam_flags = (IPTUN_KPARAM_TYPE | IPTUN_KPARAM_IMPLICIT);
1704 /* Obtain a datalink id for this tunnel. */
1705 err = dls_mgmt_create((char *)linkname, 0, DATALINK_CLASS_IPTUN, media,
1706 B_FALSE, &ik.iptun_kparam_linkid);
1707 if (err != 0) {
1708 ddi_release_devi(iptun_dip);
1709 return (err);
1712 ns = netstack_get_current();
1713 err = iptun_create(&ik, CRED());
1714 netstack_rele(ns);
1716 if (err != 0)
1717 VERIFY(dls_mgmt_destroy(ik.iptun_kparam_linkid, B_FALSE) == 0);
1718 else
1719 *linkid = ik.iptun_kparam_linkid;
1721 ddi_release_devi(iptun_dip);
1722 return (err);
1725 static int
1726 i_dls_devnet_destroy_iptun(datalink_id_t linkid)
1728 int err;
1731 * Note the use of zone_kcred() here as opposed to CRED(). This is
1732 * because the process that does the last close of this /dev/net node
1733 * may not have necessary privileges to delete this IP tunnel, but the
1734 * tunnel must always be implicitly deleted on last close.
1736 if ((err = iptun_delete(linkid, zone_kcred())) == 0)
1737 (void) dls_mgmt_destroy(linkid, B_FALSE);
1738 return (err);
1741 const char *
1742 dls_devnet_mac(dls_dl_handle_t ddh)
1744 return (ddh->dd_mac);
1747 datalink_id_t
1748 dls_devnet_linkid(dls_dl_handle_t ddh)
1750 return (ddh->dd_linkid);