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); 80*2793Slm66018 void vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, 81*2793Slm66018 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 /* 197*2793Slm66018 * 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 4741991Sheppo KMEM_FREE(vnetp); 4751991Sheppo 4761991Sheppo return (DDI_SUCCESS); 4771991Sheppo 4781991Sheppo vnet_detach_fail: 4791991Sheppo return (DDI_FAILURE); 4801991Sheppo } 4811991Sheppo 4821991Sheppo /* enable the device for transmit/receive */ 4831991Sheppo static int 4841991Sheppo vnet_m_start(void *arg) 4851991Sheppo { 4861991Sheppo vnet_t *vnetp = arg; 4871991Sheppo vp_tl_t *vp_tlp; 4882311Sseb mac_register_t *vp_macp; 4892311Sseb mac_callbacks_t *cbp; 4901991Sheppo 4911991Sheppo DBG1((vnetp, "vnet_m_start: enter\n")); 4921991Sheppo 4931991Sheppo /* 494*2793Slm66018 * NOTE: 4951991Sheppo * Currently, we only have generic transport. m_start() invokes 4961991Sheppo * vgen_start() which enables ports/channels in vgen and 4971991Sheppo * initiates handshake with peer vnets and vsw. In the future when we 4981991Sheppo * have support for hardware specific transports, this information 4991991Sheppo * needs to be propagted back to vnet from vgen and we need to revisit 5001991Sheppo * this code (see comments in vnet_attach()). 5011991Sheppo * 5021991Sheppo */ 5031991Sheppo WRITE_ENTER(&vnetp->trwlock); 5041991Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 5051991Sheppo vp_macp = vp_tlp->macp; 5062311Sseb cbp = vp_macp->m_callbacks; 5072311Sseb cbp->mc_start(vp_macp->m_driver); 5081991Sheppo } 5091991Sheppo RW_EXIT(&vnetp->trwlock); 5101991Sheppo 5111991Sheppo DBG1((vnetp, "vnet_m_start: exit\n")); 5121991Sheppo return (VNET_SUCCESS); 5131991Sheppo 5141991Sheppo } 5151991Sheppo 5161991Sheppo /* stop transmit/receive for the device */ 5171991Sheppo static void 5181991Sheppo vnet_m_stop(void *arg) 5191991Sheppo { 5201991Sheppo vnet_t *vnetp = arg; 5211991Sheppo vp_tl_t *vp_tlp; 5222311Sseb mac_register_t *vp_macp; 5232311Sseb mac_callbacks_t *cbp; 5241991Sheppo 5251991Sheppo DBG1((vnetp, "vnet_m_stop: enter\n")); 5261991Sheppo 5271991Sheppo WRITE_ENTER(&vnetp->trwlock); 5281991Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 5291991Sheppo vp_macp = vp_tlp->macp; 5302311Sseb cbp = vp_macp->m_callbacks; 5312311Sseb cbp->mc_stop(vp_macp->m_driver); 5321991Sheppo } 5331991Sheppo RW_EXIT(&vnetp->trwlock); 5341991Sheppo 5351991Sheppo DBG1((vnetp, "vnet_m_stop: exit\n")); 5361991Sheppo } 5371991Sheppo 5381991Sheppo /* set the unicast mac address of the device */ 5391991Sheppo static int 5401991Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr) 5411991Sheppo { 5421991Sheppo _NOTE(ARGUNUSED(macaddr)) 5431991Sheppo 5441991Sheppo vnet_t *vnetp = arg; 5451991Sheppo 5461991Sheppo DBG1((vnetp, "vnet_m_unicst: enter\n")); 5471991Sheppo /* 548*2793Slm66018 * NOTE: setting mac address dynamically is not supported. 5491991Sheppo */ 5501991Sheppo DBG1((vnetp, "vnet_m_unicst: exit\n")); 5511991Sheppo 5522109Slm66018 return (VNET_FAILURE); 5531991Sheppo } 5541991Sheppo 5551991Sheppo /* enable/disable a multicast address */ 5561991Sheppo static int 5571991Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 5581991Sheppo { 5591991Sheppo _NOTE(ARGUNUSED(add, mca)) 5601991Sheppo 5611991Sheppo vnet_t *vnetp = arg; 5621991Sheppo vp_tl_t *vp_tlp; 5632311Sseb mac_register_t *vp_macp; 5642311Sseb mac_callbacks_t *cbp; 5651991Sheppo int rv = VNET_SUCCESS; 5661991Sheppo 5671991Sheppo DBG1((vnetp, "vnet_m_multicst: enter\n")); 5681991Sheppo READ_ENTER(&vnetp->trwlock); 5691991Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 5701991Sheppo if (strcmp(vnetp->vgen_name, vp_tlp->name) == 0) { 5711991Sheppo vp_macp = vp_tlp->macp; 5722311Sseb cbp = vp_macp->m_callbacks; 5732311Sseb rv = cbp->mc_multicst(vp_macp->m_driver, add, mca); 5741991Sheppo break; 5751991Sheppo } 5761991Sheppo } 5771991Sheppo RW_EXIT(&vnetp->trwlock); 5781991Sheppo DBG1((vnetp, "vnet_m_multicst: exit\n")); 5791991Sheppo return (rv); 5801991Sheppo } 5811991Sheppo 5821991Sheppo /* set or clear promiscuous mode on the device */ 5831991Sheppo static int 5841991Sheppo vnet_m_promisc(void *arg, boolean_t on) 5851991Sheppo { 5861991Sheppo _NOTE(ARGUNUSED(on)) 5871991Sheppo 5881991Sheppo vnet_t *vnetp = arg; 5891991Sheppo DBG1((vnetp, "vnet_m_promisc: enter\n")); 5901991Sheppo /* 591*2793Slm66018 * NOTE: setting promiscuous mode is not supported, just return success. 5921991Sheppo */ 5931991Sheppo DBG1((vnetp, "vnet_m_promisc: exit\n")); 5941991Sheppo return (VNET_SUCCESS); 5951991Sheppo } 5961991Sheppo 5971991Sheppo /* 5981991Sheppo * Transmit a chain of packets. This function provides switching functionality 5991991Sheppo * based on the destination mac address to reach other guests (within ldoms) or 6001991Sheppo * external hosts. 6011991Sheppo */ 6021991Sheppo mblk_t * 6031991Sheppo vnet_m_tx(void *arg, mblk_t *mp) 6041991Sheppo { 6051991Sheppo vnet_t *vnetp; 6061991Sheppo mblk_t *next; 6071991Sheppo uint32_t fdbhash; 6081991Sheppo fdb_t *fdbp; 6091991Sheppo fdb_fanout_t *fdbhp; 6101991Sheppo struct ether_header *ehp; 6111991Sheppo uint8_t *macaddr; 6121991Sheppo mblk_t *resid_mp; 6131991Sheppo 6141991Sheppo vnetp = (vnet_t *)arg; 6151991Sheppo DBG1((vnetp, "vnet_m_tx: enter\n")); 6161991Sheppo ASSERT(mp != NULL); 6171991Sheppo 6181991Sheppo while (mp != NULL) { 6191991Sheppo next = mp->b_next; 6201991Sheppo mp->b_next = NULL; 6211991Sheppo 6221991Sheppo /* get the destination mac address in the eth header */ 6231991Sheppo ehp = (struct ether_header *)mp->b_rptr; 6241991Sheppo macaddr = (uint8_t *)&ehp->ether_dhost; 6251991Sheppo 6261991Sheppo /* Calculate hash value and fdb fanout */ 6271991Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 6281991Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 6291991Sheppo 6301991Sheppo READ_ENTER(&fdbhp->rwlock); 6311991Sheppo fdbp = vnet_lookup_fdb(fdbhp, macaddr); 6321991Sheppo if (fdbp) { 6331991Sheppo /* 6341991Sheppo * If the destination is in FDB, the destination is 6351991Sheppo * a vnet device within ldoms and directly reachable, 6361991Sheppo * invoke the tx function in the fdb entry. 6371991Sheppo */ 6381991Sheppo resid_mp = fdbp->m_tx(fdbp->txarg, mp); 6391991Sheppo if (resid_mp != NULL) { 6401991Sheppo /* m_tx failed */ 6411991Sheppo mp->b_next = next; 6421991Sheppo RW_EXIT(&fdbhp->rwlock); 6431991Sheppo break; 6441991Sheppo } 6451991Sheppo RW_EXIT(&fdbhp->rwlock); 6461991Sheppo } else { 6471991Sheppo /* destination is not in FDB */ 6481991Sheppo RW_EXIT(&fdbhp->rwlock); 6491991Sheppo /* 6501991Sheppo * If the destination is broadcast/multicast 6511991Sheppo * or an unknown unicast address, forward the 6521991Sheppo * packet to vsw, using the last slot in fdb which is 6531991Sheppo * reserved for default route. 6541991Sheppo */ 6551991Sheppo fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]); 6561991Sheppo READ_ENTER(&fdbhp->rwlock); 6571991Sheppo fdbp = fdbhp->headp; 6581991Sheppo if (fdbp) { 6591991Sheppo resid_mp = fdbp->m_tx(fdbp->txarg, mp); 6601991Sheppo if (resid_mp != NULL) { 6611991Sheppo /* m_tx failed */ 6621991Sheppo mp->b_next = next; 6631991Sheppo RW_EXIT(&fdbhp->rwlock); 6641991Sheppo break; 6651991Sheppo } 6661991Sheppo } else { 6671991Sheppo /* drop the packet */ 6681991Sheppo freemsg(mp); 6691991Sheppo } 6701991Sheppo RW_EXIT(&fdbhp->rwlock); 6711991Sheppo } 6721991Sheppo 6731991Sheppo mp = next; 6741991Sheppo } 6751991Sheppo 6761991Sheppo DBG1((vnetp, "vnet_m_tx: exit\n")); 6771991Sheppo return (mp); 6781991Sheppo } 6791991Sheppo 6802311Sseb /* get statistics from the device */ 6812311Sseb int 6822311Sseb vnet_m_stat(void *arg, uint_t stat, uint64_t *val) 6831991Sheppo { 6841991Sheppo vnet_t *vnetp = arg; 6851991Sheppo vp_tl_t *vp_tlp; 6862311Sseb mac_register_t *vp_macp; 6872311Sseb mac_callbacks_t *cbp; 6882311Sseb uint64_t val_total = 0; 6891991Sheppo 6901991Sheppo DBG1((vnetp, "vnet_m_stat: enter\n")); 6911991Sheppo 6921991Sheppo /* 6932311Sseb * get the specified statistic from each transport and return the 6942311Sseb * aggregate val. This obviously only works for counters. 6951991Sheppo */ 6962311Sseb if ((IS_MAC_STAT(stat) && !MAC_STAT_ISACOUNTER(stat)) || 6972311Sseb (IS_MACTYPE_STAT(stat) && !ETHER_STAT_ISACOUNTER(stat))) { 6982311Sseb return (ENOTSUP); 6992311Sseb } 7001991Sheppo READ_ENTER(&vnetp->trwlock); 7011991Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 7021991Sheppo vp_macp = vp_tlp->macp; 7032311Sseb cbp = vp_macp->m_callbacks; 7042311Sseb if (cbp->mc_getstat(vp_macp->m_driver, stat, val) == 0) 7052311Sseb val_total += *val; 7061991Sheppo } 7071991Sheppo RW_EXIT(&vnetp->trwlock); 7081991Sheppo 7092311Sseb *val = val_total; 7102311Sseb 7111991Sheppo DBG1((vnetp, "vnet_m_stat: exit\n")); 7122311Sseb return (0); 7131991Sheppo } 7141991Sheppo 7151991Sheppo /* wrapper function for mac_register() */ 7161991Sheppo static int 7171991Sheppo vnet_mac_register(vnet_t *vnetp) 7181991Sheppo { 7192311Sseb mac_register_t *macp; 7202311Sseb int err; 7211991Sheppo 7222311Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 7232311Sseb return (DDI_FAILURE); 7242311Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 7252311Sseb macp->m_driver = vnetp; 7261991Sheppo macp->m_dip = vnetp->dip; 7272311Sseb macp->m_src_addr = vnetp->curr_macaddr; 7282311Sseb macp->m_callbacks = &vnet_m_callbacks; 7292311Sseb macp->m_min_sdu = 0; 7302311Sseb macp->m_max_sdu = ETHERMTU; 7311991Sheppo 7321991Sheppo /* 7331991Sheppo * Finally, we're ready to register ourselves with the MAC layer 7341991Sheppo * interface; if this succeeds, we're all ready to start() 7351991Sheppo */ 7362311Sseb err = mac_register(macp, &vnetp->mh); 7372311Sseb mac_free(macp); 7382311Sseb return (err == 0 ? DDI_SUCCESS : DDI_FAILURE); 7391991Sheppo } 7401991Sheppo 7411991Sheppo /* add vp_tl to the list */ 7421991Sheppo static void 7431991Sheppo vnet_add_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp) 7441991Sheppo { 7451991Sheppo vp_tl_t *ttlp; 7461991Sheppo 7471991Sheppo WRITE_ENTER(&vnetp->trwlock); 7481991Sheppo if (vnetp->tlp == NULL) { 7491991Sheppo vnetp->tlp = vp_tlp; 7501991Sheppo } else { 7511991Sheppo ttlp = vnetp->tlp; 7521991Sheppo while (ttlp->nextp) 7531991Sheppo ttlp = ttlp->nextp; 7541991Sheppo ttlp->nextp = vp_tlp; 7551991Sheppo } 7561991Sheppo RW_EXIT(&vnetp->trwlock); 7571991Sheppo } 7581991Sheppo 7591991Sheppo /* remove vp_tl from the list */ 7601991Sheppo static void 7611991Sheppo vnet_del_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp) 7621991Sheppo { 7631991Sheppo vp_tl_t *ttlp, **pretlp; 7641991Sheppo boolean_t found = B_FALSE; 7651991Sheppo 7661991Sheppo pretlp = &vnetp->tlp; 7671991Sheppo ttlp = *pretlp; 7681991Sheppo while (ttlp) { 7691991Sheppo if (ttlp == vp_tlp) { 7701991Sheppo found = B_TRUE; 7711991Sheppo (*pretlp) = ttlp->nextp; 7721991Sheppo ttlp->nextp = NULL; 7731991Sheppo break; 7741991Sheppo } 7751991Sheppo pretlp = &(ttlp->nextp); 7761991Sheppo ttlp = *pretlp; 7771991Sheppo } 7781991Sheppo 7791991Sheppo if (found) { 7801991Sheppo KMEM_FREE(vp_tlp); 7811991Sheppo } 7821991Sheppo } 7831991Sheppo 7841991Sheppo /* get vp_tl corresponding to the given name */ 7851991Sheppo static vp_tl_t * 7861991Sheppo vnet_get_vptl(vnet_t *vnetp, const char *name) 7871991Sheppo { 7881991Sheppo vp_tl_t *tlp; 7891991Sheppo 7901991Sheppo tlp = vnetp->tlp; 7911991Sheppo while (tlp) { 7921991Sheppo if (strcmp(tlp->name, name) == 0) { 7931991Sheppo return (tlp); 7941991Sheppo } 7951991Sheppo tlp = tlp->nextp; 7961991Sheppo } 7971991Sheppo DWARN((vnetp, 7981991Sheppo "vnet_get_vptl: can't find vp_tl with name (%s)\n", name)); 7991991Sheppo return (NULL); 8001991Sheppo } 8011991Sheppo 8021991Sheppo /* read the mac address of the device */ 8031991Sheppo static int 8041991Sheppo vnet_read_mac_address(vnet_t *vnetp) 8051991Sheppo { 8061991Sheppo uchar_t *macaddr; 8071991Sheppo uint32_t size; 8081991Sheppo int rv; 8091991Sheppo 8101991Sheppo rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip, 8111991Sheppo DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size); 8121991Sheppo if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) { 8131991Sheppo DWARN((vnetp, 8141991Sheppo "vnet_read_mac_address: prop_lookup failed (%s) err (%d)\n", 8151991Sheppo macaddr_propname, rv)); 8161991Sheppo return (DDI_FAILURE); 8171991Sheppo } 8181991Sheppo bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL); 8191991Sheppo bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL); 8201991Sheppo ddi_prop_free(macaddr); 8211991Sheppo 8221991Sheppo return (DDI_SUCCESS); 8231991Sheppo } 8241991Sheppo 8251991Sheppo 8261991Sheppo /* 8271991Sheppo * Functions below are called only by generic transport to add/remove/modify 8281991Sheppo * entries in forwarding database. See comments in vgen_port_init(vnet_gen.c). 8291991Sheppo */ 8301991Sheppo 8311991Sheppo /* add an entry into the forwarding database */ 8321991Sheppo void 8331991Sheppo vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg) 8341991Sheppo { 8351991Sheppo vnet_t *vnetp = (vnet_t *)arg; 8361991Sheppo uint32_t fdbhash; 8371991Sheppo fdb_t *fdbp; 8381991Sheppo fdb_fanout_t *fdbhp; 8391991Sheppo 8401991Sheppo /* Calculate hash value and fdb fanout */ 8411991Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 8421991Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 8431991Sheppo 8441991Sheppo WRITE_ENTER(&fdbhp->rwlock); 8451991Sheppo 8461991Sheppo fdbp = kmem_zalloc(sizeof (fdb_t), KM_NOSLEEP); 8471991Sheppo if (fdbp == NULL) { 8481991Sheppo RW_EXIT(&fdbhp->rwlock); 8491991Sheppo return; 8501991Sheppo } 8511991Sheppo bcopy(macaddr, (caddr_t)fdbp->macaddr, ETHERADDRL); 8521991Sheppo fdbp->m_tx = m_tx; 8531991Sheppo fdbp->txarg = txarg; 8541991Sheppo fdbp->nextp = fdbhp->headp; 8551991Sheppo fdbhp->headp = fdbp; 8561991Sheppo 8571991Sheppo RW_EXIT(&fdbhp->rwlock); 8581991Sheppo } 8591991Sheppo 8601991Sheppo /* delete an entry from the forwarding database */ 8611991Sheppo void 8621991Sheppo vnet_del_fdb(void *arg, uint8_t *macaddr) 8631991Sheppo { 8641991Sheppo vnet_t *vnetp = (vnet_t *)arg; 8651991Sheppo uint32_t fdbhash; 8661991Sheppo fdb_t *fdbp; 8671991Sheppo fdb_t **pfdbp; 8681991Sheppo fdb_fanout_t *fdbhp; 8691991Sheppo 8701991Sheppo /* Calculate hash value and fdb fanout */ 8711991Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 8721991Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 8731991Sheppo 8741991Sheppo WRITE_ENTER(&fdbhp->rwlock); 8751991Sheppo 8761991Sheppo for (pfdbp = &fdbhp->headp; (fdbp = *pfdbp) != NULL; 8771991Sheppo pfdbp = &fdbp->nextp) { 8781991Sheppo if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) { 8791991Sheppo /* Unlink it from the list */ 8801991Sheppo *pfdbp = fdbp->nextp; 8811991Sheppo KMEM_FREE(fdbp); 8821991Sheppo break; 8831991Sheppo } 8841991Sheppo } 8851991Sheppo 8861991Sheppo RW_EXIT(&fdbhp->rwlock); 8871991Sheppo } 8881991Sheppo 8891991Sheppo /* modify an existing entry in the forwarding database */ 8901991Sheppo void 891*2793Slm66018 vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg, 892*2793Slm66018 boolean_t upgrade) 8931991Sheppo { 8941991Sheppo vnet_t *vnetp = (vnet_t *)arg; 8951991Sheppo uint32_t fdbhash; 8961991Sheppo fdb_t *fdbp; 8971991Sheppo fdb_fanout_t *fdbhp; 8981991Sheppo 8991991Sheppo /* Calculate hash value and fdb fanout */ 9001991Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 9011991Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 9021991Sheppo 903*2793Slm66018 if (upgrade == B_TRUE) { 904*2793Slm66018 /* 905*2793Slm66018 * Caller already holds the lock as a reader. This can 906*2793Slm66018 * occur if this function is invoked in the context 907*2793Slm66018 * of transmit routine - vnet_m_tx(), where the lock 908*2793Slm66018 * is held as a reader before calling the transmit 909*2793Slm66018 * function of an fdb entry (fdbp->m_tx). 910*2793Slm66018 * See comments in vgen_ldcsend() in vnet_gen.c 911*2793Slm66018 */ 912*2793Slm66018 if (!rw_tryupgrade(&fdbhp->rwlock)) { 913*2793Slm66018 RW_EXIT(&fdbhp->rwlock); 914*2793Slm66018 WRITE_ENTER(&fdbhp->rwlock); 915*2793Slm66018 } 916*2793Slm66018 } else { 917*2793Slm66018 /* Caller does not hold the lock */ 918*2793Slm66018 WRITE_ENTER(&fdbhp->rwlock); 919*2793Slm66018 } 9201991Sheppo 9211991Sheppo for (fdbp = fdbhp->headp; fdbp != NULL; fdbp = fdbp->nextp) { 9221991Sheppo if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) { 9231991Sheppo /* change the entry to have new tx params */ 9241991Sheppo fdbp->m_tx = m_tx; 9251991Sheppo fdbp->txarg = txarg; 9261991Sheppo break; 9271991Sheppo } 9281991Sheppo } 9291991Sheppo 930*2793Slm66018 if (upgrade == B_TRUE) { 931*2793Slm66018 /* restore the caller as a reader */ 932*2793Slm66018 rw_downgrade(&fdbhp->rwlock); 933*2793Slm66018 } else { 934*2793Slm66018 RW_EXIT(&fdbhp->rwlock); 935*2793Slm66018 } 9361991Sheppo } 9371991Sheppo 9381991Sheppo /* look up an fdb entry based on the mac address, caller holds lock */ 9391991Sheppo static fdb_t * 9401991Sheppo vnet_lookup_fdb(fdb_fanout_t *fdbhp, uint8_t *macaddr) 9411991Sheppo { 9421991Sheppo fdb_t *fdbp = NULL; 9431991Sheppo 9441991Sheppo for (fdbp = fdbhp->headp; fdbp != NULL; fdbp = fdbp->nextp) { 9451991Sheppo if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) { 9461991Sheppo break; 9471991Sheppo } 9481991Sheppo } 9491991Sheppo 9501991Sheppo return (fdbp); 9511991Sheppo } 9521991Sheppo 9531991Sheppo /* add default route entry into the forwarding database */ 9541991Sheppo void 9551991Sheppo vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg) 9561991Sheppo { 9571991Sheppo vnet_t *vnetp = (vnet_t *)arg; 9581991Sheppo fdb_t *fdbp; 9591991Sheppo fdb_fanout_t *fdbhp; 9601991Sheppo 9611991Sheppo /* 9621991Sheppo * The last hash list is reserved for default route entry, 9631991Sheppo * and for now, we have only one entry in this list. 9641991Sheppo */ 9651991Sheppo fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]); 9661991Sheppo 9671991Sheppo WRITE_ENTER(&fdbhp->rwlock); 9681991Sheppo 9691991Sheppo if (fdbhp->headp) { 9701991Sheppo DWARN((vnetp, 9711991Sheppo "vnet_add_def_rte: default rte already exists\n")); 9721991Sheppo RW_EXIT(&fdbhp->rwlock); 9731991Sheppo return; 9741991Sheppo } 9751991Sheppo fdbp = kmem_zalloc(sizeof (fdb_t), KM_NOSLEEP); 9761991Sheppo if (fdbp == NULL) { 9771991Sheppo RW_EXIT(&fdbhp->rwlock); 9781991Sheppo return; 9791991Sheppo } 9801991Sheppo bzero(fdbp->macaddr, ETHERADDRL); 9811991Sheppo fdbp->m_tx = m_tx; 9821991Sheppo fdbp->txarg = txarg; 9831991Sheppo fdbp->nextp = NULL; 9841991Sheppo fdbhp->headp = fdbp; 9851991Sheppo 9861991Sheppo RW_EXIT(&fdbhp->rwlock); 9871991Sheppo } 9881991Sheppo 9891991Sheppo /* delete default route entry from the forwarding database */ 9901991Sheppo void 9911991Sheppo vnet_del_def_rte(void *arg) 9921991Sheppo { 9931991Sheppo vnet_t *vnetp = (vnet_t *)arg; 9941991Sheppo fdb_t *fdbp; 9951991Sheppo fdb_fanout_t *fdbhp; 9961991Sheppo 9971991Sheppo /* 9981991Sheppo * The last hash list is reserved for default route entry, 9991991Sheppo * and for now, we have only one entry in this list. 10001991Sheppo */ 10011991Sheppo fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]); 10021991Sheppo 10031991Sheppo WRITE_ENTER(&fdbhp->rwlock); 10041991Sheppo 10051991Sheppo if (fdbhp->headp == NULL) { 10061991Sheppo RW_EXIT(&fdbhp->rwlock); 10071991Sheppo return; 10081991Sheppo } 10091991Sheppo fdbp = fdbhp->headp; 10101991Sheppo KMEM_FREE(fdbp); 10111991Sheppo fdbhp->headp = NULL; 10121991Sheppo 10131991Sheppo RW_EXIT(&fdbhp->rwlock); 10141991Sheppo } 10152311Sseb 10162311Sseb void 10172311Sseb vnet_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp) 10182311Sseb { 10192311Sseb vnet_t *vnetp = arg; 10202311Sseb mac_rx(vnetp->mh, mrh, mp); 10212311Sseb } 10222311Sseb 10232311Sseb void 10242311Sseb vnet_tx_update(void *arg) 10252311Sseb { 10262311Sseb vnet_t *vnetp = arg; 10272311Sseb mac_tx_update(vnetp->mh); 10282311Sseb } 1029