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 /* 231991Sheppo * Copyright 2006 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> 391991Sheppo #include <sys/debug.h> 401991Sheppo #include <sys/ethernet.h> 411991Sheppo #include <sys/dlpi.h> 421991Sheppo #include <net/if.h> 431991Sheppo #include <sys/mac.h> 442311Sseb #include <sys/mac_ether.h> 451991Sheppo #include <sys/ddi.h> 461991Sheppo #include <sys/sunddi.h> 471991Sheppo #include <sys/strsun.h> 481991Sheppo #include <sys/note.h> 491991Sheppo #include <sys/vnet.h> 501991Sheppo 511991Sheppo /* 521991Sheppo * Function prototypes. 531991Sheppo */ 541991Sheppo 551991Sheppo /* DDI entrypoints */ 561991Sheppo static int vnetdevinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 571991Sheppo static int vnetattach(dev_info_t *, ddi_attach_cmd_t); 581991Sheppo static int vnetdetach(dev_info_t *, ddi_detach_cmd_t); 591991Sheppo 601991Sheppo /* MAC entrypoints */ 612311Sseb static int vnet_m_stat(void *, uint_t, uint64_t *); 621991Sheppo static int vnet_m_start(void *); 631991Sheppo static void vnet_m_stop(void *); 641991Sheppo static int vnet_m_promisc(void *, boolean_t); 651991Sheppo static int vnet_m_multicst(void *, boolean_t, const uint8_t *); 661991Sheppo static int vnet_m_unicst(void *, const uint8_t *); 671991Sheppo mblk_t *vnet_m_tx(void *, mblk_t *); 681991Sheppo 691991Sheppo /* vnet internal functions */ 701991Sheppo static int vnet_mac_register(vnet_t *); 711991Sheppo static int vnet_read_mac_address(vnet_t *vnetp); 721991Sheppo static void vnet_add_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp); 731991Sheppo static void vnet_del_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp); 741991Sheppo static vp_tl_t *vnet_get_vptl(vnet_t *vnetp, const char *devname); 751991Sheppo static fdb_t *vnet_lookup_fdb(fdb_fanout_t *fdbhp, uint8_t *macaddr); 761991Sheppo 771991Sheppo /* exported functions */ 781991Sheppo void vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg); 791991Sheppo void vnet_del_fdb(void *arg, uint8_t *macaddr); 802793Slm66018 void vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, 812793Slm66018 void *txarg, boolean_t upgrade); 821991Sheppo void vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg); 831991Sheppo void vnet_del_def_rte(void *arg); 842311Sseb void vnet_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp); 852311Sseb void vnet_tx_update(void *arg); 861991Sheppo 871991Sheppo /* externs */ 882311Sseb extern int vgen_init(void *vnetp, dev_info_t *vnetdip, const uint8_t *macaddr, 892311Sseb mac_register_t **vgenmacp); 902336Snarayan extern int vgen_uninit(void *arg); 911991Sheppo 922311Sseb static mac_callbacks_t vnet_m_callbacks = { 932311Sseb 0, 942311Sseb vnet_m_stat, 952311Sseb vnet_m_start, 962311Sseb vnet_m_stop, 972311Sseb vnet_m_promisc, 982311Sseb vnet_m_multicst, 992311Sseb vnet_m_unicst, 1002311Sseb vnet_m_tx, 1012311Sseb NULL, 1022311Sseb NULL, 1032311Sseb NULL 1042311Sseb }; 1052311Sseb 1061991Sheppo /* 1071991Sheppo * Linked list of "vnet_t" structures - one per instance. 1081991Sheppo */ 1091991Sheppo static vnet_t *vnet_headp = NULL; 1101991Sheppo static krwlock_t vnet_rw; 1111991Sheppo 1121991Sheppo /* Tunables */ 1131991Sheppo uint32_t vnet_ntxds = VNET_NTXDS; /* power of 2 transmit descriptors */ 1141991Sheppo uint32_t vnet_ldcwd_interval = VNET_LDCWD_INTERVAL; /* watchdog freq in msec */ 1151991Sheppo uint32_t vnet_ldcwd_txtimeout = VNET_LDCWD_TXTIMEOUT; /* tx timeout in msec */ 1162410Slm66018 uint32_t vnet_ldc_mtu = VNET_LDC_MTU; /* ldc mtu */ 1171991Sheppo uint32_t vnet_nfdb_hash = VNET_NFDB_HASH; /* size of fdb hash table */ 1182336Snarayan uint32_t vnet_nrbufs = VNET_NRBUFS; /* number of receive buffers */ 1191991Sheppo 1201991Sheppo /* 1211991Sheppo * Property names 1221991Sheppo */ 1231991Sheppo static char macaddr_propname[] = "local-mac-address"; 1241991Sheppo 1251991Sheppo /* 1261991Sheppo * This is the string displayed by modinfo(1m). 1271991Sheppo */ 1282109Slm66018 static char vnet_ident[] = "vnet driver v%I%"; 1291991Sheppo extern struct mod_ops mod_driverops; 1301991Sheppo static struct cb_ops cb_vnetops = { 1311991Sheppo nulldev, /* cb_open */ 1321991Sheppo nulldev, /* cb_close */ 1331991Sheppo nodev, /* cb_strategy */ 1341991Sheppo nodev, /* cb_print */ 1351991Sheppo nodev, /* cb_dump */ 1361991Sheppo nodev, /* cb_read */ 1371991Sheppo nodev, /* cb_write */ 1381991Sheppo nodev, /* cb_ioctl */ 1391991Sheppo nodev, /* cb_devmap */ 1401991Sheppo nodev, /* cb_mmap */ 1411991Sheppo nodev, /* cb_segmap */ 1421991Sheppo nochpoll, /* cb_chpoll */ 1431991Sheppo ddi_prop_op, /* cb_prop_op */ 1441991Sheppo NULL, /* cb_stream */ 1451991Sheppo (int)(D_MP) /* cb_flag */ 1461991Sheppo }; 1471991Sheppo 1481991Sheppo static struct dev_ops vnetops = { 1491991Sheppo DEVO_REV, /* devo_rev */ 1501991Sheppo 0, /* devo_refcnt */ 1511991Sheppo NULL, /* devo_getinfo */ 1521991Sheppo nulldev, /* devo_identify */ 1531991Sheppo nulldev, /* devo_probe */ 1541991Sheppo vnetattach, /* devo_attach */ 1551991Sheppo vnetdetach, /* devo_detach */ 1561991Sheppo nodev, /* devo_reset */ 1571991Sheppo &cb_vnetops, /* devo_cb_ops */ 1581991Sheppo (struct bus_ops *)NULL /* devo_bus_ops */ 1591991Sheppo }; 1601991Sheppo 1611991Sheppo static struct modldrv modldrv = { 1621991Sheppo &mod_driverops, /* Type of module. This one is a driver */ 1631991Sheppo vnet_ident, /* ID string */ 1641991Sheppo &vnetops /* driver specific ops */ 1651991Sheppo }; 1661991Sheppo 1671991Sheppo static struct modlinkage modlinkage = { 1681991Sheppo MODREV_1, (void *)&modldrv, NULL 1691991Sheppo }; 1701991Sheppo 1711991Sheppo 1721991Sheppo /* 1731991Sheppo * Print debug messages - set to 0xf to enable all msgs 1741991Sheppo */ 1751991Sheppo int _vnet_dbglevel = 0x8; 1761991Sheppo 1771991Sheppo void 1781991Sheppo _vnetdebug_printf(void *arg, const char *fmt, ...) 1791991Sheppo { 1801991Sheppo char buf[512]; 1811991Sheppo va_list ap; 1821991Sheppo vnet_t *vnetp = (vnet_t *)arg; 1831991Sheppo 1841991Sheppo va_start(ap, fmt); 1851991Sheppo (void) vsprintf(buf, fmt, ap); 1861991Sheppo va_end(ap); 1871991Sheppo 1881991Sheppo if (vnetp == NULL) 1891991Sheppo cmn_err(CE_CONT, "%s\n", buf); 1901991Sheppo else 1911991Sheppo cmn_err(CE_CONT, "vnet%d: %s\n", vnetp->instance, buf); 1921991Sheppo } 1931991Sheppo 1941991Sheppo #ifdef DEBUG 1951991Sheppo 1961991Sheppo /* 1972793Slm66018 * NOTE: any changes to the definitions below need corresponding changes in 1981991Sheppo * vnet_gen.c 1991991Sheppo */ 2001991Sheppo 2011991Sheppo /* 2021991Sheppo * debug levels: 2031991Sheppo * DBG_LEVEL1: Function entry/exit tracing 2041991Sheppo * DBG_LEVEL2: Info messages 2051991Sheppo * DBG_LEVEL3: Warning messages 2061991Sheppo * DBG_LEVEL4: Error messages 2071991Sheppo */ 2081991Sheppo 2091991Sheppo enum { DBG_LEVEL1 = 0x01, DBG_LEVEL2 = 0x02, DBG_LEVEL3 = 0x04, 2101991Sheppo DBG_LEVEL4 = 0x08 }; 2111991Sheppo 2121991Sheppo #define DBG1(_s) do { \ 2131991Sheppo if ((_vnet_dbglevel & DBG_LEVEL1) != 0) { \ 2141991Sheppo _vnetdebug_printf _s; \ 2151991Sheppo } \ 2161991Sheppo _NOTE(CONSTCOND) } while (0) 2171991Sheppo 2181991Sheppo #define DBG2(_s) do { \ 2191991Sheppo if ((_vnet_dbglevel & DBG_LEVEL2) != 0) { \ 2201991Sheppo _vnetdebug_printf _s; \ 2211991Sheppo } \ 2221991Sheppo _NOTE(CONSTCOND) } while (0) 2231991Sheppo 2241991Sheppo #define DWARN(_s) do { \ 2251991Sheppo if ((_vnet_dbglevel & DBG_LEVEL3) != 0) { \ 2261991Sheppo _vnetdebug_printf _s; \ 2271991Sheppo } \ 2281991Sheppo _NOTE(CONSTCOND) } while (0) 2291991Sheppo 2301991Sheppo #define DERR(_s) do { \ 2311991Sheppo if ((_vnet_dbglevel & DBG_LEVEL4) != 0) { \ 2321991Sheppo _vnetdebug_printf _s; \ 2331991Sheppo } \ 2341991Sheppo _NOTE(CONSTCOND) } while (0) 2351991Sheppo 2361991Sheppo #else 2371991Sheppo 2381991Sheppo #define DBG1(_s) if (0) _vnetdebug_printf _s 2391991Sheppo #define DBG2(_s) if (0) _vnetdebug_printf _s 2401991Sheppo #define DWARN(_s) if (0) _vnetdebug_printf _s 2411991Sheppo #define DERR(_s) if (0) _vnetdebug_printf _s 2421991Sheppo 2431991Sheppo #endif 2441991Sheppo 2451991Sheppo /* _init(9E): initialize the loadable module */ 2461991Sheppo int 2471991Sheppo _init(void) 2481991Sheppo { 2491991Sheppo int status; 2501991Sheppo 2511991Sheppo DBG1((NULL, "_init: enter\n")); 2521991Sheppo 2531991Sheppo mac_init_ops(&vnetops, "vnet"); 2541991Sheppo status = mod_install(&modlinkage); 2551991Sheppo if (status != 0) { 2561991Sheppo mac_fini_ops(&vnetops); 2571991Sheppo } 2581991Sheppo 2591991Sheppo DBG1((NULL, "_init: exit\n")); 2601991Sheppo return (status); 2611991Sheppo } 2621991Sheppo 2631991Sheppo /* _fini(9E): prepare the module for unloading. */ 2641991Sheppo int 2651991Sheppo _fini(void) 2661991Sheppo { 2671991Sheppo int status; 2681991Sheppo 2691991Sheppo DBG1((NULL, "_fini: enter\n")); 2701991Sheppo 2711991Sheppo status = mod_remove(&modlinkage); 2721991Sheppo if (status != 0) 2731991Sheppo return (status); 2741991Sheppo mac_fini_ops(&vnetops); 2751991Sheppo 2761991Sheppo DBG1((NULL, "_fini: exit\n")); 2771991Sheppo return (status); 2781991Sheppo } 2791991Sheppo 2801991Sheppo /* _info(9E): return information about the loadable module */ 2811991Sheppo int 2821991Sheppo _info(struct modinfo *modinfop) 2831991Sheppo { 2841991Sheppo return (mod_info(&modlinkage, modinfop)); 2851991Sheppo } 2861991Sheppo 2871991Sheppo /* 2881991Sheppo * attach(9E): attach a device to the system. 2891991Sheppo * called once for each instance of the device on the system. 2901991Sheppo */ 2911991Sheppo static int 2921991Sheppo vnetattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2931991Sheppo { 2941991Sheppo vnet_t *vnetp; 2951991Sheppo vp_tl_t *vp_tlp; 2961991Sheppo int instance; 2971991Sheppo int status; 2981991Sheppo enum { AST_init = 0x0, AST_vnet_alloc = 0x1, 2992336Snarayan AST_mac_alloc = 0x2, AST_read_macaddr = 0x4, 3002336Snarayan AST_vgen_init = 0x8, AST_vptl_alloc = 0x10, 3012336Snarayan AST_fdbh_alloc = 0x20 } 3021991Sheppo attach_state; 3032311Sseb mac_register_t *vgenmacp = NULL; 3041991Sheppo uint32_t nfdbh = 0; 3051991Sheppo 3061991Sheppo attach_state = AST_init; 3071991Sheppo 3081991Sheppo switch (cmd) { 3091991Sheppo case DDI_ATTACH: 3101991Sheppo break; 3111991Sheppo case DDI_RESUME: 3121991Sheppo case DDI_PM_RESUME: 3131991Sheppo default: 3141991Sheppo goto vnet_attach_fail; 3151991Sheppo } 3161991Sheppo 3171991Sheppo instance = ddi_get_instance(dip); 3181991Sheppo DBG1((NULL, "vnetattach: instance(%d) enter\n", instance)); 3191991Sheppo 3201991Sheppo /* allocate vnet_t and mac_t structures */ 3211991Sheppo vnetp = kmem_zalloc(sizeof (vnet_t), KM_SLEEP); 3221991Sheppo attach_state |= AST_vnet_alloc; 3231991Sheppo 3241991Sheppo /* setup links to vnet_t from both devinfo and mac_t */ 3251991Sheppo ddi_set_driver_private(dip, (caddr_t)vnetp); 3261991Sheppo vnetp->dip = dip; 3271991Sheppo vnetp->instance = instance; 3281991Sheppo 3291991Sheppo /* read the mac address */ 3301991Sheppo status = vnet_read_mac_address(vnetp); 3311991Sheppo if (status != DDI_SUCCESS) { 3321991Sheppo goto vnet_attach_fail; 3331991Sheppo } 3341991Sheppo attach_state |= AST_read_macaddr; 3351991Sheppo 3361991Sheppo /* 3371991Sheppo * Initialize the generic vnet proxy transport. This is the first 3381991Sheppo * and default transport used by vnet. The generic transport 3391991Sheppo * is provided by using sun4v LDC (logical domain channel). On success, 3401991Sheppo * vgen_init() provides a pointer to mac_t of generic transport. 3411991Sheppo * Currently, this generic layer provides network connectivity to other 3421991Sheppo * vnets within ldoms and also to remote hosts oustide ldoms through 3431991Sheppo * the virtual switch (vsw) device on domain0. In the future, when 3441991Sheppo * physical adapters that are able to share their resources (such as 3451991Sheppo * dma channels) with guest domains become available, the vnet device 3461991Sheppo * will use hardware specific driver to communicate directly over the 3471991Sheppo * physical device to reach remote hosts without going through vswitch. 3481991Sheppo */ 3492311Sseb status = vgen_init(vnetp, vnetp->dip, (uint8_t *)vnetp->curr_macaddr, 3502311Sseb &vgenmacp); 3511991Sheppo if (status != DDI_SUCCESS) { 3521991Sheppo DERR((vnetp, "vgen_init() failed\n")); 3531991Sheppo goto vnet_attach_fail; 3541991Sheppo } 3551991Sheppo attach_state |= AST_vgen_init; 3561991Sheppo 3571991Sheppo vp_tlp = kmem_zalloc(sizeof (vp_tl_t), KM_SLEEP); 3581991Sheppo vp_tlp->macp = vgenmacp; 3591991Sheppo (void) snprintf(vp_tlp->name, MAXNAMELEN, "%s%u", "vgen", instance); 3601991Sheppo (void) strcpy(vnetp->vgen_name, vp_tlp->name); 3611991Sheppo 3621991Sheppo /* add generic transport to the list of vnet proxy transports */ 3631991Sheppo vnet_add_vptl(vnetp, vp_tlp); 3641991Sheppo attach_state |= AST_vptl_alloc; 3651991Sheppo 3661991Sheppo nfdbh = vnet_nfdb_hash; 3671991Sheppo if ((nfdbh < VNET_NFDB_HASH) || (nfdbh > VNET_NFDB_HASH_MAX)) { 3681991Sheppo vnetp->nfdb_hash = VNET_NFDB_HASH; 3691991Sheppo } 3701991Sheppo else 3711991Sheppo vnetp->nfdb_hash = nfdbh; 3721991Sheppo 3731991Sheppo /* allocate fdb hash table, with an extra slot for default route */ 3741991Sheppo vnetp->fdbhp = kmem_zalloc(sizeof (fdb_fanout_t) * 3751991Sheppo (vnetp->nfdb_hash + 1), KM_SLEEP); 3761991Sheppo attach_state |= AST_fdbh_alloc; 3771991Sheppo 3781991Sheppo /* register with MAC layer */ 3791991Sheppo status = vnet_mac_register(vnetp); 3801991Sheppo if (status != DDI_SUCCESS) { 3811991Sheppo goto vnet_attach_fail; 3821991Sheppo } 3831991Sheppo 3841991Sheppo /* add to the list of vnet devices */ 3851991Sheppo WRITE_ENTER(&vnet_rw); 3861991Sheppo vnetp->nextp = vnet_headp; 3871991Sheppo vnet_headp = vnetp; 3881991Sheppo RW_EXIT(&vnet_rw); 3891991Sheppo 3901991Sheppo DBG1((NULL, "vnetattach: instance(%d) exit\n", instance)); 3911991Sheppo return (DDI_SUCCESS); 3921991Sheppo 3931991Sheppo vnet_attach_fail: 3941991Sheppo if (attach_state & AST_fdbh_alloc) { 3951991Sheppo kmem_free(vnetp->fdbhp, 3961991Sheppo sizeof (fdb_fanout_t) * (vnetp->nfdb_hash + 1)); 3971991Sheppo } 3981991Sheppo if (attach_state & AST_vptl_alloc) { 3991991Sheppo WRITE_ENTER(&vnetp->trwlock); 4001991Sheppo vnet_del_vptl(vnetp, vp_tlp); 4011991Sheppo RW_EXIT(&vnetp->trwlock); 4021991Sheppo } 4031991Sheppo if (attach_state & AST_vgen_init) { 4042336Snarayan (void) vgen_uninit(vgenmacp->m_driver); 4051991Sheppo } 4061991Sheppo if (attach_state & AST_vnet_alloc) { 4071991Sheppo KMEM_FREE(vnetp); 4081991Sheppo } 4091991Sheppo return (DDI_FAILURE); 4101991Sheppo } 4111991Sheppo 4121991Sheppo /* 4131991Sheppo * detach(9E): detach a device from the system. 4141991Sheppo */ 4151991Sheppo static int 4161991Sheppo vnetdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4171991Sheppo { 4181991Sheppo vnet_t *vnetp; 4191991Sheppo vnet_t **vnetpp; 4201991Sheppo vp_tl_t *vp_tlp; 4211991Sheppo int instance; 4222336Snarayan int rv; 4231991Sheppo 4241991Sheppo instance = ddi_get_instance(dip); 4251991Sheppo DBG1((NULL, "vnetdetach: instance(%d) enter\n", instance)); 4261991Sheppo 4271991Sheppo vnetp = ddi_get_driver_private(dip); 4281991Sheppo if (vnetp == NULL) { 4291991Sheppo goto vnet_detach_fail; 4301991Sheppo } 4311991Sheppo 4321991Sheppo switch (cmd) { 4331991Sheppo case DDI_DETACH: 4341991Sheppo break; 4351991Sheppo case DDI_SUSPEND: 4361991Sheppo case DDI_PM_SUSPEND: 4371991Sheppo default: 4381991Sheppo goto vnet_detach_fail; 4391991Sheppo } 4401991Sheppo 4412336Snarayan /* uninit and free vnet proxy transports */ 4422336Snarayan WRITE_ENTER(&vnetp->trwlock); 4432336Snarayan while ((vp_tlp = vnetp->tlp) != NULL) { 4442336Snarayan if (strcmp(vnetp->vgen_name, vp_tlp->name) == 0) { 4452336Snarayan /* uninitialize generic transport */ 4462336Snarayan rv = vgen_uninit(vp_tlp->macp->m_driver); 4472336Snarayan if (rv != DDI_SUCCESS) { 4482336Snarayan RW_EXIT(&vnetp->trwlock); 4492336Snarayan goto vnet_detach_fail; 4502336Snarayan } 4512336Snarayan } 4522336Snarayan vnet_del_vptl(vnetp, vp_tlp); 4532336Snarayan } 4542336Snarayan RW_EXIT(&vnetp->trwlock); 4552336Snarayan 4561991Sheppo /* 4571991Sheppo * Unregister from the MAC subsystem. This can fail, in 4581991Sheppo * particular if there are DLPI style-2 streams still open - 4591991Sheppo * in which case we just return failure. 4601991Sheppo */ 4612311Sseb if (mac_unregister(vnetp->mh) != 0) 4621991Sheppo goto vnet_detach_fail; 4631991Sheppo 4641991Sheppo /* unlink from instance(vnet_t) list */ 4651991Sheppo WRITE_ENTER(&vnet_rw); 4661991Sheppo for (vnetpp = &vnet_headp; *vnetpp; vnetpp = &(*vnetpp)->nextp) { 4671991Sheppo if (*vnetpp == vnetp) { 4681991Sheppo *vnetpp = vnetp->nextp; 4691991Sheppo break; 4701991Sheppo } 4711991Sheppo } 4721991Sheppo RW_EXIT(&vnet_rw); 4731991Sheppo 474*3297Ssb155480 kmem_free(vnetp->fdbhp, 475*3297Ssb155480 sizeof (fdb_fanout_t) * (vnetp->nfdb_hash + 1)); 476*3297Ssb155480 4771991Sheppo KMEM_FREE(vnetp); 4781991Sheppo 4791991Sheppo return (DDI_SUCCESS); 4801991Sheppo 4811991Sheppo vnet_detach_fail: 4821991Sheppo return (DDI_FAILURE); 4831991Sheppo } 4841991Sheppo 4851991Sheppo /* enable the device for transmit/receive */ 4861991Sheppo static int 4871991Sheppo vnet_m_start(void *arg) 4881991Sheppo { 4891991Sheppo vnet_t *vnetp = arg; 4901991Sheppo vp_tl_t *vp_tlp; 4912311Sseb mac_register_t *vp_macp; 4922311Sseb mac_callbacks_t *cbp; 4931991Sheppo 4941991Sheppo DBG1((vnetp, "vnet_m_start: enter\n")); 4951991Sheppo 4961991Sheppo /* 4972793Slm66018 * NOTE: 4981991Sheppo * Currently, we only have generic transport. m_start() invokes 4991991Sheppo * vgen_start() which enables ports/channels in vgen and 5001991Sheppo * initiates handshake with peer vnets and vsw. In the future when we 5011991Sheppo * have support for hardware specific transports, this information 5021991Sheppo * needs to be propagted back to vnet from vgen and we need to revisit 5031991Sheppo * this code (see comments in vnet_attach()). 5041991Sheppo * 5051991Sheppo */ 5061991Sheppo WRITE_ENTER(&vnetp->trwlock); 5071991Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 5081991Sheppo vp_macp = vp_tlp->macp; 5092311Sseb cbp = vp_macp->m_callbacks; 5102311Sseb cbp->mc_start(vp_macp->m_driver); 5111991Sheppo } 5121991Sheppo RW_EXIT(&vnetp->trwlock); 5131991Sheppo 5141991Sheppo DBG1((vnetp, "vnet_m_start: exit\n")); 5151991Sheppo return (VNET_SUCCESS); 5161991Sheppo 5171991Sheppo } 5181991Sheppo 5191991Sheppo /* stop transmit/receive for the device */ 5201991Sheppo static void 5211991Sheppo vnet_m_stop(void *arg) 5221991Sheppo { 5231991Sheppo vnet_t *vnetp = arg; 5241991Sheppo vp_tl_t *vp_tlp; 5252311Sseb mac_register_t *vp_macp; 5262311Sseb mac_callbacks_t *cbp; 5271991Sheppo 5281991Sheppo DBG1((vnetp, "vnet_m_stop: enter\n")); 5291991Sheppo 5301991Sheppo WRITE_ENTER(&vnetp->trwlock); 5311991Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 5321991Sheppo vp_macp = vp_tlp->macp; 5332311Sseb cbp = vp_macp->m_callbacks; 5342311Sseb cbp->mc_stop(vp_macp->m_driver); 5351991Sheppo } 5361991Sheppo RW_EXIT(&vnetp->trwlock); 5371991Sheppo 5381991Sheppo DBG1((vnetp, "vnet_m_stop: exit\n")); 5391991Sheppo } 5401991Sheppo 5411991Sheppo /* set the unicast mac address of the device */ 5421991Sheppo static int 5431991Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr) 5441991Sheppo { 5451991Sheppo _NOTE(ARGUNUSED(macaddr)) 5461991Sheppo 5471991Sheppo vnet_t *vnetp = arg; 5481991Sheppo 5491991Sheppo DBG1((vnetp, "vnet_m_unicst: enter\n")); 5501991Sheppo /* 5512793Slm66018 * NOTE: setting mac address dynamically is not supported. 5521991Sheppo */ 5531991Sheppo DBG1((vnetp, "vnet_m_unicst: exit\n")); 5541991Sheppo 5552109Slm66018 return (VNET_FAILURE); 5561991Sheppo } 5571991Sheppo 5581991Sheppo /* enable/disable a multicast address */ 5591991Sheppo static int 5601991Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 5611991Sheppo { 5621991Sheppo _NOTE(ARGUNUSED(add, mca)) 5631991Sheppo 5641991Sheppo vnet_t *vnetp = arg; 5651991Sheppo vp_tl_t *vp_tlp; 5662311Sseb mac_register_t *vp_macp; 5672311Sseb mac_callbacks_t *cbp; 5681991Sheppo int rv = VNET_SUCCESS; 5691991Sheppo 5701991Sheppo DBG1((vnetp, "vnet_m_multicst: enter\n")); 5711991Sheppo READ_ENTER(&vnetp->trwlock); 5721991Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 5731991Sheppo if (strcmp(vnetp->vgen_name, vp_tlp->name) == 0) { 5741991Sheppo vp_macp = vp_tlp->macp; 5752311Sseb cbp = vp_macp->m_callbacks; 5762311Sseb rv = cbp->mc_multicst(vp_macp->m_driver, add, mca); 5771991Sheppo break; 5781991Sheppo } 5791991Sheppo } 5801991Sheppo RW_EXIT(&vnetp->trwlock); 5811991Sheppo DBG1((vnetp, "vnet_m_multicst: exit\n")); 5821991Sheppo return (rv); 5831991Sheppo } 5841991Sheppo 5851991Sheppo /* set or clear promiscuous mode on the device */ 5861991Sheppo static int 5871991Sheppo vnet_m_promisc(void *arg, boolean_t on) 5881991Sheppo { 5891991Sheppo _NOTE(ARGUNUSED(on)) 5901991Sheppo 5911991Sheppo vnet_t *vnetp = arg; 5921991Sheppo DBG1((vnetp, "vnet_m_promisc: enter\n")); 5931991Sheppo /* 5942793Slm66018 * NOTE: setting promiscuous mode is not supported, just return success. 5951991Sheppo */ 5961991Sheppo DBG1((vnetp, "vnet_m_promisc: exit\n")); 5971991Sheppo return (VNET_SUCCESS); 5981991Sheppo } 5991991Sheppo 6001991Sheppo /* 6011991Sheppo * Transmit a chain of packets. This function provides switching functionality 6021991Sheppo * based on the destination mac address to reach other guests (within ldoms) or 6031991Sheppo * external hosts. 6041991Sheppo */ 6051991Sheppo mblk_t * 6061991Sheppo vnet_m_tx(void *arg, mblk_t *mp) 6071991Sheppo { 6081991Sheppo vnet_t *vnetp; 6091991Sheppo mblk_t *next; 6101991Sheppo uint32_t fdbhash; 6111991Sheppo fdb_t *fdbp; 6121991Sheppo fdb_fanout_t *fdbhp; 6131991Sheppo struct ether_header *ehp; 6141991Sheppo uint8_t *macaddr; 6151991Sheppo mblk_t *resid_mp; 6161991Sheppo 6171991Sheppo vnetp = (vnet_t *)arg; 6181991Sheppo DBG1((vnetp, "vnet_m_tx: enter\n")); 6191991Sheppo ASSERT(mp != NULL); 6201991Sheppo 6211991Sheppo while (mp != NULL) { 6221991Sheppo next = mp->b_next; 6231991Sheppo mp->b_next = NULL; 6241991Sheppo 6251991Sheppo /* get the destination mac address in the eth header */ 6261991Sheppo ehp = (struct ether_header *)mp->b_rptr; 6271991Sheppo macaddr = (uint8_t *)&ehp->ether_dhost; 6281991Sheppo 6291991Sheppo /* Calculate hash value and fdb fanout */ 6301991Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 6311991Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 6321991Sheppo 6331991Sheppo READ_ENTER(&fdbhp->rwlock); 6341991Sheppo fdbp = vnet_lookup_fdb(fdbhp, macaddr); 6351991Sheppo if (fdbp) { 6361991Sheppo /* 6371991Sheppo * If the destination is in FDB, the destination is 6381991Sheppo * a vnet device within ldoms and directly reachable, 6391991Sheppo * invoke the tx function in the fdb entry. 6401991Sheppo */ 6411991Sheppo resid_mp = fdbp->m_tx(fdbp->txarg, mp); 6421991Sheppo if (resid_mp != NULL) { 6431991Sheppo /* m_tx failed */ 6441991Sheppo mp->b_next = next; 6451991Sheppo RW_EXIT(&fdbhp->rwlock); 6461991Sheppo break; 6471991Sheppo } 6481991Sheppo RW_EXIT(&fdbhp->rwlock); 6491991Sheppo } else { 6501991Sheppo /* destination is not in FDB */ 6511991Sheppo RW_EXIT(&fdbhp->rwlock); 6521991Sheppo /* 6531991Sheppo * If the destination is broadcast/multicast 6541991Sheppo * or an unknown unicast address, forward the 6551991Sheppo * packet to vsw, using the last slot in fdb which is 6561991Sheppo * reserved for default route. 6571991Sheppo */ 6581991Sheppo fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]); 6591991Sheppo READ_ENTER(&fdbhp->rwlock); 6601991Sheppo fdbp = fdbhp->headp; 6611991Sheppo if (fdbp) { 6621991Sheppo resid_mp = fdbp->m_tx(fdbp->txarg, mp); 6631991Sheppo if (resid_mp != NULL) { 6641991Sheppo /* m_tx failed */ 6651991Sheppo mp->b_next = next; 6661991Sheppo RW_EXIT(&fdbhp->rwlock); 6671991Sheppo break; 6681991Sheppo } 6691991Sheppo } else { 6701991Sheppo /* drop the packet */ 6711991Sheppo freemsg(mp); 6721991Sheppo } 6731991Sheppo RW_EXIT(&fdbhp->rwlock); 6741991Sheppo } 6751991Sheppo 6761991Sheppo mp = next; 6771991Sheppo } 6781991Sheppo 6791991Sheppo DBG1((vnetp, "vnet_m_tx: exit\n")); 6801991Sheppo return (mp); 6811991Sheppo } 6821991Sheppo 6832311Sseb /* get statistics from the device */ 6842311Sseb int 6852311Sseb vnet_m_stat(void *arg, uint_t stat, uint64_t *val) 6861991Sheppo { 6871991Sheppo vnet_t *vnetp = arg; 6881991Sheppo vp_tl_t *vp_tlp; 6892311Sseb mac_register_t *vp_macp; 6902311Sseb mac_callbacks_t *cbp; 6912311Sseb uint64_t val_total = 0; 6921991Sheppo 6931991Sheppo DBG1((vnetp, "vnet_m_stat: enter\n")); 6941991Sheppo 6951991Sheppo /* 6962311Sseb * get the specified statistic from each transport and return the 6972311Sseb * aggregate val. This obviously only works for counters. 6981991Sheppo */ 6992311Sseb if ((IS_MAC_STAT(stat) && !MAC_STAT_ISACOUNTER(stat)) || 7002311Sseb (IS_MACTYPE_STAT(stat) && !ETHER_STAT_ISACOUNTER(stat))) { 7012311Sseb return (ENOTSUP); 7022311Sseb } 7031991Sheppo READ_ENTER(&vnetp->trwlock); 7041991Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 7051991Sheppo vp_macp = vp_tlp->macp; 7062311Sseb cbp = vp_macp->m_callbacks; 7072311Sseb if (cbp->mc_getstat(vp_macp->m_driver, stat, val) == 0) 7082311Sseb val_total += *val; 7091991Sheppo } 7101991Sheppo RW_EXIT(&vnetp->trwlock); 7111991Sheppo 7122311Sseb *val = val_total; 7132311Sseb 7141991Sheppo DBG1((vnetp, "vnet_m_stat: exit\n")); 7152311Sseb return (0); 7161991Sheppo } 7171991Sheppo 7181991Sheppo /* wrapper function for mac_register() */ 7191991Sheppo static int 7201991Sheppo vnet_mac_register(vnet_t *vnetp) 7211991Sheppo { 7222311Sseb mac_register_t *macp; 7232311Sseb int err; 7241991Sheppo 7252311Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 7262311Sseb return (DDI_FAILURE); 7272311Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 7282311Sseb macp->m_driver = vnetp; 7291991Sheppo macp->m_dip = vnetp->dip; 7302311Sseb macp->m_src_addr = vnetp->curr_macaddr; 7312311Sseb macp->m_callbacks = &vnet_m_callbacks; 7322311Sseb macp->m_min_sdu = 0; 7332311Sseb macp->m_max_sdu = ETHERMTU; 7341991Sheppo 7351991Sheppo /* 7361991Sheppo * Finally, we're ready to register ourselves with the MAC layer 7371991Sheppo * interface; if this succeeds, we're all ready to start() 7381991Sheppo */ 7392311Sseb err = mac_register(macp, &vnetp->mh); 7402311Sseb mac_free(macp); 7412311Sseb return (err == 0 ? DDI_SUCCESS : DDI_FAILURE); 7421991Sheppo } 7431991Sheppo 7441991Sheppo /* add vp_tl to the list */ 7451991Sheppo static void 7461991Sheppo vnet_add_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp) 7471991Sheppo { 7481991Sheppo vp_tl_t *ttlp; 7491991Sheppo 7501991Sheppo WRITE_ENTER(&vnetp->trwlock); 7511991Sheppo if (vnetp->tlp == NULL) { 7521991Sheppo vnetp->tlp = vp_tlp; 7531991Sheppo } else { 7541991Sheppo ttlp = vnetp->tlp; 7551991Sheppo while (ttlp->nextp) 7561991Sheppo ttlp = ttlp->nextp; 7571991Sheppo ttlp->nextp = vp_tlp; 7581991Sheppo } 7591991Sheppo RW_EXIT(&vnetp->trwlock); 7601991Sheppo } 7611991Sheppo 7621991Sheppo /* remove vp_tl from the list */ 7631991Sheppo static void 7641991Sheppo vnet_del_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp) 7651991Sheppo { 7661991Sheppo vp_tl_t *ttlp, **pretlp; 7671991Sheppo boolean_t found = B_FALSE; 7681991Sheppo 7691991Sheppo pretlp = &vnetp->tlp; 7701991Sheppo ttlp = *pretlp; 7711991Sheppo while (ttlp) { 7721991Sheppo if (ttlp == vp_tlp) { 7731991Sheppo found = B_TRUE; 7741991Sheppo (*pretlp) = ttlp->nextp; 7751991Sheppo ttlp->nextp = NULL; 7761991Sheppo break; 7771991Sheppo } 7781991Sheppo pretlp = &(ttlp->nextp); 7791991Sheppo ttlp = *pretlp; 7801991Sheppo } 7811991Sheppo 7821991Sheppo if (found) { 7831991Sheppo KMEM_FREE(vp_tlp); 7841991Sheppo } 7851991Sheppo } 7861991Sheppo 7871991Sheppo /* get vp_tl corresponding to the given name */ 7881991Sheppo static vp_tl_t * 7891991Sheppo vnet_get_vptl(vnet_t *vnetp, const char *name) 7901991Sheppo { 7911991Sheppo vp_tl_t *tlp; 7921991Sheppo 7931991Sheppo tlp = vnetp->tlp; 7941991Sheppo while (tlp) { 7951991Sheppo if (strcmp(tlp->name, name) == 0) { 7961991Sheppo return (tlp); 7971991Sheppo } 7981991Sheppo tlp = tlp->nextp; 7991991Sheppo } 8001991Sheppo DWARN((vnetp, 8011991Sheppo "vnet_get_vptl: can't find vp_tl with name (%s)\n", name)); 8021991Sheppo return (NULL); 8031991Sheppo } 8041991Sheppo 8051991Sheppo /* read the mac address of the device */ 8061991Sheppo static int 8071991Sheppo vnet_read_mac_address(vnet_t *vnetp) 8081991Sheppo { 8091991Sheppo uchar_t *macaddr; 8101991Sheppo uint32_t size; 8111991Sheppo int rv; 8121991Sheppo 8131991Sheppo rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip, 8141991Sheppo DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size); 8151991Sheppo if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) { 8161991Sheppo DWARN((vnetp, 8171991Sheppo "vnet_read_mac_address: prop_lookup failed (%s) err (%d)\n", 8181991Sheppo macaddr_propname, rv)); 8191991Sheppo return (DDI_FAILURE); 8201991Sheppo } 8211991Sheppo bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL); 8221991Sheppo bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL); 8231991Sheppo ddi_prop_free(macaddr); 8241991Sheppo 8251991Sheppo return (DDI_SUCCESS); 8261991Sheppo } 8271991Sheppo 8281991Sheppo 8291991Sheppo /* 8301991Sheppo * Functions below are called only by generic transport to add/remove/modify 8311991Sheppo * entries in forwarding database. See comments in vgen_port_init(vnet_gen.c). 8321991Sheppo */ 8331991Sheppo 8341991Sheppo /* add an entry into the forwarding database */ 8351991Sheppo void 8361991Sheppo vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg) 8371991Sheppo { 8381991Sheppo vnet_t *vnetp = (vnet_t *)arg; 8391991Sheppo uint32_t fdbhash; 8401991Sheppo fdb_t *fdbp; 8411991Sheppo fdb_fanout_t *fdbhp; 8421991Sheppo 8431991Sheppo /* Calculate hash value and fdb fanout */ 8441991Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 8451991Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 8461991Sheppo 8471991Sheppo WRITE_ENTER(&fdbhp->rwlock); 8481991Sheppo 8491991Sheppo fdbp = kmem_zalloc(sizeof (fdb_t), KM_NOSLEEP); 8501991Sheppo if (fdbp == NULL) { 8511991Sheppo RW_EXIT(&fdbhp->rwlock); 8521991Sheppo return; 8531991Sheppo } 8541991Sheppo bcopy(macaddr, (caddr_t)fdbp->macaddr, ETHERADDRL); 8551991Sheppo fdbp->m_tx = m_tx; 8561991Sheppo fdbp->txarg = txarg; 8571991Sheppo fdbp->nextp = fdbhp->headp; 8581991Sheppo fdbhp->headp = fdbp; 8591991Sheppo 8601991Sheppo RW_EXIT(&fdbhp->rwlock); 8611991Sheppo } 8621991Sheppo 8631991Sheppo /* delete an entry from the forwarding database */ 8641991Sheppo void 8651991Sheppo vnet_del_fdb(void *arg, uint8_t *macaddr) 8661991Sheppo { 8671991Sheppo vnet_t *vnetp = (vnet_t *)arg; 8681991Sheppo uint32_t fdbhash; 8691991Sheppo fdb_t *fdbp; 8701991Sheppo fdb_t **pfdbp; 8711991Sheppo fdb_fanout_t *fdbhp; 8721991Sheppo 8731991Sheppo /* Calculate hash value and fdb fanout */ 8741991Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 8751991Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 8761991Sheppo 8771991Sheppo WRITE_ENTER(&fdbhp->rwlock); 8781991Sheppo 8791991Sheppo for (pfdbp = &fdbhp->headp; (fdbp = *pfdbp) != NULL; 8801991Sheppo pfdbp = &fdbp->nextp) { 8811991Sheppo if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) { 8821991Sheppo /* Unlink it from the list */ 8831991Sheppo *pfdbp = fdbp->nextp; 8841991Sheppo KMEM_FREE(fdbp); 8851991Sheppo break; 8861991Sheppo } 8871991Sheppo } 8881991Sheppo 8891991Sheppo RW_EXIT(&fdbhp->rwlock); 8901991Sheppo } 8911991Sheppo 8921991Sheppo /* modify an existing entry in the forwarding database */ 8931991Sheppo void 8942793Slm66018 vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg, 8952793Slm66018 boolean_t upgrade) 8961991Sheppo { 8971991Sheppo vnet_t *vnetp = (vnet_t *)arg; 8981991Sheppo uint32_t fdbhash; 8991991Sheppo fdb_t *fdbp; 9001991Sheppo fdb_fanout_t *fdbhp; 9011991Sheppo 9021991Sheppo /* Calculate hash value and fdb fanout */ 9031991Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 9041991Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 9051991Sheppo 9062793Slm66018 if (upgrade == B_TRUE) { 9072793Slm66018 /* 9082793Slm66018 * Caller already holds the lock as a reader. This can 9092793Slm66018 * occur if this function is invoked in the context 9102793Slm66018 * of transmit routine - vnet_m_tx(), where the lock 9112793Slm66018 * is held as a reader before calling the transmit 9122793Slm66018 * function of an fdb entry (fdbp->m_tx). 9132793Slm66018 * See comments in vgen_ldcsend() in vnet_gen.c 9142793Slm66018 */ 9152793Slm66018 if (!rw_tryupgrade(&fdbhp->rwlock)) { 9162793Slm66018 RW_EXIT(&fdbhp->rwlock); 9172793Slm66018 WRITE_ENTER(&fdbhp->rwlock); 9182793Slm66018 } 9192793Slm66018 } else { 9202793Slm66018 /* Caller does not hold the lock */ 9212793Slm66018 WRITE_ENTER(&fdbhp->rwlock); 9222793Slm66018 } 9231991Sheppo 9241991Sheppo for (fdbp = fdbhp->headp; fdbp != NULL; fdbp = fdbp->nextp) { 9251991Sheppo if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) { 9261991Sheppo /* change the entry to have new tx params */ 9271991Sheppo fdbp->m_tx = m_tx; 9281991Sheppo fdbp->txarg = txarg; 9291991Sheppo break; 9301991Sheppo } 9311991Sheppo } 9321991Sheppo 9332793Slm66018 if (upgrade == B_TRUE) { 9342793Slm66018 /* restore the caller as a reader */ 9352793Slm66018 rw_downgrade(&fdbhp->rwlock); 9362793Slm66018 } else { 9372793Slm66018 RW_EXIT(&fdbhp->rwlock); 9382793Slm66018 } 9391991Sheppo } 9401991Sheppo 9411991Sheppo /* look up an fdb entry based on the mac address, caller holds lock */ 9421991Sheppo static fdb_t * 9431991Sheppo vnet_lookup_fdb(fdb_fanout_t *fdbhp, uint8_t *macaddr) 9441991Sheppo { 9451991Sheppo fdb_t *fdbp = NULL; 9461991Sheppo 9471991Sheppo for (fdbp = fdbhp->headp; fdbp != NULL; fdbp = fdbp->nextp) { 9481991Sheppo if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) { 9491991Sheppo break; 9501991Sheppo } 9511991Sheppo } 9521991Sheppo 9531991Sheppo return (fdbp); 9541991Sheppo } 9551991Sheppo 9561991Sheppo /* add default route entry into the forwarding database */ 9571991Sheppo void 9581991Sheppo vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg) 9591991Sheppo { 9601991Sheppo vnet_t *vnetp = (vnet_t *)arg; 9611991Sheppo fdb_t *fdbp; 9621991Sheppo fdb_fanout_t *fdbhp; 9631991Sheppo 9641991Sheppo /* 9651991Sheppo * The last hash list is reserved for default route entry, 9661991Sheppo * and for now, we have only one entry in this list. 9671991Sheppo */ 9681991Sheppo fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]); 9691991Sheppo 9701991Sheppo WRITE_ENTER(&fdbhp->rwlock); 9711991Sheppo 9721991Sheppo if (fdbhp->headp) { 9731991Sheppo DWARN((vnetp, 9741991Sheppo "vnet_add_def_rte: default rte already exists\n")); 9751991Sheppo RW_EXIT(&fdbhp->rwlock); 9761991Sheppo return; 9771991Sheppo } 9781991Sheppo fdbp = kmem_zalloc(sizeof (fdb_t), KM_NOSLEEP); 9791991Sheppo if (fdbp == NULL) { 9801991Sheppo RW_EXIT(&fdbhp->rwlock); 9811991Sheppo return; 9821991Sheppo } 9831991Sheppo bzero(fdbp->macaddr, ETHERADDRL); 9841991Sheppo fdbp->m_tx = m_tx; 9851991Sheppo fdbp->txarg = txarg; 9861991Sheppo fdbp->nextp = NULL; 9871991Sheppo fdbhp->headp = fdbp; 9881991Sheppo 9891991Sheppo RW_EXIT(&fdbhp->rwlock); 9901991Sheppo } 9911991Sheppo 9921991Sheppo /* delete default route entry from the forwarding database */ 9931991Sheppo void 9941991Sheppo vnet_del_def_rte(void *arg) 9951991Sheppo { 9961991Sheppo vnet_t *vnetp = (vnet_t *)arg; 9971991Sheppo fdb_t *fdbp; 9981991Sheppo fdb_fanout_t *fdbhp; 9991991Sheppo 10001991Sheppo /* 10011991Sheppo * The last hash list is reserved for default route entry, 10021991Sheppo * and for now, we have only one entry in this list. 10031991Sheppo */ 10041991Sheppo fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]); 10051991Sheppo 10061991Sheppo WRITE_ENTER(&fdbhp->rwlock); 10071991Sheppo 10081991Sheppo if (fdbhp->headp == NULL) { 10091991Sheppo RW_EXIT(&fdbhp->rwlock); 10101991Sheppo return; 10111991Sheppo } 10121991Sheppo fdbp = fdbhp->headp; 10131991Sheppo KMEM_FREE(fdbp); 10141991Sheppo fdbhp->headp = NULL; 10151991Sheppo 10161991Sheppo RW_EXIT(&fdbhp->rwlock); 10171991Sheppo } 10182311Sseb 10192311Sseb void 10202311Sseb vnet_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp) 10212311Sseb { 10222311Sseb vnet_t *vnetp = arg; 10232311Sseb mac_rx(vnetp->mh, mrh, mp); 10242311Sseb } 10252311Sseb 10262311Sseb void 10272311Sseb vnet_tx_update(void *arg) 10282311Sseb { 10292311Sseb vnet_t *vnetp = arg; 10302311Sseb mac_tx_update(vnetp->mh); 10312311Sseb } 1032