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 /* 236419Ssb155480 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 241991Sheppo * Use is subject to license terms. 251991Sheppo */ 261991Sheppo 271991Sheppo #include <sys/types.h> 281991Sheppo #include <sys/errno.h> 291991Sheppo #include <sys/param.h> 301991Sheppo #include <sys/stream.h> 311991Sheppo #include <sys/kmem.h> 321991Sheppo #include <sys/conf.h> 331991Sheppo #include <sys/devops.h> 341991Sheppo #include <sys/ksynch.h> 351991Sheppo #include <sys/stat.h> 361991Sheppo #include <sys/modctl.h> 376419Ssb155480 #include <sys/modhash.h> 381991Sheppo #include <sys/debug.h> 391991Sheppo #include <sys/ethernet.h> 401991Sheppo #include <sys/dlpi.h> 411991Sheppo #include <net/if.h> 421991Sheppo #include <sys/mac.h> 432311Sseb #include <sys/mac_ether.h> 441991Sheppo #include <sys/ddi.h> 451991Sheppo #include <sys/sunddi.h> 461991Sheppo #include <sys/strsun.h> 471991Sheppo #include <sys/note.h> 486419Ssb155480 #include <sys/atomic.h> 491991Sheppo #include <sys/vnet.h> 506419Ssb155480 #include <sys/vlan.h> 516495Sspeer #include <sys/vnet_mailbox.h> 526495Sspeer #include <sys/vnet_common.h> 536495Sspeer #include <sys/dds.h> 546495Sspeer #include <sys/strsubr.h> 556495Sspeer #include <sys/taskq.h> 561991Sheppo 571991Sheppo /* 581991Sheppo * Function prototypes. 591991Sheppo */ 601991Sheppo 611991Sheppo /* DDI entrypoints */ 621991Sheppo static int vnetdevinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 631991Sheppo static int vnetattach(dev_info_t *, ddi_attach_cmd_t); 641991Sheppo static int vnetdetach(dev_info_t *, ddi_detach_cmd_t); 651991Sheppo 661991Sheppo /* MAC entrypoints */ 672311Sseb static int vnet_m_stat(void *, uint_t, uint64_t *); 681991Sheppo static int vnet_m_start(void *); 691991Sheppo static void vnet_m_stop(void *); 701991Sheppo static int vnet_m_promisc(void *, boolean_t); 711991Sheppo static int vnet_m_multicst(void *, boolean_t, const uint8_t *); 721991Sheppo static int vnet_m_unicst(void *, const uint8_t *); 731991Sheppo mblk_t *vnet_m_tx(void *, mblk_t *); 741991Sheppo 751991Sheppo /* vnet internal functions */ 761991Sheppo static int vnet_mac_register(vnet_t *); 771991Sheppo static int vnet_read_mac_address(vnet_t *vnetp); 781991Sheppo 796419Ssb155480 /* Forwarding database (FDB) routines */ 806419Ssb155480 static void vnet_fdb_create(vnet_t *vnetp); 816419Ssb155480 static void vnet_fdb_destroy(vnet_t *vnetp); 826495Sspeer static vnet_res_t *vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp); 836419Ssb155480 static void vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val); 846495Sspeer void vnet_fdbe_add(vnet_t *vnetp, vnet_res_t *vresp); 856495Sspeer static void vnet_fdbe_del(vnet_t *vnetp, vnet_res_t *vresp); 866495Sspeer 877896SSriharsha.Basavapatna@Sun.COM static void vnet_rx_frames_untag(uint16_t pvid, mblk_t **mp); 886495Sspeer static void vnet_rx(vio_net_handle_t vrh, mblk_t *mp); 896495Sspeer static void vnet_tx_update(vio_net_handle_t vrh); 906495Sspeer static void vnet_res_start_task(void *arg); 916495Sspeer static void vnet_start_resources(vnet_t *vnetp); 926495Sspeer static void vnet_stop_resources(vnet_t *vnetp); 936495Sspeer static void vnet_dispatch_res_task(vnet_t *vnetp); 946495Sspeer static void vnet_res_start_task(void *arg); 956495Sspeer static void vnet_handle_res_err(vio_net_handle_t vrh, vio_net_err_val_t err); 967529SSriharsha.Basavapatna@Sun.COM int vnet_mtu_update(vnet_t *vnetp, uint32_t mtu); 976419Ssb155480 98*8160SWentao.Yang@Sun.COM static kstat_t *vnet_hio_setup_kstats(char *ks_mod, char *ks_name, 99*8160SWentao.Yang@Sun.COM vnet_res_t *vresp); 100*8160SWentao.Yang@Sun.COM static int vnet_hio_update_kstats(kstat_t *ksp, int rw); 101*8160SWentao.Yang@Sun.COM static void vnet_hio_get_stats(vnet_res_t *vresp, vnet_hio_stats_t *statsp); 102*8160SWentao.Yang@Sun.COM static void vnet_hio_destroy_kstats(kstat_t *ksp); 103*8160SWentao.Yang@Sun.COM 1046495Sspeer /* Exported to to vnet_dds */ 1056495Sspeer int vnet_send_dds_msg(vnet_t *vnetp, void *dmsg); 1061991Sheppo 1076495Sspeer /* Externs that are imported from vnet_gen */ 1086495Sspeer extern int vgen_init(void *vnetp, uint64_t regprop, dev_info_t *vnetdip, 1096495Sspeer const uint8_t *macaddr, void **vgenhdl); 1102336Snarayan extern int vgen_uninit(void *arg); 1116495Sspeer extern int vgen_dds_tx(void *arg, void *dmsg); 1126495Sspeer 1136495Sspeer /* Externs that are imported from vnet_dds */ 1146495Sspeer extern void vdds_mod_init(void); 1156495Sspeer extern void vdds_mod_fini(void); 1166495Sspeer extern int vdds_init(vnet_t *vnetp); 1176495Sspeer extern void vdds_cleanup(vnet_t *vnetp); 1186495Sspeer extern void vdds_process_dds_msg(vnet_t *vnetp, vio_dds_msg_t *dmsg); 1197819SRaghuram.Kothakota@Sun.COM extern void vdds_cleanup_hybrid_res(void *arg); 1201991Sheppo 121*8160SWentao.Yang@Sun.COM #define DRV_NAME "vnet" 1226419Ssb155480 #define VNET_FDBE_REFHOLD(p) \ 1236419Ssb155480 { \ 1246419Ssb155480 atomic_inc_32(&(p)->refcnt); \ 1256419Ssb155480 ASSERT((p)->refcnt != 0); \ 1266419Ssb155480 } 1276419Ssb155480 1286419Ssb155480 #define VNET_FDBE_REFRELE(p) \ 1296419Ssb155480 { \ 1306419Ssb155480 ASSERT((p)->refcnt != 0); \ 1316419Ssb155480 atomic_dec_32(&(p)->refcnt); \ 1326419Ssb155480 } 1336419Ssb155480 1342311Sseb static mac_callbacks_t vnet_m_callbacks = { 1352311Sseb 0, 1362311Sseb vnet_m_stat, 1372311Sseb vnet_m_start, 1382311Sseb vnet_m_stop, 1392311Sseb vnet_m_promisc, 1402311Sseb vnet_m_multicst, 1412311Sseb vnet_m_unicst, 1422311Sseb vnet_m_tx, 1432311Sseb NULL, 1442311Sseb NULL, 1452311Sseb NULL 1462311Sseb }; 1472311Sseb 1481991Sheppo /* 1491991Sheppo * Linked list of "vnet_t" structures - one per instance. 1501991Sheppo */ 1511991Sheppo static vnet_t *vnet_headp = NULL; 1521991Sheppo static krwlock_t vnet_rw; 1531991Sheppo 1541991Sheppo /* Tunables */ 1551991Sheppo uint32_t vnet_ntxds = VNET_NTXDS; /* power of 2 transmit descriptors */ 1561991Sheppo uint32_t vnet_ldcwd_interval = VNET_LDCWD_INTERVAL; /* watchdog freq in msec */ 1571991Sheppo uint32_t vnet_ldcwd_txtimeout = VNET_LDCWD_TXTIMEOUT; /* tx timeout in msec */ 1582410Slm66018 uint32_t vnet_ldc_mtu = VNET_LDC_MTU; /* ldc mtu */ 1596419Ssb155480 1607529SSriharsha.Basavapatna@Sun.COM /* 1617529SSriharsha.Basavapatna@Sun.COM * Set this to non-zero to enable additional internal receive buffer pools 1627529SSriharsha.Basavapatna@Sun.COM * based on the MTU of the device for better performance at the cost of more 1637529SSriharsha.Basavapatna@Sun.COM * memory consumption. This is turned off by default, to use allocb(9F) for 1647529SSriharsha.Basavapatna@Sun.COM * receive buffer allocations of sizes > 2K. 1657529SSriharsha.Basavapatna@Sun.COM */ 1667529SSriharsha.Basavapatna@Sun.COM boolean_t vnet_jumbo_rxpools = B_FALSE; 1677529SSriharsha.Basavapatna@Sun.COM 1686419Ssb155480 /* # of chains in fdb hash table */ 1696419Ssb155480 uint32_t vnet_fdb_nchains = VNET_NFDB_HASH; 1706419Ssb155480 1716419Ssb155480 /* Internal tunables */ 1726419Ssb155480 uint32_t vnet_ethermtu = 1500; /* mtu of the device */ 1736419Ssb155480 1746419Ssb155480 /* 1756419Ssb155480 * Default vlan id. This is only used internally when the "default-vlan-id" 1766419Ssb155480 * property is not present in the MD device node. Therefore, this should not be 1776419Ssb155480 * used as a tunable; if this value is changed, the corresponding variable 1786419Ssb155480 * should be updated to the same value in vsw and also other vnets connected to 1796419Ssb155480 * the same vsw. 1806419Ssb155480 */ 1816419Ssb155480 uint16_t vnet_default_vlan_id = 1; 1826419Ssb155480 1836419Ssb155480 /* delay in usec to wait for all references on a fdb entry to be dropped */ 1846419Ssb155480 uint32_t vnet_fdbe_refcnt_delay = 10; 1851991Sheppo 1866495Sspeer static struct ether_addr etherbroadcastaddr = { 1876495Sspeer 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 1886495Sspeer }; 1896495Sspeer 1906495Sspeer 1911991Sheppo /* 1921991Sheppo * Property names 1931991Sheppo */ 1941991Sheppo static char macaddr_propname[] = "local-mac-address"; 1951991Sheppo 1961991Sheppo /* 1971991Sheppo * This is the string displayed by modinfo(1m). 1981991Sheppo */ 1997529SSriharsha.Basavapatna@Sun.COM static char vnet_ident[] = "vnet driver"; 2001991Sheppo extern struct mod_ops mod_driverops; 2011991Sheppo static struct cb_ops cb_vnetops = { 2021991Sheppo nulldev, /* cb_open */ 2031991Sheppo nulldev, /* cb_close */ 2041991Sheppo nodev, /* cb_strategy */ 2051991Sheppo nodev, /* cb_print */ 2061991Sheppo nodev, /* cb_dump */ 2071991Sheppo nodev, /* cb_read */ 2081991Sheppo nodev, /* cb_write */ 2091991Sheppo nodev, /* cb_ioctl */ 2101991Sheppo nodev, /* cb_devmap */ 2111991Sheppo nodev, /* cb_mmap */ 2121991Sheppo nodev, /* cb_segmap */ 2131991Sheppo nochpoll, /* cb_chpoll */ 2141991Sheppo ddi_prop_op, /* cb_prop_op */ 2151991Sheppo NULL, /* cb_stream */ 2161991Sheppo (int)(D_MP) /* cb_flag */ 2171991Sheppo }; 2181991Sheppo 2191991Sheppo static struct dev_ops vnetops = { 2201991Sheppo DEVO_REV, /* devo_rev */ 2211991Sheppo 0, /* devo_refcnt */ 2221991Sheppo NULL, /* devo_getinfo */ 2231991Sheppo nulldev, /* devo_identify */ 2241991Sheppo nulldev, /* devo_probe */ 2251991Sheppo vnetattach, /* devo_attach */ 2261991Sheppo vnetdetach, /* devo_detach */ 2271991Sheppo nodev, /* devo_reset */ 2281991Sheppo &cb_vnetops, /* devo_cb_ops */ 2297656SSherry.Moore@Sun.COM (struct bus_ops *)NULL, /* devo_bus_ops */ 2307656SSherry.Moore@Sun.COM NULL, /* devo_power */ 2317656SSherry.Moore@Sun.COM ddi_quiesce_not_supported, /* devo_quiesce */ 2321991Sheppo }; 2331991Sheppo 2341991Sheppo static struct modldrv modldrv = { 2351991Sheppo &mod_driverops, /* Type of module. This one is a driver */ 2361991Sheppo vnet_ident, /* ID string */ 2371991Sheppo &vnetops /* driver specific ops */ 2381991Sheppo }; 2391991Sheppo 2401991Sheppo static struct modlinkage modlinkage = { 2411991Sheppo MODREV_1, (void *)&modldrv, NULL 2421991Sheppo }; 2431991Sheppo 2444647Sraghuram #ifdef DEBUG 2451991Sheppo 2461991Sheppo /* 2471991Sheppo * Print debug messages - set to 0xf to enable all msgs 2481991Sheppo */ 2494647Sraghuram int vnet_dbglevel = 0x8; 2501991Sheppo 2514647Sraghuram static void 2524647Sraghuram debug_printf(const char *fname, void *arg, const char *fmt, ...) 2531991Sheppo { 2541991Sheppo char buf[512]; 2551991Sheppo va_list ap; 2561991Sheppo vnet_t *vnetp = (vnet_t *)arg; 2574647Sraghuram char *bufp = buf; 2581991Sheppo 2594647Sraghuram if (vnetp == NULL) { 2604647Sraghuram (void) sprintf(bufp, "%s: ", fname); 2614647Sraghuram bufp += strlen(bufp); 2624647Sraghuram } else { 2634647Sraghuram (void) sprintf(bufp, "vnet%d:%s: ", vnetp->instance, fname); 2644647Sraghuram bufp += strlen(bufp); 2654647Sraghuram } 2664647Sraghuram va_start(ap, fmt); 2674647Sraghuram (void) vsprintf(bufp, fmt, ap); 2684647Sraghuram va_end(ap); 2694647Sraghuram cmn_err(CE_CONT, "%s\n", buf); 2704647Sraghuram } 2711991Sheppo 2721991Sheppo #endif 2731991Sheppo 2741991Sheppo /* _init(9E): initialize the loadable module */ 2751991Sheppo int 2761991Sheppo _init(void) 2771991Sheppo { 2781991Sheppo int status; 2791991Sheppo 2804647Sraghuram DBG1(NULL, "enter\n"); 2811991Sheppo 2821991Sheppo mac_init_ops(&vnetops, "vnet"); 2831991Sheppo status = mod_install(&modlinkage); 2841991Sheppo if (status != 0) { 2851991Sheppo mac_fini_ops(&vnetops); 2861991Sheppo } 2876495Sspeer vdds_mod_init(); 2884647Sraghuram DBG1(NULL, "exit(%d)\n", status); 2891991Sheppo return (status); 2901991Sheppo } 2911991Sheppo 2921991Sheppo /* _fini(9E): prepare the module for unloading. */ 2931991Sheppo int 2941991Sheppo _fini(void) 2951991Sheppo { 2961991Sheppo int status; 2971991Sheppo 2984647Sraghuram DBG1(NULL, "enter\n"); 2991991Sheppo 3001991Sheppo status = mod_remove(&modlinkage); 3011991Sheppo if (status != 0) 3021991Sheppo return (status); 3031991Sheppo mac_fini_ops(&vnetops); 3046495Sspeer vdds_mod_fini(); 3051991Sheppo 3064647Sraghuram DBG1(NULL, "exit(%d)\n", status); 3071991Sheppo return (status); 3081991Sheppo } 3091991Sheppo 3101991Sheppo /* _info(9E): return information about the loadable module */ 3111991Sheppo int 3121991Sheppo _info(struct modinfo *modinfop) 3131991Sheppo { 3141991Sheppo return (mod_info(&modlinkage, modinfop)); 3151991Sheppo } 3161991Sheppo 3171991Sheppo /* 3181991Sheppo * attach(9E): attach a device to the system. 3191991Sheppo * called once for each instance of the device on the system. 3201991Sheppo */ 3211991Sheppo static int 3221991Sheppo vnetattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 3231991Sheppo { 3241991Sheppo vnet_t *vnetp; 3256495Sspeer int status; 3261991Sheppo int instance; 3276495Sspeer uint64_t reg; 3286495Sspeer char qname[TASKQ_NAMELEN]; 3294647Sraghuram enum { AST_init = 0x0, AST_vnet_alloc = 0x1, 3304647Sraghuram AST_mac_alloc = 0x2, AST_read_macaddr = 0x4, 3316495Sspeer AST_vgen_init = 0x8, AST_fdbh_alloc = 0x10, 3326495Sspeer AST_vdds_init = 0x20, AST_taskq_create = 0x40, 3336495Sspeer AST_vnet_list = 0x80 } attach_state; 3341991Sheppo 3351991Sheppo attach_state = AST_init; 3361991Sheppo 3371991Sheppo switch (cmd) { 3381991Sheppo case DDI_ATTACH: 3391991Sheppo break; 3401991Sheppo case DDI_RESUME: 3411991Sheppo case DDI_PM_RESUME: 3421991Sheppo default: 3431991Sheppo goto vnet_attach_fail; 3441991Sheppo } 3451991Sheppo 3461991Sheppo instance = ddi_get_instance(dip); 3474647Sraghuram DBG1(NULL, "instance(%d) enter\n", instance); 3481991Sheppo 3491991Sheppo /* allocate vnet_t and mac_t structures */ 3501991Sheppo vnetp = kmem_zalloc(sizeof (vnet_t), KM_SLEEP); 3516495Sspeer vnetp->dip = dip; 3526495Sspeer vnetp->instance = instance; 3536495Sspeer rw_init(&vnetp->vrwlock, NULL, RW_DRIVER, NULL); 3546495Sspeer rw_init(&vnetp->vsw_fp_rw, NULL, RW_DRIVER, NULL); 3551991Sheppo attach_state |= AST_vnet_alloc; 3561991Sheppo 3576495Sspeer status = vdds_init(vnetp); 3586495Sspeer if (status != 0) { 3596495Sspeer goto vnet_attach_fail; 3606495Sspeer } 3616495Sspeer attach_state |= AST_vdds_init; 3626495Sspeer 3631991Sheppo /* setup links to vnet_t from both devinfo and mac_t */ 3641991Sheppo ddi_set_driver_private(dip, (caddr_t)vnetp); 3651991Sheppo 3661991Sheppo /* read the mac address */ 3671991Sheppo status = vnet_read_mac_address(vnetp); 3681991Sheppo if (status != DDI_SUCCESS) { 3691991Sheppo goto vnet_attach_fail; 3701991Sheppo } 3711991Sheppo attach_state |= AST_read_macaddr; 3721991Sheppo 3736495Sspeer reg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 3746495Sspeer DDI_PROP_DONTPASS, "reg", -1); 3756495Sspeer if (reg == -1) { 3766495Sspeer goto vnet_attach_fail; 3776495Sspeer } 3786495Sspeer vnetp->reg = reg; 3796495Sspeer 3806495Sspeer vnet_fdb_create(vnetp); 3816495Sspeer attach_state |= AST_fdbh_alloc; 3826495Sspeer 3836495Sspeer (void) snprintf(qname, TASKQ_NAMELEN, "vnet_taskq%d", instance); 3846495Sspeer if ((vnetp->taskqp = ddi_taskq_create(dip, qname, 1, 3856495Sspeer TASKQ_DEFAULTPRI, 0)) == NULL) { 3866495Sspeer cmn_err(CE_WARN, "!vnet%d: Unable to create task queue", 3876495Sspeer instance); 3886495Sspeer goto vnet_attach_fail; 3896495Sspeer } 3906495Sspeer attach_state |= AST_taskq_create; 3916495Sspeer 3926495Sspeer /* add to the list of vnet devices */ 3936495Sspeer WRITE_ENTER(&vnet_rw); 3946495Sspeer vnetp->nextp = vnet_headp; 3956495Sspeer vnet_headp = vnetp; 3966495Sspeer RW_EXIT(&vnet_rw); 3976495Sspeer 3986495Sspeer attach_state |= AST_vnet_list; 3996495Sspeer 4001991Sheppo /* 4016495Sspeer * Initialize the generic vnet plugin which provides 4026495Sspeer * communication via sun4v LDC (logical domain channel) based 4036495Sspeer * resources. It will register the LDC resources as and when 4046495Sspeer * they become available. 4051991Sheppo */ 4066495Sspeer status = vgen_init(vnetp, reg, vnetp->dip, 4076495Sspeer (uint8_t *)vnetp->curr_macaddr, &vnetp->vgenhdl); 4081991Sheppo if (status != DDI_SUCCESS) { 4094647Sraghuram DERR(vnetp, "vgen_init() failed\n"); 4101991Sheppo goto vnet_attach_fail; 4111991Sheppo } 4121991Sheppo attach_state |= AST_vgen_init; 4131991Sheppo 4141991Sheppo /* register with MAC layer */ 4151991Sheppo status = vnet_mac_register(vnetp); 4161991Sheppo if (status != DDI_SUCCESS) { 4171991Sheppo goto vnet_attach_fail; 4181991Sheppo } 4191991Sheppo 4204647Sraghuram DBG1(NULL, "instance(%d) exit\n", instance); 4211991Sheppo return (DDI_SUCCESS); 4221991Sheppo 4231991Sheppo vnet_attach_fail: 4246495Sspeer 4256495Sspeer if (attach_state & AST_vnet_list) { 4266495Sspeer vnet_t **vnetpp; 4276495Sspeer /* unlink from instance(vnet_t) list */ 4286495Sspeer WRITE_ENTER(&vnet_rw); 4296495Sspeer for (vnetpp = &vnet_headp; *vnetpp; 4306495Sspeer vnetpp = &(*vnetpp)->nextp) { 4316495Sspeer if (*vnetpp == vnetp) { 4326495Sspeer *vnetpp = vnetp->nextp; 4336495Sspeer break; 4346495Sspeer } 4356495Sspeer } 4366495Sspeer RW_EXIT(&vnet_rw); 4376495Sspeer } 4386495Sspeer 4396495Sspeer if (attach_state & AST_vdds_init) { 4406495Sspeer vdds_cleanup(vnetp); 4416495Sspeer } 4426495Sspeer if (attach_state & AST_taskq_create) { 4436495Sspeer ddi_taskq_destroy(vnetp->taskqp); 4446495Sspeer } 4451991Sheppo if (attach_state & AST_fdbh_alloc) { 4466419Ssb155480 vnet_fdb_destroy(vnetp); 4471991Sheppo } 4481991Sheppo if (attach_state & AST_vgen_init) { 4496495Sspeer (void) vgen_uninit(vnetp->vgenhdl); 4501991Sheppo } 4511991Sheppo if (attach_state & AST_vnet_alloc) { 4526495Sspeer rw_destroy(&vnetp->vrwlock); 4536495Sspeer rw_destroy(&vnetp->vsw_fp_rw); 4541991Sheppo KMEM_FREE(vnetp); 4551991Sheppo } 4561991Sheppo return (DDI_FAILURE); 4571991Sheppo } 4581991Sheppo 4591991Sheppo /* 4601991Sheppo * detach(9E): detach a device from the system. 4611991Sheppo */ 4621991Sheppo static int 4631991Sheppo vnetdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4641991Sheppo { 4651991Sheppo vnet_t *vnetp; 4661991Sheppo vnet_t **vnetpp; 4671991Sheppo int instance; 4682336Snarayan int rv; 4691991Sheppo 4701991Sheppo instance = ddi_get_instance(dip); 4714647Sraghuram DBG1(NULL, "instance(%d) enter\n", instance); 4721991Sheppo 4731991Sheppo vnetp = ddi_get_driver_private(dip); 4741991Sheppo if (vnetp == NULL) { 4751991Sheppo goto vnet_detach_fail; 4761991Sheppo } 4771991Sheppo 4781991Sheppo switch (cmd) { 4791991Sheppo case DDI_DETACH: 4801991Sheppo break; 4811991Sheppo case DDI_SUSPEND: 4821991Sheppo case DDI_PM_SUSPEND: 4831991Sheppo default: 4841991Sheppo goto vnet_detach_fail; 4851991Sheppo } 4861991Sheppo 4876495Sspeer (void) vdds_cleanup(vnetp); 4886495Sspeer rv = vgen_uninit(vnetp->vgenhdl); 4896495Sspeer if (rv != DDI_SUCCESS) { 4906495Sspeer goto vnet_detach_fail; 4912336Snarayan } 4922336Snarayan 4931991Sheppo /* 4941991Sheppo * Unregister from the MAC subsystem. This can fail, in 4951991Sheppo * particular if there are DLPI style-2 streams still open - 4961991Sheppo * in which case we just return failure. 4971991Sheppo */ 4982311Sseb if (mac_unregister(vnetp->mh) != 0) 4991991Sheppo goto vnet_detach_fail; 5001991Sheppo 5011991Sheppo /* unlink from instance(vnet_t) list */ 5021991Sheppo WRITE_ENTER(&vnet_rw); 5031991Sheppo for (vnetpp = &vnet_headp; *vnetpp; vnetpp = &(*vnetpp)->nextp) { 5041991Sheppo if (*vnetpp == vnetp) { 5051991Sheppo *vnetpp = vnetp->nextp; 5061991Sheppo break; 5071991Sheppo } 5081991Sheppo } 5091991Sheppo RW_EXIT(&vnet_rw); 5101991Sheppo 5116495Sspeer ddi_taskq_destroy(vnetp->taskqp); 5126419Ssb155480 /* destroy fdb */ 5136419Ssb155480 vnet_fdb_destroy(vnetp); 5143297Ssb155480 5156495Sspeer rw_destroy(&vnetp->vrwlock); 5166495Sspeer rw_destroy(&vnetp->vsw_fp_rw); 5171991Sheppo KMEM_FREE(vnetp); 5181991Sheppo 5191991Sheppo return (DDI_SUCCESS); 5201991Sheppo 5211991Sheppo vnet_detach_fail: 5221991Sheppo return (DDI_FAILURE); 5231991Sheppo } 5241991Sheppo 5251991Sheppo /* enable the device for transmit/receive */ 5261991Sheppo static int 5271991Sheppo vnet_m_start(void *arg) 5281991Sheppo { 5291991Sheppo vnet_t *vnetp = arg; 5301991Sheppo 5314647Sraghuram DBG1(vnetp, "enter\n"); 5321991Sheppo 5336495Sspeer WRITE_ENTER(&vnetp->vrwlock); 5346495Sspeer vnetp->flags |= VNET_STARTED; 5356495Sspeer vnet_start_resources(vnetp); 5366495Sspeer RW_EXIT(&vnetp->vrwlock); 5371991Sheppo 5384647Sraghuram DBG1(vnetp, "exit\n"); 5391991Sheppo return (VNET_SUCCESS); 5401991Sheppo 5411991Sheppo } 5421991Sheppo 5431991Sheppo /* stop transmit/receive for the device */ 5441991Sheppo static void 5451991Sheppo vnet_m_stop(void *arg) 5461991Sheppo { 5471991Sheppo vnet_t *vnetp = arg; 5481991Sheppo 5494647Sraghuram DBG1(vnetp, "enter\n"); 5501991Sheppo 5516495Sspeer WRITE_ENTER(&vnetp->vrwlock); 5526495Sspeer if (vnetp->flags & VNET_STARTED) { 5536495Sspeer vnet_stop_resources(vnetp); 5546495Sspeer vnetp->flags &= ~VNET_STARTED; 5551991Sheppo } 5566495Sspeer RW_EXIT(&vnetp->vrwlock); 5571991Sheppo 5584647Sraghuram DBG1(vnetp, "exit\n"); 5591991Sheppo } 5601991Sheppo 5611991Sheppo /* set the unicast mac address of the device */ 5621991Sheppo static int 5631991Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr) 5641991Sheppo { 5651991Sheppo _NOTE(ARGUNUSED(macaddr)) 5661991Sheppo 5671991Sheppo vnet_t *vnetp = arg; 5681991Sheppo 5694647Sraghuram DBG1(vnetp, "enter\n"); 5701991Sheppo /* 5712793Slm66018 * NOTE: setting mac address dynamically is not supported. 5721991Sheppo */ 5734647Sraghuram DBG1(vnetp, "exit\n"); 5741991Sheppo 5752109Slm66018 return (VNET_FAILURE); 5761991Sheppo } 5771991Sheppo 5781991Sheppo /* enable/disable a multicast address */ 5791991Sheppo static int 5801991Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 5811991Sheppo { 5821991Sheppo _NOTE(ARGUNUSED(add, mca)) 5831991Sheppo 5841991Sheppo vnet_t *vnetp = arg; 5856495Sspeer vnet_res_t *vresp; 5866495Sspeer mac_register_t *macp; 5872311Sseb mac_callbacks_t *cbp; 5881991Sheppo int rv = VNET_SUCCESS; 5891991Sheppo 5904647Sraghuram DBG1(vnetp, "enter\n"); 5916495Sspeer 5926495Sspeer READ_ENTER(&vnetp->vrwlock); 5936495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 5946495Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 5956495Sspeer macp = &vresp->macreg; 5966495Sspeer cbp = macp->m_callbacks; 5976495Sspeer rv = cbp->mc_multicst(macp->m_driver, add, mca); 5981991Sheppo } 5991991Sheppo } 6006495Sspeer RW_EXIT(&vnetp->vrwlock); 6016495Sspeer 6024647Sraghuram DBG1(vnetp, "exit(%d)\n", rv); 6031991Sheppo return (rv); 6041991Sheppo } 6051991Sheppo 6061991Sheppo /* set or clear promiscuous mode on the device */ 6071991Sheppo static int 6081991Sheppo vnet_m_promisc(void *arg, boolean_t on) 6091991Sheppo { 6101991Sheppo _NOTE(ARGUNUSED(on)) 6111991Sheppo 6121991Sheppo vnet_t *vnetp = arg; 6134647Sraghuram DBG1(vnetp, "enter\n"); 6141991Sheppo /* 6152793Slm66018 * NOTE: setting promiscuous mode is not supported, just return success. 6161991Sheppo */ 6174647Sraghuram DBG1(vnetp, "exit\n"); 6181991Sheppo return (VNET_SUCCESS); 6191991Sheppo } 6201991Sheppo 6211991Sheppo /* 6221991Sheppo * Transmit a chain of packets. This function provides switching functionality 6231991Sheppo * based on the destination mac address to reach other guests (within ldoms) or 6241991Sheppo * external hosts. 6251991Sheppo */ 6261991Sheppo mblk_t * 6271991Sheppo vnet_m_tx(void *arg, mblk_t *mp) 6281991Sheppo { 6296419Ssb155480 vnet_t *vnetp; 6306495Sspeer vnet_res_t *vresp; 6316419Ssb155480 mblk_t *next; 6326495Sspeer mblk_t *resid_mp; 6336495Sspeer mac_register_t *macp; 6346495Sspeer struct ether_header *ehp; 6356495Sspeer boolean_t is_unicast; 6367896SSriharsha.Basavapatna@Sun.COM boolean_t is_pvid; /* non-default pvid ? */ 6377896SSriharsha.Basavapatna@Sun.COM boolean_t hres; /* Hybrid resource ? */ 6381991Sheppo 6391991Sheppo vnetp = (vnet_t *)arg; 6404647Sraghuram DBG1(vnetp, "enter\n"); 6411991Sheppo ASSERT(mp != NULL); 6421991Sheppo 6437896SSriharsha.Basavapatna@Sun.COM is_pvid = (vnetp->pvid != vnetp->default_vlan_id) ? B_TRUE : B_FALSE; 6447896SSriharsha.Basavapatna@Sun.COM 6451991Sheppo while (mp != NULL) { 6466419Ssb155480 6471991Sheppo next = mp->b_next; 6481991Sheppo mp->b_next = NULL; 6491991Sheppo 6506419Ssb155480 /* 6516419Ssb155480 * Find fdb entry for the destination 6526419Ssb155480 * and hold a reference to it. 6536419Ssb155480 */ 6541991Sheppo ehp = (struct ether_header *)mp->b_rptr; 6556495Sspeer vresp = vnet_fdbe_find(vnetp, &ehp->ether_dhost); 6566495Sspeer if (vresp != NULL) { 6571991Sheppo 6581991Sheppo /* 6596419Ssb155480 * Destination found in FDB. 6606419Ssb155480 * The destination is a vnet device within ldoms 6616419Ssb155480 * and directly reachable, invoke the tx function 6626419Ssb155480 * in the fdb entry. 6631991Sheppo */ 6646495Sspeer macp = &vresp->macreg; 6656495Sspeer resid_mp = macp->m_callbacks->mc_tx(macp->m_driver, mp); 6666419Ssb155480 6676419Ssb155480 /* tx done; now release ref on fdb entry */ 6686495Sspeer VNET_FDBE_REFRELE(vresp); 6696419Ssb155480 6701991Sheppo if (resid_mp != NULL) { 6711991Sheppo /* m_tx failed */ 6721991Sheppo mp->b_next = next; 6731991Sheppo break; 6741991Sheppo } 6751991Sheppo } else { 6766495Sspeer is_unicast = !(IS_BROADCAST(ehp) || 6776495Sspeer (IS_MULTICAST(ehp))); 6781991Sheppo /* 6796419Ssb155480 * Destination is not in FDB. 6806495Sspeer * If the destination is broadcast or multicast, 6816495Sspeer * then forward the packet to vswitch. 6826495Sspeer * If a Hybrid resource avilable, then send the 6836495Sspeer * unicast packet via hybrid resource, otherwise 6846495Sspeer * forward it to vswitch. 6851991Sheppo */ 6866419Ssb155480 READ_ENTER(&vnetp->vsw_fp_rw); 6876419Ssb155480 6886495Sspeer if ((is_unicast) && (vnetp->hio_fp != NULL)) { 6896495Sspeer vresp = vnetp->hio_fp; 6907896SSriharsha.Basavapatna@Sun.COM hres = B_TRUE; 6916495Sspeer } else { 6926495Sspeer vresp = vnetp->vsw_fp; 6937896SSriharsha.Basavapatna@Sun.COM hres = B_FALSE; 6946495Sspeer } 6956495Sspeer if (vresp == NULL) { 6966419Ssb155480 /* 6976419Ssb155480 * no fdb entry to vsw? drop the packet. 6986419Ssb155480 */ 6996419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 7001991Sheppo freemsg(mp); 7016419Ssb155480 mp = next; 7026419Ssb155480 continue; 7031991Sheppo } 7046419Ssb155480 7056419Ssb155480 /* ref hold the fdb entry to vsw */ 7066495Sspeer VNET_FDBE_REFHOLD(vresp); 7076419Ssb155480 7086419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 7096419Ssb155480 7107896SSriharsha.Basavapatna@Sun.COM /* 7117896SSriharsha.Basavapatna@Sun.COM * In the case of a hybrid resource we need to insert 7127896SSriharsha.Basavapatna@Sun.COM * the tag for the pvid case here; unlike packets that 7137896SSriharsha.Basavapatna@Sun.COM * are destined to a vnet/vsw in which case the vgen 7147896SSriharsha.Basavapatna@Sun.COM * layer does the tagging before sending it over ldc. 7157896SSriharsha.Basavapatna@Sun.COM */ 7167896SSriharsha.Basavapatna@Sun.COM if (hres == B_TRUE) { 7177896SSriharsha.Basavapatna@Sun.COM /* 7187896SSriharsha.Basavapatna@Sun.COM * Determine if the frame being transmitted 7197896SSriharsha.Basavapatna@Sun.COM * over the hybrid resource is untagged. If so, 7207896SSriharsha.Basavapatna@Sun.COM * insert the tag before transmitting. 7217896SSriharsha.Basavapatna@Sun.COM */ 7227896SSriharsha.Basavapatna@Sun.COM if (is_pvid == B_TRUE && 7237896SSriharsha.Basavapatna@Sun.COM ehp->ether_type != htons(ETHERTYPE_VLAN)) { 7247896SSriharsha.Basavapatna@Sun.COM 7257896SSriharsha.Basavapatna@Sun.COM mp = vnet_vlan_insert_tag(mp, 7267896SSriharsha.Basavapatna@Sun.COM vnetp->pvid); 7277896SSriharsha.Basavapatna@Sun.COM if (mp == NULL) { 7287896SSriharsha.Basavapatna@Sun.COM VNET_FDBE_REFRELE(vresp); 7297896SSriharsha.Basavapatna@Sun.COM mp = next; 7307896SSriharsha.Basavapatna@Sun.COM continue; 7317896SSriharsha.Basavapatna@Sun.COM } 7327896SSriharsha.Basavapatna@Sun.COM 7337896SSriharsha.Basavapatna@Sun.COM } 7347896SSriharsha.Basavapatna@Sun.COM } 7357896SSriharsha.Basavapatna@Sun.COM 7366495Sspeer macp = &vresp->macreg; 7376495Sspeer resid_mp = macp->m_callbacks->mc_tx(macp->m_driver, mp); 7386419Ssb155480 7396419Ssb155480 /* tx done; now release ref on fdb entry */ 7406495Sspeer VNET_FDBE_REFRELE(vresp); 7416419Ssb155480 7426419Ssb155480 if (resid_mp != NULL) { 7436419Ssb155480 /* m_tx failed */ 7446419Ssb155480 mp->b_next = next; 7456419Ssb155480 break; 7466419Ssb155480 } 7471991Sheppo } 7481991Sheppo 7491991Sheppo mp = next; 7501991Sheppo } 7511991Sheppo 7524647Sraghuram DBG1(vnetp, "exit\n"); 7531991Sheppo return (mp); 7541991Sheppo } 7551991Sheppo 7562311Sseb /* get statistics from the device */ 7572311Sseb int 7582311Sseb vnet_m_stat(void *arg, uint_t stat, uint64_t *val) 7591991Sheppo { 7601991Sheppo vnet_t *vnetp = arg; 7616495Sspeer vnet_res_t *vresp; 7626495Sspeer mac_register_t *macp; 7632311Sseb mac_callbacks_t *cbp; 7642311Sseb uint64_t val_total = 0; 7651991Sheppo 7664647Sraghuram DBG1(vnetp, "enter\n"); 7671991Sheppo 7681991Sheppo /* 7692311Sseb * get the specified statistic from each transport and return the 7702311Sseb * aggregate val. This obviously only works for counters. 7711991Sheppo */ 7722311Sseb if ((IS_MAC_STAT(stat) && !MAC_STAT_ISACOUNTER(stat)) || 7732311Sseb (IS_MACTYPE_STAT(stat) && !ETHER_STAT_ISACOUNTER(stat))) { 7742311Sseb return (ENOTSUP); 7752311Sseb } 7766495Sspeer 7776495Sspeer READ_ENTER(&vnetp->vrwlock); 7786495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 7796495Sspeer macp = &vresp->macreg; 7806495Sspeer cbp = macp->m_callbacks; 7816495Sspeer if (cbp->mc_getstat(macp->m_driver, stat, val) == 0) 7822311Sseb val_total += *val; 7831991Sheppo } 7846495Sspeer RW_EXIT(&vnetp->vrwlock); 7851991Sheppo 7862311Sseb *val = val_total; 7872311Sseb 7884647Sraghuram DBG1(vnetp, "exit\n"); 7892311Sseb return (0); 7901991Sheppo } 7911991Sheppo 7921991Sheppo /* wrapper function for mac_register() */ 7931991Sheppo static int 7941991Sheppo vnet_mac_register(vnet_t *vnetp) 7951991Sheppo { 7962311Sseb mac_register_t *macp; 7972311Sseb int err; 7981991Sheppo 7992311Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 8002311Sseb return (DDI_FAILURE); 8012311Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 8022311Sseb macp->m_driver = vnetp; 8031991Sheppo macp->m_dip = vnetp->dip; 8042311Sseb macp->m_src_addr = vnetp->curr_macaddr; 8052311Sseb macp->m_callbacks = &vnet_m_callbacks; 8062311Sseb macp->m_min_sdu = 0; 8077529SSriharsha.Basavapatna@Sun.COM macp->m_max_sdu = vnetp->mtu; 8086419Ssb155480 macp->m_margin = VLAN_TAGSZ; 8091991Sheppo 8101991Sheppo /* 8111991Sheppo * Finally, we're ready to register ourselves with the MAC layer 8121991Sheppo * interface; if this succeeds, we're all ready to start() 8131991Sheppo */ 8142311Sseb err = mac_register(macp, &vnetp->mh); 8152311Sseb mac_free(macp); 8162311Sseb return (err == 0 ? DDI_SUCCESS : DDI_FAILURE); 8171991Sheppo } 8181991Sheppo 8191991Sheppo /* read the mac address of the device */ 8201991Sheppo static int 8211991Sheppo vnet_read_mac_address(vnet_t *vnetp) 8221991Sheppo { 8231991Sheppo uchar_t *macaddr; 8241991Sheppo uint32_t size; 8251991Sheppo int rv; 8261991Sheppo 8271991Sheppo rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip, 8284650Sraghuram DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size); 8291991Sheppo if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) { 8304647Sraghuram DWARN(vnetp, "prop_lookup failed(%s) err(%d)\n", 8314647Sraghuram macaddr_propname, rv); 8321991Sheppo return (DDI_FAILURE); 8331991Sheppo } 8341991Sheppo bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL); 8351991Sheppo bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL); 8361991Sheppo ddi_prop_free(macaddr); 8371991Sheppo 8381991Sheppo return (DDI_SUCCESS); 8391991Sheppo } 8401991Sheppo 8416419Ssb155480 static void 8426419Ssb155480 vnet_fdb_create(vnet_t *vnetp) 8431991Sheppo { 8446419Ssb155480 char hashname[MAXNAMELEN]; 8451991Sheppo 8466419Ssb155480 (void) snprintf(hashname, MAXNAMELEN, "vnet%d-fdbhash", 8476419Ssb155480 vnetp->instance); 8486419Ssb155480 vnetp->fdb_nchains = vnet_fdb_nchains; 8496419Ssb155480 vnetp->fdb_hashp = mod_hash_create_ptrhash(hashname, vnetp->fdb_nchains, 8506419Ssb155480 mod_hash_null_valdtor, sizeof (void *)); 8516419Ssb155480 } 8521991Sheppo 8536419Ssb155480 static void 8546419Ssb155480 vnet_fdb_destroy(vnet_t *vnetp) 8556419Ssb155480 { 8566419Ssb155480 /* destroy fdb-hash-table */ 8576419Ssb155480 if (vnetp->fdb_hashp != NULL) { 8586419Ssb155480 mod_hash_destroy_hash(vnetp->fdb_hashp); 8596419Ssb155480 vnetp->fdb_hashp = NULL; 8606419Ssb155480 vnetp->fdb_nchains = 0; 8611991Sheppo } 8621991Sheppo } 8631991Sheppo 8646419Ssb155480 /* 8656419Ssb155480 * Add an entry into the fdb. 8666419Ssb155480 */ 8671991Sheppo void 8686495Sspeer vnet_fdbe_add(vnet_t *vnetp, vnet_res_t *vresp) 8691991Sheppo { 8706419Ssb155480 uint64_t addr = 0; 8716419Ssb155480 int rv; 8726419Ssb155480 8736495Sspeer KEY_HASH(addr, vresp->rem_macaddr); 8741991Sheppo 8756419Ssb155480 /* 8766495Sspeer * If the entry being added corresponds to LDC_SERVICE resource, 8776495Sspeer * that is, vswitch connection, it is added to the hash and also 8786495Sspeer * the entry is cached, an additional reference count reflects 8796495Sspeer * this. The HYBRID resource is not added to the hash, but only 8806495Sspeer * cached, as it is only used for sending out packets for unknown 8816495Sspeer * unicast destinations. 8826419Ssb155480 */ 8836495Sspeer (vresp->type == VIO_NET_RES_LDC_SERVICE) ? 8846495Sspeer (vresp->refcnt = 1) : (vresp->refcnt = 0); 8851991Sheppo 8866419Ssb155480 /* 8876419Ssb155480 * Note: duplicate keys will be rejected by mod_hash. 8886419Ssb155480 */ 8896495Sspeer if (vresp->type != VIO_NET_RES_HYBRID) { 8906495Sspeer rv = mod_hash_insert(vnetp->fdb_hashp, (mod_hash_key_t)addr, 8916495Sspeer (mod_hash_val_t)vresp); 8926495Sspeer if (rv != 0) { 8936495Sspeer DWARN(vnetp, "Duplicate macaddr key(%lx)\n", addr); 8946495Sspeer return; 8956495Sspeer } 8961991Sheppo } 8971991Sheppo 8986495Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 8996419Ssb155480 /* Cache the fdb entry to vsw-port */ 9006419Ssb155480 WRITE_ENTER(&vnetp->vsw_fp_rw); 9016419Ssb155480 if (vnetp->vsw_fp == NULL) 9026495Sspeer vnetp->vsw_fp = vresp; 9036495Sspeer RW_EXIT(&vnetp->vsw_fp_rw); 9046495Sspeer } else if (vresp->type == VIO_NET_RES_HYBRID) { 9056495Sspeer /* Cache the fdb entry to hybrid resource */ 9066495Sspeer WRITE_ENTER(&vnetp->vsw_fp_rw); 9076495Sspeer if (vnetp->hio_fp == NULL) 9086495Sspeer vnetp->hio_fp = vresp; 9096419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 9102793Slm66018 } 9111991Sheppo } 9121991Sheppo 9136419Ssb155480 /* 9146419Ssb155480 * Remove an entry from fdb. 9156419Ssb155480 */ 9166495Sspeer static void 9176495Sspeer vnet_fdbe_del(vnet_t *vnetp, vnet_res_t *vresp) 9185641Swentaoy { 9196419Ssb155480 uint64_t addr = 0; 9206419Ssb155480 int rv; 9216419Ssb155480 uint32_t refcnt; 9226495Sspeer vnet_res_t *tmp; 9235641Swentaoy 9246495Sspeer KEY_HASH(addr, vresp->rem_macaddr); 9255641Swentaoy 9266419Ssb155480 /* 9276419Ssb155480 * Remove the entry from fdb hash table. 9286419Ssb155480 * This prevents further references to this fdb entry. 9296419Ssb155480 */ 9306495Sspeer if (vresp->type != VIO_NET_RES_HYBRID) { 9316495Sspeer rv = mod_hash_remove(vnetp->fdb_hashp, (mod_hash_key_t)addr, 9326495Sspeer (mod_hash_val_t *)&tmp); 9336495Sspeer if (rv != 0) { 9346495Sspeer /* 9356495Sspeer * As the resources are added to the hash only 9366495Sspeer * after they are started, this can occur if 9376495Sspeer * a resource unregisters before it is ever started. 9386495Sspeer */ 9396495Sspeer return; 9406495Sspeer } 9416495Sspeer } 9425641Swentaoy 9436495Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 9446419Ssb155480 WRITE_ENTER(&vnetp->vsw_fp_rw); 9455641Swentaoy 9466495Sspeer ASSERT(tmp == vnetp->vsw_fp); 9476419Ssb155480 vnetp->vsw_fp = NULL; 9486419Ssb155480 9496419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 9506495Sspeer } else if (vresp->type == VIO_NET_RES_HYBRID) { 9516495Sspeer WRITE_ENTER(&vnetp->vsw_fp_rw); 9526495Sspeer 9536495Sspeer vnetp->hio_fp = NULL; 9546495Sspeer 9556495Sspeer RW_EXIT(&vnetp->vsw_fp_rw); 9565641Swentaoy } 9575641Swentaoy 9585641Swentaoy /* 9596419Ssb155480 * If there are threads already ref holding before the entry was 9606419Ssb155480 * removed from hash table, then wait for ref count to drop to zero. 9615641Swentaoy */ 9626495Sspeer (vresp->type == VIO_NET_RES_LDC_SERVICE) ? 9636495Sspeer (refcnt = 1) : (refcnt = 0); 9646495Sspeer while (vresp->refcnt > refcnt) { 9656419Ssb155480 delay(drv_usectohz(vnet_fdbe_refcnt_delay)); 9666419Ssb155480 } 9671991Sheppo } 9681991Sheppo 9696419Ssb155480 /* 9706419Ssb155480 * Search fdb for a given mac address. If an entry is found, hold 9716419Ssb155480 * a reference to it and return the entry; else returns NULL. 9726419Ssb155480 */ 9736495Sspeer static vnet_res_t * 9746419Ssb155480 vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp) 9751991Sheppo { 9766419Ssb155480 uint64_t key = 0; 9776495Sspeer vnet_res_t *vresp; 9786419Ssb155480 int rv; 9796419Ssb155480 9806495Sspeer KEY_HASH(key, addrp->ether_addr_octet); 9816419Ssb155480 9826419Ssb155480 rv = mod_hash_find_cb(vnetp->fdb_hashp, (mod_hash_key_t)key, 9836495Sspeer (mod_hash_val_t *)&vresp, vnet_fdbe_find_cb); 9841991Sheppo 9856419Ssb155480 if (rv != 0) 9866419Ssb155480 return (NULL); 9871991Sheppo 9886495Sspeer return (vresp); 9896419Ssb155480 } 9901991Sheppo 9916419Ssb155480 /* 9926419Ssb155480 * Callback function provided to mod_hash_find_cb(). After finding the fdb 9936419Ssb155480 * entry corresponding to the key (macaddr), this callback will be invoked by 9946419Ssb155480 * mod_hash_find_cb() to atomically increment the reference count on the fdb 9956419Ssb155480 * entry before returning the found entry. 9966419Ssb155480 */ 9976419Ssb155480 static void 9986419Ssb155480 vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val) 9996419Ssb155480 { 10006419Ssb155480 _NOTE(ARGUNUSED(key)) 10016495Sspeer VNET_FDBE_REFHOLD((vnet_res_t *)val); 10026495Sspeer } 10036495Sspeer 10047896SSriharsha.Basavapatna@Sun.COM /* 10057896SSriharsha.Basavapatna@Sun.COM * Frames received that are tagged with the pvid of the vnet device must be 10067896SSriharsha.Basavapatna@Sun.COM * untagged before sending up the stack. This function walks the chain of rx 10077896SSriharsha.Basavapatna@Sun.COM * frames, untags any such frames and returns the updated chain. 10087896SSriharsha.Basavapatna@Sun.COM * 10097896SSriharsha.Basavapatna@Sun.COM * Arguments: 10107896SSriharsha.Basavapatna@Sun.COM * pvid: pvid of the vnet device for which packets are being received 10117896SSriharsha.Basavapatna@Sun.COM * mp: head of pkt chain to be validated and untagged 10127896SSriharsha.Basavapatna@Sun.COM * 10137896SSriharsha.Basavapatna@Sun.COM * Returns: 10147896SSriharsha.Basavapatna@Sun.COM * mp: head of updated chain of packets 10157896SSriharsha.Basavapatna@Sun.COM */ 10167896SSriharsha.Basavapatna@Sun.COM static void 10177896SSriharsha.Basavapatna@Sun.COM vnet_rx_frames_untag(uint16_t pvid, mblk_t **mp) 10187896SSriharsha.Basavapatna@Sun.COM { 10197896SSriharsha.Basavapatna@Sun.COM struct ether_vlan_header *evhp; 10207896SSriharsha.Basavapatna@Sun.COM mblk_t *bp; 10217896SSriharsha.Basavapatna@Sun.COM mblk_t *bpt; 10227896SSriharsha.Basavapatna@Sun.COM mblk_t *bph; 10237896SSriharsha.Basavapatna@Sun.COM mblk_t *bpn; 10247896SSriharsha.Basavapatna@Sun.COM 10257896SSriharsha.Basavapatna@Sun.COM bpn = bph = bpt = NULL; 10267896SSriharsha.Basavapatna@Sun.COM 10277896SSriharsha.Basavapatna@Sun.COM for (bp = *mp; bp != NULL; bp = bpn) { 10287896SSriharsha.Basavapatna@Sun.COM 10297896SSriharsha.Basavapatna@Sun.COM bpn = bp->b_next; 10307896SSriharsha.Basavapatna@Sun.COM bp->b_next = bp->b_prev = NULL; 10317896SSriharsha.Basavapatna@Sun.COM 10327896SSriharsha.Basavapatna@Sun.COM evhp = (struct ether_vlan_header *)bp->b_rptr; 10337896SSriharsha.Basavapatna@Sun.COM 10347896SSriharsha.Basavapatna@Sun.COM if (ntohs(evhp->ether_tpid) == ETHERTYPE_VLAN && 10357896SSriharsha.Basavapatna@Sun.COM VLAN_ID(ntohs(evhp->ether_tci)) == pvid) { 10367896SSriharsha.Basavapatna@Sun.COM 10377896SSriharsha.Basavapatna@Sun.COM bp = vnet_vlan_remove_tag(bp); 10387896SSriharsha.Basavapatna@Sun.COM if (bp == NULL) { 10397896SSriharsha.Basavapatna@Sun.COM continue; 10407896SSriharsha.Basavapatna@Sun.COM } 10417896SSriharsha.Basavapatna@Sun.COM 10427896SSriharsha.Basavapatna@Sun.COM } 10437896SSriharsha.Basavapatna@Sun.COM 10447896SSriharsha.Basavapatna@Sun.COM /* build a chain of processed packets */ 10457896SSriharsha.Basavapatna@Sun.COM if (bph == NULL) { 10467896SSriharsha.Basavapatna@Sun.COM bph = bpt = bp; 10477896SSriharsha.Basavapatna@Sun.COM } else { 10487896SSriharsha.Basavapatna@Sun.COM bpt->b_next = bp; 10497896SSriharsha.Basavapatna@Sun.COM bpt = bp; 10507896SSriharsha.Basavapatna@Sun.COM } 10517896SSriharsha.Basavapatna@Sun.COM 10527896SSriharsha.Basavapatna@Sun.COM } 10537896SSriharsha.Basavapatna@Sun.COM 10547896SSriharsha.Basavapatna@Sun.COM *mp = bph; 10557896SSriharsha.Basavapatna@Sun.COM } 10567896SSriharsha.Basavapatna@Sun.COM 10576495Sspeer static void 10586495Sspeer vnet_rx(vio_net_handle_t vrh, mblk_t *mp) 10596495Sspeer { 10607896SSriharsha.Basavapatna@Sun.COM vnet_res_t *vresp = (vnet_res_t *)vrh; 10617896SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp = vresp->vnetp; 10627896SSriharsha.Basavapatna@Sun.COM 10637896SSriharsha.Basavapatna@Sun.COM if ((vnetp == NULL) || (vnetp->mh == 0)) { 10647896SSriharsha.Basavapatna@Sun.COM freemsgchain(mp); 10657896SSriharsha.Basavapatna@Sun.COM return; 10667896SSriharsha.Basavapatna@Sun.COM } 10676495Sspeer 10687896SSriharsha.Basavapatna@Sun.COM /* 10697896SSriharsha.Basavapatna@Sun.COM * Packets received over a hybrid resource need additional processing 10707896SSriharsha.Basavapatna@Sun.COM * to remove the tag, for the pvid case. The underlying resource is 10717896SSriharsha.Basavapatna@Sun.COM * not aware of the vnet's pvid and thus packets are received with the 10727896SSriharsha.Basavapatna@Sun.COM * vlan tag in the header; unlike packets that are received over a ldc 10737896SSriharsha.Basavapatna@Sun.COM * channel in which case the peer vnet/vsw would have already removed 10747896SSriharsha.Basavapatna@Sun.COM * the tag. 10757896SSriharsha.Basavapatna@Sun.COM */ 10767896SSriharsha.Basavapatna@Sun.COM if (vresp->type == VIO_NET_RES_HYBRID && 10777896SSriharsha.Basavapatna@Sun.COM vnetp->pvid != vnetp->default_vlan_id) { 10787896SSriharsha.Basavapatna@Sun.COM 10797896SSriharsha.Basavapatna@Sun.COM vnet_rx_frames_untag(vnetp->pvid, &mp); 10807896SSriharsha.Basavapatna@Sun.COM if (mp == NULL) { 10817896SSriharsha.Basavapatna@Sun.COM return; 10827896SSriharsha.Basavapatna@Sun.COM } 10836495Sspeer } 10847896SSriharsha.Basavapatna@Sun.COM 10857896SSriharsha.Basavapatna@Sun.COM mac_rx(vnetp->mh, NULL, mp); 10861991Sheppo } 10872311Sseb 10882311Sseb void 10896495Sspeer vnet_tx_update(vio_net_handle_t vrh) 10906495Sspeer { 10916495Sspeer vnet_res_t *vresp = (vnet_res_t *)vrh; 10926495Sspeer vnet_t *vnetp = vresp->vnetp; 10936495Sspeer 10946495Sspeer if ((vnetp != NULL) && (vnetp->mh != NULL)) { 10956495Sspeer mac_tx_update(vnetp->mh); 10966495Sspeer } 10976495Sspeer } 10986495Sspeer 10996495Sspeer /* 11007529SSriharsha.Basavapatna@Sun.COM * Update the new mtu of vnet into the mac layer. First check if the device has 11017529SSriharsha.Basavapatna@Sun.COM * been plumbed and if so fail the mtu update. Returns 0 on success. 11027529SSriharsha.Basavapatna@Sun.COM */ 11037529SSriharsha.Basavapatna@Sun.COM int 11047529SSriharsha.Basavapatna@Sun.COM vnet_mtu_update(vnet_t *vnetp, uint32_t mtu) 11057529SSriharsha.Basavapatna@Sun.COM { 11067529SSriharsha.Basavapatna@Sun.COM int rv; 11077529SSriharsha.Basavapatna@Sun.COM 11087529SSriharsha.Basavapatna@Sun.COM if (vnetp == NULL || vnetp->mh == NULL) { 11097529SSriharsha.Basavapatna@Sun.COM return (EINVAL); 11107529SSriharsha.Basavapatna@Sun.COM } 11117529SSriharsha.Basavapatna@Sun.COM 11127529SSriharsha.Basavapatna@Sun.COM WRITE_ENTER(&vnetp->vrwlock); 11137529SSriharsha.Basavapatna@Sun.COM 11147529SSriharsha.Basavapatna@Sun.COM if (vnetp->flags & VNET_STARTED) { 11157529SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 11167529SSriharsha.Basavapatna@Sun.COM cmn_err(CE_NOTE, "!vnet%d: Unable to process mtu " 11177529SSriharsha.Basavapatna@Sun.COM "update as the device is plumbed\n", 11187529SSriharsha.Basavapatna@Sun.COM vnetp->instance); 11197529SSriharsha.Basavapatna@Sun.COM return (EBUSY); 11207529SSriharsha.Basavapatna@Sun.COM } 11217529SSriharsha.Basavapatna@Sun.COM 11227529SSriharsha.Basavapatna@Sun.COM /* update mtu in the mac layer */ 11237529SSriharsha.Basavapatna@Sun.COM rv = mac_maxsdu_update(vnetp->mh, mtu); 11247529SSriharsha.Basavapatna@Sun.COM if (rv != 0) { 11257529SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 11267529SSriharsha.Basavapatna@Sun.COM cmn_err(CE_NOTE, 11277529SSriharsha.Basavapatna@Sun.COM "!vnet%d: Unable to update mtu with mac layer\n", 11287529SSriharsha.Basavapatna@Sun.COM vnetp->instance); 11297529SSriharsha.Basavapatna@Sun.COM return (EIO); 11307529SSriharsha.Basavapatna@Sun.COM } 11317529SSriharsha.Basavapatna@Sun.COM 11327529SSriharsha.Basavapatna@Sun.COM vnetp->mtu = mtu; 11337529SSriharsha.Basavapatna@Sun.COM 11347529SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 11357529SSriharsha.Basavapatna@Sun.COM 11367529SSriharsha.Basavapatna@Sun.COM return (0); 11377529SSriharsha.Basavapatna@Sun.COM } 11387529SSriharsha.Basavapatna@Sun.COM 11397529SSriharsha.Basavapatna@Sun.COM /* 11406495Sspeer * vio_net_resource_reg -- An interface called to register a resource 11416495Sspeer * with vnet. 11426495Sspeer * macp -- a GLDv3 mac_register that has all the details of 11436495Sspeer * a resource and its callbacks etc. 11446495Sspeer * type -- resource type. 11456495Sspeer * local_macaddr -- resource's MAC address. This is used to 11466495Sspeer * associate a resource with a corresponding vnet. 11476495Sspeer * remote_macaddr -- remote side MAC address. This is ignored for 11486495Sspeer * the Hybrid resources. 11496495Sspeer * vhp -- A handle returned to the caller. 11506495Sspeer * vcb -- A set of callbacks provided to the callers. 11516495Sspeer */ 11526495Sspeer int vio_net_resource_reg(mac_register_t *macp, vio_net_res_type_t type, 11536495Sspeer ether_addr_t local_macaddr, ether_addr_t rem_macaddr, vio_net_handle_t *vhp, 11546495Sspeer vio_net_callbacks_t *vcb) 11556495Sspeer { 11566495Sspeer vnet_t *vnetp; 11576495Sspeer vnet_res_t *vresp; 11586495Sspeer 11596495Sspeer vresp = kmem_zalloc(sizeof (vnet_res_t), KM_SLEEP); 11606495Sspeer ether_copy(local_macaddr, vresp->local_macaddr); 11616495Sspeer ether_copy(rem_macaddr, vresp->rem_macaddr); 11626495Sspeer vresp->type = type; 11636495Sspeer bcopy(macp, &vresp->macreg, sizeof (mac_register_t)); 11646495Sspeer 11656495Sspeer DBG1(NULL, "Resource Registerig type=0%X\n", type); 11666495Sspeer 11676495Sspeer READ_ENTER(&vnet_rw); 11686495Sspeer vnetp = vnet_headp; 11696495Sspeer while (vnetp != NULL) { 11706495Sspeer if (VNET_MATCH_RES(vresp, vnetp)) { 11716495Sspeer WRITE_ENTER(&vnetp->vrwlock); 11726495Sspeer vresp->vnetp = vnetp; 11736495Sspeer vresp->nextp = vnetp->vres_list; 11746495Sspeer vnetp->vres_list = vresp; 11756495Sspeer RW_EXIT(&vnetp->vrwlock); 11766495Sspeer break; 11776495Sspeer } 11786495Sspeer vnetp = vnetp->nextp; 11796495Sspeer } 11806495Sspeer RW_EXIT(&vnet_rw); 11816495Sspeer if (vresp->vnetp == NULL) { 11826495Sspeer DWARN(NULL, "No vnet instance"); 11836495Sspeer kmem_free(vresp, sizeof (vnet_res_t)); 11846495Sspeer return (ENXIO); 11856495Sspeer } 11866495Sspeer 1187*8160SWentao.Yang@Sun.COM /* Setup kstats for hio resource */ 1188*8160SWentao.Yang@Sun.COM if (vresp->type == VIO_NET_RES_HYBRID) { 1189*8160SWentao.Yang@Sun.COM vresp->ksp = vnet_hio_setup_kstats(DRV_NAME, "hio", vresp); 1190*8160SWentao.Yang@Sun.COM if (vresp->ksp == NULL) { 1191*8160SWentao.Yang@Sun.COM DWARN(NULL, "Cannot create kstats for hio resource"); 1192*8160SWentao.Yang@Sun.COM kmem_free(vresp, sizeof (vnet_res_t)); 1193*8160SWentao.Yang@Sun.COM return (ENXIO); 1194*8160SWentao.Yang@Sun.COM } 1195*8160SWentao.Yang@Sun.COM } 1196*8160SWentao.Yang@Sun.COM 11976495Sspeer *vhp = vresp; 11986495Sspeer vcb->vio_net_rx_cb = vnet_rx; 11996495Sspeer vcb->vio_net_tx_update = vnet_tx_update; 12006495Sspeer vcb->vio_net_report_err = vnet_handle_res_err; 12016495Sspeer 12026495Sspeer /* Dispatch a task to start resources */ 12036495Sspeer vnet_dispatch_res_task(vnetp); 12046495Sspeer return (0); 12056495Sspeer } 12066495Sspeer 12076495Sspeer /* 12086495Sspeer * vio_net_resource_unreg -- An interface to unregister a resource. 12096495Sspeer */ 12106495Sspeer void 12116495Sspeer vio_net_resource_unreg(vio_net_handle_t vhp) 12126495Sspeer { 12136495Sspeer vnet_res_t *vresp = (vnet_res_t *)vhp; 12146495Sspeer vnet_t *vnetp = vresp->vnetp; 12156495Sspeer vnet_res_t *vrp; 1216*8160SWentao.Yang@Sun.COM kstat_t *ksp = NULL; 12176495Sspeer 12186495Sspeer DBG1(NULL, "Resource Registerig hdl=0x%p", vhp); 12196495Sspeer 12206495Sspeer ASSERT(vnetp != NULL); 12216495Sspeer vnet_fdbe_del(vnetp, vresp); 12226495Sspeer 12236495Sspeer WRITE_ENTER(&vnetp->vrwlock); 12246495Sspeer if (vresp == vnetp->vres_list) { 12256495Sspeer vnetp->vres_list = vresp->nextp; 12266495Sspeer } else { 12276495Sspeer vrp = vnetp->vres_list; 12286495Sspeer while (vrp->nextp != NULL) { 12296495Sspeer if (vrp->nextp == vresp) { 12306495Sspeer vrp->nextp = vresp->nextp; 12316495Sspeer break; 12326495Sspeer } 12336495Sspeer vrp = vrp->nextp; 12346495Sspeer } 12356495Sspeer } 1236*8160SWentao.Yang@Sun.COM 1237*8160SWentao.Yang@Sun.COM ksp = vresp->ksp; 1238*8160SWentao.Yang@Sun.COM vresp->ksp = NULL; 1239*8160SWentao.Yang@Sun.COM 12406495Sspeer vresp->vnetp = NULL; 12416495Sspeer vresp->nextp = NULL; 12426495Sspeer RW_EXIT(&vnetp->vrwlock); 1243*8160SWentao.Yang@Sun.COM vnet_hio_destroy_kstats(ksp); 12446495Sspeer KMEM_FREE(vresp); 12456495Sspeer } 12466495Sspeer 12476495Sspeer /* 12486495Sspeer * vnet_dds_rx -- an interface called by vgen to DDS messages. 12496495Sspeer */ 12506495Sspeer void 12516495Sspeer vnet_dds_rx(void *arg, void *dmsg) 12522311Sseb { 12532311Sseb vnet_t *vnetp = arg; 12546495Sspeer vdds_process_dds_msg(vnetp, dmsg); 12552311Sseb } 12562311Sseb 12576495Sspeer /* 12586495Sspeer * vnet_send_dds_msg -- An interface provided to DDS to send 12596495Sspeer * DDS messages. This simply sends meessages via vgen. 12606495Sspeer */ 12616495Sspeer int 12626495Sspeer vnet_send_dds_msg(vnet_t *vnetp, void *dmsg) 12636495Sspeer { 12646495Sspeer int rv; 12656495Sspeer 12666495Sspeer if (vnetp->vgenhdl != NULL) { 12676495Sspeer rv = vgen_dds_tx(vnetp->vgenhdl, dmsg); 12686495Sspeer } 12696495Sspeer return (rv); 12706495Sspeer } 12716495Sspeer 12726495Sspeer /* 12736495Sspeer * vnet_handle_res_err -- A callback function called by a resource 12746495Sspeer * to report an error. For example, vgen can call to report 12756495Sspeer * an LDC down/reset event. This will trigger cleanup of associated 12766495Sspeer * Hybrid resource. 12776495Sspeer */ 12786495Sspeer /* ARGSUSED */ 12796495Sspeer static void 12806495Sspeer vnet_handle_res_err(vio_net_handle_t vrh, vio_net_err_val_t err) 12816495Sspeer { 12826495Sspeer vnet_res_t *vresp = (vnet_res_t *)vrh; 12836495Sspeer vnet_t *vnetp = vresp->vnetp; 12847819SRaghuram.Kothakota@Sun.COM int rv; 12856495Sspeer 12866495Sspeer if (vnetp == NULL) { 12876495Sspeer return; 12886495Sspeer } 12896495Sspeer if ((vresp->type != VIO_NET_RES_LDC_SERVICE) && 12906495Sspeer (vresp->type != VIO_NET_RES_HYBRID)) { 12916495Sspeer return; 12926495Sspeer } 12937819SRaghuram.Kothakota@Sun.COM rv = ddi_taskq_dispatch(vnetp->taskqp, vdds_cleanup_hybrid_res, 12947819SRaghuram.Kothakota@Sun.COM vnetp, DDI_NOSLEEP); 12957819SRaghuram.Kothakota@Sun.COM if (rv != DDI_SUCCESS) { 12967819SRaghuram.Kothakota@Sun.COM cmn_err(CE_WARN, 12977819SRaghuram.Kothakota@Sun.COM "vnet%d:Failed to dispatch task to cleanup hybrid resource", 12987819SRaghuram.Kothakota@Sun.COM vnetp->instance); 12997819SRaghuram.Kothakota@Sun.COM } 13006495Sspeer } 13016495Sspeer 13026495Sspeer /* 13036495Sspeer * vnet_dispatch_res_task -- A function to dispatch tasks start resources. 13046495Sspeer */ 13056495Sspeer static void 13066495Sspeer vnet_dispatch_res_task(vnet_t *vnetp) 13076495Sspeer { 13086495Sspeer int rv; 13096495Sspeer 13106495Sspeer WRITE_ENTER(&vnetp->vrwlock); 13116495Sspeer if (vnetp->flags & VNET_STARTED) { 13126495Sspeer rv = ddi_taskq_dispatch(vnetp->taskqp, vnet_res_start_task, 13136495Sspeer vnetp, DDI_NOSLEEP); 13146495Sspeer if (rv != DDI_SUCCESS) { 13156495Sspeer cmn_err(CE_WARN, 13166495Sspeer "vnet%d:Can't dispatch start resource task", 13176495Sspeer vnetp->instance); 13186495Sspeer } 13196495Sspeer } 13206495Sspeer RW_EXIT(&vnetp->vrwlock); 13216495Sspeer } 13226495Sspeer 13236495Sspeer /* 13246495Sspeer * vnet_res_start_task -- A taskq callback function that starts a resource. 13256495Sspeer */ 13266495Sspeer static void 13276495Sspeer vnet_res_start_task(void *arg) 13282311Sseb { 13292311Sseb vnet_t *vnetp = arg; 13306495Sspeer 13316495Sspeer WRITE_ENTER(&vnetp->vrwlock); 13326495Sspeer if (vnetp->flags & VNET_STARTED) { 13336495Sspeer vnet_start_resources(vnetp); 13346495Sspeer } 13356495Sspeer RW_EXIT(&vnetp->vrwlock); 13362311Sseb } 13376495Sspeer 13386495Sspeer /* 13396495Sspeer * vnet_start_resources -- starts all resources associated with 13406495Sspeer * a vnet. 13416495Sspeer */ 13426495Sspeer static void 13436495Sspeer vnet_start_resources(vnet_t *vnetp) 13446495Sspeer { 13456495Sspeer mac_register_t *macp; 13466495Sspeer mac_callbacks_t *cbp; 13476495Sspeer vnet_res_t *vresp; 13486495Sspeer int rv; 13496495Sspeer 13506495Sspeer DBG1(vnetp, "enter\n"); 13516495Sspeer 13526495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 13536495Sspeer /* skip if it is already started */ 13546495Sspeer if (vresp->flags & VNET_STARTED) { 13556495Sspeer continue; 13566495Sspeer } 13576495Sspeer macp = &vresp->macreg; 13586495Sspeer cbp = macp->m_callbacks; 13596495Sspeer rv = cbp->mc_start(macp->m_driver); 13606495Sspeer if (rv == 0) { 13616495Sspeer /* 13626495Sspeer * Successfully started the resource, so now 13636495Sspeer * add it to the fdb. 13646495Sspeer */ 13656495Sspeer vresp->flags |= VNET_STARTED; 13666495Sspeer vnet_fdbe_add(vnetp, vresp); 13676495Sspeer } 13686495Sspeer } 13696495Sspeer 13706495Sspeer DBG1(vnetp, "exit\n"); 13716495Sspeer 13726495Sspeer } 13736495Sspeer 13746495Sspeer /* 13756495Sspeer * vnet_stop_resources -- stop all resources associated with a vnet. 13766495Sspeer */ 13776495Sspeer static void 13786495Sspeer vnet_stop_resources(vnet_t *vnetp) 13796495Sspeer { 13806495Sspeer vnet_res_t *vresp; 13816495Sspeer vnet_res_t *nvresp; 13826495Sspeer mac_register_t *macp; 13836495Sspeer mac_callbacks_t *cbp; 13846495Sspeer 13856495Sspeer DBG1(vnetp, "enter\n"); 13866495Sspeer 13876495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; ) { 13886495Sspeer nvresp = vresp->nextp; 13896495Sspeer if (vresp->flags & VNET_STARTED) { 13906495Sspeer macp = &vresp->macreg; 13916495Sspeer cbp = macp->m_callbacks; 13926495Sspeer cbp->mc_stop(macp->m_driver); 13936495Sspeer vresp->flags &= ~VNET_STARTED; 13946495Sspeer } 13956495Sspeer vresp = nvresp; 13966495Sspeer } 13976495Sspeer DBG1(vnetp, "exit\n"); 13986495Sspeer } 1399*8160SWentao.Yang@Sun.COM 1400*8160SWentao.Yang@Sun.COM /* 1401*8160SWentao.Yang@Sun.COM * Setup kstats for the HIO statistics. 1402*8160SWentao.Yang@Sun.COM * NOTE: the synchronization for the statistics is the 1403*8160SWentao.Yang@Sun.COM * responsibility of the caller. 1404*8160SWentao.Yang@Sun.COM */ 1405*8160SWentao.Yang@Sun.COM kstat_t * 1406*8160SWentao.Yang@Sun.COM vnet_hio_setup_kstats(char *ks_mod, char *ks_name, vnet_res_t *vresp) 1407*8160SWentao.Yang@Sun.COM { 1408*8160SWentao.Yang@Sun.COM kstat_t *ksp; 1409*8160SWentao.Yang@Sun.COM vnet_t *vnetp = vresp->vnetp; 1410*8160SWentao.Yang@Sun.COM vnet_hio_kstats_t *hiokp; 1411*8160SWentao.Yang@Sun.COM size_t size; 1412*8160SWentao.Yang@Sun.COM 1413*8160SWentao.Yang@Sun.COM ASSERT(vnetp != NULL); 1414*8160SWentao.Yang@Sun.COM size = sizeof (vnet_hio_kstats_t) / sizeof (kstat_named_t); 1415*8160SWentao.Yang@Sun.COM ksp = kstat_create(ks_mod, vnetp->instance, ks_name, "net", 1416*8160SWentao.Yang@Sun.COM KSTAT_TYPE_NAMED, size, 0); 1417*8160SWentao.Yang@Sun.COM if (ksp == NULL) { 1418*8160SWentao.Yang@Sun.COM return (NULL); 1419*8160SWentao.Yang@Sun.COM } 1420*8160SWentao.Yang@Sun.COM 1421*8160SWentao.Yang@Sun.COM hiokp = (vnet_hio_kstats_t *)ksp->ks_data; 1422*8160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->ipackets, "ipackets", 1423*8160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 1424*8160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->ierrors, "ierrors", 1425*8160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 1426*8160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->opackets, "opackets", 1427*8160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 1428*8160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->oerrors, "oerrors", 1429*8160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 1430*8160SWentao.Yang@Sun.COM 1431*8160SWentao.Yang@Sun.COM 1432*8160SWentao.Yang@Sun.COM /* MIB II kstat variables */ 1433*8160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->rbytes, "rbytes", 1434*8160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 1435*8160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->obytes, "obytes", 1436*8160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 1437*8160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->multircv, "multircv", 1438*8160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 1439*8160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->multixmt, "multixmt", 1440*8160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 1441*8160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->brdcstrcv, "brdcstrcv", 1442*8160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 1443*8160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->brdcstxmt, "brdcstxmt", 1444*8160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 1445*8160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->norcvbuf, "norcvbuf", 1446*8160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 1447*8160SWentao.Yang@Sun.COM kstat_named_init(&hiokp->noxmtbuf, "noxmtbuf", 1448*8160SWentao.Yang@Sun.COM KSTAT_DATA_ULONG); 1449*8160SWentao.Yang@Sun.COM 1450*8160SWentao.Yang@Sun.COM ksp->ks_update = vnet_hio_update_kstats; 1451*8160SWentao.Yang@Sun.COM ksp->ks_private = (void *)vresp; 1452*8160SWentao.Yang@Sun.COM kstat_install(ksp); 1453*8160SWentao.Yang@Sun.COM return (ksp); 1454*8160SWentao.Yang@Sun.COM } 1455*8160SWentao.Yang@Sun.COM 1456*8160SWentao.Yang@Sun.COM /* 1457*8160SWentao.Yang@Sun.COM * Destroy kstats. 1458*8160SWentao.Yang@Sun.COM */ 1459*8160SWentao.Yang@Sun.COM static void 1460*8160SWentao.Yang@Sun.COM vnet_hio_destroy_kstats(kstat_t *ksp) 1461*8160SWentao.Yang@Sun.COM { 1462*8160SWentao.Yang@Sun.COM if (ksp != NULL) 1463*8160SWentao.Yang@Sun.COM kstat_delete(ksp); 1464*8160SWentao.Yang@Sun.COM } 1465*8160SWentao.Yang@Sun.COM 1466*8160SWentao.Yang@Sun.COM /* 1467*8160SWentao.Yang@Sun.COM * Update the kstats. 1468*8160SWentao.Yang@Sun.COM */ 1469*8160SWentao.Yang@Sun.COM static int 1470*8160SWentao.Yang@Sun.COM vnet_hio_update_kstats(kstat_t *ksp, int rw) 1471*8160SWentao.Yang@Sun.COM { 1472*8160SWentao.Yang@Sun.COM vnet_t *vnetp; 1473*8160SWentao.Yang@Sun.COM vnet_res_t *vresp; 1474*8160SWentao.Yang@Sun.COM vnet_hio_stats_t statsp; 1475*8160SWentao.Yang@Sun.COM vnet_hio_kstats_t *hiokp; 1476*8160SWentao.Yang@Sun.COM 1477*8160SWentao.Yang@Sun.COM vresp = (vnet_res_t *)ksp->ks_private; 1478*8160SWentao.Yang@Sun.COM vnetp = vresp->vnetp; 1479*8160SWentao.Yang@Sun.COM 1480*8160SWentao.Yang@Sun.COM bzero(&statsp, sizeof (vnet_hio_stats_t)); 1481*8160SWentao.Yang@Sun.COM 1482*8160SWentao.Yang@Sun.COM READ_ENTER(&vnetp->vsw_fp_rw); 1483*8160SWentao.Yang@Sun.COM if (vnetp->hio_fp == NULL) { 1484*8160SWentao.Yang@Sun.COM /* not using hio resources, just return */ 1485*8160SWentao.Yang@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw); 1486*8160SWentao.Yang@Sun.COM return (0); 1487*8160SWentao.Yang@Sun.COM } 1488*8160SWentao.Yang@Sun.COM VNET_FDBE_REFHOLD(vnetp->hio_fp); 1489*8160SWentao.Yang@Sun.COM RW_EXIT(&vnetp->vsw_fp_rw); 1490*8160SWentao.Yang@Sun.COM vnet_hio_get_stats(vnetp->hio_fp, &statsp); 1491*8160SWentao.Yang@Sun.COM VNET_FDBE_REFRELE(vnetp->hio_fp); 1492*8160SWentao.Yang@Sun.COM 1493*8160SWentao.Yang@Sun.COM hiokp = (vnet_hio_kstats_t *)ksp->ks_data; 1494*8160SWentao.Yang@Sun.COM 1495*8160SWentao.Yang@Sun.COM if (rw == KSTAT_READ) { 1496*8160SWentao.Yang@Sun.COM /* Link Input/Output stats */ 1497*8160SWentao.Yang@Sun.COM hiokp->ipackets.value.ul = (uint32_t)statsp.ipackets; 1498*8160SWentao.Yang@Sun.COM hiokp->ipackets64.value.ull = statsp.ipackets; 1499*8160SWentao.Yang@Sun.COM hiokp->ierrors.value.ul = statsp.ierrors; 1500*8160SWentao.Yang@Sun.COM hiokp->opackets.value.ul = (uint32_t)statsp.opackets; 1501*8160SWentao.Yang@Sun.COM hiokp->opackets64.value.ull = statsp.opackets; 1502*8160SWentao.Yang@Sun.COM hiokp->oerrors.value.ul = statsp.oerrors; 1503*8160SWentao.Yang@Sun.COM 1504*8160SWentao.Yang@Sun.COM /* MIB II kstat variables */ 1505*8160SWentao.Yang@Sun.COM hiokp->rbytes.value.ul = (uint32_t)statsp.rbytes; 1506*8160SWentao.Yang@Sun.COM hiokp->rbytes64.value.ull = statsp.rbytes; 1507*8160SWentao.Yang@Sun.COM hiokp->obytes.value.ul = (uint32_t)statsp.obytes; 1508*8160SWentao.Yang@Sun.COM hiokp->obytes64.value.ull = statsp.obytes; 1509*8160SWentao.Yang@Sun.COM hiokp->multircv.value.ul = statsp.multircv; 1510*8160SWentao.Yang@Sun.COM hiokp->multixmt.value.ul = statsp.multixmt; 1511*8160SWentao.Yang@Sun.COM hiokp->brdcstrcv.value.ul = statsp.brdcstrcv; 1512*8160SWentao.Yang@Sun.COM hiokp->brdcstxmt.value.ul = statsp.brdcstxmt; 1513*8160SWentao.Yang@Sun.COM hiokp->norcvbuf.value.ul = statsp.norcvbuf; 1514*8160SWentao.Yang@Sun.COM hiokp->noxmtbuf.value.ul = statsp.noxmtbuf; 1515*8160SWentao.Yang@Sun.COM } else { 1516*8160SWentao.Yang@Sun.COM return (EACCES); 1517*8160SWentao.Yang@Sun.COM } 1518*8160SWentao.Yang@Sun.COM 1519*8160SWentao.Yang@Sun.COM return (0); 1520*8160SWentao.Yang@Sun.COM } 1521*8160SWentao.Yang@Sun.COM 1522*8160SWentao.Yang@Sun.COM static void 1523*8160SWentao.Yang@Sun.COM vnet_hio_get_stats(vnet_res_t *vresp, vnet_hio_stats_t *statsp) 1524*8160SWentao.Yang@Sun.COM { 1525*8160SWentao.Yang@Sun.COM mac_register_t *macp; 1526*8160SWentao.Yang@Sun.COM mac_callbacks_t *cbp; 1527*8160SWentao.Yang@Sun.COM uint64_t val; 1528*8160SWentao.Yang@Sun.COM int stat; 1529*8160SWentao.Yang@Sun.COM 1530*8160SWentao.Yang@Sun.COM /* 1531*8160SWentao.Yang@Sun.COM * get the specified statistics from the underlying nxge. 1532*8160SWentao.Yang@Sun.COM */ 1533*8160SWentao.Yang@Sun.COM macp = &vresp->macreg; 1534*8160SWentao.Yang@Sun.COM cbp = macp->m_callbacks; 1535*8160SWentao.Yang@Sun.COM for (stat = MAC_STAT_MIN; stat < MAC_STAT_OVERFLOWS; stat++) { 1536*8160SWentao.Yang@Sun.COM if (cbp->mc_getstat(macp->m_driver, stat, &val) == 0) { 1537*8160SWentao.Yang@Sun.COM switch (stat) { 1538*8160SWentao.Yang@Sun.COM case MAC_STAT_IPACKETS: 1539*8160SWentao.Yang@Sun.COM statsp->ipackets = val; 1540*8160SWentao.Yang@Sun.COM break; 1541*8160SWentao.Yang@Sun.COM 1542*8160SWentao.Yang@Sun.COM case MAC_STAT_IERRORS: 1543*8160SWentao.Yang@Sun.COM statsp->ierrors = val; 1544*8160SWentao.Yang@Sun.COM break; 1545*8160SWentao.Yang@Sun.COM 1546*8160SWentao.Yang@Sun.COM case MAC_STAT_OPACKETS: 1547*8160SWentao.Yang@Sun.COM statsp->opackets = val; 1548*8160SWentao.Yang@Sun.COM break; 1549*8160SWentao.Yang@Sun.COM 1550*8160SWentao.Yang@Sun.COM case MAC_STAT_OERRORS: 1551*8160SWentao.Yang@Sun.COM statsp->oerrors = val; 1552*8160SWentao.Yang@Sun.COM break; 1553*8160SWentao.Yang@Sun.COM 1554*8160SWentao.Yang@Sun.COM case MAC_STAT_RBYTES: 1555*8160SWentao.Yang@Sun.COM statsp->rbytes = val; 1556*8160SWentao.Yang@Sun.COM break; 1557*8160SWentao.Yang@Sun.COM 1558*8160SWentao.Yang@Sun.COM case MAC_STAT_OBYTES: 1559*8160SWentao.Yang@Sun.COM statsp->obytes = val; 1560*8160SWentao.Yang@Sun.COM break; 1561*8160SWentao.Yang@Sun.COM 1562*8160SWentao.Yang@Sun.COM case MAC_STAT_MULTIRCV: 1563*8160SWentao.Yang@Sun.COM statsp->multircv = val; 1564*8160SWentao.Yang@Sun.COM break; 1565*8160SWentao.Yang@Sun.COM 1566*8160SWentao.Yang@Sun.COM case MAC_STAT_MULTIXMT: 1567*8160SWentao.Yang@Sun.COM statsp->multixmt = val; 1568*8160SWentao.Yang@Sun.COM break; 1569*8160SWentao.Yang@Sun.COM 1570*8160SWentao.Yang@Sun.COM case MAC_STAT_BRDCSTRCV: 1571*8160SWentao.Yang@Sun.COM statsp->brdcstrcv = val; 1572*8160SWentao.Yang@Sun.COM break; 1573*8160SWentao.Yang@Sun.COM 1574*8160SWentao.Yang@Sun.COM case MAC_STAT_BRDCSTXMT: 1575*8160SWentao.Yang@Sun.COM statsp->brdcstxmt = val; 1576*8160SWentao.Yang@Sun.COM break; 1577*8160SWentao.Yang@Sun.COM 1578*8160SWentao.Yang@Sun.COM case MAC_STAT_NOXMTBUF: 1579*8160SWentao.Yang@Sun.COM statsp->noxmtbuf = val; 1580*8160SWentao.Yang@Sun.COM break; 1581*8160SWentao.Yang@Sun.COM 1582*8160SWentao.Yang@Sun.COM case MAC_STAT_NORCVBUF: 1583*8160SWentao.Yang@Sun.COM statsp->norcvbuf = val; 1584*8160SWentao.Yang@Sun.COM break; 1585*8160SWentao.Yang@Sun.COM 1586*8160SWentao.Yang@Sun.COM default: 1587*8160SWentao.Yang@Sun.COM /* 1588*8160SWentao.Yang@Sun.COM * parameters not interested. 1589*8160SWentao.Yang@Sun.COM */ 1590*8160SWentao.Yang@Sun.COM break; 1591*8160SWentao.Yang@Sun.COM } 1592*8160SWentao.Yang@Sun.COM } 1593*8160SWentao.Yang@Sun.COM } 1594*8160SWentao.Yang@Sun.COM } 1595