1d62bc4baSyz147064 /*
2d62bc4baSyz147064 * CDDL HEADER START
3d62bc4baSyz147064 *
4d62bc4baSyz147064 * The contents of this file are subject to the terms of the
5d62bc4baSyz147064 * Common Development and Distribution License (the "License").
6d62bc4baSyz147064 * You may not use this file except in compliance with the License.
7d62bc4baSyz147064 *
8d62bc4baSyz147064 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d62bc4baSyz147064 * or http://www.opensolaris.org/os/licensing.
10d62bc4baSyz147064 * See the License for the specific language governing permissions
11d62bc4baSyz147064 * and limitations under the License.
12d62bc4baSyz147064 *
13d62bc4baSyz147064 * When distributing Covered Code, include this CDDL HEADER in each
14d62bc4baSyz147064 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d62bc4baSyz147064 * If applicable, add the following below this CDDL HEADER, with the
16d62bc4baSyz147064 * fields enclosed by brackets "[]" replaced with your own identifying
17d62bc4baSyz147064 * information: Portions Copyright [yyyy] [name of copyright owner]
18d62bc4baSyz147064 *
19d62bc4baSyz147064 * CDDL HEADER END
20d62bc4baSyz147064 */
21d62bc4baSyz147064 /*
22ae6aa22aSVenugopal Iyer * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23d62bc4baSyz147064 * Use is subject to license terms.
24d62bc4baSyz147064 */
25d62bc4baSyz147064
26d62bc4baSyz147064 /*
27d62bc4baSyz147064 * Datalink management routines.
28d62bc4baSyz147064 */
29d62bc4baSyz147064
30d62bc4baSyz147064 #include <sys/types.h>
31d62bc4baSyz147064 #include <sys/door.h>
32d62bc4baSyz147064 #include <sys/zone.h>
33d62bc4baSyz147064 #include <sys/modctl.h>
34d62bc4baSyz147064 #include <sys/file.h>
35d62bc4baSyz147064 #include <sys/modhash.h>
36d62bc4baSyz147064 #include <sys/kstat.h>
37d62bc4baSyz147064 #include <sys/vnode.h>
38d62bc4baSyz147064 #include <sys/cmn_err.h>
39d62bc4baSyz147064 #include <sys/softmac.h>
40d62bc4baSyz147064 #include <sys/dls.h>
41d62bc4baSyz147064 #include <sys/dls_impl.h>
422b24ab6bSSebastien Roy #include <sys/stropts.h>
432b24ab6bSSebastien Roy #include <sys/netstack.h>
442b24ab6bSSebastien Roy #include <inet/iptun/iptun_impl.h>
45d62bc4baSyz147064
46da14cebeSEric Cheng /*
47da14cebeSEric Cheng * This vanity name management module is treated as part of the GLD framework
48da14cebeSEric Cheng * and we don't hold any GLD framework lock across a call to any mac
49da14cebeSEric Cheng * function that needs to acquire the mac perimeter. The hierarchy is
50da14cebeSEric Cheng * mac perimeter -> framework locks
51da14cebeSEric Cheng */
52da14cebeSEric Cheng
532b24ab6bSSebastien Roy typedef struct dls_stack {
542b24ab6bSSebastien Roy zoneid_t dlss_zoneid;
552b24ab6bSSebastien Roy } dls_stack_t;
562b24ab6bSSebastien Roy
57d62bc4baSyz147064 static kmem_cache_t *i_dls_devnet_cachep;
58d62bc4baSyz147064 static kmutex_t i_dls_mgmt_lock;
59d62bc4baSyz147064 static krwlock_t i_dls_devnet_lock;
60d62bc4baSyz147064 static mod_hash_t *i_dls_devnet_id_hash;
61d62bc4baSyz147064 static mod_hash_t *i_dls_devnet_hash;
62d62bc4baSyz147064
63d62bc4baSyz147064 boolean_t devnet_need_rebuild;
64d62bc4baSyz147064
65d62bc4baSyz147064 #define VLAN_HASHSZ 67 /* prime */
66d62bc4baSyz147064
672b24ab6bSSebastien Roy /*
68d501bbfeSSebastien Roy * The following macros take a link name without the trailing PPA as input.
69d501bbfeSSebastien Roy * Opening a /dev/net node with one of these names causes a tunnel link to be
70d501bbfeSSebastien Roy * implicitly created in dls_devnet_hold_by_name() for backward compatibility
71d501bbfeSSebastien Roy * with Solaris 10 and prior.
722b24ab6bSSebastien Roy */
73d501bbfeSSebastien Roy #define IS_IPV4_TUN(name) (strcmp((name), "ip.tun") == 0)
74d501bbfeSSebastien Roy #define IS_IPV6_TUN(name) (strcmp((name), "ip6.tun") == 0)
75d501bbfeSSebastien Roy #define IS_6TO4_TUN(name) (strcmp((name), "ip.6to4tun") == 0)
762b24ab6bSSebastien Roy #define IS_IPTUN_LINK(name) ( \
772b24ab6bSSebastien Roy IS_IPV4_TUN(name) || IS_IPV6_TUN(name) || IS_6TO4_TUN(name))
782b24ab6bSSebastien Roy
79d62bc4baSyz147064 /* Upcall door handle */
80d62bc4baSyz147064 static door_handle_t dls_mgmt_dh = NULL;
81d62bc4baSyz147064
82da14cebeSEric Cheng #define DD_CONDEMNED 0x1
83ae6aa22aSVenugopal Iyer #define DD_KSTAT_CHANGING 0x2
842b24ab6bSSebastien Roy #define DD_IMPLICIT_IPTUN 0x4 /* Implicitly-created ip*.*tun* tunnel */
85da14cebeSEric Cheng
86d62bc4baSyz147064 /*
87da14cebeSEric Cheng * This structure is used to keep the <linkid, macname> mapping.
88ae6aa22aSVenugopal Iyer * This structure itself is not protected by the mac perimeter, but is
89ae6aa22aSVenugopal Iyer * protected by the dd_mutex and i_dls_devnet_lock. Thus most of the
90ae6aa22aSVenugopal Iyer * functions manipulating this structure such as dls_devnet_set/unset etc.
91ae6aa22aSVenugopal Iyer * may be called while not holding the mac perimeter.
92d62bc4baSyz147064 */
93d62bc4baSyz147064 typedef struct dls_devnet_s {
94d62bc4baSyz147064 datalink_id_t dd_linkid;
952b24ab6bSSebastien Roy char dd_linkname[MAXLINKNAMELEN];
96d62bc4baSyz147064 char dd_mac[MAXNAMELEN];
972b24ab6bSSebastien Roy kstat_t *dd_ksp; /* kstat in owner_zid */
982b24ab6bSSebastien Roy kstat_t *dd_zone_ksp; /* in dd_zid if != owner_zid */
99d62bc4baSyz147064 uint32_t dd_ref;
100d62bc4baSyz147064 kmutex_t dd_mutex;
101d62bc4baSyz147064 kcondvar_t dd_cv;
102d62bc4baSyz147064 uint32_t dd_tref;
103da14cebeSEric Cheng uint_t dd_flags;
1042b24ab6bSSebastien Roy zoneid_t dd_owner_zid; /* zone where node was created */
1052b24ab6bSSebastien Roy zoneid_t dd_zid; /* current zone */
10630890389Sartem boolean_t dd_prop_loaded;
10730890389Sartem taskqid_t dd_prop_taskid;
108d62bc4baSyz147064 } dls_devnet_t;
109d62bc4baSyz147064
110d501bbfeSSebastien Roy static int i_dls_devnet_create_iptun(const char *, const char *,
111d501bbfeSSebastien Roy datalink_id_t *);
1122b24ab6bSSebastien Roy static int i_dls_devnet_destroy_iptun(datalink_id_t);
1132b24ab6bSSebastien Roy static int i_dls_devnet_setzid(dls_devnet_t *, zoneid_t, boolean_t);
1142b24ab6bSSebastien Roy static int dls_devnet_unset(const char *, datalink_id_t *, boolean_t);
11530890389Sartem
116d62bc4baSyz147064 /*ARGSUSED*/
117d62bc4baSyz147064 static int
i_dls_devnet_constructor(void * buf,void * arg,int kmflag)118d62bc4baSyz147064 i_dls_devnet_constructor(void *buf, void *arg, int kmflag)
119d62bc4baSyz147064 {
120d62bc4baSyz147064 dls_devnet_t *ddp = buf;
121d62bc4baSyz147064
122d62bc4baSyz147064 bzero(buf, sizeof (dls_devnet_t));
123d62bc4baSyz147064 mutex_init(&ddp->dd_mutex, NULL, MUTEX_DEFAULT, NULL);
124d62bc4baSyz147064 cv_init(&ddp->dd_cv, NULL, CV_DEFAULT, NULL);
125d62bc4baSyz147064 return (0);
126d62bc4baSyz147064 }
127d62bc4baSyz147064
128d62bc4baSyz147064 /*ARGSUSED*/
129d62bc4baSyz147064 static void
i_dls_devnet_destructor(void * buf,void * arg)130d62bc4baSyz147064 i_dls_devnet_destructor(void *buf, void *arg)
131d62bc4baSyz147064 {
132d62bc4baSyz147064 dls_devnet_t *ddp = buf;
133d62bc4baSyz147064
134d62bc4baSyz147064 ASSERT(ddp->dd_ksp == NULL);
135d62bc4baSyz147064 ASSERT(ddp->dd_ref == 0);
136d62bc4baSyz147064 ASSERT(ddp->dd_tref == 0);
137d62bc4baSyz147064 mutex_destroy(&ddp->dd_mutex);
138d62bc4baSyz147064 cv_destroy(&ddp->dd_cv);
139d62bc4baSyz147064 }
140d62bc4baSyz147064
1412b24ab6bSSebastien Roy /* ARGSUSED */
1422b24ab6bSSebastien Roy static int
dls_zone_remove(datalink_id_t linkid,void * arg)1432b24ab6bSSebastien Roy dls_zone_remove(datalink_id_t linkid, void *arg)
1442b24ab6bSSebastien Roy {
1452b24ab6bSSebastien Roy dls_devnet_t *ddp;
1462b24ab6bSSebastien Roy
1472b24ab6bSSebastien Roy if (dls_devnet_hold_tmp(linkid, &ddp) == 0) {
1482b24ab6bSSebastien Roy (void) dls_devnet_setzid(ddp, GLOBAL_ZONEID);
1492b24ab6bSSebastien Roy dls_devnet_rele_tmp(ddp);
1502b24ab6bSSebastien Roy }
1512b24ab6bSSebastien Roy return (0);
1522b24ab6bSSebastien Roy }
1532b24ab6bSSebastien Roy
1542b24ab6bSSebastien Roy /* ARGSUSED */
1552b24ab6bSSebastien Roy static void *
dls_stack_init(netstackid_t stackid,netstack_t * ns)1562b24ab6bSSebastien Roy dls_stack_init(netstackid_t stackid, netstack_t *ns)
1572b24ab6bSSebastien Roy {
1582b24ab6bSSebastien Roy dls_stack_t *dlss;
1592b24ab6bSSebastien Roy
1602b24ab6bSSebastien Roy dlss = kmem_zalloc(sizeof (*dlss), KM_SLEEP);
1612b24ab6bSSebastien Roy dlss->dlss_zoneid = netstackid_to_zoneid(stackid);
1622b24ab6bSSebastien Roy return (dlss);
1632b24ab6bSSebastien Roy }
1642b24ab6bSSebastien Roy
1652b24ab6bSSebastien Roy /* ARGSUSED */
1662b24ab6bSSebastien Roy static void
dls_stack_shutdown(netstackid_t stackid,void * arg)1672b24ab6bSSebastien Roy dls_stack_shutdown(netstackid_t stackid, void *arg)
1682b24ab6bSSebastien Roy {
1692b24ab6bSSebastien Roy dls_stack_t *dlss = (dls_stack_t *)arg;
1702b24ab6bSSebastien Roy
1712b24ab6bSSebastien Roy /* Move remaining datalinks in this zone back to the global zone. */
1722b24ab6bSSebastien Roy (void) zone_datalink_walk(dlss->dlss_zoneid, dls_zone_remove, NULL);
1732b24ab6bSSebastien Roy }
1742b24ab6bSSebastien Roy
1752b24ab6bSSebastien Roy /* ARGSUSED */
1762b24ab6bSSebastien Roy static void
dls_stack_fini(netstackid_t stackid,void * arg)1772b24ab6bSSebastien Roy dls_stack_fini(netstackid_t stackid, void *arg)
1782b24ab6bSSebastien Roy {
1792b24ab6bSSebastien Roy dls_stack_t *dlss = (dls_stack_t *)arg;
1802b24ab6bSSebastien Roy
1812b24ab6bSSebastien Roy kmem_free(dlss, sizeof (*dlss));
1822b24ab6bSSebastien Roy }
1832b24ab6bSSebastien Roy
184d62bc4baSyz147064 /*
185d62bc4baSyz147064 * Module initialization and finalization functions.
186d62bc4baSyz147064 */
187d62bc4baSyz147064 void
dls_mgmt_init(void)188d62bc4baSyz147064 dls_mgmt_init(void)
189d62bc4baSyz147064 {
190d62bc4baSyz147064 mutex_init(&i_dls_mgmt_lock, NULL, MUTEX_DEFAULT, NULL);
191d62bc4baSyz147064 rw_init(&i_dls_devnet_lock, NULL, RW_DEFAULT, NULL);
192d62bc4baSyz147064
193d62bc4baSyz147064 /*
194d62bc4baSyz147064 * Create a kmem_cache of dls_devnet_t structures.
195d62bc4baSyz147064 */
196d62bc4baSyz147064 i_dls_devnet_cachep = kmem_cache_create("dls_devnet_cache",
197d62bc4baSyz147064 sizeof (dls_devnet_t), 0, i_dls_devnet_constructor,
198d62bc4baSyz147064 i_dls_devnet_destructor, NULL, NULL, NULL, 0);
199d62bc4baSyz147064 ASSERT(i_dls_devnet_cachep != NULL);
200d62bc4baSyz147064
201d62bc4baSyz147064 /*
202da14cebeSEric Cheng * Create a hash table, keyed by dd_linkid, of dls_devnet_t.
203d62bc4baSyz147064 */
204d62bc4baSyz147064 i_dls_devnet_id_hash = mod_hash_create_idhash("dls_devnet_id_hash",
205d62bc4baSyz147064 VLAN_HASHSZ, mod_hash_null_valdtor);
206d62bc4baSyz147064
207d62bc4baSyz147064 /*
208da14cebeSEric Cheng * Create a hash table, keyed by dd_mac
209d62bc4baSyz147064 */
210d62bc4baSyz147064 i_dls_devnet_hash = mod_hash_create_extended("dls_devnet_hash",
211d62bc4baSyz147064 VLAN_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
212d62bc4baSyz147064 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
213d62bc4baSyz147064
214d62bc4baSyz147064 devnet_need_rebuild = B_FALSE;
2152b24ab6bSSebastien Roy
2162b24ab6bSSebastien Roy netstack_register(NS_DLS, dls_stack_init, dls_stack_shutdown,
2172b24ab6bSSebastien Roy dls_stack_fini);
218d62bc4baSyz147064 }
219d62bc4baSyz147064
220d62bc4baSyz147064 void
dls_mgmt_fini(void)221d62bc4baSyz147064 dls_mgmt_fini(void)
222d62bc4baSyz147064 {
2232b24ab6bSSebastien Roy netstack_unregister(NS_DLS);
224d62bc4baSyz147064 mod_hash_destroy_hash(i_dls_devnet_hash);
225d62bc4baSyz147064 mod_hash_destroy_hash(i_dls_devnet_id_hash);
226d62bc4baSyz147064 kmem_cache_destroy(i_dls_devnet_cachep);
227d62bc4baSyz147064 rw_destroy(&i_dls_devnet_lock);
228d62bc4baSyz147064 mutex_destroy(&i_dls_mgmt_lock);
229d62bc4baSyz147064 }
230d62bc4baSyz147064
231d62bc4baSyz147064 int
dls_mgmt_door_set(boolean_t start)232d62bc4baSyz147064 dls_mgmt_door_set(boolean_t start)
233d62bc4baSyz147064 {
234d62bc4baSyz147064 int err;
235d62bc4baSyz147064
236d62bc4baSyz147064 /* handle daemon restart */
237d62bc4baSyz147064 mutex_enter(&i_dls_mgmt_lock);
238d62bc4baSyz147064 if (dls_mgmt_dh != NULL) {
239d62bc4baSyz147064 door_ki_rele(dls_mgmt_dh);
240d62bc4baSyz147064 dls_mgmt_dh = NULL;
241d62bc4baSyz147064 }
242d62bc4baSyz147064
243d62bc4baSyz147064 if (start && ((err = door_ki_open(DLMGMT_DOOR, &dls_mgmt_dh)) != 0)) {
244d62bc4baSyz147064 mutex_exit(&i_dls_mgmt_lock);
245d62bc4baSyz147064 return (err);
246d62bc4baSyz147064 }
247d62bc4baSyz147064
248d62bc4baSyz147064 mutex_exit(&i_dls_mgmt_lock);
249d62bc4baSyz147064
250d62bc4baSyz147064 /*
251d62bc4baSyz147064 * Create and associate <link name, linkid> mapping for network devices
252d62bc4baSyz147064 * which are already attached before the daemon is started.
253d62bc4baSyz147064 */
254d62bc4baSyz147064 if (start)
255d62bc4baSyz147064 softmac_recreate();
256d62bc4baSyz147064 return (0);
257d62bc4baSyz147064 }
258d62bc4baSyz147064
259d62bc4baSyz147064 static boolean_t
i_dls_mgmt_door_revoked(door_handle_t dh)260d62bc4baSyz147064 i_dls_mgmt_door_revoked(door_handle_t dh)
261d62bc4baSyz147064 {
262d62bc4baSyz147064 struct door_info info;
263d62bc4baSyz147064 extern int sys_shutdown;
264d62bc4baSyz147064
265d62bc4baSyz147064 ASSERT(dh != NULL);
266d62bc4baSyz147064
267d62bc4baSyz147064 if (sys_shutdown) {
268d62bc4baSyz147064 cmn_err(CE_NOTE, "dls_mgmt_door: shutdown observed\n");
269d62bc4baSyz147064 return (B_TRUE);
270d62bc4baSyz147064 }
271d62bc4baSyz147064
272d62bc4baSyz147064 if (door_ki_info(dh, &info) != 0)
273d62bc4baSyz147064 return (B_TRUE);
274d62bc4baSyz147064
275d62bc4baSyz147064 return ((info.di_attributes & DOOR_REVOKED) != 0);
276d62bc4baSyz147064 }
277d62bc4baSyz147064
278d62bc4baSyz147064 /*
279d62bc4baSyz147064 * Upcall to the datalink management daemon (dlmgmtd).
280d62bc4baSyz147064 */
281d62bc4baSyz147064 static int
i_dls_mgmt_upcall(void * arg,size_t asize,void * rbuf,size_t rsize)282024b0a25Sseb i_dls_mgmt_upcall(void *arg, size_t asize, void *rbuf, size_t rsize)
283d62bc4baSyz147064 {
284d62bc4baSyz147064 door_arg_t darg, save_arg;
285d62bc4baSyz147064 door_handle_t dh;
286024b0a25Sseb int err;
287d62bc4baSyz147064 int retry = 0;
288d62bc4baSyz147064
289d62bc4baSyz147064 #define MAXRETRYNUM 3
290d62bc4baSyz147064
291d62bc4baSyz147064 ASSERT(arg);
292d62bc4baSyz147064 darg.data_ptr = arg;
293d62bc4baSyz147064 darg.data_size = asize;
294d62bc4baSyz147064 darg.desc_ptr = NULL;
295d62bc4baSyz147064 darg.desc_num = 0;
296d62bc4baSyz147064 darg.rbuf = rbuf;
297024b0a25Sseb darg.rsize = rsize;
298d62bc4baSyz147064 save_arg = darg;
299d62bc4baSyz147064
300d62bc4baSyz147064 retry:
301d62bc4baSyz147064 mutex_enter(&i_dls_mgmt_lock);
302d62bc4baSyz147064 dh = dls_mgmt_dh;
303d62bc4baSyz147064 if ((dh == NULL) || i_dls_mgmt_door_revoked(dh)) {
304d62bc4baSyz147064 mutex_exit(&i_dls_mgmt_lock);
305d62bc4baSyz147064 return (EBADF);
306d62bc4baSyz147064 }
307d62bc4baSyz147064 door_ki_hold(dh);
308d62bc4baSyz147064 mutex_exit(&i_dls_mgmt_lock);
309d62bc4baSyz147064
310d62bc4baSyz147064 for (;;) {
311d62bc4baSyz147064 retry++;
3122b24ab6bSSebastien Roy if ((err = door_ki_upcall_limited(dh, &darg, zone_kcred(),
313323a81d9Sjwadams SIZE_MAX, 0)) == 0)
314d62bc4baSyz147064 break;
315d62bc4baSyz147064
316d62bc4baSyz147064 /*
317d62bc4baSyz147064 * handle door call errors
318d62bc4baSyz147064 */
319d62bc4baSyz147064 darg = save_arg;
320d62bc4baSyz147064 switch (err) {
321d62bc4baSyz147064 case EINTR:
322d62bc4baSyz147064 /*
323d62bc4baSyz147064 * If the operation which caused this door upcall gets
324d62bc4baSyz147064 * interrupted, return directly.
325d62bc4baSyz147064 */
326d62bc4baSyz147064 goto done;
327d62bc4baSyz147064 case EAGAIN:
328d62bc4baSyz147064 /*
329d62bc4baSyz147064 * Repeat upcall if the maximum attempt limit has not
330d62bc4baSyz147064 * been reached.
331d62bc4baSyz147064 */
332d62bc4baSyz147064 if (retry < MAXRETRYNUM) {
333d62bc4baSyz147064 delay(2 * hz);
334d62bc4baSyz147064 break;
335d62bc4baSyz147064 }
336d62bc4baSyz147064 cmn_err(CE_WARN, "dls: dlmgmtd fatal error %d\n", err);
337d62bc4baSyz147064 goto done;
338d62bc4baSyz147064 default:
339d62bc4baSyz147064 /* A fatal door error */
340d62bc4baSyz147064 if (i_dls_mgmt_door_revoked(dh)) {
341d62bc4baSyz147064 cmn_err(CE_NOTE,
342d62bc4baSyz147064 "dls: dlmgmtd door service revoked\n");
343d62bc4baSyz147064
344d62bc4baSyz147064 if (retry < MAXRETRYNUM) {
345d62bc4baSyz147064 door_ki_rele(dh);
346d62bc4baSyz147064 goto retry;
347d62bc4baSyz147064 }
348d62bc4baSyz147064 }
349d62bc4baSyz147064 cmn_err(CE_WARN, "dls: dlmgmtd fatal error %d\n", err);
350d62bc4baSyz147064 goto done;
351d62bc4baSyz147064 }
352d62bc4baSyz147064 }
353d62bc4baSyz147064
354d62bc4baSyz147064 if (darg.rbuf != rbuf) {
355d62bc4baSyz147064 /*
356d62bc4baSyz147064 * The size of the input rbuf was not big enough, so the
357d62bc4baSyz147064 * upcall allocated the rbuf itself. If this happens, assume
358d62bc4baSyz147064 * that this was an invalid door call request.
359d62bc4baSyz147064 */
360d62bc4baSyz147064 kmem_free(darg.rbuf, darg.rsize);
361d62bc4baSyz147064 err = ENOSPC;
362d62bc4baSyz147064 goto done;
363d62bc4baSyz147064 }
364d62bc4baSyz147064
365024b0a25Sseb if (darg.rsize != rsize) {
366d62bc4baSyz147064 err = EINVAL;
367d62bc4baSyz147064 goto done;
368d62bc4baSyz147064 }
369d62bc4baSyz147064
370024b0a25Sseb err = ((dlmgmt_retval_t *)rbuf)->lr_err;
371d62bc4baSyz147064
372d62bc4baSyz147064 done:
373d62bc4baSyz147064 door_ki_rele(dh);
374d62bc4baSyz147064 return (err);
375d62bc4baSyz147064 }
376d62bc4baSyz147064
377d62bc4baSyz147064 /*
378d62bc4baSyz147064 * Request the datalink management daemon to create a link with the attributes
379d62bc4baSyz147064 * below. Upon success, zero is returned and linkidp contains the linkid for
380d62bc4baSyz147064 * the new link; otherwise, an errno is returned.
381d62bc4baSyz147064 *
382d62bc4baSyz147064 * - dev physical dev_t. required for all physical links,
383d62bc4baSyz147064 * including GLDv3 links. It will be used to force the
384d62bc4baSyz147064 * attachment of a physical device, hence the
385d62bc4baSyz147064 * registration of its mac
386d62bc4baSyz147064 * - class datalink class
387d62bc4baSyz147064 * - media type media type; DL_OTHER means unknown
388d62bc4baSyz147064 * - persist whether to persist the datalink
389d62bc4baSyz147064 */
390d62bc4baSyz147064 int
dls_mgmt_create(const char * devname,dev_t dev,datalink_class_t class,uint32_t media,boolean_t persist,datalink_id_t * linkidp)391d62bc4baSyz147064 dls_mgmt_create(const char *devname, dev_t dev, datalink_class_t class,
392d62bc4baSyz147064 uint32_t media, boolean_t persist, datalink_id_t *linkidp)
393d62bc4baSyz147064 {
394d62bc4baSyz147064 dlmgmt_upcall_arg_create_t create;
395d62bc4baSyz147064 dlmgmt_create_retval_t retval;
396d62bc4baSyz147064 int err;
397d62bc4baSyz147064
398d62bc4baSyz147064 create.ld_cmd = DLMGMT_CMD_DLS_CREATE;
399d62bc4baSyz147064 create.ld_class = class;
400d62bc4baSyz147064 create.ld_media = media;
401d62bc4baSyz147064 create.ld_phymaj = getmajor(dev);
402d62bc4baSyz147064 create.ld_phyinst = getminor(dev);
403d62bc4baSyz147064 create.ld_persist = persist;
4042b24ab6bSSebastien Roy if (strlcpy(create.ld_devname, devname, sizeof (create.ld_devname)) >=
4052b24ab6bSSebastien Roy sizeof (create.ld_devname))
406d62bc4baSyz147064 return (EINVAL);
407d62bc4baSyz147064
408024b0a25Sseb if ((err = i_dls_mgmt_upcall(&create, sizeof (create), &retval,
409024b0a25Sseb sizeof (retval))) == 0) {
410d62bc4baSyz147064 *linkidp = retval.lr_linkid;
411024b0a25Sseb }
412d62bc4baSyz147064 return (err);
413d62bc4baSyz147064 }
414d62bc4baSyz147064
415d62bc4baSyz147064 /*
416d62bc4baSyz147064 * Request the datalink management daemon to destroy the specified link.
417d62bc4baSyz147064 * Returns zero upon success, or an errno upon failure.
418d62bc4baSyz147064 */
419d62bc4baSyz147064 int
dls_mgmt_destroy(datalink_id_t linkid,boolean_t persist)420d62bc4baSyz147064 dls_mgmt_destroy(datalink_id_t linkid, boolean_t persist)
421d62bc4baSyz147064 {
422d62bc4baSyz147064 dlmgmt_upcall_arg_destroy_t destroy;
423d62bc4baSyz147064 dlmgmt_destroy_retval_t retval;
424d62bc4baSyz147064
425d62bc4baSyz147064 destroy.ld_cmd = DLMGMT_CMD_DLS_DESTROY;
426d62bc4baSyz147064 destroy.ld_linkid = linkid;
427d62bc4baSyz147064 destroy.ld_persist = persist;
428d62bc4baSyz147064
429024b0a25Sseb return (i_dls_mgmt_upcall(&destroy, sizeof (destroy),
430024b0a25Sseb &retval, sizeof (retval)));
431d62bc4baSyz147064 }
432d62bc4baSyz147064
433d62bc4baSyz147064 /*
434d62bc4baSyz147064 * Request the datalink management daemon to verify/update the information
435d62bc4baSyz147064 * for a physical link. Upon success, get its linkid.
436d62bc4baSyz147064 *
437d62bc4baSyz147064 * - media type media type
438d62bc4baSyz147064 * - novanity whether this physical datalink supports vanity naming.
439d62bc4baSyz147064 * physical links that do not use the GLDv3 MAC plugin
440d62bc4baSyz147064 * cannot suport vanity naming
441d62bc4baSyz147064 *
442d62bc4baSyz147064 * This function could fail with ENOENT or EEXIST. Two cases return EEXIST:
443d62bc4baSyz147064 *
444d62bc4baSyz147064 * 1. A link with devname already exists, but the media type does not match.
445d62bc4baSyz147064 * In this case, mediap will bee set to the media type of the existing link.
446d62bc4baSyz147064 * 2. A link with devname already exists, but its link name does not match
447d62bc4baSyz147064 * the device name, although this link does not support vanity naming.
448d62bc4baSyz147064 */
449d62bc4baSyz147064 int
dls_mgmt_update(const char * devname,uint32_t media,boolean_t novanity,uint32_t * mediap,datalink_id_t * linkidp)450d62bc4baSyz147064 dls_mgmt_update(const char *devname, uint32_t media, boolean_t novanity,
451d62bc4baSyz147064 uint32_t *mediap, datalink_id_t *linkidp)
452d62bc4baSyz147064 {
453d62bc4baSyz147064 dlmgmt_upcall_arg_update_t update;
454d62bc4baSyz147064 dlmgmt_update_retval_t retval;
455d62bc4baSyz147064 int err;
456d62bc4baSyz147064
457d62bc4baSyz147064 update.ld_cmd = DLMGMT_CMD_DLS_UPDATE;
458d62bc4baSyz147064
4592b24ab6bSSebastien Roy if (strlcpy(update.ld_devname, devname, sizeof (update.ld_devname)) >=
4602b24ab6bSSebastien Roy sizeof (update.ld_devname))
461d62bc4baSyz147064 return (EINVAL);
462d62bc4baSyz147064
463d62bc4baSyz147064 update.ld_media = media;
464d62bc4baSyz147064 update.ld_novanity = novanity;
465d62bc4baSyz147064
466024b0a25Sseb if ((err = i_dls_mgmt_upcall(&update, sizeof (update), &retval,
467024b0a25Sseb sizeof (retval))) == EEXIST) {
468d62bc4baSyz147064 *linkidp = retval.lr_linkid;
469d62bc4baSyz147064 *mediap = retval.lr_media;
470d62bc4baSyz147064 } else if (err == 0) {
471d62bc4baSyz147064 *linkidp = retval.lr_linkid;
472d62bc4baSyz147064 }
473d62bc4baSyz147064
474d62bc4baSyz147064 return (err);
475d62bc4baSyz147064 }
476d62bc4baSyz147064
477d62bc4baSyz147064 /*
478d62bc4baSyz147064 * Request the datalink management daemon to get the information for a link.
479d62bc4baSyz147064 * Returns zero upon success, or an errno upon failure.
480d62bc4baSyz147064 *
481d62bc4baSyz147064 * Only fills in information for argument pointers that are non-NULL.
482d62bc4baSyz147064 * Note that the link argument is expected to be MAXLINKNAMELEN bytes.
483d62bc4baSyz147064 */
484d62bc4baSyz147064 int
dls_mgmt_get_linkinfo(datalink_id_t linkid,char * link,datalink_class_t * classp,uint32_t * mediap,uint32_t * flagsp)485d62bc4baSyz147064 dls_mgmt_get_linkinfo(datalink_id_t linkid, char *link,
486d62bc4baSyz147064 datalink_class_t *classp, uint32_t *mediap, uint32_t *flagsp)
487d62bc4baSyz147064 {
488d62bc4baSyz147064 dlmgmt_door_getname_t getname;
489d62bc4baSyz147064 dlmgmt_getname_retval_t retval;
490d62bc4baSyz147064 int err, len;
491d62bc4baSyz147064
492d62bc4baSyz147064 getname.ld_cmd = DLMGMT_CMD_GETNAME;
493d62bc4baSyz147064 getname.ld_linkid = linkid;
494d62bc4baSyz147064
495024b0a25Sseb if ((err = i_dls_mgmt_upcall(&getname, sizeof (getname), &retval,
496024b0a25Sseb sizeof (retval))) != 0) {
497d62bc4baSyz147064 return (err);
498024b0a25Sseb }
499d62bc4baSyz147064
500d62bc4baSyz147064 len = strlen(retval.lr_link);
501d62bc4baSyz147064 if (len <= 1 || len >= MAXLINKNAMELEN)
502d62bc4baSyz147064 return (EINVAL);
503d62bc4baSyz147064
504d62bc4baSyz147064 if (link != NULL)
505d62bc4baSyz147064 (void) strlcpy(link, retval.lr_link, MAXLINKNAMELEN);
506d62bc4baSyz147064 if (classp != NULL)
507d62bc4baSyz147064 *classp = retval.lr_class;
508d62bc4baSyz147064 if (mediap != NULL)
509d62bc4baSyz147064 *mediap = retval.lr_media;
510d62bc4baSyz147064 if (flagsp != NULL)
511d62bc4baSyz147064 *flagsp = retval.lr_flags;
512d62bc4baSyz147064 return (0);
513d62bc4baSyz147064 }
514d62bc4baSyz147064
515d62bc4baSyz147064 /*
516d62bc4baSyz147064 * Request the datalink management daemon to get the linkid for a link.
517d62bc4baSyz147064 * Returns a non-zero error code on failure. The linkid argument is only
518d62bc4baSyz147064 * set on success (when zero is returned.)
519d62bc4baSyz147064 */
520d62bc4baSyz147064 int
dls_mgmt_get_linkid(const char * link,datalink_id_t * linkid)521d62bc4baSyz147064 dls_mgmt_get_linkid(const char *link, datalink_id_t *linkid)
522d62bc4baSyz147064 {
523d62bc4baSyz147064 dlmgmt_door_getlinkid_t getlinkid;
524d62bc4baSyz147064 dlmgmt_getlinkid_retval_t retval;
525d62bc4baSyz147064 int err;
526d62bc4baSyz147064
527d62bc4baSyz147064 getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID;
528d62bc4baSyz147064 (void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN);
529d62bc4baSyz147064
530024b0a25Sseb if ((err = i_dls_mgmt_upcall(&getlinkid, sizeof (getlinkid), &retval,
531024b0a25Sseb sizeof (retval))) == 0) {
532d62bc4baSyz147064 *linkid = retval.lr_linkid;
533024b0a25Sseb }
534d62bc4baSyz147064 return (err);
535d62bc4baSyz147064 }
536d62bc4baSyz147064
537d62bc4baSyz147064 datalink_id_t
dls_mgmt_get_next(datalink_id_t linkid,datalink_class_t class,datalink_media_t dmedia,uint32_t flags)538d62bc4baSyz147064 dls_mgmt_get_next(datalink_id_t linkid, datalink_class_t class,
539d62bc4baSyz147064 datalink_media_t dmedia, uint32_t flags)
540d62bc4baSyz147064 {
541d62bc4baSyz147064 dlmgmt_door_getnext_t getnext;
542d62bc4baSyz147064 dlmgmt_getnext_retval_t retval;
543d62bc4baSyz147064
544d62bc4baSyz147064 getnext.ld_cmd = DLMGMT_CMD_GETNEXT;
545d62bc4baSyz147064 getnext.ld_class = class;
546d62bc4baSyz147064 getnext.ld_dmedia = dmedia;
547d62bc4baSyz147064 getnext.ld_flags = flags;
548d62bc4baSyz147064 getnext.ld_linkid = linkid;
549d62bc4baSyz147064
550024b0a25Sseb if (i_dls_mgmt_upcall(&getnext, sizeof (getnext), &retval,
551024b0a25Sseb sizeof (retval)) != 0) {
552d62bc4baSyz147064 return (DATALINK_INVALID_LINKID);
553024b0a25Sseb }
554d62bc4baSyz147064
555d62bc4baSyz147064 return (retval.lr_linkid);
556d62bc4baSyz147064 }
557d62bc4baSyz147064
558d62bc4baSyz147064 static int
i_dls_mgmt_get_linkattr(const datalink_id_t linkid,const char * attr,void * attrval,size_t * attrszp)559d62bc4baSyz147064 i_dls_mgmt_get_linkattr(const datalink_id_t linkid, const char *attr,
560d62bc4baSyz147064 void *attrval, size_t *attrszp)
561d62bc4baSyz147064 {
562d62bc4baSyz147064 dlmgmt_upcall_arg_getattr_t getattr;
563024b0a25Sseb dlmgmt_getattr_retval_t retval;
564d62bc4baSyz147064 int err;
565d62bc4baSyz147064
566d62bc4baSyz147064 getattr.ld_cmd = DLMGMT_CMD_DLS_GETATTR;
567d62bc4baSyz147064 getattr.ld_linkid = linkid;
568d62bc4baSyz147064 (void) strlcpy(getattr.ld_attr, attr, MAXLINKATTRLEN);
569d62bc4baSyz147064
570024b0a25Sseb if ((err = i_dls_mgmt_upcall(&getattr, sizeof (getattr), &retval,
571024b0a25Sseb sizeof (retval))) == 0) {
572024b0a25Sseb if (*attrszp < retval.lr_attrsz)
573024b0a25Sseb return (EINVAL);
574024b0a25Sseb *attrszp = retval.lr_attrsz;
575024b0a25Sseb bcopy(retval.lr_attrval, attrval, retval.lr_attrsz);
576d62bc4baSyz147064 }
577d62bc4baSyz147064
578d62bc4baSyz147064 return (err);
579d62bc4baSyz147064 }
580d62bc4baSyz147064
581d62bc4baSyz147064 /*
582d62bc4baSyz147064 * Note that this function can only get devp successfully for non-VLAN link.
583d62bc4baSyz147064 */
584d62bc4baSyz147064 int
dls_mgmt_get_phydev(datalink_id_t linkid,dev_t * devp)585d62bc4baSyz147064 dls_mgmt_get_phydev(datalink_id_t linkid, dev_t *devp)
586d62bc4baSyz147064 {
587d62bc4baSyz147064 uint64_t maj, inst;
588d62bc4baSyz147064 size_t attrsz = sizeof (uint64_t);
589d62bc4baSyz147064
590d62bc4baSyz147064 if (i_dls_mgmt_get_linkattr(linkid, FPHYMAJ, &maj, &attrsz) != 0 ||
591d62bc4baSyz147064 attrsz != sizeof (uint64_t) ||
592d62bc4baSyz147064 i_dls_mgmt_get_linkattr(linkid, FPHYINST, &inst, &attrsz) != 0 ||
593d62bc4baSyz147064 attrsz != sizeof (uint64_t)) {
594d62bc4baSyz147064 return (EINVAL);
595d62bc4baSyz147064 }
596d62bc4baSyz147064
597d62bc4baSyz147064 *devp = makedevice((major_t)maj, (minor_t)inst);
598d62bc4baSyz147064 return (0);
599d62bc4baSyz147064 }
600d62bc4baSyz147064
601d62bc4baSyz147064 /*
60230890389Sartem * Request the datalink management daemon to push in
60330890389Sartem * all properties associated with the link.
60430890389Sartem * Returns a non-zero error code on failure.
60530890389Sartem */
60630890389Sartem int
dls_mgmt_linkprop_init(datalink_id_t linkid)60730890389Sartem dls_mgmt_linkprop_init(datalink_id_t linkid)
60830890389Sartem {
60930890389Sartem dlmgmt_door_linkprop_init_t li;
61030890389Sartem dlmgmt_linkprop_init_retval_t retval;
61130890389Sartem int err;
61230890389Sartem
61330890389Sartem li.ld_cmd = DLMGMT_CMD_LINKPROP_INIT;
61430890389Sartem li.ld_linkid = linkid;
61530890389Sartem
61630890389Sartem err = i_dls_mgmt_upcall(&li, sizeof (li), &retval, sizeof (retval));
61730890389Sartem return (err);
61830890389Sartem }
61930890389Sartem
62030890389Sartem static void
dls_devnet_prop_task(void * arg)62130890389Sartem dls_devnet_prop_task(void *arg)
62230890389Sartem {
62330890389Sartem dls_devnet_t *ddp = arg;
62430890389Sartem
625da14cebeSEric Cheng (void) dls_mgmt_linkprop_init(ddp->dd_linkid);
62630890389Sartem
62730890389Sartem mutex_enter(&ddp->dd_mutex);
62830890389Sartem ddp->dd_prop_loaded = B_TRUE;
62930890389Sartem ddp->dd_prop_taskid = NULL;
63030890389Sartem cv_broadcast(&ddp->dd_cv);
63130890389Sartem mutex_exit(&ddp->dd_mutex);
63230890389Sartem }
63330890389Sartem
63430890389Sartem /*
63530890389Sartem * Ensure property loading task is completed.
63630890389Sartem */
63730890389Sartem void
dls_devnet_prop_task_wait(dls_dl_handle_t ddp)63830890389Sartem dls_devnet_prop_task_wait(dls_dl_handle_t ddp)
63930890389Sartem {
64030890389Sartem mutex_enter(&ddp->dd_mutex);
64130890389Sartem while (ddp->dd_prop_taskid != NULL)
64230890389Sartem cv_wait(&ddp->dd_cv, &ddp->dd_mutex);
64330890389Sartem mutex_exit(&ddp->dd_mutex);
64430890389Sartem }
64530890389Sartem
646d62bc4baSyz147064 void
dls_devnet_rele_tmp(dls_dl_handle_t dlh)647d62bc4baSyz147064 dls_devnet_rele_tmp(dls_dl_handle_t dlh)
648d62bc4baSyz147064 {
649d62bc4baSyz147064 dls_devnet_t *ddp = dlh;
650d62bc4baSyz147064
651d62bc4baSyz147064 mutex_enter(&ddp->dd_mutex);
652d62bc4baSyz147064 ASSERT(ddp->dd_tref != 0);
653d62bc4baSyz147064 if (--ddp->dd_tref == 0)
654d62bc4baSyz147064 cv_signal(&ddp->dd_cv);
655d62bc4baSyz147064 mutex_exit(&ddp->dd_mutex);
656d62bc4baSyz147064 }
657d62bc4baSyz147064
658da14cebeSEric Cheng int
dls_devnet_hold_link(datalink_id_t linkid,dls_dl_handle_t * ddhp,dls_link_t ** dlpp)659da14cebeSEric Cheng dls_devnet_hold_link(datalink_id_t linkid, dls_dl_handle_t *ddhp,
660da14cebeSEric Cheng dls_link_t **dlpp)
661da14cebeSEric Cheng {
662da14cebeSEric Cheng dls_dl_handle_t dlh;
663da14cebeSEric Cheng dls_link_t *dlp;
664da14cebeSEric Cheng int err;
665da14cebeSEric Cheng
666da14cebeSEric Cheng if ((err = dls_devnet_hold_tmp(linkid, &dlh)) != 0)
667da14cebeSEric Cheng return (err);
668da14cebeSEric Cheng
669da14cebeSEric Cheng if ((err = dls_link_hold(dls_devnet_mac(dlh), &dlp)) != 0) {
670da14cebeSEric Cheng dls_devnet_rele_tmp(dlh);
671da14cebeSEric Cheng return (err);
672da14cebeSEric Cheng }
673da14cebeSEric Cheng
674da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD(dlp->dl_mh));
675da14cebeSEric Cheng
676da14cebeSEric Cheng *ddhp = dlh;
677da14cebeSEric Cheng *dlpp = dlp;
678da14cebeSEric Cheng return (0);
679da14cebeSEric Cheng }
680da14cebeSEric Cheng
681da14cebeSEric Cheng void
dls_devnet_rele_link(dls_dl_handle_t dlh,dls_link_t * dlp)682da14cebeSEric Cheng dls_devnet_rele_link(dls_dl_handle_t dlh, dls_link_t *dlp)
683da14cebeSEric Cheng {
684da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD(dlp->dl_mh));
685da14cebeSEric Cheng
686da14cebeSEric Cheng dls_link_rele(dlp);
687da14cebeSEric Cheng dls_devnet_rele_tmp(dlh);
688da14cebeSEric Cheng }
689da14cebeSEric Cheng
690d62bc4baSyz147064 /*
691d62bc4baSyz147064 * "link" kstats related functions.
692d62bc4baSyz147064 */
693d62bc4baSyz147064
694d62bc4baSyz147064 /*
695d62bc4baSyz147064 * Query the "link" kstats.
696ae6aa22aSVenugopal Iyer *
697ae6aa22aSVenugopal Iyer * We may be called from the kstat subsystem in an arbitrary context.
698ae6aa22aSVenugopal Iyer * If the caller is the stack, the context could be an upcall data
699ae6aa22aSVenugopal Iyer * thread. Hence we can't acquire the mac perimeter in this function
700ae6aa22aSVenugopal Iyer * for fear of deadlock.
701d62bc4baSyz147064 */
702d62bc4baSyz147064 static int
dls_devnet_stat_update(kstat_t * ksp,int rw)703d62bc4baSyz147064 dls_devnet_stat_update(kstat_t *ksp, int rw)
704d62bc4baSyz147064 {
705d62bc4baSyz147064 dls_devnet_t *ddp = ksp->ks_private;
706da14cebeSEric Cheng dls_link_t *dlp;
707d62bc4baSyz147064 int err;
708d62bc4baSyz147064
709ae6aa22aSVenugopal Iyer /*
710ae6aa22aSVenugopal Iyer * Check the link is being renamed or if the link is going away
711ae6aa22aSVenugopal Iyer * before incrementing dd_tref which in turn prevents the link
712ae6aa22aSVenugopal Iyer * from being renamed or deleted until we finish.
713ae6aa22aSVenugopal Iyer */
714ae6aa22aSVenugopal Iyer mutex_enter(&ddp->dd_mutex);
715ae6aa22aSVenugopal Iyer if (ddp->dd_flags & (DD_CONDEMNED | DD_KSTAT_CHANGING)) {
716ae6aa22aSVenugopal Iyer mutex_exit(&ddp->dd_mutex);
717ae6aa22aSVenugopal Iyer return (ENOENT);
718ae6aa22aSVenugopal Iyer }
719ae6aa22aSVenugopal Iyer ddp->dd_tref++;
720ae6aa22aSVenugopal Iyer mutex_exit(&ddp->dd_mutex);
721d62bc4baSyz147064
722ae6aa22aSVenugopal Iyer /*
723ae6aa22aSVenugopal Iyer * If a device detach happens at this time, it will block in
724ae6aa22aSVenugopal Iyer * dls_devnet_unset since the dd_tref has been bumped up above. So the
725ae6aa22aSVenugopal Iyer * access to 'dlp' is safe even though we don't hold the mac perimeter.
726ae6aa22aSVenugopal Iyer */
727ae6aa22aSVenugopal Iyer if (mod_hash_find(i_dls_link_hash, (mod_hash_key_t)ddp->dd_mac,
728ae6aa22aSVenugopal Iyer (mod_hash_val_t *)&dlp) != 0) {
729ae6aa22aSVenugopal Iyer dls_devnet_rele_tmp(ddp);
730ae6aa22aSVenugopal Iyer return (ENOENT);
731da14cebeSEric Cheng }
732da14cebeSEric Cheng
733da14cebeSEric Cheng err = dls_stat_update(ksp, dlp, rw);
734ae6aa22aSVenugopal Iyer
735ae6aa22aSVenugopal Iyer dls_devnet_rele_tmp(ddp);
736d62bc4baSyz147064 return (err);
737d62bc4baSyz147064 }
738d62bc4baSyz147064
739d62bc4baSyz147064 /*
740d62bc4baSyz147064 * Create the "link" kstats.
741d62bc4baSyz147064 */
742d62bc4baSyz147064 static void
dls_devnet_stat_create(dls_devnet_t * ddp,zoneid_t zoneid)7432b24ab6bSSebastien Roy dls_devnet_stat_create(dls_devnet_t *ddp, zoneid_t zoneid)
744d62bc4baSyz147064 {
745d62bc4baSyz147064 kstat_t *ksp;
746d62bc4baSyz147064
7472b24ab6bSSebastien Roy if (dls_stat_create("link", 0, ddp->dd_linkname, zoneid,
7482b24ab6bSSebastien Roy dls_devnet_stat_update, ddp, &ksp) == 0) {
749d62bc4baSyz147064 ASSERT(ksp != NULL);
7502b24ab6bSSebastien Roy if (zoneid == ddp->dd_owner_zid) {
7512b24ab6bSSebastien Roy ASSERT(ddp->dd_ksp == NULL);
752d62bc4baSyz147064 ddp->dd_ksp = ksp;
7532b24ab6bSSebastien Roy } else {
7542b24ab6bSSebastien Roy ASSERT(ddp->dd_zone_ksp == NULL);
7552b24ab6bSSebastien Roy ddp->dd_zone_ksp = ksp;
7562b24ab6bSSebastien Roy }
7572b24ab6bSSebastien Roy }
758d62bc4baSyz147064 }
759d62bc4baSyz147064
760d62bc4baSyz147064 /*
761d62bc4baSyz147064 * Destroy the "link" kstats.
762d62bc4baSyz147064 */
763d62bc4baSyz147064 static void
dls_devnet_stat_destroy(dls_devnet_t * ddp,zoneid_t zoneid)7642b24ab6bSSebastien Roy dls_devnet_stat_destroy(dls_devnet_t *ddp, zoneid_t zoneid)
765d62bc4baSyz147064 {
7662b24ab6bSSebastien Roy if (zoneid == ddp->dd_owner_zid) {
7672b24ab6bSSebastien Roy if (ddp->dd_ksp != NULL) {
768d62bc4baSyz147064 kstat_delete(ddp->dd_ksp);
769d62bc4baSyz147064 ddp->dd_ksp = NULL;
770d62bc4baSyz147064 }
7712b24ab6bSSebastien Roy } else {
7722b24ab6bSSebastien Roy if (ddp->dd_zone_ksp != NULL) {
7732b24ab6bSSebastien Roy kstat_delete(ddp->dd_zone_ksp);
7742b24ab6bSSebastien Roy ddp->dd_zone_ksp = NULL;
7752b24ab6bSSebastien Roy }
7762b24ab6bSSebastien Roy }
7772b24ab6bSSebastien Roy }
778d62bc4baSyz147064
779d62bc4baSyz147064 /*
780d62bc4baSyz147064 * The link has been renamed. Destroy the old non-legacy kstats ("link kstats")
781d62bc4baSyz147064 * and create the new set using the new name.
782d62bc4baSyz147064 */
783d62bc4baSyz147064 static void
dls_devnet_stat_rename(dls_devnet_t * ddp)7842b24ab6bSSebastien Roy dls_devnet_stat_rename(dls_devnet_t *ddp)
785d62bc4baSyz147064 {
786d62bc4baSyz147064 if (ddp->dd_ksp != NULL) {
787d62bc4baSyz147064 kstat_delete(ddp->dd_ksp);
788d62bc4baSyz147064 ddp->dd_ksp = NULL;
789d62bc4baSyz147064 }
7902b24ab6bSSebastien Roy /* We can't rename a link while it's assigned to a non-global zone. */
7912b24ab6bSSebastien Roy ASSERT(ddp->dd_zone_ksp == NULL);
7922b24ab6bSSebastien Roy dls_devnet_stat_create(ddp, ddp->dd_owner_zid);
793d62bc4baSyz147064 }
794d62bc4baSyz147064
795d62bc4baSyz147064 /*
796da14cebeSEric Cheng * Associate a linkid with a given link (identified by macname)
797d62bc4baSyz147064 */
798d62bc4baSyz147064 static int
dls_devnet_set(const char * macname,datalink_id_t linkid,zoneid_t zoneid,dls_devnet_t ** ddpp)7992b24ab6bSSebastien Roy dls_devnet_set(const char *macname, datalink_id_t linkid, zoneid_t zoneid,
8002b24ab6bSSebastien Roy dls_devnet_t **ddpp)
801d62bc4baSyz147064 {
802d62bc4baSyz147064 dls_devnet_t *ddp = NULL;
803d62bc4baSyz147064 datalink_class_t class;
804d62bc4baSyz147064 int err;
805ae6aa22aSVenugopal Iyer boolean_t stat_create = B_FALSE;
8062b24ab6bSSebastien Roy char linkname[MAXLINKNAMELEN];
807d62bc4baSyz147064
808d62bc4baSyz147064 rw_enter(&i_dls_devnet_lock, RW_WRITER);
8092b24ab6bSSebastien Roy
8102b24ab6bSSebastien Roy /*
8112b24ab6bSSebastien Roy * Don't allow callers to set a link name with a linkid that already
8122b24ab6bSSebastien Roy * has a name association (that's what rename is for).
8132b24ab6bSSebastien Roy */
8142b24ab6bSSebastien Roy if (linkid != DATALINK_INVALID_LINKID) {
8152b24ab6bSSebastien Roy if (mod_hash_find(i_dls_devnet_id_hash,
8162b24ab6bSSebastien Roy (mod_hash_key_t)(uintptr_t)linkid,
8172b24ab6bSSebastien Roy (mod_hash_val_t *)&ddp) == 0) {
8182b24ab6bSSebastien Roy err = EEXIST;
8192b24ab6bSSebastien Roy goto done;
8202b24ab6bSSebastien Roy }
8212b24ab6bSSebastien Roy if ((err = dls_mgmt_get_linkinfo(linkid, linkname, &class,
8222b24ab6bSSebastien Roy NULL, NULL)) != 0)
8232b24ab6bSSebastien Roy goto done;
8242b24ab6bSSebastien Roy }
8252b24ab6bSSebastien Roy
826d62bc4baSyz147064 if ((err = mod_hash_find(i_dls_devnet_hash,
827da14cebeSEric Cheng (mod_hash_key_t)macname, (mod_hash_val_t *)&ddp)) == 0) {
828da14cebeSEric Cheng if (ddp->dd_linkid != DATALINK_INVALID_LINKID) {
829d62bc4baSyz147064 err = EEXIST;
830d62bc4baSyz147064 goto done;
831d62bc4baSyz147064 }
832d62bc4baSyz147064
833d62bc4baSyz147064 /*
834d62bc4baSyz147064 * This might be a physical link that has already
835da14cebeSEric Cheng * been created, but which does not have a linkid
836d62bc4baSyz147064 * because dlmgmtd was not running when it was created.
837d62bc4baSyz147064 */
8382b24ab6bSSebastien Roy if (linkid == DATALINK_INVALID_LINKID ||
8392b24ab6bSSebastien Roy class != DATALINK_CLASS_PHYS) {
840d62bc4baSyz147064 err = EINVAL;
841d62bc4baSyz147064 goto done;
842d62bc4baSyz147064 }
8432b24ab6bSSebastien Roy } else {
844d62bc4baSyz147064 ddp = kmem_cache_alloc(i_dls_devnet_cachep, KM_SLEEP);
845d62bc4baSyz147064 ddp->dd_tref = 0;
846d62bc4baSyz147064 ddp->dd_ref++;
8472b24ab6bSSebastien Roy ddp->dd_owner_zid = zoneid;
8482b24ab6bSSebastien Roy (void) strlcpy(ddp->dd_mac, macname, sizeof (ddp->dd_mac));
849d62bc4baSyz147064 VERIFY(mod_hash_insert(i_dls_devnet_hash,
850da14cebeSEric Cheng (mod_hash_key_t)ddp->dd_mac, (mod_hash_val_t)ddp) == 0);
8512b24ab6bSSebastien Roy }
852d62bc4baSyz147064
853da14cebeSEric Cheng if (linkid != DATALINK_INVALID_LINKID) {
854d62bc4baSyz147064 ddp->dd_linkid = linkid;
8552b24ab6bSSebastien Roy (void) strlcpy(ddp->dd_linkname, linkname,
8562b24ab6bSSebastien Roy sizeof (ddp->dd_linkname));
857d62bc4baSyz147064 VERIFY(mod_hash_insert(i_dls_devnet_id_hash,
858da14cebeSEric Cheng (mod_hash_key_t)(uintptr_t)linkid,
859d62bc4baSyz147064 (mod_hash_val_t)ddp) == 0);
860d62bc4baSyz147064 devnet_need_rebuild = B_TRUE;
861ae6aa22aSVenugopal Iyer stat_create = B_TRUE;
86230890389Sartem mutex_enter(&ddp->dd_mutex);
86330890389Sartem if (!ddp->dd_prop_loaded && (ddp->dd_prop_taskid == NULL)) {
86430890389Sartem ddp->dd_prop_taskid = taskq_dispatch(system_taskq,
86530890389Sartem dls_devnet_prop_task, ddp, TQ_SLEEP);
866d62bc4baSyz147064 }
86730890389Sartem mutex_exit(&ddp->dd_mutex);
86830890389Sartem }
869d62bc4baSyz147064 err = 0;
870d62bc4baSyz147064 done:
871ae6aa22aSVenugopal Iyer /*
872ae6aa22aSVenugopal Iyer * It is safe to drop the i_dls_devnet_lock at this point. In the case
873ae6aa22aSVenugopal Iyer * of physical devices, the softmac framework will fail the device
874ae6aa22aSVenugopal Iyer * detach based on the smac_state or smac_hold_cnt. Other cases like
875ae6aa22aSVenugopal Iyer * vnic and aggr use their own scheme to serialize creates and deletes
876ae6aa22aSVenugopal Iyer * and ensure that *ddp is valid.
8772b24ab6bSSebastien Roy */
8782b24ab6bSSebastien Roy rw_exit(&i_dls_devnet_lock);
8792b24ab6bSSebastien Roy if (err == 0) {
8802b24ab6bSSebastien Roy if (zoneid != GLOBAL_ZONEID &&
8812b24ab6bSSebastien Roy (err = i_dls_devnet_setzid(ddp, zoneid, B_FALSE)) != 0)
8822b24ab6bSSebastien Roy (void) dls_devnet_unset(macname, &linkid, B_TRUE);
8832b24ab6bSSebastien Roy /*
8842b24ab6bSSebastien Roy * The kstat subsystem holds its own locks (rather perimeter)
8852b24ab6bSSebastien Roy * before calling the ks_update (dls_devnet_stat_update) entry
8862b24ab6bSSebastien Roy * point which in turn grabs the i_dls_devnet_lock. So the
8872b24ab6bSSebastien Roy * lock hierarchy is kstat locks -> i_dls_devnet_lock.
888ae6aa22aSVenugopal Iyer */
889ae6aa22aSVenugopal Iyer if (stat_create)
8902b24ab6bSSebastien Roy dls_devnet_stat_create(ddp, zoneid);
8912b24ab6bSSebastien Roy if (ddpp != NULL)
892d62bc4baSyz147064 *ddpp = ddp;
8932b24ab6bSSebastien Roy }
894d62bc4baSyz147064 return (err);
895d62bc4baSyz147064 }
896d62bc4baSyz147064
897d62bc4baSyz147064 /*
898da14cebeSEric Cheng * Disassociate a linkid with a given link (identified by macname)
899da14cebeSEric Cheng * This waits until temporary references to the dls_devnet_t are gone.
900d62bc4baSyz147064 */
901d62bc4baSyz147064 static int
dls_devnet_unset(const char * macname,datalink_id_t * id,boolean_t wait)902da14cebeSEric Cheng dls_devnet_unset(const char *macname, datalink_id_t *id, boolean_t wait)
903d62bc4baSyz147064 {
904d62bc4baSyz147064 dls_devnet_t *ddp;
905d62bc4baSyz147064 int err;
906da14cebeSEric Cheng mod_hash_val_t val;
907d62bc4baSyz147064
908d62bc4baSyz147064 rw_enter(&i_dls_devnet_lock, RW_WRITER);
909d62bc4baSyz147064 if ((err = mod_hash_find(i_dls_devnet_hash,
910da14cebeSEric Cheng (mod_hash_key_t)macname, (mod_hash_val_t *)&ddp)) != 0) {
911d62bc4baSyz147064 ASSERT(err == MH_ERR_NOTFOUND);
912d62bc4baSyz147064 rw_exit(&i_dls_devnet_lock);
913d62bc4baSyz147064 return (ENOENT);
914d62bc4baSyz147064 }
915d62bc4baSyz147064
916da14cebeSEric Cheng mutex_enter(&ddp->dd_mutex);
917d62bc4baSyz147064
918da14cebeSEric Cheng /*
919da14cebeSEric Cheng * Make sure downcalls into softmac_create or softmac_destroy from
920da14cebeSEric Cheng * devfs don't cv_wait on any devfs related condition for fear of
921da14cebeSEric Cheng * deadlock. Return EBUSY if the asynchronous thread started for
922da14cebeSEric Cheng * property loading as part of the post attach hasn't yet completed.
923da14cebeSEric Cheng */
924da14cebeSEric Cheng ASSERT(ddp->dd_ref != 0);
925da14cebeSEric Cheng if ((ddp->dd_ref != 1) || (!wait &&
926da14cebeSEric Cheng (ddp->dd_tref != 0 || ddp->dd_prop_taskid != NULL))) {
927da14cebeSEric Cheng mutex_exit(&ddp->dd_mutex);
928d62bc4baSyz147064 rw_exit(&i_dls_devnet_lock);
929d62bc4baSyz147064 return (EBUSY);
930d62bc4baSyz147064 }
931d62bc4baSyz147064
932da14cebeSEric Cheng ddp->dd_flags |= DD_CONDEMNED;
933d62bc4baSyz147064 ddp->dd_ref--;
934da14cebeSEric Cheng *id = ddp->dd_linkid;
935d62bc4baSyz147064
9362b24ab6bSSebastien Roy if (ddp->dd_zid != GLOBAL_ZONEID)
9372b24ab6bSSebastien Roy (void) i_dls_devnet_setzid(ddp, GLOBAL_ZONEID, B_FALSE);
9382b24ab6bSSebastien Roy
939da14cebeSEric Cheng /*
940da14cebeSEric Cheng * Remove this dls_devnet_t from the hash table.
941da14cebeSEric Cheng */
942da14cebeSEric Cheng VERIFY(mod_hash_remove(i_dls_devnet_hash,
943da14cebeSEric Cheng (mod_hash_key_t)ddp->dd_mac, &val) == 0);
944d62bc4baSyz147064
945da14cebeSEric Cheng if (ddp->dd_linkid != DATALINK_INVALID_LINKID) {
946da14cebeSEric Cheng VERIFY(mod_hash_remove(i_dls_devnet_id_hash,
947da14cebeSEric Cheng (mod_hash_key_t)(uintptr_t)ddp->dd_linkid, &val) == 0);
948da14cebeSEric Cheng
949da14cebeSEric Cheng devnet_need_rebuild = B_TRUE;
950da14cebeSEric Cheng }
951d62bc4baSyz147064 rw_exit(&i_dls_devnet_lock);
952da14cebeSEric Cheng
953da14cebeSEric Cheng if (wait) {
954da14cebeSEric Cheng /*
955da14cebeSEric Cheng * Wait until all temporary references are released.
956da14cebeSEric Cheng */
957da14cebeSEric Cheng while ((ddp->dd_tref != 0) || (ddp->dd_prop_taskid != NULL))
958da14cebeSEric Cheng cv_wait(&ddp->dd_cv, &ddp->dd_mutex);
959da14cebeSEric Cheng } else {
960da14cebeSEric Cheng ASSERT(ddp->dd_tref == 0 && ddp->dd_prop_taskid == NULL);
961da14cebeSEric Cheng }
962da14cebeSEric Cheng
963ae6aa22aSVenugopal Iyer if (ddp->dd_linkid != DATALINK_INVALID_LINKID)
9642b24ab6bSSebastien Roy dls_devnet_stat_destroy(ddp, ddp->dd_owner_zid);
965ae6aa22aSVenugopal Iyer
966da14cebeSEric Cheng ddp->dd_prop_loaded = B_FALSE;
967da14cebeSEric Cheng ddp->dd_linkid = DATALINK_INVALID_LINKID;
968da14cebeSEric Cheng ddp->dd_flags = 0;
969da14cebeSEric Cheng mutex_exit(&ddp->dd_mutex);
970da14cebeSEric Cheng kmem_cache_free(i_dls_devnet_cachep, ddp);
971da14cebeSEric Cheng
972d62bc4baSyz147064 return (0);
973d62bc4baSyz147064 }
974d62bc4baSyz147064
975d62bc4baSyz147064 static int
dls_devnet_hold_common(datalink_id_t linkid,dls_devnet_t ** ddpp,boolean_t tmp_hold)976da14cebeSEric Cheng dls_devnet_hold_common(datalink_id_t linkid, dls_devnet_t **ddpp,
977da14cebeSEric Cheng boolean_t tmp_hold)
978d62bc4baSyz147064 {
979d62bc4baSyz147064 dls_devnet_t *ddp;
980d62bc4baSyz147064 dev_t phydev = 0;
981d62bc4baSyz147064 dls_dev_handle_t ddh = NULL;
982d62bc4baSyz147064 int err;
983d62bc4baSyz147064
984d62bc4baSyz147064 /*
985d62bc4baSyz147064 * Hold this link to prevent it being detached in case of a
986d62bc4baSyz147064 * physical link.
987d62bc4baSyz147064 */
988d62bc4baSyz147064 if (dls_mgmt_get_phydev(linkid, &phydev) == 0)
989d62bc4baSyz147064 (void) softmac_hold_device(phydev, &ddh);
990d62bc4baSyz147064
991d62bc4baSyz147064 rw_enter(&i_dls_devnet_lock, RW_WRITER);
992d62bc4baSyz147064 if ((err = mod_hash_find(i_dls_devnet_id_hash,
993d62bc4baSyz147064 (mod_hash_key_t)(uintptr_t)linkid, (mod_hash_val_t *)&ddp)) != 0) {
994d62bc4baSyz147064 ASSERT(err == MH_ERR_NOTFOUND);
995d62bc4baSyz147064 rw_exit(&i_dls_devnet_lock);
996d62bc4baSyz147064 softmac_rele_device(ddh);
997d62bc4baSyz147064 return (ENOENT);
998d62bc4baSyz147064 }
999d62bc4baSyz147064
1000da14cebeSEric Cheng mutex_enter(&ddp->dd_mutex);
1001d62bc4baSyz147064 ASSERT(ddp->dd_ref > 0);
1002da14cebeSEric Cheng if (ddp->dd_flags & DD_CONDEMNED) {
1003da14cebeSEric Cheng mutex_exit(&ddp->dd_mutex);
1004d62bc4baSyz147064 rw_exit(&i_dls_devnet_lock);
1005d62bc4baSyz147064 softmac_rele_device(ddh);
1006da14cebeSEric Cheng return (ENOENT);
1007da14cebeSEric Cheng }
1008da14cebeSEric Cheng if (tmp_hold)
1009da14cebeSEric Cheng ddp->dd_tref++;
1010da14cebeSEric Cheng else
1011da14cebeSEric Cheng ddp->dd_ref++;
1012da14cebeSEric Cheng mutex_exit(&ddp->dd_mutex);
1013da14cebeSEric Cheng rw_exit(&i_dls_devnet_lock);
1014d62bc4baSyz147064
1015da14cebeSEric Cheng softmac_rele_device(ddh);
1016da14cebeSEric Cheng
1017d62bc4baSyz147064 *ddpp = ddp;
1018d62bc4baSyz147064 return (0);
1019d62bc4baSyz147064 }
1020d62bc4baSyz147064
1021da14cebeSEric Cheng int
dls_devnet_hold(datalink_id_t linkid,dls_devnet_t ** ddpp)1022da14cebeSEric Cheng dls_devnet_hold(datalink_id_t linkid, dls_devnet_t **ddpp)
1023da14cebeSEric Cheng {
1024da14cebeSEric Cheng return (dls_devnet_hold_common(linkid, ddpp, B_FALSE));
1025da14cebeSEric Cheng }
1026da14cebeSEric Cheng
1027da14cebeSEric Cheng /*
1028da14cebeSEric Cheng * Hold the vanity naming structure (dls_devnet_t) temporarily. The request to
1029da14cebeSEric Cheng * delete the dls_devnet_t will wait until the temporary reference is released.
1030da14cebeSEric Cheng */
1031da14cebeSEric Cheng int
dls_devnet_hold_tmp(datalink_id_t linkid,dls_devnet_t ** ddpp)1032da14cebeSEric Cheng dls_devnet_hold_tmp(datalink_id_t linkid, dls_devnet_t **ddpp)
1033da14cebeSEric Cheng {
1034da14cebeSEric Cheng return (dls_devnet_hold_common(linkid, ddpp, B_TRUE));
1035da14cebeSEric Cheng }
1036da14cebeSEric Cheng
1037d62bc4baSyz147064 /*
1038d62bc4baSyz147064 * This funtion is called when a DLS client tries to open a device node.
1039d62bc4baSyz147064 * This dev_t could a result of a /dev/net node access (returned by
1040d62bc4baSyz147064 * devnet_create_rvp->dls_devnet_open()) or a direct /dev node access.
1041da14cebeSEric Cheng * In both cases, this function bumps up the reference count of the
1042da14cebeSEric Cheng * dls_devnet_t structure. The reference is held as long as the device node
1043da14cebeSEric Cheng * is open. In the case of /dev/net while it is true that the initial reference
1044da14cebeSEric Cheng * is held when the devnet_create_rvp->dls_devnet_open call happens, this
1045da14cebeSEric Cheng * initial reference is released immediately in devnet_inactive_callback ->
1046da14cebeSEric Cheng * dls_devnet_close(). (Note that devnet_inactive_callback() is called right
1047da14cebeSEric Cheng * after dld_open completes, not when the /dev/net node is being closed).
1048da14cebeSEric Cheng * To undo this function, call dls_devnet_rele()
1049d62bc4baSyz147064 */
1050d62bc4baSyz147064 int
dls_devnet_hold_by_dev(dev_t dev,dls_dl_handle_t * ddhp)1051da14cebeSEric Cheng dls_devnet_hold_by_dev(dev_t dev, dls_dl_handle_t *ddhp)
1052d62bc4baSyz147064 {
1053da14cebeSEric Cheng char name[MAXNAMELEN];
1054da14cebeSEric Cheng char *drv;
1055d62bc4baSyz147064 dls_dev_handle_t ddh = NULL;
1056d62bc4baSyz147064 dls_devnet_t *ddp;
1057d62bc4baSyz147064 int err;
1058d62bc4baSyz147064
1059da14cebeSEric Cheng if ((drv = ddi_major_to_name(getmajor(dev))) == NULL)
1060da14cebeSEric Cheng return (EINVAL);
1061da14cebeSEric Cheng
106261af1958SGarrett D'Amore (void) snprintf(name, sizeof (name), "%s%d", drv,
106361af1958SGarrett D'Amore DLS_MINOR2INST(getminor(dev)));
1064da14cebeSEric Cheng
1065d62bc4baSyz147064 /*
1066d62bc4baSyz147064 * Hold this link to prevent it being detached in case of a
1067d62bc4baSyz147064 * GLDv3 physical link.
1068d62bc4baSyz147064 */
1069*3ade6e84SGarrett D'Amore if (DLS_MINOR2INST(getminor(dev)) <= DLS_MAX_PPA)
1070d62bc4baSyz147064 (void) softmac_hold_device(dev, &ddh);
1071d62bc4baSyz147064
1072d62bc4baSyz147064 rw_enter(&i_dls_devnet_lock, RW_WRITER);
1073d62bc4baSyz147064 if ((err = mod_hash_find(i_dls_devnet_hash,
1074da14cebeSEric Cheng (mod_hash_key_t)name, (mod_hash_val_t *)&ddp)) != 0) {
1075d62bc4baSyz147064 ASSERT(err == MH_ERR_NOTFOUND);
1076d62bc4baSyz147064 rw_exit(&i_dls_devnet_lock);
1077da14cebeSEric Cheng softmac_rele_device(ddh);
1078da14cebeSEric Cheng return (ENOENT);
1079d62bc4baSyz147064 }
1080da14cebeSEric Cheng mutex_enter(&ddp->dd_mutex);
1081d62bc4baSyz147064 ASSERT(ddp->dd_ref > 0);
1082da14cebeSEric Cheng if (ddp->dd_flags & DD_CONDEMNED) {
1083da14cebeSEric Cheng mutex_exit(&ddp->dd_mutex);
1084d62bc4baSyz147064 rw_exit(&i_dls_devnet_lock);
1085da14cebeSEric Cheng softmac_rele_device(ddh);
1086da14cebeSEric Cheng return (ENOENT);
1087da14cebeSEric Cheng }
1088da14cebeSEric Cheng ddp->dd_ref++;
1089da14cebeSEric Cheng mutex_exit(&ddp->dd_mutex);
1090da14cebeSEric Cheng rw_exit(&i_dls_devnet_lock);
1091da14cebeSEric Cheng
1092da14cebeSEric Cheng softmac_rele_device(ddh);
1093da14cebeSEric Cheng
1094d62bc4baSyz147064 *ddhp = ddp;
1095d62bc4baSyz147064 return (0);
1096d62bc4baSyz147064 }
1097d62bc4baSyz147064
1098da14cebeSEric Cheng void
dls_devnet_rele(dls_devnet_t * ddp)1099d62bc4baSyz147064 dls_devnet_rele(dls_devnet_t *ddp)
1100d62bc4baSyz147064 {
1101da14cebeSEric Cheng mutex_enter(&ddp->dd_mutex);
1102da14cebeSEric Cheng ASSERT(ddp->dd_ref > 1);
1103da14cebeSEric Cheng ddp->dd_ref--;
11042b24ab6bSSebastien Roy if ((ddp->dd_flags & DD_IMPLICIT_IPTUN) && ddp->dd_ref == 1) {
11052b24ab6bSSebastien Roy mutex_exit(&ddp->dd_mutex);
11062b24ab6bSSebastien Roy if (i_dls_devnet_destroy_iptun(ddp->dd_linkid) != 0)
11072b24ab6bSSebastien Roy ddp->dd_flags |= DD_IMPLICIT_IPTUN;
11082b24ab6bSSebastien Roy return;
11092b24ab6bSSebastien Roy }
1110da14cebeSEric Cheng mutex_exit(&ddp->dd_mutex);
1111d62bc4baSyz147064 }
1112d62bc4baSyz147064
1113d62bc4baSyz147064 static int
dls_devnet_hold_by_name(const char * link,dls_devnet_t ** ddpp)1114da14cebeSEric Cheng dls_devnet_hold_by_name(const char *link, dls_devnet_t **ddpp)
1115d62bc4baSyz147064 {
1116d62bc4baSyz147064 char drv[MAXLINKNAMELEN];
1117d62bc4baSyz147064 uint_t ppa;
1118d62bc4baSyz147064 major_t major;
1119d62bc4baSyz147064 dev_t phy_dev, tmp_dev;
1120d62bc4baSyz147064 datalink_id_t linkid;
1121d62bc4baSyz147064 dls_dev_handle_t ddh;
1122d62bc4baSyz147064 int err;
1123d62bc4baSyz147064
1124d62bc4baSyz147064 if ((err = dls_mgmt_get_linkid(link, &linkid)) == 0)
1125d62bc4baSyz147064 return (dls_devnet_hold(linkid, ddpp));
1126d62bc4baSyz147064
1127d62bc4baSyz147064 /*
1128d62bc4baSyz147064 * If we failed to get the link's linkid because the dlmgmtd daemon
1129d62bc4baSyz147064 * has not been started, return ENOENT so that the application can
1130d62bc4baSyz147064 * fallback to open the /dev node.
1131d62bc4baSyz147064 */
1132d62bc4baSyz147064 if (err == EBADF)
1133d62bc4baSyz147064 return (ENOENT);
1134d62bc4baSyz147064
1135d62bc4baSyz147064 if (err != ENOENT)
1136d62bc4baSyz147064 return (err);
1137d62bc4baSyz147064
1138d501bbfeSSebastien Roy if (ddi_parse(link, drv, &ppa) != DDI_SUCCESS)
1139d501bbfeSSebastien Roy return (ENOENT);
1140d501bbfeSSebastien Roy
1141d501bbfeSSebastien Roy if (IS_IPTUN_LINK(drv)) {
1142d501bbfeSSebastien Roy if ((err = i_dls_devnet_create_iptun(link, drv, &linkid)) != 0)
11432b24ab6bSSebastien Roy return (err);
11442b24ab6bSSebastien Roy /*
11452b24ab6bSSebastien Roy * At this point, an IP tunnel MAC has registered, which
11462b24ab6bSSebastien Roy * resulted in a link being created.
11472b24ab6bSSebastien Roy */
11482b24ab6bSSebastien Roy err = dls_devnet_hold(linkid, ddpp);
11492b24ab6bSSebastien Roy ASSERT(err == 0);
11502b24ab6bSSebastien Roy if (err != 0) {
11512b24ab6bSSebastien Roy VERIFY(i_dls_devnet_destroy_iptun(linkid) == 0);
11522b24ab6bSSebastien Roy return (err);
11532b24ab6bSSebastien Roy }
11542b24ab6bSSebastien Roy /*
11552b24ab6bSSebastien Roy * dls_devnet_rele() will know to destroy the implicit IP
11562b24ab6bSSebastien Roy * tunnel on last reference release if DD_IMPLICIT_IPTUN is
11572b24ab6bSSebastien Roy * set.
11582b24ab6bSSebastien Roy */
11592b24ab6bSSebastien Roy (*ddpp)->dd_flags |= DD_IMPLICIT_IPTUN;
11602b24ab6bSSebastien Roy return (0);
11612b24ab6bSSebastien Roy }
11622b24ab6bSSebastien Roy
1163d62bc4baSyz147064 /*
1164da14cebeSEric Cheng * If this link:
1165d62bc4baSyz147064 * (a) is a physical device, (b) this is the first boot, (c) the MAC
1166d62bc4baSyz147064 * is not registered yet, and (d) we cannot find its linkid, then the
1167d62bc4baSyz147064 * linkname is the same as the devname.
1168d62bc4baSyz147064 *
1169d62bc4baSyz147064 * First filter out invalid names.
1170d62bc4baSyz147064 */
1171d62bc4baSyz147064 if ((major = ddi_name_to_major(drv)) == (major_t)-1)
1172d62bc4baSyz147064 return (ENOENT);
1173d62bc4baSyz147064
117461af1958SGarrett D'Amore phy_dev = makedevice(major, DLS_PPA2MINOR(ppa));
1175d62bc4baSyz147064 if (softmac_hold_device(phy_dev, &ddh) != 0)
1176d62bc4baSyz147064 return (ENOENT);
1177d62bc4baSyz147064
1178d62bc4baSyz147064 /*
1179d62bc4baSyz147064 * At this time, the MAC should be registered, check its phy_dev using
1180d62bc4baSyz147064 * the given name.
1181d62bc4baSyz147064 */
1182da14cebeSEric Cheng if ((err = dls_mgmt_get_linkid(link, &linkid)) != 0 ||
1183d62bc4baSyz147064 (err = dls_mgmt_get_phydev(linkid, &tmp_dev)) != 0) {
1184d62bc4baSyz147064 softmac_rele_device(ddh);
1185d62bc4baSyz147064 return (err);
1186d62bc4baSyz147064 }
1187d62bc4baSyz147064 if (tmp_dev != phy_dev) {
1188d62bc4baSyz147064 softmac_rele_device(ddh);
1189d62bc4baSyz147064 return (ENOENT);
1190d62bc4baSyz147064 }
1191d62bc4baSyz147064
1192d62bc4baSyz147064 err = dls_devnet_hold(linkid, ddpp);
1193d62bc4baSyz147064 softmac_rele_device(ddh);
1194d62bc4baSyz147064 return (err);
1195d62bc4baSyz147064 }
1196d62bc4baSyz147064
1197da14cebeSEric Cheng int
dls_devnet_macname2linkid(const char * macname,datalink_id_t * linkidp)1198da14cebeSEric Cheng dls_devnet_macname2linkid(const char *macname, datalink_id_t *linkidp)
1199da14cebeSEric Cheng {
1200da14cebeSEric Cheng dls_devnet_t *ddp;
1201d62bc4baSyz147064
1202da14cebeSEric Cheng rw_enter(&i_dls_devnet_lock, RW_READER);
1203da14cebeSEric Cheng if (mod_hash_find(i_dls_devnet_hash, (mod_hash_key_t)macname,
1204da14cebeSEric Cheng (mod_hash_val_t *)&ddp) != 0) {
1205da14cebeSEric Cheng rw_exit(&i_dls_devnet_lock);
1206da14cebeSEric Cheng return (ENOENT);
1207d62bc4baSyz147064 }
1208d62bc4baSyz147064
1209da14cebeSEric Cheng *linkidp = ddp->dd_linkid;
1210da14cebeSEric Cheng rw_exit(&i_dls_devnet_lock);
1211da14cebeSEric Cheng return (0);
1212da14cebeSEric Cheng }
1213da14cebeSEric Cheng
1214d62bc4baSyz147064 /*
1215d62bc4baSyz147064 * Get linkid for the given dev.
1216d62bc4baSyz147064 */
1217d62bc4baSyz147064 int
dls_devnet_dev2linkid(dev_t dev,datalink_id_t * linkidp)1218d62bc4baSyz147064 dls_devnet_dev2linkid(dev_t dev, datalink_id_t *linkidp)
1219d62bc4baSyz147064 {
1220da14cebeSEric Cheng char macname[MAXNAMELEN];
1221da14cebeSEric Cheng char *drv;
1222d62bc4baSyz147064
1223da14cebeSEric Cheng if ((drv = ddi_major_to_name(getmajor(dev))) == NULL)
1224da14cebeSEric Cheng return (EINVAL);
1225d62bc4baSyz147064
12262b24ab6bSSebastien Roy (void) snprintf(macname, sizeof (macname), "%s%d", drv,
122761af1958SGarrett D'Amore DLS_MINOR2INST(getminor(dev)));
1228da14cebeSEric Cheng return (dls_devnet_macname2linkid(macname, linkidp));
1229d62bc4baSyz147064 }
1230d62bc4baSyz147064
1231d62bc4baSyz147064 /*
1232d62bc4baSyz147064 * Get the link's physical dev_t. It this is a VLAN, get the dev_t of the
1233d62bc4baSyz147064 * link this VLAN is created on.
1234d62bc4baSyz147064 */
1235d62bc4baSyz147064 int
dls_devnet_phydev(datalink_id_t vlanid,dev_t * devp)1236d62bc4baSyz147064 dls_devnet_phydev(datalink_id_t vlanid, dev_t *devp)
1237d62bc4baSyz147064 {
1238d62bc4baSyz147064 dls_devnet_t *ddp;
1239d62bc4baSyz147064 int err;
1240d62bc4baSyz147064
1241d62bc4baSyz147064 if ((err = dls_devnet_hold_tmp(vlanid, &ddp)) != 0)
1242d62bc4baSyz147064 return (err);
1243d62bc4baSyz147064
1244d62bc4baSyz147064 err = dls_mgmt_get_phydev(ddp->dd_linkid, devp);
1245d62bc4baSyz147064 dls_devnet_rele_tmp(ddp);
1246d62bc4baSyz147064 return (err);
1247d62bc4baSyz147064 }
1248d62bc4baSyz147064
1249d62bc4baSyz147064 /*
1250d62bc4baSyz147064 * Handle the renaming requests. There are two rename cases:
1251d62bc4baSyz147064 *
1252d62bc4baSyz147064 * 1. Request to rename a valid link (id1) to an non-existent link name
1253d62bc4baSyz147064 * (id2). In this case id2 is DATALINK_INVALID_LINKID. Just check whether
1254d62bc4baSyz147064 * id1 is held by any applications.
1255d62bc4baSyz147064 *
1256d62bc4baSyz147064 * In this case, the link's kstats need to be updated using the given name.
1257d62bc4baSyz147064 *
1258d62bc4baSyz147064 * 2. Request to rename a valid link (id1) to the name of a REMOVED
125930890389Sartem * physical link (id2). In this case, check that id1 and its associated
1260d62bc4baSyz147064 * mac is not held by any application, and update the link's linkid to id2.
1261d62bc4baSyz147064 *
1262d62bc4baSyz147064 * This case does not change the <link name, linkid> mapping, so the link's
1263d62bc4baSyz147064 * kstats need to be updated with using name associated the given id2.
1264d62bc4baSyz147064 */
1265d62bc4baSyz147064 int
dls_devnet_rename(datalink_id_t id1,datalink_id_t id2,const char * link)1266d62bc4baSyz147064 dls_devnet_rename(datalink_id_t id1, datalink_id_t id2, const char *link)
1267d62bc4baSyz147064 {
1268d62bc4baSyz147064 dls_dev_handle_t ddh = NULL;
1269d62bc4baSyz147064 int err = 0;
1270d62bc4baSyz147064 dev_t phydev = 0;
1271d62bc4baSyz147064 dls_devnet_t *ddp;
1272da14cebeSEric Cheng mac_perim_handle_t mph = NULL;
1273d62bc4baSyz147064 mac_handle_t mh;
1274d62bc4baSyz147064 mod_hash_val_t val;
1275ae6aa22aSVenugopal Iyer boolean_t clear_dd_flag = B_FALSE;
1276d62bc4baSyz147064
1277d62bc4baSyz147064 /*
1278d62bc4baSyz147064 * In the second case, id2 must be a REMOVED physical link.
1279d62bc4baSyz147064 */
1280d62bc4baSyz147064 if ((id2 != DATALINK_INVALID_LINKID) &&
1281d62bc4baSyz147064 (dls_mgmt_get_phydev(id2, &phydev) == 0) &&
1282d62bc4baSyz147064 softmac_hold_device(phydev, &ddh) == 0) {
1283d62bc4baSyz147064 softmac_rele_device(ddh);
1284d62bc4baSyz147064 return (EEXIST);
1285d62bc4baSyz147064 }
1286d62bc4baSyz147064
1287d62bc4baSyz147064 /*
1288d62bc4baSyz147064 * Hold id1 to prevent it from being detached (if a physical link).
1289d62bc4baSyz147064 */
1290d62bc4baSyz147064 if (dls_mgmt_get_phydev(id1, &phydev) == 0)
1291d62bc4baSyz147064 (void) softmac_hold_device(phydev, &ddh);
1292d62bc4baSyz147064
1293da14cebeSEric Cheng /*
1294da14cebeSEric Cheng * The framework does not hold hold locks across calls to the
1295da14cebeSEric Cheng * mac perimeter, hence enter the perimeter first. This also waits
1296da14cebeSEric Cheng * for the property loading to finish.
1297da14cebeSEric Cheng */
1298ae6aa22aSVenugopal Iyer if ((err = mac_perim_enter_by_linkid(id1, &mph)) != 0) {
1299ae6aa22aSVenugopal Iyer softmac_rele_device(ddh);
1300ae6aa22aSVenugopal Iyer return (err);
1301ae6aa22aSVenugopal Iyer }
1302da14cebeSEric Cheng
1303d62bc4baSyz147064 rw_enter(&i_dls_devnet_lock, RW_WRITER);
1304d62bc4baSyz147064 if ((err = mod_hash_find(i_dls_devnet_id_hash,
1305d62bc4baSyz147064 (mod_hash_key_t)(uintptr_t)id1, (mod_hash_val_t *)&ddp)) != 0) {
1306d62bc4baSyz147064 ASSERT(err == MH_ERR_NOTFOUND);
1307d62bc4baSyz147064 err = ENOENT;
1308d62bc4baSyz147064 goto done;
1309d62bc4baSyz147064 }
1310d62bc4baSyz147064
1311d62bc4baSyz147064 /*
13122b24ab6bSSebastien Roy * Return EBUSY if any applications have this link open, if any thread
13132b24ab6bSSebastien Roy * is currently accessing the link kstats, or if the link is on-loan
13142b24ab6bSSebastien Roy * to a non-global zone. Then set the DD_KSTAT_CHANGING flag to
13152b24ab6bSSebastien Roy * prevent any access to the kstats while we delete and recreate
13162b24ab6bSSebastien Roy * kstats below.
1317d62bc4baSyz147064 */
1318ae6aa22aSVenugopal Iyer mutex_enter(&ddp->dd_mutex);
1319da14cebeSEric Cheng if (ddp->dd_ref > 1) {
1320ae6aa22aSVenugopal Iyer mutex_exit(&ddp->dd_mutex);
1321d62bc4baSyz147064 err = EBUSY;
1322d62bc4baSyz147064 goto done;
1323d62bc4baSyz147064 }
1324d62bc4baSyz147064
1325ae6aa22aSVenugopal Iyer ddp->dd_flags |= DD_KSTAT_CHANGING;
1326ae6aa22aSVenugopal Iyer clear_dd_flag = B_TRUE;
1327ae6aa22aSVenugopal Iyer mutex_exit(&ddp->dd_mutex);
1328ae6aa22aSVenugopal Iyer
1329d62bc4baSyz147064 if (id2 == DATALINK_INVALID_LINKID) {
13302b24ab6bSSebastien Roy (void) strlcpy(ddp->dd_linkname, link,
13312b24ab6bSSebastien Roy sizeof (ddp->dd_linkname));
1332da14cebeSEric Cheng
1333da14cebeSEric Cheng /* rename mac client name and its flow if exists */
1334da14cebeSEric Cheng if ((err = mac_open(ddp->dd_mac, &mh)) != 0)
1335da14cebeSEric Cheng goto done;
1336da14cebeSEric Cheng (void) mac_rename_primary(mh, link);
1337da14cebeSEric Cheng mac_close(mh);
1338d62bc4baSyz147064 goto done;
1339d62bc4baSyz147064 }
1340d62bc4baSyz147064
1341d62bc4baSyz147064 /*
1342d62bc4baSyz147064 * The second case, check whether the MAC is used by any MAC
1343d62bc4baSyz147064 * user. This must be a physical link so ddh must not be NULL.
1344d62bc4baSyz147064 */
1345d62bc4baSyz147064 if (ddh == NULL) {
1346d62bc4baSyz147064 err = EINVAL;
1347d62bc4baSyz147064 goto done;
1348d62bc4baSyz147064 }
1349d62bc4baSyz147064
1350d62bc4baSyz147064 if ((err = mac_open(ddp->dd_mac, &mh)) != 0)
1351d62bc4baSyz147064 goto done;
1352d62bc4baSyz147064
1353d62bc4baSyz147064 /*
1354d62bc4baSyz147064 * We release the reference of the MAC which mac_open() is
1355d62bc4baSyz147064 * holding. Note that this mac will not be unregistered
1356da14cebeSEric Cheng * because the physical device is held.
1357d62bc4baSyz147064 */
1358d62bc4baSyz147064 mac_close(mh);
1359d62bc4baSyz147064
1360d62bc4baSyz147064 /*
1361d62bc4baSyz147064 * Check if there is any other MAC clients, if not, hold this mac
1362d62bc4baSyz147064 * exclusively until we are done.
1363d62bc4baSyz147064 */
1364da14cebeSEric Cheng if ((err = mac_mark_exclusive(mh)) != 0)
1365d62bc4baSyz147064 goto done;
1366d62bc4baSyz147064
1367d62bc4baSyz147064 /*
1368d62bc4baSyz147064 * Update the link's linkid.
1369d62bc4baSyz147064 */
1370d62bc4baSyz147064 if ((err = mod_hash_find(i_dls_devnet_id_hash,
1371d62bc4baSyz147064 (mod_hash_key_t)(uintptr_t)id2, &val)) != MH_ERR_NOTFOUND) {
1372da14cebeSEric Cheng mac_unmark_exclusive(mh);
1373d62bc4baSyz147064 err = EEXIST;
1374d62bc4baSyz147064 goto done;
1375d62bc4baSyz147064 }
1376d62bc4baSyz147064
13772b24ab6bSSebastien Roy err = dls_mgmt_get_linkinfo(id2, ddp->dd_linkname, NULL, NULL, NULL);
1378d62bc4baSyz147064 if (err != 0) {
1379da14cebeSEric Cheng mac_unmark_exclusive(mh);
1380d62bc4baSyz147064 goto done;
1381d62bc4baSyz147064 }
1382d62bc4baSyz147064
1383d62bc4baSyz147064 (void) mod_hash_remove(i_dls_devnet_id_hash,
1384d62bc4baSyz147064 (mod_hash_key_t)(uintptr_t)id1, &val);
1385d62bc4baSyz147064
1386da14cebeSEric Cheng ddp->dd_linkid = id2;
1387d62bc4baSyz147064 (void) mod_hash_insert(i_dls_devnet_id_hash,
1388da14cebeSEric Cheng (mod_hash_key_t)(uintptr_t)ddp->dd_linkid, (mod_hash_val_t)ddp);
1389da14cebeSEric Cheng
1390da14cebeSEric Cheng mac_unmark_exclusive(mh);
1391d62bc4baSyz147064
139230890389Sartem /* load properties for new id */
139330890389Sartem mutex_enter(&ddp->dd_mutex);
139430890389Sartem ddp->dd_prop_loaded = B_FALSE;
139530890389Sartem ddp->dd_prop_taskid = taskq_dispatch(system_taskq,
139630890389Sartem dls_devnet_prop_task, ddp, TQ_SLEEP);
139730890389Sartem mutex_exit(&ddp->dd_mutex);
139830890389Sartem
1399d62bc4baSyz147064 done:
1400d62bc4baSyz147064 /*
1401d62bc4baSyz147064 * Change the name of the kstat based on the new link name.
1402ae6aa22aSVenugopal Iyer * We can't hold the i_dls_devnet_lock across calls to the kstat
1403ae6aa22aSVenugopal Iyer * subsystem. Instead the DD_KSTAT_CHANGING flag set above in this
1404ae6aa22aSVenugopal Iyer * function prevents any access to the dd_ksp while we delete and
1405ae6aa22aSVenugopal Iyer * recreate it below.
1406d62bc4baSyz147064 */
1407ae6aa22aSVenugopal Iyer rw_exit(&i_dls_devnet_lock);
1408d62bc4baSyz147064 if (err == 0)
14092b24ab6bSSebastien Roy dls_devnet_stat_rename(ddp);
1410d62bc4baSyz147064
1411ae6aa22aSVenugopal Iyer if (clear_dd_flag) {
1412ae6aa22aSVenugopal Iyer mutex_enter(&ddp->dd_mutex);
1413ae6aa22aSVenugopal Iyer ddp->dd_flags &= ~DD_KSTAT_CHANGING;
1414ae6aa22aSVenugopal Iyer mutex_exit(&ddp->dd_mutex);
1415ae6aa22aSVenugopal Iyer }
1416ae6aa22aSVenugopal Iyer
1417da14cebeSEric Cheng if (mph != NULL)
1418da14cebeSEric Cheng mac_perim_exit(mph);
1419d62bc4baSyz147064 softmac_rele_device(ddh);
1420d62bc4baSyz147064 return (err);
1421d62bc4baSyz147064 }
1422d62bc4baSyz147064
14232b24ab6bSSebastien Roy static int
i_dls_devnet_setzid(dls_devnet_t * ddp,zoneid_t new_zoneid,boolean_t setprop)14242b24ab6bSSebastien Roy i_dls_devnet_setzid(dls_devnet_t *ddp, zoneid_t new_zoneid, boolean_t setprop)
14252b24ab6bSSebastien Roy {
14262b24ab6bSSebastien Roy int err;
14272b24ab6bSSebastien Roy mac_perim_handle_t mph;
14282b24ab6bSSebastien Roy boolean_t upcall_done = B_FALSE;
14292b24ab6bSSebastien Roy datalink_id_t linkid = ddp->dd_linkid;
14302b24ab6bSSebastien Roy zoneid_t old_zoneid = ddp->dd_zid;
14312b24ab6bSSebastien Roy dlmgmt_door_setzoneid_t setzid;
14322b24ab6bSSebastien Roy dlmgmt_setzoneid_retval_t retval;
14332b24ab6bSSebastien Roy
14342b24ab6bSSebastien Roy if (old_zoneid == new_zoneid)
14352b24ab6bSSebastien Roy return (0);
14362b24ab6bSSebastien Roy
14372b24ab6bSSebastien Roy if ((err = mac_perim_enter_by_macname(ddp->dd_mac, &mph)) != 0)
14382b24ab6bSSebastien Roy return (err);
14392b24ab6bSSebastien Roy
14402b24ab6bSSebastien Roy /*
14412b24ab6bSSebastien Roy * When changing the zoneid of an existing link, we need to tell
14422b24ab6bSSebastien Roy * dlmgmtd about it. dlmgmtd already knows the zoneid associated with
14432b24ab6bSSebastien Roy * newly created links.
14442b24ab6bSSebastien Roy */
14452b24ab6bSSebastien Roy if (setprop) {
14462b24ab6bSSebastien Roy setzid.ld_cmd = DLMGMT_CMD_SETZONEID;
14472b24ab6bSSebastien Roy setzid.ld_linkid = linkid;
14482b24ab6bSSebastien Roy setzid.ld_zoneid = new_zoneid;
14492b24ab6bSSebastien Roy err = i_dls_mgmt_upcall(&setzid, sizeof (setzid), &retval,
14502b24ab6bSSebastien Roy sizeof (retval));
14512b24ab6bSSebastien Roy if (err != 0)
14522b24ab6bSSebastien Roy goto done;
14532b24ab6bSSebastien Roy upcall_done = B_TRUE;
14542b24ab6bSSebastien Roy }
14552b24ab6bSSebastien Roy if ((err = dls_link_setzid(ddp->dd_mac, new_zoneid)) == 0) {
14562b24ab6bSSebastien Roy ddp->dd_zid = new_zoneid;
14572b24ab6bSSebastien Roy devnet_need_rebuild = B_TRUE;
14582b24ab6bSSebastien Roy }
14592b24ab6bSSebastien Roy
14602b24ab6bSSebastien Roy done:
14612b24ab6bSSebastien Roy if (err != 0 && upcall_done) {
14622b24ab6bSSebastien Roy setzid.ld_zoneid = old_zoneid;
14632b24ab6bSSebastien Roy (void) i_dls_mgmt_upcall(&setzid, sizeof (setzid), &retval,
14642b24ab6bSSebastien Roy sizeof (retval));
14652b24ab6bSSebastien Roy }
14662b24ab6bSSebastien Roy mac_perim_exit(mph);
14672b24ab6bSSebastien Roy return (err);
14682b24ab6bSSebastien Roy }
14692b24ab6bSSebastien Roy
1470d62bc4baSyz147064 int
dls_devnet_setzid(dls_dl_handle_t ddh,zoneid_t new_zid)14712b24ab6bSSebastien Roy dls_devnet_setzid(dls_dl_handle_t ddh, zoneid_t new_zid)
1472d62bc4baSyz147064 {
1473d62bc4baSyz147064 dls_devnet_t *ddp;
1474d62bc4baSyz147064 int err;
1475d62bc4baSyz147064 zoneid_t old_zid;
14762b24ab6bSSebastien Roy boolean_t refheld = B_FALSE;
1477d62bc4baSyz147064
14782b24ab6bSSebastien Roy old_zid = ddh->dd_zid;
1479d62bc4baSyz147064
14802b24ab6bSSebastien Roy if (old_zid == new_zid)
1481d62bc4baSyz147064 return (0);
14822b24ab6bSSebastien Roy
14832b24ab6bSSebastien Roy /*
14842b24ab6bSSebastien Roy * Acquire an additional reference to the link if it is being assigned
14852b24ab6bSSebastien Roy * to a non-global zone from the global zone.
14862b24ab6bSSebastien Roy */
14872b24ab6bSSebastien Roy if (old_zid == GLOBAL_ZONEID && new_zid != GLOBAL_ZONEID) {
14882b24ab6bSSebastien Roy if ((err = dls_devnet_hold(ddh->dd_linkid, &ddp)) != 0)
14892b24ab6bSSebastien Roy return (err);
14902b24ab6bSSebastien Roy refheld = B_TRUE;
1491d62bc4baSyz147064 }
1492d62bc4baSyz147064
14932b24ab6bSSebastien Roy if ((err = i_dls_devnet_setzid(ddh, new_zid, B_TRUE)) != 0) {
14942b24ab6bSSebastien Roy if (refheld)
1495d62bc4baSyz147064 dls_devnet_rele(ddp);
1496d62bc4baSyz147064 return (err);
1497d62bc4baSyz147064 }
1498d62bc4baSyz147064
1499d62bc4baSyz147064 /*
15002b24ab6bSSebastien Roy * Release the additional reference if the link is returning to the
15012b24ab6bSSebastien Roy * global zone from a non-global zone.
1502d62bc4baSyz147064 */
15032b24ab6bSSebastien Roy if (old_zid != GLOBAL_ZONEID && new_zid == GLOBAL_ZONEID)
15042b24ab6bSSebastien Roy dls_devnet_rele(ddh);
1505d62bc4baSyz147064
15062b24ab6bSSebastien Roy /* Re-create kstats in the appropriate zones. */
15072b24ab6bSSebastien Roy if (old_zid != GLOBAL_ZONEID)
15082b24ab6bSSebastien Roy dls_devnet_stat_destroy(ddh, old_zid);
15092b24ab6bSSebastien Roy if (new_zid != GLOBAL_ZONEID)
15102b24ab6bSSebastien Roy dls_devnet_stat_create(ddh, new_zid);
1511d62bc4baSyz147064
1512d62bc4baSyz147064 return (0);
1513d62bc4baSyz147064 }
1514d62bc4baSyz147064
15152b24ab6bSSebastien Roy zoneid_t
dls_devnet_getzid(dls_dl_handle_t ddh)15162b24ab6bSSebastien Roy dls_devnet_getzid(dls_dl_handle_t ddh)
15172b24ab6bSSebastien Roy {
15182b24ab6bSSebastien Roy return (((dls_devnet_t *)ddh)->dd_zid);
15192b24ab6bSSebastien Roy }
15202b24ab6bSSebastien Roy
15212b24ab6bSSebastien Roy zoneid_t
dls_devnet_getownerzid(dls_dl_handle_t ddh)15222b24ab6bSSebastien Roy dls_devnet_getownerzid(dls_dl_handle_t ddh)
15232b24ab6bSSebastien Roy {
15242b24ab6bSSebastien Roy return (((dls_devnet_t *)ddh)->dd_owner_zid);
15252b24ab6bSSebastien Roy }
15262b24ab6bSSebastien Roy
15272b24ab6bSSebastien Roy /*
15282b24ab6bSSebastien Roy * Is linkid visible from zoneid? A link is visible if it was created in the
15292b24ab6bSSebastien Roy * zone, or if it is currently assigned to the zone.
15302b24ab6bSSebastien Roy */
15312b24ab6bSSebastien Roy boolean_t
dls_devnet_islinkvisible(datalink_id_t linkid,zoneid_t zoneid)15322b24ab6bSSebastien Roy dls_devnet_islinkvisible(datalink_id_t linkid, zoneid_t zoneid)
1533d62bc4baSyz147064 {
1534d62bc4baSyz147064 dls_devnet_t *ddp;
15352b24ab6bSSebastien Roy boolean_t result;
1536d62bc4baSyz147064
15372b24ab6bSSebastien Roy if (dls_devnet_hold_tmp(linkid, &ddp) != 0)
15382b24ab6bSSebastien Roy return (B_FALSE);
15392b24ab6bSSebastien Roy result = (ddp->dd_owner_zid == zoneid || ddp->dd_zid == zoneid);
1540d62bc4baSyz147064 dls_devnet_rele_tmp(ddp);
15412b24ab6bSSebastien Roy return (result);
1542d62bc4baSyz147064 }
1543d62bc4baSyz147064
1544d62bc4baSyz147064 /*
1545d62bc4baSyz147064 * Access a vanity naming node.
1546d62bc4baSyz147064 */
1547d62bc4baSyz147064 int
dls_devnet_open(const char * link,dls_dl_handle_t * dhp,dev_t * devp)1548d62bc4baSyz147064 dls_devnet_open(const char *link, dls_dl_handle_t *dhp, dev_t *devp)
1549d62bc4baSyz147064 {
1550d62bc4baSyz147064 dls_devnet_t *ddp;
1551da14cebeSEric Cheng dls_link_t *dlp;
1552d62bc4baSyz147064 zoneid_t zid = getzoneid();
1553d62bc4baSyz147064 int err;
1554da14cebeSEric Cheng mac_perim_handle_t mph;
1555d62bc4baSyz147064
1556da14cebeSEric Cheng if ((err = dls_devnet_hold_by_name(link, &ddp)) != 0)
1557d62bc4baSyz147064 return (err);
1558d62bc4baSyz147064
1559da14cebeSEric Cheng dls_devnet_prop_task_wait(ddp);
1560da14cebeSEric Cheng
1561d62bc4baSyz147064 /*
1562d62bc4baSyz147064 * Opening a link that does not belong to the current non-global zone
1563d62bc4baSyz147064 * is not allowed.
1564d62bc4baSyz147064 */
1565d62bc4baSyz147064 if (zid != GLOBAL_ZONEID && ddp->dd_zid != zid) {
1566d62bc4baSyz147064 dls_devnet_rele(ddp);
1567d62bc4baSyz147064 return (ENOENT);
1568d62bc4baSyz147064 }
1569d62bc4baSyz147064
1570da14cebeSEric Cheng err = mac_perim_enter_by_macname(ddp->dd_mac, &mph);
1571d62bc4baSyz147064 if (err != 0) {
1572d62bc4baSyz147064 dls_devnet_rele(ddp);
1573d62bc4baSyz147064 return (err);
1574d62bc4baSyz147064 }
1575d62bc4baSyz147064
1576da14cebeSEric Cheng err = dls_link_hold_create(ddp->dd_mac, &dlp);
1577da14cebeSEric Cheng mac_perim_exit(mph);
1578da14cebeSEric Cheng
1579da14cebeSEric Cheng if (err != 0) {
1580da14cebeSEric Cheng dls_devnet_rele(ddp);
1581da14cebeSEric Cheng return (err);
1582da14cebeSEric Cheng }
158330890389Sartem
1584d62bc4baSyz147064 *dhp = ddp;
1585da14cebeSEric Cheng *devp = dls_link_dev(dlp);
1586d62bc4baSyz147064 return (0);
1587d62bc4baSyz147064 }
1588d62bc4baSyz147064
1589d62bc4baSyz147064 /*
1590d62bc4baSyz147064 * Close access to a vanity naming node.
1591d62bc4baSyz147064 */
1592d62bc4baSyz147064 void
dls_devnet_close(dls_dl_handle_t dlh)1593d62bc4baSyz147064 dls_devnet_close(dls_dl_handle_t dlh)
1594d62bc4baSyz147064 {
1595d62bc4baSyz147064 dls_devnet_t *ddp = dlh;
1596da14cebeSEric Cheng dls_link_t *dlp;
1597da14cebeSEric Cheng mac_perim_handle_t mph;
1598da14cebeSEric Cheng
1599da14cebeSEric Cheng VERIFY(mac_perim_enter_by_macname(ddp->dd_mac, &mph) == 0);
1600da14cebeSEric Cheng VERIFY(dls_link_hold(ddp->dd_mac, &dlp) == 0);
1601d62bc4baSyz147064
1602d62bc4baSyz147064 /*
1603da14cebeSEric Cheng * One rele for the hold placed in dls_devnet_open, another for
1604da14cebeSEric Cheng * the hold done just above
1605d62bc4baSyz147064 */
1606da14cebeSEric Cheng dls_link_rele(dlp);
1607da14cebeSEric Cheng dls_link_rele(dlp);
1608da14cebeSEric Cheng mac_perim_exit(mph);
1609da14cebeSEric Cheng
1610d62bc4baSyz147064 dls_devnet_rele(ddp);
1611d62bc4baSyz147064 }
1612d62bc4baSyz147064
1613d62bc4baSyz147064 /*
1614d62bc4baSyz147064 * This is used by /dev/net to rebuild the nodes for readdir(). It is not
1615d62bc4baSyz147064 * critical and no protection is needed.
1616d62bc4baSyz147064 */
1617d62bc4baSyz147064 boolean_t
dls_devnet_rebuild()1618d62bc4baSyz147064 dls_devnet_rebuild()
1619d62bc4baSyz147064 {
1620d62bc4baSyz147064 boolean_t updated = devnet_need_rebuild;
1621d62bc4baSyz147064
1622d62bc4baSyz147064 devnet_need_rebuild = B_FALSE;
1623d62bc4baSyz147064 return (updated);
1624d62bc4baSyz147064 }
1625d62bc4baSyz147064
1626d62bc4baSyz147064 int
dls_devnet_create(mac_handle_t mh,datalink_id_t linkid,zoneid_t zoneid)16272b24ab6bSSebastien Roy dls_devnet_create(mac_handle_t mh, datalink_id_t linkid, zoneid_t zoneid)
1628d62bc4baSyz147064 {
1629da14cebeSEric Cheng dls_link_t *dlp;
16302b24ab6bSSebastien Roy dls_devnet_t *ddp;
1631d62bc4baSyz147064 int err;
1632da14cebeSEric Cheng mac_perim_handle_t mph;
1633d62bc4baSyz147064
1634ae6aa22aSVenugopal Iyer /*
1635ae6aa22aSVenugopal Iyer * Holding the mac perimeter ensures that the downcall from the
1636ae6aa22aSVenugopal Iyer * dlmgmt daemon which does the property loading does not proceed
1637ae6aa22aSVenugopal Iyer * until we relinquish the perimeter.
1638ae6aa22aSVenugopal Iyer */
1639da14cebeSEric Cheng mac_perim_enter_by_mh(mh, &mph);
1640da14cebeSEric Cheng /*
1641da14cebeSEric Cheng * Make this association before we call dls_link_hold_create as
1642da14cebeSEric Cheng * we need to use the linkid to get the user name for the link
1643da14cebeSEric Cheng * when we create the MAC client.
1644da14cebeSEric Cheng */
16452b24ab6bSSebastien Roy if ((err = dls_devnet_set(mac_name(mh), linkid, zoneid, &ddp)) == 0) {
1646da14cebeSEric Cheng if ((err = dls_link_hold_create(mac_name(mh), &dlp)) != 0) {
1647da14cebeSEric Cheng mac_perim_exit(mph);
1648ae6aa22aSVenugopal Iyer (void) dls_devnet_unset(mac_name(mh), &linkid, B_TRUE);
1649da14cebeSEric Cheng return (err);
1650da14cebeSEric Cheng }
16512b24ab6bSSebastien Roy }
1652da14cebeSEric Cheng mac_perim_exit(mph);
1653d62bc4baSyz147064 return (err);
1654d62bc4baSyz147064 }
1655d62bc4baSyz147064
1656d62bc4baSyz147064 /*
1657d62bc4baSyz147064 * Set the linkid of the dls_devnet_t and add it into the i_dls_devnet_id_hash.
1658d62bc4baSyz147064 * This is called in the case that the dlmgmtd daemon is started later than
1659d62bc4baSyz147064 * the physical devices get attached, and the linkid is only known after the
1660d62bc4baSyz147064 * daemon starts.
1661d62bc4baSyz147064 */
1662d62bc4baSyz147064 int
dls_devnet_recreate(mac_handle_t mh,datalink_id_t linkid)1663d62bc4baSyz147064 dls_devnet_recreate(mac_handle_t mh, datalink_id_t linkid)
1664d62bc4baSyz147064 {
1665d62bc4baSyz147064 ASSERT(linkid != DATALINK_INVALID_LINKID);
16662b24ab6bSSebastien Roy return (dls_devnet_set(mac_name(mh), linkid, GLOBAL_ZONEID, NULL));
1667d62bc4baSyz147064 }
1668d62bc4baSyz147064
1669d62bc4baSyz147064 int
dls_devnet_destroy(mac_handle_t mh,datalink_id_t * idp,boolean_t wait)1670da14cebeSEric Cheng dls_devnet_destroy(mac_handle_t mh, datalink_id_t *idp, boolean_t wait)
1671d62bc4baSyz147064 {
1672d62bc4baSyz147064 int err;
1673da14cebeSEric Cheng mac_perim_handle_t mph;
1674d62bc4baSyz147064
1675d62bc4baSyz147064 *idp = DATALINK_INVALID_LINKID;
1676da14cebeSEric Cheng err = dls_devnet_unset(mac_name(mh), idp, wait);
1677d62bc4baSyz147064 if (err != 0 && err != ENOENT)
1678d62bc4baSyz147064 return (err);
1679d62bc4baSyz147064
1680da14cebeSEric Cheng mac_perim_enter_by_mh(mh, &mph);
1681da14cebeSEric Cheng err = dls_link_rele_by_name(mac_name(mh));
1682da14cebeSEric Cheng mac_perim_exit(mph);
1683da14cebeSEric Cheng
16842b24ab6bSSebastien Roy if (err != 0) {
16852b24ab6bSSebastien Roy /*
16862b24ab6bSSebastien Roy * XXX It is a general GLDv3 bug that dls_devnet_set() has to
16872b24ab6bSSebastien Roy * be called to re-set the link when destroy fails. The
16882b24ab6bSSebastien Roy * zoneid below will be incorrect if this function is ever
16892b24ab6bSSebastien Roy * called from kernel context or from a zone other than that
16902b24ab6bSSebastien Roy * which initially created the link.
16912b24ab6bSSebastien Roy */
16922b24ab6bSSebastien Roy (void) dls_devnet_set(mac_name(mh), *idp, crgetzoneid(CRED()),
16932b24ab6bSSebastien Roy NULL);
16942b24ab6bSSebastien Roy }
16952b24ab6bSSebastien Roy return (err);
16962b24ab6bSSebastien Roy }
1697d62bc4baSyz147064
16982b24ab6bSSebastien Roy /*
16992b24ab6bSSebastien Roy * Implicitly create an IP tunnel link.
17002b24ab6bSSebastien Roy */
17012b24ab6bSSebastien Roy static int
i_dls_devnet_create_iptun(const char * linkname,const char * drvname,datalink_id_t * linkid)1702d501bbfeSSebastien Roy i_dls_devnet_create_iptun(const char *linkname, const char *drvname,
1703d501bbfeSSebastien Roy datalink_id_t *linkid)
17042b24ab6bSSebastien Roy {
17052b24ab6bSSebastien Roy int err;
17062b24ab6bSSebastien Roy iptun_kparams_t ik;
17072b24ab6bSSebastien Roy uint32_t media;
17082b24ab6bSSebastien Roy netstack_t *ns;
17092b24ab6bSSebastien Roy major_t iptun_major;
17102b24ab6bSSebastien Roy dev_info_t *iptun_dip;
17112b24ab6bSSebastien Roy
17122b24ab6bSSebastien Roy /* First ensure that the iptun device is attached. */
17132b24ab6bSSebastien Roy if ((iptun_major = ddi_name_to_major(IPTUN_DRIVER_NAME)) == (major_t)-1)
17142b24ab6bSSebastien Roy return (EINVAL);
17152b24ab6bSSebastien Roy if ((iptun_dip = ddi_hold_devi_by_instance(iptun_major, 0, 0)) == NULL)
17162b24ab6bSSebastien Roy return (EINVAL);
17172b24ab6bSSebastien Roy
1718d501bbfeSSebastien Roy if (IS_IPV4_TUN(drvname)) {
17192b24ab6bSSebastien Roy ik.iptun_kparam_type = IPTUN_TYPE_IPV4;
17202b24ab6bSSebastien Roy media = DL_IPV4;
1721d501bbfeSSebastien Roy } else if (IS_6TO4_TUN(drvname)) {
17222b24ab6bSSebastien Roy ik.iptun_kparam_type = IPTUN_TYPE_6TO4;
17232b24ab6bSSebastien Roy media = DL_6TO4;
1724d501bbfeSSebastien Roy } else if (IS_IPV6_TUN(drvname)) {
17252b24ab6bSSebastien Roy ik.iptun_kparam_type = IPTUN_TYPE_IPV6;
17262b24ab6bSSebastien Roy media = DL_IPV6;
17272b24ab6bSSebastien Roy }
17282b24ab6bSSebastien Roy ik.iptun_kparam_flags = (IPTUN_KPARAM_TYPE | IPTUN_KPARAM_IMPLICIT);
17292b24ab6bSSebastien Roy
17302b24ab6bSSebastien Roy /* Obtain a datalink id for this tunnel. */
1731d501bbfeSSebastien Roy err = dls_mgmt_create((char *)linkname, 0, DATALINK_CLASS_IPTUN, media,
17322b24ab6bSSebastien Roy B_FALSE, &ik.iptun_kparam_linkid);
17332b24ab6bSSebastien Roy if (err != 0) {
17342b24ab6bSSebastien Roy ddi_release_devi(iptun_dip);
17352b24ab6bSSebastien Roy return (err);
17362b24ab6bSSebastien Roy }
17372b24ab6bSSebastien Roy
17382b24ab6bSSebastien Roy ns = netstack_get_current();
17392b24ab6bSSebastien Roy err = iptun_create(&ik, CRED());
17402b24ab6bSSebastien Roy netstack_rele(ns);
17412b24ab6bSSebastien Roy
17422b24ab6bSSebastien Roy if (err != 0)
17432b24ab6bSSebastien Roy VERIFY(dls_mgmt_destroy(ik.iptun_kparam_linkid, B_FALSE) == 0);
17442b24ab6bSSebastien Roy else
17452b24ab6bSSebastien Roy *linkid = ik.iptun_kparam_linkid;
17462b24ab6bSSebastien Roy
17472b24ab6bSSebastien Roy ddi_release_devi(iptun_dip);
17482b24ab6bSSebastien Roy return (err);
17492b24ab6bSSebastien Roy }
17502b24ab6bSSebastien Roy
17512b24ab6bSSebastien Roy static int
i_dls_devnet_destroy_iptun(datalink_id_t linkid)17522b24ab6bSSebastien Roy i_dls_devnet_destroy_iptun(datalink_id_t linkid)
17532b24ab6bSSebastien Roy {
17542b24ab6bSSebastien Roy int err;
17552b24ab6bSSebastien Roy
17562b24ab6bSSebastien Roy /*
17572b24ab6bSSebastien Roy * Note the use of zone_kcred() here as opposed to CRED(). This is
17582b24ab6bSSebastien Roy * because the process that does the last close of this /dev/net node
17592b24ab6bSSebastien Roy * may not have necessary privileges to delete this IP tunnel, but the
17602b24ab6bSSebastien Roy * tunnel must always be implicitly deleted on last close.
17612b24ab6bSSebastien Roy */
17622b24ab6bSSebastien Roy if ((err = iptun_delete(linkid, zone_kcred())) == 0)
17632b24ab6bSSebastien Roy (void) dls_mgmt_destroy(linkid, B_FALSE);
1764d62bc4baSyz147064 return (err);
1765d62bc4baSyz147064 }
1766d62bc4baSyz147064
1767d62bc4baSyz147064 const char *
dls_devnet_mac(dls_dl_handle_t ddh)1768d62bc4baSyz147064 dls_devnet_mac(dls_dl_handle_t ddh)
1769d62bc4baSyz147064 {
1770d62bc4baSyz147064 return (ddh->dd_mac);
1771d62bc4baSyz147064 }
1772d62bc4baSyz147064
1773d62bc4baSyz147064 datalink_id_t
dls_devnet_linkid(dls_dl_handle_t ddh)1774d62bc4baSyz147064 dls_devnet_linkid(dls_dl_handle_t ddh)
1775d62bc4baSyz147064 {
1776d62bc4baSyz147064 return (ddh->dd_linkid);
1777d62bc4baSyz147064 }
1778