11ae08745Sheppo /* 21ae08745Sheppo * CDDL HEADER START 31ae08745Sheppo * 41ae08745Sheppo * The contents of this file are subject to the terms of the 51ae08745Sheppo * Common Development and Distribution License (the "License"). 61ae08745Sheppo * You may not use this file except in compliance with the License. 71ae08745Sheppo * 81ae08745Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91ae08745Sheppo * or http://www.opensolaris.org/os/licensing. 101ae08745Sheppo * See the License for the specific language governing permissions 111ae08745Sheppo * and limitations under the License. 121ae08745Sheppo * 131ae08745Sheppo * When distributing Covered Code, include this CDDL HEADER in each 141ae08745Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151ae08745Sheppo * If applicable, add the following below this CDDL HEADER, with the 161ae08745Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 171ae08745Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 181ae08745Sheppo * 191ae08745Sheppo * CDDL HEADER END 201ae08745Sheppo */ 211ae08745Sheppo 221ae08745Sheppo /* 231ae08745Sheppo * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 241ae08745Sheppo * Use is subject to license terms. 251ae08745Sheppo */ 261ae08745Sheppo 271ae08745Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 281ae08745Sheppo 291ae08745Sheppo #include <sys/types.h> 301ae08745Sheppo #include <sys/errno.h> 311ae08745Sheppo #include <sys/param.h> 321ae08745Sheppo #include <sys/stream.h> 331ae08745Sheppo #include <sys/kmem.h> 341ae08745Sheppo #include <sys/conf.h> 351ae08745Sheppo #include <sys/devops.h> 361ae08745Sheppo #include <sys/ksynch.h> 371ae08745Sheppo #include <sys/stat.h> 381ae08745Sheppo #include <sys/modctl.h> 391ae08745Sheppo #include <sys/debug.h> 401ae08745Sheppo #include <sys/ethernet.h> 411ae08745Sheppo #include <sys/dlpi.h> 421ae08745Sheppo #include <net/if.h> 431ae08745Sheppo #include <sys/mac.h> 44ba2e4443Sseb #include <sys/mac_ether.h> 451ae08745Sheppo #include <sys/ddi.h> 461ae08745Sheppo #include <sys/sunddi.h> 471ae08745Sheppo #include <sys/strsun.h> 481ae08745Sheppo #include <sys/note.h> 491ae08745Sheppo #include <sys/vnet.h> 501ae08745Sheppo 511ae08745Sheppo /* 521ae08745Sheppo * Function prototypes. 531ae08745Sheppo */ 541ae08745Sheppo 551ae08745Sheppo /* DDI entrypoints */ 561ae08745Sheppo static int vnetdevinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 571ae08745Sheppo static int vnetattach(dev_info_t *, ddi_attach_cmd_t); 581ae08745Sheppo static int vnetdetach(dev_info_t *, ddi_detach_cmd_t); 591ae08745Sheppo 601ae08745Sheppo /* MAC entrypoints */ 61ba2e4443Sseb static int vnet_m_stat(void *, uint_t, uint64_t *); 621ae08745Sheppo static int vnet_m_start(void *); 631ae08745Sheppo static void vnet_m_stop(void *); 641ae08745Sheppo static int vnet_m_promisc(void *, boolean_t); 651ae08745Sheppo static int vnet_m_multicst(void *, boolean_t, const uint8_t *); 661ae08745Sheppo static int vnet_m_unicst(void *, const uint8_t *); 671ae08745Sheppo mblk_t *vnet_m_tx(void *, mblk_t *); 681ae08745Sheppo 691ae08745Sheppo /* vnet internal functions */ 701ae08745Sheppo static int vnet_mac_register(vnet_t *); 711ae08745Sheppo static int vnet_read_mac_address(vnet_t *vnetp); 721ae08745Sheppo static void vnet_add_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp); 731ae08745Sheppo static void vnet_del_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp); 741ae08745Sheppo static vp_tl_t *vnet_get_vptl(vnet_t *vnetp, const char *devname); 751ae08745Sheppo static fdb_t *vnet_lookup_fdb(fdb_fanout_t *fdbhp, uint8_t *macaddr); 761ae08745Sheppo 771ae08745Sheppo /* exported functions */ 781ae08745Sheppo void vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg); 791ae08745Sheppo void vnet_del_fdb(void *arg, uint8_t *macaddr); 80*3af08d82Slm66018 void vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, 81*3af08d82Slm66018 void *txarg, boolean_t upgrade); 821ae08745Sheppo void vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg); 831ae08745Sheppo void vnet_del_def_rte(void *arg); 84ba2e4443Sseb void vnet_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp); 85ba2e4443Sseb void vnet_tx_update(void *arg); 861ae08745Sheppo 871ae08745Sheppo /* externs */ 88ba2e4443Sseb extern int vgen_init(void *vnetp, dev_info_t *vnetdip, const uint8_t *macaddr, 89ba2e4443Sseb mac_register_t **vgenmacp); 90d10e4ef2Snarayan extern int vgen_uninit(void *arg); 911ae08745Sheppo 92ba2e4443Sseb static mac_callbacks_t vnet_m_callbacks = { 93ba2e4443Sseb 0, 94ba2e4443Sseb vnet_m_stat, 95ba2e4443Sseb vnet_m_start, 96ba2e4443Sseb vnet_m_stop, 97ba2e4443Sseb vnet_m_promisc, 98ba2e4443Sseb vnet_m_multicst, 99ba2e4443Sseb vnet_m_unicst, 100ba2e4443Sseb vnet_m_tx, 101ba2e4443Sseb NULL, 102ba2e4443Sseb NULL, 103ba2e4443Sseb NULL 104ba2e4443Sseb }; 105ba2e4443Sseb 1061ae08745Sheppo /* 1071ae08745Sheppo * Linked list of "vnet_t" structures - one per instance. 1081ae08745Sheppo */ 1091ae08745Sheppo static vnet_t *vnet_headp = NULL; 1101ae08745Sheppo static krwlock_t vnet_rw; 1111ae08745Sheppo 1121ae08745Sheppo /* Tunables */ 1131ae08745Sheppo uint32_t vnet_ntxds = VNET_NTXDS; /* power of 2 transmit descriptors */ 1141ae08745Sheppo uint32_t vnet_ldcwd_interval = VNET_LDCWD_INTERVAL; /* watchdog freq in msec */ 1151ae08745Sheppo uint32_t vnet_ldcwd_txtimeout = VNET_LDCWD_TXTIMEOUT; /* tx timeout in msec */ 116e1ebb9ecSlm66018 uint32_t vnet_ldc_mtu = VNET_LDC_MTU; /* ldc mtu */ 1171ae08745Sheppo uint32_t vnet_nfdb_hash = VNET_NFDB_HASH; /* size of fdb hash table */ 118d10e4ef2Snarayan uint32_t vnet_nrbufs = VNET_NRBUFS; /* number of receive buffers */ 1191ae08745Sheppo 1201ae08745Sheppo /* 1211ae08745Sheppo * Property names 1221ae08745Sheppo */ 1231ae08745Sheppo static char macaddr_propname[] = "local-mac-address"; 1241ae08745Sheppo 1251ae08745Sheppo /* 1261ae08745Sheppo * This is the string displayed by modinfo(1m). 1271ae08745Sheppo */ 1288e6a2a04Slm66018 static char vnet_ident[] = "vnet driver v%I%"; 1291ae08745Sheppo extern struct mod_ops mod_driverops; 1301ae08745Sheppo static struct cb_ops cb_vnetops = { 1311ae08745Sheppo nulldev, /* cb_open */ 1321ae08745Sheppo nulldev, /* cb_close */ 1331ae08745Sheppo nodev, /* cb_strategy */ 1341ae08745Sheppo nodev, /* cb_print */ 1351ae08745Sheppo nodev, /* cb_dump */ 1361ae08745Sheppo nodev, /* cb_read */ 1371ae08745Sheppo nodev, /* cb_write */ 1381ae08745Sheppo nodev, /* cb_ioctl */ 1391ae08745Sheppo nodev, /* cb_devmap */ 1401ae08745Sheppo nodev, /* cb_mmap */ 1411ae08745Sheppo nodev, /* cb_segmap */ 1421ae08745Sheppo nochpoll, /* cb_chpoll */ 1431ae08745Sheppo ddi_prop_op, /* cb_prop_op */ 1441ae08745Sheppo NULL, /* cb_stream */ 1451ae08745Sheppo (int)(D_MP) /* cb_flag */ 1461ae08745Sheppo }; 1471ae08745Sheppo 1481ae08745Sheppo static struct dev_ops vnetops = { 1491ae08745Sheppo DEVO_REV, /* devo_rev */ 1501ae08745Sheppo 0, /* devo_refcnt */ 1511ae08745Sheppo NULL, /* devo_getinfo */ 1521ae08745Sheppo nulldev, /* devo_identify */ 1531ae08745Sheppo nulldev, /* devo_probe */ 1541ae08745Sheppo vnetattach, /* devo_attach */ 1551ae08745Sheppo vnetdetach, /* devo_detach */ 1561ae08745Sheppo nodev, /* devo_reset */ 1571ae08745Sheppo &cb_vnetops, /* devo_cb_ops */ 1581ae08745Sheppo (struct bus_ops *)NULL /* devo_bus_ops */ 1591ae08745Sheppo }; 1601ae08745Sheppo 1611ae08745Sheppo static struct modldrv modldrv = { 1621ae08745Sheppo &mod_driverops, /* Type of module. This one is a driver */ 1631ae08745Sheppo vnet_ident, /* ID string */ 1641ae08745Sheppo &vnetops /* driver specific ops */ 1651ae08745Sheppo }; 1661ae08745Sheppo 1671ae08745Sheppo static struct modlinkage modlinkage = { 1681ae08745Sheppo MODREV_1, (void *)&modldrv, NULL 1691ae08745Sheppo }; 1701ae08745Sheppo 1711ae08745Sheppo 1721ae08745Sheppo /* 1731ae08745Sheppo * Print debug messages - set to 0xf to enable all msgs 1741ae08745Sheppo */ 1751ae08745Sheppo int _vnet_dbglevel = 0x8; 1761ae08745Sheppo 1771ae08745Sheppo void 1781ae08745Sheppo _vnetdebug_printf(void *arg, const char *fmt, ...) 1791ae08745Sheppo { 1801ae08745Sheppo char buf[512]; 1811ae08745Sheppo va_list ap; 1821ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 1831ae08745Sheppo 1841ae08745Sheppo va_start(ap, fmt); 1851ae08745Sheppo (void) vsprintf(buf, fmt, ap); 1861ae08745Sheppo va_end(ap); 1871ae08745Sheppo 1881ae08745Sheppo if (vnetp == NULL) 1891ae08745Sheppo cmn_err(CE_CONT, "%s\n", buf); 1901ae08745Sheppo else 1911ae08745Sheppo cmn_err(CE_CONT, "vnet%d: %s\n", vnetp->instance, buf); 1921ae08745Sheppo } 1931ae08745Sheppo 1941ae08745Sheppo #ifdef DEBUG 1951ae08745Sheppo 1961ae08745Sheppo /* 197*3af08d82Slm66018 * NOTE: any changes to the definitions below need corresponding changes in 1981ae08745Sheppo * vnet_gen.c 1991ae08745Sheppo */ 2001ae08745Sheppo 2011ae08745Sheppo /* 2021ae08745Sheppo * debug levels: 2031ae08745Sheppo * DBG_LEVEL1: Function entry/exit tracing 2041ae08745Sheppo * DBG_LEVEL2: Info messages 2051ae08745Sheppo * DBG_LEVEL3: Warning messages 2061ae08745Sheppo * DBG_LEVEL4: Error messages 2071ae08745Sheppo */ 2081ae08745Sheppo 2091ae08745Sheppo enum { DBG_LEVEL1 = 0x01, DBG_LEVEL2 = 0x02, DBG_LEVEL3 = 0x04, 2101ae08745Sheppo DBG_LEVEL4 = 0x08 }; 2111ae08745Sheppo 2121ae08745Sheppo #define DBG1(_s) do { \ 2131ae08745Sheppo if ((_vnet_dbglevel & DBG_LEVEL1) != 0) { \ 2141ae08745Sheppo _vnetdebug_printf _s; \ 2151ae08745Sheppo } \ 2161ae08745Sheppo _NOTE(CONSTCOND) } while (0) 2171ae08745Sheppo 2181ae08745Sheppo #define DBG2(_s) do { \ 2191ae08745Sheppo if ((_vnet_dbglevel & DBG_LEVEL2) != 0) { \ 2201ae08745Sheppo _vnetdebug_printf _s; \ 2211ae08745Sheppo } \ 2221ae08745Sheppo _NOTE(CONSTCOND) } while (0) 2231ae08745Sheppo 2241ae08745Sheppo #define DWARN(_s) do { \ 2251ae08745Sheppo if ((_vnet_dbglevel & DBG_LEVEL3) != 0) { \ 2261ae08745Sheppo _vnetdebug_printf _s; \ 2271ae08745Sheppo } \ 2281ae08745Sheppo _NOTE(CONSTCOND) } while (0) 2291ae08745Sheppo 2301ae08745Sheppo #define DERR(_s) do { \ 2311ae08745Sheppo if ((_vnet_dbglevel & DBG_LEVEL4) != 0) { \ 2321ae08745Sheppo _vnetdebug_printf _s; \ 2331ae08745Sheppo } \ 2341ae08745Sheppo _NOTE(CONSTCOND) } while (0) 2351ae08745Sheppo 2361ae08745Sheppo #else 2371ae08745Sheppo 2381ae08745Sheppo #define DBG1(_s) if (0) _vnetdebug_printf _s 2391ae08745Sheppo #define DBG2(_s) if (0) _vnetdebug_printf _s 2401ae08745Sheppo #define DWARN(_s) if (0) _vnetdebug_printf _s 2411ae08745Sheppo #define DERR(_s) if (0) _vnetdebug_printf _s 2421ae08745Sheppo 2431ae08745Sheppo #endif 2441ae08745Sheppo 2451ae08745Sheppo /* _init(9E): initialize the loadable module */ 2461ae08745Sheppo int 2471ae08745Sheppo _init(void) 2481ae08745Sheppo { 2491ae08745Sheppo int status; 2501ae08745Sheppo 2511ae08745Sheppo DBG1((NULL, "_init: enter\n")); 2521ae08745Sheppo 2531ae08745Sheppo mac_init_ops(&vnetops, "vnet"); 2541ae08745Sheppo status = mod_install(&modlinkage); 2551ae08745Sheppo if (status != 0) { 2561ae08745Sheppo mac_fini_ops(&vnetops); 2571ae08745Sheppo } 2581ae08745Sheppo 2591ae08745Sheppo DBG1((NULL, "_init: exit\n")); 2601ae08745Sheppo return (status); 2611ae08745Sheppo } 2621ae08745Sheppo 2631ae08745Sheppo /* _fini(9E): prepare the module for unloading. */ 2641ae08745Sheppo int 2651ae08745Sheppo _fini(void) 2661ae08745Sheppo { 2671ae08745Sheppo int status; 2681ae08745Sheppo 2691ae08745Sheppo DBG1((NULL, "_fini: enter\n")); 2701ae08745Sheppo 2711ae08745Sheppo status = mod_remove(&modlinkage); 2721ae08745Sheppo if (status != 0) 2731ae08745Sheppo return (status); 2741ae08745Sheppo mac_fini_ops(&vnetops); 2751ae08745Sheppo 2761ae08745Sheppo DBG1((NULL, "_fini: exit\n")); 2771ae08745Sheppo return (status); 2781ae08745Sheppo } 2791ae08745Sheppo 2801ae08745Sheppo /* _info(9E): return information about the loadable module */ 2811ae08745Sheppo int 2821ae08745Sheppo _info(struct modinfo *modinfop) 2831ae08745Sheppo { 2841ae08745Sheppo return (mod_info(&modlinkage, modinfop)); 2851ae08745Sheppo } 2861ae08745Sheppo 2871ae08745Sheppo /* 2881ae08745Sheppo * attach(9E): attach a device to the system. 2891ae08745Sheppo * called once for each instance of the device on the system. 2901ae08745Sheppo */ 2911ae08745Sheppo static int 2921ae08745Sheppo vnetattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2931ae08745Sheppo { 2941ae08745Sheppo vnet_t *vnetp; 2951ae08745Sheppo vp_tl_t *vp_tlp; 2961ae08745Sheppo int instance; 2971ae08745Sheppo int status; 2981ae08745Sheppo enum { AST_init = 0x0, AST_vnet_alloc = 0x1, 299d10e4ef2Snarayan AST_mac_alloc = 0x2, AST_read_macaddr = 0x4, 300d10e4ef2Snarayan AST_vgen_init = 0x8, AST_vptl_alloc = 0x10, 301d10e4ef2Snarayan AST_fdbh_alloc = 0x20 } 3021ae08745Sheppo attach_state; 303ba2e4443Sseb mac_register_t *vgenmacp = NULL; 3041ae08745Sheppo uint32_t nfdbh = 0; 3051ae08745Sheppo 3061ae08745Sheppo attach_state = AST_init; 3071ae08745Sheppo 3081ae08745Sheppo switch (cmd) { 3091ae08745Sheppo case DDI_ATTACH: 3101ae08745Sheppo break; 3111ae08745Sheppo case DDI_RESUME: 3121ae08745Sheppo case DDI_PM_RESUME: 3131ae08745Sheppo default: 3141ae08745Sheppo goto vnet_attach_fail; 3151ae08745Sheppo } 3161ae08745Sheppo 3171ae08745Sheppo instance = ddi_get_instance(dip); 3181ae08745Sheppo DBG1((NULL, "vnetattach: instance(%d) enter\n", instance)); 3191ae08745Sheppo 3201ae08745Sheppo /* allocate vnet_t and mac_t structures */ 3211ae08745Sheppo vnetp = kmem_zalloc(sizeof (vnet_t), KM_SLEEP); 3221ae08745Sheppo attach_state |= AST_vnet_alloc; 3231ae08745Sheppo 3241ae08745Sheppo /* setup links to vnet_t from both devinfo and mac_t */ 3251ae08745Sheppo ddi_set_driver_private(dip, (caddr_t)vnetp); 3261ae08745Sheppo vnetp->dip = dip; 3271ae08745Sheppo vnetp->instance = instance; 3281ae08745Sheppo 3291ae08745Sheppo /* read the mac address */ 3301ae08745Sheppo status = vnet_read_mac_address(vnetp); 3311ae08745Sheppo if (status != DDI_SUCCESS) { 3321ae08745Sheppo goto vnet_attach_fail; 3331ae08745Sheppo } 3341ae08745Sheppo attach_state |= AST_read_macaddr; 3351ae08745Sheppo 3361ae08745Sheppo /* 3371ae08745Sheppo * Initialize the generic vnet proxy transport. This is the first 3381ae08745Sheppo * and default transport used by vnet. The generic transport 3391ae08745Sheppo * is provided by using sun4v LDC (logical domain channel). On success, 3401ae08745Sheppo * vgen_init() provides a pointer to mac_t of generic transport. 3411ae08745Sheppo * Currently, this generic layer provides network connectivity to other 3421ae08745Sheppo * vnets within ldoms and also to remote hosts oustide ldoms through 3431ae08745Sheppo * the virtual switch (vsw) device on domain0. In the future, when 3441ae08745Sheppo * physical adapters that are able to share their resources (such as 3451ae08745Sheppo * dma channels) with guest domains become available, the vnet device 3461ae08745Sheppo * will use hardware specific driver to communicate directly over the 3471ae08745Sheppo * physical device to reach remote hosts without going through vswitch. 3481ae08745Sheppo */ 349ba2e4443Sseb status = vgen_init(vnetp, vnetp->dip, (uint8_t *)vnetp->curr_macaddr, 350ba2e4443Sseb &vgenmacp); 3511ae08745Sheppo if (status != DDI_SUCCESS) { 3521ae08745Sheppo DERR((vnetp, "vgen_init() failed\n")); 3531ae08745Sheppo goto vnet_attach_fail; 3541ae08745Sheppo } 3551ae08745Sheppo attach_state |= AST_vgen_init; 3561ae08745Sheppo 3571ae08745Sheppo vp_tlp = kmem_zalloc(sizeof (vp_tl_t), KM_SLEEP); 3581ae08745Sheppo vp_tlp->macp = vgenmacp; 3591ae08745Sheppo (void) snprintf(vp_tlp->name, MAXNAMELEN, "%s%u", "vgen", instance); 3601ae08745Sheppo (void) strcpy(vnetp->vgen_name, vp_tlp->name); 3611ae08745Sheppo 3621ae08745Sheppo /* add generic transport to the list of vnet proxy transports */ 3631ae08745Sheppo vnet_add_vptl(vnetp, vp_tlp); 3641ae08745Sheppo attach_state |= AST_vptl_alloc; 3651ae08745Sheppo 3661ae08745Sheppo nfdbh = vnet_nfdb_hash; 3671ae08745Sheppo if ((nfdbh < VNET_NFDB_HASH) || (nfdbh > VNET_NFDB_HASH_MAX)) { 3681ae08745Sheppo vnetp->nfdb_hash = VNET_NFDB_HASH; 3691ae08745Sheppo } 3701ae08745Sheppo else 3711ae08745Sheppo vnetp->nfdb_hash = nfdbh; 3721ae08745Sheppo 3731ae08745Sheppo /* allocate fdb hash table, with an extra slot for default route */ 3741ae08745Sheppo vnetp->fdbhp = kmem_zalloc(sizeof (fdb_fanout_t) * 3751ae08745Sheppo (vnetp->nfdb_hash + 1), KM_SLEEP); 3761ae08745Sheppo attach_state |= AST_fdbh_alloc; 3771ae08745Sheppo 3781ae08745Sheppo /* register with MAC layer */ 3791ae08745Sheppo status = vnet_mac_register(vnetp); 3801ae08745Sheppo if (status != DDI_SUCCESS) { 3811ae08745Sheppo goto vnet_attach_fail; 3821ae08745Sheppo } 3831ae08745Sheppo 3841ae08745Sheppo /* add to the list of vnet devices */ 3851ae08745Sheppo WRITE_ENTER(&vnet_rw); 3861ae08745Sheppo vnetp->nextp = vnet_headp; 3871ae08745Sheppo vnet_headp = vnetp; 3881ae08745Sheppo RW_EXIT(&vnet_rw); 3891ae08745Sheppo 3901ae08745Sheppo DBG1((NULL, "vnetattach: instance(%d) exit\n", instance)); 3911ae08745Sheppo return (DDI_SUCCESS); 3921ae08745Sheppo 3931ae08745Sheppo vnet_attach_fail: 3941ae08745Sheppo if (attach_state & AST_fdbh_alloc) { 3951ae08745Sheppo kmem_free(vnetp->fdbhp, 3961ae08745Sheppo sizeof (fdb_fanout_t) * (vnetp->nfdb_hash + 1)); 3971ae08745Sheppo } 3981ae08745Sheppo if (attach_state & AST_vptl_alloc) { 3991ae08745Sheppo WRITE_ENTER(&vnetp->trwlock); 4001ae08745Sheppo vnet_del_vptl(vnetp, vp_tlp); 4011ae08745Sheppo RW_EXIT(&vnetp->trwlock); 4021ae08745Sheppo } 4031ae08745Sheppo if (attach_state & AST_vgen_init) { 404d10e4ef2Snarayan (void) vgen_uninit(vgenmacp->m_driver); 4051ae08745Sheppo } 4061ae08745Sheppo if (attach_state & AST_vnet_alloc) { 4071ae08745Sheppo KMEM_FREE(vnetp); 4081ae08745Sheppo } 4091ae08745Sheppo return (DDI_FAILURE); 4101ae08745Sheppo } 4111ae08745Sheppo 4121ae08745Sheppo /* 4131ae08745Sheppo * detach(9E): detach a device from the system. 4141ae08745Sheppo */ 4151ae08745Sheppo static int 4161ae08745Sheppo vnetdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4171ae08745Sheppo { 4181ae08745Sheppo vnet_t *vnetp; 4191ae08745Sheppo vnet_t **vnetpp; 4201ae08745Sheppo vp_tl_t *vp_tlp; 4211ae08745Sheppo int instance; 422d10e4ef2Snarayan int rv; 4231ae08745Sheppo 4241ae08745Sheppo instance = ddi_get_instance(dip); 4251ae08745Sheppo DBG1((NULL, "vnetdetach: instance(%d) enter\n", instance)); 4261ae08745Sheppo 4271ae08745Sheppo vnetp = ddi_get_driver_private(dip); 4281ae08745Sheppo if (vnetp == NULL) { 4291ae08745Sheppo goto vnet_detach_fail; 4301ae08745Sheppo } 4311ae08745Sheppo 4321ae08745Sheppo switch (cmd) { 4331ae08745Sheppo case DDI_DETACH: 4341ae08745Sheppo break; 4351ae08745Sheppo case DDI_SUSPEND: 4361ae08745Sheppo case DDI_PM_SUSPEND: 4371ae08745Sheppo default: 4381ae08745Sheppo goto vnet_detach_fail; 4391ae08745Sheppo } 4401ae08745Sheppo 441d10e4ef2Snarayan /* uninit and free vnet proxy transports */ 442d10e4ef2Snarayan WRITE_ENTER(&vnetp->trwlock); 443d10e4ef2Snarayan while ((vp_tlp = vnetp->tlp) != NULL) { 444d10e4ef2Snarayan if (strcmp(vnetp->vgen_name, vp_tlp->name) == 0) { 445d10e4ef2Snarayan /* uninitialize generic transport */ 446d10e4ef2Snarayan rv = vgen_uninit(vp_tlp->macp->m_driver); 447d10e4ef2Snarayan if (rv != DDI_SUCCESS) { 448d10e4ef2Snarayan RW_EXIT(&vnetp->trwlock); 449d10e4ef2Snarayan goto vnet_detach_fail; 450d10e4ef2Snarayan } 451d10e4ef2Snarayan } 452d10e4ef2Snarayan vnet_del_vptl(vnetp, vp_tlp); 453d10e4ef2Snarayan } 454d10e4ef2Snarayan RW_EXIT(&vnetp->trwlock); 455d10e4ef2Snarayan 4561ae08745Sheppo /* 4571ae08745Sheppo * Unregister from the MAC subsystem. This can fail, in 4581ae08745Sheppo * particular if there are DLPI style-2 streams still open - 4591ae08745Sheppo * in which case we just return failure. 4601ae08745Sheppo */ 461ba2e4443Sseb if (mac_unregister(vnetp->mh) != 0) 4621ae08745Sheppo goto vnet_detach_fail; 4631ae08745Sheppo 4641ae08745Sheppo /* unlink from instance(vnet_t) list */ 4651ae08745Sheppo WRITE_ENTER(&vnet_rw); 4661ae08745Sheppo for (vnetpp = &vnet_headp; *vnetpp; vnetpp = &(*vnetpp)->nextp) { 4671ae08745Sheppo if (*vnetpp == vnetp) { 4681ae08745Sheppo *vnetpp = vnetp->nextp; 4691ae08745Sheppo break; 4701ae08745Sheppo } 4711ae08745Sheppo } 4721ae08745Sheppo RW_EXIT(&vnet_rw); 4731ae08745Sheppo 4741ae08745Sheppo KMEM_FREE(vnetp); 4751ae08745Sheppo 4761ae08745Sheppo return (DDI_SUCCESS); 4771ae08745Sheppo 4781ae08745Sheppo vnet_detach_fail: 4791ae08745Sheppo return (DDI_FAILURE); 4801ae08745Sheppo } 4811ae08745Sheppo 4821ae08745Sheppo /* enable the device for transmit/receive */ 4831ae08745Sheppo static int 4841ae08745Sheppo vnet_m_start(void *arg) 4851ae08745Sheppo { 4861ae08745Sheppo vnet_t *vnetp = arg; 4871ae08745Sheppo vp_tl_t *vp_tlp; 488ba2e4443Sseb mac_register_t *vp_macp; 489ba2e4443Sseb mac_callbacks_t *cbp; 4901ae08745Sheppo 4911ae08745Sheppo DBG1((vnetp, "vnet_m_start: enter\n")); 4921ae08745Sheppo 4931ae08745Sheppo /* 494*3af08d82Slm66018 * NOTE: 4951ae08745Sheppo * Currently, we only have generic transport. m_start() invokes 4961ae08745Sheppo * vgen_start() which enables ports/channels in vgen and 4971ae08745Sheppo * initiates handshake with peer vnets and vsw. In the future when we 4981ae08745Sheppo * have support for hardware specific transports, this information 4991ae08745Sheppo * needs to be propagted back to vnet from vgen and we need to revisit 5001ae08745Sheppo * this code (see comments in vnet_attach()). 5011ae08745Sheppo * 5021ae08745Sheppo */ 5031ae08745Sheppo WRITE_ENTER(&vnetp->trwlock); 5041ae08745Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 5051ae08745Sheppo vp_macp = vp_tlp->macp; 506ba2e4443Sseb cbp = vp_macp->m_callbacks; 507ba2e4443Sseb cbp->mc_start(vp_macp->m_driver); 5081ae08745Sheppo } 5091ae08745Sheppo RW_EXIT(&vnetp->trwlock); 5101ae08745Sheppo 5111ae08745Sheppo DBG1((vnetp, "vnet_m_start: exit\n")); 5121ae08745Sheppo return (VNET_SUCCESS); 5131ae08745Sheppo 5141ae08745Sheppo } 5151ae08745Sheppo 5161ae08745Sheppo /* stop transmit/receive for the device */ 5171ae08745Sheppo static void 5181ae08745Sheppo vnet_m_stop(void *arg) 5191ae08745Sheppo { 5201ae08745Sheppo vnet_t *vnetp = arg; 5211ae08745Sheppo vp_tl_t *vp_tlp; 522ba2e4443Sseb mac_register_t *vp_macp; 523ba2e4443Sseb mac_callbacks_t *cbp; 5241ae08745Sheppo 5251ae08745Sheppo DBG1((vnetp, "vnet_m_stop: enter\n")); 5261ae08745Sheppo 5271ae08745Sheppo WRITE_ENTER(&vnetp->trwlock); 5281ae08745Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 5291ae08745Sheppo vp_macp = vp_tlp->macp; 530ba2e4443Sseb cbp = vp_macp->m_callbacks; 531ba2e4443Sseb cbp->mc_stop(vp_macp->m_driver); 5321ae08745Sheppo } 5331ae08745Sheppo RW_EXIT(&vnetp->trwlock); 5341ae08745Sheppo 5351ae08745Sheppo DBG1((vnetp, "vnet_m_stop: exit\n")); 5361ae08745Sheppo } 5371ae08745Sheppo 5381ae08745Sheppo /* set the unicast mac address of the device */ 5391ae08745Sheppo static int 5401ae08745Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr) 5411ae08745Sheppo { 5421ae08745Sheppo _NOTE(ARGUNUSED(macaddr)) 5431ae08745Sheppo 5441ae08745Sheppo vnet_t *vnetp = arg; 5451ae08745Sheppo 5461ae08745Sheppo DBG1((vnetp, "vnet_m_unicst: enter\n")); 5471ae08745Sheppo /* 548*3af08d82Slm66018 * NOTE: setting mac address dynamically is not supported. 5491ae08745Sheppo */ 5501ae08745Sheppo DBG1((vnetp, "vnet_m_unicst: exit\n")); 5511ae08745Sheppo 5528e6a2a04Slm66018 return (VNET_FAILURE); 5531ae08745Sheppo } 5541ae08745Sheppo 5551ae08745Sheppo /* enable/disable a multicast address */ 5561ae08745Sheppo static int 5571ae08745Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 5581ae08745Sheppo { 5591ae08745Sheppo _NOTE(ARGUNUSED(add, mca)) 5601ae08745Sheppo 5611ae08745Sheppo vnet_t *vnetp = arg; 5621ae08745Sheppo vp_tl_t *vp_tlp; 563ba2e4443Sseb mac_register_t *vp_macp; 564ba2e4443Sseb mac_callbacks_t *cbp; 5651ae08745Sheppo int rv = VNET_SUCCESS; 5661ae08745Sheppo 5671ae08745Sheppo DBG1((vnetp, "vnet_m_multicst: enter\n")); 5681ae08745Sheppo READ_ENTER(&vnetp->trwlock); 5691ae08745Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 5701ae08745Sheppo if (strcmp(vnetp->vgen_name, vp_tlp->name) == 0) { 5711ae08745Sheppo vp_macp = vp_tlp->macp; 572ba2e4443Sseb cbp = vp_macp->m_callbacks; 573ba2e4443Sseb rv = cbp->mc_multicst(vp_macp->m_driver, add, mca); 5741ae08745Sheppo break; 5751ae08745Sheppo } 5761ae08745Sheppo } 5771ae08745Sheppo RW_EXIT(&vnetp->trwlock); 5781ae08745Sheppo DBG1((vnetp, "vnet_m_multicst: exit\n")); 5791ae08745Sheppo return (rv); 5801ae08745Sheppo } 5811ae08745Sheppo 5821ae08745Sheppo /* set or clear promiscuous mode on the device */ 5831ae08745Sheppo static int 5841ae08745Sheppo vnet_m_promisc(void *arg, boolean_t on) 5851ae08745Sheppo { 5861ae08745Sheppo _NOTE(ARGUNUSED(on)) 5871ae08745Sheppo 5881ae08745Sheppo vnet_t *vnetp = arg; 5891ae08745Sheppo DBG1((vnetp, "vnet_m_promisc: enter\n")); 5901ae08745Sheppo /* 591*3af08d82Slm66018 * NOTE: setting promiscuous mode is not supported, just return success. 5921ae08745Sheppo */ 5931ae08745Sheppo DBG1((vnetp, "vnet_m_promisc: exit\n")); 5941ae08745Sheppo return (VNET_SUCCESS); 5951ae08745Sheppo } 5961ae08745Sheppo 5971ae08745Sheppo /* 5981ae08745Sheppo * Transmit a chain of packets. This function provides switching functionality 5991ae08745Sheppo * based on the destination mac address to reach other guests (within ldoms) or 6001ae08745Sheppo * external hosts. 6011ae08745Sheppo */ 6021ae08745Sheppo mblk_t * 6031ae08745Sheppo vnet_m_tx(void *arg, mblk_t *mp) 6041ae08745Sheppo { 6051ae08745Sheppo vnet_t *vnetp; 6061ae08745Sheppo mblk_t *next; 6071ae08745Sheppo uint32_t fdbhash; 6081ae08745Sheppo fdb_t *fdbp; 6091ae08745Sheppo fdb_fanout_t *fdbhp; 6101ae08745Sheppo struct ether_header *ehp; 6111ae08745Sheppo uint8_t *macaddr; 6121ae08745Sheppo mblk_t *resid_mp; 6131ae08745Sheppo 6141ae08745Sheppo vnetp = (vnet_t *)arg; 6151ae08745Sheppo DBG1((vnetp, "vnet_m_tx: enter\n")); 6161ae08745Sheppo ASSERT(mp != NULL); 6171ae08745Sheppo 6181ae08745Sheppo while (mp != NULL) { 6191ae08745Sheppo next = mp->b_next; 6201ae08745Sheppo mp->b_next = NULL; 6211ae08745Sheppo 6221ae08745Sheppo /* get the destination mac address in the eth header */ 6231ae08745Sheppo ehp = (struct ether_header *)mp->b_rptr; 6241ae08745Sheppo macaddr = (uint8_t *)&ehp->ether_dhost; 6251ae08745Sheppo 6261ae08745Sheppo /* Calculate hash value and fdb fanout */ 6271ae08745Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 6281ae08745Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 6291ae08745Sheppo 6301ae08745Sheppo READ_ENTER(&fdbhp->rwlock); 6311ae08745Sheppo fdbp = vnet_lookup_fdb(fdbhp, macaddr); 6321ae08745Sheppo if (fdbp) { 6331ae08745Sheppo /* 6341ae08745Sheppo * If the destination is in FDB, the destination is 6351ae08745Sheppo * a vnet device within ldoms and directly reachable, 6361ae08745Sheppo * invoke the tx function in the fdb entry. 6371ae08745Sheppo */ 6381ae08745Sheppo resid_mp = fdbp->m_tx(fdbp->txarg, mp); 6391ae08745Sheppo if (resid_mp != NULL) { 6401ae08745Sheppo /* m_tx failed */ 6411ae08745Sheppo mp->b_next = next; 6421ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 6431ae08745Sheppo break; 6441ae08745Sheppo } 6451ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 6461ae08745Sheppo } else { 6471ae08745Sheppo /* destination is not in FDB */ 6481ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 6491ae08745Sheppo /* 6501ae08745Sheppo * If the destination is broadcast/multicast 6511ae08745Sheppo * or an unknown unicast address, forward the 6521ae08745Sheppo * packet to vsw, using the last slot in fdb which is 6531ae08745Sheppo * reserved for default route. 6541ae08745Sheppo */ 6551ae08745Sheppo fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]); 6561ae08745Sheppo READ_ENTER(&fdbhp->rwlock); 6571ae08745Sheppo fdbp = fdbhp->headp; 6581ae08745Sheppo if (fdbp) { 6591ae08745Sheppo resid_mp = fdbp->m_tx(fdbp->txarg, mp); 6601ae08745Sheppo if (resid_mp != NULL) { 6611ae08745Sheppo /* m_tx failed */ 6621ae08745Sheppo mp->b_next = next; 6631ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 6641ae08745Sheppo break; 6651ae08745Sheppo } 6661ae08745Sheppo } else { 6671ae08745Sheppo /* drop the packet */ 6681ae08745Sheppo freemsg(mp); 6691ae08745Sheppo } 6701ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 6711ae08745Sheppo } 6721ae08745Sheppo 6731ae08745Sheppo mp = next; 6741ae08745Sheppo } 6751ae08745Sheppo 6761ae08745Sheppo DBG1((vnetp, "vnet_m_tx: exit\n")); 6771ae08745Sheppo return (mp); 6781ae08745Sheppo } 6791ae08745Sheppo 6801ae08745Sheppo /* get statistics from the device */ 681ba2e4443Sseb int 682ba2e4443Sseb vnet_m_stat(void *arg, uint_t stat, uint64_t *val) 6831ae08745Sheppo { 6841ae08745Sheppo vnet_t *vnetp = arg; 6851ae08745Sheppo vp_tl_t *vp_tlp; 686ba2e4443Sseb mac_register_t *vp_macp; 687ba2e4443Sseb mac_callbacks_t *cbp; 688ba2e4443Sseb uint64_t val_total = 0; 6891ae08745Sheppo 6901ae08745Sheppo DBG1((vnetp, "vnet_m_stat: enter\n")); 6911ae08745Sheppo 6921ae08745Sheppo /* 693ba2e4443Sseb * get the specified statistic from each transport and return the 694ba2e4443Sseb * aggregate val. This obviously only works for counters. 6951ae08745Sheppo */ 696ba2e4443Sseb if ((IS_MAC_STAT(stat) && !MAC_STAT_ISACOUNTER(stat)) || 697ba2e4443Sseb (IS_MACTYPE_STAT(stat) && !ETHER_STAT_ISACOUNTER(stat))) { 698ba2e4443Sseb return (ENOTSUP); 699ba2e4443Sseb } 7001ae08745Sheppo READ_ENTER(&vnetp->trwlock); 7011ae08745Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 7021ae08745Sheppo vp_macp = vp_tlp->macp; 703ba2e4443Sseb cbp = vp_macp->m_callbacks; 704ba2e4443Sseb if (cbp->mc_getstat(vp_macp->m_driver, stat, val) == 0) 705ba2e4443Sseb val_total += *val; 7061ae08745Sheppo } 7071ae08745Sheppo RW_EXIT(&vnetp->trwlock); 7081ae08745Sheppo 709ba2e4443Sseb *val = val_total; 710ba2e4443Sseb 7111ae08745Sheppo DBG1((vnetp, "vnet_m_stat: exit\n")); 712ba2e4443Sseb return (0); 7131ae08745Sheppo } 7141ae08745Sheppo 7151ae08745Sheppo /* wrapper function for mac_register() */ 7161ae08745Sheppo static int 7171ae08745Sheppo vnet_mac_register(vnet_t *vnetp) 7181ae08745Sheppo { 719ba2e4443Sseb mac_register_t *macp; 720ba2e4443Sseb int err; 7211ae08745Sheppo 722ba2e4443Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 723ba2e4443Sseb return (DDI_FAILURE); 724ba2e4443Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 725ba2e4443Sseb macp->m_driver = vnetp; 7261ae08745Sheppo macp->m_dip = vnetp->dip; 727ba2e4443Sseb macp->m_src_addr = vnetp->curr_macaddr; 728ba2e4443Sseb macp->m_callbacks = &vnet_m_callbacks; 729ba2e4443Sseb macp->m_min_sdu = 0; 730ba2e4443Sseb macp->m_max_sdu = ETHERMTU; 7311ae08745Sheppo 7321ae08745Sheppo /* 7331ae08745Sheppo * Finally, we're ready to register ourselves with the MAC layer 7341ae08745Sheppo * interface; if this succeeds, we're all ready to start() 7351ae08745Sheppo */ 736ba2e4443Sseb err = mac_register(macp, &vnetp->mh); 737ba2e4443Sseb mac_free(macp); 738ba2e4443Sseb return (err == 0 ? DDI_SUCCESS : DDI_FAILURE); 7391ae08745Sheppo } 7401ae08745Sheppo 7411ae08745Sheppo /* add vp_tl to the list */ 7421ae08745Sheppo static void 7431ae08745Sheppo vnet_add_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp) 7441ae08745Sheppo { 7451ae08745Sheppo vp_tl_t *ttlp; 7461ae08745Sheppo 7471ae08745Sheppo WRITE_ENTER(&vnetp->trwlock); 7481ae08745Sheppo if (vnetp->tlp == NULL) { 7491ae08745Sheppo vnetp->tlp = vp_tlp; 7501ae08745Sheppo } else { 7511ae08745Sheppo ttlp = vnetp->tlp; 7521ae08745Sheppo while (ttlp->nextp) 7531ae08745Sheppo ttlp = ttlp->nextp; 7541ae08745Sheppo ttlp->nextp = vp_tlp; 7551ae08745Sheppo } 7561ae08745Sheppo RW_EXIT(&vnetp->trwlock); 7571ae08745Sheppo } 7581ae08745Sheppo 7591ae08745Sheppo /* remove vp_tl from the list */ 7601ae08745Sheppo static void 7611ae08745Sheppo vnet_del_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp) 7621ae08745Sheppo { 7631ae08745Sheppo vp_tl_t *ttlp, **pretlp; 7641ae08745Sheppo boolean_t found = B_FALSE; 7651ae08745Sheppo 7661ae08745Sheppo pretlp = &vnetp->tlp; 7671ae08745Sheppo ttlp = *pretlp; 7681ae08745Sheppo while (ttlp) { 7691ae08745Sheppo if (ttlp == vp_tlp) { 7701ae08745Sheppo found = B_TRUE; 7711ae08745Sheppo (*pretlp) = ttlp->nextp; 7721ae08745Sheppo ttlp->nextp = NULL; 7731ae08745Sheppo break; 7741ae08745Sheppo } 7751ae08745Sheppo pretlp = &(ttlp->nextp); 7761ae08745Sheppo ttlp = *pretlp; 7771ae08745Sheppo } 7781ae08745Sheppo 7791ae08745Sheppo if (found) { 7801ae08745Sheppo KMEM_FREE(vp_tlp); 7811ae08745Sheppo } 7821ae08745Sheppo } 7831ae08745Sheppo 7841ae08745Sheppo /* get vp_tl corresponding to the given name */ 7851ae08745Sheppo static vp_tl_t * 7861ae08745Sheppo vnet_get_vptl(vnet_t *vnetp, const char *name) 7871ae08745Sheppo { 7881ae08745Sheppo vp_tl_t *tlp; 7891ae08745Sheppo 7901ae08745Sheppo tlp = vnetp->tlp; 7911ae08745Sheppo while (tlp) { 7921ae08745Sheppo if (strcmp(tlp->name, name) == 0) { 7931ae08745Sheppo return (tlp); 7941ae08745Sheppo } 7951ae08745Sheppo tlp = tlp->nextp; 7961ae08745Sheppo } 7971ae08745Sheppo DWARN((vnetp, 7981ae08745Sheppo "vnet_get_vptl: can't find vp_tl with name (%s)\n", name)); 7991ae08745Sheppo return (NULL); 8001ae08745Sheppo } 8011ae08745Sheppo 8021ae08745Sheppo /* read the mac address of the device */ 8031ae08745Sheppo static int 8041ae08745Sheppo vnet_read_mac_address(vnet_t *vnetp) 8051ae08745Sheppo { 8061ae08745Sheppo uchar_t *macaddr; 8071ae08745Sheppo uint32_t size; 8081ae08745Sheppo int rv; 8091ae08745Sheppo 8101ae08745Sheppo rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip, 8111ae08745Sheppo DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size); 8121ae08745Sheppo if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) { 8131ae08745Sheppo DWARN((vnetp, 8141ae08745Sheppo "vnet_read_mac_address: prop_lookup failed (%s) err (%d)\n", 8151ae08745Sheppo macaddr_propname, rv)); 8161ae08745Sheppo return (DDI_FAILURE); 8171ae08745Sheppo } 8181ae08745Sheppo bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL); 8191ae08745Sheppo bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL); 8201ae08745Sheppo ddi_prop_free(macaddr); 8211ae08745Sheppo 8221ae08745Sheppo return (DDI_SUCCESS); 8231ae08745Sheppo } 8241ae08745Sheppo 8251ae08745Sheppo 8261ae08745Sheppo /* 8271ae08745Sheppo * Functions below are called only by generic transport to add/remove/modify 8281ae08745Sheppo * entries in forwarding database. See comments in vgen_port_init(vnet_gen.c). 8291ae08745Sheppo */ 8301ae08745Sheppo 8311ae08745Sheppo /* add an entry into the forwarding database */ 8321ae08745Sheppo void 8331ae08745Sheppo vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg) 8341ae08745Sheppo { 8351ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 8361ae08745Sheppo uint32_t fdbhash; 8371ae08745Sheppo fdb_t *fdbp; 8381ae08745Sheppo fdb_fanout_t *fdbhp; 8391ae08745Sheppo 8401ae08745Sheppo /* Calculate hash value and fdb fanout */ 8411ae08745Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 8421ae08745Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 8431ae08745Sheppo 8441ae08745Sheppo WRITE_ENTER(&fdbhp->rwlock); 8451ae08745Sheppo 8461ae08745Sheppo fdbp = kmem_zalloc(sizeof (fdb_t), KM_NOSLEEP); 8471ae08745Sheppo if (fdbp == NULL) { 8481ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 8491ae08745Sheppo return; 8501ae08745Sheppo } 8511ae08745Sheppo bcopy(macaddr, (caddr_t)fdbp->macaddr, ETHERADDRL); 8521ae08745Sheppo fdbp->m_tx = m_tx; 8531ae08745Sheppo fdbp->txarg = txarg; 8541ae08745Sheppo fdbp->nextp = fdbhp->headp; 8551ae08745Sheppo fdbhp->headp = fdbp; 8561ae08745Sheppo 8571ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 8581ae08745Sheppo } 8591ae08745Sheppo 8601ae08745Sheppo /* delete an entry from the forwarding database */ 8611ae08745Sheppo void 8621ae08745Sheppo vnet_del_fdb(void *arg, uint8_t *macaddr) 8631ae08745Sheppo { 8641ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 8651ae08745Sheppo uint32_t fdbhash; 8661ae08745Sheppo fdb_t *fdbp; 8671ae08745Sheppo fdb_t **pfdbp; 8681ae08745Sheppo fdb_fanout_t *fdbhp; 8691ae08745Sheppo 8701ae08745Sheppo /* Calculate hash value and fdb fanout */ 8711ae08745Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 8721ae08745Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 8731ae08745Sheppo 8741ae08745Sheppo WRITE_ENTER(&fdbhp->rwlock); 8751ae08745Sheppo 8761ae08745Sheppo for (pfdbp = &fdbhp->headp; (fdbp = *pfdbp) != NULL; 8771ae08745Sheppo pfdbp = &fdbp->nextp) { 8781ae08745Sheppo if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) { 8791ae08745Sheppo /* Unlink it from the list */ 8801ae08745Sheppo *pfdbp = fdbp->nextp; 8811ae08745Sheppo KMEM_FREE(fdbp); 8821ae08745Sheppo break; 8831ae08745Sheppo } 8841ae08745Sheppo } 8851ae08745Sheppo 8861ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 8871ae08745Sheppo } 8881ae08745Sheppo 8891ae08745Sheppo /* modify an existing entry in the forwarding database */ 8901ae08745Sheppo void 891*3af08d82Slm66018 vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg, 892*3af08d82Slm66018 boolean_t upgrade) 8931ae08745Sheppo { 8941ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 8951ae08745Sheppo uint32_t fdbhash; 8961ae08745Sheppo fdb_t *fdbp; 8971ae08745Sheppo fdb_fanout_t *fdbhp; 8981ae08745Sheppo 8991ae08745Sheppo /* Calculate hash value and fdb fanout */ 9001ae08745Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 9011ae08745Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 9021ae08745Sheppo 903*3af08d82Slm66018 if (upgrade == B_TRUE) { 904*3af08d82Slm66018 /* 905*3af08d82Slm66018 * Caller already holds the lock as a reader. This can 906*3af08d82Slm66018 * occur if this function is invoked in the context 907*3af08d82Slm66018 * of transmit routine - vnet_m_tx(), where the lock 908*3af08d82Slm66018 * is held as a reader before calling the transmit 909*3af08d82Slm66018 * function of an fdb entry (fdbp->m_tx). 910*3af08d82Slm66018 * See comments in vgen_ldcsend() in vnet_gen.c 911*3af08d82Slm66018 */ 912*3af08d82Slm66018 if (!rw_tryupgrade(&fdbhp->rwlock)) { 913*3af08d82Slm66018 RW_EXIT(&fdbhp->rwlock); 9141ae08745Sheppo WRITE_ENTER(&fdbhp->rwlock); 915*3af08d82Slm66018 } 916*3af08d82Slm66018 } else { 917*3af08d82Slm66018 /* Caller does not hold the lock */ 918*3af08d82Slm66018 WRITE_ENTER(&fdbhp->rwlock); 919*3af08d82Slm66018 } 9201ae08745Sheppo 9211ae08745Sheppo for (fdbp = fdbhp->headp; fdbp != NULL; fdbp = fdbp->nextp) { 9221ae08745Sheppo if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) { 9231ae08745Sheppo /* change the entry to have new tx params */ 9241ae08745Sheppo fdbp->m_tx = m_tx; 9251ae08745Sheppo fdbp->txarg = txarg; 9261ae08745Sheppo break; 9271ae08745Sheppo } 9281ae08745Sheppo } 9291ae08745Sheppo 930*3af08d82Slm66018 if (upgrade == B_TRUE) { 931*3af08d82Slm66018 /* restore the caller as a reader */ 932*3af08d82Slm66018 rw_downgrade(&fdbhp->rwlock); 933*3af08d82Slm66018 } else { 9341ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 9351ae08745Sheppo } 936*3af08d82Slm66018 } 9371ae08745Sheppo 9381ae08745Sheppo /* look up an fdb entry based on the mac address, caller holds lock */ 9391ae08745Sheppo static fdb_t * 9401ae08745Sheppo vnet_lookup_fdb(fdb_fanout_t *fdbhp, uint8_t *macaddr) 9411ae08745Sheppo { 9421ae08745Sheppo fdb_t *fdbp = NULL; 9431ae08745Sheppo 9441ae08745Sheppo for (fdbp = fdbhp->headp; fdbp != NULL; fdbp = fdbp->nextp) { 9451ae08745Sheppo if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) { 9461ae08745Sheppo break; 9471ae08745Sheppo } 9481ae08745Sheppo } 9491ae08745Sheppo 9501ae08745Sheppo return (fdbp); 9511ae08745Sheppo } 9521ae08745Sheppo 9531ae08745Sheppo /* add default route entry into the forwarding database */ 9541ae08745Sheppo void 9551ae08745Sheppo vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg) 9561ae08745Sheppo { 9571ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 9581ae08745Sheppo fdb_t *fdbp; 9591ae08745Sheppo fdb_fanout_t *fdbhp; 9601ae08745Sheppo 9611ae08745Sheppo /* 9621ae08745Sheppo * The last hash list is reserved for default route entry, 9631ae08745Sheppo * and for now, we have only one entry in this list. 9641ae08745Sheppo */ 9651ae08745Sheppo fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]); 9661ae08745Sheppo 9671ae08745Sheppo WRITE_ENTER(&fdbhp->rwlock); 9681ae08745Sheppo 9691ae08745Sheppo if (fdbhp->headp) { 9701ae08745Sheppo DWARN((vnetp, 9711ae08745Sheppo "vnet_add_def_rte: default rte already exists\n")); 9721ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 9731ae08745Sheppo return; 9741ae08745Sheppo } 9751ae08745Sheppo fdbp = kmem_zalloc(sizeof (fdb_t), KM_NOSLEEP); 9761ae08745Sheppo if (fdbp == NULL) { 9771ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 9781ae08745Sheppo return; 9791ae08745Sheppo } 9801ae08745Sheppo bzero(fdbp->macaddr, ETHERADDRL); 9811ae08745Sheppo fdbp->m_tx = m_tx; 9821ae08745Sheppo fdbp->txarg = txarg; 9831ae08745Sheppo fdbp->nextp = NULL; 9841ae08745Sheppo fdbhp->headp = fdbp; 9851ae08745Sheppo 9861ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 9871ae08745Sheppo } 9881ae08745Sheppo 9891ae08745Sheppo /* delete default route entry from the forwarding database */ 9901ae08745Sheppo void 9911ae08745Sheppo vnet_del_def_rte(void *arg) 9921ae08745Sheppo { 9931ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 9941ae08745Sheppo fdb_t *fdbp; 9951ae08745Sheppo fdb_fanout_t *fdbhp; 9961ae08745Sheppo 9971ae08745Sheppo /* 9981ae08745Sheppo * The last hash list is reserved for default route entry, 9991ae08745Sheppo * and for now, we have only one entry in this list. 10001ae08745Sheppo */ 10011ae08745Sheppo fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]); 10021ae08745Sheppo 10031ae08745Sheppo WRITE_ENTER(&fdbhp->rwlock); 10041ae08745Sheppo 10051ae08745Sheppo if (fdbhp->headp == NULL) { 10061ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 10071ae08745Sheppo return; 10081ae08745Sheppo } 10091ae08745Sheppo fdbp = fdbhp->headp; 10101ae08745Sheppo KMEM_FREE(fdbp); 10111ae08745Sheppo fdbhp->headp = NULL; 10121ae08745Sheppo 10131ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 10141ae08745Sheppo } 1015ba2e4443Sseb 1016ba2e4443Sseb void 1017ba2e4443Sseb vnet_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp) 1018ba2e4443Sseb { 1019ba2e4443Sseb vnet_t *vnetp = arg; 1020ba2e4443Sseb mac_rx(vnetp->mh, mrh, mp); 1021ba2e4443Sseb } 1022ba2e4443Sseb 1023ba2e4443Sseb void 1024ba2e4443Sseb vnet_tx_update(void *arg) 1025ba2e4443Sseb { 1026ba2e4443Sseb vnet_t *vnetp = arg; 1027ba2e4443Sseb mac_tx_update(vnetp->mh); 1028ba2e4443Sseb } 1029