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); 801ae08745Sheppo void vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg); 811ae08745Sheppo void vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg); 821ae08745Sheppo void vnet_del_def_rte(void *arg); 83ba2e4443Sseb void vnet_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp); 84ba2e4443Sseb void vnet_tx_update(void *arg); 851ae08745Sheppo 861ae08745Sheppo /* externs */ 87ba2e4443Sseb extern int vgen_init(void *vnetp, dev_info_t *vnetdip, const uint8_t *macaddr, 88ba2e4443Sseb mac_register_t **vgenmacp); 89*d10e4ef2Snarayan extern int vgen_uninit(void *arg); 901ae08745Sheppo 91ba2e4443Sseb static mac_callbacks_t vnet_m_callbacks = { 92ba2e4443Sseb 0, 93ba2e4443Sseb vnet_m_stat, 94ba2e4443Sseb vnet_m_start, 95ba2e4443Sseb vnet_m_stop, 96ba2e4443Sseb vnet_m_promisc, 97ba2e4443Sseb vnet_m_multicst, 98ba2e4443Sseb vnet_m_unicst, 99ba2e4443Sseb vnet_m_tx, 100ba2e4443Sseb NULL, 101ba2e4443Sseb NULL, 102ba2e4443Sseb NULL 103ba2e4443Sseb }; 104ba2e4443Sseb 1051ae08745Sheppo /* 1061ae08745Sheppo * Linked list of "vnet_t" structures - one per instance. 1071ae08745Sheppo */ 1081ae08745Sheppo static vnet_t *vnet_headp = NULL; 1091ae08745Sheppo static krwlock_t vnet_rw; 1101ae08745Sheppo 1111ae08745Sheppo /* Tunables */ 1121ae08745Sheppo uint32_t vnet_ntxds = VNET_NTXDS; /* power of 2 transmit descriptors */ 1131ae08745Sheppo uint32_t vnet_reclaim_lowat = VNET_RECLAIM_LOWAT; /* tx recl low watermark */ 1141ae08745Sheppo uint32_t vnet_reclaim_hiwat = VNET_RECLAIM_HIWAT; /* tx recl high watermark */ 1151ae08745Sheppo uint32_t vnet_ldcwd_interval = VNET_LDCWD_INTERVAL; /* watchdog freq in msec */ 1161ae08745Sheppo uint32_t vnet_ldcwd_txtimeout = VNET_LDCWD_TXTIMEOUT; /* tx timeout in msec */ 1171ae08745Sheppo uint32_t vnet_ldc_qlen = VNET_LDC_QLEN; /* ldc qlen */ 1181ae08745Sheppo uint32_t vnet_nfdb_hash = VNET_NFDB_HASH; /* size of fdb hash table */ 119*d10e4ef2Snarayan uint32_t vnet_nrbufs = VNET_NRBUFS; /* number of receive buffers */ 1201ae08745Sheppo 1211ae08745Sheppo /* 1221ae08745Sheppo * Property names 1231ae08745Sheppo */ 1241ae08745Sheppo static char macaddr_propname[] = "local-mac-address"; 1251ae08745Sheppo 1261ae08745Sheppo /* 1271ae08745Sheppo * This is the string displayed by modinfo(1m). 1281ae08745Sheppo */ 1298e6a2a04Slm66018 static char vnet_ident[] = "vnet driver v%I%"; 1301ae08745Sheppo extern struct mod_ops mod_driverops; 1311ae08745Sheppo static struct cb_ops cb_vnetops = { 1321ae08745Sheppo nulldev, /* cb_open */ 1331ae08745Sheppo nulldev, /* cb_close */ 1341ae08745Sheppo nodev, /* cb_strategy */ 1351ae08745Sheppo nodev, /* cb_print */ 1361ae08745Sheppo nodev, /* cb_dump */ 1371ae08745Sheppo nodev, /* cb_read */ 1381ae08745Sheppo nodev, /* cb_write */ 1391ae08745Sheppo nodev, /* cb_ioctl */ 1401ae08745Sheppo nodev, /* cb_devmap */ 1411ae08745Sheppo nodev, /* cb_mmap */ 1421ae08745Sheppo nodev, /* cb_segmap */ 1431ae08745Sheppo nochpoll, /* cb_chpoll */ 1441ae08745Sheppo ddi_prop_op, /* cb_prop_op */ 1451ae08745Sheppo NULL, /* cb_stream */ 1461ae08745Sheppo (int)(D_MP) /* cb_flag */ 1471ae08745Sheppo }; 1481ae08745Sheppo 1491ae08745Sheppo static struct dev_ops vnetops = { 1501ae08745Sheppo DEVO_REV, /* devo_rev */ 1511ae08745Sheppo 0, /* devo_refcnt */ 1521ae08745Sheppo NULL, /* devo_getinfo */ 1531ae08745Sheppo nulldev, /* devo_identify */ 1541ae08745Sheppo nulldev, /* devo_probe */ 1551ae08745Sheppo vnetattach, /* devo_attach */ 1561ae08745Sheppo vnetdetach, /* devo_detach */ 1571ae08745Sheppo nodev, /* devo_reset */ 1581ae08745Sheppo &cb_vnetops, /* devo_cb_ops */ 1591ae08745Sheppo (struct bus_ops *)NULL /* devo_bus_ops */ 1601ae08745Sheppo }; 1611ae08745Sheppo 1621ae08745Sheppo static struct modldrv modldrv = { 1631ae08745Sheppo &mod_driverops, /* Type of module. This one is a driver */ 1641ae08745Sheppo vnet_ident, /* ID string */ 1651ae08745Sheppo &vnetops /* driver specific ops */ 1661ae08745Sheppo }; 1671ae08745Sheppo 1681ae08745Sheppo static struct modlinkage modlinkage = { 1691ae08745Sheppo MODREV_1, (void *)&modldrv, NULL 1701ae08745Sheppo }; 1711ae08745Sheppo 1721ae08745Sheppo 1731ae08745Sheppo /* 1741ae08745Sheppo * Print debug messages - set to 0xf to enable all msgs 1751ae08745Sheppo */ 1761ae08745Sheppo int _vnet_dbglevel = 0x8; 1771ae08745Sheppo 1781ae08745Sheppo void 1791ae08745Sheppo _vnetdebug_printf(void *arg, const char *fmt, ...) 1801ae08745Sheppo { 1811ae08745Sheppo char buf[512]; 1821ae08745Sheppo va_list ap; 1831ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 1841ae08745Sheppo 1851ae08745Sheppo va_start(ap, fmt); 1861ae08745Sheppo (void) vsprintf(buf, fmt, ap); 1871ae08745Sheppo va_end(ap); 1881ae08745Sheppo 1891ae08745Sheppo if (vnetp == NULL) 1901ae08745Sheppo cmn_err(CE_CONT, "%s\n", buf); 1911ae08745Sheppo else 1921ae08745Sheppo cmn_err(CE_CONT, "vnet%d: %s\n", vnetp->instance, buf); 1931ae08745Sheppo } 1941ae08745Sheppo 1951ae08745Sheppo #ifdef DEBUG 1961ae08745Sheppo 1971ae08745Sheppo /* 1981ae08745Sheppo * XXX: any changes to the definitions below need corresponding changes in 1991ae08745Sheppo * vnet_gen.c 2001ae08745Sheppo */ 2011ae08745Sheppo 2021ae08745Sheppo /* 2031ae08745Sheppo * debug levels: 2041ae08745Sheppo * DBG_LEVEL1: Function entry/exit tracing 2051ae08745Sheppo * DBG_LEVEL2: Info messages 2061ae08745Sheppo * DBG_LEVEL3: Warning messages 2071ae08745Sheppo * DBG_LEVEL4: Error messages 2081ae08745Sheppo */ 2091ae08745Sheppo 2101ae08745Sheppo enum { DBG_LEVEL1 = 0x01, DBG_LEVEL2 = 0x02, DBG_LEVEL3 = 0x04, 2111ae08745Sheppo DBG_LEVEL4 = 0x08 }; 2121ae08745Sheppo 2131ae08745Sheppo #define DBG1(_s) do { \ 2141ae08745Sheppo if ((_vnet_dbglevel & DBG_LEVEL1) != 0) { \ 2151ae08745Sheppo _vnetdebug_printf _s; \ 2161ae08745Sheppo } \ 2171ae08745Sheppo _NOTE(CONSTCOND) } while (0) 2181ae08745Sheppo 2191ae08745Sheppo #define DBG2(_s) do { \ 2201ae08745Sheppo if ((_vnet_dbglevel & DBG_LEVEL2) != 0) { \ 2211ae08745Sheppo _vnetdebug_printf _s; \ 2221ae08745Sheppo } \ 2231ae08745Sheppo _NOTE(CONSTCOND) } while (0) 2241ae08745Sheppo 2251ae08745Sheppo #define DWARN(_s) do { \ 2261ae08745Sheppo if ((_vnet_dbglevel & DBG_LEVEL3) != 0) { \ 2271ae08745Sheppo _vnetdebug_printf _s; \ 2281ae08745Sheppo } \ 2291ae08745Sheppo _NOTE(CONSTCOND) } while (0) 2301ae08745Sheppo 2311ae08745Sheppo #define DERR(_s) do { \ 2321ae08745Sheppo if ((_vnet_dbglevel & DBG_LEVEL4) != 0) { \ 2331ae08745Sheppo _vnetdebug_printf _s; \ 2341ae08745Sheppo } \ 2351ae08745Sheppo _NOTE(CONSTCOND) } while (0) 2361ae08745Sheppo 2371ae08745Sheppo #else 2381ae08745Sheppo 2391ae08745Sheppo #define DBG1(_s) if (0) _vnetdebug_printf _s 2401ae08745Sheppo #define DBG2(_s) if (0) _vnetdebug_printf _s 2411ae08745Sheppo #define DWARN(_s) if (0) _vnetdebug_printf _s 2421ae08745Sheppo #define DERR(_s) if (0) _vnetdebug_printf _s 2431ae08745Sheppo 2441ae08745Sheppo #endif 2451ae08745Sheppo 2461ae08745Sheppo /* _init(9E): initialize the loadable module */ 2471ae08745Sheppo int 2481ae08745Sheppo _init(void) 2491ae08745Sheppo { 2501ae08745Sheppo int status; 2511ae08745Sheppo 2521ae08745Sheppo DBG1((NULL, "_init: enter\n")); 2531ae08745Sheppo 2541ae08745Sheppo mac_init_ops(&vnetops, "vnet"); 2551ae08745Sheppo status = mod_install(&modlinkage); 2561ae08745Sheppo if (status != 0) { 2571ae08745Sheppo mac_fini_ops(&vnetops); 2581ae08745Sheppo } 2591ae08745Sheppo 2601ae08745Sheppo DBG1((NULL, "_init: exit\n")); 2611ae08745Sheppo return (status); 2621ae08745Sheppo } 2631ae08745Sheppo 2641ae08745Sheppo /* _fini(9E): prepare the module for unloading. */ 2651ae08745Sheppo int 2661ae08745Sheppo _fini(void) 2671ae08745Sheppo { 2681ae08745Sheppo int status; 2691ae08745Sheppo 2701ae08745Sheppo DBG1((NULL, "_fini: enter\n")); 2711ae08745Sheppo 2721ae08745Sheppo status = mod_remove(&modlinkage); 2731ae08745Sheppo if (status != 0) 2741ae08745Sheppo return (status); 2751ae08745Sheppo mac_fini_ops(&vnetops); 2761ae08745Sheppo 2771ae08745Sheppo DBG1((NULL, "_fini: exit\n")); 2781ae08745Sheppo return (status); 2791ae08745Sheppo } 2801ae08745Sheppo 2811ae08745Sheppo /* _info(9E): return information about the loadable module */ 2821ae08745Sheppo int 2831ae08745Sheppo _info(struct modinfo *modinfop) 2841ae08745Sheppo { 2851ae08745Sheppo return (mod_info(&modlinkage, modinfop)); 2861ae08745Sheppo } 2871ae08745Sheppo 2881ae08745Sheppo /* 2891ae08745Sheppo * attach(9E): attach a device to the system. 2901ae08745Sheppo * called once for each instance of the device on the system. 2911ae08745Sheppo */ 2921ae08745Sheppo static int 2931ae08745Sheppo vnetattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2941ae08745Sheppo { 2951ae08745Sheppo vnet_t *vnetp; 2961ae08745Sheppo vp_tl_t *vp_tlp; 2971ae08745Sheppo int instance; 2981ae08745Sheppo int status; 2991ae08745Sheppo enum { AST_init = 0x0, AST_vnet_alloc = 0x1, 300*d10e4ef2Snarayan AST_mac_alloc = 0x2, AST_read_macaddr = 0x4, 301*d10e4ef2Snarayan AST_vgen_init = 0x8, AST_vptl_alloc = 0x10, 302*d10e4ef2Snarayan AST_fdbh_alloc = 0x20 } 3031ae08745Sheppo attach_state; 304ba2e4443Sseb mac_register_t *vgenmacp = NULL; 3051ae08745Sheppo uint32_t nfdbh = 0; 3061ae08745Sheppo 3071ae08745Sheppo attach_state = AST_init; 3081ae08745Sheppo 3091ae08745Sheppo switch (cmd) { 3101ae08745Sheppo case DDI_ATTACH: 3111ae08745Sheppo break; 3121ae08745Sheppo case DDI_RESUME: 3131ae08745Sheppo case DDI_PM_RESUME: 3141ae08745Sheppo default: 3151ae08745Sheppo goto vnet_attach_fail; 3161ae08745Sheppo } 3171ae08745Sheppo 3181ae08745Sheppo instance = ddi_get_instance(dip); 3191ae08745Sheppo DBG1((NULL, "vnetattach: instance(%d) enter\n", instance)); 3201ae08745Sheppo 3211ae08745Sheppo /* allocate vnet_t and mac_t structures */ 3221ae08745Sheppo vnetp = kmem_zalloc(sizeof (vnet_t), KM_SLEEP); 3231ae08745Sheppo attach_state |= AST_vnet_alloc; 3241ae08745Sheppo 3251ae08745Sheppo /* setup links to vnet_t from both devinfo and mac_t */ 3261ae08745Sheppo ddi_set_driver_private(dip, (caddr_t)vnetp); 3271ae08745Sheppo vnetp->dip = dip; 3281ae08745Sheppo vnetp->instance = instance; 3291ae08745Sheppo 3301ae08745Sheppo /* read the mac address */ 3311ae08745Sheppo status = vnet_read_mac_address(vnetp); 3321ae08745Sheppo if (status != DDI_SUCCESS) { 3331ae08745Sheppo goto vnet_attach_fail; 3341ae08745Sheppo } 3351ae08745Sheppo attach_state |= AST_read_macaddr; 3361ae08745Sheppo 3371ae08745Sheppo /* 3381ae08745Sheppo * Initialize the generic vnet proxy transport. This is the first 3391ae08745Sheppo * and default transport used by vnet. The generic transport 3401ae08745Sheppo * is provided by using sun4v LDC (logical domain channel). On success, 3411ae08745Sheppo * vgen_init() provides a pointer to mac_t of generic transport. 3421ae08745Sheppo * Currently, this generic layer provides network connectivity to other 3431ae08745Sheppo * vnets within ldoms and also to remote hosts oustide ldoms through 3441ae08745Sheppo * the virtual switch (vsw) device on domain0. In the future, when 3451ae08745Sheppo * physical adapters that are able to share their resources (such as 3461ae08745Sheppo * dma channels) with guest domains become available, the vnet device 3471ae08745Sheppo * will use hardware specific driver to communicate directly over the 3481ae08745Sheppo * physical device to reach remote hosts without going through vswitch. 3491ae08745Sheppo */ 350ba2e4443Sseb status = vgen_init(vnetp, vnetp->dip, (uint8_t *)vnetp->curr_macaddr, 351ba2e4443Sseb &vgenmacp); 3521ae08745Sheppo if (status != DDI_SUCCESS) { 3531ae08745Sheppo DERR((vnetp, "vgen_init() failed\n")); 3541ae08745Sheppo goto vnet_attach_fail; 3551ae08745Sheppo } 3561ae08745Sheppo attach_state |= AST_vgen_init; 3571ae08745Sheppo 3581ae08745Sheppo vp_tlp = kmem_zalloc(sizeof (vp_tl_t), KM_SLEEP); 3591ae08745Sheppo vp_tlp->macp = vgenmacp; 3601ae08745Sheppo (void) snprintf(vp_tlp->name, MAXNAMELEN, "%s%u", "vgen", instance); 3611ae08745Sheppo (void) strcpy(vnetp->vgen_name, vp_tlp->name); 3621ae08745Sheppo 3631ae08745Sheppo /* add generic transport to the list of vnet proxy transports */ 3641ae08745Sheppo vnet_add_vptl(vnetp, vp_tlp); 3651ae08745Sheppo attach_state |= AST_vptl_alloc; 3661ae08745Sheppo 3671ae08745Sheppo nfdbh = vnet_nfdb_hash; 3681ae08745Sheppo if ((nfdbh < VNET_NFDB_HASH) || (nfdbh > VNET_NFDB_HASH_MAX)) { 3691ae08745Sheppo vnetp->nfdb_hash = VNET_NFDB_HASH; 3701ae08745Sheppo } 3711ae08745Sheppo else 3721ae08745Sheppo vnetp->nfdb_hash = nfdbh; 3731ae08745Sheppo 3741ae08745Sheppo /* allocate fdb hash table, with an extra slot for default route */ 3751ae08745Sheppo vnetp->fdbhp = kmem_zalloc(sizeof (fdb_fanout_t) * 3761ae08745Sheppo (vnetp->nfdb_hash + 1), KM_SLEEP); 3771ae08745Sheppo attach_state |= AST_fdbh_alloc; 3781ae08745Sheppo 3791ae08745Sheppo /* register with MAC layer */ 3801ae08745Sheppo status = vnet_mac_register(vnetp); 3811ae08745Sheppo if (status != DDI_SUCCESS) { 3821ae08745Sheppo goto vnet_attach_fail; 3831ae08745Sheppo } 3841ae08745Sheppo 3851ae08745Sheppo /* add to the list of vnet devices */ 3861ae08745Sheppo WRITE_ENTER(&vnet_rw); 3871ae08745Sheppo vnetp->nextp = vnet_headp; 3881ae08745Sheppo vnet_headp = vnetp; 3891ae08745Sheppo RW_EXIT(&vnet_rw); 3901ae08745Sheppo 3911ae08745Sheppo DBG1((NULL, "vnetattach: instance(%d) exit\n", instance)); 3921ae08745Sheppo return (DDI_SUCCESS); 3931ae08745Sheppo 3941ae08745Sheppo vnet_attach_fail: 3951ae08745Sheppo if (attach_state & AST_fdbh_alloc) { 3961ae08745Sheppo kmem_free(vnetp->fdbhp, 3971ae08745Sheppo sizeof (fdb_fanout_t) * (vnetp->nfdb_hash + 1)); 3981ae08745Sheppo } 3991ae08745Sheppo if (attach_state & AST_vptl_alloc) { 4001ae08745Sheppo WRITE_ENTER(&vnetp->trwlock); 4011ae08745Sheppo vnet_del_vptl(vnetp, vp_tlp); 4021ae08745Sheppo RW_EXIT(&vnetp->trwlock); 4031ae08745Sheppo } 4041ae08745Sheppo if (attach_state & AST_vgen_init) { 405*d10e4ef2Snarayan (void) vgen_uninit(vgenmacp->m_driver); 4061ae08745Sheppo } 4071ae08745Sheppo if (attach_state & AST_vnet_alloc) { 4081ae08745Sheppo KMEM_FREE(vnetp); 4091ae08745Sheppo } 4101ae08745Sheppo return (DDI_FAILURE); 4111ae08745Sheppo } 4121ae08745Sheppo 4131ae08745Sheppo /* 4141ae08745Sheppo * detach(9E): detach a device from the system. 4151ae08745Sheppo */ 4161ae08745Sheppo static int 4171ae08745Sheppo vnetdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4181ae08745Sheppo { 4191ae08745Sheppo vnet_t *vnetp; 4201ae08745Sheppo vnet_t **vnetpp; 4211ae08745Sheppo vp_tl_t *vp_tlp; 4221ae08745Sheppo int instance; 423*d10e4ef2Snarayan int rv; 4241ae08745Sheppo 4251ae08745Sheppo instance = ddi_get_instance(dip); 4261ae08745Sheppo DBG1((NULL, "vnetdetach: instance(%d) enter\n", instance)); 4271ae08745Sheppo 4281ae08745Sheppo vnetp = ddi_get_driver_private(dip); 4291ae08745Sheppo if (vnetp == NULL) { 4301ae08745Sheppo goto vnet_detach_fail; 4311ae08745Sheppo } 4321ae08745Sheppo 4331ae08745Sheppo switch (cmd) { 4341ae08745Sheppo case DDI_DETACH: 4351ae08745Sheppo break; 4361ae08745Sheppo case DDI_SUSPEND: 4371ae08745Sheppo case DDI_PM_SUSPEND: 4381ae08745Sheppo default: 4391ae08745Sheppo goto vnet_detach_fail; 4401ae08745Sheppo } 4411ae08745Sheppo 442*d10e4ef2Snarayan /* uninit and free vnet proxy transports */ 443*d10e4ef2Snarayan WRITE_ENTER(&vnetp->trwlock); 444*d10e4ef2Snarayan while ((vp_tlp = vnetp->tlp) != NULL) { 445*d10e4ef2Snarayan if (strcmp(vnetp->vgen_name, vp_tlp->name) == 0) { 446*d10e4ef2Snarayan /* uninitialize generic transport */ 447*d10e4ef2Snarayan rv = vgen_uninit(vp_tlp->macp->m_driver); 448*d10e4ef2Snarayan if (rv != DDI_SUCCESS) { 449*d10e4ef2Snarayan RW_EXIT(&vnetp->trwlock); 450*d10e4ef2Snarayan goto vnet_detach_fail; 451*d10e4ef2Snarayan } 452*d10e4ef2Snarayan } 453*d10e4ef2Snarayan vnet_del_vptl(vnetp, vp_tlp); 454*d10e4ef2Snarayan } 455*d10e4ef2Snarayan RW_EXIT(&vnetp->trwlock); 456*d10e4ef2Snarayan 4571ae08745Sheppo /* 4581ae08745Sheppo * Unregister from the MAC subsystem. This can fail, in 4591ae08745Sheppo * particular if there are DLPI style-2 streams still open - 4601ae08745Sheppo * in which case we just return failure. 4611ae08745Sheppo */ 462ba2e4443Sseb if (mac_unregister(vnetp->mh) != 0) 4631ae08745Sheppo goto vnet_detach_fail; 4641ae08745Sheppo 4651ae08745Sheppo /* unlink from instance(vnet_t) list */ 4661ae08745Sheppo WRITE_ENTER(&vnet_rw); 4671ae08745Sheppo for (vnetpp = &vnet_headp; *vnetpp; vnetpp = &(*vnetpp)->nextp) { 4681ae08745Sheppo if (*vnetpp == vnetp) { 4691ae08745Sheppo *vnetpp = vnetp->nextp; 4701ae08745Sheppo break; 4711ae08745Sheppo } 4721ae08745Sheppo } 4731ae08745Sheppo RW_EXIT(&vnet_rw); 4741ae08745Sheppo 4751ae08745Sheppo KMEM_FREE(vnetp); 4761ae08745Sheppo 4771ae08745Sheppo return (DDI_SUCCESS); 4781ae08745Sheppo 4791ae08745Sheppo vnet_detach_fail: 4801ae08745Sheppo return (DDI_FAILURE); 4811ae08745Sheppo } 4821ae08745Sheppo 4831ae08745Sheppo /* enable the device for transmit/receive */ 4841ae08745Sheppo static int 4851ae08745Sheppo vnet_m_start(void *arg) 4861ae08745Sheppo { 4871ae08745Sheppo vnet_t *vnetp = arg; 4881ae08745Sheppo vp_tl_t *vp_tlp; 489ba2e4443Sseb mac_register_t *vp_macp; 490ba2e4443Sseb mac_callbacks_t *cbp; 4911ae08745Sheppo 4921ae08745Sheppo DBG1((vnetp, "vnet_m_start: enter\n")); 4931ae08745Sheppo 4941ae08745Sheppo /* 4951ae08745Sheppo * XXX 4961ae08745Sheppo * Currently, we only have generic transport. m_start() invokes 4971ae08745Sheppo * vgen_start() which enables ports/channels in vgen and 4981ae08745Sheppo * initiates handshake with peer vnets and vsw. In the future when we 4991ae08745Sheppo * have support for hardware specific transports, this information 5001ae08745Sheppo * needs to be propagted back to vnet from vgen and we need to revisit 5011ae08745Sheppo * this code (see comments in vnet_attach()). 5021ae08745Sheppo * 5031ae08745Sheppo */ 5041ae08745Sheppo WRITE_ENTER(&vnetp->trwlock); 5051ae08745Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 5061ae08745Sheppo vp_macp = vp_tlp->macp; 507ba2e4443Sseb cbp = vp_macp->m_callbacks; 508ba2e4443Sseb cbp->mc_start(vp_macp->m_driver); 5091ae08745Sheppo } 5101ae08745Sheppo RW_EXIT(&vnetp->trwlock); 5111ae08745Sheppo 5121ae08745Sheppo DBG1((vnetp, "vnet_m_start: exit\n")); 5131ae08745Sheppo return (VNET_SUCCESS); 5141ae08745Sheppo 5151ae08745Sheppo } 5161ae08745Sheppo 5171ae08745Sheppo /* stop transmit/receive for the device */ 5181ae08745Sheppo static void 5191ae08745Sheppo vnet_m_stop(void *arg) 5201ae08745Sheppo { 5211ae08745Sheppo vnet_t *vnetp = arg; 5221ae08745Sheppo vp_tl_t *vp_tlp; 523ba2e4443Sseb mac_register_t *vp_macp; 524ba2e4443Sseb mac_callbacks_t *cbp; 5251ae08745Sheppo 5261ae08745Sheppo DBG1((vnetp, "vnet_m_stop: enter\n")); 5271ae08745Sheppo 5281ae08745Sheppo WRITE_ENTER(&vnetp->trwlock); 5291ae08745Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 5301ae08745Sheppo vp_macp = vp_tlp->macp; 531ba2e4443Sseb cbp = vp_macp->m_callbacks; 532ba2e4443Sseb cbp->mc_stop(vp_macp->m_driver); 5331ae08745Sheppo } 5341ae08745Sheppo RW_EXIT(&vnetp->trwlock); 5351ae08745Sheppo 5361ae08745Sheppo DBG1((vnetp, "vnet_m_stop: exit\n")); 5371ae08745Sheppo } 5381ae08745Sheppo 5391ae08745Sheppo /* set the unicast mac address of the device */ 5401ae08745Sheppo static int 5411ae08745Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr) 5421ae08745Sheppo { 5431ae08745Sheppo _NOTE(ARGUNUSED(macaddr)) 5441ae08745Sheppo 5451ae08745Sheppo vnet_t *vnetp = arg; 5461ae08745Sheppo 5471ae08745Sheppo DBG1((vnetp, "vnet_m_unicst: enter\n")); 5481ae08745Sheppo /* 5491ae08745Sheppo * XXX: setting mac address dynamically is not supported. 5501ae08745Sheppo */ 5511ae08745Sheppo DBG1((vnetp, "vnet_m_unicst: exit\n")); 5521ae08745Sheppo 5538e6a2a04Slm66018 return (VNET_FAILURE); 5541ae08745Sheppo } 5551ae08745Sheppo 5561ae08745Sheppo /* enable/disable a multicast address */ 5571ae08745Sheppo static int 5581ae08745Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 5591ae08745Sheppo { 5601ae08745Sheppo _NOTE(ARGUNUSED(add, mca)) 5611ae08745Sheppo 5621ae08745Sheppo vnet_t *vnetp = arg; 5631ae08745Sheppo vp_tl_t *vp_tlp; 564ba2e4443Sseb mac_register_t *vp_macp; 565ba2e4443Sseb mac_callbacks_t *cbp; 5661ae08745Sheppo int rv = VNET_SUCCESS; 5671ae08745Sheppo 5681ae08745Sheppo DBG1((vnetp, "vnet_m_multicst: enter\n")); 5691ae08745Sheppo READ_ENTER(&vnetp->trwlock); 5701ae08745Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 5711ae08745Sheppo if (strcmp(vnetp->vgen_name, vp_tlp->name) == 0) { 5721ae08745Sheppo vp_macp = vp_tlp->macp; 573ba2e4443Sseb cbp = vp_macp->m_callbacks; 574ba2e4443Sseb rv = cbp->mc_multicst(vp_macp->m_driver, add, mca); 5751ae08745Sheppo break; 5761ae08745Sheppo } 5771ae08745Sheppo } 5781ae08745Sheppo RW_EXIT(&vnetp->trwlock); 5791ae08745Sheppo DBG1((vnetp, "vnet_m_multicst: exit\n")); 5801ae08745Sheppo return (rv); 5811ae08745Sheppo } 5821ae08745Sheppo 5831ae08745Sheppo /* set or clear promiscuous mode on the device */ 5841ae08745Sheppo static int 5851ae08745Sheppo vnet_m_promisc(void *arg, boolean_t on) 5861ae08745Sheppo { 5871ae08745Sheppo _NOTE(ARGUNUSED(on)) 5881ae08745Sheppo 5891ae08745Sheppo vnet_t *vnetp = arg; 5901ae08745Sheppo DBG1((vnetp, "vnet_m_promisc: enter\n")); 5911ae08745Sheppo /* 5921ae08745Sheppo * XXX: setting promiscuous mode is not supported, just return success. 5931ae08745Sheppo */ 5941ae08745Sheppo DBG1((vnetp, "vnet_m_promisc: exit\n")); 5951ae08745Sheppo return (VNET_SUCCESS); 5961ae08745Sheppo } 5971ae08745Sheppo 5981ae08745Sheppo /* 5991ae08745Sheppo * Transmit a chain of packets. This function provides switching functionality 6001ae08745Sheppo * based on the destination mac address to reach other guests (within ldoms) or 6011ae08745Sheppo * external hosts. 6021ae08745Sheppo */ 6031ae08745Sheppo mblk_t * 6041ae08745Sheppo vnet_m_tx(void *arg, mblk_t *mp) 6051ae08745Sheppo { 6061ae08745Sheppo vnet_t *vnetp; 6071ae08745Sheppo mblk_t *next; 6081ae08745Sheppo uint32_t fdbhash; 6091ae08745Sheppo fdb_t *fdbp; 6101ae08745Sheppo fdb_fanout_t *fdbhp; 6111ae08745Sheppo struct ether_header *ehp; 6121ae08745Sheppo uint8_t *macaddr; 6131ae08745Sheppo mblk_t *resid_mp; 6141ae08745Sheppo 6151ae08745Sheppo vnetp = (vnet_t *)arg; 6161ae08745Sheppo DBG1((vnetp, "vnet_m_tx: enter\n")); 6171ae08745Sheppo ASSERT(mp != NULL); 6181ae08745Sheppo 6191ae08745Sheppo while (mp != NULL) { 6201ae08745Sheppo next = mp->b_next; 6211ae08745Sheppo mp->b_next = NULL; 6221ae08745Sheppo 6231ae08745Sheppo /* get the destination mac address in the eth header */ 6241ae08745Sheppo ehp = (struct ether_header *)mp->b_rptr; 6251ae08745Sheppo macaddr = (uint8_t *)&ehp->ether_dhost; 6261ae08745Sheppo 6271ae08745Sheppo /* Calculate hash value and fdb fanout */ 6281ae08745Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 6291ae08745Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 6301ae08745Sheppo 6311ae08745Sheppo READ_ENTER(&fdbhp->rwlock); 6321ae08745Sheppo fdbp = vnet_lookup_fdb(fdbhp, macaddr); 6331ae08745Sheppo if (fdbp) { 6341ae08745Sheppo /* 6351ae08745Sheppo * If the destination is in FDB, the destination is 6361ae08745Sheppo * a vnet device within ldoms and directly reachable, 6371ae08745Sheppo * invoke the tx function in the fdb entry. 6381ae08745Sheppo */ 6391ae08745Sheppo resid_mp = fdbp->m_tx(fdbp->txarg, mp); 6401ae08745Sheppo if (resid_mp != NULL) { 6411ae08745Sheppo /* m_tx failed */ 6421ae08745Sheppo mp->b_next = next; 6431ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 6441ae08745Sheppo break; 6451ae08745Sheppo } 6461ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 6471ae08745Sheppo } else { 6481ae08745Sheppo /* destination is not in FDB */ 6491ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 6501ae08745Sheppo /* 6511ae08745Sheppo * If the destination is broadcast/multicast 6521ae08745Sheppo * or an unknown unicast address, forward the 6531ae08745Sheppo * packet to vsw, using the last slot in fdb which is 6541ae08745Sheppo * reserved for default route. 6551ae08745Sheppo */ 6561ae08745Sheppo fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]); 6571ae08745Sheppo READ_ENTER(&fdbhp->rwlock); 6581ae08745Sheppo fdbp = fdbhp->headp; 6591ae08745Sheppo if (fdbp) { 6601ae08745Sheppo resid_mp = fdbp->m_tx(fdbp->txarg, mp); 6611ae08745Sheppo if (resid_mp != NULL) { 6621ae08745Sheppo /* m_tx failed */ 6631ae08745Sheppo mp->b_next = next; 6641ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 6651ae08745Sheppo break; 6661ae08745Sheppo } 6671ae08745Sheppo } else { 6681ae08745Sheppo /* drop the packet */ 6691ae08745Sheppo freemsg(mp); 6701ae08745Sheppo } 6711ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 6721ae08745Sheppo } 6731ae08745Sheppo 6741ae08745Sheppo mp = next; 6751ae08745Sheppo } 6761ae08745Sheppo 6771ae08745Sheppo DBG1((vnetp, "vnet_m_tx: exit\n")); 6781ae08745Sheppo return (mp); 6791ae08745Sheppo } 6801ae08745Sheppo 6811ae08745Sheppo /* get statistics from the device */ 682ba2e4443Sseb int 683ba2e4443Sseb vnet_m_stat(void *arg, uint_t stat, uint64_t *val) 6841ae08745Sheppo { 6851ae08745Sheppo vnet_t *vnetp = arg; 6861ae08745Sheppo vp_tl_t *vp_tlp; 687ba2e4443Sseb mac_register_t *vp_macp; 688ba2e4443Sseb mac_callbacks_t *cbp; 689ba2e4443Sseb uint64_t val_total = 0; 6901ae08745Sheppo 6911ae08745Sheppo DBG1((vnetp, "vnet_m_stat: enter\n")); 6921ae08745Sheppo 6931ae08745Sheppo /* 694ba2e4443Sseb * get the specified statistic from each transport and return the 695ba2e4443Sseb * aggregate val. This obviously only works for counters. 6961ae08745Sheppo */ 697ba2e4443Sseb if ((IS_MAC_STAT(stat) && !MAC_STAT_ISACOUNTER(stat)) || 698ba2e4443Sseb (IS_MACTYPE_STAT(stat) && !ETHER_STAT_ISACOUNTER(stat))) { 699ba2e4443Sseb return (ENOTSUP); 700ba2e4443Sseb } 7011ae08745Sheppo READ_ENTER(&vnetp->trwlock); 7021ae08745Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 7031ae08745Sheppo vp_macp = vp_tlp->macp; 704ba2e4443Sseb cbp = vp_macp->m_callbacks; 705ba2e4443Sseb if (cbp->mc_getstat(vp_macp->m_driver, stat, val) == 0) 706ba2e4443Sseb val_total += *val; 7071ae08745Sheppo } 7081ae08745Sheppo RW_EXIT(&vnetp->trwlock); 7091ae08745Sheppo 710ba2e4443Sseb *val = val_total; 711ba2e4443Sseb 7121ae08745Sheppo DBG1((vnetp, "vnet_m_stat: exit\n")); 713ba2e4443Sseb return (0); 7141ae08745Sheppo } 7151ae08745Sheppo 7161ae08745Sheppo /* wrapper function for mac_register() */ 7171ae08745Sheppo static int 7181ae08745Sheppo vnet_mac_register(vnet_t *vnetp) 7191ae08745Sheppo { 720ba2e4443Sseb mac_register_t *macp; 721ba2e4443Sseb int err; 7221ae08745Sheppo 723ba2e4443Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 724ba2e4443Sseb return (DDI_FAILURE); 725ba2e4443Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 726ba2e4443Sseb macp->m_driver = vnetp; 7271ae08745Sheppo macp->m_dip = vnetp->dip; 728ba2e4443Sseb macp->m_src_addr = vnetp->curr_macaddr; 729ba2e4443Sseb macp->m_callbacks = &vnet_m_callbacks; 730ba2e4443Sseb macp->m_min_sdu = 0; 731ba2e4443Sseb macp->m_max_sdu = ETHERMTU; 7321ae08745Sheppo 7331ae08745Sheppo /* 7341ae08745Sheppo * Finally, we're ready to register ourselves with the MAC layer 7351ae08745Sheppo * interface; if this succeeds, we're all ready to start() 7361ae08745Sheppo */ 737ba2e4443Sseb err = mac_register(macp, &vnetp->mh); 738ba2e4443Sseb mac_free(macp); 739ba2e4443Sseb return (err == 0 ? DDI_SUCCESS : DDI_FAILURE); 7401ae08745Sheppo } 7411ae08745Sheppo 7421ae08745Sheppo /* add vp_tl to the list */ 7431ae08745Sheppo static void 7441ae08745Sheppo vnet_add_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp) 7451ae08745Sheppo { 7461ae08745Sheppo vp_tl_t *ttlp; 7471ae08745Sheppo 7481ae08745Sheppo WRITE_ENTER(&vnetp->trwlock); 7491ae08745Sheppo if (vnetp->tlp == NULL) { 7501ae08745Sheppo vnetp->tlp = vp_tlp; 7511ae08745Sheppo } else { 7521ae08745Sheppo ttlp = vnetp->tlp; 7531ae08745Sheppo while (ttlp->nextp) 7541ae08745Sheppo ttlp = ttlp->nextp; 7551ae08745Sheppo ttlp->nextp = vp_tlp; 7561ae08745Sheppo } 7571ae08745Sheppo RW_EXIT(&vnetp->trwlock); 7581ae08745Sheppo } 7591ae08745Sheppo 7601ae08745Sheppo /* remove vp_tl from the list */ 7611ae08745Sheppo static void 7621ae08745Sheppo vnet_del_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp) 7631ae08745Sheppo { 7641ae08745Sheppo vp_tl_t *ttlp, **pretlp; 7651ae08745Sheppo boolean_t found = B_FALSE; 7661ae08745Sheppo 7671ae08745Sheppo pretlp = &vnetp->tlp; 7681ae08745Sheppo ttlp = *pretlp; 7691ae08745Sheppo while (ttlp) { 7701ae08745Sheppo if (ttlp == vp_tlp) { 7711ae08745Sheppo found = B_TRUE; 7721ae08745Sheppo (*pretlp) = ttlp->nextp; 7731ae08745Sheppo ttlp->nextp = NULL; 7741ae08745Sheppo break; 7751ae08745Sheppo } 7761ae08745Sheppo pretlp = &(ttlp->nextp); 7771ae08745Sheppo ttlp = *pretlp; 7781ae08745Sheppo } 7791ae08745Sheppo 7801ae08745Sheppo if (found) { 7811ae08745Sheppo KMEM_FREE(vp_tlp); 7821ae08745Sheppo } 7831ae08745Sheppo } 7841ae08745Sheppo 7851ae08745Sheppo /* get vp_tl corresponding to the given name */ 7861ae08745Sheppo static vp_tl_t * 7871ae08745Sheppo vnet_get_vptl(vnet_t *vnetp, const char *name) 7881ae08745Sheppo { 7891ae08745Sheppo vp_tl_t *tlp; 7901ae08745Sheppo 7911ae08745Sheppo tlp = vnetp->tlp; 7921ae08745Sheppo while (tlp) { 7931ae08745Sheppo if (strcmp(tlp->name, name) == 0) { 7941ae08745Sheppo return (tlp); 7951ae08745Sheppo } 7961ae08745Sheppo tlp = tlp->nextp; 7971ae08745Sheppo } 7981ae08745Sheppo DWARN((vnetp, 7991ae08745Sheppo "vnet_get_vptl: can't find vp_tl with name (%s)\n", name)); 8001ae08745Sheppo return (NULL); 8011ae08745Sheppo } 8021ae08745Sheppo 8031ae08745Sheppo /* read the mac address of the device */ 8041ae08745Sheppo static int 8051ae08745Sheppo vnet_read_mac_address(vnet_t *vnetp) 8061ae08745Sheppo { 8071ae08745Sheppo uchar_t *macaddr; 8081ae08745Sheppo uint32_t size; 8091ae08745Sheppo int rv; 8101ae08745Sheppo 8111ae08745Sheppo rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip, 8121ae08745Sheppo DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size); 8131ae08745Sheppo if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) { 8141ae08745Sheppo DWARN((vnetp, 8151ae08745Sheppo "vnet_read_mac_address: prop_lookup failed (%s) err (%d)\n", 8161ae08745Sheppo macaddr_propname, rv)); 8171ae08745Sheppo return (DDI_FAILURE); 8181ae08745Sheppo } 8191ae08745Sheppo bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL); 8201ae08745Sheppo bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL); 8211ae08745Sheppo ddi_prop_free(macaddr); 8221ae08745Sheppo 8231ae08745Sheppo return (DDI_SUCCESS); 8241ae08745Sheppo } 8251ae08745Sheppo 8261ae08745Sheppo 8271ae08745Sheppo /* 8281ae08745Sheppo * Functions below are called only by generic transport to add/remove/modify 8291ae08745Sheppo * entries in forwarding database. See comments in vgen_port_init(vnet_gen.c). 8301ae08745Sheppo */ 8311ae08745Sheppo 8321ae08745Sheppo /* add an entry into the forwarding database */ 8331ae08745Sheppo void 8341ae08745Sheppo vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg) 8351ae08745Sheppo { 8361ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 8371ae08745Sheppo uint32_t fdbhash; 8381ae08745Sheppo fdb_t *fdbp; 8391ae08745Sheppo fdb_fanout_t *fdbhp; 8401ae08745Sheppo 8411ae08745Sheppo /* Calculate hash value and fdb fanout */ 8421ae08745Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 8431ae08745Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 8441ae08745Sheppo 8451ae08745Sheppo WRITE_ENTER(&fdbhp->rwlock); 8461ae08745Sheppo 8471ae08745Sheppo fdbp = kmem_zalloc(sizeof (fdb_t), KM_NOSLEEP); 8481ae08745Sheppo if (fdbp == NULL) { 8491ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 8501ae08745Sheppo return; 8511ae08745Sheppo } 8521ae08745Sheppo bcopy(macaddr, (caddr_t)fdbp->macaddr, ETHERADDRL); 8531ae08745Sheppo fdbp->m_tx = m_tx; 8541ae08745Sheppo fdbp->txarg = txarg; 8551ae08745Sheppo fdbp->nextp = fdbhp->headp; 8561ae08745Sheppo fdbhp->headp = fdbp; 8571ae08745Sheppo 8581ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 8591ae08745Sheppo } 8601ae08745Sheppo 8611ae08745Sheppo /* delete an entry from the forwarding database */ 8621ae08745Sheppo void 8631ae08745Sheppo vnet_del_fdb(void *arg, uint8_t *macaddr) 8641ae08745Sheppo { 8651ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 8661ae08745Sheppo uint32_t fdbhash; 8671ae08745Sheppo fdb_t *fdbp; 8681ae08745Sheppo fdb_t **pfdbp; 8691ae08745Sheppo fdb_fanout_t *fdbhp; 8701ae08745Sheppo 8711ae08745Sheppo /* Calculate hash value and fdb fanout */ 8721ae08745Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 8731ae08745Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 8741ae08745Sheppo 8751ae08745Sheppo WRITE_ENTER(&fdbhp->rwlock); 8761ae08745Sheppo 8771ae08745Sheppo for (pfdbp = &fdbhp->headp; (fdbp = *pfdbp) != NULL; 8781ae08745Sheppo pfdbp = &fdbp->nextp) { 8791ae08745Sheppo if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) { 8801ae08745Sheppo /* Unlink it from the list */ 8811ae08745Sheppo *pfdbp = fdbp->nextp; 8821ae08745Sheppo KMEM_FREE(fdbp); 8831ae08745Sheppo break; 8841ae08745Sheppo } 8851ae08745Sheppo } 8861ae08745Sheppo 8871ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 8881ae08745Sheppo } 8891ae08745Sheppo 8901ae08745Sheppo /* modify an existing entry in the forwarding database */ 8911ae08745Sheppo void 8921ae08745Sheppo vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg) 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 9031ae08745Sheppo WRITE_ENTER(&fdbhp->rwlock); 9041ae08745Sheppo 9051ae08745Sheppo for (fdbp = fdbhp->headp; fdbp != NULL; fdbp = fdbp->nextp) { 9061ae08745Sheppo if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) { 9071ae08745Sheppo /* change the entry to have new tx params */ 9081ae08745Sheppo fdbp->m_tx = m_tx; 9091ae08745Sheppo fdbp->txarg = txarg; 9101ae08745Sheppo break; 9111ae08745Sheppo } 9121ae08745Sheppo } 9131ae08745Sheppo 9141ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 9151ae08745Sheppo } 9161ae08745Sheppo 9171ae08745Sheppo /* look up an fdb entry based on the mac address, caller holds lock */ 9181ae08745Sheppo static fdb_t * 9191ae08745Sheppo vnet_lookup_fdb(fdb_fanout_t *fdbhp, uint8_t *macaddr) 9201ae08745Sheppo { 9211ae08745Sheppo fdb_t *fdbp = NULL; 9221ae08745Sheppo 9231ae08745Sheppo for (fdbp = fdbhp->headp; fdbp != NULL; fdbp = fdbp->nextp) { 9241ae08745Sheppo if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) { 9251ae08745Sheppo break; 9261ae08745Sheppo } 9271ae08745Sheppo } 9281ae08745Sheppo 9291ae08745Sheppo return (fdbp); 9301ae08745Sheppo } 9311ae08745Sheppo 9321ae08745Sheppo /* add default route entry into the forwarding database */ 9331ae08745Sheppo void 9341ae08745Sheppo vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg) 9351ae08745Sheppo { 9361ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 9371ae08745Sheppo fdb_t *fdbp; 9381ae08745Sheppo fdb_fanout_t *fdbhp; 9391ae08745Sheppo 9401ae08745Sheppo /* 9411ae08745Sheppo * The last hash list is reserved for default route entry, 9421ae08745Sheppo * and for now, we have only one entry in this list. 9431ae08745Sheppo */ 9441ae08745Sheppo fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]); 9451ae08745Sheppo 9461ae08745Sheppo WRITE_ENTER(&fdbhp->rwlock); 9471ae08745Sheppo 9481ae08745Sheppo if (fdbhp->headp) { 9491ae08745Sheppo DWARN((vnetp, 9501ae08745Sheppo "vnet_add_def_rte: default rte already exists\n")); 9511ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 9521ae08745Sheppo return; 9531ae08745Sheppo } 9541ae08745Sheppo fdbp = kmem_zalloc(sizeof (fdb_t), KM_NOSLEEP); 9551ae08745Sheppo if (fdbp == NULL) { 9561ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 9571ae08745Sheppo return; 9581ae08745Sheppo } 9591ae08745Sheppo bzero(fdbp->macaddr, ETHERADDRL); 9601ae08745Sheppo fdbp->m_tx = m_tx; 9611ae08745Sheppo fdbp->txarg = txarg; 9621ae08745Sheppo fdbp->nextp = NULL; 9631ae08745Sheppo fdbhp->headp = fdbp; 9641ae08745Sheppo 9651ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 9661ae08745Sheppo } 9671ae08745Sheppo 9681ae08745Sheppo /* delete default route entry from the forwarding database */ 9691ae08745Sheppo void 9701ae08745Sheppo vnet_del_def_rte(void *arg) 9711ae08745Sheppo { 9721ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 9731ae08745Sheppo fdb_t *fdbp; 9741ae08745Sheppo fdb_fanout_t *fdbhp; 9751ae08745Sheppo 9761ae08745Sheppo /* 9771ae08745Sheppo * The last hash list is reserved for default route entry, 9781ae08745Sheppo * and for now, we have only one entry in this list. 9791ae08745Sheppo */ 9801ae08745Sheppo fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]); 9811ae08745Sheppo 9821ae08745Sheppo WRITE_ENTER(&fdbhp->rwlock); 9831ae08745Sheppo 9841ae08745Sheppo if (fdbhp->headp == NULL) { 9851ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 9861ae08745Sheppo return; 9871ae08745Sheppo } 9881ae08745Sheppo fdbp = fdbhp->headp; 9891ae08745Sheppo KMEM_FREE(fdbp); 9901ae08745Sheppo fdbhp->headp = NULL; 9911ae08745Sheppo 9921ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 9931ae08745Sheppo } 994ba2e4443Sseb 995ba2e4443Sseb void 996ba2e4443Sseb vnet_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp) 997ba2e4443Sseb { 998ba2e4443Sseb vnet_t *vnetp = arg; 999ba2e4443Sseb mac_rx(vnetp->mh, mrh, mp); 1000ba2e4443Sseb } 1001ba2e4443Sseb 1002ba2e4443Sseb void 1003ba2e4443Sseb vnet_tx_update(void *arg) 1004ba2e4443Sseb { 1005ba2e4443Sseb vnet_t *vnetp = arg; 1006ba2e4443Sseb mac_tx_update(vnetp->mh); 1007ba2e4443Sseb } 1008