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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 10693ade6e84SGarrett 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 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 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 1138*ccdeb6b6SDan McDonald if (ddi_parse_dlen(link, drv, MAXLINKNAMELEN, &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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 1768d62bc4baSyz147064 dls_devnet_mac(dls_dl_handle_t ddh) 1769d62bc4baSyz147064 { 1770d62bc4baSyz147064 return (ddh->dd_mac); 1771d62bc4baSyz147064 } 1772d62bc4baSyz147064 1773d62bc4baSyz147064 datalink_id_t 1774d62bc4baSyz147064 dls_devnet_linkid(dls_dl_handle_t ddh) 1775d62bc4baSyz147064 { 1776d62bc4baSyz147064 return (ddh->dd_linkid); 1777d62bc4baSyz147064 } 1778