11ae08745Sheppo /* 21ae08745Sheppo * CDDL HEADER START 31ae08745Sheppo * 41ae08745Sheppo * The contents of this file are subject to the terms of the 51ae08745Sheppo * Common Development and Distribution License (the "License"). 61ae08745Sheppo * You may not use this file except in compliance with the License. 71ae08745Sheppo * 81ae08745Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91ae08745Sheppo * or http://www.opensolaris.org/os/licensing. 101ae08745Sheppo * See the License for the specific language governing permissions 111ae08745Sheppo * and limitations under the License. 121ae08745Sheppo * 131ae08745Sheppo * When distributing Covered Code, include this CDDL HEADER in each 141ae08745Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151ae08745Sheppo * If applicable, add the following below this CDDL HEADER, with the 161ae08745Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 171ae08745Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 181ae08745Sheppo * 191ae08745Sheppo * CDDL HEADER END 201ae08745Sheppo */ 211ae08745Sheppo 221ae08745Sheppo /* 23*844e62a3Sraghuram * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 241ae08745Sheppo * Use is subject to license terms. 251ae08745Sheppo */ 261ae08745Sheppo 271ae08745Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 281ae08745Sheppo 291ae08745Sheppo #include <sys/types.h> 301ae08745Sheppo #include <sys/errno.h> 311ae08745Sheppo #include <sys/param.h> 321ae08745Sheppo #include <sys/stream.h> 331ae08745Sheppo #include <sys/kmem.h> 341ae08745Sheppo #include <sys/conf.h> 351ae08745Sheppo #include <sys/devops.h> 361ae08745Sheppo #include <sys/ksynch.h> 371ae08745Sheppo #include <sys/stat.h> 381ae08745Sheppo #include <sys/modctl.h> 391ae08745Sheppo #include <sys/debug.h> 401ae08745Sheppo #include <sys/ethernet.h> 411ae08745Sheppo #include <sys/dlpi.h> 421ae08745Sheppo #include <net/if.h> 431ae08745Sheppo #include <sys/mac.h> 44ba2e4443Sseb #include <sys/mac_ether.h> 451ae08745Sheppo #include <sys/ddi.h> 461ae08745Sheppo #include <sys/sunddi.h> 471ae08745Sheppo #include <sys/strsun.h> 481ae08745Sheppo #include <sys/note.h> 491ae08745Sheppo #include <sys/vnet.h> 501ae08745Sheppo 511ae08745Sheppo /* 521ae08745Sheppo * Function prototypes. 531ae08745Sheppo */ 541ae08745Sheppo 551ae08745Sheppo /* DDI entrypoints */ 561ae08745Sheppo static int vnetdevinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 571ae08745Sheppo static int vnetattach(dev_info_t *, ddi_attach_cmd_t); 581ae08745Sheppo static int vnetdetach(dev_info_t *, ddi_detach_cmd_t); 591ae08745Sheppo 601ae08745Sheppo /* MAC entrypoints */ 61ba2e4443Sseb static int vnet_m_stat(void *, uint_t, uint64_t *); 621ae08745Sheppo static int vnet_m_start(void *); 631ae08745Sheppo static void vnet_m_stop(void *); 641ae08745Sheppo static int vnet_m_promisc(void *, boolean_t); 651ae08745Sheppo static int vnet_m_multicst(void *, boolean_t, const uint8_t *); 661ae08745Sheppo static int vnet_m_unicst(void *, const uint8_t *); 671ae08745Sheppo mblk_t *vnet_m_tx(void *, mblk_t *); 681ae08745Sheppo 691ae08745Sheppo /* vnet internal functions */ 701ae08745Sheppo static int vnet_mac_register(vnet_t *); 711ae08745Sheppo static int vnet_read_mac_address(vnet_t *vnetp); 721ae08745Sheppo static void vnet_add_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp); 731ae08745Sheppo static void vnet_del_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp); 741ae08745Sheppo static vp_tl_t *vnet_get_vptl(vnet_t *vnetp, const char *devname); 751ae08745Sheppo static fdb_t *vnet_lookup_fdb(fdb_fanout_t *fdbhp, uint8_t *macaddr); 761ae08745Sheppo 771ae08745Sheppo /* exported functions */ 781ae08745Sheppo void vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg); 791ae08745Sheppo void vnet_del_fdb(void *arg, uint8_t *macaddr); 803af08d82Slm66018 void vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, 813af08d82Slm66018 void *txarg, boolean_t upgrade); 821ae08745Sheppo void vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg); 831ae08745Sheppo void vnet_del_def_rte(void *arg); 84ba2e4443Sseb void vnet_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp); 85ba2e4443Sseb void vnet_tx_update(void *arg); 861ae08745Sheppo 871ae08745Sheppo /* externs */ 88ba2e4443Sseb extern int vgen_init(void *vnetp, dev_info_t *vnetdip, const uint8_t *macaddr, 89ba2e4443Sseb mac_register_t **vgenmacp); 90d10e4ef2Snarayan extern int vgen_uninit(void *arg); 911ae08745Sheppo 92ba2e4443Sseb static mac_callbacks_t vnet_m_callbacks = { 93ba2e4443Sseb 0, 94ba2e4443Sseb vnet_m_stat, 95ba2e4443Sseb vnet_m_start, 96ba2e4443Sseb vnet_m_stop, 97ba2e4443Sseb vnet_m_promisc, 98ba2e4443Sseb vnet_m_multicst, 99ba2e4443Sseb vnet_m_unicst, 100ba2e4443Sseb vnet_m_tx, 101ba2e4443Sseb NULL, 102ba2e4443Sseb NULL, 103ba2e4443Sseb NULL 104ba2e4443Sseb }; 105ba2e4443Sseb 1061ae08745Sheppo /* 1071ae08745Sheppo * Linked list of "vnet_t" structures - one per instance. 1081ae08745Sheppo */ 1091ae08745Sheppo static vnet_t *vnet_headp = NULL; 1101ae08745Sheppo static krwlock_t vnet_rw; 1111ae08745Sheppo 1121ae08745Sheppo /* Tunables */ 1131ae08745Sheppo uint32_t vnet_ntxds = VNET_NTXDS; /* power of 2 transmit descriptors */ 1141ae08745Sheppo uint32_t vnet_ldcwd_interval = VNET_LDCWD_INTERVAL; /* watchdog freq in msec */ 1151ae08745Sheppo uint32_t vnet_ldcwd_txtimeout = VNET_LDCWD_TXTIMEOUT; /* tx timeout in msec */ 116e1ebb9ecSlm66018 uint32_t vnet_ldc_mtu = VNET_LDC_MTU; /* ldc mtu */ 1171ae08745Sheppo uint32_t vnet_nfdb_hash = VNET_NFDB_HASH; /* size of fdb hash table */ 1181ae08745Sheppo 1191ae08745Sheppo /* 1201ae08745Sheppo * Property names 1211ae08745Sheppo */ 1221ae08745Sheppo static char macaddr_propname[] = "local-mac-address"; 1231ae08745Sheppo 1241ae08745Sheppo /* 1251ae08745Sheppo * This is the string displayed by modinfo(1m). 1261ae08745Sheppo */ 1278e6a2a04Slm66018 static char vnet_ident[] = "vnet driver v%I%"; 1281ae08745Sheppo extern struct mod_ops mod_driverops; 1291ae08745Sheppo static struct cb_ops cb_vnetops = { 1301ae08745Sheppo nulldev, /* cb_open */ 1311ae08745Sheppo nulldev, /* cb_close */ 1321ae08745Sheppo nodev, /* cb_strategy */ 1331ae08745Sheppo nodev, /* cb_print */ 1341ae08745Sheppo nodev, /* cb_dump */ 1351ae08745Sheppo nodev, /* cb_read */ 1361ae08745Sheppo nodev, /* cb_write */ 1371ae08745Sheppo nodev, /* cb_ioctl */ 1381ae08745Sheppo nodev, /* cb_devmap */ 1391ae08745Sheppo nodev, /* cb_mmap */ 1401ae08745Sheppo nodev, /* cb_segmap */ 1411ae08745Sheppo nochpoll, /* cb_chpoll */ 1421ae08745Sheppo ddi_prop_op, /* cb_prop_op */ 1431ae08745Sheppo NULL, /* cb_stream */ 1441ae08745Sheppo (int)(D_MP) /* cb_flag */ 1451ae08745Sheppo }; 1461ae08745Sheppo 1471ae08745Sheppo static struct dev_ops vnetops = { 1481ae08745Sheppo DEVO_REV, /* devo_rev */ 1491ae08745Sheppo 0, /* devo_refcnt */ 1501ae08745Sheppo NULL, /* devo_getinfo */ 1511ae08745Sheppo nulldev, /* devo_identify */ 1521ae08745Sheppo nulldev, /* devo_probe */ 1531ae08745Sheppo vnetattach, /* devo_attach */ 1541ae08745Sheppo vnetdetach, /* devo_detach */ 1551ae08745Sheppo nodev, /* devo_reset */ 1561ae08745Sheppo &cb_vnetops, /* devo_cb_ops */ 1571ae08745Sheppo (struct bus_ops *)NULL /* devo_bus_ops */ 1581ae08745Sheppo }; 1591ae08745Sheppo 1601ae08745Sheppo static struct modldrv modldrv = { 1611ae08745Sheppo &mod_driverops, /* Type of module. This one is a driver */ 1621ae08745Sheppo vnet_ident, /* ID string */ 1631ae08745Sheppo &vnetops /* driver specific ops */ 1641ae08745Sheppo }; 1651ae08745Sheppo 1661ae08745Sheppo static struct modlinkage modlinkage = { 1671ae08745Sheppo MODREV_1, (void *)&modldrv, NULL 1681ae08745Sheppo }; 1691ae08745Sheppo 170*844e62a3Sraghuram #ifdef DEBUG 1711ae08745Sheppo 1721ae08745Sheppo /* 1731ae08745Sheppo * Print debug messages - set to 0xf to enable all msgs 1741ae08745Sheppo */ 175*844e62a3Sraghuram int vnet_dbglevel = 0x8; 1761ae08745Sheppo 177*844e62a3Sraghuram static void 178*844e62a3Sraghuram debug_printf(const char *fname, void *arg, const char *fmt, ...) 1791ae08745Sheppo { 1801ae08745Sheppo char buf[512]; 1811ae08745Sheppo va_list ap; 1821ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 183*844e62a3Sraghuram char *bufp = buf; 1841ae08745Sheppo 185*844e62a3Sraghuram if (vnetp == NULL) { 186*844e62a3Sraghuram (void) sprintf(bufp, "%s: ", fname); 187*844e62a3Sraghuram bufp += strlen(bufp); 188*844e62a3Sraghuram } else { 189*844e62a3Sraghuram (void) sprintf(bufp, "vnet%d:%s: ", vnetp->instance, fname); 190*844e62a3Sraghuram bufp += strlen(bufp); 1911ae08745Sheppo } 192*844e62a3Sraghuram va_start(ap, fmt); 193*844e62a3Sraghuram (void) vsprintf(bufp, fmt, ap); 194*844e62a3Sraghuram va_end(ap); 195*844e62a3Sraghuram cmn_err(CE_CONT, "%s\n", buf); 196*844e62a3Sraghuram } 1971ae08745Sheppo 1981ae08745Sheppo #endif 1991ae08745Sheppo 2001ae08745Sheppo /* _init(9E): initialize the loadable module */ 2011ae08745Sheppo int 2021ae08745Sheppo _init(void) 2031ae08745Sheppo { 2041ae08745Sheppo int status; 2051ae08745Sheppo 206*844e62a3Sraghuram DBG1(NULL, "enter\n"); 2071ae08745Sheppo 2081ae08745Sheppo mac_init_ops(&vnetops, "vnet"); 2091ae08745Sheppo status = mod_install(&modlinkage); 2101ae08745Sheppo if (status != 0) { 2111ae08745Sheppo mac_fini_ops(&vnetops); 2121ae08745Sheppo } 2131ae08745Sheppo 214*844e62a3Sraghuram DBG1(NULL, "exit(%d)\n", status); 2151ae08745Sheppo return (status); 2161ae08745Sheppo } 2171ae08745Sheppo 2181ae08745Sheppo /* _fini(9E): prepare the module for unloading. */ 2191ae08745Sheppo int 2201ae08745Sheppo _fini(void) 2211ae08745Sheppo { 2221ae08745Sheppo int status; 2231ae08745Sheppo 224*844e62a3Sraghuram DBG1(NULL, "enter\n"); 2251ae08745Sheppo 2261ae08745Sheppo status = mod_remove(&modlinkage); 2271ae08745Sheppo if (status != 0) 2281ae08745Sheppo return (status); 2291ae08745Sheppo mac_fini_ops(&vnetops); 2301ae08745Sheppo 231*844e62a3Sraghuram DBG1(NULL, "exit(%d)\n", status); 2321ae08745Sheppo return (status); 2331ae08745Sheppo } 2341ae08745Sheppo 2351ae08745Sheppo /* _info(9E): return information about the loadable module */ 2361ae08745Sheppo int 2371ae08745Sheppo _info(struct modinfo *modinfop) 2381ae08745Sheppo { 2391ae08745Sheppo return (mod_info(&modlinkage, modinfop)); 2401ae08745Sheppo } 2411ae08745Sheppo 2421ae08745Sheppo /* 2431ae08745Sheppo * attach(9E): attach a device to the system. 2441ae08745Sheppo * called once for each instance of the device on the system. 2451ae08745Sheppo */ 2461ae08745Sheppo static int 2471ae08745Sheppo vnetattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2481ae08745Sheppo { 2491ae08745Sheppo vnet_t *vnetp; 2501ae08745Sheppo vp_tl_t *vp_tlp; 2511ae08745Sheppo int instance; 2521ae08745Sheppo int status; 253*844e62a3Sraghuram mac_register_t *vgenmacp = NULL; 254*844e62a3Sraghuram uint32_t nfdbh = 0; 2551ae08745Sheppo enum { AST_init = 0x0, AST_vnet_alloc = 0x1, 256d10e4ef2Snarayan AST_mac_alloc = 0x2, AST_read_macaddr = 0x4, 257d10e4ef2Snarayan AST_vgen_init = 0x8, AST_vptl_alloc = 0x10, 258*844e62a3Sraghuram AST_fdbh_alloc = 0x20 } attach_state; 2591ae08745Sheppo 2601ae08745Sheppo attach_state = AST_init; 2611ae08745Sheppo 2621ae08745Sheppo switch (cmd) { 2631ae08745Sheppo case DDI_ATTACH: 2641ae08745Sheppo break; 2651ae08745Sheppo case DDI_RESUME: 2661ae08745Sheppo case DDI_PM_RESUME: 2671ae08745Sheppo default: 2681ae08745Sheppo goto vnet_attach_fail; 2691ae08745Sheppo } 2701ae08745Sheppo 2711ae08745Sheppo instance = ddi_get_instance(dip); 272*844e62a3Sraghuram DBG1(NULL, "instance(%d) enter\n", instance); 2731ae08745Sheppo 2741ae08745Sheppo /* allocate vnet_t and mac_t structures */ 2751ae08745Sheppo vnetp = kmem_zalloc(sizeof (vnet_t), KM_SLEEP); 2761ae08745Sheppo attach_state |= AST_vnet_alloc; 2771ae08745Sheppo 2781ae08745Sheppo /* setup links to vnet_t from both devinfo and mac_t */ 2791ae08745Sheppo ddi_set_driver_private(dip, (caddr_t)vnetp); 2801ae08745Sheppo vnetp->dip = dip; 2811ae08745Sheppo vnetp->instance = instance; 2821ae08745Sheppo 2831ae08745Sheppo /* read the mac address */ 2841ae08745Sheppo status = vnet_read_mac_address(vnetp); 2851ae08745Sheppo if (status != DDI_SUCCESS) { 2861ae08745Sheppo goto vnet_attach_fail; 2871ae08745Sheppo } 2881ae08745Sheppo attach_state |= AST_read_macaddr; 2891ae08745Sheppo 2901ae08745Sheppo /* 2911ae08745Sheppo * Initialize the generic vnet proxy transport. This is the first 2921ae08745Sheppo * and default transport used by vnet. The generic transport 2931ae08745Sheppo * is provided by using sun4v LDC (logical domain channel). On success, 2941ae08745Sheppo * vgen_init() provides a pointer to mac_t of generic transport. 2951ae08745Sheppo * Currently, this generic layer provides network connectivity to other 2961ae08745Sheppo * vnets within ldoms and also to remote hosts oustide ldoms through 2971ae08745Sheppo * the virtual switch (vsw) device on domain0. In the future, when 2981ae08745Sheppo * physical adapters that are able to share their resources (such as 2991ae08745Sheppo * dma channels) with guest domains become available, the vnet device 3001ae08745Sheppo * will use hardware specific driver to communicate directly over the 3011ae08745Sheppo * physical device to reach remote hosts without going through vswitch. 3021ae08745Sheppo */ 303ba2e4443Sseb status = vgen_init(vnetp, vnetp->dip, (uint8_t *)vnetp->curr_macaddr, 304ba2e4443Sseb &vgenmacp); 3051ae08745Sheppo if (status != DDI_SUCCESS) { 306*844e62a3Sraghuram DERR(vnetp, "vgen_init() failed\n"); 3071ae08745Sheppo goto vnet_attach_fail; 3081ae08745Sheppo } 3091ae08745Sheppo attach_state |= AST_vgen_init; 3101ae08745Sheppo 3111ae08745Sheppo vp_tlp = kmem_zalloc(sizeof (vp_tl_t), KM_SLEEP); 3121ae08745Sheppo vp_tlp->macp = vgenmacp; 3131ae08745Sheppo (void) snprintf(vp_tlp->name, MAXNAMELEN, "%s%u", "vgen", instance); 3141ae08745Sheppo (void) strcpy(vnetp->vgen_name, vp_tlp->name); 3151ae08745Sheppo 3161ae08745Sheppo /* add generic transport to the list of vnet proxy transports */ 3171ae08745Sheppo vnet_add_vptl(vnetp, vp_tlp); 3181ae08745Sheppo attach_state |= AST_vptl_alloc; 3191ae08745Sheppo 3201ae08745Sheppo nfdbh = vnet_nfdb_hash; 3211ae08745Sheppo if ((nfdbh < VNET_NFDB_HASH) || (nfdbh > VNET_NFDB_HASH_MAX)) { 3221ae08745Sheppo vnetp->nfdb_hash = VNET_NFDB_HASH; 3231ae08745Sheppo } 3241ae08745Sheppo else 3251ae08745Sheppo vnetp->nfdb_hash = nfdbh; 3261ae08745Sheppo 3271ae08745Sheppo /* allocate fdb hash table, with an extra slot for default route */ 3281ae08745Sheppo vnetp->fdbhp = kmem_zalloc(sizeof (fdb_fanout_t) * 3291ae08745Sheppo (vnetp->nfdb_hash + 1), KM_SLEEP); 3301ae08745Sheppo attach_state |= AST_fdbh_alloc; 3311ae08745Sheppo 3321ae08745Sheppo /* register with MAC layer */ 3331ae08745Sheppo status = vnet_mac_register(vnetp); 3341ae08745Sheppo if (status != DDI_SUCCESS) { 3351ae08745Sheppo goto vnet_attach_fail; 3361ae08745Sheppo } 3371ae08745Sheppo 3381ae08745Sheppo /* add to the list of vnet devices */ 3391ae08745Sheppo WRITE_ENTER(&vnet_rw); 3401ae08745Sheppo vnetp->nextp = vnet_headp; 3411ae08745Sheppo vnet_headp = vnetp; 3421ae08745Sheppo RW_EXIT(&vnet_rw); 3431ae08745Sheppo 344*844e62a3Sraghuram DBG1(NULL, "instance(%d) exit\n", instance); 3451ae08745Sheppo return (DDI_SUCCESS); 3461ae08745Sheppo 3471ae08745Sheppo vnet_attach_fail: 3481ae08745Sheppo if (attach_state & AST_fdbh_alloc) { 3491ae08745Sheppo kmem_free(vnetp->fdbhp, 3501ae08745Sheppo sizeof (fdb_fanout_t) * (vnetp->nfdb_hash + 1)); 3511ae08745Sheppo } 3521ae08745Sheppo if (attach_state & AST_vptl_alloc) { 3531ae08745Sheppo WRITE_ENTER(&vnetp->trwlock); 3541ae08745Sheppo vnet_del_vptl(vnetp, vp_tlp); 3551ae08745Sheppo RW_EXIT(&vnetp->trwlock); 3561ae08745Sheppo } 3571ae08745Sheppo if (attach_state & AST_vgen_init) { 358d10e4ef2Snarayan (void) vgen_uninit(vgenmacp->m_driver); 3591ae08745Sheppo } 3601ae08745Sheppo if (attach_state & AST_vnet_alloc) { 3611ae08745Sheppo KMEM_FREE(vnetp); 3621ae08745Sheppo } 3631ae08745Sheppo return (DDI_FAILURE); 3641ae08745Sheppo } 3651ae08745Sheppo 3661ae08745Sheppo /* 3671ae08745Sheppo * detach(9E): detach a device from the system. 3681ae08745Sheppo */ 3691ae08745Sheppo static int 3701ae08745Sheppo vnetdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3711ae08745Sheppo { 3721ae08745Sheppo vnet_t *vnetp; 3731ae08745Sheppo vnet_t **vnetpp; 3741ae08745Sheppo vp_tl_t *vp_tlp; 3751ae08745Sheppo int instance; 376d10e4ef2Snarayan int rv; 3771ae08745Sheppo 3781ae08745Sheppo instance = ddi_get_instance(dip); 379*844e62a3Sraghuram DBG1(NULL, "instance(%d) enter\n", instance); 3801ae08745Sheppo 3811ae08745Sheppo vnetp = ddi_get_driver_private(dip); 3821ae08745Sheppo if (vnetp == NULL) { 3831ae08745Sheppo goto vnet_detach_fail; 3841ae08745Sheppo } 3851ae08745Sheppo 3861ae08745Sheppo switch (cmd) { 3871ae08745Sheppo case DDI_DETACH: 3881ae08745Sheppo break; 3891ae08745Sheppo case DDI_SUSPEND: 3901ae08745Sheppo case DDI_PM_SUSPEND: 3911ae08745Sheppo default: 3921ae08745Sheppo goto vnet_detach_fail; 3931ae08745Sheppo } 3941ae08745Sheppo 395d10e4ef2Snarayan /* uninit and free vnet proxy transports */ 396d10e4ef2Snarayan WRITE_ENTER(&vnetp->trwlock); 397d10e4ef2Snarayan while ((vp_tlp = vnetp->tlp) != NULL) { 398d10e4ef2Snarayan if (strcmp(vnetp->vgen_name, vp_tlp->name) == 0) { 399d10e4ef2Snarayan /* uninitialize generic transport */ 400d10e4ef2Snarayan rv = vgen_uninit(vp_tlp->macp->m_driver); 401d10e4ef2Snarayan if (rv != DDI_SUCCESS) { 402d10e4ef2Snarayan RW_EXIT(&vnetp->trwlock); 403d10e4ef2Snarayan goto vnet_detach_fail; 404d10e4ef2Snarayan } 405d10e4ef2Snarayan } 406d10e4ef2Snarayan vnet_del_vptl(vnetp, vp_tlp); 407d10e4ef2Snarayan } 408d10e4ef2Snarayan RW_EXIT(&vnetp->trwlock); 409d10e4ef2Snarayan 4101ae08745Sheppo /* 4111ae08745Sheppo * Unregister from the MAC subsystem. This can fail, in 4121ae08745Sheppo * particular if there are DLPI style-2 streams still open - 4131ae08745Sheppo * in which case we just return failure. 4141ae08745Sheppo */ 415ba2e4443Sseb if (mac_unregister(vnetp->mh) != 0) 4161ae08745Sheppo goto vnet_detach_fail; 4171ae08745Sheppo 4181ae08745Sheppo /* unlink from instance(vnet_t) list */ 4191ae08745Sheppo WRITE_ENTER(&vnet_rw); 4201ae08745Sheppo for (vnetpp = &vnet_headp; *vnetpp; vnetpp = &(*vnetpp)->nextp) { 4211ae08745Sheppo if (*vnetpp == vnetp) { 4221ae08745Sheppo *vnetpp = vnetp->nextp; 4231ae08745Sheppo break; 4241ae08745Sheppo } 4251ae08745Sheppo } 4261ae08745Sheppo RW_EXIT(&vnet_rw); 4271ae08745Sheppo 428445b4c2eSsb155480 kmem_free(vnetp->fdbhp, 429445b4c2eSsb155480 sizeof (fdb_fanout_t) * (vnetp->nfdb_hash + 1)); 430445b4c2eSsb155480 4311ae08745Sheppo KMEM_FREE(vnetp); 4321ae08745Sheppo 4331ae08745Sheppo return (DDI_SUCCESS); 4341ae08745Sheppo 4351ae08745Sheppo vnet_detach_fail: 4361ae08745Sheppo return (DDI_FAILURE); 4371ae08745Sheppo } 4381ae08745Sheppo 4391ae08745Sheppo /* enable the device for transmit/receive */ 4401ae08745Sheppo static int 4411ae08745Sheppo vnet_m_start(void *arg) 4421ae08745Sheppo { 4431ae08745Sheppo vnet_t *vnetp = arg; 4441ae08745Sheppo vp_tl_t *vp_tlp; 445ba2e4443Sseb mac_register_t *vp_macp; 446ba2e4443Sseb mac_callbacks_t *cbp; 4471ae08745Sheppo 448*844e62a3Sraghuram DBG1(vnetp, "enter\n"); 4491ae08745Sheppo 4501ae08745Sheppo /* 4513af08d82Slm66018 * NOTE: 4521ae08745Sheppo * Currently, we only have generic transport. m_start() invokes 4531ae08745Sheppo * vgen_start() which enables ports/channels in vgen and 4541ae08745Sheppo * initiates handshake with peer vnets and vsw. In the future when we 4551ae08745Sheppo * have support for hardware specific transports, this information 4561ae08745Sheppo * needs to be propagted back to vnet from vgen and we need to revisit 4571ae08745Sheppo * this code (see comments in vnet_attach()). 4581ae08745Sheppo * 4591ae08745Sheppo */ 4601ae08745Sheppo WRITE_ENTER(&vnetp->trwlock); 4611ae08745Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 4621ae08745Sheppo vp_macp = vp_tlp->macp; 463ba2e4443Sseb cbp = vp_macp->m_callbacks; 464ba2e4443Sseb cbp->mc_start(vp_macp->m_driver); 4651ae08745Sheppo } 4661ae08745Sheppo RW_EXIT(&vnetp->trwlock); 4671ae08745Sheppo 468*844e62a3Sraghuram DBG1(vnetp, "exit\n"); 4691ae08745Sheppo return (VNET_SUCCESS); 4701ae08745Sheppo 4711ae08745Sheppo } 4721ae08745Sheppo 4731ae08745Sheppo /* stop transmit/receive for the device */ 4741ae08745Sheppo static void 4751ae08745Sheppo vnet_m_stop(void *arg) 4761ae08745Sheppo { 4771ae08745Sheppo vnet_t *vnetp = arg; 4781ae08745Sheppo vp_tl_t *vp_tlp; 479ba2e4443Sseb mac_register_t *vp_macp; 480ba2e4443Sseb mac_callbacks_t *cbp; 4811ae08745Sheppo 482*844e62a3Sraghuram DBG1(vnetp, "enter\n"); 4831ae08745Sheppo 4841ae08745Sheppo WRITE_ENTER(&vnetp->trwlock); 4851ae08745Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 4861ae08745Sheppo vp_macp = vp_tlp->macp; 487ba2e4443Sseb cbp = vp_macp->m_callbacks; 488ba2e4443Sseb cbp->mc_stop(vp_macp->m_driver); 4891ae08745Sheppo } 4901ae08745Sheppo RW_EXIT(&vnetp->trwlock); 4911ae08745Sheppo 492*844e62a3Sraghuram DBG1(vnetp, "exit\n"); 4931ae08745Sheppo } 4941ae08745Sheppo 4951ae08745Sheppo /* set the unicast mac address of the device */ 4961ae08745Sheppo static int 4971ae08745Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr) 4981ae08745Sheppo { 4991ae08745Sheppo _NOTE(ARGUNUSED(macaddr)) 5001ae08745Sheppo 5011ae08745Sheppo vnet_t *vnetp = arg; 5021ae08745Sheppo 503*844e62a3Sraghuram DBG1(vnetp, "enter\n"); 5041ae08745Sheppo /* 5053af08d82Slm66018 * NOTE: setting mac address dynamically is not supported. 5061ae08745Sheppo */ 507*844e62a3Sraghuram DBG1(vnetp, "exit\n"); 5081ae08745Sheppo 5098e6a2a04Slm66018 return (VNET_FAILURE); 5101ae08745Sheppo } 5111ae08745Sheppo 5121ae08745Sheppo /* enable/disable a multicast address */ 5131ae08745Sheppo static int 5141ae08745Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 5151ae08745Sheppo { 5161ae08745Sheppo _NOTE(ARGUNUSED(add, mca)) 5171ae08745Sheppo 5181ae08745Sheppo vnet_t *vnetp = arg; 5191ae08745Sheppo vp_tl_t *vp_tlp; 520ba2e4443Sseb mac_register_t *vp_macp; 521ba2e4443Sseb mac_callbacks_t *cbp; 5221ae08745Sheppo int rv = VNET_SUCCESS; 5231ae08745Sheppo 524*844e62a3Sraghuram DBG1(vnetp, "enter\n"); 5251ae08745Sheppo READ_ENTER(&vnetp->trwlock); 5261ae08745Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 5271ae08745Sheppo if (strcmp(vnetp->vgen_name, vp_tlp->name) == 0) { 5281ae08745Sheppo vp_macp = vp_tlp->macp; 529ba2e4443Sseb cbp = vp_macp->m_callbacks; 530ba2e4443Sseb rv = cbp->mc_multicst(vp_macp->m_driver, add, mca); 5311ae08745Sheppo break; 5321ae08745Sheppo } 5331ae08745Sheppo } 5341ae08745Sheppo RW_EXIT(&vnetp->trwlock); 535*844e62a3Sraghuram DBG1(vnetp, "exit(%d)\n", rv); 5361ae08745Sheppo return (rv); 5371ae08745Sheppo } 5381ae08745Sheppo 5391ae08745Sheppo /* set or clear promiscuous mode on the device */ 5401ae08745Sheppo static int 5411ae08745Sheppo vnet_m_promisc(void *arg, boolean_t on) 5421ae08745Sheppo { 5431ae08745Sheppo _NOTE(ARGUNUSED(on)) 5441ae08745Sheppo 5451ae08745Sheppo vnet_t *vnetp = arg; 546*844e62a3Sraghuram DBG1(vnetp, "enter\n"); 5471ae08745Sheppo /* 5483af08d82Slm66018 * NOTE: setting promiscuous mode is not supported, just return success. 5491ae08745Sheppo */ 550*844e62a3Sraghuram DBG1(vnetp, "exit\n"); 5511ae08745Sheppo return (VNET_SUCCESS); 5521ae08745Sheppo } 5531ae08745Sheppo 5541ae08745Sheppo /* 5551ae08745Sheppo * Transmit a chain of packets. This function provides switching functionality 5561ae08745Sheppo * based on the destination mac address to reach other guests (within ldoms) or 5571ae08745Sheppo * external hosts. 5581ae08745Sheppo */ 5591ae08745Sheppo mblk_t * 5601ae08745Sheppo vnet_m_tx(void *arg, mblk_t *mp) 5611ae08745Sheppo { 5621ae08745Sheppo vnet_t *vnetp; 5631ae08745Sheppo mblk_t *next; 5641ae08745Sheppo uint32_t fdbhash; 5651ae08745Sheppo fdb_t *fdbp; 5661ae08745Sheppo fdb_fanout_t *fdbhp; 5671ae08745Sheppo struct ether_header *ehp; 5681ae08745Sheppo uint8_t *macaddr; 5691ae08745Sheppo mblk_t *resid_mp; 5701ae08745Sheppo 5711ae08745Sheppo vnetp = (vnet_t *)arg; 572*844e62a3Sraghuram DBG1(vnetp, "enter\n"); 5731ae08745Sheppo ASSERT(mp != NULL); 5741ae08745Sheppo 5751ae08745Sheppo while (mp != NULL) { 5761ae08745Sheppo next = mp->b_next; 5771ae08745Sheppo mp->b_next = NULL; 5781ae08745Sheppo 5791ae08745Sheppo /* get the destination mac address in the eth header */ 5801ae08745Sheppo ehp = (struct ether_header *)mp->b_rptr; 5811ae08745Sheppo macaddr = (uint8_t *)&ehp->ether_dhost; 5821ae08745Sheppo 5831ae08745Sheppo /* Calculate hash value and fdb fanout */ 5841ae08745Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 5851ae08745Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 5861ae08745Sheppo 5871ae08745Sheppo READ_ENTER(&fdbhp->rwlock); 5881ae08745Sheppo fdbp = vnet_lookup_fdb(fdbhp, macaddr); 5891ae08745Sheppo if (fdbp) { 5901ae08745Sheppo /* 5911ae08745Sheppo * If the destination is in FDB, the destination is 5921ae08745Sheppo * a vnet device within ldoms and directly reachable, 5931ae08745Sheppo * invoke the tx function in the fdb entry. 5941ae08745Sheppo */ 5951ae08745Sheppo resid_mp = fdbp->m_tx(fdbp->txarg, mp); 5961ae08745Sheppo if (resid_mp != NULL) { 5971ae08745Sheppo /* m_tx failed */ 5981ae08745Sheppo mp->b_next = next; 5991ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 6001ae08745Sheppo break; 6011ae08745Sheppo } 6021ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 6031ae08745Sheppo } else { 6041ae08745Sheppo /* destination is not in FDB */ 6051ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 6061ae08745Sheppo /* 6071ae08745Sheppo * If the destination is broadcast/multicast 6081ae08745Sheppo * or an unknown unicast address, forward the 6091ae08745Sheppo * packet to vsw, using the last slot in fdb which is 6101ae08745Sheppo * reserved for default route. 6111ae08745Sheppo */ 6121ae08745Sheppo fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]); 6131ae08745Sheppo READ_ENTER(&fdbhp->rwlock); 6141ae08745Sheppo fdbp = fdbhp->headp; 6151ae08745Sheppo if (fdbp) { 6161ae08745Sheppo resid_mp = fdbp->m_tx(fdbp->txarg, mp); 6171ae08745Sheppo if (resid_mp != NULL) { 6181ae08745Sheppo /* m_tx failed */ 6191ae08745Sheppo mp->b_next = next; 6201ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 6211ae08745Sheppo break; 6221ae08745Sheppo } 6231ae08745Sheppo } else { 6241ae08745Sheppo /* drop the packet */ 6251ae08745Sheppo freemsg(mp); 6261ae08745Sheppo } 6271ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 6281ae08745Sheppo } 6291ae08745Sheppo 6301ae08745Sheppo mp = next; 6311ae08745Sheppo } 6321ae08745Sheppo 633*844e62a3Sraghuram DBG1(vnetp, "exit\n"); 6341ae08745Sheppo return (mp); 6351ae08745Sheppo } 6361ae08745Sheppo 6371ae08745Sheppo /* get statistics from the device */ 638ba2e4443Sseb int 639ba2e4443Sseb vnet_m_stat(void *arg, uint_t stat, uint64_t *val) 6401ae08745Sheppo { 6411ae08745Sheppo vnet_t *vnetp = arg; 6421ae08745Sheppo vp_tl_t *vp_tlp; 643ba2e4443Sseb mac_register_t *vp_macp; 644ba2e4443Sseb mac_callbacks_t *cbp; 645ba2e4443Sseb uint64_t val_total = 0; 6461ae08745Sheppo 647*844e62a3Sraghuram DBG1(vnetp, "enter\n"); 6481ae08745Sheppo 6491ae08745Sheppo /* 650ba2e4443Sseb * get the specified statistic from each transport and return the 651ba2e4443Sseb * aggregate val. This obviously only works for counters. 6521ae08745Sheppo */ 653ba2e4443Sseb if ((IS_MAC_STAT(stat) && !MAC_STAT_ISACOUNTER(stat)) || 654ba2e4443Sseb (IS_MACTYPE_STAT(stat) && !ETHER_STAT_ISACOUNTER(stat))) { 655ba2e4443Sseb return (ENOTSUP); 656ba2e4443Sseb } 6571ae08745Sheppo READ_ENTER(&vnetp->trwlock); 6581ae08745Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 6591ae08745Sheppo vp_macp = vp_tlp->macp; 660ba2e4443Sseb cbp = vp_macp->m_callbacks; 661ba2e4443Sseb if (cbp->mc_getstat(vp_macp->m_driver, stat, val) == 0) 662ba2e4443Sseb val_total += *val; 6631ae08745Sheppo } 6641ae08745Sheppo RW_EXIT(&vnetp->trwlock); 6651ae08745Sheppo 666ba2e4443Sseb *val = val_total; 667ba2e4443Sseb 668*844e62a3Sraghuram DBG1(vnetp, "exit\n"); 669ba2e4443Sseb return (0); 6701ae08745Sheppo } 6711ae08745Sheppo 6721ae08745Sheppo /* wrapper function for mac_register() */ 6731ae08745Sheppo static int 6741ae08745Sheppo vnet_mac_register(vnet_t *vnetp) 6751ae08745Sheppo { 676ba2e4443Sseb mac_register_t *macp; 677ba2e4443Sseb int err; 6781ae08745Sheppo 679ba2e4443Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 680ba2e4443Sseb return (DDI_FAILURE); 681ba2e4443Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 682ba2e4443Sseb macp->m_driver = vnetp; 6831ae08745Sheppo macp->m_dip = vnetp->dip; 684ba2e4443Sseb macp->m_src_addr = vnetp->curr_macaddr; 685ba2e4443Sseb macp->m_callbacks = &vnet_m_callbacks; 686ba2e4443Sseb macp->m_min_sdu = 0; 687ba2e4443Sseb macp->m_max_sdu = ETHERMTU; 6881ae08745Sheppo 6891ae08745Sheppo /* 6901ae08745Sheppo * Finally, we're ready to register ourselves with the MAC layer 6911ae08745Sheppo * interface; if this succeeds, we're all ready to start() 6921ae08745Sheppo */ 693ba2e4443Sseb err = mac_register(macp, &vnetp->mh); 694ba2e4443Sseb mac_free(macp); 695ba2e4443Sseb return (err == 0 ? DDI_SUCCESS : DDI_FAILURE); 6961ae08745Sheppo } 6971ae08745Sheppo 6981ae08745Sheppo /* add vp_tl to the list */ 6991ae08745Sheppo static void 7001ae08745Sheppo vnet_add_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp) 7011ae08745Sheppo { 7021ae08745Sheppo vp_tl_t *ttlp; 7031ae08745Sheppo 7041ae08745Sheppo WRITE_ENTER(&vnetp->trwlock); 7051ae08745Sheppo if (vnetp->tlp == NULL) { 7061ae08745Sheppo vnetp->tlp = vp_tlp; 7071ae08745Sheppo } else { 7081ae08745Sheppo ttlp = vnetp->tlp; 7091ae08745Sheppo while (ttlp->nextp) 7101ae08745Sheppo ttlp = ttlp->nextp; 7111ae08745Sheppo ttlp->nextp = vp_tlp; 7121ae08745Sheppo } 7131ae08745Sheppo RW_EXIT(&vnetp->trwlock); 7141ae08745Sheppo } 7151ae08745Sheppo 7161ae08745Sheppo /* remove vp_tl from the list */ 7171ae08745Sheppo static void 7181ae08745Sheppo vnet_del_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp) 7191ae08745Sheppo { 7201ae08745Sheppo vp_tl_t *ttlp, **pretlp; 7211ae08745Sheppo boolean_t found = B_FALSE; 7221ae08745Sheppo 7231ae08745Sheppo pretlp = &vnetp->tlp; 7241ae08745Sheppo ttlp = *pretlp; 7251ae08745Sheppo while (ttlp) { 7261ae08745Sheppo if (ttlp == vp_tlp) { 7271ae08745Sheppo found = B_TRUE; 7281ae08745Sheppo (*pretlp) = ttlp->nextp; 7291ae08745Sheppo ttlp->nextp = NULL; 7301ae08745Sheppo break; 7311ae08745Sheppo } 7321ae08745Sheppo pretlp = &(ttlp->nextp); 7331ae08745Sheppo ttlp = *pretlp; 7341ae08745Sheppo } 7351ae08745Sheppo 7361ae08745Sheppo if (found) { 7371ae08745Sheppo KMEM_FREE(vp_tlp); 7381ae08745Sheppo } 7391ae08745Sheppo } 7401ae08745Sheppo 7411ae08745Sheppo /* get vp_tl corresponding to the given name */ 7421ae08745Sheppo static vp_tl_t * 7431ae08745Sheppo vnet_get_vptl(vnet_t *vnetp, const char *name) 7441ae08745Sheppo { 7451ae08745Sheppo vp_tl_t *tlp; 7461ae08745Sheppo 7471ae08745Sheppo tlp = vnetp->tlp; 7481ae08745Sheppo while (tlp) { 7491ae08745Sheppo if (strcmp(tlp->name, name) == 0) { 7501ae08745Sheppo return (tlp); 7511ae08745Sheppo } 7521ae08745Sheppo tlp = tlp->nextp; 7531ae08745Sheppo } 754*844e62a3Sraghuram DWARN(vnetp, "can't find vp_tl with name (%s)\n", name); 7551ae08745Sheppo return (NULL); 7561ae08745Sheppo } 7571ae08745Sheppo 7581ae08745Sheppo /* read the mac address of the device */ 7591ae08745Sheppo static int 7601ae08745Sheppo vnet_read_mac_address(vnet_t *vnetp) 7611ae08745Sheppo { 7621ae08745Sheppo uchar_t *macaddr; 7631ae08745Sheppo uint32_t size; 7641ae08745Sheppo int rv; 7651ae08745Sheppo 7661ae08745Sheppo rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip, 7671ae08745Sheppo DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size); 7681ae08745Sheppo if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) { 769*844e62a3Sraghuram DWARN(vnetp, "prop_lookup failed(%s) err(%d)\n", 770*844e62a3Sraghuram macaddr_propname, rv); 7711ae08745Sheppo return (DDI_FAILURE); 7721ae08745Sheppo } 7731ae08745Sheppo bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL); 7741ae08745Sheppo bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL); 7751ae08745Sheppo ddi_prop_free(macaddr); 7761ae08745Sheppo 7771ae08745Sheppo return (DDI_SUCCESS); 7781ae08745Sheppo } 7791ae08745Sheppo 7801ae08745Sheppo 7811ae08745Sheppo /* 7821ae08745Sheppo * Functions below are called only by generic transport to add/remove/modify 7831ae08745Sheppo * entries in forwarding database. See comments in vgen_port_init(vnet_gen.c). 7841ae08745Sheppo */ 7851ae08745Sheppo 7861ae08745Sheppo /* add an entry into the forwarding database */ 7871ae08745Sheppo void 7881ae08745Sheppo vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg) 7891ae08745Sheppo { 7901ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 7911ae08745Sheppo uint32_t fdbhash; 7921ae08745Sheppo fdb_t *fdbp; 7931ae08745Sheppo fdb_fanout_t *fdbhp; 7941ae08745Sheppo 7951ae08745Sheppo /* Calculate hash value and fdb fanout */ 7961ae08745Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 7971ae08745Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 7981ae08745Sheppo 7991ae08745Sheppo WRITE_ENTER(&fdbhp->rwlock); 8001ae08745Sheppo 8011ae08745Sheppo fdbp = kmem_zalloc(sizeof (fdb_t), KM_NOSLEEP); 8021ae08745Sheppo if (fdbp == NULL) { 8031ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 8041ae08745Sheppo return; 8051ae08745Sheppo } 8061ae08745Sheppo bcopy(macaddr, (caddr_t)fdbp->macaddr, ETHERADDRL); 8071ae08745Sheppo fdbp->m_tx = m_tx; 8081ae08745Sheppo fdbp->txarg = txarg; 8091ae08745Sheppo fdbp->nextp = fdbhp->headp; 8101ae08745Sheppo fdbhp->headp = fdbp; 8111ae08745Sheppo 8121ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 8131ae08745Sheppo } 8141ae08745Sheppo 8151ae08745Sheppo /* delete an entry from the forwarding database */ 8161ae08745Sheppo void 8171ae08745Sheppo vnet_del_fdb(void *arg, uint8_t *macaddr) 8181ae08745Sheppo { 8191ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 8201ae08745Sheppo uint32_t fdbhash; 8211ae08745Sheppo fdb_t *fdbp; 8221ae08745Sheppo fdb_t **pfdbp; 8231ae08745Sheppo fdb_fanout_t *fdbhp; 8241ae08745Sheppo 8251ae08745Sheppo /* Calculate hash value and fdb fanout */ 8261ae08745Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 8271ae08745Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 8281ae08745Sheppo 8291ae08745Sheppo WRITE_ENTER(&fdbhp->rwlock); 8301ae08745Sheppo 8311ae08745Sheppo for (pfdbp = &fdbhp->headp; (fdbp = *pfdbp) != NULL; 8321ae08745Sheppo pfdbp = &fdbp->nextp) { 8331ae08745Sheppo if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) { 8341ae08745Sheppo /* Unlink it from the list */ 8351ae08745Sheppo *pfdbp = fdbp->nextp; 8361ae08745Sheppo KMEM_FREE(fdbp); 8371ae08745Sheppo break; 8381ae08745Sheppo } 8391ae08745Sheppo } 8401ae08745Sheppo 8411ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 8421ae08745Sheppo } 8431ae08745Sheppo 8441ae08745Sheppo /* modify an existing entry in the forwarding database */ 8451ae08745Sheppo void 8463af08d82Slm66018 vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg, 8473af08d82Slm66018 boolean_t upgrade) 8481ae08745Sheppo { 8491ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 8501ae08745Sheppo uint32_t fdbhash; 8511ae08745Sheppo fdb_t *fdbp; 8521ae08745Sheppo fdb_fanout_t *fdbhp; 8531ae08745Sheppo 8541ae08745Sheppo /* Calculate hash value and fdb fanout */ 8551ae08745Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 8561ae08745Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 8571ae08745Sheppo 8583af08d82Slm66018 if (upgrade == B_TRUE) { 8593af08d82Slm66018 /* 8603af08d82Slm66018 * Caller already holds the lock as a reader. This can 8613af08d82Slm66018 * occur if this function is invoked in the context 8623af08d82Slm66018 * of transmit routine - vnet_m_tx(), where the lock 8633af08d82Slm66018 * is held as a reader before calling the transmit 8643af08d82Slm66018 * function of an fdb entry (fdbp->m_tx). 8653af08d82Slm66018 * See comments in vgen_ldcsend() in vnet_gen.c 8663af08d82Slm66018 */ 8673af08d82Slm66018 if (!rw_tryupgrade(&fdbhp->rwlock)) { 8683af08d82Slm66018 RW_EXIT(&fdbhp->rwlock); 8691ae08745Sheppo WRITE_ENTER(&fdbhp->rwlock); 8703af08d82Slm66018 } 8713af08d82Slm66018 } else { 8723af08d82Slm66018 /* Caller does not hold the lock */ 8733af08d82Slm66018 WRITE_ENTER(&fdbhp->rwlock); 8743af08d82Slm66018 } 8751ae08745Sheppo 8761ae08745Sheppo for (fdbp = fdbhp->headp; fdbp != NULL; fdbp = fdbp->nextp) { 8771ae08745Sheppo if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) { 8781ae08745Sheppo /* change the entry to have new tx params */ 8791ae08745Sheppo fdbp->m_tx = m_tx; 8801ae08745Sheppo fdbp->txarg = txarg; 8811ae08745Sheppo break; 8821ae08745Sheppo } 8831ae08745Sheppo } 8841ae08745Sheppo 8853af08d82Slm66018 if (upgrade == B_TRUE) { 8863af08d82Slm66018 /* restore the caller as a reader */ 8873af08d82Slm66018 rw_downgrade(&fdbhp->rwlock); 8883af08d82Slm66018 } else { 8891ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 8901ae08745Sheppo } 8913af08d82Slm66018 } 8921ae08745Sheppo 8931ae08745Sheppo /* look up an fdb entry based on the mac address, caller holds lock */ 8941ae08745Sheppo static fdb_t * 8951ae08745Sheppo vnet_lookup_fdb(fdb_fanout_t *fdbhp, uint8_t *macaddr) 8961ae08745Sheppo { 8971ae08745Sheppo fdb_t *fdbp = NULL; 8981ae08745Sheppo 8991ae08745Sheppo for (fdbp = fdbhp->headp; fdbp != NULL; fdbp = fdbp->nextp) { 9001ae08745Sheppo if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) { 9011ae08745Sheppo break; 9021ae08745Sheppo } 9031ae08745Sheppo } 9041ae08745Sheppo 9051ae08745Sheppo return (fdbp); 9061ae08745Sheppo } 9071ae08745Sheppo 9081ae08745Sheppo /* add default route entry into the forwarding database */ 9091ae08745Sheppo void 9101ae08745Sheppo vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg) 9111ae08745Sheppo { 9121ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 9131ae08745Sheppo fdb_t *fdbp; 9141ae08745Sheppo fdb_fanout_t *fdbhp; 9151ae08745Sheppo 9161ae08745Sheppo /* 9171ae08745Sheppo * The last hash list is reserved for default route entry, 9181ae08745Sheppo * and for now, we have only one entry in this list. 9191ae08745Sheppo */ 9201ae08745Sheppo fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]); 9211ae08745Sheppo 9221ae08745Sheppo WRITE_ENTER(&fdbhp->rwlock); 9231ae08745Sheppo 9241ae08745Sheppo if (fdbhp->headp) { 925*844e62a3Sraghuram DWARN(vnetp, "default rte already exists\n"); 9261ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 9271ae08745Sheppo return; 9281ae08745Sheppo } 9291ae08745Sheppo fdbp = kmem_zalloc(sizeof (fdb_t), KM_NOSLEEP); 9301ae08745Sheppo if (fdbp == NULL) { 9311ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 9321ae08745Sheppo return; 9331ae08745Sheppo } 9341ae08745Sheppo bzero(fdbp->macaddr, ETHERADDRL); 9351ae08745Sheppo fdbp->m_tx = m_tx; 9361ae08745Sheppo fdbp->txarg = txarg; 9371ae08745Sheppo fdbp->nextp = NULL; 9381ae08745Sheppo fdbhp->headp = fdbp; 9391ae08745Sheppo 9401ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 9411ae08745Sheppo } 9421ae08745Sheppo 9431ae08745Sheppo /* delete default route entry from the forwarding database */ 9441ae08745Sheppo void 9451ae08745Sheppo vnet_del_def_rte(void *arg) 9461ae08745Sheppo { 9471ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 9481ae08745Sheppo fdb_t *fdbp; 9491ae08745Sheppo fdb_fanout_t *fdbhp; 9501ae08745Sheppo 9511ae08745Sheppo /* 9521ae08745Sheppo * The last hash list is reserved for default route entry, 9531ae08745Sheppo * and for now, we have only one entry in this list. 9541ae08745Sheppo */ 9551ae08745Sheppo fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]); 9561ae08745Sheppo 9571ae08745Sheppo WRITE_ENTER(&fdbhp->rwlock); 9581ae08745Sheppo 9591ae08745Sheppo if (fdbhp->headp == NULL) { 9601ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 9611ae08745Sheppo return; 9621ae08745Sheppo } 9631ae08745Sheppo fdbp = fdbhp->headp; 9641ae08745Sheppo KMEM_FREE(fdbp); 9651ae08745Sheppo fdbhp->headp = NULL; 9661ae08745Sheppo 9671ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 9681ae08745Sheppo } 969ba2e4443Sseb 970ba2e4443Sseb void 971ba2e4443Sseb vnet_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp) 972ba2e4443Sseb { 973ba2e4443Sseb vnet_t *vnetp = arg; 974ba2e4443Sseb mac_rx(vnetp->mh, mrh, mp); 975ba2e4443Sseb } 976ba2e4443Sseb 977ba2e4443Sseb void 978ba2e4443Sseb vnet_tx_update(void *arg) 979ba2e4443Sseb { 980ba2e4443Sseb vnet_t *vnetp = arg; 981ba2e4443Sseb mac_tx_update(vnetp->mh); 982ba2e4443Sseb } 983