11ae08745Sheppo /* 21ae08745Sheppo * CDDL HEADER START 31ae08745Sheppo * 41ae08745Sheppo * The contents of this file are subject to the terms of the 51ae08745Sheppo * Common Development and Distribution License (the "License"). 61ae08745Sheppo * You may not use this file except in compliance with the License. 71ae08745Sheppo * 81ae08745Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91ae08745Sheppo * or http://www.opensolaris.org/os/licensing. 101ae08745Sheppo * See the License for the specific language governing permissions 111ae08745Sheppo * and limitations under the License. 121ae08745Sheppo * 131ae08745Sheppo * When distributing Covered Code, include this CDDL HEADER in each 141ae08745Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151ae08745Sheppo * If applicable, add the following below this CDDL HEADER, with the 161ae08745Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 171ae08745Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 181ae08745Sheppo * 191ae08745Sheppo * CDDL HEADER END 201ae08745Sheppo */ 211ae08745Sheppo 221ae08745Sheppo /* 23*6f09f0feSWENTAO YANG * Copyright 2009 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 */ 76*6f09f0feSWENTAO YANG static int vnet_unattach(vnet_t *vnetp); 771ae08745Sheppo static int vnet_mac_register(vnet_t *); 781ae08745Sheppo static int vnet_read_mac_address(vnet_t *vnetp); 791ae08745Sheppo 80c1c61f44Ssb155480 /* Forwarding database (FDB) routines */ 81c1c61f44Ssb155480 static void vnet_fdb_create(vnet_t *vnetp); 82c1c61f44Ssb155480 static void vnet_fdb_destroy(vnet_t *vnetp); 83678453a8Sspeer static vnet_res_t *vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp); 84c1c61f44Ssb155480 static void vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val); 85678453a8Sspeer void vnet_fdbe_add(vnet_t *vnetp, vnet_res_t *vresp); 86678453a8Sspeer static void vnet_fdbe_del(vnet_t *vnetp, vnet_res_t *vresp); 87c1c61f44Ssb155480 888c242ab0SSriharsha Basavapatna static void vnet_rx_frames_untag(uint16_t pvid, mblk_t **mp); 89678453a8Sspeer static void vnet_rx(vio_net_handle_t vrh, mblk_t *mp); 90678453a8Sspeer static void vnet_tx_update(vio_net_handle_t vrh); 91678453a8Sspeer static void vnet_res_start_task(void *arg); 92678453a8Sspeer static void vnet_start_resources(vnet_t *vnetp); 93678453a8Sspeer static void vnet_stop_resources(vnet_t *vnetp); 94678453a8Sspeer static void vnet_dispatch_res_task(vnet_t *vnetp); 95678453a8Sspeer static void vnet_res_start_task(void *arg); 96678453a8Sspeer static void vnet_handle_res_err(vio_net_handle_t vrh, vio_net_err_val_t err); 977b1f684aSSriharsha Basavapatna int vnet_mtu_update(vnet_t *vnetp, uint32_t mtu); 98678453a8Sspeer 996ab6cb20SWENTAO YANG static kstat_t *vnet_hio_setup_kstats(char *ks_mod, char *ks_name, 1006ab6cb20SWENTAO YANG vnet_res_t *vresp); 1016ab6cb20SWENTAO YANG static int vnet_hio_update_kstats(kstat_t *ksp, int rw); 1026ab6cb20SWENTAO YANG static void vnet_hio_get_stats(vnet_res_t *vresp, vnet_hio_stats_t *statsp); 1036ab6cb20SWENTAO YANG static void vnet_hio_destroy_kstats(kstat_t *ksp); 1046ab6cb20SWENTAO YANG 105678453a8Sspeer /* Exported to to vnet_dds */ 106678453a8Sspeer int vnet_send_dds_msg(vnet_t *vnetp, void *dmsg); 107678453a8Sspeer 108678453a8Sspeer /* Externs that are imported from vnet_gen */ 109678453a8Sspeer extern int vgen_init(void *vnetp, uint64_t regprop, dev_info_t *vnetdip, 110678453a8Sspeer const uint8_t *macaddr, void **vgenhdl); 111d10e4ef2Snarayan extern int vgen_uninit(void *arg); 112678453a8Sspeer extern int vgen_dds_tx(void *arg, void *dmsg); 113*6f09f0feSWENTAO YANG extern void vgen_mod_init(void); 114*6f09f0feSWENTAO YANG extern int vgen_mod_cleanup(void); 115*6f09f0feSWENTAO YANG extern void vgen_mod_fini(void); 116678453a8Sspeer 117678453a8Sspeer /* Externs that are imported from vnet_dds */ 118678453a8Sspeer extern void vdds_mod_init(void); 119678453a8Sspeer extern void vdds_mod_fini(void); 120678453a8Sspeer extern int vdds_init(vnet_t *vnetp); 121678453a8Sspeer extern void vdds_cleanup(vnet_t *vnetp); 122678453a8Sspeer extern void vdds_process_dds_msg(vnet_t *vnetp, vio_dds_msg_t *dmsg); 123d0288fccSRaghuram Kothakota extern void vdds_cleanup_hybrid_res(void *arg); 1241ae08745Sheppo 1256ab6cb20SWENTAO YANG #define DRV_NAME "vnet" 126c1c61f44Ssb155480 #define VNET_FDBE_REFHOLD(p) \ 127c1c61f44Ssb155480 { \ 128c1c61f44Ssb155480 atomic_inc_32(&(p)->refcnt); \ 129c1c61f44Ssb155480 ASSERT((p)->refcnt != 0); \ 130c1c61f44Ssb155480 } 131c1c61f44Ssb155480 132c1c61f44Ssb155480 #define VNET_FDBE_REFRELE(p) \ 133c1c61f44Ssb155480 { \ 134c1c61f44Ssb155480 ASSERT((p)->refcnt != 0); \ 135c1c61f44Ssb155480 atomic_dec_32(&(p)->refcnt); \ 136c1c61f44Ssb155480 } 137c1c61f44Ssb155480 138ba2e4443Sseb static mac_callbacks_t vnet_m_callbacks = { 139ba2e4443Sseb 0, 140ba2e4443Sseb vnet_m_stat, 141ba2e4443Sseb vnet_m_start, 142ba2e4443Sseb vnet_m_stop, 143ba2e4443Sseb vnet_m_promisc, 144ba2e4443Sseb vnet_m_multicst, 145ba2e4443Sseb vnet_m_unicst, 146ba2e4443Sseb vnet_m_tx, 147ba2e4443Sseb NULL, 148ba2e4443Sseb NULL, 149ba2e4443Sseb NULL 150ba2e4443Sseb }; 151ba2e4443Sseb 1521ae08745Sheppo /* 1531ae08745Sheppo * Linked list of "vnet_t" structures - one per instance. 1541ae08745Sheppo */ 1551ae08745Sheppo static vnet_t *vnet_headp = NULL; 1561ae08745Sheppo static krwlock_t vnet_rw; 1571ae08745Sheppo 1581ae08745Sheppo /* Tunables */ 1591ae08745Sheppo uint32_t vnet_ntxds = VNET_NTXDS; /* power of 2 transmit descriptors */ 1601ae08745Sheppo uint32_t vnet_ldcwd_interval = VNET_LDCWD_INTERVAL; /* watchdog freq in msec */ 1611ae08745Sheppo uint32_t vnet_ldcwd_txtimeout = VNET_LDCWD_TXTIMEOUT; /* tx timeout in msec */ 162e1ebb9ecSlm66018 uint32_t vnet_ldc_mtu = VNET_LDC_MTU; /* ldc mtu */ 163c1c61f44Ssb155480 1647b1f684aSSriharsha Basavapatna /* 1657b1f684aSSriharsha Basavapatna * Set this to non-zero to enable additional internal receive buffer pools 1667b1f684aSSriharsha Basavapatna * based on the MTU of the device for better performance at the cost of more 1677b1f684aSSriharsha Basavapatna * memory consumption. This is turned off by default, to use allocb(9F) for 1687b1f684aSSriharsha Basavapatna * receive buffer allocations of sizes > 2K. 1697b1f684aSSriharsha Basavapatna */ 1707b1f684aSSriharsha Basavapatna boolean_t vnet_jumbo_rxpools = B_FALSE; 1717b1f684aSSriharsha Basavapatna 172c1c61f44Ssb155480 /* # of chains in fdb hash table */ 173c1c61f44Ssb155480 uint32_t vnet_fdb_nchains = VNET_NFDB_HASH; 174c1c61f44Ssb155480 175c1c61f44Ssb155480 /* Internal tunables */ 176c1c61f44Ssb155480 uint32_t vnet_ethermtu = 1500; /* mtu of the device */ 177c1c61f44Ssb155480 178c1c61f44Ssb155480 /* 179c1c61f44Ssb155480 * Default vlan id. This is only used internally when the "default-vlan-id" 180c1c61f44Ssb155480 * property is not present in the MD device node. Therefore, this should not be 181c1c61f44Ssb155480 * used as a tunable; if this value is changed, the corresponding variable 182c1c61f44Ssb155480 * should be updated to the same value in vsw and also other vnets connected to 183c1c61f44Ssb155480 * the same vsw. 184c1c61f44Ssb155480 */ 185c1c61f44Ssb155480 uint16_t vnet_default_vlan_id = 1; 186c1c61f44Ssb155480 187c1c61f44Ssb155480 /* delay in usec to wait for all references on a fdb entry to be dropped */ 188c1c61f44Ssb155480 uint32_t vnet_fdbe_refcnt_delay = 10; 1891ae08745Sheppo 190678453a8Sspeer static struct ether_addr etherbroadcastaddr = { 191678453a8Sspeer 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 192678453a8Sspeer }; 193678453a8Sspeer 194678453a8Sspeer 1951ae08745Sheppo /* 1961ae08745Sheppo * Property names 1971ae08745Sheppo */ 1981ae08745Sheppo static char macaddr_propname[] = "local-mac-address"; 1991ae08745Sheppo 2001ae08745Sheppo /* 2011ae08745Sheppo * This is the string displayed by modinfo(1m). 2021ae08745Sheppo */ 2037b1f684aSSriharsha Basavapatna static char vnet_ident[] = "vnet driver"; 2041ae08745Sheppo extern struct mod_ops mod_driverops; 2051ae08745Sheppo static struct cb_ops cb_vnetops = { 2061ae08745Sheppo nulldev, /* cb_open */ 2071ae08745Sheppo nulldev, /* cb_close */ 2081ae08745Sheppo nodev, /* cb_strategy */ 2091ae08745Sheppo nodev, /* cb_print */ 2101ae08745Sheppo nodev, /* cb_dump */ 2111ae08745Sheppo nodev, /* cb_read */ 2121ae08745Sheppo nodev, /* cb_write */ 2131ae08745Sheppo nodev, /* cb_ioctl */ 2141ae08745Sheppo nodev, /* cb_devmap */ 2151ae08745Sheppo nodev, /* cb_mmap */ 2161ae08745Sheppo nodev, /* cb_segmap */ 2171ae08745Sheppo nochpoll, /* cb_chpoll */ 2181ae08745Sheppo ddi_prop_op, /* cb_prop_op */ 2191ae08745Sheppo NULL, /* cb_stream */ 2201ae08745Sheppo (int)(D_MP) /* cb_flag */ 2211ae08745Sheppo }; 2221ae08745Sheppo 2231ae08745Sheppo static struct dev_ops vnetops = { 2241ae08745Sheppo DEVO_REV, /* devo_rev */ 2251ae08745Sheppo 0, /* devo_refcnt */ 2261ae08745Sheppo NULL, /* devo_getinfo */ 2271ae08745Sheppo nulldev, /* devo_identify */ 2281ae08745Sheppo nulldev, /* devo_probe */ 2291ae08745Sheppo vnetattach, /* devo_attach */ 2301ae08745Sheppo vnetdetach, /* devo_detach */ 2311ae08745Sheppo nodev, /* devo_reset */ 2321ae08745Sheppo &cb_vnetops, /* devo_cb_ops */ 23319397407SSherry Moore (struct bus_ops *)NULL, /* devo_bus_ops */ 23419397407SSherry Moore NULL, /* devo_power */ 23519397407SSherry Moore ddi_quiesce_not_supported, /* devo_quiesce */ 2361ae08745Sheppo }; 2371ae08745Sheppo 2381ae08745Sheppo static struct modldrv modldrv = { 2391ae08745Sheppo &mod_driverops, /* Type of module. This one is a driver */ 2401ae08745Sheppo vnet_ident, /* ID string */ 2411ae08745Sheppo &vnetops /* driver specific ops */ 2421ae08745Sheppo }; 2431ae08745Sheppo 2441ae08745Sheppo static struct modlinkage modlinkage = { 2451ae08745Sheppo MODREV_1, (void *)&modldrv, NULL 2461ae08745Sheppo }; 2471ae08745Sheppo 248844e62a3Sraghuram #ifdef DEBUG 2491ae08745Sheppo 2501ae08745Sheppo /* 2511ae08745Sheppo * Print debug messages - set to 0xf to enable all msgs 2521ae08745Sheppo */ 253844e62a3Sraghuram int vnet_dbglevel = 0x8; 2541ae08745Sheppo 255844e62a3Sraghuram static void 256844e62a3Sraghuram debug_printf(const char *fname, void *arg, const char *fmt, ...) 2571ae08745Sheppo { 2581ae08745Sheppo char buf[512]; 2591ae08745Sheppo va_list ap; 2601ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 261844e62a3Sraghuram char *bufp = buf; 2621ae08745Sheppo 263844e62a3Sraghuram if (vnetp == NULL) { 264844e62a3Sraghuram (void) sprintf(bufp, "%s: ", fname); 265844e62a3Sraghuram bufp += strlen(bufp); 266844e62a3Sraghuram } else { 267844e62a3Sraghuram (void) sprintf(bufp, "vnet%d:%s: ", vnetp->instance, fname); 268844e62a3Sraghuram bufp += strlen(bufp); 2691ae08745Sheppo } 270844e62a3Sraghuram va_start(ap, fmt); 271844e62a3Sraghuram (void) vsprintf(bufp, fmt, ap); 272844e62a3Sraghuram va_end(ap); 273844e62a3Sraghuram cmn_err(CE_CONT, "%s\n", buf); 274844e62a3Sraghuram } 2751ae08745Sheppo 2761ae08745Sheppo #endif 2771ae08745Sheppo 2781ae08745Sheppo /* _init(9E): initialize the loadable module */ 2791ae08745Sheppo int 2801ae08745Sheppo _init(void) 2811ae08745Sheppo { 2821ae08745Sheppo int status; 2831ae08745Sheppo 284844e62a3Sraghuram DBG1(NULL, "enter\n"); 2851ae08745Sheppo 2861ae08745Sheppo mac_init_ops(&vnetops, "vnet"); 2871ae08745Sheppo status = mod_install(&modlinkage); 2881ae08745Sheppo if (status != 0) { 2891ae08745Sheppo mac_fini_ops(&vnetops); 2901ae08745Sheppo } 291678453a8Sspeer vdds_mod_init(); 292*6f09f0feSWENTAO YANG vgen_mod_init(); 293844e62a3Sraghuram DBG1(NULL, "exit(%d)\n", status); 2941ae08745Sheppo return (status); 2951ae08745Sheppo } 2961ae08745Sheppo 2971ae08745Sheppo /* _fini(9E): prepare the module for unloading. */ 2981ae08745Sheppo int 2991ae08745Sheppo _fini(void) 3001ae08745Sheppo { 3011ae08745Sheppo int status; 3021ae08745Sheppo 303844e62a3Sraghuram DBG1(NULL, "enter\n"); 3041ae08745Sheppo 305*6f09f0feSWENTAO YANG status = vgen_mod_cleanup(); 306*6f09f0feSWENTAO YANG if (status != 0) 307*6f09f0feSWENTAO YANG return (status); 308*6f09f0feSWENTAO YANG 3091ae08745Sheppo status = mod_remove(&modlinkage); 3101ae08745Sheppo if (status != 0) 3111ae08745Sheppo return (status); 3121ae08745Sheppo mac_fini_ops(&vnetops); 313*6f09f0feSWENTAO YANG vgen_mod_fini(); 314678453a8Sspeer vdds_mod_fini(); 3151ae08745Sheppo 316844e62a3Sraghuram DBG1(NULL, "exit(%d)\n", status); 3171ae08745Sheppo return (status); 3181ae08745Sheppo } 3191ae08745Sheppo 3201ae08745Sheppo /* _info(9E): return information about the loadable module */ 3211ae08745Sheppo int 3221ae08745Sheppo _info(struct modinfo *modinfop) 3231ae08745Sheppo { 3241ae08745Sheppo return (mod_info(&modlinkage, modinfop)); 3251ae08745Sheppo } 3261ae08745Sheppo 3271ae08745Sheppo /* 3281ae08745Sheppo * attach(9E): attach a device to the system. 3291ae08745Sheppo * called once for each instance of the device on the system. 3301ae08745Sheppo */ 3311ae08745Sheppo static int 3321ae08745Sheppo vnetattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 3331ae08745Sheppo { 3341ae08745Sheppo vnet_t *vnetp; 3351ae08745Sheppo int status; 336678453a8Sspeer int instance; 337678453a8Sspeer uint64_t reg; 338678453a8Sspeer char qname[TASKQ_NAMELEN]; 339*6f09f0feSWENTAO YANG vnet_attach_progress_t attach_progress; 3401ae08745Sheppo 341*6f09f0feSWENTAO YANG attach_progress = AST_init; 3421ae08745Sheppo 3431ae08745Sheppo switch (cmd) { 3441ae08745Sheppo case DDI_ATTACH: 3451ae08745Sheppo break; 3461ae08745Sheppo case DDI_RESUME: 3471ae08745Sheppo case DDI_PM_RESUME: 3481ae08745Sheppo default: 3491ae08745Sheppo goto vnet_attach_fail; 3501ae08745Sheppo } 3511ae08745Sheppo 3521ae08745Sheppo instance = ddi_get_instance(dip); 353844e62a3Sraghuram DBG1(NULL, "instance(%d) enter\n", instance); 3541ae08745Sheppo 3551ae08745Sheppo /* allocate vnet_t and mac_t structures */ 3561ae08745Sheppo vnetp = kmem_zalloc(sizeof (vnet_t), KM_SLEEP); 357678453a8Sspeer vnetp->dip = dip; 358678453a8Sspeer vnetp->instance = instance; 359678453a8Sspeer rw_init(&vnetp->vrwlock, NULL, RW_DRIVER, NULL); 360678453a8Sspeer rw_init(&vnetp->vsw_fp_rw, NULL, RW_DRIVER, NULL); 361*6f09f0feSWENTAO YANG attach_progress |= AST_vnet_alloc; 3621ae08745Sheppo 363678453a8Sspeer status = vdds_init(vnetp); 364678453a8Sspeer if (status != 0) { 365678453a8Sspeer goto vnet_attach_fail; 366678453a8Sspeer } 367*6f09f0feSWENTAO YANG attach_progress |= AST_vdds_init; 368678453a8Sspeer 3691ae08745Sheppo /* setup links to vnet_t from both devinfo and mac_t */ 3701ae08745Sheppo ddi_set_driver_private(dip, (caddr_t)vnetp); 3711ae08745Sheppo 3721ae08745Sheppo /* read the mac address */ 3731ae08745Sheppo status = vnet_read_mac_address(vnetp); 3741ae08745Sheppo if (status != DDI_SUCCESS) { 3751ae08745Sheppo goto vnet_attach_fail; 3761ae08745Sheppo } 377*6f09f0feSWENTAO YANG attach_progress |= AST_read_macaddr; 3781ae08745Sheppo 379678453a8Sspeer reg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 380678453a8Sspeer DDI_PROP_DONTPASS, "reg", -1); 381678453a8Sspeer if (reg == -1) { 3821ae08745Sheppo goto vnet_attach_fail; 3831ae08745Sheppo } 384678453a8Sspeer vnetp->reg = reg; 3851ae08745Sheppo 386c1c61f44Ssb155480 vnet_fdb_create(vnetp); 387*6f09f0feSWENTAO YANG attach_progress |= AST_fdbh_alloc; 3881ae08745Sheppo 389678453a8Sspeer (void) snprintf(qname, TASKQ_NAMELEN, "vnet_taskq%d", instance); 390678453a8Sspeer if ((vnetp->taskqp = ddi_taskq_create(dip, qname, 1, 391678453a8Sspeer TASKQ_DEFAULTPRI, 0)) == NULL) { 392678453a8Sspeer cmn_err(CE_WARN, "!vnet%d: Unable to create task queue", 393678453a8Sspeer instance); 3941ae08745Sheppo goto vnet_attach_fail; 3951ae08745Sheppo } 396*6f09f0feSWENTAO YANG attach_progress |= AST_taskq_create; 3971ae08745Sheppo 3981ae08745Sheppo /* add to the list of vnet devices */ 3991ae08745Sheppo WRITE_ENTER(&vnet_rw); 4001ae08745Sheppo vnetp->nextp = vnet_headp; 4011ae08745Sheppo vnet_headp = vnetp; 4021ae08745Sheppo RW_EXIT(&vnet_rw); 4031ae08745Sheppo 404*6f09f0feSWENTAO YANG attach_progress |= AST_vnet_list; 405678453a8Sspeer 406678453a8Sspeer /* 407678453a8Sspeer * Initialize the generic vnet plugin which provides 408678453a8Sspeer * communication via sun4v LDC (logical domain channel) based 409678453a8Sspeer * resources. It will register the LDC resources as and when 410678453a8Sspeer * they become available. 411678453a8Sspeer */ 412678453a8Sspeer status = vgen_init(vnetp, reg, vnetp->dip, 413678453a8Sspeer (uint8_t *)vnetp->curr_macaddr, &vnetp->vgenhdl); 414678453a8Sspeer if (status != DDI_SUCCESS) { 415678453a8Sspeer DERR(vnetp, "vgen_init() failed\n"); 416678453a8Sspeer goto vnet_attach_fail; 417678453a8Sspeer } 418*6f09f0feSWENTAO YANG attach_progress |= AST_vgen_init; 419678453a8Sspeer 420678453a8Sspeer /* register with MAC layer */ 421678453a8Sspeer status = vnet_mac_register(vnetp); 422678453a8Sspeer if (status != DDI_SUCCESS) { 423678453a8Sspeer goto vnet_attach_fail; 424678453a8Sspeer } 425678453a8Sspeer 426*6f09f0feSWENTAO YANG attach_progress |= AST_macreg; 427*6f09f0feSWENTAO YANG 428*6f09f0feSWENTAO YANG vnetp->attach_progress = attach_progress; 429*6f09f0feSWENTAO YANG 430844e62a3Sraghuram DBG1(NULL, "instance(%d) exit\n", instance); 4311ae08745Sheppo return (DDI_SUCCESS); 4321ae08745Sheppo 4331ae08745Sheppo vnet_attach_fail: 434*6f09f0feSWENTAO YANG vnetp->attach_progress = attach_progress; 435*6f09f0feSWENTAO YANG vnet_unattach(vnetp); 4361ae08745Sheppo return (DDI_FAILURE); 4371ae08745Sheppo } 4381ae08745Sheppo 4391ae08745Sheppo /* 4401ae08745Sheppo * detach(9E): detach a device from the system. 4411ae08745Sheppo */ 4421ae08745Sheppo static int 4431ae08745Sheppo vnetdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4441ae08745Sheppo { 4451ae08745Sheppo vnet_t *vnetp; 4461ae08745Sheppo int instance; 4471ae08745Sheppo 4481ae08745Sheppo instance = ddi_get_instance(dip); 449844e62a3Sraghuram DBG1(NULL, "instance(%d) enter\n", instance); 4501ae08745Sheppo 4511ae08745Sheppo vnetp = ddi_get_driver_private(dip); 4521ae08745Sheppo if (vnetp == NULL) { 4531ae08745Sheppo goto vnet_detach_fail; 4541ae08745Sheppo } 4551ae08745Sheppo 4561ae08745Sheppo switch (cmd) { 4571ae08745Sheppo case DDI_DETACH: 4581ae08745Sheppo break; 4591ae08745Sheppo case DDI_SUSPEND: 4601ae08745Sheppo case DDI_PM_SUSPEND: 4611ae08745Sheppo default: 4621ae08745Sheppo goto vnet_detach_fail; 4631ae08745Sheppo } 4641ae08745Sheppo 465*6f09f0feSWENTAO YANG if (vnet_unattach(vnetp) != 0) { 466d10e4ef2Snarayan goto vnet_detach_fail; 467d10e4ef2Snarayan } 468d10e4ef2Snarayan 469*6f09f0feSWENTAO YANG return (DDI_SUCCESS); 4701ae08745Sheppo 471*6f09f0feSWENTAO YANG vnet_detach_fail: 472*6f09f0feSWENTAO YANG return (DDI_FAILURE); 473*6f09f0feSWENTAO YANG } 474*6f09f0feSWENTAO YANG 475*6f09f0feSWENTAO YANG /* 476*6f09f0feSWENTAO YANG * Common routine to handle vnetattach() failure and vnetdetach(). Note that 477*6f09f0feSWENTAO YANG * the only reason this function could fail is if mac_unregister() fails. 478*6f09f0feSWENTAO YANG * Otherwise, this function must ensure that all resources are freed and return 479*6f09f0feSWENTAO YANG * success. 480*6f09f0feSWENTAO YANG */ 481*6f09f0feSWENTAO YANG static int 482*6f09f0feSWENTAO YANG vnet_unattach(vnet_t *vnetp) 483*6f09f0feSWENTAO YANG { 484*6f09f0feSWENTAO YANG vnet_attach_progress_t attach_progress; 485*6f09f0feSWENTAO YANG 486*6f09f0feSWENTAO YANG attach_progress = vnetp->attach_progress; 487*6f09f0feSWENTAO YANG 488*6f09f0feSWENTAO YANG /* 489*6f09f0feSWENTAO YANG * Unregister from the gldv3 subsystem. This can fail, in particular 490*6f09f0feSWENTAO YANG * if there are still any open references to this mac device; in which 491*6f09f0feSWENTAO YANG * case we just return failure without continuing to detach further. 492*6f09f0feSWENTAO YANG */ 493*6f09f0feSWENTAO YANG if (attach_progress & AST_macreg) { 494*6f09f0feSWENTAO YANG if (mac_unregister(vnetp->mh) != 0) { 495*6f09f0feSWENTAO YANG return (1); 496*6f09f0feSWENTAO YANG } 497*6f09f0feSWENTAO YANG attach_progress &= ~AST_macreg; 498*6f09f0feSWENTAO YANG } 499*6f09f0feSWENTAO YANG 500*6f09f0feSWENTAO YANG /* 501*6f09f0feSWENTAO YANG * Now that we have unregistered from gldv3, we must finish all other 502*6f09f0feSWENTAO YANG * steps and successfully return from this function; otherwise we will 503*6f09f0feSWENTAO YANG * end up leaving the device in a broken/unusable state. 504*6f09f0feSWENTAO YANG * 505*6f09f0feSWENTAO YANG * First, release any hybrid resources assigned to this vnet device. 506*6f09f0feSWENTAO YANG */ 507*6f09f0feSWENTAO YANG if (attach_progress & AST_vdds_init) { 508*6f09f0feSWENTAO YANG vdds_cleanup(vnetp); 509*6f09f0feSWENTAO YANG attach_progress &= ~AST_vdds_init; 510*6f09f0feSWENTAO YANG } 511*6f09f0feSWENTAO YANG 512*6f09f0feSWENTAO YANG /* 513*6f09f0feSWENTAO YANG * Uninit vgen. This stops further mdeg callbacks to this vnet 514*6f09f0feSWENTAO YANG * device and/or its ports; and detaches any existing ports. 515*6f09f0feSWENTAO YANG */ 516*6f09f0feSWENTAO YANG if (attach_progress & AST_vgen_init) { 517*6f09f0feSWENTAO YANG vgen_uninit(vnetp->vgenhdl); 518*6f09f0feSWENTAO YANG attach_progress &= ~AST_vgen_init; 519*6f09f0feSWENTAO YANG } 520*6f09f0feSWENTAO YANG 521*6f09f0feSWENTAO YANG /* Destroy the taskq. */ 522*6f09f0feSWENTAO YANG if (attach_progress & AST_taskq_create) { 523*6f09f0feSWENTAO YANG ddi_taskq_destroy(vnetp->taskqp); 524*6f09f0feSWENTAO YANG attach_progress &= ~AST_taskq_create; 525*6f09f0feSWENTAO YANG } 526*6f09f0feSWENTAO YANG 527*6f09f0feSWENTAO YANG /* Destroy fdb. */ 528*6f09f0feSWENTAO YANG if (attach_progress & AST_fdbh_alloc) { 529*6f09f0feSWENTAO YANG vnet_fdb_destroy(vnetp); 530*6f09f0feSWENTAO YANG attach_progress &= ~AST_fdbh_alloc; 531*6f09f0feSWENTAO YANG } 532*6f09f0feSWENTAO YANG 533*6f09f0feSWENTAO YANG /* Remove from the device list */ 534*6f09f0feSWENTAO YANG if (attach_progress & AST_vnet_list) { 535*6f09f0feSWENTAO YANG vnet_t **vnetpp; 5361ae08745Sheppo /* unlink from instance(vnet_t) list */ 5371ae08745Sheppo WRITE_ENTER(&vnet_rw); 538*6f09f0feSWENTAO YANG for (vnetpp = &vnet_headp; *vnetpp; 539*6f09f0feSWENTAO YANG vnetpp = &(*vnetpp)->nextp) { 5401ae08745Sheppo if (*vnetpp == vnetp) { 5411ae08745Sheppo *vnetpp = vnetp->nextp; 5421ae08745Sheppo break; 5431ae08745Sheppo } 5441ae08745Sheppo } 5451ae08745Sheppo RW_EXIT(&vnet_rw); 546*6f09f0feSWENTAO YANG attach_progress &= ~AST_vnet_list; 547*6f09f0feSWENTAO YANG } 5481ae08745Sheppo 549*6f09f0feSWENTAO YANG if (attach_progress & AST_vnet_alloc) { 550678453a8Sspeer rw_destroy(&vnetp->vrwlock); 551678453a8Sspeer rw_destroy(&vnetp->vsw_fp_rw); 552*6f09f0feSWENTAO YANG attach_progress &= ~AST_vnet_list; 5531ae08745Sheppo KMEM_FREE(vnetp); 554*6f09f0feSWENTAO YANG } 5551ae08745Sheppo 556*6f09f0feSWENTAO YANG return (0); 5571ae08745Sheppo } 5581ae08745Sheppo 5591ae08745Sheppo /* enable the device for transmit/receive */ 5601ae08745Sheppo static int 5611ae08745Sheppo vnet_m_start(void *arg) 5621ae08745Sheppo { 5631ae08745Sheppo vnet_t *vnetp = arg; 5641ae08745Sheppo 565844e62a3Sraghuram DBG1(vnetp, "enter\n"); 5661ae08745Sheppo 567678453a8Sspeer WRITE_ENTER(&vnetp->vrwlock); 568678453a8Sspeer vnetp->flags |= VNET_STARTED; 569678453a8Sspeer vnet_start_resources(vnetp); 570678453a8Sspeer RW_EXIT(&vnetp->vrwlock); 5711ae08745Sheppo 572844e62a3Sraghuram DBG1(vnetp, "exit\n"); 5731ae08745Sheppo return (VNET_SUCCESS); 5741ae08745Sheppo 5751ae08745Sheppo } 5761ae08745Sheppo 5771ae08745Sheppo /* stop transmit/receive for the device */ 5781ae08745Sheppo static void 5791ae08745Sheppo vnet_m_stop(void *arg) 5801ae08745Sheppo { 5811ae08745Sheppo vnet_t *vnetp = arg; 5821ae08745Sheppo 583844e62a3Sraghuram DBG1(vnetp, "enter\n"); 5841ae08745Sheppo 585678453a8Sspeer WRITE_ENTER(&vnetp->vrwlock); 586678453a8Sspeer if (vnetp->flags & VNET_STARTED) { 587678453a8Sspeer vnet_stop_resources(vnetp); 588678453a8Sspeer vnetp->flags &= ~VNET_STARTED; 5891ae08745Sheppo } 590678453a8Sspeer RW_EXIT(&vnetp->vrwlock); 5911ae08745Sheppo 592844e62a3Sraghuram DBG1(vnetp, "exit\n"); 5931ae08745Sheppo } 5941ae08745Sheppo 5951ae08745Sheppo /* set the unicast mac address of the device */ 5961ae08745Sheppo static int 5971ae08745Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr) 5981ae08745Sheppo { 5991ae08745Sheppo _NOTE(ARGUNUSED(macaddr)) 6001ae08745Sheppo 6011ae08745Sheppo vnet_t *vnetp = arg; 6021ae08745Sheppo 603844e62a3Sraghuram DBG1(vnetp, "enter\n"); 6041ae08745Sheppo /* 6053af08d82Slm66018 * NOTE: setting mac address dynamically is not supported. 6061ae08745Sheppo */ 607844e62a3Sraghuram DBG1(vnetp, "exit\n"); 6081ae08745Sheppo 6098e6a2a04Slm66018 return (VNET_FAILURE); 6101ae08745Sheppo } 6111ae08745Sheppo 6121ae08745Sheppo /* enable/disable a multicast address */ 6131ae08745Sheppo static int 6141ae08745Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 6151ae08745Sheppo { 6161ae08745Sheppo _NOTE(ARGUNUSED(add, mca)) 6171ae08745Sheppo 6181ae08745Sheppo vnet_t *vnetp = arg; 619678453a8Sspeer vnet_res_t *vresp; 620678453a8Sspeer mac_register_t *macp; 621ba2e4443Sseb mac_callbacks_t *cbp; 6221ae08745Sheppo int rv = VNET_SUCCESS; 6231ae08745Sheppo 624844e62a3Sraghuram DBG1(vnetp, "enter\n"); 625678453a8Sspeer 626678453a8Sspeer READ_ENTER(&vnetp->vrwlock); 627678453a8Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 628678453a8Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 629678453a8Sspeer macp = &vresp->macreg; 630678453a8Sspeer cbp = macp->m_callbacks; 631678453a8Sspeer rv = cbp->mc_multicst(macp->m_driver, add, mca); 6321ae08745Sheppo } 6331ae08745Sheppo } 634678453a8Sspeer RW_EXIT(&vnetp->vrwlock); 635678453a8Sspeer 636844e62a3Sraghuram DBG1(vnetp, "exit(%d)\n", rv); 6371ae08745Sheppo return (rv); 6381ae08745Sheppo } 6391ae08745Sheppo 6401ae08745Sheppo /* set or clear promiscuous mode on the device */ 6411ae08745Sheppo static int 6421ae08745Sheppo vnet_m_promisc(void *arg, boolean_t on) 6431ae08745Sheppo { 6441ae08745Sheppo _NOTE(ARGUNUSED(on)) 6451ae08745Sheppo 6461ae08745Sheppo vnet_t *vnetp = arg; 647844e62a3Sraghuram DBG1(vnetp, "enter\n"); 6481ae08745Sheppo /* 6493af08d82Slm66018 * NOTE: setting promiscuous mode is not supported, just return success. 6501ae08745Sheppo */ 651844e62a3Sraghuram DBG1(vnetp, "exit\n"); 6521ae08745Sheppo return (VNET_SUCCESS); 6531ae08745Sheppo } 6541ae08745Sheppo 6551ae08745Sheppo /* 6561ae08745Sheppo * Transmit a chain of packets. This function provides switching functionality 6571ae08745Sheppo * based on the destination mac address to reach other guests (within ldoms) or 6581ae08745Sheppo * external hosts. 6591ae08745Sheppo */ 6601ae08745Sheppo mblk_t * 6611ae08745Sheppo vnet_m_tx(void *arg, mblk_t *mp) 6621ae08745Sheppo { 6631ae08745Sheppo vnet_t *vnetp; 664678453a8Sspeer vnet_res_t *vresp; 6651ae08745Sheppo mblk_t *next; 6661ae08745Sheppo mblk_t *resid_mp; 667678453a8Sspeer mac_register_t *macp; 668c1c61f44Ssb155480 struct ether_header *ehp; 669678453a8Sspeer boolean_t is_unicast; 6708c242ab0SSriharsha Basavapatna boolean_t is_pvid; /* non-default pvid ? */ 6718c242ab0SSriharsha Basavapatna boolean_t hres; /* Hybrid resource ? */ 6721ae08745Sheppo 6731ae08745Sheppo vnetp = (vnet_t *)arg; 674844e62a3Sraghuram DBG1(vnetp, "enter\n"); 6751ae08745Sheppo ASSERT(mp != NULL); 6761ae08745Sheppo 6778c242ab0SSriharsha Basavapatna is_pvid = (vnetp->pvid != vnetp->default_vlan_id) ? B_TRUE : B_FALSE; 6788c242ab0SSriharsha Basavapatna 6791ae08745Sheppo while (mp != NULL) { 680c1c61f44Ssb155480 6811ae08745Sheppo next = mp->b_next; 6821ae08745Sheppo mp->b_next = NULL; 6831ae08745Sheppo 6841ae08745Sheppo /* 685c1c61f44Ssb155480 * Find fdb entry for the destination 686c1c61f44Ssb155480 * and hold a reference to it. 6871ae08745Sheppo */ 688c1c61f44Ssb155480 ehp = (struct ether_header *)mp->b_rptr; 689678453a8Sspeer vresp = vnet_fdbe_find(vnetp, &ehp->ether_dhost); 690678453a8Sspeer if (vresp != NULL) { 691c1c61f44Ssb155480 692c1c61f44Ssb155480 /* 693c1c61f44Ssb155480 * Destination found in FDB. 694c1c61f44Ssb155480 * The destination is a vnet device within ldoms 695c1c61f44Ssb155480 * and directly reachable, invoke the tx function 696c1c61f44Ssb155480 * in the fdb entry. 697c1c61f44Ssb155480 */ 698678453a8Sspeer macp = &vresp->macreg; 699678453a8Sspeer resid_mp = macp->m_callbacks->mc_tx(macp->m_driver, mp); 700c1c61f44Ssb155480 701c1c61f44Ssb155480 /* tx done; now release ref on fdb entry */ 702678453a8Sspeer VNET_FDBE_REFRELE(vresp); 703c1c61f44Ssb155480 7041ae08745Sheppo if (resid_mp != NULL) { 7051ae08745Sheppo /* m_tx failed */ 7061ae08745Sheppo mp->b_next = next; 7071ae08745Sheppo break; 7081ae08745Sheppo } 7091ae08745Sheppo } else { 710678453a8Sspeer is_unicast = !(IS_BROADCAST(ehp) || 711678453a8Sspeer (IS_MULTICAST(ehp))); 7121ae08745Sheppo /* 713c1c61f44Ssb155480 * Destination is not in FDB. 714678453a8Sspeer * If the destination is broadcast or multicast, 715678453a8Sspeer * then forward the packet to vswitch. 716678453a8Sspeer * If a Hybrid resource avilable, then send the 717678453a8Sspeer * unicast packet via hybrid resource, otherwise 718678453a8Sspeer * forward it to vswitch. 7191ae08745Sheppo */ 720c1c61f44Ssb155480 READ_ENTER(&vnetp->vsw_fp_rw); 721c1c61f44Ssb155480 722678453a8Sspeer if ((is_unicast) && (vnetp->hio_fp != NULL)) { 723678453a8Sspeer vresp = vnetp->hio_fp; 7248c242ab0SSriharsha Basavapatna hres = B_TRUE; 725678453a8Sspeer } else { 726678453a8Sspeer vresp = vnetp->vsw_fp; 7278c242ab0SSriharsha Basavapatna hres = B_FALSE; 728678453a8Sspeer } 729678453a8Sspeer if (vresp == NULL) { 730c1c61f44Ssb155480 /* 731c1c61f44Ssb155480 * no fdb entry to vsw? drop the packet. 732c1c61f44Ssb155480 */ 733c1c61f44Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 734c1c61f44Ssb155480 freemsg(mp); 735c1c61f44Ssb155480 mp = next; 736c1c61f44Ssb155480 continue; 737c1c61f44Ssb155480 } 738c1c61f44Ssb155480 739c1c61f44Ssb155480 /* ref hold the fdb entry to vsw */ 740678453a8Sspeer VNET_FDBE_REFHOLD(vresp); 741c1c61f44Ssb155480 742c1c61f44Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 743c1c61f44Ssb155480 7448c242ab0SSriharsha Basavapatna /* 7458c242ab0SSriharsha Basavapatna * In the case of a hybrid resource we need to insert 7468c242ab0SSriharsha Basavapatna * the tag for the pvid case here; unlike packets that 7478c242ab0SSriharsha Basavapatna * are destined to a vnet/vsw in which case the vgen 7488c242ab0SSriharsha Basavapatna * layer does the tagging before sending it over ldc. 7498c242ab0SSriharsha Basavapatna */ 7508c242ab0SSriharsha Basavapatna if (hres == B_TRUE) { 7518c242ab0SSriharsha Basavapatna /* 7528c242ab0SSriharsha Basavapatna * Determine if the frame being transmitted 7538c242ab0SSriharsha Basavapatna * over the hybrid resource is untagged. If so, 7548c242ab0SSriharsha Basavapatna * insert the tag before transmitting. 7558c242ab0SSriharsha Basavapatna */ 7568c242ab0SSriharsha Basavapatna if (is_pvid == B_TRUE && 7578c242ab0SSriharsha Basavapatna ehp->ether_type != htons(ETHERTYPE_VLAN)) { 7588c242ab0SSriharsha Basavapatna 7598c242ab0SSriharsha Basavapatna mp = vnet_vlan_insert_tag(mp, 7608c242ab0SSriharsha Basavapatna vnetp->pvid); 7618c242ab0SSriharsha Basavapatna if (mp == NULL) { 7628c242ab0SSriharsha Basavapatna VNET_FDBE_REFRELE(vresp); 7638c242ab0SSriharsha Basavapatna mp = next; 7648c242ab0SSriharsha Basavapatna continue; 7658c242ab0SSriharsha Basavapatna } 7668c242ab0SSriharsha Basavapatna 7678c242ab0SSriharsha Basavapatna } 7688c242ab0SSriharsha Basavapatna } 7698c242ab0SSriharsha Basavapatna 770678453a8Sspeer macp = &vresp->macreg; 771678453a8Sspeer resid_mp = macp->m_callbacks->mc_tx(macp->m_driver, mp); 772c1c61f44Ssb155480 773c1c61f44Ssb155480 /* tx done; now release ref on fdb entry */ 774678453a8Sspeer VNET_FDBE_REFRELE(vresp); 775c1c61f44Ssb155480 7761ae08745Sheppo if (resid_mp != NULL) { 7771ae08745Sheppo /* m_tx failed */ 7781ae08745Sheppo mp->b_next = next; 7791ae08745Sheppo break; 7801ae08745Sheppo } 7811ae08745Sheppo } 7821ae08745Sheppo 7831ae08745Sheppo mp = next; 7841ae08745Sheppo } 7851ae08745Sheppo 786844e62a3Sraghuram DBG1(vnetp, "exit\n"); 7871ae08745Sheppo return (mp); 7881ae08745Sheppo } 7891ae08745Sheppo 7901ae08745Sheppo /* get statistics from the device */ 791ba2e4443Sseb int 792ba2e4443Sseb vnet_m_stat(void *arg, uint_t stat, uint64_t *val) 7931ae08745Sheppo { 7941ae08745Sheppo vnet_t *vnetp = arg; 795678453a8Sspeer vnet_res_t *vresp; 796678453a8Sspeer mac_register_t *macp; 797ba2e4443Sseb mac_callbacks_t *cbp; 798ba2e4443Sseb uint64_t val_total = 0; 7991ae08745Sheppo 800844e62a3Sraghuram DBG1(vnetp, "enter\n"); 8011ae08745Sheppo 8021ae08745Sheppo /* 803ba2e4443Sseb * get the specified statistic from each transport and return the 804ba2e4443Sseb * aggregate val. This obviously only works for counters. 8051ae08745Sheppo */ 806ba2e4443Sseb if ((IS_MAC_STAT(stat) && !MAC_STAT_ISACOUNTER(stat)) || 807ba2e4443Sseb (IS_MACTYPE_STAT(stat) && !ETHER_STAT_ISACOUNTER(stat))) { 808ba2e4443Sseb return (ENOTSUP); 809ba2e4443Sseb } 810678453a8Sspeer 811678453a8Sspeer READ_ENTER(&vnetp->vrwlock); 812678453a8Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 813678453a8Sspeer macp = &vresp->macreg; 814678453a8Sspeer cbp = macp->m_callbacks; 815678453a8Sspeer if (cbp->mc_getstat(macp->m_driver, stat, val) == 0) 816ba2e4443Sseb val_total += *val; 8171ae08745Sheppo } 818678453a8Sspeer RW_EXIT(&vnetp->vrwlock); 8191ae08745Sheppo 820ba2e4443Sseb *val = val_total; 821ba2e4443Sseb 822844e62a3Sraghuram DBG1(vnetp, "exit\n"); 823ba2e4443Sseb return (0); 8241ae08745Sheppo } 8251ae08745Sheppo 8261ae08745Sheppo /* wrapper function for mac_register() */ 8271ae08745Sheppo static int 8281ae08745Sheppo vnet_mac_register(vnet_t *vnetp) 8291ae08745Sheppo { 830ba2e4443Sseb mac_register_t *macp; 831ba2e4443Sseb int err; 8321ae08745Sheppo 833ba2e4443Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 834ba2e4443Sseb return (DDI_FAILURE); 835ba2e4443Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 836ba2e4443Sseb macp->m_driver = vnetp; 8371ae08745Sheppo macp->m_dip = vnetp->dip; 838ba2e4443Sseb macp->m_src_addr = vnetp->curr_macaddr; 839ba2e4443Sseb macp->m_callbacks = &vnet_m_callbacks; 840ba2e4443Sseb macp->m_min_sdu = 0; 8417b1f684aSSriharsha Basavapatna macp->m_max_sdu = vnetp->mtu; 842c1c61f44Ssb155480 macp->m_margin = VLAN_TAGSZ; 8431ae08745Sheppo 8441ae08745Sheppo /* 8451ae08745Sheppo * Finally, we're ready to register ourselves with the MAC layer 8461ae08745Sheppo * interface; if this succeeds, we're all ready to start() 8471ae08745Sheppo */ 848ba2e4443Sseb err = mac_register(macp, &vnetp->mh); 849ba2e4443Sseb mac_free(macp); 850ba2e4443Sseb return (err == 0 ? DDI_SUCCESS : DDI_FAILURE); 8511ae08745Sheppo } 8521ae08745Sheppo 8531ae08745Sheppo /* read the mac address of the device */ 8541ae08745Sheppo static int 8551ae08745Sheppo vnet_read_mac_address(vnet_t *vnetp) 8561ae08745Sheppo { 8571ae08745Sheppo uchar_t *macaddr; 8581ae08745Sheppo uint32_t size; 8591ae08745Sheppo int rv; 8601ae08745Sheppo 8611ae08745Sheppo rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip, 8621ae08745Sheppo DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size); 8631ae08745Sheppo if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) { 864844e62a3Sraghuram DWARN(vnetp, "prop_lookup failed(%s) err(%d)\n", 865844e62a3Sraghuram macaddr_propname, rv); 8661ae08745Sheppo return (DDI_FAILURE); 8671ae08745Sheppo } 8681ae08745Sheppo bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL); 8691ae08745Sheppo bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL); 8701ae08745Sheppo ddi_prop_free(macaddr); 8711ae08745Sheppo 8721ae08745Sheppo return (DDI_SUCCESS); 8731ae08745Sheppo } 8741ae08745Sheppo 87593b13a42Swentaoy static void 876c1c61f44Ssb155480 vnet_fdb_create(vnet_t *vnetp) 87793b13a42Swentaoy { 878c1c61f44Ssb155480 char hashname[MAXNAMELEN]; 87993b13a42Swentaoy 880c1c61f44Ssb155480 (void) snprintf(hashname, MAXNAMELEN, "vnet%d-fdbhash", 881c1c61f44Ssb155480 vnetp->instance); 882c1c61f44Ssb155480 vnetp->fdb_nchains = vnet_fdb_nchains; 883c1c61f44Ssb155480 vnetp->fdb_hashp = mod_hash_create_ptrhash(hashname, vnetp->fdb_nchains, 884c1c61f44Ssb155480 mod_hash_null_valdtor, sizeof (void *)); 88593b13a42Swentaoy } 88693b13a42Swentaoy 88793b13a42Swentaoy static void 888c1c61f44Ssb155480 vnet_fdb_destroy(vnet_t *vnetp) 88993b13a42Swentaoy { 890c1c61f44Ssb155480 /* destroy fdb-hash-table */ 891c1c61f44Ssb155480 if (vnetp->fdb_hashp != NULL) { 892c1c61f44Ssb155480 mod_hash_destroy_hash(vnetp->fdb_hashp); 893c1c61f44Ssb155480 vnetp->fdb_hashp = NULL; 894c1c61f44Ssb155480 vnetp->fdb_nchains = 0; 895c1c61f44Ssb155480 } 89693b13a42Swentaoy } 89793b13a42Swentaoy 89893b13a42Swentaoy /* 899c1c61f44Ssb155480 * Add an entry into the fdb. 90093b13a42Swentaoy */ 9011ae08745Sheppo void 902678453a8Sspeer vnet_fdbe_add(vnet_t *vnetp, vnet_res_t *vresp) 9031ae08745Sheppo { 904c1c61f44Ssb155480 uint64_t addr = 0; 905c1c61f44Ssb155480 int rv; 906c1c61f44Ssb155480 907678453a8Sspeer KEY_HASH(addr, vresp->rem_macaddr); 9081ae08745Sheppo 9091ae08745Sheppo /* 910678453a8Sspeer * If the entry being added corresponds to LDC_SERVICE resource, 911678453a8Sspeer * that is, vswitch connection, it is added to the hash and also 912678453a8Sspeer * the entry is cached, an additional reference count reflects 913678453a8Sspeer * this. The HYBRID resource is not added to the hash, but only 914678453a8Sspeer * cached, as it is only used for sending out packets for unknown 915678453a8Sspeer * unicast destinations. 9161ae08745Sheppo */ 917678453a8Sspeer (vresp->type == VIO_NET_RES_LDC_SERVICE) ? 918678453a8Sspeer (vresp->refcnt = 1) : (vresp->refcnt = 0); 9191ae08745Sheppo 920c1c61f44Ssb155480 /* 921c1c61f44Ssb155480 * Note: duplicate keys will be rejected by mod_hash. 922c1c61f44Ssb155480 */ 923678453a8Sspeer if (vresp->type != VIO_NET_RES_HYBRID) { 924c1c61f44Ssb155480 rv = mod_hash_insert(vnetp->fdb_hashp, (mod_hash_key_t)addr, 925678453a8Sspeer (mod_hash_val_t)vresp); 926c1c61f44Ssb155480 if (rv != 0) { 927c1c61f44Ssb155480 DWARN(vnetp, "Duplicate macaddr key(%lx)\n", addr); 9281ae08745Sheppo return; 9291ae08745Sheppo } 930678453a8Sspeer } 9311ae08745Sheppo 932678453a8Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 933c1c61f44Ssb155480 /* Cache the fdb entry to vsw-port */ 934c1c61f44Ssb155480 WRITE_ENTER(&vnetp->vsw_fp_rw); 935c1c61f44Ssb155480 if (vnetp->vsw_fp == NULL) 936678453a8Sspeer vnetp->vsw_fp = vresp; 937678453a8Sspeer RW_EXIT(&vnetp->vsw_fp_rw); 938678453a8Sspeer } else if (vresp->type == VIO_NET_RES_HYBRID) { 939678453a8Sspeer /* Cache the fdb entry to hybrid resource */ 940678453a8Sspeer WRITE_ENTER(&vnetp->vsw_fp_rw); 941678453a8Sspeer if (vnetp->hio_fp == NULL) 942678453a8Sspeer vnetp->hio_fp = vresp; 943c1c61f44Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 944c1c61f44Ssb155480 } 9451ae08745Sheppo } 9461ae08745Sheppo 947c1c61f44Ssb155480 /* 948c1c61f44Ssb155480 * Remove an entry from fdb. 949c1c61f44Ssb155480 */ 950678453a8Sspeer static void 951678453a8Sspeer vnet_fdbe_del(vnet_t *vnetp, vnet_res_t *vresp) 9521ae08745Sheppo { 953c1c61f44Ssb155480 uint64_t addr = 0; 954c1c61f44Ssb155480 int rv; 955c1c61f44Ssb155480 uint32_t refcnt; 956678453a8Sspeer vnet_res_t *tmp; 957c1c61f44Ssb155480 958678453a8Sspeer KEY_HASH(addr, vresp->rem_macaddr); 9591ae08745Sheppo 9601ae08745Sheppo /* 961c1c61f44Ssb155480 * Remove the entry from fdb hash table. 962c1c61f44Ssb155480 * This prevents further references to this fdb entry. 9631ae08745Sheppo */ 964678453a8Sspeer if (vresp->type != VIO_NET_RES_HYBRID) { 965c1c61f44Ssb155480 rv = mod_hash_remove(vnetp->fdb_hashp, (mod_hash_key_t)addr, 966678453a8Sspeer (mod_hash_val_t *)&tmp); 967678453a8Sspeer if (rv != 0) { 968678453a8Sspeer /* 969678453a8Sspeer * As the resources are added to the hash only 970678453a8Sspeer * after they are started, this can occur if 971678453a8Sspeer * a resource unregisters before it is ever started. 972678453a8Sspeer */ 973678453a8Sspeer return; 974678453a8Sspeer } 975678453a8Sspeer } 9761ae08745Sheppo 977678453a8Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 978c1c61f44Ssb155480 WRITE_ENTER(&vnetp->vsw_fp_rw); 9791ae08745Sheppo 980678453a8Sspeer ASSERT(tmp == vnetp->vsw_fp); 981c1c61f44Ssb155480 vnetp->vsw_fp = NULL; 982c1c61f44Ssb155480 983c1c61f44Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 984678453a8Sspeer } else if (vresp->type == VIO_NET_RES_HYBRID) { 985678453a8Sspeer WRITE_ENTER(&vnetp->vsw_fp_rw); 986678453a8Sspeer 987678453a8Sspeer vnetp->hio_fp = NULL; 988678453a8Sspeer 989678453a8Sspeer RW_EXIT(&vnetp->vsw_fp_rw); 9901ae08745Sheppo } 9911ae08745Sheppo 992c1c61f44Ssb155480 /* 993c1c61f44Ssb155480 * If there are threads already ref holding before the entry was 994c1c61f44Ssb155480 * removed from hash table, then wait for ref count to drop to zero. 995c1c61f44Ssb155480 */ 996678453a8Sspeer (vresp->type == VIO_NET_RES_LDC_SERVICE) ? 997678453a8Sspeer (refcnt = 1) : (refcnt = 0); 998678453a8Sspeer while (vresp->refcnt > refcnt) { 999c1c61f44Ssb155480 delay(drv_usectohz(vnet_fdbe_refcnt_delay)); 1000c1c61f44Ssb155480 } 1001c1c61f44Ssb155480 } 1002c1c61f44Ssb155480 1003c1c61f44Ssb155480 /* 1004c1c61f44Ssb155480 * Search fdb for a given mac address. If an entry is found, hold 1005c1c61f44Ssb155480 * a reference to it and return the entry; else returns NULL. 1006c1c61f44Ssb155480 */ 1007678453a8Sspeer static vnet_res_t * 1008c1c61f44Ssb155480 vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp) 1009c1c61f44Ssb155480 { 1010c1c61f44Ssb155480 uint64_t key = 0; 1011678453a8Sspeer vnet_res_t *vresp; 1012c1c61f44Ssb155480 int rv; 1013c1c61f44Ssb155480 1014678453a8Sspeer KEY_HASH(key, addrp->ether_addr_octet); 1015c1c61f44Ssb155480 1016c1c61f44Ssb155480 rv = mod_hash_find_cb(vnetp->fdb_hashp, (mod_hash_key_t)key, 1017678453a8Sspeer (mod_hash_val_t *)&vresp, vnet_fdbe_find_cb); 1018c1c61f44Ssb155480 1019c1c61f44Ssb155480 if (rv != 0) 1020c1c61f44Ssb155480 return (NULL); 1021c1c61f44Ssb155480 1022678453a8Sspeer return (vresp); 1023c1c61f44Ssb155480 } 1024c1c61f44Ssb155480 1025c1c61f44Ssb155480 /* 1026c1c61f44Ssb155480 * Callback function provided to mod_hash_find_cb(). After finding the fdb 1027c1c61f44Ssb155480 * entry corresponding to the key (macaddr), this callback will be invoked by 1028c1c61f44Ssb155480 * mod_hash_find_cb() to atomically increment the reference count on the fdb 1029c1c61f44Ssb155480 * entry before returning the found entry. 1030c1c61f44Ssb155480 */ 1031c1c61f44Ssb155480 static void 1032c1c61f44Ssb155480 vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val) 1033c1c61f44Ssb155480 { 1034c1c61f44Ssb155480 _NOTE(ARGUNUSED(key)) 1035678453a8Sspeer VNET_FDBE_REFHOLD((vnet_res_t *)val); 1036678453a8Sspeer } 1037678453a8Sspeer 10388c242ab0SSriharsha Basavapatna /* 10398c242ab0SSriharsha Basavapatna * Frames received that are tagged with the pvid of the vnet device must be 10408c242ab0SSriharsha Basavapatna * untagged before sending up the stack. This function walks the chain of rx 10418c242ab0SSriharsha Basavapatna * frames, untags any such frames and returns the updated chain. 10428c242ab0SSriharsha Basavapatna * 10438c242ab0SSriharsha Basavapatna * Arguments: 10448c242ab0SSriharsha Basavapatna * pvid: pvid of the vnet device for which packets are being received 10458c242ab0SSriharsha Basavapatna * mp: head of pkt chain to be validated and untagged 10468c242ab0SSriharsha Basavapatna * 10478c242ab0SSriharsha Basavapatna * Returns: 10488c242ab0SSriharsha Basavapatna * mp: head of updated chain of packets 10498c242ab0SSriharsha Basavapatna */ 10508c242ab0SSriharsha Basavapatna static void 10518c242ab0SSriharsha Basavapatna vnet_rx_frames_untag(uint16_t pvid, mblk_t **mp) 10528c242ab0SSriharsha Basavapatna { 10538c242ab0SSriharsha Basavapatna struct ether_vlan_header *evhp; 10548c242ab0SSriharsha Basavapatna mblk_t *bp; 10558c242ab0SSriharsha Basavapatna mblk_t *bpt; 10568c242ab0SSriharsha Basavapatna mblk_t *bph; 10578c242ab0SSriharsha Basavapatna mblk_t *bpn; 10588c242ab0SSriharsha Basavapatna 10598c242ab0SSriharsha Basavapatna bpn = bph = bpt = NULL; 10608c242ab0SSriharsha Basavapatna 10618c242ab0SSriharsha Basavapatna for (bp = *mp; bp != NULL; bp = bpn) { 10628c242ab0SSriharsha Basavapatna 10638c242ab0SSriharsha Basavapatna bpn = bp->b_next; 10648c242ab0SSriharsha Basavapatna bp->b_next = bp->b_prev = NULL; 10658c242ab0SSriharsha Basavapatna 10668c242ab0SSriharsha Basavapatna evhp = (struct ether_vlan_header *)bp->b_rptr; 10678c242ab0SSriharsha Basavapatna 10688c242ab0SSriharsha Basavapatna if (ntohs(evhp->ether_tpid) == ETHERTYPE_VLAN && 10698c242ab0SSriharsha Basavapatna VLAN_ID(ntohs(evhp->ether_tci)) == pvid) { 10708c242ab0SSriharsha Basavapatna 10718c242ab0SSriharsha Basavapatna bp = vnet_vlan_remove_tag(bp); 10728c242ab0SSriharsha Basavapatna if (bp == NULL) { 10738c242ab0SSriharsha Basavapatna continue; 10748c242ab0SSriharsha Basavapatna } 10758c242ab0SSriharsha Basavapatna 10768c242ab0SSriharsha Basavapatna } 10778c242ab0SSriharsha Basavapatna 10788c242ab0SSriharsha Basavapatna /* build a chain of processed packets */ 10798c242ab0SSriharsha Basavapatna if (bph == NULL) { 10808c242ab0SSriharsha Basavapatna bph = bpt = bp; 10818c242ab0SSriharsha Basavapatna } else { 10828c242ab0SSriharsha Basavapatna bpt->b_next = bp; 10838c242ab0SSriharsha Basavapatna bpt = bp; 10848c242ab0SSriharsha Basavapatna } 10858c242ab0SSriharsha Basavapatna 10868c242ab0SSriharsha Basavapatna } 10878c242ab0SSriharsha Basavapatna 10888c242ab0SSriharsha Basavapatna *mp = bph; 10898c242ab0SSriharsha Basavapatna } 10908c242ab0SSriharsha Basavapatna 1091678453a8Sspeer static void 1092678453a8Sspeer vnet_rx(vio_net_handle_t vrh, mblk_t *mp) 1093678453a8Sspeer { 1094678453a8Sspeer vnet_res_t *vresp = (vnet_res_t *)vrh; 1095678453a8Sspeer vnet_t *vnetp = vresp->vnetp; 1096678453a8Sspeer 10978c242ab0SSriharsha Basavapatna if ((vnetp == NULL) || (vnetp->mh == 0)) { 1098678453a8Sspeer freemsgchain(mp); 10998c242ab0SSriharsha Basavapatna return; 1100678453a8Sspeer } 11018c242ab0SSriharsha Basavapatna 11028c242ab0SSriharsha Basavapatna /* 11038c242ab0SSriharsha Basavapatna * Packets received over a hybrid resource need additional processing 11048c242ab0SSriharsha Basavapatna * to remove the tag, for the pvid case. The underlying resource is 11058c242ab0SSriharsha Basavapatna * not aware of the vnet's pvid and thus packets are received with the 11068c242ab0SSriharsha Basavapatna * vlan tag in the header; unlike packets that are received over a ldc 11078c242ab0SSriharsha Basavapatna * channel in which case the peer vnet/vsw would have already removed 11088c242ab0SSriharsha Basavapatna * the tag. 11098c242ab0SSriharsha Basavapatna */ 11108c242ab0SSriharsha Basavapatna if (vresp->type == VIO_NET_RES_HYBRID && 11118c242ab0SSriharsha Basavapatna vnetp->pvid != vnetp->default_vlan_id) { 11128c242ab0SSriharsha Basavapatna 11138c242ab0SSriharsha Basavapatna vnet_rx_frames_untag(vnetp->pvid, &mp); 11148c242ab0SSriharsha Basavapatna if (mp == NULL) { 11158c242ab0SSriharsha Basavapatna return; 11168c242ab0SSriharsha Basavapatna } 11178c242ab0SSriharsha Basavapatna } 11188c242ab0SSriharsha Basavapatna 11198c242ab0SSriharsha Basavapatna mac_rx(vnetp->mh, NULL, mp); 11201ae08745Sheppo } 1121ba2e4443Sseb 1122ba2e4443Sseb void 1123678453a8Sspeer vnet_tx_update(vio_net_handle_t vrh) 1124ba2e4443Sseb { 1125678453a8Sspeer vnet_res_t *vresp = (vnet_res_t *)vrh; 1126678453a8Sspeer vnet_t *vnetp = vresp->vnetp; 1127ba2e4443Sseb 1128678453a8Sspeer if ((vnetp != NULL) && (vnetp->mh != NULL)) { 1129ba2e4443Sseb mac_tx_update(vnetp->mh); 1130ba2e4443Sseb } 1131678453a8Sspeer } 1132678453a8Sspeer 1133678453a8Sspeer /* 11347b1f684aSSriharsha Basavapatna * Update the new mtu of vnet into the mac layer. First check if the device has 11357b1f684aSSriharsha Basavapatna * been plumbed and if so fail the mtu update. Returns 0 on success. 11367b1f684aSSriharsha Basavapatna */ 11377b1f684aSSriharsha Basavapatna int 11387b1f684aSSriharsha Basavapatna vnet_mtu_update(vnet_t *vnetp, uint32_t mtu) 11397b1f684aSSriharsha Basavapatna { 11407b1f684aSSriharsha Basavapatna int rv; 11417b1f684aSSriharsha Basavapatna 11427b1f684aSSriharsha Basavapatna if (vnetp == NULL || vnetp->mh == NULL) { 11437b1f684aSSriharsha Basavapatna return (EINVAL); 11447b1f684aSSriharsha Basavapatna } 11457b1f684aSSriharsha Basavapatna 11467b1f684aSSriharsha Basavapatna WRITE_ENTER(&vnetp->vrwlock); 11477b1f684aSSriharsha Basavapatna 11487b1f684aSSriharsha Basavapatna if (vnetp->flags & VNET_STARTED) { 11497b1f684aSSriharsha Basavapatna RW_EXIT(&vnetp->vrwlock); 11507b1f684aSSriharsha Basavapatna cmn_err(CE_NOTE, "!vnet%d: Unable to process mtu " 11517b1f684aSSriharsha Basavapatna "update as the device is plumbed\n", 11527b1f684aSSriharsha Basavapatna vnetp->instance); 11537b1f684aSSriharsha Basavapatna return (EBUSY); 11547b1f684aSSriharsha Basavapatna } 11557b1f684aSSriharsha Basavapatna 11567b1f684aSSriharsha Basavapatna /* update mtu in the mac layer */ 11577b1f684aSSriharsha Basavapatna rv = mac_maxsdu_update(vnetp->mh, mtu); 11587b1f684aSSriharsha Basavapatna if (rv != 0) { 11597b1f684aSSriharsha Basavapatna RW_EXIT(&vnetp->vrwlock); 11607b1f684aSSriharsha Basavapatna cmn_err(CE_NOTE, 11617b1f684aSSriharsha Basavapatna "!vnet%d: Unable to update mtu with mac layer\n", 11627b1f684aSSriharsha Basavapatna vnetp->instance); 11637b1f684aSSriharsha Basavapatna return (EIO); 11647b1f684aSSriharsha Basavapatna } 11657b1f684aSSriharsha Basavapatna 11667b1f684aSSriharsha Basavapatna vnetp->mtu = mtu; 11677b1f684aSSriharsha Basavapatna 11687b1f684aSSriharsha Basavapatna RW_EXIT(&vnetp->vrwlock); 11697b1f684aSSriharsha Basavapatna 11707b1f684aSSriharsha Basavapatna return (0); 11717b1f684aSSriharsha Basavapatna } 11727b1f684aSSriharsha Basavapatna 11737b1f684aSSriharsha Basavapatna /* 1174678453a8Sspeer * vio_net_resource_reg -- An interface called to register a resource 1175678453a8Sspeer * with vnet. 1176678453a8Sspeer * macp -- a GLDv3 mac_register that has all the details of 1177678453a8Sspeer * a resource and its callbacks etc. 1178678453a8Sspeer * type -- resource type. 1179678453a8Sspeer * local_macaddr -- resource's MAC address. This is used to 1180678453a8Sspeer * associate a resource with a corresponding vnet. 1181678453a8Sspeer * remote_macaddr -- remote side MAC address. This is ignored for 1182678453a8Sspeer * the Hybrid resources. 1183678453a8Sspeer * vhp -- A handle returned to the caller. 1184678453a8Sspeer * vcb -- A set of callbacks provided to the callers. 1185678453a8Sspeer */ 1186678453a8Sspeer int vio_net_resource_reg(mac_register_t *macp, vio_net_res_type_t type, 1187678453a8Sspeer ether_addr_t local_macaddr, ether_addr_t rem_macaddr, vio_net_handle_t *vhp, 1188678453a8Sspeer vio_net_callbacks_t *vcb) 1189678453a8Sspeer { 1190678453a8Sspeer vnet_t *vnetp; 1191678453a8Sspeer vnet_res_t *vresp; 1192678453a8Sspeer 1193678453a8Sspeer vresp = kmem_zalloc(sizeof (vnet_res_t), KM_SLEEP); 1194678453a8Sspeer ether_copy(local_macaddr, vresp->local_macaddr); 1195678453a8Sspeer ether_copy(rem_macaddr, vresp->rem_macaddr); 1196678453a8Sspeer vresp->type = type; 1197678453a8Sspeer bcopy(macp, &vresp->macreg, sizeof (mac_register_t)); 1198678453a8Sspeer 1199678453a8Sspeer DBG1(NULL, "Resource Registerig type=0%X\n", type); 1200678453a8Sspeer 1201678453a8Sspeer READ_ENTER(&vnet_rw); 1202678453a8Sspeer vnetp = vnet_headp; 1203678453a8Sspeer while (vnetp != NULL) { 1204678453a8Sspeer if (VNET_MATCH_RES(vresp, vnetp)) { 1205678453a8Sspeer vresp->vnetp = vnetp; 12066b8fc343SWENTAO YANG 12076b8fc343SWENTAO YANG /* Setup kstats for hio resource */ 12086b8fc343SWENTAO YANG if (vresp->type == VIO_NET_RES_HYBRID) { 12096b8fc343SWENTAO YANG vresp->ksp = vnet_hio_setup_kstats(DRV_NAME, 12106b8fc343SWENTAO YANG "hio", vresp); 12116b8fc343SWENTAO YANG if (vresp->ksp == NULL) { 12126b8fc343SWENTAO YANG cmn_err(CE_NOTE, "!vnet%d: Cannot " 12136b8fc343SWENTAO YANG "create kstats for hio resource", 12146b8fc343SWENTAO YANG vnetp->instance); 12156b8fc343SWENTAO YANG } 12166b8fc343SWENTAO YANG } 12176b8fc343SWENTAO YANG 12186b8fc343SWENTAO YANG WRITE_ENTER(&vnetp->vrwlock); 1219678453a8Sspeer vresp->nextp = vnetp->vres_list; 1220678453a8Sspeer vnetp->vres_list = vresp; 1221678453a8Sspeer RW_EXIT(&vnetp->vrwlock); 1222678453a8Sspeer break; 1223678453a8Sspeer } 1224678453a8Sspeer vnetp = vnetp->nextp; 1225678453a8Sspeer } 1226678453a8Sspeer RW_EXIT(&vnet_rw); 1227678453a8Sspeer if (vresp->vnetp == NULL) { 1228678453a8Sspeer DWARN(NULL, "No vnet instance"); 1229678453a8Sspeer kmem_free(vresp, sizeof (vnet_res_t)); 1230678453a8Sspeer return (ENXIO); 1231678453a8Sspeer } 1232678453a8Sspeer 1233678453a8Sspeer *vhp = vresp; 1234678453a8Sspeer vcb->vio_net_rx_cb = vnet_rx; 1235678453a8Sspeer vcb->vio_net_tx_update = vnet_tx_update; 1236678453a8Sspeer vcb->vio_net_report_err = vnet_handle_res_err; 1237678453a8Sspeer 1238678453a8Sspeer /* Dispatch a task to start resources */ 1239678453a8Sspeer vnet_dispatch_res_task(vnetp); 1240678453a8Sspeer return (0); 1241678453a8Sspeer } 1242678453a8Sspeer 1243678453a8Sspeer /* 1244678453a8Sspeer * vio_net_resource_unreg -- An interface to unregister a resource. 1245678453a8Sspeer */ 1246678453a8Sspeer void 1247678453a8Sspeer vio_net_resource_unreg(vio_net_handle_t vhp) 1248678453a8Sspeer { 1249678453a8Sspeer vnet_res_t *vresp = (vnet_res_t *)vhp; 1250678453a8Sspeer vnet_t *vnetp = vresp->vnetp; 1251678453a8Sspeer vnet_res_t *vrp; 12526ab6cb20SWENTAO YANG kstat_t *ksp = NULL; 1253678453a8Sspeer 1254678453a8Sspeer DBG1(NULL, "Resource Registerig hdl=0x%p", vhp); 1255678453a8Sspeer 1256678453a8Sspeer ASSERT(vnetp != NULL); 1257678453a8Sspeer vnet_fdbe_del(vnetp, vresp); 1258678453a8Sspeer 1259678453a8Sspeer WRITE_ENTER(&vnetp->vrwlock); 1260678453a8Sspeer if (vresp == vnetp->vres_list) { 1261678453a8Sspeer vnetp->vres_list = vresp->nextp; 1262678453a8Sspeer } else { 1263678453a8Sspeer vrp = vnetp->vres_list; 1264678453a8Sspeer while (vrp->nextp != NULL) { 1265678453a8Sspeer if (vrp->nextp == vresp) { 1266678453a8Sspeer vrp->nextp = vresp->nextp; 1267678453a8Sspeer break; 1268678453a8Sspeer } 1269678453a8Sspeer vrp = vrp->nextp; 1270678453a8Sspeer } 1271678453a8Sspeer } 12726ab6cb20SWENTAO YANG 12736ab6cb20SWENTAO YANG ksp = vresp->ksp; 12746ab6cb20SWENTAO YANG vresp->ksp = NULL; 12756ab6cb20SWENTAO YANG 1276678453a8Sspeer vresp->vnetp = NULL; 1277678453a8Sspeer vresp->nextp = NULL; 1278678453a8Sspeer RW_EXIT(&vnetp->vrwlock); 12796ab6cb20SWENTAO YANG vnet_hio_destroy_kstats(ksp); 1280678453a8Sspeer KMEM_FREE(vresp); 1281678453a8Sspeer } 1282678453a8Sspeer 1283678453a8Sspeer /* 1284678453a8Sspeer * vnet_dds_rx -- an interface called by vgen to DDS messages. 1285678453a8Sspeer */ 1286678453a8Sspeer void 1287678453a8Sspeer vnet_dds_rx(void *arg, void *dmsg) 1288678453a8Sspeer { 1289678453a8Sspeer vnet_t *vnetp = arg; 1290678453a8Sspeer vdds_process_dds_msg(vnetp, dmsg); 1291678453a8Sspeer } 1292678453a8Sspeer 1293678453a8Sspeer /* 1294678453a8Sspeer * vnet_send_dds_msg -- An interface provided to DDS to send 1295678453a8Sspeer * DDS messages. This simply sends meessages via vgen. 1296678453a8Sspeer */ 1297678453a8Sspeer int 1298678453a8Sspeer vnet_send_dds_msg(vnet_t *vnetp, void *dmsg) 1299678453a8Sspeer { 1300678453a8Sspeer int rv; 1301678453a8Sspeer 1302678453a8Sspeer if (vnetp->vgenhdl != NULL) { 1303678453a8Sspeer rv = vgen_dds_tx(vnetp->vgenhdl, dmsg); 1304678453a8Sspeer } 1305678453a8Sspeer return (rv); 1306678453a8Sspeer } 1307678453a8Sspeer 1308678453a8Sspeer /* 1309678453a8Sspeer * vnet_handle_res_err -- A callback function called by a resource 1310678453a8Sspeer * to report an error. For example, vgen can call to report 1311678453a8Sspeer * an LDC down/reset event. This will trigger cleanup of associated 1312678453a8Sspeer * Hybrid resource. 1313678453a8Sspeer */ 1314678453a8Sspeer /* ARGSUSED */ 1315678453a8Sspeer static void 1316678453a8Sspeer vnet_handle_res_err(vio_net_handle_t vrh, vio_net_err_val_t err) 1317678453a8Sspeer { 1318678453a8Sspeer vnet_res_t *vresp = (vnet_res_t *)vrh; 1319678453a8Sspeer vnet_t *vnetp = vresp->vnetp; 1320d0288fccSRaghuram Kothakota int rv; 1321678453a8Sspeer 1322678453a8Sspeer if (vnetp == NULL) { 1323678453a8Sspeer return; 1324678453a8Sspeer } 1325678453a8Sspeer if ((vresp->type != VIO_NET_RES_LDC_SERVICE) && 1326678453a8Sspeer (vresp->type != VIO_NET_RES_HYBRID)) { 1327678453a8Sspeer return; 1328678453a8Sspeer } 1329d0288fccSRaghuram Kothakota rv = ddi_taskq_dispatch(vnetp->taskqp, vdds_cleanup_hybrid_res, 1330d0288fccSRaghuram Kothakota vnetp, DDI_NOSLEEP); 1331d0288fccSRaghuram Kothakota if (rv != DDI_SUCCESS) { 1332d0288fccSRaghuram Kothakota cmn_err(CE_WARN, 1333d0288fccSRaghuram Kothakota "vnet%d:Failed to dispatch task to cleanup hybrid resource", 1334d0288fccSRaghuram Kothakota vnetp->instance); 1335d0288fccSRaghuram Kothakota } 1336678453a8Sspeer } 1337678453a8Sspeer 1338678453a8Sspeer /* 1339678453a8Sspeer * vnet_dispatch_res_task -- A function to dispatch tasks start resources. 1340678453a8Sspeer */ 1341678453a8Sspeer static void 1342678453a8Sspeer vnet_dispatch_res_task(vnet_t *vnetp) 1343678453a8Sspeer { 1344678453a8Sspeer int rv; 1345678453a8Sspeer 1346678453a8Sspeer WRITE_ENTER(&vnetp->vrwlock); 1347678453a8Sspeer if (vnetp->flags & VNET_STARTED) { 1348678453a8Sspeer rv = ddi_taskq_dispatch(vnetp->taskqp, vnet_res_start_task, 1349678453a8Sspeer vnetp, DDI_NOSLEEP); 1350678453a8Sspeer if (rv != DDI_SUCCESS) { 1351678453a8Sspeer cmn_err(CE_WARN, 1352678453a8Sspeer "vnet%d:Can't dispatch start resource task", 1353678453a8Sspeer vnetp->instance); 1354678453a8Sspeer } 1355678453a8Sspeer } 1356678453a8Sspeer RW_EXIT(&vnetp->vrwlock); 1357678453a8Sspeer } 1358678453a8Sspeer 1359678453a8Sspeer /* 1360678453a8Sspeer * vnet_res_start_task -- A taskq callback function that starts a resource. 1361678453a8Sspeer */ 1362678453a8Sspeer static void 1363678453a8Sspeer vnet_res_start_task(void *arg) 1364678453a8Sspeer { 1365678453a8Sspeer vnet_t *vnetp = arg; 1366678453a8Sspeer 1367678453a8Sspeer WRITE_ENTER(&vnetp->vrwlock); 1368678453a8Sspeer if (vnetp->flags & VNET_STARTED) { 1369678453a8Sspeer vnet_start_resources(vnetp); 1370678453a8Sspeer } 1371678453a8Sspeer RW_EXIT(&vnetp->vrwlock); 1372678453a8Sspeer } 1373678453a8Sspeer 1374678453a8Sspeer /* 1375678453a8Sspeer * vnet_start_resources -- starts all resources associated with 1376678453a8Sspeer * a vnet. 1377678453a8Sspeer */ 1378678453a8Sspeer static void 1379678453a8Sspeer vnet_start_resources(vnet_t *vnetp) 1380678453a8Sspeer { 1381678453a8Sspeer mac_register_t *macp; 1382678453a8Sspeer mac_callbacks_t *cbp; 1383678453a8Sspeer vnet_res_t *vresp; 1384678453a8Sspeer int rv; 1385678453a8Sspeer 1386678453a8Sspeer DBG1(vnetp, "enter\n"); 1387678453a8Sspeer 1388678453a8Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 1389678453a8Sspeer /* skip if it is already started */ 1390678453a8Sspeer if (vresp->flags & VNET_STARTED) { 1391678453a8Sspeer continue; 1392678453a8Sspeer } 1393678453a8Sspeer macp = &vresp->macreg; 1394678453a8Sspeer cbp = macp->m_callbacks; 1395678453a8Sspeer rv = cbp->mc_start(macp->m_driver); 1396678453a8Sspeer if (rv == 0) { 1397678453a8Sspeer /* 1398678453a8Sspeer * Successfully started the resource, so now 1399678453a8Sspeer * add it to the fdb. 1400678453a8Sspeer */ 1401678453a8Sspeer vresp->flags |= VNET_STARTED; 1402678453a8Sspeer vnet_fdbe_add(vnetp, vresp); 1403678453a8Sspeer } 1404678453a8Sspeer } 1405678453a8Sspeer 1406678453a8Sspeer DBG1(vnetp, "exit\n"); 1407678453a8Sspeer 1408678453a8Sspeer } 1409678453a8Sspeer 1410678453a8Sspeer /* 1411678453a8Sspeer * vnet_stop_resources -- stop all resources associated with a vnet. 1412678453a8Sspeer */ 1413678453a8Sspeer static void 1414678453a8Sspeer vnet_stop_resources(vnet_t *vnetp) 1415678453a8Sspeer { 1416678453a8Sspeer vnet_res_t *vresp; 1417678453a8Sspeer vnet_res_t *nvresp; 1418678453a8Sspeer mac_register_t *macp; 1419678453a8Sspeer mac_callbacks_t *cbp; 1420678453a8Sspeer 1421678453a8Sspeer DBG1(vnetp, "enter\n"); 1422678453a8Sspeer 1423678453a8Sspeer for (vresp = vnetp->vres_list; vresp != NULL; ) { 1424678453a8Sspeer nvresp = vresp->nextp; 1425678453a8Sspeer if (vresp->flags & VNET_STARTED) { 1426678453a8Sspeer macp = &vresp->macreg; 1427678453a8Sspeer cbp = macp->m_callbacks; 1428678453a8Sspeer cbp->mc_stop(macp->m_driver); 1429678453a8Sspeer vresp->flags &= ~VNET_STARTED; 1430678453a8Sspeer } 1431678453a8Sspeer vresp = nvresp; 1432678453a8Sspeer } 1433678453a8Sspeer DBG1(vnetp, "exit\n"); 1434678453a8Sspeer } 14356ab6cb20SWENTAO YANG 14366ab6cb20SWENTAO YANG /* 14376ab6cb20SWENTAO YANG * Setup kstats for the HIO statistics. 14386ab6cb20SWENTAO YANG * NOTE: the synchronization for the statistics is the 14396ab6cb20SWENTAO YANG * responsibility of the caller. 14406ab6cb20SWENTAO YANG */ 14416ab6cb20SWENTAO YANG kstat_t * 14426ab6cb20SWENTAO YANG vnet_hio_setup_kstats(char *ks_mod, char *ks_name, vnet_res_t *vresp) 14436ab6cb20SWENTAO YANG { 14446ab6cb20SWENTAO YANG kstat_t *ksp; 14456ab6cb20SWENTAO YANG vnet_t *vnetp = vresp->vnetp; 14466ab6cb20SWENTAO YANG vnet_hio_kstats_t *hiokp; 14476ab6cb20SWENTAO YANG size_t size; 14486ab6cb20SWENTAO YANG 14496ab6cb20SWENTAO YANG ASSERT(vnetp != NULL); 14506ab6cb20SWENTAO YANG size = sizeof (vnet_hio_kstats_t) / sizeof (kstat_named_t); 14516ab6cb20SWENTAO YANG ksp = kstat_create(ks_mod, vnetp->instance, ks_name, "net", 14526ab6cb20SWENTAO YANG KSTAT_TYPE_NAMED, size, 0); 14536ab6cb20SWENTAO YANG if (ksp == NULL) { 14546ab6cb20SWENTAO YANG return (NULL); 14556ab6cb20SWENTAO YANG } 14566ab6cb20SWENTAO YANG 14576ab6cb20SWENTAO YANG hiokp = (vnet_hio_kstats_t *)ksp->ks_data; 14586ab6cb20SWENTAO YANG kstat_named_init(&hiokp->ipackets, "ipackets", 14596ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 14606ab6cb20SWENTAO YANG kstat_named_init(&hiokp->ierrors, "ierrors", 14616ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 14626ab6cb20SWENTAO YANG kstat_named_init(&hiokp->opackets, "opackets", 14636ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 14646ab6cb20SWENTAO YANG kstat_named_init(&hiokp->oerrors, "oerrors", 14656ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 14666ab6cb20SWENTAO YANG 14676ab6cb20SWENTAO YANG 14686ab6cb20SWENTAO YANG /* MIB II kstat variables */ 14696ab6cb20SWENTAO YANG kstat_named_init(&hiokp->rbytes, "rbytes", 14706ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 14716ab6cb20SWENTAO YANG kstat_named_init(&hiokp->obytes, "obytes", 14726ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 14736ab6cb20SWENTAO YANG kstat_named_init(&hiokp->multircv, "multircv", 14746ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 14756ab6cb20SWENTAO YANG kstat_named_init(&hiokp->multixmt, "multixmt", 14766ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 14776ab6cb20SWENTAO YANG kstat_named_init(&hiokp->brdcstrcv, "brdcstrcv", 14786ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 14796ab6cb20SWENTAO YANG kstat_named_init(&hiokp->brdcstxmt, "brdcstxmt", 14806ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 14816ab6cb20SWENTAO YANG kstat_named_init(&hiokp->norcvbuf, "norcvbuf", 14826ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 14836ab6cb20SWENTAO YANG kstat_named_init(&hiokp->noxmtbuf, "noxmtbuf", 14846ab6cb20SWENTAO YANG KSTAT_DATA_ULONG); 14856ab6cb20SWENTAO YANG 14866ab6cb20SWENTAO YANG ksp->ks_update = vnet_hio_update_kstats; 14876ab6cb20SWENTAO YANG ksp->ks_private = (void *)vresp; 14886ab6cb20SWENTAO YANG kstat_install(ksp); 14896ab6cb20SWENTAO YANG return (ksp); 14906ab6cb20SWENTAO YANG } 14916ab6cb20SWENTAO YANG 14926ab6cb20SWENTAO YANG /* 14936ab6cb20SWENTAO YANG * Destroy kstats. 14946ab6cb20SWENTAO YANG */ 14956ab6cb20SWENTAO YANG static void 14966ab6cb20SWENTAO YANG vnet_hio_destroy_kstats(kstat_t *ksp) 14976ab6cb20SWENTAO YANG { 14986ab6cb20SWENTAO YANG if (ksp != NULL) 14996ab6cb20SWENTAO YANG kstat_delete(ksp); 15006ab6cb20SWENTAO YANG } 15016ab6cb20SWENTAO YANG 15026ab6cb20SWENTAO YANG /* 15036ab6cb20SWENTAO YANG * Update the kstats. 15046ab6cb20SWENTAO YANG */ 15056ab6cb20SWENTAO YANG static int 15066ab6cb20SWENTAO YANG vnet_hio_update_kstats(kstat_t *ksp, int rw) 15076ab6cb20SWENTAO YANG { 15086ab6cb20SWENTAO YANG vnet_t *vnetp; 15096ab6cb20SWENTAO YANG vnet_res_t *vresp; 15106ab6cb20SWENTAO YANG vnet_hio_stats_t statsp; 15116ab6cb20SWENTAO YANG vnet_hio_kstats_t *hiokp; 15126ab6cb20SWENTAO YANG 15136ab6cb20SWENTAO YANG vresp = (vnet_res_t *)ksp->ks_private; 15146ab6cb20SWENTAO YANG vnetp = vresp->vnetp; 15156ab6cb20SWENTAO YANG 15166ab6cb20SWENTAO YANG bzero(&statsp, sizeof (vnet_hio_stats_t)); 15176ab6cb20SWENTAO YANG 15186ab6cb20SWENTAO YANG READ_ENTER(&vnetp->vsw_fp_rw); 15196ab6cb20SWENTAO YANG if (vnetp->hio_fp == NULL) { 15206ab6cb20SWENTAO YANG /* not using hio resources, just return */ 15216ab6cb20SWENTAO YANG RW_EXIT(&vnetp->vsw_fp_rw); 15226ab6cb20SWENTAO YANG return (0); 15236ab6cb20SWENTAO YANG } 15246ab6cb20SWENTAO YANG VNET_FDBE_REFHOLD(vnetp->hio_fp); 15256ab6cb20SWENTAO YANG RW_EXIT(&vnetp->vsw_fp_rw); 15266ab6cb20SWENTAO YANG vnet_hio_get_stats(vnetp->hio_fp, &statsp); 15276ab6cb20SWENTAO YANG VNET_FDBE_REFRELE(vnetp->hio_fp); 15286ab6cb20SWENTAO YANG 15296ab6cb20SWENTAO YANG hiokp = (vnet_hio_kstats_t *)ksp->ks_data; 15306ab6cb20SWENTAO YANG 15316ab6cb20SWENTAO YANG if (rw == KSTAT_READ) { 15326ab6cb20SWENTAO YANG /* Link Input/Output stats */ 15336ab6cb20SWENTAO YANG hiokp->ipackets.value.ul = (uint32_t)statsp.ipackets; 15346ab6cb20SWENTAO YANG hiokp->ipackets64.value.ull = statsp.ipackets; 15356ab6cb20SWENTAO YANG hiokp->ierrors.value.ul = statsp.ierrors; 15366ab6cb20SWENTAO YANG hiokp->opackets.value.ul = (uint32_t)statsp.opackets; 15376ab6cb20SWENTAO YANG hiokp->opackets64.value.ull = statsp.opackets; 15386ab6cb20SWENTAO YANG hiokp->oerrors.value.ul = statsp.oerrors; 15396ab6cb20SWENTAO YANG 15406ab6cb20SWENTAO YANG /* MIB II kstat variables */ 15416ab6cb20SWENTAO YANG hiokp->rbytes.value.ul = (uint32_t)statsp.rbytes; 15426ab6cb20SWENTAO YANG hiokp->rbytes64.value.ull = statsp.rbytes; 15436ab6cb20SWENTAO YANG hiokp->obytes.value.ul = (uint32_t)statsp.obytes; 15446ab6cb20SWENTAO YANG hiokp->obytes64.value.ull = statsp.obytes; 15456ab6cb20SWENTAO YANG hiokp->multircv.value.ul = statsp.multircv; 15466ab6cb20SWENTAO YANG hiokp->multixmt.value.ul = statsp.multixmt; 15476ab6cb20SWENTAO YANG hiokp->brdcstrcv.value.ul = statsp.brdcstrcv; 15486ab6cb20SWENTAO YANG hiokp->brdcstxmt.value.ul = statsp.brdcstxmt; 15496ab6cb20SWENTAO YANG hiokp->norcvbuf.value.ul = statsp.norcvbuf; 15506ab6cb20SWENTAO YANG hiokp->noxmtbuf.value.ul = statsp.noxmtbuf; 15516ab6cb20SWENTAO YANG } else { 15526ab6cb20SWENTAO YANG return (EACCES); 15536ab6cb20SWENTAO YANG } 15546ab6cb20SWENTAO YANG 15556ab6cb20SWENTAO YANG return (0); 15566ab6cb20SWENTAO YANG } 15576ab6cb20SWENTAO YANG 15586ab6cb20SWENTAO YANG static void 15596ab6cb20SWENTAO YANG vnet_hio_get_stats(vnet_res_t *vresp, vnet_hio_stats_t *statsp) 15606ab6cb20SWENTAO YANG { 15616ab6cb20SWENTAO YANG mac_register_t *macp; 15626ab6cb20SWENTAO YANG mac_callbacks_t *cbp; 15636ab6cb20SWENTAO YANG uint64_t val; 15646ab6cb20SWENTAO YANG int stat; 15656ab6cb20SWENTAO YANG 15666ab6cb20SWENTAO YANG /* 15676ab6cb20SWENTAO YANG * get the specified statistics from the underlying nxge. 15686ab6cb20SWENTAO YANG */ 15696ab6cb20SWENTAO YANG macp = &vresp->macreg; 15706ab6cb20SWENTAO YANG cbp = macp->m_callbacks; 15716ab6cb20SWENTAO YANG for (stat = MAC_STAT_MIN; stat < MAC_STAT_OVERFLOWS; stat++) { 15726ab6cb20SWENTAO YANG if (cbp->mc_getstat(macp->m_driver, stat, &val) == 0) { 15736ab6cb20SWENTAO YANG switch (stat) { 15746ab6cb20SWENTAO YANG case MAC_STAT_IPACKETS: 15756ab6cb20SWENTAO YANG statsp->ipackets = val; 15766ab6cb20SWENTAO YANG break; 15776ab6cb20SWENTAO YANG 15786ab6cb20SWENTAO YANG case MAC_STAT_IERRORS: 15796ab6cb20SWENTAO YANG statsp->ierrors = val; 15806ab6cb20SWENTAO YANG break; 15816ab6cb20SWENTAO YANG 15826ab6cb20SWENTAO YANG case MAC_STAT_OPACKETS: 15836ab6cb20SWENTAO YANG statsp->opackets = val; 15846ab6cb20SWENTAO YANG break; 15856ab6cb20SWENTAO YANG 15866ab6cb20SWENTAO YANG case MAC_STAT_OERRORS: 15876ab6cb20SWENTAO YANG statsp->oerrors = val; 15886ab6cb20SWENTAO YANG break; 15896ab6cb20SWENTAO YANG 15906ab6cb20SWENTAO YANG case MAC_STAT_RBYTES: 15916ab6cb20SWENTAO YANG statsp->rbytes = val; 15926ab6cb20SWENTAO YANG break; 15936ab6cb20SWENTAO YANG 15946ab6cb20SWENTAO YANG case MAC_STAT_OBYTES: 15956ab6cb20SWENTAO YANG statsp->obytes = val; 15966ab6cb20SWENTAO YANG break; 15976ab6cb20SWENTAO YANG 15986ab6cb20SWENTAO YANG case MAC_STAT_MULTIRCV: 15996ab6cb20SWENTAO YANG statsp->multircv = val; 16006ab6cb20SWENTAO YANG break; 16016ab6cb20SWENTAO YANG 16026ab6cb20SWENTAO YANG case MAC_STAT_MULTIXMT: 16036ab6cb20SWENTAO YANG statsp->multixmt = val; 16046ab6cb20SWENTAO YANG break; 16056ab6cb20SWENTAO YANG 16066ab6cb20SWENTAO YANG case MAC_STAT_BRDCSTRCV: 16076ab6cb20SWENTAO YANG statsp->brdcstrcv = val; 16086ab6cb20SWENTAO YANG break; 16096ab6cb20SWENTAO YANG 16106ab6cb20SWENTAO YANG case MAC_STAT_BRDCSTXMT: 16116ab6cb20SWENTAO YANG statsp->brdcstxmt = val; 16126ab6cb20SWENTAO YANG break; 16136ab6cb20SWENTAO YANG 16146ab6cb20SWENTAO YANG case MAC_STAT_NOXMTBUF: 16156ab6cb20SWENTAO YANG statsp->noxmtbuf = val; 16166ab6cb20SWENTAO YANG break; 16176ab6cb20SWENTAO YANG 16186ab6cb20SWENTAO YANG case MAC_STAT_NORCVBUF: 16196ab6cb20SWENTAO YANG statsp->norcvbuf = val; 16206ab6cb20SWENTAO YANG break; 16216ab6cb20SWENTAO YANG 16226ab6cb20SWENTAO YANG default: 16236ab6cb20SWENTAO YANG /* 16246ab6cb20SWENTAO YANG * parameters not interested. 16256ab6cb20SWENTAO YANG */ 16266ab6cb20SWENTAO YANG break; 16276ab6cb20SWENTAO YANG } 16286ab6cb20SWENTAO YANG } 16296ab6cb20SWENTAO YANG } 16306ab6cb20SWENTAO YANG } 1631