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 /* 23c1c61f44Ssb155480 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 241ae08745Sheppo * Use is subject to license terms. 251ae08745Sheppo */ 261ae08745Sheppo 271ae08745Sheppo #include <sys/types.h> 281ae08745Sheppo #include <sys/errno.h> 291ae08745Sheppo #include <sys/param.h> 301ae08745Sheppo #include <sys/stream.h> 311ae08745Sheppo #include <sys/kmem.h> 321ae08745Sheppo #include <sys/conf.h> 331ae08745Sheppo #include <sys/devops.h> 341ae08745Sheppo #include <sys/ksynch.h> 351ae08745Sheppo #include <sys/stat.h> 361ae08745Sheppo #include <sys/modctl.h> 37c1c61f44Ssb155480 #include <sys/modhash.h> 381ae08745Sheppo #include <sys/debug.h> 391ae08745Sheppo #include <sys/ethernet.h> 401ae08745Sheppo #include <sys/dlpi.h> 411ae08745Sheppo #include <net/if.h> 42da14cebeSEric Cheng #include <sys/mac_provider.h> 43ba2e4443Sseb #include <sys/mac_ether.h> 441ae08745Sheppo #include <sys/ddi.h> 451ae08745Sheppo #include <sys/sunddi.h> 461ae08745Sheppo #include <sys/strsun.h> 471ae08745Sheppo #include <sys/note.h> 48c1c61f44Ssb155480 #include <sys/atomic.h> 491ae08745Sheppo #include <sys/vnet.h> 50c1c61f44Ssb155480 #include <sys/vlan.h> 51678453a8Sspeer #include <sys/vnet_mailbox.h> 52678453a8Sspeer #include <sys/vnet_common.h> 53678453a8Sspeer #include <sys/dds.h> 54678453a8Sspeer #include <sys/strsubr.h> 55678453a8Sspeer #include <sys/taskq.h> 561ae08745Sheppo 571ae08745Sheppo /* 581ae08745Sheppo * Function prototypes. 591ae08745Sheppo */ 601ae08745Sheppo 611ae08745Sheppo /* DDI entrypoints */ 621ae08745Sheppo static int vnetdevinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 631ae08745Sheppo static int vnetattach(dev_info_t *, ddi_attach_cmd_t); 641ae08745Sheppo static int vnetdetach(dev_info_t *, ddi_detach_cmd_t); 651ae08745Sheppo 661ae08745Sheppo /* MAC entrypoints */ 67ba2e4443Sseb static int vnet_m_stat(void *, uint_t, uint64_t *); 681ae08745Sheppo static int vnet_m_start(void *); 691ae08745Sheppo static void vnet_m_stop(void *); 701ae08745Sheppo static int vnet_m_promisc(void *, boolean_t); 711ae08745Sheppo static int vnet_m_multicst(void *, boolean_t, const uint8_t *); 721ae08745Sheppo static int vnet_m_unicst(void *, const uint8_t *); 731ae08745Sheppo mblk_t *vnet_m_tx(void *, mblk_t *); 741ae08745Sheppo 751ae08745Sheppo /* vnet internal functions */ 761ae08745Sheppo static int vnet_mac_register(vnet_t *); 771ae08745Sheppo static int vnet_read_mac_address(vnet_t *vnetp); 781ae08745Sheppo 79c1c61f44Ssb155480 /* Forwarding database (FDB) routines */ 80c1c61f44Ssb155480 static void vnet_fdb_create(vnet_t *vnetp); 81c1c61f44Ssb155480 static void vnet_fdb_destroy(vnet_t *vnetp); 82678453a8Sspeer static vnet_res_t *vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp); 83c1c61f44Ssb155480 static void vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val); 84678453a8Sspeer void vnet_fdbe_add(vnet_t *vnetp, vnet_res_t *vresp); 85678453a8Sspeer static void vnet_fdbe_del(vnet_t *vnetp, vnet_res_t *vresp); 86c1c61f44Ssb155480 878c242ab0SSriharsha Basavapatna static void vnet_rx_frames_untag(uint16_t pvid, mblk_t **mp); 88678453a8Sspeer static void vnet_rx(vio_net_handle_t vrh, mblk_t *mp); 89678453a8Sspeer static void vnet_tx_update(vio_net_handle_t vrh); 90678453a8Sspeer static void vnet_res_start_task(void *arg); 91678453a8Sspeer static void vnet_start_resources(vnet_t *vnetp); 92678453a8Sspeer static void vnet_stop_resources(vnet_t *vnetp); 93678453a8Sspeer static void vnet_dispatch_res_task(vnet_t *vnetp); 94678453a8Sspeer static void vnet_res_start_task(void *arg); 95678453a8Sspeer static void vnet_handle_res_err(vio_net_handle_t vrh, vio_net_err_val_t err); 967b1f684aSSriharsha Basavapatna int vnet_mtu_update(vnet_t *vnetp, uint32_t mtu); 97678453a8Sspeer 986ab6cb20SWENTAO YANG static kstat_t *vnet_hio_setup_kstats(char *ks_mod, char *ks_name, 996ab6cb20SWENTAO YANG vnet_res_t *vresp); 1006ab6cb20SWENTAO YANG static int vnet_hio_update_kstats(kstat_t *ksp, int rw); 1016ab6cb20SWENTAO YANG static void vnet_hio_get_stats(vnet_res_t *vresp, vnet_hio_stats_t *statsp); 1026ab6cb20SWENTAO YANG static void vnet_hio_destroy_kstats(kstat_t *ksp); 1036ab6cb20SWENTAO YANG 104678453a8Sspeer /* Exported to to vnet_dds */ 105678453a8Sspeer int vnet_send_dds_msg(vnet_t *vnetp, void *dmsg); 106678453a8Sspeer 107678453a8Sspeer /* Externs that are imported from vnet_gen */ 108678453a8Sspeer extern int vgen_init(void *vnetp, uint64_t regprop, dev_info_t *vnetdip, 109678453a8Sspeer const uint8_t *macaddr, void **vgenhdl); 110d10e4ef2Snarayan extern int vgen_uninit(void *arg); 111678453a8Sspeer extern int vgen_dds_tx(void *arg, void *dmsg); 112678453a8Sspeer 113678453a8Sspeer /* Externs that are imported from vnet_dds */ 114678453a8Sspeer extern void vdds_mod_init(void); 115678453a8Sspeer extern void vdds_mod_fini(void); 116678453a8Sspeer extern int vdds_init(vnet_t *vnetp); 117678453a8Sspeer extern void vdds_cleanup(vnet_t *vnetp); 118678453a8Sspeer extern void vdds_process_dds_msg(vnet_t *vnetp, vio_dds_msg_t *dmsg); 119d0288fccSRaghuram Kothakota extern void vdds_cleanup_hybrid_res(void *arg); 1201ae08745Sheppo 1216ab6cb20SWENTAO YANG #define DRV_NAME "vnet" 122c1c61f44Ssb155480 #define VNET_FDBE_REFHOLD(p) \ 123c1c61f44Ssb155480 { \ 124c1c61f44Ssb155480 atomic_inc_32(&(p)->refcnt); \ 125c1c61f44Ssb155480 ASSERT((p)->refcnt != 0); \ 126c1c61f44Ssb155480 } 127c1c61f44Ssb155480 128c1c61f44Ssb155480 #define VNET_FDBE_REFRELE(p) \ 129c1c61f44Ssb155480 { \ 130c1c61f44Ssb155480 ASSERT((p)->refcnt != 0); \ 131c1c61f44Ssb155480 atomic_dec_32(&(p)->refcnt); \ 132c1c61f44Ssb155480 } 133c1c61f44Ssb155480 134ba2e4443Sseb static mac_callbacks_t vnet_m_callbacks = { 135ba2e4443Sseb 0, 136ba2e4443Sseb vnet_m_stat, 137ba2e4443Sseb vnet_m_start, 138ba2e4443Sseb vnet_m_stop, 139ba2e4443Sseb vnet_m_promisc, 140ba2e4443Sseb vnet_m_multicst, 141ba2e4443Sseb vnet_m_unicst, 142ba2e4443Sseb vnet_m_tx, 143ba2e4443Sseb NULL, 144ba2e4443Sseb NULL, 145ba2e4443Sseb NULL 146ba2e4443Sseb }; 147ba2e4443Sseb 1481ae08745Sheppo /* 1491ae08745Sheppo * Linked list of "vnet_t" structures - one per instance. 1501ae08745Sheppo */ 1511ae08745Sheppo static vnet_t *vnet_headp = NULL; 1521ae08745Sheppo static krwlock_t vnet_rw; 1531ae08745Sheppo 1541ae08745Sheppo /* Tunables */ 1551ae08745Sheppo uint32_t vnet_ntxds = VNET_NTXDS; /* power of 2 transmit descriptors */ 1561ae08745Sheppo uint32_t vnet_ldcwd_interval = VNET_LDCWD_INTERVAL; /* watchdog freq in msec */ 1571ae08745Sheppo uint32_t vnet_ldcwd_txtimeout = VNET_LDCWD_TXTIMEOUT; /* tx timeout in msec */ 158e1ebb9ecSlm66018 uint32_t vnet_ldc_mtu = VNET_LDC_MTU; /* ldc mtu */ 159c1c61f44Ssb155480 1607b1f684aSSriharsha Basavapatna /* 1617b1f684aSSriharsha Basavapatna * Set this to non-zero to enable additional internal receive buffer pools 1627b1f684aSSriharsha Basavapatna * based on the MTU of the device for better performance at the cost of more 1637b1f684aSSriharsha Basavapatna * memory consumption. This is turned off by default, to use allocb(9F) for 1647b1f684aSSriharsha Basavapatna * receive buffer allocations of sizes > 2K. 1657b1f684aSSriharsha Basavapatna */ 1667b1f684aSSriharsha Basavapatna boolean_t vnet_jumbo_rxpools = B_FALSE; 1677b1f684aSSriharsha Basavapatna 168c1c61f44Ssb155480 /* # of chains in fdb hash table */ 169c1c61f44Ssb155480 uint32_t vnet_fdb_nchains = VNET_NFDB_HASH; 170c1c61f44Ssb155480 171c1c61f44Ssb155480 /* Internal tunables */ 172c1c61f44Ssb155480 uint32_t vnet_ethermtu = 1500; /* mtu of the device */ 173c1c61f44Ssb155480 174c1c61f44Ssb155480 /* 175c1c61f44Ssb155480 * Default vlan id. This is only used internally when the "default-vlan-id" 176c1c61f44Ssb155480 * property is not present in the MD device node. Therefore, this should not be 177c1c61f44Ssb155480 * used as a tunable; if this value is changed, the corresponding variable 178c1c61f44Ssb155480 * should be updated to the same value in vsw and also other vnets connected to 179c1c61f44Ssb155480 * the same vsw. 180c1c61f44Ssb155480 */ 181c1c61f44Ssb155480 uint16_t vnet_default_vlan_id = 1; 182c1c61f44Ssb155480 183c1c61f44Ssb155480 /* delay in usec to wait for all references on a fdb entry to be dropped */ 184c1c61f44Ssb155480 uint32_t vnet_fdbe_refcnt_delay = 10; 1851ae08745Sheppo 186678453a8Sspeer static struct ether_addr etherbroadcastaddr = { 187678453a8Sspeer 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 188678453a8Sspeer }; 189678453a8Sspeer 190678453a8Sspeer 1911ae08745Sheppo /* 1921ae08745Sheppo * Property names 1931ae08745Sheppo */ 1941ae08745Sheppo static char macaddr_propname[] = "local-mac-address"; 1951ae08745Sheppo 1961ae08745Sheppo /* 1971ae08745Sheppo * This is the string displayed by modinfo(1m). 1981ae08745Sheppo */ 1997b1f684aSSriharsha Basavapatna static char vnet_ident[] = "vnet driver"; 2001ae08745Sheppo extern struct mod_ops mod_driverops; 2011ae08745Sheppo static struct cb_ops cb_vnetops = { 2021ae08745Sheppo nulldev, /* cb_open */ 2031ae08745Sheppo nulldev, /* cb_close */ 2041ae08745Sheppo nodev, /* cb_strategy */ 2051ae08745Sheppo nodev, /* cb_print */ 2061ae08745Sheppo nodev, /* cb_dump */ 2071ae08745Sheppo nodev, /* cb_read */ 2081ae08745Sheppo nodev, /* cb_write */ 2091ae08745Sheppo nodev, /* cb_ioctl */ 2101ae08745Sheppo nodev, /* cb_devmap */ 2111ae08745Sheppo nodev, /* cb_mmap */ 2121ae08745Sheppo nodev, /* cb_segmap */ 2131ae08745Sheppo nochpoll, /* cb_chpoll */ 2141ae08745Sheppo ddi_prop_op, /* cb_prop_op */ 2151ae08745Sheppo NULL, /* cb_stream */ 2161ae08745Sheppo (int)(D_MP) /* cb_flag */ 2171ae08745Sheppo }; 2181ae08745Sheppo 2191ae08745Sheppo static struct dev_ops vnetops = { 2201ae08745Sheppo DEVO_REV, /* devo_rev */ 2211ae08745Sheppo 0, /* devo_refcnt */ 2221ae08745Sheppo NULL, /* devo_getinfo */ 2231ae08745Sheppo nulldev, /* devo_identify */ 2241ae08745Sheppo nulldev, /* devo_probe */ 2251ae08745Sheppo vnetattach, /* devo_attach */ 2261ae08745Sheppo vnetdetach, /* devo_detach */ 2271ae08745Sheppo nodev, /* devo_reset */ 2281ae08745Sheppo &cb_vnetops, /* devo_cb_ops */ 22919397407SSherry Moore (struct bus_ops *)NULL, /* devo_bus_ops */ 23019397407SSherry Moore NULL, /* devo_power */ 23119397407SSherry Moore ddi_quiesce_not_supported, /* devo_quiesce */ 2321ae08745Sheppo }; 2331ae08745Sheppo 2341ae08745Sheppo static struct modldrv modldrv = { 2351ae08745Sheppo &mod_driverops, /* Type of module. This one is a driver */ 2361ae08745Sheppo vnet_ident, /* ID string */ 2371ae08745Sheppo &vnetops /* driver specific ops */ 2381ae08745Sheppo }; 2391ae08745Sheppo 2401ae08745Sheppo static struct modlinkage modlinkage = { 2411ae08745Sheppo MODREV_1, (void *)&modldrv, NULL 2421ae08745Sheppo }; 2431ae08745Sheppo 244844e62a3Sraghuram #ifdef DEBUG 2451ae08745Sheppo 2461ae08745Sheppo /* 2471ae08745Sheppo * Print debug messages - set to 0xf to enable all msgs 2481ae08745Sheppo */ 249844e62a3Sraghuram int vnet_dbglevel = 0x8; 2501ae08745Sheppo 251844e62a3Sraghuram static void 252844e62a3Sraghuram debug_printf(const char *fname, void *arg, const char *fmt, ...) 2531ae08745Sheppo { 2541ae08745Sheppo char buf[512]; 2551ae08745Sheppo va_list ap; 2561ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 257844e62a3Sraghuram char *bufp = buf; 2581ae08745Sheppo 259844e62a3Sraghuram if (vnetp == NULL) { 260844e62a3Sraghuram (void) sprintf(bufp, "%s: ", fname); 261844e62a3Sraghuram bufp += strlen(bufp); 262844e62a3Sraghuram } else { 263844e62a3Sraghuram (void) sprintf(bufp, "vnet%d:%s: ", vnetp->instance, fname); 264844e62a3Sraghuram bufp += strlen(bufp); 2651ae08745Sheppo } 266844e62a3Sraghuram va_start(ap, fmt); 267844e62a3Sraghuram (void) vsprintf(bufp, fmt, ap); 268844e62a3Sraghuram va_end(ap); 269844e62a3Sraghuram cmn_err(CE_CONT, "%s\n", buf); 270844e62a3Sraghuram } 2711ae08745Sheppo 2721ae08745Sheppo #endif 2731ae08745Sheppo 2741ae08745Sheppo /* _init(9E): initialize the loadable module */ 2751ae08745Sheppo int 2761ae08745Sheppo _init(void) 2771ae08745Sheppo { 2781ae08745Sheppo int status; 2791ae08745Sheppo 280844e62a3Sraghuram DBG1(NULL, "enter\n"); 2811ae08745Sheppo 2821ae08745Sheppo mac_init_ops(&vnetops, "vnet"); 2831ae08745Sheppo status = mod_install(&modlinkage); 2841ae08745Sheppo if (status != 0) { 2851ae08745Sheppo mac_fini_ops(&vnetops); 2861ae08745Sheppo } 287678453a8Sspeer vdds_mod_init(); 288844e62a3Sraghuram DBG1(NULL, "exit(%d)\n", status); 2891ae08745Sheppo return (status); 2901ae08745Sheppo } 2911ae08745Sheppo 2921ae08745Sheppo /* _fini(9E): prepare the module for unloading. */ 2931ae08745Sheppo int 2941ae08745Sheppo _fini(void) 2951ae08745Sheppo { 2961ae08745Sheppo int status; 2971ae08745Sheppo 298844e62a3Sraghuram DBG1(NULL, "enter\n"); 2991ae08745Sheppo 3001ae08745Sheppo status = mod_remove(&modlinkage); 3011ae08745Sheppo if (status != 0) 3021ae08745Sheppo return (status); 3031ae08745Sheppo mac_fini_ops(&vnetops); 304678453a8Sspeer vdds_mod_fini(); 3051ae08745Sheppo 306844e62a3Sraghuram DBG1(NULL, "exit(%d)\n", status); 3071ae08745Sheppo return (status); 3081ae08745Sheppo } 3091ae08745Sheppo 3101ae08745Sheppo /* _info(9E): return information about the loadable module */ 3111ae08745Sheppo int 3121ae08745Sheppo _info(struct modinfo *modinfop) 3131ae08745Sheppo { 3141ae08745Sheppo return (mod_info(&modlinkage, modinfop)); 3151ae08745Sheppo } 3161ae08745Sheppo 3171ae08745Sheppo /* 3181ae08745Sheppo * attach(9E): attach a device to the system. 3191ae08745Sheppo * called once for each instance of the device on the system. 3201ae08745Sheppo */ 3211ae08745Sheppo static int 3221ae08745Sheppo vnetattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 3231ae08745Sheppo { 3241ae08745Sheppo vnet_t *vnetp; 3251ae08745Sheppo int status; 326678453a8Sspeer int instance; 327678453a8Sspeer uint64_t reg; 328678453a8Sspeer char qname[TASKQ_NAMELEN]; 3291ae08745Sheppo enum { AST_init = 0x0, AST_vnet_alloc = 0x1, 330d10e4ef2Snarayan AST_mac_alloc = 0x2, AST_read_macaddr = 0x4, 331678453a8Sspeer AST_vgen_init = 0x8, AST_fdbh_alloc = 0x10, 332678453a8Sspeer AST_vdds_init = 0x20, AST_taskq_create = 0x40, 333678453a8Sspeer AST_vnet_list = 0x80 } attach_state; 3341ae08745Sheppo 3351ae08745Sheppo attach_state = AST_init; 3361ae08745Sheppo 3371ae08745Sheppo switch (cmd) { 3381ae08745Sheppo case DDI_ATTACH: 3391ae08745Sheppo break; 3401ae08745Sheppo case DDI_RESUME: 3411ae08745Sheppo case DDI_PM_RESUME: 3421ae08745Sheppo default: 3431ae08745Sheppo goto vnet_attach_fail; 3441ae08745Sheppo } 3451ae08745Sheppo 3461ae08745Sheppo instance = ddi_get_instance(dip); 347844e62a3Sraghuram DBG1(NULL, "instance(%d) enter\n", instance); 3481ae08745Sheppo 3491ae08745Sheppo /* allocate vnet_t and mac_t structures */ 3501ae08745Sheppo vnetp = kmem_zalloc(sizeof (vnet_t), KM_SLEEP); 351678453a8Sspeer vnetp->dip = dip; 352678453a8Sspeer vnetp->instance = instance; 353678453a8Sspeer rw_init(&vnetp->vrwlock, NULL, RW_DRIVER, NULL); 354678453a8Sspeer rw_init(&vnetp->vsw_fp_rw, NULL, RW_DRIVER, NULL); 3551ae08745Sheppo attach_state |= AST_vnet_alloc; 3561ae08745Sheppo 357678453a8Sspeer status = vdds_init(vnetp); 358678453a8Sspeer if (status != 0) { 359678453a8Sspeer goto vnet_attach_fail; 360678453a8Sspeer } 361678453a8Sspeer attach_state |= AST_vdds_init; 362678453a8Sspeer 3631ae08745Sheppo /* setup links to vnet_t from both devinfo and mac_t */ 3641ae08745Sheppo ddi_set_driver_private(dip, (caddr_t)vnetp); 3651ae08745Sheppo 3661ae08745Sheppo /* read the mac address */ 3671ae08745Sheppo status = vnet_read_mac_address(vnetp); 3681ae08745Sheppo if (status != DDI_SUCCESS) { 3691ae08745Sheppo goto vnet_attach_fail; 3701ae08745Sheppo } 3711ae08745Sheppo attach_state |= AST_read_macaddr; 3721ae08745Sheppo 373678453a8Sspeer reg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 374678453a8Sspeer DDI_PROP_DONTPASS, "reg", -1); 375678453a8Sspeer if (reg == -1) { 3761ae08745Sheppo goto vnet_attach_fail; 3771ae08745Sheppo } 378678453a8Sspeer vnetp->reg = reg; 3791ae08745Sheppo 380c1c61f44Ssb155480 vnet_fdb_create(vnetp); 3811ae08745Sheppo attach_state |= AST_fdbh_alloc; 3821ae08745Sheppo 383678453a8Sspeer (void) snprintf(qname, TASKQ_NAMELEN, "vnet_taskq%d", instance); 384678453a8Sspeer if ((vnetp->taskqp = ddi_taskq_create(dip, qname, 1, 385678453a8Sspeer TASKQ_DEFAULTPRI, 0)) == NULL) { 386678453a8Sspeer cmn_err(CE_WARN, "!vnet%d: Unable to create task queue", 387678453a8Sspeer instance); 3881ae08745Sheppo goto vnet_attach_fail; 3891ae08745Sheppo } 390678453a8Sspeer attach_state |= AST_taskq_create; 3911ae08745Sheppo 3921ae08745Sheppo /* add to the list of vnet devices */ 3931ae08745Sheppo WRITE_ENTER(&vnet_rw); 3941ae08745Sheppo vnetp->nextp = vnet_headp; 3951ae08745Sheppo vnet_headp = vnetp; 3961ae08745Sheppo RW_EXIT(&vnet_rw); 3971ae08745Sheppo 398678453a8Sspeer attach_state |= AST_vnet_list; 399678453a8Sspeer 400678453a8Sspeer /* 401678453a8Sspeer * Initialize the generic vnet plugin which provides 402678453a8Sspeer * communication via sun4v LDC (logical domain channel) based 403678453a8Sspeer * resources. It will register the LDC resources as and when 404678453a8Sspeer * they become available. 405678453a8Sspeer */ 406678453a8Sspeer status = vgen_init(vnetp, reg, vnetp->dip, 407678453a8Sspeer (uint8_t *)vnetp->curr_macaddr, &vnetp->vgenhdl); 408678453a8Sspeer if (status != DDI_SUCCESS) { 409678453a8Sspeer DERR(vnetp, "vgen_init() failed\n"); 410678453a8Sspeer goto vnet_attach_fail; 411678453a8Sspeer } 412678453a8Sspeer attach_state |= AST_vgen_init; 413678453a8Sspeer 414678453a8Sspeer /* register with MAC layer */ 415678453a8Sspeer status = vnet_mac_register(vnetp); 416678453a8Sspeer if (status != DDI_SUCCESS) { 417678453a8Sspeer goto vnet_attach_fail; 418678453a8Sspeer } 419678453a8Sspeer 420844e62a3Sraghuram DBG1(NULL, "instance(%d) exit\n", instance); 4211ae08745Sheppo return (DDI_SUCCESS); 4221ae08745Sheppo 4231ae08745Sheppo vnet_attach_fail: 424678453a8Sspeer 425678453a8Sspeer if (attach_state & AST_vnet_list) { 426678453a8Sspeer vnet_t **vnetpp; 427678453a8Sspeer /* unlink from instance(vnet_t) list */ 428678453a8Sspeer WRITE_ENTER(&vnet_rw); 429678453a8Sspeer for (vnetpp = &vnet_headp; *vnetpp; 430678453a8Sspeer vnetpp = &(*vnetpp)->nextp) { 431678453a8Sspeer if (*vnetpp == vnetp) { 432678453a8Sspeer *vnetpp = vnetp->nextp; 433678453a8Sspeer break; 434678453a8Sspeer } 435678453a8Sspeer } 436678453a8Sspeer RW_EXIT(&vnet_rw); 437678453a8Sspeer } 438678453a8Sspeer 439678453a8Sspeer if (attach_state & AST_vdds_init) { 440678453a8Sspeer vdds_cleanup(vnetp); 441678453a8Sspeer } 442678453a8Sspeer if (attach_state & AST_taskq_create) { 443678453a8Sspeer ddi_taskq_destroy(vnetp->taskqp); 444678453a8Sspeer } 4451ae08745Sheppo if (attach_state & AST_fdbh_alloc) { 446c1c61f44Ssb155480 vnet_fdb_destroy(vnetp); 4471ae08745Sheppo } 4481ae08745Sheppo if (attach_state & AST_vgen_init) { 449678453a8Sspeer (void) vgen_uninit(vnetp->vgenhdl); 4501ae08745Sheppo } 4511ae08745Sheppo if (attach_state & AST_vnet_alloc) { 452678453a8Sspeer rw_destroy(&vnetp->vrwlock); 453678453a8Sspeer rw_destroy(&vnetp->vsw_fp_rw); 4541ae08745Sheppo KMEM_FREE(vnetp); 4551ae08745Sheppo } 4561ae08745Sheppo return (DDI_FAILURE); 4571ae08745Sheppo } 4581ae08745Sheppo 4591ae08745Sheppo /* 4601ae08745Sheppo * detach(9E): detach a device from the system. 4611ae08745Sheppo */ 4621ae08745Sheppo static int 4631ae08745Sheppo vnetdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4641ae08745Sheppo { 4651ae08745Sheppo vnet_t *vnetp; 4661ae08745Sheppo vnet_t **vnetpp; 4671ae08745Sheppo int instance; 468d10e4ef2Snarayan int rv; 4691ae08745Sheppo 4701ae08745Sheppo instance = ddi_get_instance(dip); 471844e62a3Sraghuram DBG1(NULL, "instance(%d) enter\n", instance); 4721ae08745Sheppo 4731ae08745Sheppo vnetp = ddi_get_driver_private(dip); 4741ae08745Sheppo if (vnetp == NULL) { 4751ae08745Sheppo goto vnet_detach_fail; 4761ae08745Sheppo } 4771ae08745Sheppo 4781ae08745Sheppo switch (cmd) { 4791ae08745Sheppo case DDI_DETACH: 4801ae08745Sheppo break; 4811ae08745Sheppo case DDI_SUSPEND: 4821ae08745Sheppo case DDI_PM_SUSPEND: 4831ae08745Sheppo default: 4841ae08745Sheppo goto vnet_detach_fail; 4851ae08745Sheppo } 4861ae08745Sheppo 487678453a8Sspeer (void) vdds_cleanup(vnetp); 488678453a8Sspeer rv = vgen_uninit(vnetp->vgenhdl); 489d10e4ef2Snarayan if (rv != DDI_SUCCESS) { 490d10e4ef2Snarayan goto vnet_detach_fail; 491d10e4ef2Snarayan } 492d10e4ef2Snarayan 4931ae08745Sheppo /* 4941ae08745Sheppo * Unregister from the MAC subsystem. This can fail, in 4951ae08745Sheppo * particular if there are DLPI style-2 streams still open - 4961ae08745Sheppo * in which case we just return failure. 4971ae08745Sheppo */ 498ba2e4443Sseb if (mac_unregister(vnetp->mh) != 0) 4991ae08745Sheppo goto vnet_detach_fail; 5001ae08745Sheppo 5011ae08745Sheppo /* unlink from instance(vnet_t) list */ 5021ae08745Sheppo WRITE_ENTER(&vnet_rw); 5031ae08745Sheppo for (vnetpp = &vnet_headp; *vnetpp; vnetpp = &(*vnetpp)->nextp) { 5041ae08745Sheppo if (*vnetpp == vnetp) { 5051ae08745Sheppo *vnetpp = vnetp->nextp; 5061ae08745Sheppo break; 5071ae08745Sheppo } 5081ae08745Sheppo } 5091ae08745Sheppo RW_EXIT(&vnet_rw); 5101ae08745Sheppo 511678453a8Sspeer ddi_taskq_destroy(vnetp->taskqp); 512c1c61f44Ssb155480 /* destroy fdb */ 513c1c61f44Ssb155480 vnet_fdb_destroy(vnetp); 514445b4c2eSsb155480 515678453a8Sspeer rw_destroy(&vnetp->vrwlock); 516678453a8Sspeer rw_destroy(&vnetp->vsw_fp_rw); 5171ae08745Sheppo KMEM_FREE(vnetp); 5181ae08745Sheppo 5191ae08745Sheppo return (DDI_SUCCESS); 5201ae08745Sheppo 5211ae08745Sheppo vnet_detach_fail: 5221ae08745Sheppo return (DDI_FAILURE); 5231ae08745Sheppo } 5241ae08745Sheppo 5251ae08745Sheppo /* enable the device for transmit/receive */ 5261ae08745Sheppo static int 5271ae08745Sheppo vnet_m_start(void *arg) 5281ae08745Sheppo { 5291ae08745Sheppo vnet_t *vnetp = arg; 5301ae08745Sheppo 531844e62a3Sraghuram DBG1(vnetp, "enter\n"); 5321ae08745Sheppo 533678453a8Sspeer WRITE_ENTER(&vnetp->vrwlock); 534678453a8Sspeer vnetp->flags |= VNET_STARTED; 535678453a8Sspeer vnet_start_resources(vnetp); 536678453a8Sspeer RW_EXIT(&vnetp->vrwlock); 5371ae08745Sheppo 538844e62a3Sraghuram DBG1(vnetp, "exit\n"); 5391ae08745Sheppo return (VNET_SUCCESS); 5401ae08745Sheppo 5411ae08745Sheppo } 5421ae08745Sheppo 5431ae08745Sheppo /* stop transmit/receive for the device */ 5441ae08745Sheppo static void 5451ae08745Sheppo vnet_m_stop(void *arg) 5461ae08745Sheppo { 5471ae08745Sheppo vnet_t *vnetp = arg; 5481ae08745Sheppo 549844e62a3Sraghuram DBG1(vnetp, "enter\n"); 5501ae08745Sheppo 551678453a8Sspeer WRITE_ENTER(&vnetp->vrwlock); 552678453a8Sspeer if (vnetp->flags & VNET_STARTED) { 553678453a8Sspeer vnet_stop_resources(vnetp); 554678453a8Sspeer vnetp->flags &= ~VNET_STARTED; 5551ae08745Sheppo } 556678453a8Sspeer RW_EXIT(&vnetp->vrwlock); 5571ae08745Sheppo 558844e62a3Sraghuram DBG1(vnetp, "exit\n"); 5591ae08745Sheppo } 5601ae08745Sheppo 5611ae08745Sheppo /* set the unicast mac address of the device */ 5621ae08745Sheppo static int 5631ae08745Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr) 5641ae08745Sheppo { 5651ae08745Sheppo _NOTE(ARGUNUSED(macaddr)) 5661ae08745Sheppo 5671ae08745Sheppo vnet_t *vnetp = arg; 5681ae08745Sheppo 569844e62a3Sraghuram DBG1(vnetp, "enter\n"); 5701ae08745Sheppo /* 5713af08d82Slm66018 * NOTE: setting mac address dynamically is not supported. 5721ae08745Sheppo */ 573844e62a3Sraghuram DBG1(vnetp, "exit\n"); 5741ae08745Sheppo 5758e6a2a04Slm66018 return (VNET_FAILURE); 5761ae08745Sheppo } 5771ae08745Sheppo 5781ae08745Sheppo /* enable/disable a multicast address */ 5791ae08745Sheppo static int 5801ae08745Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 5811ae08745Sheppo { 5821ae08745Sheppo _NOTE(ARGUNUSED(add, mca)) 5831ae08745Sheppo 5841ae08745Sheppo vnet_t *vnetp = arg; 585678453a8Sspeer vnet_res_t *vresp; 586678453a8Sspeer mac_register_t *macp; 587ba2e4443Sseb mac_callbacks_t *cbp; 5881ae08745Sheppo int rv = VNET_SUCCESS; 5891ae08745Sheppo 590844e62a3Sraghuram DBG1(vnetp, "enter\n"); 591678453a8Sspeer 592678453a8Sspeer READ_ENTER(&vnetp->vrwlock); 593678453a8Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 594678453a8Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 595678453a8Sspeer macp = &vresp->macreg; 596678453a8Sspeer cbp = macp->m_callbacks; 597678453a8Sspeer rv = cbp->mc_multicst(macp->m_driver, add, mca); 5981ae08745Sheppo } 5991ae08745Sheppo } 600678453a8Sspeer RW_EXIT(&vnetp->vrwlock); 601678453a8Sspeer 602844e62a3Sraghuram DBG1(vnetp, "exit(%d)\n", rv); 6031ae08745Sheppo return (rv); 6041ae08745Sheppo } 6051ae08745Sheppo 6061ae08745Sheppo /* set or clear promiscuous mode on the device */ 6071ae08745Sheppo static int 6081ae08745Sheppo vnet_m_promisc(void *arg, boolean_t on) 6091ae08745Sheppo { 6101ae08745Sheppo _NOTE(ARGUNUSED(on)) 6111ae08745Sheppo 6121ae08745Sheppo vnet_t *vnetp = arg; 613844e62a3Sraghuram DBG1(vnetp, "enter\n"); 6141ae08745Sheppo /* 6153af08d82Slm66018 * NOTE: setting promiscuous mode is not supported, just return success. 6161ae08745Sheppo */ 617844e62a3Sraghuram DBG1(vnetp, "exit\n"); 6181ae08745Sheppo return (VNET_SUCCESS); 6191ae08745Sheppo } 6201ae08745Sheppo 6211ae08745Sheppo /* 6221ae08745Sheppo * Transmit a chain of packets. This function provides switching functionality 6231ae08745Sheppo * based on the destination mac address to reach other guests (within ldoms) or 6241ae08745Sheppo * external hosts. 6251ae08745Sheppo */ 6261ae08745Sheppo mblk_t * 6271ae08745Sheppo vnet_m_tx(void *arg, mblk_t *mp) 6281ae08745Sheppo { 6291ae08745Sheppo vnet_t *vnetp; 630678453a8Sspeer vnet_res_t *vresp; 6311ae08745Sheppo mblk_t *next; 6321ae08745Sheppo mblk_t *resid_mp; 633678453a8Sspeer mac_register_t *macp; 634c1c61f44Ssb155480 struct ether_header *ehp; 635678453a8Sspeer boolean_t is_unicast; 6368c242ab0SSriharsha Basavapatna boolean_t is_pvid; /* non-default pvid ? */ 6378c242ab0SSriharsha Basavapatna boolean_t hres; /* Hybrid resource ? */ 6381ae08745Sheppo 6391ae08745Sheppo vnetp = (vnet_t *)arg; 640844e62a3Sraghuram DBG1(vnetp, "enter\n"); 6411ae08745Sheppo ASSERT(mp != NULL); 6421ae08745Sheppo 6438c242ab0SSriharsha Basavapatna is_pvid = (vnetp->pvid != vnetp->default_vlan_id) ? B_TRUE : B_FALSE; 6448c242ab0SSriharsha Basavapatna 6451ae08745Sheppo while (mp != NULL) { 646c1c61f44Ssb155480 6471ae08745Sheppo next = mp->b_next; 6481ae08745Sheppo mp->b_next = NULL; 6491ae08745Sheppo 6501ae08745Sheppo /* 651c1c61f44Ssb155480 * Find fdb entry for the destination 652c1c61f44Ssb155480 * and hold a reference to it. 6531ae08745Sheppo */ 654c1c61f44Ssb155480 ehp = (struct ether_header *)mp->b_rptr; 655678453a8Sspeer vresp = vnet_fdbe_find(vnetp, &ehp->ether_dhost); 656678453a8Sspeer if (vresp != NULL) { 657c1c61f44Ssb155480 658c1c61f44Ssb155480 /* 659c1c61f44Ssb155480 * Destination found in FDB. 660c1c61f44Ssb155480 * The destination is a vnet device within ldoms 661c1c61f44Ssb155480 * and directly reachable, invoke the tx function 662c1c61f44Ssb155480 * in the fdb entry. 663c1c61f44Ssb155480 */ 664678453a8Sspeer macp = &vresp->macreg; 665678453a8Sspeer resid_mp = macp->m_callbacks->mc_tx(macp->m_driver, mp); 666c1c61f44Ssb155480 667c1c61f44Ssb155480 /* tx done; now release ref on fdb entry */ 668678453a8Sspeer VNET_FDBE_REFRELE(vresp); 669c1c61f44Ssb155480 6701ae08745Sheppo if (resid_mp != NULL) { 6711ae08745Sheppo /* m_tx failed */ 6721ae08745Sheppo mp->b_next = next; 6731ae08745Sheppo break; 6741ae08745Sheppo } 6751ae08745Sheppo } else { 676678453a8Sspeer is_unicast = !(IS_BROADCAST(ehp) || 677678453a8Sspeer (IS_MULTICAST(ehp))); 6781ae08745Sheppo /* 679c1c61f44Ssb155480 * Destination is not in FDB. 680678453a8Sspeer * If the destination is broadcast or multicast, 681678453a8Sspeer * then forward the packet to vswitch. 682678453a8Sspeer * If a Hybrid resource avilable, then send the 683678453a8Sspeer * unicast packet via hybrid resource, otherwise 684678453a8Sspeer * forward it to vswitch. 6851ae08745Sheppo */ 686c1c61f44Ssb155480 READ_ENTER(&vnetp->vsw_fp_rw); 687c1c61f44Ssb155480 688678453a8Sspeer if ((is_unicast) && (vnetp->hio_fp != NULL)) { 689678453a8Sspeer vresp = vnetp->hio_fp; 6908c242ab0SSriharsha Basavapatna hres = B_TRUE; 691678453a8Sspeer } else { 692678453a8Sspeer vresp = vnetp->vsw_fp; 6938c242ab0SSriharsha Basavapatna hres = B_FALSE; 694678453a8Sspeer } 695678453a8Sspeer if (vresp == NULL) { 696c1c61f44Ssb155480 /* 697c1c61f44Ssb155480 * no fdb entry to vsw? drop the packet. 698c1c61f44Ssb155480 */ 699c1c61f44Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 700c1c61f44Ssb155480 freemsg(mp); 701c1c61f44Ssb155480 mp = next; 702c1c61f44Ssb155480 continue; 703c1c61f44Ssb155480 } 704c1c61f44Ssb155480 705c1c61f44Ssb155480 /* ref hold the fdb entry to vsw */ 706678453a8Sspeer VNET_FDBE_REFHOLD(vresp); 707c1c61f44Ssb155480 708c1c61f44Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 709c1c61f44Ssb155480 7108c242ab0SSriharsha Basavapatna /* 7118c242ab0SSriharsha Basavapatna * In the case of a hybrid resource we need to insert 7128c242ab0SSriharsha Basavapatna * the tag for the pvid case here; unlike packets that 7138c242ab0SSriharsha Basavapatna * are destined to a vnet/vsw in which case the vgen 7148c242ab0SSriharsha Basavapatna * layer does the tagging before sending it over ldc. 7158c242ab0SSriharsha Basavapatna */ 7168c242ab0SSriharsha Basavapatna if (hres == B_TRUE) { 7178c242ab0SSriharsha Basavapatna /* 7188c242ab0SSriharsha Basavapatna * Determine if the frame being transmitted 7198c242ab0SSriharsha Basavapatna * over the hybrid resource is untagged. If so, 7208c242ab0SSriharsha Basavapatna * insert the tag before transmitting. 7218c242ab0SSriharsha Basavapatna */ 7228c242ab0SSriharsha Basavapatna if (is_pvid == B_TRUE && 7238c242ab0SSriharsha Basavapatna ehp->ether_type != htons(ETHERTYPE_VLAN)) { 7248c242ab0SSriharsha Basavapatna 7258c242ab0SSriharsha Basavapatna mp = vnet_vlan_insert_tag(mp, 7268c242ab0SSriharsha Basavapatna vnetp->pvid); 7278c242ab0SSriharsha Basavapatna if (mp == NULL) { 7288c242ab0SSriharsha Basavapatna VNET_FDBE_REFRELE(vresp); 7298c242ab0SSriharsha Basavapatna mp = next; 7308c242ab0SSriharsha Basavapatna continue; 7318c242ab0SSriharsha Basavapatna } 7328c242ab0SSriharsha Basavapatna 7338c242ab0SSriharsha Basavapatna } 7348c242ab0SSriharsha Basavapatna } 7358c242ab0SSriharsha Basavapatna 736678453a8Sspeer macp = &vresp->macreg; 737678453a8Sspeer resid_mp = macp->m_callbacks->mc_tx(macp->m_driver, mp); 738c1c61f44Ssb155480 739c1c61f44Ssb155480 /* tx done; now release ref on fdb entry */ 740678453a8Sspeer VNET_FDBE_REFRELE(vresp); 741c1c61f44Ssb155480 7421ae08745Sheppo if (resid_mp != NULL) { 7431ae08745Sheppo /* m_tx failed */ 7441ae08745Sheppo mp->b_next = next; 7451ae08745Sheppo break; 7461ae08745Sheppo } 7471ae08745Sheppo } 7481ae08745Sheppo 7491ae08745Sheppo mp = next; 7501ae08745Sheppo } 7511ae08745Sheppo 752844e62a3Sraghuram DBG1(vnetp, "exit\n"); 7531ae08745Sheppo return (mp); 7541ae08745Sheppo } 7551ae08745Sheppo 7561ae08745Sheppo /* get statistics from the device */ 757ba2e4443Sseb int 758ba2e4443Sseb vnet_m_stat(void *arg, uint_t stat, uint64_t *val) 7591ae08745Sheppo { 7601ae08745Sheppo vnet_t *vnetp = arg; 761678453a8Sspeer vnet_res_t *vresp; 762678453a8Sspeer mac_register_t *macp; 763ba2e4443Sseb mac_callbacks_t *cbp; 764ba2e4443Sseb uint64_t val_total = 0; 7651ae08745Sheppo 766844e62a3Sraghuram DBG1(vnetp, "enter\n"); 7671ae08745Sheppo 7681ae08745Sheppo /* 769ba2e4443Sseb * get the specified statistic from each transport and return the 770ba2e4443Sseb * aggregate val. This obviously only works for counters. 7711ae08745Sheppo */ 772ba2e4443Sseb if ((IS_MAC_STAT(stat) && !MAC_STAT_ISACOUNTER(stat)) || 773ba2e4443Sseb (IS_MACTYPE_STAT(stat) && !ETHER_STAT_ISACOUNTER(stat))) { 774ba2e4443Sseb return (ENOTSUP); 775ba2e4443Sseb } 776678453a8Sspeer 777678453a8Sspeer READ_ENTER(&vnetp->vrwlock); 778678453a8Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 779678453a8Sspeer macp = &vresp->macreg; 780678453a8Sspeer cbp = macp->m_callbacks; 781678453a8Sspeer if (cbp->mc_getstat(macp->m_driver, stat, val) == 0) 782ba2e4443Sseb val_total += *val; 7831ae08745Sheppo } 784678453a8Sspeer RW_EXIT(&vnetp->vrwlock); 7851ae08745Sheppo 786ba2e4443Sseb *val = val_total; 787ba2e4443Sseb 788844e62a3Sraghuram DBG1(vnetp, "exit\n"); 789ba2e4443Sseb return (0); 7901ae08745Sheppo } 7911ae08745Sheppo 7921ae08745Sheppo /* wrapper function for mac_register() */ 7931ae08745Sheppo static int 7941ae08745Sheppo vnet_mac_register(vnet_t *vnetp) 7951ae08745Sheppo { 796ba2e4443Sseb mac_register_t *macp; 797ba2e4443Sseb int err; 7981ae08745Sheppo 799ba2e4443Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 800ba2e4443Sseb return (DDI_FAILURE); 801ba2e4443Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 802ba2e4443Sseb macp->m_driver = vnetp; 8031ae08745Sheppo macp->m_dip = vnetp->dip; 804ba2e4443Sseb macp->m_src_addr = vnetp->curr_macaddr; 805ba2e4443Sseb macp->m_callbacks = &vnet_m_callbacks; 806ba2e4443Sseb macp->m_min_sdu = 0; 8077b1f684aSSriharsha Basavapatna macp->m_max_sdu = vnetp->mtu; 808c1c61f44Ssb155480 macp->m_margin = VLAN_TAGSZ; 8091ae08745Sheppo 8101ae08745Sheppo /* 8111ae08745Sheppo * Finally, we're ready to register ourselves with the MAC layer 8121ae08745Sheppo * interface; if this succeeds, we're all ready to start() 8131ae08745Sheppo */ 814ba2e4443Sseb err = mac_register(macp, &vnetp->mh); 815ba2e4443Sseb mac_free(macp); 816ba2e4443Sseb return (err == 0 ? DDI_SUCCESS : DDI_FAILURE); 8171ae08745Sheppo } 8181ae08745Sheppo 8191ae08745Sheppo /* read the mac address of the device */ 8201ae08745Sheppo static int 8211ae08745Sheppo vnet_read_mac_address(vnet_t *vnetp) 8221ae08745Sheppo { 8231ae08745Sheppo uchar_t *macaddr; 8241ae08745Sheppo uint32_t size; 8251ae08745Sheppo int rv; 8261ae08745Sheppo 8271ae08745Sheppo rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip, 8281ae08745Sheppo DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size); 8291ae08745Sheppo if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) { 830844e62a3Sraghuram DWARN(vnetp, "prop_lookup failed(%s) err(%d)\n", 831844e62a3Sraghuram macaddr_propname, rv); 8321ae08745Sheppo return (DDI_FAILURE); 8331ae08745Sheppo } 8341ae08745Sheppo bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL); 8351ae08745Sheppo bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL); 8361ae08745Sheppo ddi_prop_free(macaddr); 8371ae08745Sheppo 8381ae08745Sheppo return (DDI_SUCCESS); 8391ae08745Sheppo } 8401ae08745Sheppo 84193b13a42Swentaoy static void 842c1c61f44Ssb155480 vnet_fdb_create(vnet_t *vnetp) 84393b13a42Swentaoy { 844c1c61f44Ssb155480 char hashname[MAXNAMELEN]; 84593b13a42Swentaoy 846c1c61f44Ssb155480 (void) snprintf(hashname, MAXNAMELEN, "vnet%d-fdbhash", 847c1c61f44Ssb155480 vnetp->instance); 848c1c61f44Ssb155480 vnetp->fdb_nchains = vnet_fdb_nchains; 849c1c61f44Ssb155480 vnetp->fdb_hashp = mod_hash_create_ptrhash(hashname, vnetp->fdb_nchains, 850c1c61f44Ssb155480 mod_hash_null_valdtor, sizeof (void *)); 85193b13a42Swentaoy } 85293b13a42Swentaoy 85393b13a42Swentaoy static void 854c1c61f44Ssb155480 vnet_fdb_destroy(vnet_t *vnetp) 85593b13a42Swentaoy { 856c1c61f44Ssb155480 /* destroy fdb-hash-table */ 857c1c61f44Ssb155480 if (vnetp->fdb_hashp != NULL) { 858c1c61f44Ssb155480 mod_hash_destroy_hash(vnetp->fdb_hashp); 859c1c61f44Ssb155480 vnetp->fdb_hashp = NULL; 860c1c61f44Ssb155480 vnetp->fdb_nchains = 0; 861c1c61f44Ssb155480 } 86293b13a42Swentaoy } 86393b13a42Swentaoy 86493b13a42Swentaoy /* 865c1c61f44Ssb155480 * Add an entry into the fdb. 86693b13a42Swentaoy */ 8671ae08745Sheppo void 868678453a8Sspeer vnet_fdbe_add(vnet_t *vnetp, vnet_res_t *vresp) 8691ae08745Sheppo { 870c1c61f44Ssb155480 uint64_t addr = 0; 871c1c61f44Ssb155480 int rv; 872c1c61f44Ssb155480 873678453a8Sspeer KEY_HASH(addr, vresp->rem_macaddr); 8741ae08745Sheppo 8751ae08745Sheppo /* 876678453a8Sspeer * If the entry being added corresponds to LDC_SERVICE resource, 877678453a8Sspeer * that is, vswitch connection, it is added to the hash and also 878678453a8Sspeer * the entry is cached, an additional reference count reflects 879678453a8Sspeer * this. The HYBRID resource is not added to the hash, but only 880678453a8Sspeer * cached, as it is only used for sending out packets for unknown 881678453a8Sspeer * unicast destinations. 8821ae08745Sheppo */ 883678453a8Sspeer (vresp->type == VIO_NET_RES_LDC_SERVICE) ? 884678453a8Sspeer (vresp->refcnt = 1) : (vresp->refcnt = 0); 8851ae08745Sheppo 886c1c61f44Ssb155480 /* 887c1c61f44Ssb155480 * Note: duplicate keys will be rejected by mod_hash. 888c1c61f44Ssb155480 */ 889678453a8Sspeer if (vresp->type != VIO_NET_RES_HYBRID) { 890c1c61f44Ssb155480 rv = mod_hash_insert(vnetp->fdb_hashp, (mod_hash_key_t)addr, 891678453a8Sspeer (mod_hash_val_t)vresp); 892c1c61f44Ssb155480 if (rv != 0) { 893c1c61f44Ssb155480 DWARN(vnetp, "Duplicate macaddr key(%lx)\n", addr); 8941ae08745Sheppo return; 8951ae08745Sheppo } 896678453a8Sspeer } 8971ae08745Sheppo 898678453a8Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 899c1c61f44Ssb155480 /* Cache the fdb entry to vsw-port */ 900c1c61f44Ssb155480 WRITE_ENTER(&vnetp->vsw_fp_rw); 901c1c61f44Ssb155480 if (vnetp->vsw_fp == NULL) 902678453a8Sspeer vnetp->vsw_fp = vresp; 903678453a8Sspeer RW_EXIT(&vnetp->vsw_fp_rw); 904678453a8Sspeer } else if (vresp->type == VIO_NET_RES_HYBRID) { 905678453a8Sspeer /* Cache the fdb entry to hybrid resource */ 906678453a8Sspeer WRITE_ENTER(&vnetp->vsw_fp_rw); 907678453a8Sspeer if (vnetp->hio_fp == NULL) 908678453a8Sspeer vnetp->hio_fp = vresp; 909c1c61f44Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 910c1c61f44Ssb155480 } 9111ae08745Sheppo } 9121ae08745Sheppo 913c1c61f44Ssb155480 /* 914c1c61f44Ssb155480 * Remove an entry from fdb. 915c1c61f44Ssb155480 */ 916678453a8Sspeer static void 917678453a8Sspeer vnet_fdbe_del(vnet_t *vnetp, vnet_res_t *vresp) 9181ae08745Sheppo { 919c1c61f44Ssb155480 uint64_t addr = 0; 920c1c61f44Ssb155480 int rv; 921c1c61f44Ssb155480 uint32_t refcnt; 922678453a8Sspeer vnet_res_t *tmp; 923c1c61f44Ssb155480 924678453a8Sspeer KEY_HASH(addr, vresp->rem_macaddr); 9251ae08745Sheppo 9261ae08745Sheppo /* 927c1c61f44Ssb155480 * Remove the entry from fdb hash table. 928c1c61f44Ssb155480 * This prevents further references to this fdb entry. 9291ae08745Sheppo */ 930678453a8Sspeer if (vresp->type != VIO_NET_RES_HYBRID) { 931c1c61f44Ssb155480 rv = mod_hash_remove(vnetp->fdb_hashp, (mod_hash_key_t)addr, 932678453a8Sspeer (mod_hash_val_t *)&tmp); 933678453a8Sspeer if (rv != 0) { 934678453a8Sspeer /* 935678453a8Sspeer * As the resources are added to the hash only 936678453a8Sspeer * after they are started, this can occur if 937678453a8Sspeer * a resource unregisters before it is ever started. 938678453a8Sspeer */ 939678453a8Sspeer return; 940678453a8Sspeer } 941678453a8Sspeer } 9421ae08745Sheppo 943678453a8Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 944c1c61f44Ssb155480 WRITE_ENTER(&vnetp->vsw_fp_rw); 9451ae08745Sheppo 946678453a8Sspeer ASSERT(tmp == vnetp->vsw_fp); 947c1c61f44Ssb155480 vnetp->vsw_fp = NULL; 948c1c61f44Ssb155480 949c1c61f44Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 950678453a8Sspeer } else if (vresp->type == VIO_NET_RES_HYBRID) { 951678453a8Sspeer WRITE_ENTER(&vnetp->vsw_fp_rw); 952678453a8Sspeer 953678453a8Sspeer vnetp->hio_fp = NULL; 954678453a8Sspeer 955678453a8Sspeer RW_EXIT(&vnetp->vsw_fp_rw); 9561ae08745Sheppo } 9571ae08745Sheppo 958c1c61f44Ssb155480 /* 959c1c61f44Ssb155480 * If there are threads already ref holding before the entry was 960c1c61f44Ssb155480 * removed from hash table, then wait for ref count to drop to zero. 961c1c61f44Ssb155480 */ 962678453a8Sspeer (vresp->type == VIO_NET_RES_LDC_SERVICE) ? 963678453a8Sspeer (refcnt = 1) : (refcnt = 0); 964678453a8Sspeer while (vresp->refcnt > refcnt) { 965c1c61f44Ssb155480 delay(drv_usectohz(vnet_fdbe_refcnt_delay)); 966c1c61f44Ssb155480 } 967c1c61f44Ssb155480 } 968c1c61f44Ssb155480 969c1c61f44Ssb155480 /* 970c1c61f44Ssb155480 * Search fdb for a given mac address. If an entry is found, hold 971c1c61f44Ssb155480 * a reference to it and return the entry; else returns NULL. 972c1c61f44Ssb155480 */ 973678453a8Sspeer static vnet_res_t * 974c1c61f44Ssb155480 vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp) 975c1c61f44Ssb155480 { 976c1c61f44Ssb155480 uint64_t key = 0; 977678453a8Sspeer vnet_res_t *vresp; 978c1c61f44Ssb155480 int rv; 979c1c61f44Ssb155480 980678453a8Sspeer KEY_HASH(key, addrp->ether_addr_octet); 981c1c61f44Ssb155480 982c1c61f44Ssb155480 rv = mod_hash_find_cb(vnetp->fdb_hashp, (mod_hash_key_t)key, 983678453a8Sspeer (mod_hash_val_t *)&vresp, vnet_fdbe_find_cb); 984c1c61f44Ssb155480 985c1c61f44Ssb155480 if (rv != 0) 986c1c61f44Ssb155480 return (NULL); 987c1c61f44Ssb155480 988678453a8Sspeer return (vresp); 989c1c61f44Ssb155480 } 990c1c61f44Ssb155480 991c1c61f44Ssb155480 /* 992c1c61f44Ssb155480 * Callback function provided to mod_hash_find_cb(). After finding the fdb 993c1c61f44Ssb155480 * entry corresponding to the key (macaddr), this callback will be invoked by 994c1c61f44Ssb155480 * mod_hash_find_cb() to atomically increment the reference count on the fdb 995c1c61f44Ssb155480 * entry before returning the found entry. 996c1c61f44Ssb155480 */ 997c1c61f44Ssb155480 static void 998c1c61f44Ssb155480 vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val) 999c1c61f44Ssb155480 { 1000c1c61f44Ssb155480 _NOTE(ARGUNUSED(key)) 1001678453a8Sspeer VNET_FDBE_REFHOLD((vnet_res_t *)val); 1002678453a8Sspeer } 1003678453a8Sspeer 10048c242ab0SSriharsha Basavapatna /* 10058c242ab0SSriharsha Basavapatna * Frames received that are tagged with the pvid of the vnet device must be 10068c242ab0SSriharsha Basavapatna * untagged before sending up the stack. This function walks the chain of rx 10078c242ab0SSriharsha Basavapatna * frames, untags any such frames and returns the updated chain. 10088c242ab0SSriharsha Basavapatna * 10098c242ab0SSriharsha Basavapatna * Arguments: 10108c242ab0SSriharsha Basavapatna * pvid: pvid of the vnet device for which packets are being received 10118c242ab0SSriharsha Basavapatna * mp: head of pkt chain to be validated and untagged 10128c242ab0SSriharsha Basavapatna * 10138c242ab0SSriharsha Basavapatna * Returns: 10148c242ab0SSriharsha Basavapatna * mp: head of updated chain of packets 10158c242ab0SSriharsha Basavapatna */ 10168c242ab0SSriharsha Basavapatna static void 10178c242ab0SSriharsha Basavapatna vnet_rx_frames_untag(uint16_t pvid, mblk_t **mp) 10188c242ab0SSriharsha Basavapatna { 10198c242ab0SSriharsha Basavapatna struct ether_vlan_header *evhp; 10208c242ab0SSriharsha Basavapatna mblk_t *bp; 10218c242ab0SSriharsha Basavapatna mblk_t *bpt; 10228c242ab0SSriharsha Basavapatna mblk_t *bph; 10238c242ab0SSriharsha Basavapatna mblk_t *bpn; 10248c242ab0SSriharsha Basavapatna 10258c242ab0SSriharsha Basavapatna bpn = bph = bpt = NULL; 10268c242ab0SSriharsha Basavapatna 10278c242ab0SSriharsha Basavapatna for (bp = *mp; bp != NULL; bp = bpn) { 10288c242ab0SSriharsha Basavapatna 10298c242ab0SSriharsha Basavapatna bpn = bp->b_next; 10308c242ab0SSriharsha Basavapatna bp->b_next = bp->b_prev = NULL; 10318c242ab0SSriharsha Basavapatna 10328c242ab0SSriharsha Basavapatna evhp = (struct ether_vlan_header *)bp->b_rptr; 10338c242ab0SSriharsha Basavapatna 10348c242ab0SSriharsha Basavapatna if (ntohs(evhp->ether_tpid) == ETHERTYPE_VLAN && 10358c242ab0SSriharsha Basavapatna VLAN_ID(ntohs(evhp->ether_tci)) == pvid) { 10368c242ab0SSriharsha Basavapatna 10378c242ab0SSriharsha Basavapatna bp = vnet_vlan_remove_tag(bp); 10388c242ab0SSriharsha Basavapatna if (bp == NULL) { 10398c242ab0SSriharsha Basavapatna continue; 10408c242ab0SSriharsha Basavapatna } 10418c242ab0SSriharsha Basavapatna 10428c242ab0SSriharsha Basavapatna } 10438c242ab0SSriharsha Basavapatna 10448c242ab0SSriharsha Basavapatna /* build a chain of processed packets */ 10458c242ab0SSriharsha Basavapatna if (bph == NULL) { 10468c242ab0SSriharsha Basavapatna bph = bpt = bp; 10478c242ab0SSriharsha Basavapatna } else { 10488c242ab0SSriharsha Basavapatna bpt->b_next = bp; 10498c242ab0SSriharsha Basavapatna bpt = bp; 10508c242ab0SSriharsha Basavapatna } 10518c242ab0SSriharsha Basavapatna 10528c242ab0SSriharsha Basavapatna } 10538c242ab0SSriharsha Basavapatna 10548c242ab0SSriharsha Basavapatna *mp = bph; 10558c242ab0SSriharsha Basavapatna } 10568c242ab0SSriharsha Basavapatna 1057678453a8Sspeer static void 1058678453a8Sspeer vnet_rx(vio_net_handle_t vrh, mblk_t *mp) 1059678453a8Sspeer { 1060678453a8Sspeer vnet_res_t *vresp = (vnet_res_t *)vrh; 1061678453a8Sspeer vnet_t *vnetp = vresp->vnetp; 1062678453a8Sspeer 10638c242ab0SSriharsha Basavapatna if ((vnetp == NULL) || (vnetp->mh == 0)) { 1064678453a8Sspeer freemsgchain(mp); 10658c242ab0SSriharsha Basavapatna return; 1066678453a8Sspeer } 10678c242ab0SSriharsha Basavapatna 10688c242ab0SSriharsha Basavapatna /* 10698c242ab0SSriharsha Basavapatna * Packets received over a hybrid resource need additional processing 10708c242ab0SSriharsha Basavapatna * to remove the tag, for the pvid case. The underlying resource is 10718c242ab0SSriharsha Basavapatna * not aware of the vnet's pvid and thus packets are received with the 10728c242ab0SSriharsha Basavapatna * vlan tag in the header; unlike packets that are received over a ldc 10738c242ab0SSriharsha Basavapatna * channel in which case the peer vnet/vsw would have already removed 10748c242ab0SSriharsha Basavapatna * the tag. 10758c242ab0SSriharsha Basavapatna */ 10768c242ab0SSriharsha Basavapatna if (vresp->type == VIO_NET_RES_HYBRID && 10778c242ab0SSriharsha Basavapatna vnetp->pvid != vnetp->default_vlan_id) { 10788c242ab0SSriharsha Basavapatna 10798c242ab0SSriharsha Basavapatna vnet_rx_frames_untag(vnetp->pvid, &mp); 10808c242ab0SSriharsha Basavapatna if (mp == NULL) { 10818c242ab0SSriharsha Basavapatna return; 10828c242ab0SSriharsha Basavapatna } 10838c242ab0SSriharsha Basavapatna } 10848c242ab0SSriharsha Basavapatna 10858c242ab0SSriharsha Basavapatna mac_rx(vnetp->mh, NULL, mp); 10861ae08745Sheppo } 1087ba2e4443Sseb 1088ba2e4443Sseb void 1089678453a8Sspeer vnet_tx_update(vio_net_handle_t vrh) 1090ba2e4443Sseb { 1091678453a8Sspeer vnet_res_t *vresp = (vnet_res_t *)vrh; 1092678453a8Sspeer vnet_t *vnetp = vresp->vnetp; 1093ba2e4443Sseb 1094678453a8Sspeer if ((vnetp != NULL) && (vnetp->mh != NULL)) { 1095ba2e4443Sseb mac_tx_update(vnetp->mh); 1096ba2e4443Sseb } 1097678453a8Sspeer } 1098678453a8Sspeer 1099678453a8Sspeer /* 11007b1f684aSSriharsha Basavapatna * Update the new mtu of vnet into the mac layer. First check if the device has 11017b1f684aSSriharsha Basavapatna * been plumbed and if so fail the mtu update. Returns 0 on success. 11027b1f684aSSriharsha Basavapatna */ 11037b1f684aSSriharsha Basavapatna int 11047b1f684aSSriharsha Basavapatna vnet_mtu_update(vnet_t *vnetp, uint32_t mtu) 11057b1f684aSSriharsha Basavapatna { 11067b1f684aSSriharsha Basavapatna int rv; 11077b1f684aSSriharsha Basavapatna 11087b1f684aSSriharsha Basavapatna if (vnetp == NULL || vnetp->mh == NULL) { 11097b1f684aSSriharsha Basavapatna return (EINVAL); 11107b1f684aSSriharsha Basavapatna } 11117b1f684aSSriharsha Basavapatna 11127b1f684aSSriharsha Basavapatna WRITE_ENTER(&vnetp->vrwlock); 11137b1f684aSSriharsha Basavapatna 11147b1f684aSSriharsha Basavapatna if (vnetp->flags & VNET_STARTED) { 11157b1f684aSSriharsha Basavapatna RW_EXIT(&vnetp->vrwlock); 11167b1f684aSSriharsha Basavapatna cmn_err(CE_NOTE, "!vnet%d: Unable to process mtu " 11177b1f684aSSriharsha Basavapatna "update as the device is plumbed\n", 11187b1f684aSSriharsha Basavapatna vnetp->instance); 11197b1f684aSSriharsha Basavapatna return (EBUSY); 11207b1f684aSSriharsha Basavapatna } 11217b1f684aSSriharsha Basavapatna 11227b1f684aSSriharsha Basavapatna /* update mtu in the mac layer */ 11237b1f684aSSriharsha Basavapatna rv = mac_maxsdu_update(vnetp->mh, mtu); 11247b1f684aSSriharsha Basavapatna if (rv != 0) { 11257b1f684aSSriharsha Basavapatna RW_EXIT(&vnetp->vrwlock); 11267b1f684aSSriharsha Basavapatna cmn_err(CE_NOTE, 11277b1f684aSSriharsha Basavapatna "!vnet%d: Unable to update mtu with mac layer\n", 11287b1f684aSSriharsha Basavapatna vnetp->instance); 11297b1f684aSSriharsha Basavapatna return (EIO); 11307b1f684aSSriharsha Basavapatna } 11317b1f684aSSriharsha Basavapatna 11327b1f684aSSriharsha Basavapatna vnetp->mtu = mtu; 11337b1f684aSSriharsha Basavapatna 11347b1f684aSSriharsha Basavapatna RW_EXIT(&vnetp->vrwlock); 11357b1f684aSSriharsha Basavapatna 11367b1f684aSSriharsha Basavapatna return (0); 11377b1f684aSSriharsha Basavapatna } 11387b1f684aSSriharsha Basavapatna 11397b1f684aSSriharsha Basavapatna /* 1140678453a8Sspeer * vio_net_resource_reg -- An interface called to register a resource 1141678453a8Sspeer * with vnet. 1142678453a8Sspeer * macp -- a GLDv3 mac_register that has all the details of 1143678453a8Sspeer * a resource and its callbacks etc. 1144678453a8Sspeer * type -- resource type. 1145678453a8Sspeer * local_macaddr -- resource's MAC address. This is used to 1146678453a8Sspeer * associate a resource with a corresponding vnet. 1147678453a8Sspeer * remote_macaddr -- remote side MAC address. This is ignored for 1148678453a8Sspeer * the Hybrid resources. 1149678453a8Sspeer * vhp -- A handle returned to the caller. 1150678453a8Sspeer * vcb -- A set of callbacks provided to the callers. 1151678453a8Sspeer */ 1152678453a8Sspeer int vio_net_resource_reg(mac_register_t *macp, vio_net_res_type_t type, 1153678453a8Sspeer ether_addr_t local_macaddr, ether_addr_t rem_macaddr, vio_net_handle_t *vhp, 1154678453a8Sspeer vio_net_callbacks_t *vcb) 1155678453a8Sspeer { 1156678453a8Sspeer vnet_t *vnetp; 1157678453a8Sspeer vnet_res_t *vresp; 1158678453a8Sspeer 1159678453a8Sspeer vresp = kmem_zalloc(sizeof (vnet_res_t), KM_SLEEP); 1160678453a8Sspeer ether_copy(local_macaddr, vresp->local_macaddr); 1161678453a8Sspeer ether_copy(rem_macaddr, vresp->rem_macaddr); 1162678453a8Sspeer vresp->type = type; 1163678453a8Sspeer bcopy(macp, &vresp->macreg, sizeof (mac_register_t)); 1164678453a8Sspeer 1165678453a8Sspeer DBG1(NULL, "Resource Registerig type=0%X\n", type); 1166678453a8Sspeer 1167678453a8Sspeer READ_ENTER(&vnet_rw); 1168678453a8Sspeer vnetp = vnet_headp; 1169678453a8Sspeer while (vnetp != NULL) { 1170678453a8Sspeer if (VNET_MATCH_RES(vresp, vnetp)) { 1171678453a8Sspeer vresp->vnetp = vnetp; 1172*6b8fc343SWENTAO YANG 1173*6b8fc343SWENTAO YANG /* Setup kstats for hio resource */ 1174*6b8fc343SWENTAO YANG if (vresp->type == VIO_NET_RES_HYBRID) { 1175*6b8fc343SWENTAO YANG vresp->ksp = vnet_hio_setup_kstats(DRV_NAME, 1176*6b8fc343SWENTAO YANG "hio", vresp); 1177*6b8fc343SWENTAO YANG if (vresp->ksp == NULL) { 1178*6b8fc343SWENTAO YANG cmn_err(CE_NOTE, "!vnet%d: Cannot " 1179*6b8fc343SWENTAO YANG "create kstats for hio resource", 1180*6b8fc343SWENTAO YANG vnetp->instance); 1181*6b8fc343SWENTAO YANG } 1182*6b8fc343SWENTAO YANG } 1183*6b8fc343SWENTAO YANG 1184*6b8fc343SWENTAO YANG WRITE_ENTER(&vnetp->vrwlock); 1185678453a8Sspeer vresp->nextp = vnetp->vres_list; 1186678453a8Sspeer vnetp->vres_list = vresp; 1187678453a8Sspeer RW_EXIT(&vnetp->vrwlock); 1188678453a8Sspeer break; 1189678453a8Sspeer } 1190678453a8Sspeer vnetp = vnetp->nextp; 1191678453a8Sspeer } 1192678453a8Sspeer RW_EXIT(&vnet_rw); 1193678453a8Sspeer if (vresp->vnetp == NULL) { 1194678453a8Sspeer DWARN(NULL, "No vnet instance"); 1195678453a8Sspeer kmem_free(vresp, sizeof (vnet_res_t)); 1196678453a8Sspeer return (ENXIO); 1197678453a8Sspeer } 1198678453a8Sspeer 1199678453a8Sspeer *vhp = vresp; 1200678453a8Sspeer vcb->vio_net_rx_cb = vnet_rx; 1201678453a8Sspeer vcb->vio_net_tx_update = vnet_tx_update; 1202678453a8Sspeer vcb->vio_net_report_err = vnet_handle_res_err; 1203678453a8Sspeer 1204678453a8Sspeer /* Dispatch a task to start resources */ 1205678453a8Sspeer vnet_dispatch_res_task(vnetp); 1206678453a8Sspeer return (0); 1207678453a8Sspeer } 1208678453a8Sspeer 1209678453a8Sspeer /* 1210678453a8Sspeer * vio_net_resource_unreg -- An interface to unregister a resource. 1211678453a8Sspeer */ 1212678453a8Sspeer void 1213678453a8Sspeer vio_net_resource_unreg(vio_net_handle_t vhp) 1214678453a8Sspeer { 1215678453a8Sspeer vnet_res_t *vresp = (vnet_res_t *)vhp; 1216678453a8Sspeer vnet_t *vnetp = vresp->vnetp; 1217678453a8Sspeer vnet_res_t *vrp; 12186ab6cb20SWENTAO YANG kstat_t *ksp = NULL; 1219678453a8Sspeer 1220678453a8Sspeer DBG1(NULL, "Resource Registerig hdl=0x%p", vhp); 1221678453a8Sspeer 1222678453a8Sspeer ASSERT(vnetp != NULL); 1223678453a8Sspeer vnet_fdbe_del(vnetp, vresp); 1224678453a8Sspeer 1225678453a8Sspeer WRITE_ENTER(&vnetp->vrwlock); 1226678453a8Sspeer if (vresp == vnetp->vres_list) { 1227678453a8Sspeer vnetp->vres_list = vresp->nextp; 1228678453a8Sspeer } else { 1229678453a8Sspeer vrp = vnetp->vres_list; 1230678453a8Sspeer while (vrp->nextp != NULL) { 1231678453a8Sspeer if (vrp->nextp == vresp) { 1232678453a8Sspeer vrp->nextp = vresp->nextp; 1233678453a8Sspeer break; 1234678453a8Sspeer } 1235678453a8Sspeer vrp = vrp->nextp; 1236678453a8Sspeer } 1237678453a8Sspeer } 12386ab6cb20SWENTAO YANG 12396ab6cb20SWENTAO YANG ksp = vresp->ksp; 12406ab6cb20SWENTAO YANG vresp->ksp = NULL; 12416ab6cb20SWENTAO YANG 1242678453a8Sspeer vresp->vnetp = NULL; 1243678453a8Sspeer vresp->nextp = NULL; 1244678453a8Sspeer RW_EXIT(&vnetp->vrwlock); 12456ab6cb20SWENTAO YANG vnet_hio_destroy_kstats(ksp); 1246678453a8Sspeer KMEM_FREE(vresp); 1247678453a8Sspeer } 1248678453a8Sspeer 1249678453a8Sspeer /* 1250678453a8Sspeer * vnet_dds_rx -- an interface called by vgen to DDS messages. 1251678453a8Sspeer */ 1252678453a8Sspeer void 1253678453a8Sspeer vnet_dds_rx(void *arg, void *dmsg) 1254678453a8Sspeer { 1255678453a8Sspeer vnet_t *vnetp = arg; 1256678453a8Sspeer vdds_process_dds_msg(vnetp, dmsg); 1257678453a8Sspeer } 1258678453a8Sspeer 1259678453a8Sspeer /* 1260678453a8Sspeer * vnet_send_dds_msg -- An interface provided to DDS to send 1261678453a8Sspeer * DDS messages. This simply sends meessages via vgen. 1262678453a8Sspeer */ 1263678453a8Sspeer int 1264678453a8Sspeer vnet_send_dds_msg(vnet_t *vnetp, void *dmsg) 1265678453a8Sspeer { 1266678453a8Sspeer int rv; 1267678453a8Sspeer 1268678453a8Sspeer if (vnetp->vgenhdl != NULL) { 1269678453a8Sspeer rv = vgen_dds_tx(vnetp->vgenhdl, dmsg); 1270678453a8Sspeer } 1271678453a8Sspeer return (rv); 1272678453a8Sspeer } 1273678453a8Sspeer 1274678453a8Sspeer /* 1275678453a8Sspeer * vnet_handle_res_err -- A callback function called by a resource 1276678453a8Sspeer * to report an error. For example, vgen can call to report 1277678453a8Sspeer * an LDC down/reset event. This will trigger cleanup of associated 1278678453a8Sspeer * Hybrid resource. 1279678453a8Sspeer */ 1280678453a8Sspeer /* ARGSUSED */ 1281678453a8Sspeer static void 1282678453a8Sspeer vnet_handle_res_err(vio_net_handle_t vrh, vio_net_err_val_t err) 1283678453a8Sspeer { 1284678453a8Sspeer vnet_res_t *vresp = (vnet_res_t *)vrh; 1285678453a8Sspeer vnet_t *vnetp = vresp->vnetp; 1286d0288fccSRaghuram Kothakota int rv; 1287678453a8Sspeer 1288678453a8Sspeer if (vnetp == NULL) { 1289678453a8Sspeer return; 1290678453a8Sspeer } 1291678453a8Sspeer if ((vresp->type != VIO_NET_RES_LDC_SERVICE) && 1292678453a8Sspeer (vresp->type != VIO_NET_RES_HYBRID)) { 1293678453a8Sspeer return; 1294678453a8Sspeer } 1295d0288fccSRaghuram Kothakota rv = ddi_taskq_dispatch(vnetp->taskqp, vdds_cleanup_hybrid_res, 1296d0288fccSRaghuram Kothakota vnetp, DDI_NOSLEEP); 1297d0288fccSRaghuram Kothakota if (rv != DDI_SUCCESS) { 1298d0288fccSRaghuram Kothakota cmn_err(CE_WARN, 1299d0288fccSRaghuram Kothakota "vnet%d:Failed to dispatch task to cleanup hybrid resource", 1300d0288fccSRaghuram Kothakota vnetp->instance); 1301d0288fccSRaghuram Kothakota } 1302678453a8Sspeer } 1303678453a8Sspeer 1304678453a8Sspeer /* 1305678453a8Sspeer * vnet_dispatch_res_task -- A function to dispatch tasks start resources. 1306678453a8Sspeer */ 1307678453a8Sspeer static void 1308678453a8Sspeer vnet_dispatch_res_task(vnet_t *vnetp) 1309678453a8Sspeer { 1310678453a8Sspeer int rv; 1311678453a8Sspeer 1312678453a8Sspeer WRITE_ENTER(&vnetp->vrwlock); 1313678453a8Sspeer if (vnetp->flags & VNET_STARTED) { 1314678453a8Sspeer rv = ddi_taskq_dispatch(vnetp->taskqp, vnet_res_start_task, 1315678453a8Sspeer vnetp, DDI_NOSLEEP); 1316678453a8Sspeer if (rv != DDI_SUCCESS) { 1317678453a8Sspeer cmn_err(CE_WARN, 1318678453a8Sspeer "vnet%d:Can't dispatch start resource task", 1319678453a8Sspeer vnetp->instance); 1320678453a8Sspeer } 1321678453a8Sspeer } 1322678453a8Sspeer RW_EXIT(&vnetp->vrwlock); 1323678453a8Sspeer } 1324678453a8Sspeer 1325678453a8Sspeer /* 1326678453a8Sspeer * vnet_res_start_task -- A taskq callback function that starts a resource. 1327678453a8Sspeer */ 1328678453a8Sspeer static void 1329678453a8Sspeer vnet_res_start_task(void *arg) 1330678453a8Sspeer { 1331678453a8Sspeer vnet_t *vnetp = arg; 1332678453a8Sspeer 1333678453a8Sspeer WRITE_ENTER(&vnetp->vrwlock); 1334678453a8Sspeer if (vnetp->flags & VNET_STARTED) { 1335678453a8Sspeer vnet_start_resources(vnetp); 1336678453a8Sspeer } 1337678453a8Sspeer RW_EXIT(&vnetp->vrwlock); 1338678453a8Sspeer } 1339678453a8Sspeer 1340678453a8Sspeer /* 1341678453a8Sspeer * vnet_start_resources -- starts all resources associated with 1342678453a8Sspeer * a vnet. 1343678453a8Sspeer */ 1344678453a8Sspeer static void 1345678453a8Sspeer vnet_start_resources(vnet_t *vnetp) 1346678453a8Sspeer { 1347678453a8Sspeer mac_register_t *macp; 1348678453a8Sspeer mac_callbacks_t *cbp; 1349678453a8Sspeer vnet_res_t *vresp; 1350678453a8Sspeer int rv; 1351678453a8Sspeer 1352678453a8Sspeer DBG1(vnetp, "enter\n"); 1353678453a8Sspeer 1354678453a8Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 1355678453a8Sspeer /* skip if it is already started */ 1356678453a8Sspeer if (vresp->flags & VNET_STARTED) { 1357678453a8Sspeer continue; 1358678453a8Sspeer } 1359678453a8Sspeer macp = &vresp->macreg; 1360678453a8Sspeer cbp = macp->m_callbacks; 1361678453a8Sspeer rv = cbp->mc_start(macp->m_driver); 1362678453a8Sspeer if (rv == 0) { 1363678453a8Sspeer /* 1364678453a8Sspeer * Successfully started the resource, so now 1365678453a8Sspeer * add it to the fdb. 1366678453a8Sspeer */ 1367678453a8Sspeer vresp->flags |= VNET_STARTED; 1368678453a8Sspeer vnet_fdbe_add(vnetp, vresp); 1369678453a8Sspeer } 1370678453a8Sspeer } 1371678453a8Sspeer 1372678453a8Sspeer DBG1(vnetp, "exit\n"); 1373678453a8Sspeer 1374678453a8Sspeer } 1375678453a8Sspeer 1376678453a8Sspeer /* 1377678453a8Sspeer * vnet_stop_resources -- stop all resources associated with a vnet. 1378678453a8Sspeer */ 1379678453a8Sspeer static void 1380678453a8Sspeer vnet_stop_resources(vnet_t *vnetp) 1381678453a8Sspeer { 1382678453a8Sspeer vnet_res_t *vresp; 1383678453a8Sspeer vnet_res_t *nvresp; 1384678453a8Sspeer mac_register_t *macp; 1385678453a8Sspeer mac_callbacks_t *cbp; 1386678453a8Sspeer 1387678453a8Sspeer DBG1(vnetp, "enter\n"); 1388678453a8Sspeer 1389678453a8Sspeer for (vresp = vnetp->vres_list; vresp != NULL; ) { 1390678453a8Sspeer nvresp = vresp->nextp; 1391678453a8Sspeer if (vresp->flags & VNET_STARTED) { 1392678453a8Sspeer macp = &vresp->macreg; 1393678453a8Sspeer cbp = macp->m_callbacks; 1394678453a8Sspeer cbp->mc_stop(macp->m_driver); 1395678453a8Sspeer vresp->flags &= ~VNET_STARTED; 1396678453a8Sspeer } 1397678453a8Sspeer vresp = nvresp; 1398678453a8Sspeer } 1399678453a8Sspeer DBG1(vnetp, "exit\n"); 1400678453a8Sspeer } 14016ab6cb20SWENTAO YANG 14026ab6cb20SWENTAO YANG /* 14036ab6cb20SWENTAO YANG * Setup kstats for the HIO statistics. 14046ab6cb20SWENTAO YANG * NOTE: the synchronization for the statistics is the 14056ab6cb20SWENTAO YANG * responsibility of the caller. 14066ab6cb20SWENTAO YANG */ 14076ab6cb20SWENTAO YANG kstat_t * 14086ab6cb20SWENTAO YANG vnet_hio_setup_kstats(char *ks_mod, char *ks_name, vnet_res_t *vresp) 14096ab6cb20SWENTAO YANG { 14106ab6cb20SWENTAO YANG kstat_t *ksp; 14116ab6cb20SWENTAO YANG vnet_t *vnetp = vresp->vnetp; 14126ab6cb20SWENTAO YANG vnet_hio_kstats_t *hiokp; 14136ab6cb20SWENTAO YANG size_t size; 14146ab6cb20SWENTAO YANG 14156ab6cb20SWENTAO YANG ASSERT(vnetp != NULL); 14166ab6cb20SWENTAO YANG size = sizeof (vnet_hio_kstats_t) / sizeof (kstat_named_t); 14176ab6cb20SWENTAO YANG ksp = kstat_create(ks_mod, vnetp->instance, ks_name, "net", 14186ab6cb20SWENTAO YANG KSTAT_TYPE_NAMED, size, 0); 14196ab6cb20SWENTAO YANG if (ksp == NULL) { 14206ab6cb20SWENTAO YANG return (NULL); 14216ab6cb20SWENTAO YANG } 14226ab6cb20SWENTAO YANG 14236ab6cb20SWENTAO YANG hiokp = (vnet_hio_kstats_t *)ksp->ks_data; 14246ab6cb20SWENTAO YANG kstat_named_init(&hiokp->ipackets, "ipackets", 14256ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 14266ab6cb20SWENTAO YANG kstat_named_init(&hiokp->ierrors, "ierrors", 14276ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 14286ab6cb20SWENTAO YANG kstat_named_init(&hiokp->opackets, "opackets", 14296ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 14306ab6cb20SWENTAO YANG kstat_named_init(&hiokp->oerrors, "oerrors", 14316ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 14326ab6cb20SWENTAO YANG 14336ab6cb20SWENTAO YANG 14346ab6cb20SWENTAO YANG /* MIB II kstat variables */ 14356ab6cb20SWENTAO YANG kstat_named_init(&hiokp->rbytes, "rbytes", 14366ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 14376ab6cb20SWENTAO YANG kstat_named_init(&hiokp->obytes, "obytes", 14386ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 14396ab6cb20SWENTAO YANG kstat_named_init(&hiokp->multircv, "multircv", 14406ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 14416ab6cb20SWENTAO YANG kstat_named_init(&hiokp->multixmt, "multixmt", 14426ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 14436ab6cb20SWENTAO YANG kstat_named_init(&hiokp->brdcstrcv, "brdcstrcv", 14446ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 14456ab6cb20SWENTAO YANG kstat_named_init(&hiokp->brdcstxmt, "brdcstxmt", 14466ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 14476ab6cb20SWENTAO YANG kstat_named_init(&hiokp->norcvbuf, "norcvbuf", 14486ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 14496ab6cb20SWENTAO YANG kstat_named_init(&hiokp->noxmtbuf, "noxmtbuf", 14506ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 14516ab6cb20SWENTAO YANG 14526ab6cb20SWENTAO YANG ksp->ks_update = vnet_hio_update_kstats; 14536ab6cb20SWENTAO YANG ksp->ks_private = (void *)vresp; 14546ab6cb20SWENTAO YANG kstat_install(ksp); 14556ab6cb20SWENTAO YANG return (ksp); 14566ab6cb20SWENTAO YANG } 14576ab6cb20SWENTAO YANG 14586ab6cb20SWENTAO YANG /* 14596ab6cb20SWENTAO YANG * Destroy kstats. 14606ab6cb20SWENTAO YANG */ 14616ab6cb20SWENTAO YANG static void 14626ab6cb20SWENTAO YANG vnet_hio_destroy_kstats(kstat_t *ksp) 14636ab6cb20SWENTAO YANG { 14646ab6cb20SWENTAO YANG if (ksp != NULL) 14656ab6cb20SWENTAO YANG kstat_delete(ksp); 14666ab6cb20SWENTAO YANG } 14676ab6cb20SWENTAO YANG 14686ab6cb20SWENTAO YANG /* 14696ab6cb20SWENTAO YANG * Update the kstats. 14706ab6cb20SWENTAO YANG */ 14716ab6cb20SWENTAO YANG static int 14726ab6cb20SWENTAO YANG vnet_hio_update_kstats(kstat_t *ksp, int rw) 14736ab6cb20SWENTAO YANG { 14746ab6cb20SWENTAO YANG vnet_t *vnetp; 14756ab6cb20SWENTAO YANG vnet_res_t *vresp; 14766ab6cb20SWENTAO YANG vnet_hio_stats_t statsp; 14776ab6cb20SWENTAO YANG vnet_hio_kstats_t *hiokp; 14786ab6cb20SWENTAO YANG 14796ab6cb20SWENTAO YANG vresp = (vnet_res_t *)ksp->ks_private; 14806ab6cb20SWENTAO YANG vnetp = vresp->vnetp; 14816ab6cb20SWENTAO YANG 14826ab6cb20SWENTAO YANG bzero(&statsp, sizeof (vnet_hio_stats_t)); 14836ab6cb20SWENTAO YANG 14846ab6cb20SWENTAO YANG READ_ENTER(&vnetp->vsw_fp_rw); 14856ab6cb20SWENTAO YANG if (vnetp->hio_fp == NULL) { 14866ab6cb20SWENTAO YANG /* not using hio resources, just return */ 14876ab6cb20SWENTAO YANG RW_EXIT(&vnetp->vsw_fp_rw); 14886ab6cb20SWENTAO YANG return (0); 14896ab6cb20SWENTAO YANG } 14906ab6cb20SWENTAO YANG VNET_FDBE_REFHOLD(vnetp->hio_fp); 14916ab6cb20SWENTAO YANG RW_EXIT(&vnetp->vsw_fp_rw); 14926ab6cb20SWENTAO YANG vnet_hio_get_stats(vnetp->hio_fp, &statsp); 14936ab6cb20SWENTAO YANG VNET_FDBE_REFRELE(vnetp->hio_fp); 14946ab6cb20SWENTAO YANG 14956ab6cb20SWENTAO YANG hiokp = (vnet_hio_kstats_t *)ksp->ks_data; 14966ab6cb20SWENTAO YANG 14976ab6cb20SWENTAO YANG if (rw == KSTAT_READ) { 14986ab6cb20SWENTAO YANG /* Link Input/Output stats */ 14996ab6cb20SWENTAO YANG hiokp->ipackets.value.ul = (uint32_t)statsp.ipackets; 15006ab6cb20SWENTAO YANG hiokp->ipackets64.value.ull = statsp.ipackets; 15016ab6cb20SWENTAO YANG hiokp->ierrors.value.ul = statsp.ierrors; 15026ab6cb20SWENTAO YANG hiokp->opackets.value.ul = (uint32_t)statsp.opackets; 15036ab6cb20SWENTAO YANG hiokp->opackets64.value.ull = statsp.opackets; 15046ab6cb20SWENTAO YANG hiokp->oerrors.value.ul = statsp.oerrors; 15056ab6cb20SWENTAO YANG 15066ab6cb20SWENTAO YANG /* MIB II kstat variables */ 15076ab6cb20SWENTAO YANG hiokp->rbytes.value.ul = (uint32_t)statsp.rbytes; 15086ab6cb20SWENTAO YANG hiokp->rbytes64.value.ull = statsp.rbytes; 15096ab6cb20SWENTAO YANG hiokp->obytes.value.ul = (uint32_t)statsp.obytes; 15106ab6cb20SWENTAO YANG hiokp->obytes64.value.ull = statsp.obytes; 15116ab6cb20SWENTAO YANG hiokp->multircv.value.ul = statsp.multircv; 15126ab6cb20SWENTAO YANG hiokp->multixmt.value.ul = statsp.multixmt; 15136ab6cb20SWENTAO YANG hiokp->brdcstrcv.value.ul = statsp.brdcstrcv; 15146ab6cb20SWENTAO YANG hiokp->brdcstxmt.value.ul = statsp.brdcstxmt; 15156ab6cb20SWENTAO YANG hiokp->norcvbuf.value.ul = statsp.norcvbuf; 15166ab6cb20SWENTAO YANG hiokp->noxmtbuf.value.ul = statsp.noxmtbuf; 15176ab6cb20SWENTAO YANG } else { 15186ab6cb20SWENTAO YANG return (EACCES); 15196ab6cb20SWENTAO YANG } 15206ab6cb20SWENTAO YANG 15216ab6cb20SWENTAO YANG return (0); 15226ab6cb20SWENTAO YANG } 15236ab6cb20SWENTAO YANG 15246ab6cb20SWENTAO YANG static void 15256ab6cb20SWENTAO YANG vnet_hio_get_stats(vnet_res_t *vresp, vnet_hio_stats_t *statsp) 15266ab6cb20SWENTAO YANG { 15276ab6cb20SWENTAO YANG mac_register_t *macp; 15286ab6cb20SWENTAO YANG mac_callbacks_t *cbp; 15296ab6cb20SWENTAO YANG uint64_t val; 15306ab6cb20SWENTAO YANG int stat; 15316ab6cb20SWENTAO YANG 15326ab6cb20SWENTAO YANG /* 15336ab6cb20SWENTAO YANG * get the specified statistics from the underlying nxge. 15346ab6cb20SWENTAO YANG */ 15356ab6cb20SWENTAO YANG macp = &vresp->macreg; 15366ab6cb20SWENTAO YANG cbp = macp->m_callbacks; 15376ab6cb20SWENTAO YANG for (stat = MAC_STAT_MIN; stat < MAC_STAT_OVERFLOWS; stat++) { 15386ab6cb20SWENTAO YANG if (cbp->mc_getstat(macp->m_driver, stat, &val) == 0) { 15396ab6cb20SWENTAO YANG switch (stat) { 15406ab6cb20SWENTAO YANG case MAC_STAT_IPACKETS: 15416ab6cb20SWENTAO YANG statsp->ipackets = val; 15426ab6cb20SWENTAO YANG break; 15436ab6cb20SWENTAO YANG 15446ab6cb20SWENTAO YANG case MAC_STAT_IERRORS: 15456ab6cb20SWENTAO YANG statsp->ierrors = val; 15466ab6cb20SWENTAO YANG break; 15476ab6cb20SWENTAO YANG 15486ab6cb20SWENTAO YANG case MAC_STAT_OPACKETS: 15496ab6cb20SWENTAO YANG statsp->opackets = val; 15506ab6cb20SWENTAO YANG break; 15516ab6cb20SWENTAO YANG 15526ab6cb20SWENTAO YANG case MAC_STAT_OERRORS: 15536ab6cb20SWENTAO YANG statsp->oerrors = val; 15546ab6cb20SWENTAO YANG break; 15556ab6cb20SWENTAO YANG 15566ab6cb20SWENTAO YANG case MAC_STAT_RBYTES: 15576ab6cb20SWENTAO YANG statsp->rbytes = val; 15586ab6cb20SWENTAO YANG break; 15596ab6cb20SWENTAO YANG 15606ab6cb20SWENTAO YANG case MAC_STAT_OBYTES: 15616ab6cb20SWENTAO YANG statsp->obytes = val; 15626ab6cb20SWENTAO YANG break; 15636ab6cb20SWENTAO YANG 15646ab6cb20SWENTAO YANG case MAC_STAT_MULTIRCV: 15656ab6cb20SWENTAO YANG statsp->multircv = val; 15666ab6cb20SWENTAO YANG break; 15676ab6cb20SWENTAO YANG 15686ab6cb20SWENTAO YANG case MAC_STAT_MULTIXMT: 15696ab6cb20SWENTAO YANG statsp->multixmt = val; 15706ab6cb20SWENTAO YANG break; 15716ab6cb20SWENTAO YANG 15726ab6cb20SWENTAO YANG case MAC_STAT_BRDCSTRCV: 15736ab6cb20SWENTAO YANG statsp->brdcstrcv = val; 15746ab6cb20SWENTAO YANG break; 15756ab6cb20SWENTAO YANG 15766ab6cb20SWENTAO YANG case MAC_STAT_BRDCSTXMT: 15776ab6cb20SWENTAO YANG statsp->brdcstxmt = val; 15786ab6cb20SWENTAO YANG break; 15796ab6cb20SWENTAO YANG 15806ab6cb20SWENTAO YANG case MAC_STAT_NOXMTBUF: 15816ab6cb20SWENTAO YANG statsp->noxmtbuf = val; 15826ab6cb20SWENTAO YANG break; 15836ab6cb20SWENTAO YANG 15846ab6cb20SWENTAO YANG case MAC_STAT_NORCVBUF: 15856ab6cb20SWENTAO YANG statsp->norcvbuf = val; 15866ab6cb20SWENTAO YANG break; 15876ab6cb20SWENTAO YANG 15886ab6cb20SWENTAO YANG default: 15896ab6cb20SWENTAO YANG /* 15906ab6cb20SWENTAO YANG * parameters not interested. 15916ab6cb20SWENTAO YANG */ 15926ab6cb20SWENTAO YANG break; 15936ab6cb20SWENTAO YANG } 15946ab6cb20SWENTAO YANG } 15956ab6cb20SWENTAO YANG } 15966ab6cb20SWENTAO YANG } 1597