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> 441991Sheppo #include <sys/ddi.h> 451991Sheppo #include <sys/sunddi.h> 461991Sheppo #include <sys/strsun.h> 471991Sheppo #include <sys/note.h> 481991Sheppo #include <sys/vnet.h> 491991Sheppo 501991Sheppo /* 511991Sheppo * Function prototypes. 521991Sheppo */ 531991Sheppo 541991Sheppo /* DDI entrypoints */ 551991Sheppo static int vnetdevinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 561991Sheppo static int vnetattach(dev_info_t *, ddi_attach_cmd_t); 571991Sheppo static int vnetdetach(dev_info_t *, ddi_detach_cmd_t); 581991Sheppo 591991Sheppo /* MAC entrypoints */ 601991Sheppo static uint64_t vnet_m_stat(void *arg, enum mac_stat stat); 611991Sheppo static int vnet_m_start(void *); 621991Sheppo static void vnet_m_stop(void *); 631991Sheppo static int vnet_m_promisc(void *, boolean_t); 641991Sheppo static int vnet_m_multicst(void *, boolean_t, const uint8_t *); 651991Sheppo static int vnet_m_unicst(void *, const uint8_t *); 661991Sheppo static void vnet_m_resources(void *); 671991Sheppo static void vnet_m_ioctl(void *, queue_t *, mblk_t *); 681991Sheppo mblk_t *vnet_m_tx(void *, mblk_t *); 691991Sheppo 701991Sheppo /* vnet internal functions */ 711991Sheppo static int vnet_mac_register(vnet_t *); 721991Sheppo static int vnet_read_mac_address(vnet_t *vnetp); 731991Sheppo static void vnet_add_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp); 741991Sheppo static void vnet_del_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp); 751991Sheppo static vp_tl_t *vnet_get_vptl(vnet_t *vnetp, const char *devname); 761991Sheppo static fdb_t *vnet_lookup_fdb(fdb_fanout_t *fdbhp, uint8_t *macaddr); 771991Sheppo 781991Sheppo /* exported functions */ 791991Sheppo void vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg); 801991Sheppo void vnet_del_fdb(void *arg, uint8_t *macaddr); 811991Sheppo void vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg); 821991Sheppo void vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg); 831991Sheppo void vnet_del_def_rte(void *arg); 841991Sheppo 851991Sheppo /* externs */ 861991Sheppo extern int vgen_init(void *vnetp, dev_info_t *vnetdip, void *vnetmacp, 871991Sheppo const uint8_t *macaddr, mac_t **vgenmacp); 881991Sheppo extern void vgen_uninit(void *arg); 891991Sheppo 901991Sheppo /* 911991Sheppo * Linked list of "vnet_t" structures - one per instance. 921991Sheppo */ 931991Sheppo static vnet_t *vnet_headp = NULL; 941991Sheppo static krwlock_t vnet_rw; 951991Sheppo 961991Sheppo /* Tunables */ 971991Sheppo uint32_t vnet_ntxds = VNET_NTXDS; /* power of 2 transmit descriptors */ 981991Sheppo uint32_t vnet_reclaim_lowat = VNET_RECLAIM_LOWAT; /* tx recl low watermark */ 991991Sheppo uint32_t vnet_reclaim_hiwat = VNET_RECLAIM_HIWAT; /* tx recl high watermark */ 1001991Sheppo uint32_t vnet_ldcwd_interval = VNET_LDCWD_INTERVAL; /* watchdog freq in msec */ 1011991Sheppo uint32_t vnet_ldcwd_txtimeout = VNET_LDCWD_TXTIMEOUT; /* tx timeout in msec */ 1021991Sheppo uint32_t vnet_ldc_qlen = VNET_LDC_QLEN; /* ldc qlen */ 1031991Sheppo uint32_t vnet_nfdb_hash = VNET_NFDB_HASH; /* size of fdb hash table */ 1041991Sheppo 1051991Sheppo /* 1061991Sheppo * Property names 1071991Sheppo */ 1081991Sheppo static char macaddr_propname[] = "local-mac-address"; 1091991Sheppo 1101991Sheppo static struct ether_addr etherbroadcastaddr = { 1111991Sheppo 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 1121991Sheppo }; 1131991Sheppo 1141991Sheppo /* 1151991Sheppo * MIB II broadcast/multicast packets 1161991Sheppo */ 1171991Sheppo #define IS_BROADCAST(ehp) \ 1181991Sheppo (ether_cmp(&ehp->ether_dhost, ðerbroadcastaddr) == 0) 1191991Sheppo #define IS_MULTICAST(ehp) \ 1201991Sheppo ((ehp->ether_dhost.ether_addr_octet[0] & 01) == 1) 1211991Sheppo 1221991Sheppo /* 1231991Sheppo * This is the string displayed by modinfo(1m). 1241991Sheppo */ 125*2109Slm66018 static char vnet_ident[] = "vnet driver v%I%"; 1261991Sheppo extern struct mod_ops mod_driverops; 1271991Sheppo static struct cb_ops cb_vnetops = { 1281991Sheppo nulldev, /* cb_open */ 1291991Sheppo nulldev, /* cb_close */ 1301991Sheppo nodev, /* cb_strategy */ 1311991Sheppo nodev, /* cb_print */ 1321991Sheppo nodev, /* cb_dump */ 1331991Sheppo nodev, /* cb_read */ 1341991Sheppo nodev, /* cb_write */ 1351991Sheppo nodev, /* cb_ioctl */ 1361991Sheppo nodev, /* cb_devmap */ 1371991Sheppo nodev, /* cb_mmap */ 1381991Sheppo nodev, /* cb_segmap */ 1391991Sheppo nochpoll, /* cb_chpoll */ 1401991Sheppo ddi_prop_op, /* cb_prop_op */ 1411991Sheppo NULL, /* cb_stream */ 1421991Sheppo (int)(D_MP) /* cb_flag */ 1431991Sheppo }; 1441991Sheppo 1451991Sheppo static struct dev_ops vnetops = { 1461991Sheppo DEVO_REV, /* devo_rev */ 1471991Sheppo 0, /* devo_refcnt */ 1481991Sheppo NULL, /* devo_getinfo */ 1491991Sheppo nulldev, /* devo_identify */ 1501991Sheppo nulldev, /* devo_probe */ 1511991Sheppo vnetattach, /* devo_attach */ 1521991Sheppo vnetdetach, /* devo_detach */ 1531991Sheppo nodev, /* devo_reset */ 1541991Sheppo &cb_vnetops, /* devo_cb_ops */ 1551991Sheppo (struct bus_ops *)NULL /* devo_bus_ops */ 1561991Sheppo }; 1571991Sheppo 1581991Sheppo static struct modldrv modldrv = { 1591991Sheppo &mod_driverops, /* Type of module. This one is a driver */ 1601991Sheppo vnet_ident, /* ID string */ 1611991Sheppo &vnetops /* driver specific ops */ 1621991Sheppo }; 1631991Sheppo 1641991Sheppo static struct modlinkage modlinkage = { 1651991Sheppo MODREV_1, (void *)&modldrv, NULL 1661991Sheppo }; 1671991Sheppo 1681991Sheppo 1691991Sheppo /* 1701991Sheppo * Print debug messages - set to 0xf to enable all msgs 1711991Sheppo */ 1721991Sheppo int _vnet_dbglevel = 0x8; 1731991Sheppo 1741991Sheppo void 1751991Sheppo _vnetdebug_printf(void *arg, const char *fmt, ...) 1761991Sheppo { 1771991Sheppo char buf[512]; 1781991Sheppo va_list ap; 1791991Sheppo vnet_t *vnetp = (vnet_t *)arg; 1801991Sheppo 1811991Sheppo va_start(ap, fmt); 1821991Sheppo (void) vsprintf(buf, fmt, ap); 1831991Sheppo va_end(ap); 1841991Sheppo 1851991Sheppo if (vnetp == NULL) 1861991Sheppo cmn_err(CE_CONT, "%s\n", buf); 1871991Sheppo else 1881991Sheppo cmn_err(CE_CONT, "vnet%d: %s\n", vnetp->instance, buf); 1891991Sheppo } 1901991Sheppo 1911991Sheppo #ifdef DEBUG 1921991Sheppo 1931991Sheppo /* 1941991Sheppo * XXX: any changes to the definitions below need corresponding changes in 1951991Sheppo * vnet_gen.c 1961991Sheppo */ 1971991Sheppo 1981991Sheppo /* 1991991Sheppo * debug levels: 2001991Sheppo * DBG_LEVEL1: Function entry/exit tracing 2011991Sheppo * DBG_LEVEL2: Info messages 2021991Sheppo * DBG_LEVEL3: Warning messages 2031991Sheppo * DBG_LEVEL4: Error messages 2041991Sheppo */ 2051991Sheppo 2061991Sheppo enum { DBG_LEVEL1 = 0x01, DBG_LEVEL2 = 0x02, DBG_LEVEL3 = 0x04, 2071991Sheppo DBG_LEVEL4 = 0x08 }; 2081991Sheppo 2091991Sheppo #define DBG1(_s) do { \ 2101991Sheppo if ((_vnet_dbglevel & DBG_LEVEL1) != 0) { \ 2111991Sheppo _vnetdebug_printf _s; \ 2121991Sheppo } \ 2131991Sheppo _NOTE(CONSTCOND) } while (0) 2141991Sheppo 2151991Sheppo #define DBG2(_s) do { \ 2161991Sheppo if ((_vnet_dbglevel & DBG_LEVEL2) != 0) { \ 2171991Sheppo _vnetdebug_printf _s; \ 2181991Sheppo } \ 2191991Sheppo _NOTE(CONSTCOND) } while (0) 2201991Sheppo 2211991Sheppo #define DWARN(_s) do { \ 2221991Sheppo if ((_vnet_dbglevel & DBG_LEVEL3) != 0) { \ 2231991Sheppo _vnetdebug_printf _s; \ 2241991Sheppo } \ 2251991Sheppo _NOTE(CONSTCOND) } while (0) 2261991Sheppo 2271991Sheppo #define DERR(_s) do { \ 2281991Sheppo if ((_vnet_dbglevel & DBG_LEVEL4) != 0) { \ 2291991Sheppo _vnetdebug_printf _s; \ 2301991Sheppo } \ 2311991Sheppo _NOTE(CONSTCOND) } while (0) 2321991Sheppo 2331991Sheppo #else 2341991Sheppo 2351991Sheppo #define DBG1(_s) if (0) _vnetdebug_printf _s 2361991Sheppo #define DBG2(_s) if (0) _vnetdebug_printf _s 2371991Sheppo #define DWARN(_s) if (0) _vnetdebug_printf _s 2381991Sheppo #define DERR(_s) if (0) _vnetdebug_printf _s 2391991Sheppo 2401991Sheppo #endif 2411991Sheppo 2421991Sheppo /* _init(9E): initialize the loadable module */ 2431991Sheppo int 2441991Sheppo _init(void) 2451991Sheppo { 2461991Sheppo int status; 2471991Sheppo 2481991Sheppo DBG1((NULL, "_init: enter\n")); 2491991Sheppo 2501991Sheppo mac_init_ops(&vnetops, "vnet"); 2511991Sheppo status = mod_install(&modlinkage); 2521991Sheppo if (status != 0) { 2531991Sheppo mac_fini_ops(&vnetops); 2541991Sheppo } 2551991Sheppo 2561991Sheppo DBG1((NULL, "_init: exit\n")); 2571991Sheppo return (status); 2581991Sheppo } 2591991Sheppo 2601991Sheppo /* _fini(9E): prepare the module for unloading. */ 2611991Sheppo int 2621991Sheppo _fini(void) 2631991Sheppo { 2641991Sheppo int status; 2651991Sheppo 2661991Sheppo DBG1((NULL, "_fini: enter\n")); 2671991Sheppo 2681991Sheppo status = mod_remove(&modlinkage); 2691991Sheppo if (status != 0) 2701991Sheppo return (status); 2711991Sheppo mac_fini_ops(&vnetops); 2721991Sheppo 2731991Sheppo DBG1((NULL, "_fini: exit\n")); 2741991Sheppo return (status); 2751991Sheppo } 2761991Sheppo 2771991Sheppo /* _info(9E): return information about the loadable module */ 2781991Sheppo int 2791991Sheppo _info(struct modinfo *modinfop) 2801991Sheppo { 2811991Sheppo return (mod_info(&modlinkage, modinfop)); 2821991Sheppo } 2831991Sheppo 2841991Sheppo /* 2851991Sheppo * attach(9E): attach a device to the system. 2861991Sheppo * called once for each instance of the device on the system. 2871991Sheppo */ 2881991Sheppo static int 2891991Sheppo vnetattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2901991Sheppo { 2911991Sheppo mac_t *macp; 2921991Sheppo vnet_t *vnetp; 2931991Sheppo vp_tl_t *vp_tlp; 2941991Sheppo int instance; 2951991Sheppo int status; 2961991Sheppo enum { AST_init = 0x0, AST_vnet_alloc = 0x1, 2971991Sheppo AST_mac_alloc = 0x2, AST_read_macaddr = 0x4, 2981991Sheppo AST_vgen_init = 0x8, AST_vptl_alloc = 0x10, 2991991Sheppo AST_fdbh_alloc = 0x20 } 3001991Sheppo attach_state; 3011991Sheppo mac_t *vgenmacp = NULL; 3021991Sheppo uint32_t nfdbh = 0; 3031991Sheppo 3041991Sheppo attach_state = AST_init; 3051991Sheppo 3061991Sheppo switch (cmd) { 3071991Sheppo case DDI_ATTACH: 3081991Sheppo break; 3091991Sheppo case DDI_RESUME: 3101991Sheppo case DDI_PM_RESUME: 3111991Sheppo default: 3121991Sheppo goto vnet_attach_fail; 3131991Sheppo } 3141991Sheppo 3151991Sheppo instance = ddi_get_instance(dip); 3161991Sheppo DBG1((NULL, "vnetattach: instance(%d) enter\n", instance)); 3171991Sheppo 3181991Sheppo /* allocate vnet_t and mac_t structures */ 3191991Sheppo vnetp = kmem_zalloc(sizeof (vnet_t), KM_SLEEP); 3201991Sheppo attach_state |= AST_vnet_alloc; 3211991Sheppo 3221991Sheppo macp = kmem_zalloc(sizeof (mac_t), KM_SLEEP); 3231991Sheppo attach_state |= AST_mac_alloc; 3241991Sheppo 3251991Sheppo /* setup links to vnet_t from both devinfo and mac_t */ 3261991Sheppo ddi_set_driver_private(dip, (caddr_t)vnetp); 3271991Sheppo macp->m_driver = vnetp; 3281991Sheppo vnetp->dip = dip; 3291991Sheppo vnetp->macp = macp; 3301991Sheppo vnetp->instance = instance; 3311991Sheppo 3321991Sheppo /* read the mac address */ 3331991Sheppo status = vnet_read_mac_address(vnetp); 3341991Sheppo if (status != DDI_SUCCESS) { 3351991Sheppo goto vnet_attach_fail; 3361991Sheppo } 3371991Sheppo attach_state |= AST_read_macaddr; 3381991Sheppo 3391991Sheppo /* 3401991Sheppo * Initialize the generic vnet proxy transport. This is the first 3411991Sheppo * and default transport used by vnet. The generic transport 3421991Sheppo * is provided by using sun4v LDC (logical domain channel). On success, 3431991Sheppo * vgen_init() provides a pointer to mac_t of generic transport. 3441991Sheppo * Currently, this generic layer provides network connectivity to other 3451991Sheppo * vnets within ldoms and also to remote hosts oustide ldoms through 3461991Sheppo * the virtual switch (vsw) device on domain0. In the future, when 3471991Sheppo * physical adapters that are able to share their resources (such as 3481991Sheppo * dma channels) with guest domains become available, the vnet device 3491991Sheppo * will use hardware specific driver to communicate directly over the 3501991Sheppo * physical device to reach remote hosts without going through vswitch. 3511991Sheppo */ 3521991Sheppo status = vgen_init(vnetp, vnetp->dip, vnetp->macp, 3531991Sheppo (uint8_t *)vnetp->curr_macaddr, &vgenmacp); 3541991Sheppo if (status != DDI_SUCCESS) { 3551991Sheppo DERR((vnetp, "vgen_init() failed\n")); 3561991Sheppo goto vnet_attach_fail; 3571991Sheppo } 3581991Sheppo attach_state |= AST_vgen_init; 3591991Sheppo 3601991Sheppo vp_tlp = kmem_zalloc(sizeof (vp_tl_t), KM_SLEEP); 3611991Sheppo vp_tlp->macp = vgenmacp; 3621991Sheppo (void) snprintf(vp_tlp->name, MAXNAMELEN, "%s%u", "vgen", instance); 3631991Sheppo (void) strcpy(vnetp->vgen_name, vp_tlp->name); 3641991Sheppo 3651991Sheppo /* add generic transport to the list of vnet proxy transports */ 3661991Sheppo vnet_add_vptl(vnetp, vp_tlp); 3671991Sheppo attach_state |= AST_vptl_alloc; 3681991Sheppo 3691991Sheppo nfdbh = vnet_nfdb_hash; 3701991Sheppo if ((nfdbh < VNET_NFDB_HASH) || (nfdbh > VNET_NFDB_HASH_MAX)) { 3711991Sheppo vnetp->nfdb_hash = VNET_NFDB_HASH; 3721991Sheppo } 3731991Sheppo else 3741991Sheppo vnetp->nfdb_hash = nfdbh; 3751991Sheppo 3761991Sheppo /* allocate fdb hash table, with an extra slot for default route */ 3771991Sheppo vnetp->fdbhp = kmem_zalloc(sizeof (fdb_fanout_t) * 3781991Sheppo (vnetp->nfdb_hash + 1), KM_SLEEP); 3791991Sheppo attach_state |= AST_fdbh_alloc; 3801991Sheppo 3811991Sheppo /* register with MAC layer */ 3821991Sheppo status = vnet_mac_register(vnetp); 3831991Sheppo if (status != DDI_SUCCESS) { 3841991Sheppo goto vnet_attach_fail; 3851991Sheppo } 3861991Sheppo 3871991Sheppo /* add to the list of vnet devices */ 3881991Sheppo WRITE_ENTER(&vnet_rw); 3891991Sheppo vnetp->nextp = vnet_headp; 3901991Sheppo vnet_headp = vnetp; 3911991Sheppo RW_EXIT(&vnet_rw); 3921991Sheppo 3931991Sheppo DBG1((NULL, "vnetattach: instance(%d) exit\n", instance)); 3941991Sheppo return (DDI_SUCCESS); 3951991Sheppo 3961991Sheppo vnet_attach_fail: 3971991Sheppo if (attach_state & AST_fdbh_alloc) { 3981991Sheppo kmem_free(vnetp->fdbhp, 3991991Sheppo sizeof (fdb_fanout_t) * (vnetp->nfdb_hash + 1)); 4001991Sheppo } 4011991Sheppo if (attach_state & AST_vptl_alloc) { 4021991Sheppo WRITE_ENTER(&vnetp->trwlock); 4031991Sheppo vnet_del_vptl(vnetp, vp_tlp); 4041991Sheppo RW_EXIT(&vnetp->trwlock); 4051991Sheppo } 4061991Sheppo if (attach_state & AST_vgen_init) { 4071991Sheppo vgen_uninit(vgenmacp->m_driver); 4081991Sheppo } 4091991Sheppo if (attach_state & AST_mac_alloc) { 4101991Sheppo KMEM_FREE(macp); 4111991Sheppo } 4121991Sheppo if (attach_state & AST_vnet_alloc) { 4131991Sheppo KMEM_FREE(vnetp); 4141991Sheppo } 4151991Sheppo return (DDI_FAILURE); 4161991Sheppo } 4171991Sheppo 4181991Sheppo /* 4191991Sheppo * detach(9E): detach a device from the system. 4201991Sheppo */ 4211991Sheppo static int 4221991Sheppo vnetdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4231991Sheppo { 4241991Sheppo vnet_t *vnetp; 4251991Sheppo vnet_t **vnetpp; 4261991Sheppo vp_tl_t *vp_tlp; 4271991Sheppo int instance; 4281991Sheppo 4291991Sheppo instance = ddi_get_instance(dip); 4301991Sheppo DBG1((NULL, "vnetdetach: instance(%d) enter\n", instance)); 4311991Sheppo 4321991Sheppo vnetp = ddi_get_driver_private(dip); 4331991Sheppo if (vnetp == NULL) { 4341991Sheppo goto vnet_detach_fail; 4351991Sheppo } 4361991Sheppo 4371991Sheppo switch (cmd) { 4381991Sheppo case DDI_DETACH: 4391991Sheppo break; 4401991Sheppo case DDI_SUSPEND: 4411991Sheppo case DDI_PM_SUSPEND: 4421991Sheppo default: 4431991Sheppo goto vnet_detach_fail; 4441991Sheppo } 4451991Sheppo 4461991Sheppo /* 4471991Sheppo * Unregister from the MAC subsystem. This can fail, in 4481991Sheppo * particular if there are DLPI style-2 streams still open - 4491991Sheppo * in which case we just return failure. 4501991Sheppo */ 4511991Sheppo if (mac_unregister(vnetp->macp) != 0) 4521991Sheppo goto vnet_detach_fail; 4531991Sheppo 4541991Sheppo /* unlink from instance(vnet_t) list */ 4551991Sheppo WRITE_ENTER(&vnet_rw); 4561991Sheppo for (vnetpp = &vnet_headp; *vnetpp; vnetpp = &(*vnetpp)->nextp) { 4571991Sheppo if (*vnetpp == vnetp) { 4581991Sheppo *vnetpp = vnetp->nextp; 4591991Sheppo break; 4601991Sheppo } 4611991Sheppo } 4621991Sheppo RW_EXIT(&vnet_rw); 4631991Sheppo 4641991Sheppo /* uninit and free vnet proxy transports */ 4651991Sheppo WRITE_ENTER(&vnetp->trwlock); 4661991Sheppo while ((vp_tlp = vnetp->tlp) != NULL) { 4671991Sheppo if (strcmp(vnetp->vgen_name, vp_tlp->name) == 0) { 4681991Sheppo /* uninitialize generic transport */ 4691991Sheppo vgen_uninit(vp_tlp->macp->m_driver); 4701991Sheppo } 4711991Sheppo vnet_del_vptl(vnetp, vp_tlp); 4721991Sheppo } 4731991Sheppo RW_EXIT(&vnetp->trwlock); 4741991Sheppo 4751991Sheppo KMEM_FREE(vnetp->macp); 4761991Sheppo KMEM_FREE(vnetp); 4771991Sheppo 4781991Sheppo return (DDI_SUCCESS); 4791991Sheppo 4801991Sheppo vnet_detach_fail: 4811991Sheppo return (DDI_FAILURE); 4821991Sheppo } 4831991Sheppo 4841991Sheppo /* enable the device for transmit/receive */ 4851991Sheppo static int 4861991Sheppo vnet_m_start(void *arg) 4871991Sheppo { 4881991Sheppo vnet_t *vnetp = arg; 4891991Sheppo vp_tl_t *vp_tlp; 4901991Sheppo mac_t *vp_macp; 4911991Sheppo 4921991Sheppo DBG1((vnetp, "vnet_m_start: enter\n")); 4931991Sheppo 4941991Sheppo /* 4951991Sheppo * XXX 4961991Sheppo * Currently, we only have generic transport. m_start() invokes 4971991Sheppo * vgen_start() which enables ports/channels in vgen and 4981991Sheppo * initiates handshake with peer vnets and vsw. In the future when we 4991991Sheppo * have support for hardware specific transports, this information 5001991Sheppo * needs to be propagted back to vnet from vgen and we need to revisit 5011991Sheppo * this code (see comments in vnet_attach()). 5021991Sheppo * 5031991Sheppo */ 5041991Sheppo WRITE_ENTER(&vnetp->trwlock); 5051991Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 5061991Sheppo vp_macp = vp_tlp->macp; 5071991Sheppo vp_macp->m_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; 5221991Sheppo mac_t *vp_macp; 5231991Sheppo 5241991Sheppo DBG1((vnetp, "vnet_m_stop: enter\n")); 5251991Sheppo 5261991Sheppo WRITE_ENTER(&vnetp->trwlock); 5271991Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 5281991Sheppo vp_macp = vp_tlp->macp; 5291991Sheppo vp_macp->m_stop(vp_macp->m_driver); 5301991Sheppo } 5311991Sheppo RW_EXIT(&vnetp->trwlock); 5321991Sheppo 5331991Sheppo DBG1((vnetp, "vnet_m_stop: exit\n")); 5341991Sheppo } 5351991Sheppo 5361991Sheppo /* set the unicast mac address of the device */ 5371991Sheppo static int 5381991Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr) 5391991Sheppo { 5401991Sheppo _NOTE(ARGUNUSED(macaddr)) 5411991Sheppo 5421991Sheppo vnet_t *vnetp = arg; 5431991Sheppo 5441991Sheppo DBG1((vnetp, "vnet_m_unicst: enter\n")); 5451991Sheppo /* 5461991Sheppo * XXX: setting mac address dynamically is not supported. 5471991Sheppo */ 5481991Sheppo DBG1((vnetp, "vnet_m_unicst: exit\n")); 5491991Sheppo 550*2109Slm66018 return (VNET_FAILURE); 5511991Sheppo } 5521991Sheppo 5531991Sheppo /* enable/disable a multicast address */ 5541991Sheppo static int 5551991Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 5561991Sheppo { 5571991Sheppo _NOTE(ARGUNUSED(add, mca)) 5581991Sheppo 5591991Sheppo vnet_t *vnetp = arg; 5601991Sheppo vp_tl_t *vp_tlp; 5611991Sheppo mac_t *vp_macp; 5621991Sheppo int rv = VNET_SUCCESS; 5631991Sheppo 5641991Sheppo DBG1((vnetp, "vnet_m_multicst: enter\n")); 5651991Sheppo READ_ENTER(&vnetp->trwlock); 5661991Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 5671991Sheppo if (strcmp(vnetp->vgen_name, vp_tlp->name) == 0) { 5681991Sheppo vp_macp = vp_tlp->macp; 5691991Sheppo rv = vp_macp->m_multicst(vp_macp->m_driver, add, mca); 5701991Sheppo break; 5711991Sheppo } 5721991Sheppo } 5731991Sheppo RW_EXIT(&vnetp->trwlock); 5741991Sheppo DBG1((vnetp, "vnet_m_multicst: exit\n")); 5751991Sheppo return (rv); 5761991Sheppo } 5771991Sheppo 5781991Sheppo /* set or clear promiscuous mode on the device */ 5791991Sheppo static int 5801991Sheppo vnet_m_promisc(void *arg, boolean_t on) 5811991Sheppo { 5821991Sheppo _NOTE(ARGUNUSED(on)) 5831991Sheppo 5841991Sheppo vnet_t *vnetp = arg; 5851991Sheppo DBG1((vnetp, "vnet_m_promisc: enter\n")); 5861991Sheppo /* 5871991Sheppo * XXX: setting promiscuous mode is not supported, just return success. 5881991Sheppo */ 5891991Sheppo DBG1((vnetp, "vnet_m_promisc: exit\n")); 5901991Sheppo return (VNET_SUCCESS); 5911991Sheppo } 5921991Sheppo 5931991Sheppo /* 5941991Sheppo * Transmit a chain of packets. This function provides switching functionality 5951991Sheppo * based on the destination mac address to reach other guests (within ldoms) or 5961991Sheppo * external hosts. 5971991Sheppo */ 5981991Sheppo mblk_t * 5991991Sheppo vnet_m_tx(void *arg, mblk_t *mp) 6001991Sheppo { 6011991Sheppo vnet_t *vnetp; 6021991Sheppo mblk_t *next; 6031991Sheppo uint32_t fdbhash; 6041991Sheppo fdb_t *fdbp; 6051991Sheppo fdb_fanout_t *fdbhp; 6061991Sheppo struct ether_header *ehp; 6071991Sheppo uint8_t *macaddr; 6081991Sheppo mblk_t *resid_mp; 6091991Sheppo 6101991Sheppo vnetp = (vnet_t *)arg; 6111991Sheppo DBG1((vnetp, "vnet_m_tx: enter\n")); 6121991Sheppo ASSERT(mp != NULL); 6131991Sheppo 6141991Sheppo while (mp != NULL) { 6151991Sheppo next = mp->b_next; 6161991Sheppo mp->b_next = NULL; 6171991Sheppo 6181991Sheppo /* get the destination mac address in the eth header */ 6191991Sheppo ehp = (struct ether_header *)mp->b_rptr; 6201991Sheppo macaddr = (uint8_t *)&ehp->ether_dhost; 6211991Sheppo 6221991Sheppo /* Calculate hash value and fdb fanout */ 6231991Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 6241991Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 6251991Sheppo 6261991Sheppo READ_ENTER(&fdbhp->rwlock); 6271991Sheppo fdbp = vnet_lookup_fdb(fdbhp, macaddr); 6281991Sheppo if (fdbp) { 6291991Sheppo /* 6301991Sheppo * If the destination is in FDB, the destination is 6311991Sheppo * a vnet device within ldoms and directly reachable, 6321991Sheppo * invoke the tx function in the fdb entry. 6331991Sheppo */ 6341991Sheppo resid_mp = fdbp->m_tx(fdbp->txarg, mp); 6351991Sheppo if (resid_mp != NULL) { 6361991Sheppo /* m_tx failed */ 6371991Sheppo mp->b_next = next; 6381991Sheppo RW_EXIT(&fdbhp->rwlock); 6391991Sheppo break; 6401991Sheppo } 6411991Sheppo RW_EXIT(&fdbhp->rwlock); 6421991Sheppo } else { 6431991Sheppo /* destination is not in FDB */ 6441991Sheppo RW_EXIT(&fdbhp->rwlock); 6451991Sheppo /* 6461991Sheppo * If the destination is broadcast/multicast 6471991Sheppo * or an unknown unicast address, forward the 6481991Sheppo * packet to vsw, using the last slot in fdb which is 6491991Sheppo * reserved for default route. 6501991Sheppo */ 6511991Sheppo fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]); 6521991Sheppo READ_ENTER(&fdbhp->rwlock); 6531991Sheppo fdbp = fdbhp->headp; 6541991Sheppo if (fdbp) { 6551991Sheppo resid_mp = fdbp->m_tx(fdbp->txarg, mp); 6561991Sheppo if (resid_mp != NULL) { 6571991Sheppo /* m_tx failed */ 6581991Sheppo mp->b_next = next; 6591991Sheppo RW_EXIT(&fdbhp->rwlock); 6601991Sheppo break; 6611991Sheppo } 6621991Sheppo } else { 6631991Sheppo /* drop the packet */ 6641991Sheppo freemsg(mp); 6651991Sheppo } 6661991Sheppo RW_EXIT(&fdbhp->rwlock); 6671991Sheppo } 6681991Sheppo 6691991Sheppo mp = next; 6701991Sheppo } 6711991Sheppo 6721991Sheppo DBG1((vnetp, "vnet_m_tx: exit\n")); 6731991Sheppo return (mp); 6741991Sheppo } 6751991Sheppo 6761991Sheppo /* register resources with mac layer */ 6771991Sheppo static void 6781991Sheppo vnet_m_resources(void *arg) 6791991Sheppo { 6801991Sheppo vnet_t *vnetp = arg; 6811991Sheppo vp_tl_t *vp_tlp; 6821991Sheppo mac_t *vp_macp; 6831991Sheppo 6841991Sheppo DBG1((vnetp, "vnet_m_resources: enter\n")); 6851991Sheppo 6861991Sheppo WRITE_ENTER(&vnetp->trwlock); 6871991Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 6881991Sheppo vp_macp = vp_tlp->macp; 6891991Sheppo vp_macp->m_resources(vp_macp->m_driver); 6901991Sheppo } 6911991Sheppo RW_EXIT(&vnetp->trwlock); 6921991Sheppo 6931991Sheppo DBG1((vnetp, "vnet_m_resources: exit\n")); 6941991Sheppo } 6951991Sheppo 6961991Sheppo /* 6971991Sheppo * vnet specific ioctls 6981991Sheppo */ 6991991Sheppo static void 7001991Sheppo vnet_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 7011991Sheppo { 7021991Sheppo vnet_t *vnetp = (vnet_t *)arg; 7031991Sheppo struct iocblk *iocp; 7041991Sheppo int cmd; 7051991Sheppo 7061991Sheppo DBG1((vnetp, "vnet_m_ioctl: enter\n")); 7071991Sheppo 7081991Sheppo iocp = (struct iocblk *)mp->b_rptr; 7091991Sheppo iocp->ioc_error = 0; 7101991Sheppo cmd = iocp->ioc_cmd; 7111991Sheppo switch (cmd) { 7121991Sheppo default: 7131991Sheppo miocnak(wq, mp, 0, EINVAL); 7141991Sheppo break; 7151991Sheppo } 7161991Sheppo DBG1((vnetp, "vnet_m_ioctl: exit\n")); 7171991Sheppo } 7181991Sheppo 7191991Sheppo /* get statistics from the device */ 7201991Sheppo uint64_t 7211991Sheppo vnet_m_stat(void *arg, enum mac_stat stat) 7221991Sheppo { 7231991Sheppo vnet_t *vnetp = arg; 7241991Sheppo vp_tl_t *vp_tlp; 7251991Sheppo mac_t *vp_macp; 7261991Sheppo uint64_t val = 0; 7271991Sheppo 7281991Sheppo DBG1((vnetp, "vnet_m_stat: enter\n")); 7291991Sheppo 7301991Sheppo /* 7311991Sheppo * get the specified statistic from each transport 7321991Sheppo * and return the aggregate val 7331991Sheppo */ 7341991Sheppo READ_ENTER(&vnetp->trwlock); 7351991Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 7361991Sheppo vp_macp = vp_tlp->macp; 7371991Sheppo val += vp_macp->m_stat(vp_macp->m_driver, stat); 7381991Sheppo } 7391991Sheppo RW_EXIT(&vnetp->trwlock); 7401991Sheppo 7411991Sheppo DBG1((vnetp, "vnet_m_stat: exit\n")); 7421991Sheppo return (val); 7431991Sheppo } 7441991Sheppo 7451991Sheppo /* wrapper function for mac_register() */ 7461991Sheppo static int 7471991Sheppo vnet_mac_register(vnet_t *vnetp) 7481991Sheppo { 7491991Sheppo mac_info_t *mip; 7501991Sheppo mac_t *macp; 7511991Sheppo 7521991Sheppo macp = vnetp->macp; 7531991Sheppo 7541991Sheppo mip = &(macp->m_info); 7551991Sheppo mip->mi_media = DL_ETHER; 7561991Sheppo mip->mi_sdu_min = 0; 7571991Sheppo mip->mi_sdu_max = ETHERMTU; 7581991Sheppo mip->mi_cksum = 0; 7591991Sheppo mip->mi_poll = 0; /* DL_CAPAB_POLL ? */ 7601991Sheppo mip->mi_addr_length = ETHERADDRL; 7611991Sheppo bcopy(ðerbroadcastaddr, mip->mi_brdcst_addr, ETHERADDRL); 7621991Sheppo bcopy(vnetp->curr_macaddr, mip->mi_unicst_addr, ETHERADDRL); 7631991Sheppo 7641991Sheppo MAC_STAT_MIB(mip->mi_stat); 7651991Sheppo mip->mi_stat[MAC_STAT_UNKNOWNS] = B_FALSE; 7661991Sheppo MAC_STAT_ETHER(mip->mi_stat); 7671991Sheppo mip->mi_stat[MAC_STAT_SQE_ERRORS] = B_FALSE; 7681991Sheppo mip->mi_stat[MAC_STAT_MACRCV_ERRORS] = B_FALSE; 7691991Sheppo 7701991Sheppo macp->m_stat = vnet_m_stat; 7711991Sheppo macp->m_start = vnet_m_start; 7721991Sheppo macp->m_stop = vnet_m_stop; 7731991Sheppo macp->m_promisc = vnet_m_promisc; 7741991Sheppo macp->m_multicst = vnet_m_multicst; 7751991Sheppo macp->m_unicst = vnet_m_unicst; 7761991Sheppo macp->m_resources = vnet_m_resources; 7771991Sheppo macp->m_ioctl = vnet_m_ioctl; 7781991Sheppo macp->m_tx = vnet_m_tx; 7791991Sheppo 7801991Sheppo macp->m_dip = vnetp->dip; 7811991Sheppo macp->m_ident = MAC_IDENT; 7821991Sheppo 7831991Sheppo /* 7841991Sheppo * Finally, we're ready to register ourselves with the MAC layer 7851991Sheppo * interface; if this succeeds, we're all ready to start() 7861991Sheppo */ 7871991Sheppo if (mac_register(macp) != 0) { 7881991Sheppo KMEM_FREE(macp); 7891991Sheppo return (DDI_FAILURE); 7901991Sheppo } 7911991Sheppo 7921991Sheppo return (DDI_SUCCESS); 7931991Sheppo } 7941991Sheppo 7951991Sheppo /* add vp_tl to the list */ 7961991Sheppo static void 7971991Sheppo vnet_add_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp) 7981991Sheppo { 7991991Sheppo vp_tl_t *ttlp; 8001991Sheppo 8011991Sheppo WRITE_ENTER(&vnetp->trwlock); 8021991Sheppo if (vnetp->tlp == NULL) { 8031991Sheppo vnetp->tlp = vp_tlp; 8041991Sheppo } else { 8051991Sheppo ttlp = vnetp->tlp; 8061991Sheppo while (ttlp->nextp) 8071991Sheppo ttlp = ttlp->nextp; 8081991Sheppo ttlp->nextp = vp_tlp; 8091991Sheppo } 8101991Sheppo RW_EXIT(&vnetp->trwlock); 8111991Sheppo } 8121991Sheppo 8131991Sheppo /* remove vp_tl from the list */ 8141991Sheppo static void 8151991Sheppo vnet_del_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp) 8161991Sheppo { 8171991Sheppo vp_tl_t *ttlp, **pretlp; 8181991Sheppo boolean_t found = B_FALSE; 8191991Sheppo 8201991Sheppo pretlp = &vnetp->tlp; 8211991Sheppo ttlp = *pretlp; 8221991Sheppo while (ttlp) { 8231991Sheppo if (ttlp == vp_tlp) { 8241991Sheppo found = B_TRUE; 8251991Sheppo (*pretlp) = ttlp->nextp; 8261991Sheppo ttlp->nextp = NULL; 8271991Sheppo break; 8281991Sheppo } 8291991Sheppo pretlp = &(ttlp->nextp); 8301991Sheppo ttlp = *pretlp; 8311991Sheppo } 8321991Sheppo 8331991Sheppo if (found) { 8341991Sheppo KMEM_FREE(vp_tlp); 8351991Sheppo } 8361991Sheppo } 8371991Sheppo 8381991Sheppo /* get vp_tl corresponding to the given name */ 8391991Sheppo static vp_tl_t * 8401991Sheppo vnet_get_vptl(vnet_t *vnetp, const char *name) 8411991Sheppo { 8421991Sheppo vp_tl_t *tlp; 8431991Sheppo 8441991Sheppo tlp = vnetp->tlp; 8451991Sheppo while (tlp) { 8461991Sheppo if (strcmp(tlp->name, name) == 0) { 8471991Sheppo return (tlp); 8481991Sheppo } 8491991Sheppo tlp = tlp->nextp; 8501991Sheppo } 8511991Sheppo DWARN((vnetp, 8521991Sheppo "vnet_get_vptl: can't find vp_tl with name (%s)\n", name)); 8531991Sheppo return (NULL); 8541991Sheppo } 8551991Sheppo 8561991Sheppo /* read the mac address of the device */ 8571991Sheppo static int 8581991Sheppo vnet_read_mac_address(vnet_t *vnetp) 8591991Sheppo { 8601991Sheppo uchar_t *macaddr; 8611991Sheppo uint32_t size; 8621991Sheppo int rv; 8631991Sheppo 8641991Sheppo rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip, 8651991Sheppo DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size); 8661991Sheppo if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) { 8671991Sheppo DWARN((vnetp, 8681991Sheppo "vnet_read_mac_address: prop_lookup failed (%s) err (%d)\n", 8691991Sheppo macaddr_propname, rv)); 8701991Sheppo return (DDI_FAILURE); 8711991Sheppo } 8721991Sheppo bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL); 8731991Sheppo bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL); 8741991Sheppo ddi_prop_free(macaddr); 8751991Sheppo 8761991Sheppo return (DDI_SUCCESS); 8771991Sheppo } 8781991Sheppo 8791991Sheppo 8801991Sheppo /* 8811991Sheppo * Functions below are called only by generic transport to add/remove/modify 8821991Sheppo * entries in forwarding database. See comments in vgen_port_init(vnet_gen.c). 8831991Sheppo */ 8841991Sheppo 8851991Sheppo /* add an entry into the forwarding database */ 8861991Sheppo void 8871991Sheppo vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg) 8881991Sheppo { 8891991Sheppo vnet_t *vnetp = (vnet_t *)arg; 8901991Sheppo uint32_t fdbhash; 8911991Sheppo fdb_t *fdbp; 8921991Sheppo fdb_fanout_t *fdbhp; 8931991Sheppo 8941991Sheppo /* Calculate hash value and fdb fanout */ 8951991Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 8961991Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 8971991Sheppo 8981991Sheppo WRITE_ENTER(&fdbhp->rwlock); 8991991Sheppo 9001991Sheppo fdbp = kmem_zalloc(sizeof (fdb_t), KM_NOSLEEP); 9011991Sheppo if (fdbp == NULL) { 9021991Sheppo RW_EXIT(&fdbhp->rwlock); 9031991Sheppo return; 9041991Sheppo } 9051991Sheppo bcopy(macaddr, (caddr_t)fdbp->macaddr, ETHERADDRL); 9061991Sheppo fdbp->m_tx = m_tx; 9071991Sheppo fdbp->txarg = txarg; 9081991Sheppo fdbp->nextp = fdbhp->headp; 9091991Sheppo fdbhp->headp = fdbp; 9101991Sheppo 9111991Sheppo RW_EXIT(&fdbhp->rwlock); 9121991Sheppo } 9131991Sheppo 9141991Sheppo /* delete an entry from the forwarding database */ 9151991Sheppo void 9161991Sheppo vnet_del_fdb(void *arg, uint8_t *macaddr) 9171991Sheppo { 9181991Sheppo vnet_t *vnetp = (vnet_t *)arg; 9191991Sheppo uint32_t fdbhash; 9201991Sheppo fdb_t *fdbp; 9211991Sheppo fdb_t **pfdbp; 9221991Sheppo fdb_fanout_t *fdbhp; 9231991Sheppo 9241991Sheppo /* Calculate hash value and fdb fanout */ 9251991Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 9261991Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 9271991Sheppo 9281991Sheppo WRITE_ENTER(&fdbhp->rwlock); 9291991Sheppo 9301991Sheppo for (pfdbp = &fdbhp->headp; (fdbp = *pfdbp) != NULL; 9311991Sheppo pfdbp = &fdbp->nextp) { 9321991Sheppo if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) { 9331991Sheppo /* Unlink it from the list */ 9341991Sheppo *pfdbp = fdbp->nextp; 9351991Sheppo KMEM_FREE(fdbp); 9361991Sheppo break; 9371991Sheppo } 9381991Sheppo } 9391991Sheppo 9401991Sheppo RW_EXIT(&fdbhp->rwlock); 9411991Sheppo } 9421991Sheppo 9431991Sheppo /* modify an existing entry in the forwarding database */ 9441991Sheppo void 9451991Sheppo vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg) 9461991Sheppo { 9471991Sheppo vnet_t *vnetp = (vnet_t *)arg; 9481991Sheppo uint32_t fdbhash; 9491991Sheppo fdb_t *fdbp; 9501991Sheppo fdb_fanout_t *fdbhp; 9511991Sheppo 9521991Sheppo /* Calculate hash value and fdb fanout */ 9531991Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 9541991Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 9551991Sheppo 9561991Sheppo WRITE_ENTER(&fdbhp->rwlock); 9571991Sheppo 9581991Sheppo for (fdbp = fdbhp->headp; fdbp != NULL; fdbp = fdbp->nextp) { 9591991Sheppo if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) { 9601991Sheppo /* change the entry to have new tx params */ 9611991Sheppo fdbp->m_tx = m_tx; 9621991Sheppo fdbp->txarg = txarg; 9631991Sheppo break; 9641991Sheppo } 9651991Sheppo } 9661991Sheppo 9671991Sheppo RW_EXIT(&fdbhp->rwlock); 9681991Sheppo } 9691991Sheppo 9701991Sheppo /* look up an fdb entry based on the mac address, caller holds lock */ 9711991Sheppo static fdb_t * 9721991Sheppo vnet_lookup_fdb(fdb_fanout_t *fdbhp, uint8_t *macaddr) 9731991Sheppo { 9741991Sheppo fdb_t *fdbp = NULL; 9751991Sheppo 9761991Sheppo for (fdbp = fdbhp->headp; fdbp != NULL; fdbp = fdbp->nextp) { 9771991Sheppo if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) { 9781991Sheppo break; 9791991Sheppo } 9801991Sheppo } 9811991Sheppo 9821991Sheppo return (fdbp); 9831991Sheppo } 9841991Sheppo 9851991Sheppo /* add default route entry into the forwarding database */ 9861991Sheppo void 9871991Sheppo vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg) 9881991Sheppo { 9891991Sheppo vnet_t *vnetp = (vnet_t *)arg; 9901991Sheppo fdb_t *fdbp; 9911991Sheppo fdb_fanout_t *fdbhp; 9921991Sheppo 9931991Sheppo /* 9941991Sheppo * The last hash list is reserved for default route entry, 9951991Sheppo * and for now, we have only one entry in this list. 9961991Sheppo */ 9971991Sheppo fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]); 9981991Sheppo 9991991Sheppo WRITE_ENTER(&fdbhp->rwlock); 10001991Sheppo 10011991Sheppo if (fdbhp->headp) { 10021991Sheppo DWARN((vnetp, 10031991Sheppo "vnet_add_def_rte: default rte already exists\n")); 10041991Sheppo RW_EXIT(&fdbhp->rwlock); 10051991Sheppo return; 10061991Sheppo } 10071991Sheppo fdbp = kmem_zalloc(sizeof (fdb_t), KM_NOSLEEP); 10081991Sheppo if (fdbp == NULL) { 10091991Sheppo RW_EXIT(&fdbhp->rwlock); 10101991Sheppo return; 10111991Sheppo } 10121991Sheppo bzero(fdbp->macaddr, ETHERADDRL); 10131991Sheppo fdbp->m_tx = m_tx; 10141991Sheppo fdbp->txarg = txarg; 10151991Sheppo fdbp->nextp = NULL; 10161991Sheppo fdbhp->headp = fdbp; 10171991Sheppo 10181991Sheppo RW_EXIT(&fdbhp->rwlock); 10191991Sheppo } 10201991Sheppo 10211991Sheppo /* delete default route entry from the forwarding database */ 10221991Sheppo void 10231991Sheppo vnet_del_def_rte(void *arg) 10241991Sheppo { 10251991Sheppo vnet_t *vnetp = (vnet_t *)arg; 10261991Sheppo fdb_t *fdbp; 10271991Sheppo fdb_fanout_t *fdbhp; 10281991Sheppo 10291991Sheppo /* 10301991Sheppo * The last hash list is reserved for default route entry, 10311991Sheppo * and for now, we have only one entry in this list. 10321991Sheppo */ 10331991Sheppo fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]); 10341991Sheppo 10351991Sheppo WRITE_ENTER(&fdbhp->rwlock); 10361991Sheppo 10371991Sheppo if (fdbhp->headp == NULL) { 10381991Sheppo RW_EXIT(&fdbhp->rwlock); 10391991Sheppo return; 10401991Sheppo } 10411991Sheppo fdbp = fdbhp->headp; 10421991Sheppo KMEM_FREE(fdbp); 10431991Sheppo fdbhp->headp = NULL; 10441991Sheppo 10451991Sheppo RW_EXIT(&fdbhp->rwlock); 10461991Sheppo } 1047