11991Sheppo /* 21991Sheppo * CDDL HEADER START 31991Sheppo * 41991Sheppo * The contents of this file are subject to the terms of the 51991Sheppo * Common Development and Distribution License (the "License"). 61991Sheppo * You may not use this file except in compliance with the License. 71991Sheppo * 81991Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91991Sheppo * or http://www.opensolaris.org/os/licensing. 101991Sheppo * See the License for the specific language governing permissions 111991Sheppo * and limitations under the License. 121991Sheppo * 131991Sheppo * When distributing Covered Code, include this CDDL HEADER in each 141991Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151991Sheppo * If applicable, add the following below this CDDL HEADER, with the 161991Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 171991Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 181991Sheppo * 191991Sheppo * CDDL HEADER END 201991Sheppo */ 211991Sheppo 221991Sheppo /* 23*6419Ssb155480 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 241991Sheppo * Use is subject to license terms. 251991Sheppo */ 261991Sheppo 271991Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 281991Sheppo 291991Sheppo #include <sys/types.h> 301991Sheppo #include <sys/errno.h> 311991Sheppo #include <sys/param.h> 321991Sheppo #include <sys/stream.h> 331991Sheppo #include <sys/kmem.h> 341991Sheppo #include <sys/conf.h> 351991Sheppo #include <sys/devops.h> 361991Sheppo #include <sys/ksynch.h> 371991Sheppo #include <sys/stat.h> 381991Sheppo #include <sys/modctl.h> 39*6419Ssb155480 #include <sys/modhash.h> 401991Sheppo #include <sys/debug.h> 411991Sheppo #include <sys/ethernet.h> 421991Sheppo #include <sys/dlpi.h> 431991Sheppo #include <net/if.h> 441991Sheppo #include <sys/mac.h> 452311Sseb #include <sys/mac_ether.h> 461991Sheppo #include <sys/ddi.h> 471991Sheppo #include <sys/sunddi.h> 481991Sheppo #include <sys/strsun.h> 491991Sheppo #include <sys/note.h> 50*6419Ssb155480 #include <sys/atomic.h> 511991Sheppo #include <sys/vnet.h> 52*6419Ssb155480 #include <sys/vlan.h> 531991Sheppo 541991Sheppo /* 551991Sheppo * Function prototypes. 561991Sheppo */ 571991Sheppo 581991Sheppo /* DDI entrypoints */ 591991Sheppo static int vnetdevinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 601991Sheppo static int vnetattach(dev_info_t *, ddi_attach_cmd_t); 611991Sheppo static int vnetdetach(dev_info_t *, ddi_detach_cmd_t); 621991Sheppo 631991Sheppo /* MAC entrypoints */ 642311Sseb static int vnet_m_stat(void *, uint_t, uint64_t *); 651991Sheppo static int vnet_m_start(void *); 661991Sheppo static void vnet_m_stop(void *); 671991Sheppo static int vnet_m_promisc(void *, boolean_t); 681991Sheppo static int vnet_m_multicst(void *, boolean_t, const uint8_t *); 691991Sheppo static int vnet_m_unicst(void *, const uint8_t *); 701991Sheppo mblk_t *vnet_m_tx(void *, mblk_t *); 711991Sheppo 721991Sheppo /* vnet internal functions */ 731991Sheppo static int vnet_mac_register(vnet_t *); 741991Sheppo static int vnet_read_mac_address(vnet_t *vnetp); 751991Sheppo static void vnet_add_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp); 761991Sheppo static void vnet_del_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp); 771991Sheppo static vp_tl_t *vnet_get_vptl(vnet_t *vnetp, const char *devname); 781991Sheppo 79*6419Ssb155480 /* Forwarding database (FDB) routines */ 80*6419Ssb155480 static void vnet_fdb_create(vnet_t *vnetp); 81*6419Ssb155480 static void vnet_fdb_destroy(vnet_t *vnetp); 82*6419Ssb155480 static vnet_fdbe_t *vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *eaddr); 83*6419Ssb155480 static void vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val); 84*6419Ssb155480 void vnet_fdbe_add(vnet_t *vnetp, struct ether_addr *macaddr, 85*6419Ssb155480 uint8_t type, mac_tx_t m_tx, void *port); 86*6419Ssb155480 void vnet_fdbe_del(vnet_t *vnetp, struct ether_addr *eaddr); 87*6419Ssb155480 void vnet_fdbe_modify(vnet_t *vnetp, struct ether_addr *macaddr, 88*6419Ssb155480 void *portp, boolean_t flag); 89*6419Ssb155480 902311Sseb void vnet_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp); 912311Sseb void vnet_tx_update(void *arg); 921991Sheppo 931991Sheppo /* externs */ 94*6419Ssb155480 extern int vgen_init(vnet_t *vnetp, dev_info_t *vnetdip, const uint8_t *macaddr, 952311Sseb mac_register_t **vgenmacp); 962336Snarayan extern int vgen_uninit(void *arg); 971991Sheppo 98*6419Ssb155480 #define VNET_FDBE_REFHOLD(p) \ 99*6419Ssb155480 { \ 100*6419Ssb155480 atomic_inc_32(&(p)->refcnt); \ 101*6419Ssb155480 ASSERT((p)->refcnt != 0); \ 102*6419Ssb155480 } 103*6419Ssb155480 104*6419Ssb155480 #define VNET_FDBE_REFRELE(p) \ 105*6419Ssb155480 { \ 106*6419Ssb155480 ASSERT((p)->refcnt != 0); \ 107*6419Ssb155480 atomic_dec_32(&(p)->refcnt); \ 108*6419Ssb155480 } 109*6419Ssb155480 1102311Sseb static mac_callbacks_t vnet_m_callbacks = { 1112311Sseb 0, 1122311Sseb vnet_m_stat, 1132311Sseb vnet_m_start, 1142311Sseb vnet_m_stop, 1152311Sseb vnet_m_promisc, 1162311Sseb vnet_m_multicst, 1172311Sseb vnet_m_unicst, 1182311Sseb vnet_m_tx, 1192311Sseb NULL, 1202311Sseb NULL, 1212311Sseb NULL 1222311Sseb }; 1232311Sseb 1241991Sheppo /* 1251991Sheppo * Linked list of "vnet_t" structures - one per instance. 1261991Sheppo */ 1271991Sheppo static vnet_t *vnet_headp = NULL; 1281991Sheppo static krwlock_t vnet_rw; 1291991Sheppo 1301991Sheppo /* Tunables */ 1311991Sheppo uint32_t vnet_ntxds = VNET_NTXDS; /* power of 2 transmit descriptors */ 1321991Sheppo uint32_t vnet_ldcwd_interval = VNET_LDCWD_INTERVAL; /* watchdog freq in msec */ 1331991Sheppo uint32_t vnet_ldcwd_txtimeout = VNET_LDCWD_TXTIMEOUT; /* tx timeout in msec */ 1342410Slm66018 uint32_t vnet_ldc_mtu = VNET_LDC_MTU; /* ldc mtu */ 135*6419Ssb155480 136*6419Ssb155480 /* # of chains in fdb hash table */ 137*6419Ssb155480 uint32_t vnet_fdb_nchains = VNET_NFDB_HASH; 138*6419Ssb155480 139*6419Ssb155480 /* Internal tunables */ 140*6419Ssb155480 uint32_t vnet_ethermtu = 1500; /* mtu of the device */ 141*6419Ssb155480 142*6419Ssb155480 /* 143*6419Ssb155480 * Default vlan id. This is only used internally when the "default-vlan-id" 144*6419Ssb155480 * property is not present in the MD device node. Therefore, this should not be 145*6419Ssb155480 * used as a tunable; if this value is changed, the corresponding variable 146*6419Ssb155480 * should be updated to the same value in vsw and also other vnets connected to 147*6419Ssb155480 * the same vsw. 148*6419Ssb155480 */ 149*6419Ssb155480 uint16_t vnet_default_vlan_id = 1; 150*6419Ssb155480 151*6419Ssb155480 /* delay in usec to wait for all references on a fdb entry to be dropped */ 152*6419Ssb155480 uint32_t vnet_fdbe_refcnt_delay = 10; 1531991Sheppo 1541991Sheppo /* 1551991Sheppo * Property names 1561991Sheppo */ 1571991Sheppo static char macaddr_propname[] = "local-mac-address"; 1581991Sheppo 1591991Sheppo /* 1601991Sheppo * This is the string displayed by modinfo(1m). 1611991Sheppo */ 1622109Slm66018 static char vnet_ident[] = "vnet driver v%I%"; 1631991Sheppo extern struct mod_ops mod_driverops; 1641991Sheppo static struct cb_ops cb_vnetops = { 1651991Sheppo nulldev, /* cb_open */ 1661991Sheppo nulldev, /* cb_close */ 1671991Sheppo nodev, /* cb_strategy */ 1681991Sheppo nodev, /* cb_print */ 1691991Sheppo nodev, /* cb_dump */ 1701991Sheppo nodev, /* cb_read */ 1711991Sheppo nodev, /* cb_write */ 1721991Sheppo nodev, /* cb_ioctl */ 1731991Sheppo nodev, /* cb_devmap */ 1741991Sheppo nodev, /* cb_mmap */ 1751991Sheppo nodev, /* cb_segmap */ 1761991Sheppo nochpoll, /* cb_chpoll */ 1771991Sheppo ddi_prop_op, /* cb_prop_op */ 1781991Sheppo NULL, /* cb_stream */ 1791991Sheppo (int)(D_MP) /* cb_flag */ 1801991Sheppo }; 1811991Sheppo 1821991Sheppo static struct dev_ops vnetops = { 1831991Sheppo DEVO_REV, /* devo_rev */ 1841991Sheppo 0, /* devo_refcnt */ 1851991Sheppo NULL, /* devo_getinfo */ 1861991Sheppo nulldev, /* devo_identify */ 1871991Sheppo nulldev, /* devo_probe */ 1881991Sheppo vnetattach, /* devo_attach */ 1891991Sheppo vnetdetach, /* devo_detach */ 1901991Sheppo nodev, /* devo_reset */ 1911991Sheppo &cb_vnetops, /* devo_cb_ops */ 1921991Sheppo (struct bus_ops *)NULL /* devo_bus_ops */ 1931991Sheppo }; 1941991Sheppo 1951991Sheppo static struct modldrv modldrv = { 1961991Sheppo &mod_driverops, /* Type of module. This one is a driver */ 1971991Sheppo vnet_ident, /* ID string */ 1981991Sheppo &vnetops /* driver specific ops */ 1991991Sheppo }; 2001991Sheppo 2011991Sheppo static struct modlinkage modlinkage = { 2021991Sheppo MODREV_1, (void *)&modldrv, NULL 2031991Sheppo }; 2041991Sheppo 2054647Sraghuram #ifdef DEBUG 2061991Sheppo 2071991Sheppo /* 2081991Sheppo * Print debug messages - set to 0xf to enable all msgs 2091991Sheppo */ 2104647Sraghuram int vnet_dbglevel = 0x8; 2111991Sheppo 2124647Sraghuram static void 2134647Sraghuram debug_printf(const char *fname, void *arg, const char *fmt, ...) 2141991Sheppo { 2151991Sheppo char buf[512]; 2161991Sheppo va_list ap; 2171991Sheppo vnet_t *vnetp = (vnet_t *)arg; 2184647Sraghuram char *bufp = buf; 2191991Sheppo 2204647Sraghuram if (vnetp == NULL) { 2214647Sraghuram (void) sprintf(bufp, "%s: ", fname); 2224647Sraghuram bufp += strlen(bufp); 2234647Sraghuram } else { 2244647Sraghuram (void) sprintf(bufp, "vnet%d:%s: ", vnetp->instance, fname); 2254647Sraghuram bufp += strlen(bufp); 2264647Sraghuram } 2274647Sraghuram va_start(ap, fmt); 2284647Sraghuram (void) vsprintf(bufp, fmt, ap); 2294647Sraghuram va_end(ap); 2304647Sraghuram cmn_err(CE_CONT, "%s\n", buf); 2314647Sraghuram } 2321991Sheppo 2331991Sheppo #endif 2341991Sheppo 2351991Sheppo /* _init(9E): initialize the loadable module */ 2361991Sheppo int 2371991Sheppo _init(void) 2381991Sheppo { 2391991Sheppo int status; 2401991Sheppo 2414647Sraghuram DBG1(NULL, "enter\n"); 2421991Sheppo 2431991Sheppo mac_init_ops(&vnetops, "vnet"); 2441991Sheppo status = mod_install(&modlinkage); 2451991Sheppo if (status != 0) { 2461991Sheppo mac_fini_ops(&vnetops); 2471991Sheppo } 2481991Sheppo 2494647Sraghuram DBG1(NULL, "exit(%d)\n", status); 2501991Sheppo return (status); 2511991Sheppo } 2521991Sheppo 2531991Sheppo /* _fini(9E): prepare the module for unloading. */ 2541991Sheppo int 2551991Sheppo _fini(void) 2561991Sheppo { 2571991Sheppo int status; 2581991Sheppo 2594647Sraghuram DBG1(NULL, "enter\n"); 2601991Sheppo 2611991Sheppo status = mod_remove(&modlinkage); 2621991Sheppo if (status != 0) 2631991Sheppo return (status); 2641991Sheppo mac_fini_ops(&vnetops); 2651991Sheppo 2664647Sraghuram DBG1(NULL, "exit(%d)\n", status); 2671991Sheppo return (status); 2681991Sheppo } 2691991Sheppo 2701991Sheppo /* _info(9E): return information about the loadable module */ 2711991Sheppo int 2721991Sheppo _info(struct modinfo *modinfop) 2731991Sheppo { 2741991Sheppo return (mod_info(&modlinkage, modinfop)); 2751991Sheppo } 2761991Sheppo 2771991Sheppo /* 2781991Sheppo * attach(9E): attach a device to the system. 2791991Sheppo * called once for each instance of the device on the system. 2801991Sheppo */ 2811991Sheppo static int 2821991Sheppo vnetattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2831991Sheppo { 2841991Sheppo vnet_t *vnetp; 2851991Sheppo vp_tl_t *vp_tlp; 2861991Sheppo int instance; 2871991Sheppo int status; 2882311Sseb mac_register_t *vgenmacp = NULL; 2894647Sraghuram enum { AST_init = 0x0, AST_vnet_alloc = 0x1, 2904647Sraghuram AST_mac_alloc = 0x2, AST_read_macaddr = 0x4, 2914647Sraghuram AST_vgen_init = 0x8, AST_vptl_alloc = 0x10, 2924647Sraghuram AST_fdbh_alloc = 0x20 } attach_state; 2931991Sheppo 2941991Sheppo attach_state = AST_init; 2951991Sheppo 2961991Sheppo switch (cmd) { 2971991Sheppo case DDI_ATTACH: 2981991Sheppo break; 2991991Sheppo case DDI_RESUME: 3001991Sheppo case DDI_PM_RESUME: 3011991Sheppo default: 3021991Sheppo goto vnet_attach_fail; 3031991Sheppo } 3041991Sheppo 3051991Sheppo instance = ddi_get_instance(dip); 3064647Sraghuram DBG1(NULL, "instance(%d) enter\n", instance); 3071991Sheppo 3081991Sheppo /* allocate vnet_t and mac_t structures */ 3091991Sheppo vnetp = kmem_zalloc(sizeof (vnet_t), KM_SLEEP); 3101991Sheppo attach_state |= AST_vnet_alloc; 3111991Sheppo 3121991Sheppo /* setup links to vnet_t from both devinfo and mac_t */ 3131991Sheppo ddi_set_driver_private(dip, (caddr_t)vnetp); 3141991Sheppo vnetp->dip = dip; 3151991Sheppo vnetp->instance = instance; 3161991Sheppo 3171991Sheppo /* read the mac address */ 3181991Sheppo status = vnet_read_mac_address(vnetp); 3191991Sheppo if (status != DDI_SUCCESS) { 3201991Sheppo goto vnet_attach_fail; 3211991Sheppo } 3221991Sheppo attach_state |= AST_read_macaddr; 3231991Sheppo 3241991Sheppo /* 3251991Sheppo * Initialize the generic vnet proxy transport. This is the first 3261991Sheppo * and default transport used by vnet. The generic transport 3271991Sheppo * is provided by using sun4v LDC (logical domain channel). On success, 3281991Sheppo * vgen_init() provides a pointer to mac_t of generic transport. 3291991Sheppo * Currently, this generic layer provides network connectivity to other 3301991Sheppo * vnets within ldoms and also to remote hosts oustide ldoms through 3311991Sheppo * the virtual switch (vsw) device on domain0. In the future, when 3321991Sheppo * physical adapters that are able to share their resources (such as 3331991Sheppo * dma channels) with guest domains become available, the vnet device 3341991Sheppo * will use hardware specific driver to communicate directly over the 3351991Sheppo * physical device to reach remote hosts without going through vswitch. 3361991Sheppo */ 3372311Sseb status = vgen_init(vnetp, vnetp->dip, (uint8_t *)vnetp->curr_macaddr, 3382311Sseb &vgenmacp); 3391991Sheppo if (status != DDI_SUCCESS) { 3404647Sraghuram DERR(vnetp, "vgen_init() failed\n"); 3411991Sheppo goto vnet_attach_fail; 3421991Sheppo } 3435641Swentaoy rw_init(&vnetp->trwlock, NULL, RW_DRIVER, NULL); 3441991Sheppo attach_state |= AST_vgen_init; 3451991Sheppo 3461991Sheppo vp_tlp = kmem_zalloc(sizeof (vp_tl_t), KM_SLEEP); 3471991Sheppo vp_tlp->macp = vgenmacp; 3481991Sheppo (void) snprintf(vp_tlp->name, MAXNAMELEN, "%s%u", "vgen", instance); 3491991Sheppo (void) strcpy(vnetp->vgen_name, vp_tlp->name); 3501991Sheppo 3511991Sheppo /* add generic transport to the list of vnet proxy transports */ 3521991Sheppo vnet_add_vptl(vnetp, vp_tlp); 3531991Sheppo attach_state |= AST_vptl_alloc; 3541991Sheppo 355*6419Ssb155480 vnet_fdb_create(vnetp); 3561991Sheppo attach_state |= AST_fdbh_alloc; 3571991Sheppo 3581991Sheppo /* register with MAC layer */ 3591991Sheppo status = vnet_mac_register(vnetp); 3601991Sheppo if (status != DDI_SUCCESS) { 3611991Sheppo goto vnet_attach_fail; 3621991Sheppo } 3631991Sheppo 3641991Sheppo /* add to the list of vnet devices */ 3651991Sheppo WRITE_ENTER(&vnet_rw); 3661991Sheppo vnetp->nextp = vnet_headp; 3671991Sheppo vnet_headp = vnetp; 3681991Sheppo RW_EXIT(&vnet_rw); 3691991Sheppo 3704647Sraghuram DBG1(NULL, "instance(%d) exit\n", instance); 3711991Sheppo return (DDI_SUCCESS); 3721991Sheppo 3731991Sheppo vnet_attach_fail: 3741991Sheppo if (attach_state & AST_fdbh_alloc) { 375*6419Ssb155480 vnet_fdb_destroy(vnetp); 3761991Sheppo } 3771991Sheppo if (attach_state & AST_vptl_alloc) { 3781991Sheppo WRITE_ENTER(&vnetp->trwlock); 3791991Sheppo vnet_del_vptl(vnetp, vp_tlp); 3801991Sheppo RW_EXIT(&vnetp->trwlock); 3811991Sheppo } 3821991Sheppo if (attach_state & AST_vgen_init) { 3832336Snarayan (void) vgen_uninit(vgenmacp->m_driver); 3845641Swentaoy rw_destroy(&vnetp->trwlock); 3851991Sheppo } 3861991Sheppo if (attach_state & AST_vnet_alloc) { 3871991Sheppo KMEM_FREE(vnetp); 3881991Sheppo } 3891991Sheppo return (DDI_FAILURE); 3901991Sheppo } 3911991Sheppo 3921991Sheppo /* 3931991Sheppo * detach(9E): detach a device from the system. 3941991Sheppo */ 3951991Sheppo static int 3961991Sheppo vnetdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3971991Sheppo { 3981991Sheppo vnet_t *vnetp; 3991991Sheppo vnet_t **vnetpp; 4001991Sheppo vp_tl_t *vp_tlp; 4011991Sheppo int instance; 4022336Snarayan int rv; 4031991Sheppo 4041991Sheppo instance = ddi_get_instance(dip); 4054647Sraghuram DBG1(NULL, "instance(%d) enter\n", instance); 4061991Sheppo 4071991Sheppo vnetp = ddi_get_driver_private(dip); 4081991Sheppo if (vnetp == NULL) { 4091991Sheppo goto vnet_detach_fail; 4101991Sheppo } 4111991Sheppo 4121991Sheppo switch (cmd) { 4131991Sheppo case DDI_DETACH: 4141991Sheppo break; 4151991Sheppo case DDI_SUSPEND: 4161991Sheppo case DDI_PM_SUSPEND: 4171991Sheppo default: 4181991Sheppo goto vnet_detach_fail; 4191991Sheppo } 4201991Sheppo 4212336Snarayan /* uninit and free vnet proxy transports */ 4222336Snarayan WRITE_ENTER(&vnetp->trwlock); 4232336Snarayan while ((vp_tlp = vnetp->tlp) != NULL) { 4242336Snarayan if (strcmp(vnetp->vgen_name, vp_tlp->name) == 0) { 4252336Snarayan /* uninitialize generic transport */ 4262336Snarayan rv = vgen_uninit(vp_tlp->macp->m_driver); 4272336Snarayan if (rv != DDI_SUCCESS) { 4282336Snarayan RW_EXIT(&vnetp->trwlock); 4292336Snarayan goto vnet_detach_fail; 4302336Snarayan } 4312336Snarayan } 4322336Snarayan vnet_del_vptl(vnetp, vp_tlp); 4332336Snarayan } 4342336Snarayan RW_EXIT(&vnetp->trwlock); 4352336Snarayan 4361991Sheppo /* 4371991Sheppo * Unregister from the MAC subsystem. This can fail, in 4381991Sheppo * particular if there are DLPI style-2 streams still open - 4391991Sheppo * in which case we just return failure. 4401991Sheppo */ 4412311Sseb if (mac_unregister(vnetp->mh) != 0) 4421991Sheppo goto vnet_detach_fail; 4431991Sheppo 4441991Sheppo /* unlink from instance(vnet_t) list */ 4451991Sheppo WRITE_ENTER(&vnet_rw); 4461991Sheppo for (vnetpp = &vnet_headp; *vnetpp; vnetpp = &(*vnetpp)->nextp) { 4471991Sheppo if (*vnetpp == vnetp) { 4481991Sheppo *vnetpp = vnetp->nextp; 4491991Sheppo break; 4501991Sheppo } 4511991Sheppo } 4521991Sheppo RW_EXIT(&vnet_rw); 4531991Sheppo 454*6419Ssb155480 /* destroy fdb */ 455*6419Ssb155480 vnet_fdb_destroy(vnetp); 4563297Ssb155480 4575641Swentaoy rw_destroy(&vnetp->trwlock); 4581991Sheppo KMEM_FREE(vnetp); 4591991Sheppo 4601991Sheppo return (DDI_SUCCESS); 4611991Sheppo 4621991Sheppo vnet_detach_fail: 4631991Sheppo return (DDI_FAILURE); 4641991Sheppo } 4651991Sheppo 4661991Sheppo /* enable the device for transmit/receive */ 4671991Sheppo static int 4681991Sheppo vnet_m_start(void *arg) 4691991Sheppo { 4701991Sheppo vnet_t *vnetp = arg; 4711991Sheppo vp_tl_t *vp_tlp; 4722311Sseb mac_register_t *vp_macp; 4732311Sseb mac_callbacks_t *cbp; 4741991Sheppo 4754647Sraghuram DBG1(vnetp, "enter\n"); 4761991Sheppo 4771991Sheppo /* 4782793Slm66018 * NOTE: 4791991Sheppo * Currently, we only have generic transport. m_start() invokes 4801991Sheppo * vgen_start() which enables ports/channels in vgen and 4811991Sheppo * initiates handshake with peer vnets and vsw. In the future when we 4821991Sheppo * have support for hardware specific transports, this information 4831991Sheppo * needs to be propagted back to vnet from vgen and we need to revisit 4841991Sheppo * this code (see comments in vnet_attach()). 4851991Sheppo * 4861991Sheppo */ 4871991Sheppo WRITE_ENTER(&vnetp->trwlock); 4881991Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 4891991Sheppo vp_macp = vp_tlp->macp; 4902311Sseb cbp = vp_macp->m_callbacks; 4912311Sseb cbp->mc_start(vp_macp->m_driver); 4921991Sheppo } 4931991Sheppo RW_EXIT(&vnetp->trwlock); 4941991Sheppo 4954647Sraghuram DBG1(vnetp, "exit\n"); 4961991Sheppo return (VNET_SUCCESS); 4971991Sheppo 4981991Sheppo } 4991991Sheppo 5001991Sheppo /* stop transmit/receive for the device */ 5011991Sheppo static void 5021991Sheppo vnet_m_stop(void *arg) 5031991Sheppo { 5041991Sheppo vnet_t *vnetp = arg; 5051991Sheppo vp_tl_t *vp_tlp; 5062311Sseb mac_register_t *vp_macp; 5072311Sseb mac_callbacks_t *cbp; 5081991Sheppo 5094647Sraghuram DBG1(vnetp, "enter\n"); 5101991Sheppo 5111991Sheppo WRITE_ENTER(&vnetp->trwlock); 5121991Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 5131991Sheppo vp_macp = vp_tlp->macp; 5142311Sseb cbp = vp_macp->m_callbacks; 5152311Sseb cbp->mc_stop(vp_macp->m_driver); 5161991Sheppo } 5171991Sheppo RW_EXIT(&vnetp->trwlock); 5181991Sheppo 5194647Sraghuram DBG1(vnetp, "exit\n"); 5201991Sheppo } 5211991Sheppo 5221991Sheppo /* set the unicast mac address of the device */ 5231991Sheppo static int 5241991Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr) 5251991Sheppo { 5261991Sheppo _NOTE(ARGUNUSED(macaddr)) 5271991Sheppo 5281991Sheppo vnet_t *vnetp = arg; 5291991Sheppo 5304647Sraghuram DBG1(vnetp, "enter\n"); 5311991Sheppo /* 5322793Slm66018 * NOTE: setting mac address dynamically is not supported. 5331991Sheppo */ 5344647Sraghuram DBG1(vnetp, "exit\n"); 5351991Sheppo 5362109Slm66018 return (VNET_FAILURE); 5371991Sheppo } 5381991Sheppo 5391991Sheppo /* enable/disable a multicast address */ 5401991Sheppo static int 5411991Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 5421991Sheppo { 5431991Sheppo _NOTE(ARGUNUSED(add, mca)) 5441991Sheppo 5451991Sheppo vnet_t *vnetp = arg; 5461991Sheppo vp_tl_t *vp_tlp; 5472311Sseb mac_register_t *vp_macp; 5482311Sseb mac_callbacks_t *cbp; 5491991Sheppo int rv = VNET_SUCCESS; 5501991Sheppo 5514647Sraghuram DBG1(vnetp, "enter\n"); 5521991Sheppo READ_ENTER(&vnetp->trwlock); 5531991Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 5541991Sheppo if (strcmp(vnetp->vgen_name, vp_tlp->name) == 0) { 5551991Sheppo vp_macp = vp_tlp->macp; 5562311Sseb cbp = vp_macp->m_callbacks; 5572311Sseb rv = cbp->mc_multicst(vp_macp->m_driver, add, mca); 5581991Sheppo break; 5591991Sheppo } 5601991Sheppo } 5611991Sheppo RW_EXIT(&vnetp->trwlock); 5624647Sraghuram DBG1(vnetp, "exit(%d)\n", rv); 5631991Sheppo return (rv); 5641991Sheppo } 5651991Sheppo 5661991Sheppo /* set or clear promiscuous mode on the device */ 5671991Sheppo static int 5681991Sheppo vnet_m_promisc(void *arg, boolean_t on) 5691991Sheppo { 5701991Sheppo _NOTE(ARGUNUSED(on)) 5711991Sheppo 5721991Sheppo vnet_t *vnetp = arg; 5734647Sraghuram DBG1(vnetp, "enter\n"); 5741991Sheppo /* 5752793Slm66018 * NOTE: setting promiscuous mode is not supported, just return success. 5761991Sheppo */ 5774647Sraghuram DBG1(vnetp, "exit\n"); 5781991Sheppo return (VNET_SUCCESS); 5791991Sheppo } 5801991Sheppo 5811991Sheppo /* 5821991Sheppo * Transmit a chain of packets. This function provides switching functionality 5831991Sheppo * based on the destination mac address to reach other guests (within ldoms) or 5841991Sheppo * external hosts. 5851991Sheppo */ 5861991Sheppo mblk_t * 5871991Sheppo vnet_m_tx(void *arg, mblk_t *mp) 5881991Sheppo { 589*6419Ssb155480 vnet_t *vnetp; 590*6419Ssb155480 vnet_fdbe_t *fp; 591*6419Ssb155480 mblk_t *next; 592*6419Ssb155480 mblk_t *resid_mp; 593*6419Ssb155480 struct ether_header *ehp; 5941991Sheppo 5951991Sheppo vnetp = (vnet_t *)arg; 5964647Sraghuram DBG1(vnetp, "enter\n"); 5971991Sheppo ASSERT(mp != NULL); 5981991Sheppo 5991991Sheppo while (mp != NULL) { 600*6419Ssb155480 6011991Sheppo next = mp->b_next; 6021991Sheppo mp->b_next = NULL; 6031991Sheppo 604*6419Ssb155480 /* 605*6419Ssb155480 * Find fdb entry for the destination 606*6419Ssb155480 * and hold a reference to it. 607*6419Ssb155480 */ 6081991Sheppo ehp = (struct ether_header *)mp->b_rptr; 609*6419Ssb155480 fp = vnet_fdbe_find(vnetp, &ehp->ether_dhost); 610*6419Ssb155480 if (fp != NULL) { 6111991Sheppo 6121991Sheppo /* 613*6419Ssb155480 * Destination found in FDB. 614*6419Ssb155480 * The destination is a vnet device within ldoms 615*6419Ssb155480 * and directly reachable, invoke the tx function 616*6419Ssb155480 * in the fdb entry. 6171991Sheppo */ 618*6419Ssb155480 resid_mp = fp->m_tx(fp->txarg, mp); 619*6419Ssb155480 620*6419Ssb155480 /* tx done; now release ref on fdb entry */ 621*6419Ssb155480 VNET_FDBE_REFRELE(fp); 622*6419Ssb155480 6231991Sheppo if (resid_mp != NULL) { 6241991Sheppo /* m_tx failed */ 6251991Sheppo mp->b_next = next; 6261991Sheppo break; 6271991Sheppo } 6281991Sheppo } else { 6291991Sheppo /* 630*6419Ssb155480 * Destination is not in FDB. 6311991Sheppo * If the destination is broadcast/multicast 6321991Sheppo * or an unknown unicast address, forward the 633*6419Ssb155480 * packet to vsw, using the cached fdb entry 634*6419Ssb155480 * to vsw. 6351991Sheppo */ 636*6419Ssb155480 READ_ENTER(&vnetp->vsw_fp_rw); 637*6419Ssb155480 638*6419Ssb155480 fp = vnetp->vsw_fp; 639*6419Ssb155480 if (fp == NULL) { 640*6419Ssb155480 /* 641*6419Ssb155480 * no fdb entry to vsw? drop the packet. 642*6419Ssb155480 */ 643*6419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 6441991Sheppo freemsg(mp); 645*6419Ssb155480 mp = next; 646*6419Ssb155480 continue; 6471991Sheppo } 648*6419Ssb155480 649*6419Ssb155480 /* ref hold the fdb entry to vsw */ 650*6419Ssb155480 VNET_FDBE_REFHOLD(fp); 651*6419Ssb155480 652*6419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 653*6419Ssb155480 654*6419Ssb155480 resid_mp = fp->m_tx(fp->txarg, mp); 655*6419Ssb155480 656*6419Ssb155480 /* tx done; now release ref on fdb entry */ 657*6419Ssb155480 VNET_FDBE_REFRELE(fp); 658*6419Ssb155480 659*6419Ssb155480 if (resid_mp != NULL) { 660*6419Ssb155480 /* m_tx failed */ 661*6419Ssb155480 mp->b_next = next; 662*6419Ssb155480 break; 663*6419Ssb155480 } 6641991Sheppo } 6651991Sheppo 6661991Sheppo mp = next; 6671991Sheppo } 6681991Sheppo 6694647Sraghuram DBG1(vnetp, "exit\n"); 6701991Sheppo return (mp); 6711991Sheppo } 6721991Sheppo 6732311Sseb /* get statistics from the device */ 6742311Sseb int 6752311Sseb vnet_m_stat(void *arg, uint_t stat, uint64_t *val) 6761991Sheppo { 6771991Sheppo vnet_t *vnetp = arg; 6781991Sheppo vp_tl_t *vp_tlp; 6792311Sseb mac_register_t *vp_macp; 6802311Sseb mac_callbacks_t *cbp; 6812311Sseb uint64_t val_total = 0; 6821991Sheppo 6834647Sraghuram DBG1(vnetp, "enter\n"); 6841991Sheppo 6851991Sheppo /* 6862311Sseb * get the specified statistic from each transport and return the 6872311Sseb * aggregate val. This obviously only works for counters. 6881991Sheppo */ 6892311Sseb if ((IS_MAC_STAT(stat) && !MAC_STAT_ISACOUNTER(stat)) || 6902311Sseb (IS_MACTYPE_STAT(stat) && !ETHER_STAT_ISACOUNTER(stat))) { 6912311Sseb return (ENOTSUP); 6922311Sseb } 6931991Sheppo READ_ENTER(&vnetp->trwlock); 6941991Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 6951991Sheppo vp_macp = vp_tlp->macp; 6962311Sseb cbp = vp_macp->m_callbacks; 6972311Sseb if (cbp->mc_getstat(vp_macp->m_driver, stat, val) == 0) 6982311Sseb val_total += *val; 6991991Sheppo } 7001991Sheppo RW_EXIT(&vnetp->trwlock); 7011991Sheppo 7022311Sseb *val = val_total; 7032311Sseb 7044647Sraghuram DBG1(vnetp, "exit\n"); 7052311Sseb return (0); 7061991Sheppo } 7071991Sheppo 7081991Sheppo /* wrapper function for mac_register() */ 7091991Sheppo static int 7101991Sheppo vnet_mac_register(vnet_t *vnetp) 7111991Sheppo { 7122311Sseb mac_register_t *macp; 7132311Sseb int err; 7141991Sheppo 7152311Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 7162311Sseb return (DDI_FAILURE); 7172311Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 7182311Sseb macp->m_driver = vnetp; 7191991Sheppo macp->m_dip = vnetp->dip; 7202311Sseb macp->m_src_addr = vnetp->curr_macaddr; 7212311Sseb macp->m_callbacks = &vnet_m_callbacks; 7222311Sseb macp->m_min_sdu = 0; 723*6419Ssb155480 macp->m_max_sdu = vnet_ethermtu; 724*6419Ssb155480 macp->m_margin = VLAN_TAGSZ; 7251991Sheppo 7261991Sheppo /* 7271991Sheppo * Finally, we're ready to register ourselves with the MAC layer 7281991Sheppo * interface; if this succeeds, we're all ready to start() 7291991Sheppo */ 7302311Sseb err = mac_register(macp, &vnetp->mh); 7312311Sseb mac_free(macp); 7322311Sseb return (err == 0 ? DDI_SUCCESS : DDI_FAILURE); 7331991Sheppo } 7341991Sheppo 7351991Sheppo /* add vp_tl to the list */ 7361991Sheppo static void 7371991Sheppo vnet_add_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp) 7381991Sheppo { 7391991Sheppo vp_tl_t *ttlp; 7401991Sheppo 7411991Sheppo WRITE_ENTER(&vnetp->trwlock); 7421991Sheppo if (vnetp->tlp == NULL) { 7431991Sheppo vnetp->tlp = vp_tlp; 7441991Sheppo } else { 7451991Sheppo ttlp = vnetp->tlp; 7461991Sheppo while (ttlp->nextp) 7471991Sheppo ttlp = ttlp->nextp; 7481991Sheppo ttlp->nextp = vp_tlp; 7491991Sheppo } 7501991Sheppo RW_EXIT(&vnetp->trwlock); 7511991Sheppo } 7521991Sheppo 7531991Sheppo /* remove vp_tl from the list */ 7541991Sheppo static void 7551991Sheppo vnet_del_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp) 7561991Sheppo { 7571991Sheppo vp_tl_t *ttlp, **pretlp; 7581991Sheppo boolean_t found = B_FALSE; 7591991Sheppo 7601991Sheppo pretlp = &vnetp->tlp; 7611991Sheppo ttlp = *pretlp; 7621991Sheppo while (ttlp) { 7631991Sheppo if (ttlp == vp_tlp) { 7641991Sheppo found = B_TRUE; 7651991Sheppo (*pretlp) = ttlp->nextp; 7661991Sheppo ttlp->nextp = NULL; 7671991Sheppo break; 7681991Sheppo } 7691991Sheppo pretlp = &(ttlp->nextp); 7701991Sheppo ttlp = *pretlp; 7711991Sheppo } 7721991Sheppo 7731991Sheppo if (found) { 7741991Sheppo KMEM_FREE(vp_tlp); 7751991Sheppo } 7761991Sheppo } 7771991Sheppo 7781991Sheppo /* get vp_tl corresponding to the given name */ 7791991Sheppo static vp_tl_t * 7801991Sheppo vnet_get_vptl(vnet_t *vnetp, const char *name) 7811991Sheppo { 7821991Sheppo vp_tl_t *tlp; 7831991Sheppo 7841991Sheppo tlp = vnetp->tlp; 7851991Sheppo while (tlp) { 7861991Sheppo if (strcmp(tlp->name, name) == 0) { 7871991Sheppo return (tlp); 7881991Sheppo } 7891991Sheppo tlp = tlp->nextp; 7901991Sheppo } 7914647Sraghuram DWARN(vnetp, "can't find vp_tl with name (%s)\n", name); 7921991Sheppo return (NULL); 7931991Sheppo } 7941991Sheppo 7951991Sheppo /* read the mac address of the device */ 7961991Sheppo static int 7971991Sheppo vnet_read_mac_address(vnet_t *vnetp) 7981991Sheppo { 7991991Sheppo uchar_t *macaddr; 8001991Sheppo uint32_t size; 8011991Sheppo int rv; 8021991Sheppo 8031991Sheppo rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip, 8044650Sraghuram DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size); 8051991Sheppo if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) { 8064647Sraghuram DWARN(vnetp, "prop_lookup failed(%s) err(%d)\n", 8074647Sraghuram macaddr_propname, rv); 8081991Sheppo return (DDI_FAILURE); 8091991Sheppo } 8101991Sheppo bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL); 8111991Sheppo bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL); 8121991Sheppo ddi_prop_free(macaddr); 8131991Sheppo 8141991Sheppo return (DDI_SUCCESS); 8151991Sheppo } 8161991Sheppo 817*6419Ssb155480 static void 818*6419Ssb155480 vnet_fdb_create(vnet_t *vnetp) 8191991Sheppo { 820*6419Ssb155480 char hashname[MAXNAMELEN]; 8211991Sheppo 822*6419Ssb155480 (void) snprintf(hashname, MAXNAMELEN, "vnet%d-fdbhash", 823*6419Ssb155480 vnetp->instance); 824*6419Ssb155480 vnetp->fdb_nchains = vnet_fdb_nchains; 825*6419Ssb155480 vnetp->fdb_hashp = mod_hash_create_ptrhash(hashname, vnetp->fdb_nchains, 826*6419Ssb155480 mod_hash_null_valdtor, sizeof (void *)); 827*6419Ssb155480 } 8281991Sheppo 829*6419Ssb155480 static void 830*6419Ssb155480 vnet_fdb_destroy(vnet_t *vnetp) 831*6419Ssb155480 { 832*6419Ssb155480 /* destroy fdb-hash-table */ 833*6419Ssb155480 if (vnetp->fdb_hashp != NULL) { 834*6419Ssb155480 mod_hash_destroy_hash(vnetp->fdb_hashp); 835*6419Ssb155480 vnetp->fdb_hashp = NULL; 836*6419Ssb155480 vnetp->fdb_nchains = 0; 8371991Sheppo } 8381991Sheppo } 8391991Sheppo 840*6419Ssb155480 /* 841*6419Ssb155480 * Add an entry into the fdb. 842*6419Ssb155480 */ 8431991Sheppo void 844*6419Ssb155480 vnet_fdbe_add(vnet_t *vnetp, struct ether_addr *macaddr, uint8_t type, 845*6419Ssb155480 mac_tx_t m_tx, void *port) 8461991Sheppo { 847*6419Ssb155480 uint64_t addr = 0; 848*6419Ssb155480 vnet_fdbe_t *fp; 849*6419Ssb155480 int rv; 850*6419Ssb155480 851*6419Ssb155480 KEY_HASH(addr, macaddr); 852*6419Ssb155480 853*6419Ssb155480 fp = kmem_zalloc(sizeof (vnet_fdbe_t), KM_SLEEP); 854*6419Ssb155480 fp->txarg = port; 855*6419Ssb155480 fp->type = type; 856*6419Ssb155480 fp->m_tx = m_tx; 8571991Sheppo 858*6419Ssb155480 /* 859*6419Ssb155480 * If the entry being added corresponds to vsw-port, we cache that 860*6419Ssb155480 * entry and keep a permanent reference to it. This is done to avoid 861*6419Ssb155480 * searching this entry when we need to transmit a frame with an 862*6419Ssb155480 * unknown unicast destination, in vnet_m_tx(). 863*6419Ssb155480 */ 864*6419Ssb155480 (fp->type == VNET_VSWPORT) ? (fp->refcnt = 1) : (fp->refcnt = 0); 8651991Sheppo 866*6419Ssb155480 /* 867*6419Ssb155480 * Note: duplicate keys will be rejected by mod_hash. 868*6419Ssb155480 */ 869*6419Ssb155480 rv = mod_hash_insert(vnetp->fdb_hashp, (mod_hash_key_t)addr, 870*6419Ssb155480 (mod_hash_val_t)fp); 871*6419Ssb155480 if (rv != 0) { 872*6419Ssb155480 DWARN(vnetp, "Duplicate macaddr key(%lx)\n", addr); 873*6419Ssb155480 KMEM_FREE(fp); 874*6419Ssb155480 return; 8751991Sheppo } 8761991Sheppo 877*6419Ssb155480 if (type == VNET_VSWPORT) { 878*6419Ssb155480 /* Cache the fdb entry to vsw-port */ 879*6419Ssb155480 WRITE_ENTER(&vnetp->vsw_fp_rw); 880*6419Ssb155480 if (vnetp->vsw_fp == NULL) 881*6419Ssb155480 vnetp->vsw_fp = fp; 882*6419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 8832793Slm66018 } 8841991Sheppo } 8851991Sheppo 886*6419Ssb155480 /* 887*6419Ssb155480 * Remove an entry from fdb. 888*6419Ssb155480 */ 889*6419Ssb155480 void 890*6419Ssb155480 vnet_fdbe_del(vnet_t *vnetp, struct ether_addr *eaddr) 8915641Swentaoy { 892*6419Ssb155480 uint64_t addr = 0; 893*6419Ssb155480 vnet_fdbe_t *fp; 894*6419Ssb155480 int rv; 895*6419Ssb155480 uint32_t refcnt; 8965641Swentaoy 897*6419Ssb155480 KEY_HASH(addr, eaddr); 8985641Swentaoy 899*6419Ssb155480 /* 900*6419Ssb155480 * Remove the entry from fdb hash table. 901*6419Ssb155480 * This prevents further references to this fdb entry. 902*6419Ssb155480 */ 903*6419Ssb155480 rv = mod_hash_remove(vnetp->fdb_hashp, (mod_hash_key_t)addr, 904*6419Ssb155480 (mod_hash_val_t *)&fp); 905*6419Ssb155480 ASSERT(rv == 0); 9065641Swentaoy 907*6419Ssb155480 if (fp->type == VNET_VSWPORT) { 908*6419Ssb155480 WRITE_ENTER(&vnetp->vsw_fp_rw); 9095641Swentaoy 910*6419Ssb155480 ASSERT(fp == vnetp->vsw_fp); 911*6419Ssb155480 vnetp->vsw_fp = NULL; 912*6419Ssb155480 913*6419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 9145641Swentaoy } 9155641Swentaoy 9165641Swentaoy /* 917*6419Ssb155480 * If there are threads already ref holding before the entry was 918*6419Ssb155480 * removed from hash table, then wait for ref count to drop to zero. 9195641Swentaoy */ 920*6419Ssb155480 (fp->type == VNET_VSWPORT) ? (refcnt = 1) : (refcnt = 0); 921*6419Ssb155480 while (fp->refcnt > refcnt) { 922*6419Ssb155480 delay(drv_usectohz(vnet_fdbe_refcnt_delay)); 923*6419Ssb155480 } 924*6419Ssb155480 925*6419Ssb155480 kmem_free(fp, sizeof (*fp)); 9265641Swentaoy } 9275641Swentaoy 928*6419Ssb155480 /* 929*6419Ssb155480 * Modify the fdb entry for the given macaddr, 930*6419Ssb155480 * to use the specified port for transmits. 931*6419Ssb155480 */ 932*6419Ssb155480 void 933*6419Ssb155480 vnet_fdbe_modify(vnet_t *vnetp, struct ether_addr *macaddr, void *portp, 934*6419Ssb155480 boolean_t flag) 9351991Sheppo { 936*6419Ssb155480 vnet_fdbe_t *fp; 937*6419Ssb155480 uint64_t addr = 0; 938*6419Ssb155480 int rv; 939*6419Ssb155480 uint32_t refcnt; 9401991Sheppo 941*6419Ssb155480 KEY_HASH(addr, macaddr); 9421991Sheppo 943*6419Ssb155480 /* 944*6419Ssb155480 * Remove the entry from fdb hash table. 945*6419Ssb155480 * This prevents further references to this fdb entry. 946*6419Ssb155480 */ 947*6419Ssb155480 rv = mod_hash_remove(vnetp->fdb_hashp, (mod_hash_key_t)addr, 948*6419Ssb155480 (mod_hash_val_t *)&fp); 949*6419Ssb155480 ASSERT(rv == 0); 9501991Sheppo 951*6419Ssb155480 /* fdb entry of vsw port must never be modified */ 952*6419Ssb155480 ASSERT(fp->type == VNET_VNETPORT); 9531991Sheppo 9541991Sheppo /* 955*6419Ssb155480 * If there are threads already ref holding before the entry was 956*6419Ssb155480 * removed from hash table, then wait for reference count to drop to 957*6419Ssb155480 * zero. Note: flag indicates the context of caller. If we are in the 958*6419Ssb155480 * context of transmit routine, there is a reference held by the caller 959*6419Ssb155480 * too, in which case, wait for the refcnt to drop to 1. 9601991Sheppo */ 961*6419Ssb155480 (flag == B_TRUE) ? (refcnt = 1) : (refcnt = 0); 962*6419Ssb155480 while (fp->refcnt > refcnt) { 963*6419Ssb155480 delay(drv_usectohz(vnet_fdbe_refcnt_delay)); 9641991Sheppo } 965*6419Ssb155480 966*6419Ssb155480 /* update the portp in fdb entry with the new value */ 967*6419Ssb155480 fp->txarg = portp; 9681991Sheppo 969*6419Ssb155480 /* Reinsert the updated fdb entry into the table */ 970*6419Ssb155480 rv = mod_hash_insert(vnetp->fdb_hashp, (mod_hash_key_t)addr, 971*6419Ssb155480 (mod_hash_val_t)fp); 972*6419Ssb155480 ASSERT(rv == 0); 9731991Sheppo } 9741991Sheppo 975*6419Ssb155480 /* 976*6419Ssb155480 * Search fdb for a given mac address. If an entry is found, hold 977*6419Ssb155480 * a reference to it and return the entry; else returns NULL. 978*6419Ssb155480 */ 979*6419Ssb155480 static vnet_fdbe_t * 980*6419Ssb155480 vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp) 9811991Sheppo { 982*6419Ssb155480 uint64_t key = 0; 983*6419Ssb155480 vnet_fdbe_t *fp; 984*6419Ssb155480 int rv; 985*6419Ssb155480 986*6419Ssb155480 KEY_HASH(key, addrp); 987*6419Ssb155480 988*6419Ssb155480 rv = mod_hash_find_cb(vnetp->fdb_hashp, (mod_hash_key_t)key, 989*6419Ssb155480 (mod_hash_val_t *)&fp, vnet_fdbe_find_cb); 9901991Sheppo 991*6419Ssb155480 if (rv != 0) 992*6419Ssb155480 return (NULL); 9931991Sheppo 994*6419Ssb155480 return (fp); 995*6419Ssb155480 } 9961991Sheppo 997*6419Ssb155480 /* 998*6419Ssb155480 * Callback function provided to mod_hash_find_cb(). After finding the fdb 999*6419Ssb155480 * entry corresponding to the key (macaddr), this callback will be invoked by 1000*6419Ssb155480 * mod_hash_find_cb() to atomically increment the reference count on the fdb 1001*6419Ssb155480 * entry before returning the found entry. 1002*6419Ssb155480 */ 1003*6419Ssb155480 static void 1004*6419Ssb155480 vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val) 1005*6419Ssb155480 { 1006*6419Ssb155480 _NOTE(ARGUNUSED(key)) 1007*6419Ssb155480 VNET_FDBE_REFHOLD((vnet_fdbe_t *)val); 10081991Sheppo } 10092311Sseb 10102311Sseb void 10112311Sseb vnet_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp) 10122311Sseb { 10132311Sseb vnet_t *vnetp = arg; 10142311Sseb mac_rx(vnetp->mh, mrh, mp); 10152311Sseb } 10162311Sseb 10172311Sseb void 10182311Sseb vnet_tx_update(void *arg) 10192311Sseb { 10202311Sseb vnet_t *vnetp = arg; 10212311Sseb mac_tx_update(vnetp->mh); 10222311Sseb } 1023