11991Sheppo /* 21991Sheppo * CDDL HEADER START 31991Sheppo * 41991Sheppo * The contents of this file are subject to the terms of the 51991Sheppo * Common Development and Distribution License (the "License"). 61991Sheppo * You may not use this file except in compliance with the License. 71991Sheppo * 81991Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91991Sheppo * or http://www.opensolaris.org/os/licensing. 101991Sheppo * See the License for the specific language governing permissions 111991Sheppo * and limitations under the License. 121991Sheppo * 131991Sheppo * When distributing Covered Code, include this CDDL HEADER in each 141991Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151991Sheppo * If applicable, add the following below this CDDL HEADER, with the 161991Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 171991Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 181991Sheppo * 191991Sheppo * CDDL HEADER END 201991Sheppo */ 211991Sheppo 221991Sheppo /* 236419Ssb155480 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 241991Sheppo * Use is subject to license terms. 251991Sheppo */ 261991Sheppo 271991Sheppo #include <sys/types.h> 281991Sheppo #include <sys/errno.h> 291991Sheppo #include <sys/param.h> 301991Sheppo #include <sys/stream.h> 311991Sheppo #include <sys/kmem.h> 321991Sheppo #include <sys/conf.h> 331991Sheppo #include <sys/devops.h> 341991Sheppo #include <sys/ksynch.h> 351991Sheppo #include <sys/stat.h> 361991Sheppo #include <sys/modctl.h> 376419Ssb155480 #include <sys/modhash.h> 381991Sheppo #include <sys/debug.h> 391991Sheppo #include <sys/ethernet.h> 401991Sheppo #include <sys/dlpi.h> 411991Sheppo #include <net/if.h> 421991Sheppo #include <sys/mac.h> 432311Sseb #include <sys/mac_ether.h> 441991Sheppo #include <sys/ddi.h> 451991Sheppo #include <sys/sunddi.h> 461991Sheppo #include <sys/strsun.h> 471991Sheppo #include <sys/note.h> 486419Ssb155480 #include <sys/atomic.h> 491991Sheppo #include <sys/vnet.h> 506419Ssb155480 #include <sys/vlan.h> 516495Sspeer #include <sys/vnet_mailbox.h> 526495Sspeer #include <sys/vnet_common.h> 536495Sspeer #include <sys/dds.h> 546495Sspeer #include <sys/strsubr.h> 556495Sspeer #include <sys/taskq.h> 561991Sheppo 571991Sheppo /* 581991Sheppo * Function prototypes. 591991Sheppo */ 601991Sheppo 611991Sheppo /* DDI entrypoints */ 621991Sheppo static int vnetdevinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 631991Sheppo static int vnetattach(dev_info_t *, ddi_attach_cmd_t); 641991Sheppo static int vnetdetach(dev_info_t *, ddi_detach_cmd_t); 651991Sheppo 661991Sheppo /* MAC entrypoints */ 672311Sseb static int vnet_m_stat(void *, uint_t, uint64_t *); 681991Sheppo static int vnet_m_start(void *); 691991Sheppo static void vnet_m_stop(void *); 701991Sheppo static int vnet_m_promisc(void *, boolean_t); 711991Sheppo static int vnet_m_multicst(void *, boolean_t, const uint8_t *); 721991Sheppo static int vnet_m_unicst(void *, const uint8_t *); 731991Sheppo mblk_t *vnet_m_tx(void *, mblk_t *); 741991Sheppo 751991Sheppo /* vnet internal functions */ 761991Sheppo static int vnet_mac_register(vnet_t *); 771991Sheppo static int vnet_read_mac_address(vnet_t *vnetp); 781991Sheppo 796419Ssb155480 /* Forwarding database (FDB) routines */ 806419Ssb155480 static void vnet_fdb_create(vnet_t *vnetp); 816419Ssb155480 static void vnet_fdb_destroy(vnet_t *vnetp); 826495Sspeer static vnet_res_t *vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp); 836419Ssb155480 static void vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val); 846495Sspeer void vnet_fdbe_add(vnet_t *vnetp, vnet_res_t *vresp); 856495Sspeer static void vnet_fdbe_del(vnet_t *vnetp, vnet_res_t *vresp); 866495Sspeer 87*7896SSriharsha.Basavapatna@Sun.COM static void vnet_rx_frames_untag(uint16_t pvid, mblk_t **mp); 886495Sspeer static void vnet_rx(vio_net_handle_t vrh, mblk_t *mp); 896495Sspeer static void vnet_tx_update(vio_net_handle_t vrh); 906495Sspeer static void vnet_res_start_task(void *arg); 916495Sspeer static void vnet_start_resources(vnet_t *vnetp); 926495Sspeer static void vnet_stop_resources(vnet_t *vnetp); 936495Sspeer static void vnet_dispatch_res_task(vnet_t *vnetp); 946495Sspeer static void vnet_res_start_task(void *arg); 956495Sspeer static void vnet_handle_res_err(vio_net_handle_t vrh, vio_net_err_val_t err); 967529SSriharsha.Basavapatna@Sun.COM int vnet_mtu_update(vnet_t *vnetp, uint32_t mtu); 976419Ssb155480 986495Sspeer /* Exported to to vnet_dds */ 996495Sspeer int vnet_send_dds_msg(vnet_t *vnetp, void *dmsg); 1001991Sheppo 1016495Sspeer /* Externs that are imported from vnet_gen */ 1026495Sspeer extern int vgen_init(void *vnetp, uint64_t regprop, dev_info_t *vnetdip, 1036495Sspeer const uint8_t *macaddr, void **vgenhdl); 1042336Snarayan extern int vgen_uninit(void *arg); 1056495Sspeer extern int vgen_dds_tx(void *arg, void *dmsg); 1066495Sspeer 1076495Sspeer /* Externs that are imported from vnet_dds */ 1086495Sspeer extern void vdds_mod_init(void); 1096495Sspeer extern void vdds_mod_fini(void); 1106495Sspeer extern int vdds_init(vnet_t *vnetp); 1116495Sspeer extern void vdds_cleanup(vnet_t *vnetp); 1126495Sspeer extern void vdds_process_dds_msg(vnet_t *vnetp, vio_dds_msg_t *dmsg); 1137819SRaghuram.Kothakota@Sun.COM extern void vdds_cleanup_hybrid_res(void *arg); 1141991Sheppo 1156419Ssb155480 #define VNET_FDBE_REFHOLD(p) \ 1166419Ssb155480 { \ 1176419Ssb155480 atomic_inc_32(&(p)->refcnt); \ 1186419Ssb155480 ASSERT((p)->refcnt != 0); \ 1196419Ssb155480 } 1206419Ssb155480 1216419Ssb155480 #define VNET_FDBE_REFRELE(p) \ 1226419Ssb155480 { \ 1236419Ssb155480 ASSERT((p)->refcnt != 0); \ 1246419Ssb155480 atomic_dec_32(&(p)->refcnt); \ 1256419Ssb155480 } 1266419Ssb155480 1272311Sseb static mac_callbacks_t vnet_m_callbacks = { 1282311Sseb 0, 1292311Sseb vnet_m_stat, 1302311Sseb vnet_m_start, 1312311Sseb vnet_m_stop, 1322311Sseb vnet_m_promisc, 1332311Sseb vnet_m_multicst, 1342311Sseb vnet_m_unicst, 1352311Sseb vnet_m_tx, 1362311Sseb NULL, 1372311Sseb NULL, 1382311Sseb NULL 1392311Sseb }; 1402311Sseb 1411991Sheppo /* 1421991Sheppo * Linked list of "vnet_t" structures - one per instance. 1431991Sheppo */ 1441991Sheppo static vnet_t *vnet_headp = NULL; 1451991Sheppo static krwlock_t vnet_rw; 1461991Sheppo 1471991Sheppo /* Tunables */ 1481991Sheppo uint32_t vnet_ntxds = VNET_NTXDS; /* power of 2 transmit descriptors */ 1491991Sheppo uint32_t vnet_ldcwd_interval = VNET_LDCWD_INTERVAL; /* watchdog freq in msec */ 1501991Sheppo uint32_t vnet_ldcwd_txtimeout = VNET_LDCWD_TXTIMEOUT; /* tx timeout in msec */ 1512410Slm66018 uint32_t vnet_ldc_mtu = VNET_LDC_MTU; /* ldc mtu */ 1526419Ssb155480 1537529SSriharsha.Basavapatna@Sun.COM /* 1547529SSriharsha.Basavapatna@Sun.COM * Set this to non-zero to enable additional internal receive buffer pools 1557529SSriharsha.Basavapatna@Sun.COM * based on the MTU of the device for better performance at the cost of more 1567529SSriharsha.Basavapatna@Sun.COM * memory consumption. This is turned off by default, to use allocb(9F) for 1577529SSriharsha.Basavapatna@Sun.COM * receive buffer allocations of sizes > 2K. 1587529SSriharsha.Basavapatna@Sun.COM */ 1597529SSriharsha.Basavapatna@Sun.COM boolean_t vnet_jumbo_rxpools = B_FALSE; 1607529SSriharsha.Basavapatna@Sun.COM 1616419Ssb155480 /* # of chains in fdb hash table */ 1626419Ssb155480 uint32_t vnet_fdb_nchains = VNET_NFDB_HASH; 1636419Ssb155480 1646419Ssb155480 /* Internal tunables */ 1656419Ssb155480 uint32_t vnet_ethermtu = 1500; /* mtu of the device */ 1666419Ssb155480 1676419Ssb155480 /* 1686419Ssb155480 * Default vlan id. This is only used internally when the "default-vlan-id" 1696419Ssb155480 * property is not present in the MD device node. Therefore, this should not be 1706419Ssb155480 * used as a tunable; if this value is changed, the corresponding variable 1716419Ssb155480 * should be updated to the same value in vsw and also other vnets connected to 1726419Ssb155480 * the same vsw. 1736419Ssb155480 */ 1746419Ssb155480 uint16_t vnet_default_vlan_id = 1; 1756419Ssb155480 1766419Ssb155480 /* delay in usec to wait for all references on a fdb entry to be dropped */ 1776419Ssb155480 uint32_t vnet_fdbe_refcnt_delay = 10; 1781991Sheppo 1796495Sspeer static struct ether_addr etherbroadcastaddr = { 1806495Sspeer 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 1816495Sspeer }; 1826495Sspeer 1836495Sspeer 1841991Sheppo /* 1851991Sheppo * Property names 1861991Sheppo */ 1871991Sheppo static char macaddr_propname[] = "local-mac-address"; 1881991Sheppo 1891991Sheppo /* 1901991Sheppo * This is the string displayed by modinfo(1m). 1911991Sheppo */ 1927529SSriharsha.Basavapatna@Sun.COM static char vnet_ident[] = "vnet driver"; 1931991Sheppo extern struct mod_ops mod_driverops; 1941991Sheppo static struct cb_ops cb_vnetops = { 1951991Sheppo nulldev, /* cb_open */ 1961991Sheppo nulldev, /* cb_close */ 1971991Sheppo nodev, /* cb_strategy */ 1981991Sheppo nodev, /* cb_print */ 1991991Sheppo nodev, /* cb_dump */ 2001991Sheppo nodev, /* cb_read */ 2011991Sheppo nodev, /* cb_write */ 2021991Sheppo nodev, /* cb_ioctl */ 2031991Sheppo nodev, /* cb_devmap */ 2041991Sheppo nodev, /* cb_mmap */ 2051991Sheppo nodev, /* cb_segmap */ 2061991Sheppo nochpoll, /* cb_chpoll */ 2071991Sheppo ddi_prop_op, /* cb_prop_op */ 2081991Sheppo NULL, /* cb_stream */ 2091991Sheppo (int)(D_MP) /* cb_flag */ 2101991Sheppo }; 2111991Sheppo 2121991Sheppo static struct dev_ops vnetops = { 2131991Sheppo DEVO_REV, /* devo_rev */ 2141991Sheppo 0, /* devo_refcnt */ 2151991Sheppo NULL, /* devo_getinfo */ 2161991Sheppo nulldev, /* devo_identify */ 2171991Sheppo nulldev, /* devo_probe */ 2181991Sheppo vnetattach, /* devo_attach */ 2191991Sheppo vnetdetach, /* devo_detach */ 2201991Sheppo nodev, /* devo_reset */ 2211991Sheppo &cb_vnetops, /* devo_cb_ops */ 2227656SSherry.Moore@Sun.COM (struct bus_ops *)NULL, /* devo_bus_ops */ 2237656SSherry.Moore@Sun.COM NULL, /* devo_power */ 2247656SSherry.Moore@Sun.COM ddi_quiesce_not_supported, /* devo_quiesce */ 2251991Sheppo }; 2261991Sheppo 2271991Sheppo static struct modldrv modldrv = { 2281991Sheppo &mod_driverops, /* Type of module. This one is a driver */ 2291991Sheppo vnet_ident, /* ID string */ 2301991Sheppo &vnetops /* driver specific ops */ 2311991Sheppo }; 2321991Sheppo 2331991Sheppo static struct modlinkage modlinkage = { 2341991Sheppo MODREV_1, (void *)&modldrv, NULL 2351991Sheppo }; 2361991Sheppo 2374647Sraghuram #ifdef DEBUG 2381991Sheppo 2391991Sheppo /* 2401991Sheppo * Print debug messages - set to 0xf to enable all msgs 2411991Sheppo */ 2424647Sraghuram int vnet_dbglevel = 0x8; 2431991Sheppo 2444647Sraghuram static void 2454647Sraghuram debug_printf(const char *fname, void *arg, const char *fmt, ...) 2461991Sheppo { 2471991Sheppo char buf[512]; 2481991Sheppo va_list ap; 2491991Sheppo vnet_t *vnetp = (vnet_t *)arg; 2504647Sraghuram char *bufp = buf; 2511991Sheppo 2524647Sraghuram if (vnetp == NULL) { 2534647Sraghuram (void) sprintf(bufp, "%s: ", fname); 2544647Sraghuram bufp += strlen(bufp); 2554647Sraghuram } else { 2564647Sraghuram (void) sprintf(bufp, "vnet%d:%s: ", vnetp->instance, fname); 2574647Sraghuram bufp += strlen(bufp); 2584647Sraghuram } 2594647Sraghuram va_start(ap, fmt); 2604647Sraghuram (void) vsprintf(bufp, fmt, ap); 2614647Sraghuram va_end(ap); 2624647Sraghuram cmn_err(CE_CONT, "%s\n", buf); 2634647Sraghuram } 2641991Sheppo 2651991Sheppo #endif 2661991Sheppo 2671991Sheppo /* _init(9E): initialize the loadable module */ 2681991Sheppo int 2691991Sheppo _init(void) 2701991Sheppo { 2711991Sheppo int status; 2721991Sheppo 2734647Sraghuram DBG1(NULL, "enter\n"); 2741991Sheppo 2751991Sheppo mac_init_ops(&vnetops, "vnet"); 2761991Sheppo status = mod_install(&modlinkage); 2771991Sheppo if (status != 0) { 2781991Sheppo mac_fini_ops(&vnetops); 2791991Sheppo } 2806495Sspeer vdds_mod_init(); 2814647Sraghuram DBG1(NULL, "exit(%d)\n", status); 2821991Sheppo return (status); 2831991Sheppo } 2841991Sheppo 2851991Sheppo /* _fini(9E): prepare the module for unloading. */ 2861991Sheppo int 2871991Sheppo _fini(void) 2881991Sheppo { 2891991Sheppo int status; 2901991Sheppo 2914647Sraghuram DBG1(NULL, "enter\n"); 2921991Sheppo 2931991Sheppo status = mod_remove(&modlinkage); 2941991Sheppo if (status != 0) 2951991Sheppo return (status); 2961991Sheppo mac_fini_ops(&vnetops); 2976495Sspeer vdds_mod_fini(); 2981991Sheppo 2994647Sraghuram DBG1(NULL, "exit(%d)\n", status); 3001991Sheppo return (status); 3011991Sheppo } 3021991Sheppo 3031991Sheppo /* _info(9E): return information about the loadable module */ 3041991Sheppo int 3051991Sheppo _info(struct modinfo *modinfop) 3061991Sheppo { 3071991Sheppo return (mod_info(&modlinkage, modinfop)); 3081991Sheppo } 3091991Sheppo 3101991Sheppo /* 3111991Sheppo * attach(9E): attach a device to the system. 3121991Sheppo * called once for each instance of the device on the system. 3131991Sheppo */ 3141991Sheppo static int 3151991Sheppo vnetattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 3161991Sheppo { 3171991Sheppo vnet_t *vnetp; 3186495Sspeer int status; 3191991Sheppo int instance; 3206495Sspeer uint64_t reg; 3216495Sspeer char qname[TASKQ_NAMELEN]; 3224647Sraghuram enum { AST_init = 0x0, AST_vnet_alloc = 0x1, 3234647Sraghuram AST_mac_alloc = 0x2, AST_read_macaddr = 0x4, 3246495Sspeer AST_vgen_init = 0x8, AST_fdbh_alloc = 0x10, 3256495Sspeer AST_vdds_init = 0x20, AST_taskq_create = 0x40, 3266495Sspeer AST_vnet_list = 0x80 } attach_state; 3271991Sheppo 3281991Sheppo attach_state = AST_init; 3291991Sheppo 3301991Sheppo switch (cmd) { 3311991Sheppo case DDI_ATTACH: 3321991Sheppo break; 3331991Sheppo case DDI_RESUME: 3341991Sheppo case DDI_PM_RESUME: 3351991Sheppo default: 3361991Sheppo goto vnet_attach_fail; 3371991Sheppo } 3381991Sheppo 3391991Sheppo instance = ddi_get_instance(dip); 3404647Sraghuram DBG1(NULL, "instance(%d) enter\n", instance); 3411991Sheppo 3421991Sheppo /* allocate vnet_t and mac_t structures */ 3431991Sheppo vnetp = kmem_zalloc(sizeof (vnet_t), KM_SLEEP); 3446495Sspeer vnetp->dip = dip; 3456495Sspeer vnetp->instance = instance; 3466495Sspeer rw_init(&vnetp->vrwlock, NULL, RW_DRIVER, NULL); 3476495Sspeer rw_init(&vnetp->vsw_fp_rw, NULL, RW_DRIVER, NULL); 3481991Sheppo attach_state |= AST_vnet_alloc; 3491991Sheppo 3506495Sspeer status = vdds_init(vnetp); 3516495Sspeer if (status != 0) { 3526495Sspeer goto vnet_attach_fail; 3536495Sspeer } 3546495Sspeer attach_state |= AST_vdds_init; 3556495Sspeer 3561991Sheppo /* setup links to vnet_t from both devinfo and mac_t */ 3571991Sheppo ddi_set_driver_private(dip, (caddr_t)vnetp); 3581991Sheppo 3591991Sheppo /* read the mac address */ 3601991Sheppo status = vnet_read_mac_address(vnetp); 3611991Sheppo if (status != DDI_SUCCESS) { 3621991Sheppo goto vnet_attach_fail; 3631991Sheppo } 3641991Sheppo attach_state |= AST_read_macaddr; 3651991Sheppo 3666495Sspeer reg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 3676495Sspeer DDI_PROP_DONTPASS, "reg", -1); 3686495Sspeer if (reg == -1) { 3696495Sspeer goto vnet_attach_fail; 3706495Sspeer } 3716495Sspeer vnetp->reg = reg; 3726495Sspeer 3736495Sspeer vnet_fdb_create(vnetp); 3746495Sspeer attach_state |= AST_fdbh_alloc; 3756495Sspeer 3766495Sspeer (void) snprintf(qname, TASKQ_NAMELEN, "vnet_taskq%d", instance); 3776495Sspeer if ((vnetp->taskqp = ddi_taskq_create(dip, qname, 1, 3786495Sspeer TASKQ_DEFAULTPRI, 0)) == NULL) { 3796495Sspeer cmn_err(CE_WARN, "!vnet%d: Unable to create task queue", 3806495Sspeer instance); 3816495Sspeer goto vnet_attach_fail; 3826495Sspeer } 3836495Sspeer attach_state |= AST_taskq_create; 3846495Sspeer 3856495Sspeer /* add to the list of vnet devices */ 3866495Sspeer WRITE_ENTER(&vnet_rw); 3876495Sspeer vnetp->nextp = vnet_headp; 3886495Sspeer vnet_headp = vnetp; 3896495Sspeer RW_EXIT(&vnet_rw); 3906495Sspeer 3916495Sspeer attach_state |= AST_vnet_list; 3926495Sspeer 3931991Sheppo /* 3946495Sspeer * Initialize the generic vnet plugin which provides 3956495Sspeer * communication via sun4v LDC (logical domain channel) based 3966495Sspeer * resources. It will register the LDC resources as and when 3976495Sspeer * they become available. 3981991Sheppo */ 3996495Sspeer status = vgen_init(vnetp, reg, vnetp->dip, 4006495Sspeer (uint8_t *)vnetp->curr_macaddr, &vnetp->vgenhdl); 4011991Sheppo if (status != DDI_SUCCESS) { 4024647Sraghuram DERR(vnetp, "vgen_init() failed\n"); 4031991Sheppo goto vnet_attach_fail; 4041991Sheppo } 4051991Sheppo attach_state |= AST_vgen_init; 4061991Sheppo 4071991Sheppo /* register with MAC layer */ 4081991Sheppo status = vnet_mac_register(vnetp); 4091991Sheppo if (status != DDI_SUCCESS) { 4101991Sheppo goto vnet_attach_fail; 4111991Sheppo } 4121991Sheppo 4134647Sraghuram DBG1(NULL, "instance(%d) exit\n", instance); 4141991Sheppo return (DDI_SUCCESS); 4151991Sheppo 4161991Sheppo vnet_attach_fail: 4176495Sspeer 4186495Sspeer if (attach_state & AST_vnet_list) { 4196495Sspeer vnet_t **vnetpp; 4206495Sspeer /* unlink from instance(vnet_t) list */ 4216495Sspeer WRITE_ENTER(&vnet_rw); 4226495Sspeer for (vnetpp = &vnet_headp; *vnetpp; 4236495Sspeer vnetpp = &(*vnetpp)->nextp) { 4246495Sspeer if (*vnetpp == vnetp) { 4256495Sspeer *vnetpp = vnetp->nextp; 4266495Sspeer break; 4276495Sspeer } 4286495Sspeer } 4296495Sspeer RW_EXIT(&vnet_rw); 4306495Sspeer } 4316495Sspeer 4326495Sspeer if (attach_state & AST_vdds_init) { 4336495Sspeer vdds_cleanup(vnetp); 4346495Sspeer } 4356495Sspeer if (attach_state & AST_taskq_create) { 4366495Sspeer ddi_taskq_destroy(vnetp->taskqp); 4376495Sspeer } 4381991Sheppo if (attach_state & AST_fdbh_alloc) { 4396419Ssb155480 vnet_fdb_destroy(vnetp); 4401991Sheppo } 4411991Sheppo if (attach_state & AST_vgen_init) { 4426495Sspeer (void) vgen_uninit(vnetp->vgenhdl); 4431991Sheppo } 4441991Sheppo if (attach_state & AST_vnet_alloc) { 4456495Sspeer rw_destroy(&vnetp->vrwlock); 4466495Sspeer rw_destroy(&vnetp->vsw_fp_rw); 4471991Sheppo KMEM_FREE(vnetp); 4481991Sheppo } 4491991Sheppo return (DDI_FAILURE); 4501991Sheppo } 4511991Sheppo 4521991Sheppo /* 4531991Sheppo * detach(9E): detach a device from the system. 4541991Sheppo */ 4551991Sheppo static int 4561991Sheppo vnetdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4571991Sheppo { 4581991Sheppo vnet_t *vnetp; 4591991Sheppo vnet_t **vnetpp; 4601991Sheppo int instance; 4612336Snarayan int rv; 4621991Sheppo 4631991Sheppo instance = ddi_get_instance(dip); 4644647Sraghuram DBG1(NULL, "instance(%d) enter\n", instance); 4651991Sheppo 4661991Sheppo vnetp = ddi_get_driver_private(dip); 4671991Sheppo if (vnetp == NULL) { 4681991Sheppo goto vnet_detach_fail; 4691991Sheppo } 4701991Sheppo 4711991Sheppo switch (cmd) { 4721991Sheppo case DDI_DETACH: 4731991Sheppo break; 4741991Sheppo case DDI_SUSPEND: 4751991Sheppo case DDI_PM_SUSPEND: 4761991Sheppo default: 4771991Sheppo goto vnet_detach_fail; 4781991Sheppo } 4791991Sheppo 4806495Sspeer (void) vdds_cleanup(vnetp); 4816495Sspeer rv = vgen_uninit(vnetp->vgenhdl); 4826495Sspeer if (rv != DDI_SUCCESS) { 4836495Sspeer goto vnet_detach_fail; 4842336Snarayan } 4852336Snarayan 4861991Sheppo /* 4871991Sheppo * Unregister from the MAC subsystem. This can fail, in 4881991Sheppo * particular if there are DLPI style-2 streams still open - 4891991Sheppo * in which case we just return failure. 4901991Sheppo */ 4912311Sseb if (mac_unregister(vnetp->mh) != 0) 4921991Sheppo goto vnet_detach_fail; 4931991Sheppo 4941991Sheppo /* unlink from instance(vnet_t) list */ 4951991Sheppo WRITE_ENTER(&vnet_rw); 4961991Sheppo for (vnetpp = &vnet_headp; *vnetpp; vnetpp = &(*vnetpp)->nextp) { 4971991Sheppo if (*vnetpp == vnetp) { 4981991Sheppo *vnetpp = vnetp->nextp; 4991991Sheppo break; 5001991Sheppo } 5011991Sheppo } 5021991Sheppo RW_EXIT(&vnet_rw); 5031991Sheppo 5046495Sspeer ddi_taskq_destroy(vnetp->taskqp); 5056419Ssb155480 /* destroy fdb */ 5066419Ssb155480 vnet_fdb_destroy(vnetp); 5073297Ssb155480 5086495Sspeer rw_destroy(&vnetp->vrwlock); 5096495Sspeer rw_destroy(&vnetp->vsw_fp_rw); 5101991Sheppo KMEM_FREE(vnetp); 5111991Sheppo 5121991Sheppo return (DDI_SUCCESS); 5131991Sheppo 5141991Sheppo vnet_detach_fail: 5151991Sheppo return (DDI_FAILURE); 5161991Sheppo } 5171991Sheppo 5181991Sheppo /* enable the device for transmit/receive */ 5191991Sheppo static int 5201991Sheppo vnet_m_start(void *arg) 5211991Sheppo { 5221991Sheppo vnet_t *vnetp = arg; 5231991Sheppo 5244647Sraghuram DBG1(vnetp, "enter\n"); 5251991Sheppo 5266495Sspeer WRITE_ENTER(&vnetp->vrwlock); 5276495Sspeer vnetp->flags |= VNET_STARTED; 5286495Sspeer vnet_start_resources(vnetp); 5296495Sspeer RW_EXIT(&vnetp->vrwlock); 5301991Sheppo 5314647Sraghuram DBG1(vnetp, "exit\n"); 5321991Sheppo return (VNET_SUCCESS); 5331991Sheppo 5341991Sheppo } 5351991Sheppo 5361991Sheppo /* stop transmit/receive for the device */ 5371991Sheppo static void 5381991Sheppo vnet_m_stop(void *arg) 5391991Sheppo { 5401991Sheppo vnet_t *vnetp = arg; 5411991Sheppo 5424647Sraghuram DBG1(vnetp, "enter\n"); 5431991Sheppo 5446495Sspeer WRITE_ENTER(&vnetp->vrwlock); 5456495Sspeer if (vnetp->flags & VNET_STARTED) { 5466495Sspeer vnet_stop_resources(vnetp); 5476495Sspeer vnetp->flags &= ~VNET_STARTED; 5481991Sheppo } 5496495Sspeer RW_EXIT(&vnetp->vrwlock); 5501991Sheppo 5514647Sraghuram DBG1(vnetp, "exit\n"); 5521991Sheppo } 5531991Sheppo 5541991Sheppo /* set the unicast mac address of the device */ 5551991Sheppo static int 5561991Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr) 5571991Sheppo { 5581991Sheppo _NOTE(ARGUNUSED(macaddr)) 5591991Sheppo 5601991Sheppo vnet_t *vnetp = arg; 5611991Sheppo 5624647Sraghuram DBG1(vnetp, "enter\n"); 5631991Sheppo /* 5642793Slm66018 * NOTE: setting mac address dynamically is not supported. 5651991Sheppo */ 5664647Sraghuram DBG1(vnetp, "exit\n"); 5671991Sheppo 5682109Slm66018 return (VNET_FAILURE); 5691991Sheppo } 5701991Sheppo 5711991Sheppo /* enable/disable a multicast address */ 5721991Sheppo static int 5731991Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 5741991Sheppo { 5751991Sheppo _NOTE(ARGUNUSED(add, mca)) 5761991Sheppo 5771991Sheppo vnet_t *vnetp = arg; 5786495Sspeer vnet_res_t *vresp; 5796495Sspeer mac_register_t *macp; 5802311Sseb mac_callbacks_t *cbp; 5811991Sheppo int rv = VNET_SUCCESS; 5821991Sheppo 5834647Sraghuram DBG1(vnetp, "enter\n"); 5846495Sspeer 5856495Sspeer READ_ENTER(&vnetp->vrwlock); 5866495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 5876495Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 5886495Sspeer macp = &vresp->macreg; 5896495Sspeer cbp = macp->m_callbacks; 5906495Sspeer rv = cbp->mc_multicst(macp->m_driver, add, mca); 5911991Sheppo } 5921991Sheppo } 5936495Sspeer RW_EXIT(&vnetp->vrwlock); 5946495Sspeer 5954647Sraghuram DBG1(vnetp, "exit(%d)\n", rv); 5961991Sheppo return (rv); 5971991Sheppo } 5981991Sheppo 5991991Sheppo /* set or clear promiscuous mode on the device */ 6001991Sheppo static int 6011991Sheppo vnet_m_promisc(void *arg, boolean_t on) 6021991Sheppo { 6031991Sheppo _NOTE(ARGUNUSED(on)) 6041991Sheppo 6051991Sheppo vnet_t *vnetp = arg; 6064647Sraghuram DBG1(vnetp, "enter\n"); 6071991Sheppo /* 6082793Slm66018 * NOTE: setting promiscuous mode is not supported, just return success. 6091991Sheppo */ 6104647Sraghuram DBG1(vnetp, "exit\n"); 6111991Sheppo return (VNET_SUCCESS); 6121991Sheppo } 6131991Sheppo 6141991Sheppo /* 6151991Sheppo * Transmit a chain of packets. This function provides switching functionality 6161991Sheppo * based on the destination mac address to reach other guests (within ldoms) or 6171991Sheppo * external hosts. 6181991Sheppo */ 6191991Sheppo mblk_t * 6201991Sheppo vnet_m_tx(void *arg, mblk_t *mp) 6211991Sheppo { 6226419Ssb155480 vnet_t *vnetp; 6236495Sspeer vnet_res_t *vresp; 6246419Ssb155480 mblk_t *next; 6256495Sspeer mblk_t *resid_mp; 6266495Sspeer mac_register_t *macp; 6276495Sspeer struct ether_header *ehp; 6286495Sspeer boolean_t is_unicast; 629*7896SSriharsha.Basavapatna@Sun.COM boolean_t is_pvid; /* non-default pvid ? */ 630*7896SSriharsha.Basavapatna@Sun.COM boolean_t hres; /* Hybrid resource ? */ 6311991Sheppo 6321991Sheppo vnetp = (vnet_t *)arg; 6334647Sraghuram DBG1(vnetp, "enter\n"); 6341991Sheppo ASSERT(mp != NULL); 6351991Sheppo 636*7896SSriharsha.Basavapatna@Sun.COM is_pvid = (vnetp->pvid != vnetp->default_vlan_id) ? B_TRUE : B_FALSE; 637*7896SSriharsha.Basavapatna@Sun.COM 6381991Sheppo while (mp != NULL) { 6396419Ssb155480 6401991Sheppo next = mp->b_next; 6411991Sheppo mp->b_next = NULL; 6421991Sheppo 6436419Ssb155480 /* 6446419Ssb155480 * Find fdb entry for the destination 6456419Ssb155480 * and hold a reference to it. 6466419Ssb155480 */ 6471991Sheppo ehp = (struct ether_header *)mp->b_rptr; 6486495Sspeer vresp = vnet_fdbe_find(vnetp, &ehp->ether_dhost); 6496495Sspeer if (vresp != NULL) { 6501991Sheppo 6511991Sheppo /* 6526419Ssb155480 * Destination found in FDB. 6536419Ssb155480 * The destination is a vnet device within ldoms 6546419Ssb155480 * and directly reachable, invoke the tx function 6556419Ssb155480 * in the fdb entry. 6561991Sheppo */ 6576495Sspeer macp = &vresp->macreg; 6586495Sspeer resid_mp = macp->m_callbacks->mc_tx(macp->m_driver, mp); 6596419Ssb155480 6606419Ssb155480 /* tx done; now release ref on fdb entry */ 6616495Sspeer VNET_FDBE_REFRELE(vresp); 6626419Ssb155480 6631991Sheppo if (resid_mp != NULL) { 6641991Sheppo /* m_tx failed */ 6651991Sheppo mp->b_next = next; 6661991Sheppo break; 6671991Sheppo } 6681991Sheppo } else { 6696495Sspeer is_unicast = !(IS_BROADCAST(ehp) || 6706495Sspeer (IS_MULTICAST(ehp))); 6711991Sheppo /* 6726419Ssb155480 * Destination is not in FDB. 6736495Sspeer * If the destination is broadcast or multicast, 6746495Sspeer * then forward the packet to vswitch. 6756495Sspeer * If a Hybrid resource avilable, then send the 6766495Sspeer * unicast packet via hybrid resource, otherwise 6776495Sspeer * forward it to vswitch. 6781991Sheppo */ 6796419Ssb155480 READ_ENTER(&vnetp->vsw_fp_rw); 6806419Ssb155480 6816495Sspeer if ((is_unicast) && (vnetp->hio_fp != NULL)) { 6826495Sspeer vresp = vnetp->hio_fp; 683*7896SSriharsha.Basavapatna@Sun.COM hres = B_TRUE; 6846495Sspeer } else { 6856495Sspeer vresp = vnetp->vsw_fp; 686*7896SSriharsha.Basavapatna@Sun.COM hres = B_FALSE; 6876495Sspeer } 6886495Sspeer if (vresp == NULL) { 6896419Ssb155480 /* 6906419Ssb155480 * no fdb entry to vsw? drop the packet. 6916419Ssb155480 */ 6926419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 6931991Sheppo freemsg(mp); 6946419Ssb155480 mp = next; 6956419Ssb155480 continue; 6961991Sheppo } 6976419Ssb155480 6986419Ssb155480 /* ref hold the fdb entry to vsw */ 6996495Sspeer VNET_FDBE_REFHOLD(vresp); 7006419Ssb155480 7016419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 7026419Ssb155480 703*7896SSriharsha.Basavapatna@Sun.COM /* 704*7896SSriharsha.Basavapatna@Sun.COM * In the case of a hybrid resource we need to insert 705*7896SSriharsha.Basavapatna@Sun.COM * the tag for the pvid case here; unlike packets that 706*7896SSriharsha.Basavapatna@Sun.COM * are destined to a vnet/vsw in which case the vgen 707*7896SSriharsha.Basavapatna@Sun.COM * layer does the tagging before sending it over ldc. 708*7896SSriharsha.Basavapatna@Sun.COM */ 709*7896SSriharsha.Basavapatna@Sun.COM if (hres == B_TRUE) { 710*7896SSriharsha.Basavapatna@Sun.COM /* 711*7896SSriharsha.Basavapatna@Sun.COM * Determine if the frame being transmitted 712*7896SSriharsha.Basavapatna@Sun.COM * over the hybrid resource is untagged. If so, 713*7896SSriharsha.Basavapatna@Sun.COM * insert the tag before transmitting. 714*7896SSriharsha.Basavapatna@Sun.COM */ 715*7896SSriharsha.Basavapatna@Sun.COM if (is_pvid == B_TRUE && 716*7896SSriharsha.Basavapatna@Sun.COM ehp->ether_type != htons(ETHERTYPE_VLAN)) { 717*7896SSriharsha.Basavapatna@Sun.COM 718*7896SSriharsha.Basavapatna@Sun.COM mp = vnet_vlan_insert_tag(mp, 719*7896SSriharsha.Basavapatna@Sun.COM vnetp->pvid); 720*7896SSriharsha.Basavapatna@Sun.COM if (mp == NULL) { 721*7896SSriharsha.Basavapatna@Sun.COM VNET_FDBE_REFRELE(vresp); 722*7896SSriharsha.Basavapatna@Sun.COM mp = next; 723*7896SSriharsha.Basavapatna@Sun.COM continue; 724*7896SSriharsha.Basavapatna@Sun.COM } 725*7896SSriharsha.Basavapatna@Sun.COM 726*7896SSriharsha.Basavapatna@Sun.COM } 727*7896SSriharsha.Basavapatna@Sun.COM } 728*7896SSriharsha.Basavapatna@Sun.COM 7296495Sspeer macp = &vresp->macreg; 7306495Sspeer resid_mp = macp->m_callbacks->mc_tx(macp->m_driver, mp); 7316419Ssb155480 7326419Ssb155480 /* tx done; now release ref on fdb entry */ 7336495Sspeer VNET_FDBE_REFRELE(vresp); 7346419Ssb155480 7356419Ssb155480 if (resid_mp != NULL) { 7366419Ssb155480 /* m_tx failed */ 7376419Ssb155480 mp->b_next = next; 7386419Ssb155480 break; 7396419Ssb155480 } 7401991Sheppo } 7411991Sheppo 7421991Sheppo mp = next; 7431991Sheppo } 7441991Sheppo 7454647Sraghuram DBG1(vnetp, "exit\n"); 7461991Sheppo return (mp); 7471991Sheppo } 7481991Sheppo 7492311Sseb /* get statistics from the device */ 7502311Sseb int 7512311Sseb vnet_m_stat(void *arg, uint_t stat, uint64_t *val) 7521991Sheppo { 7531991Sheppo vnet_t *vnetp = arg; 7546495Sspeer vnet_res_t *vresp; 7556495Sspeer mac_register_t *macp; 7562311Sseb mac_callbacks_t *cbp; 7572311Sseb uint64_t val_total = 0; 7581991Sheppo 7594647Sraghuram DBG1(vnetp, "enter\n"); 7601991Sheppo 7611991Sheppo /* 7622311Sseb * get the specified statistic from each transport and return the 7632311Sseb * aggregate val. This obviously only works for counters. 7641991Sheppo */ 7652311Sseb if ((IS_MAC_STAT(stat) && !MAC_STAT_ISACOUNTER(stat)) || 7662311Sseb (IS_MACTYPE_STAT(stat) && !ETHER_STAT_ISACOUNTER(stat))) { 7672311Sseb return (ENOTSUP); 7682311Sseb } 7696495Sspeer 7706495Sspeer READ_ENTER(&vnetp->vrwlock); 7716495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 7726495Sspeer macp = &vresp->macreg; 7736495Sspeer cbp = macp->m_callbacks; 7746495Sspeer if (cbp->mc_getstat(macp->m_driver, stat, val) == 0) 7752311Sseb val_total += *val; 7761991Sheppo } 7776495Sspeer RW_EXIT(&vnetp->vrwlock); 7781991Sheppo 7792311Sseb *val = val_total; 7802311Sseb 7814647Sraghuram DBG1(vnetp, "exit\n"); 7822311Sseb return (0); 7831991Sheppo } 7841991Sheppo 7851991Sheppo /* wrapper function for mac_register() */ 7861991Sheppo static int 7871991Sheppo vnet_mac_register(vnet_t *vnetp) 7881991Sheppo { 7892311Sseb mac_register_t *macp; 7902311Sseb int err; 7911991Sheppo 7922311Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 7932311Sseb return (DDI_FAILURE); 7942311Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 7952311Sseb macp->m_driver = vnetp; 7961991Sheppo macp->m_dip = vnetp->dip; 7972311Sseb macp->m_src_addr = vnetp->curr_macaddr; 7982311Sseb macp->m_callbacks = &vnet_m_callbacks; 7992311Sseb macp->m_min_sdu = 0; 8007529SSriharsha.Basavapatna@Sun.COM macp->m_max_sdu = vnetp->mtu; 8016419Ssb155480 macp->m_margin = VLAN_TAGSZ; 8021991Sheppo 8031991Sheppo /* 8041991Sheppo * Finally, we're ready to register ourselves with the MAC layer 8051991Sheppo * interface; if this succeeds, we're all ready to start() 8061991Sheppo */ 8072311Sseb err = mac_register(macp, &vnetp->mh); 8082311Sseb mac_free(macp); 8092311Sseb return (err == 0 ? DDI_SUCCESS : DDI_FAILURE); 8101991Sheppo } 8111991Sheppo 8121991Sheppo /* read the mac address of the device */ 8131991Sheppo static int 8141991Sheppo vnet_read_mac_address(vnet_t *vnetp) 8151991Sheppo { 8161991Sheppo uchar_t *macaddr; 8171991Sheppo uint32_t size; 8181991Sheppo int rv; 8191991Sheppo 8201991Sheppo rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip, 8214650Sraghuram DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size); 8221991Sheppo if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) { 8234647Sraghuram DWARN(vnetp, "prop_lookup failed(%s) err(%d)\n", 8244647Sraghuram macaddr_propname, rv); 8251991Sheppo return (DDI_FAILURE); 8261991Sheppo } 8271991Sheppo bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL); 8281991Sheppo bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL); 8291991Sheppo ddi_prop_free(macaddr); 8301991Sheppo 8311991Sheppo return (DDI_SUCCESS); 8321991Sheppo } 8331991Sheppo 8346419Ssb155480 static void 8356419Ssb155480 vnet_fdb_create(vnet_t *vnetp) 8361991Sheppo { 8376419Ssb155480 char hashname[MAXNAMELEN]; 8381991Sheppo 8396419Ssb155480 (void) snprintf(hashname, MAXNAMELEN, "vnet%d-fdbhash", 8406419Ssb155480 vnetp->instance); 8416419Ssb155480 vnetp->fdb_nchains = vnet_fdb_nchains; 8426419Ssb155480 vnetp->fdb_hashp = mod_hash_create_ptrhash(hashname, vnetp->fdb_nchains, 8436419Ssb155480 mod_hash_null_valdtor, sizeof (void *)); 8446419Ssb155480 } 8451991Sheppo 8466419Ssb155480 static void 8476419Ssb155480 vnet_fdb_destroy(vnet_t *vnetp) 8486419Ssb155480 { 8496419Ssb155480 /* destroy fdb-hash-table */ 8506419Ssb155480 if (vnetp->fdb_hashp != NULL) { 8516419Ssb155480 mod_hash_destroy_hash(vnetp->fdb_hashp); 8526419Ssb155480 vnetp->fdb_hashp = NULL; 8536419Ssb155480 vnetp->fdb_nchains = 0; 8541991Sheppo } 8551991Sheppo } 8561991Sheppo 8576419Ssb155480 /* 8586419Ssb155480 * Add an entry into the fdb. 8596419Ssb155480 */ 8601991Sheppo void 8616495Sspeer vnet_fdbe_add(vnet_t *vnetp, vnet_res_t *vresp) 8621991Sheppo { 8636419Ssb155480 uint64_t addr = 0; 8646419Ssb155480 int rv; 8656419Ssb155480 8666495Sspeer KEY_HASH(addr, vresp->rem_macaddr); 8671991Sheppo 8686419Ssb155480 /* 8696495Sspeer * If the entry being added corresponds to LDC_SERVICE resource, 8706495Sspeer * that is, vswitch connection, it is added to the hash and also 8716495Sspeer * the entry is cached, an additional reference count reflects 8726495Sspeer * this. The HYBRID resource is not added to the hash, but only 8736495Sspeer * cached, as it is only used for sending out packets for unknown 8746495Sspeer * unicast destinations. 8756419Ssb155480 */ 8766495Sspeer (vresp->type == VIO_NET_RES_LDC_SERVICE) ? 8776495Sspeer (vresp->refcnt = 1) : (vresp->refcnt = 0); 8781991Sheppo 8796419Ssb155480 /* 8806419Ssb155480 * Note: duplicate keys will be rejected by mod_hash. 8816419Ssb155480 */ 8826495Sspeer if (vresp->type != VIO_NET_RES_HYBRID) { 8836495Sspeer rv = mod_hash_insert(vnetp->fdb_hashp, (mod_hash_key_t)addr, 8846495Sspeer (mod_hash_val_t)vresp); 8856495Sspeer if (rv != 0) { 8866495Sspeer DWARN(vnetp, "Duplicate macaddr key(%lx)\n", addr); 8876495Sspeer return; 8886495Sspeer } 8891991Sheppo } 8901991Sheppo 8916495Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 8926419Ssb155480 /* Cache the fdb entry to vsw-port */ 8936419Ssb155480 WRITE_ENTER(&vnetp->vsw_fp_rw); 8946419Ssb155480 if (vnetp->vsw_fp == NULL) 8956495Sspeer vnetp->vsw_fp = vresp; 8966495Sspeer RW_EXIT(&vnetp->vsw_fp_rw); 8976495Sspeer } else if (vresp->type == VIO_NET_RES_HYBRID) { 8986495Sspeer /* Cache the fdb entry to hybrid resource */ 8996495Sspeer WRITE_ENTER(&vnetp->vsw_fp_rw); 9006495Sspeer if (vnetp->hio_fp == NULL) 9016495Sspeer vnetp->hio_fp = vresp; 9026419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 9032793Slm66018 } 9041991Sheppo } 9051991Sheppo 9066419Ssb155480 /* 9076419Ssb155480 * Remove an entry from fdb. 9086419Ssb155480 */ 9096495Sspeer static void 9106495Sspeer vnet_fdbe_del(vnet_t *vnetp, vnet_res_t *vresp) 9115641Swentaoy { 9126419Ssb155480 uint64_t addr = 0; 9136419Ssb155480 int rv; 9146419Ssb155480 uint32_t refcnt; 9156495Sspeer vnet_res_t *tmp; 9165641Swentaoy 9176495Sspeer KEY_HASH(addr, vresp->rem_macaddr); 9185641Swentaoy 9196419Ssb155480 /* 9206419Ssb155480 * Remove the entry from fdb hash table. 9216419Ssb155480 * This prevents further references to this fdb entry. 9226419Ssb155480 */ 9236495Sspeer if (vresp->type != VIO_NET_RES_HYBRID) { 9246495Sspeer rv = mod_hash_remove(vnetp->fdb_hashp, (mod_hash_key_t)addr, 9256495Sspeer (mod_hash_val_t *)&tmp); 9266495Sspeer if (rv != 0) { 9276495Sspeer /* 9286495Sspeer * As the resources are added to the hash only 9296495Sspeer * after they are started, this can occur if 9306495Sspeer * a resource unregisters before it is ever started. 9316495Sspeer */ 9326495Sspeer return; 9336495Sspeer } 9346495Sspeer } 9355641Swentaoy 9366495Sspeer if (vresp->type == VIO_NET_RES_LDC_SERVICE) { 9376419Ssb155480 WRITE_ENTER(&vnetp->vsw_fp_rw); 9385641Swentaoy 9396495Sspeer ASSERT(tmp == vnetp->vsw_fp); 9406419Ssb155480 vnetp->vsw_fp = NULL; 9416419Ssb155480 9426419Ssb155480 RW_EXIT(&vnetp->vsw_fp_rw); 9436495Sspeer } else if (vresp->type == VIO_NET_RES_HYBRID) { 9446495Sspeer WRITE_ENTER(&vnetp->vsw_fp_rw); 9456495Sspeer 9466495Sspeer vnetp->hio_fp = NULL; 9476495Sspeer 9486495Sspeer RW_EXIT(&vnetp->vsw_fp_rw); 9495641Swentaoy } 9505641Swentaoy 9515641Swentaoy /* 9526419Ssb155480 * If there are threads already ref holding before the entry was 9536419Ssb155480 * removed from hash table, then wait for ref count to drop to zero. 9545641Swentaoy */ 9556495Sspeer (vresp->type == VIO_NET_RES_LDC_SERVICE) ? 9566495Sspeer (refcnt = 1) : (refcnt = 0); 9576495Sspeer while (vresp->refcnt > refcnt) { 9586419Ssb155480 delay(drv_usectohz(vnet_fdbe_refcnt_delay)); 9596419Ssb155480 } 9601991Sheppo } 9611991Sheppo 9626419Ssb155480 /* 9636419Ssb155480 * Search fdb for a given mac address. If an entry is found, hold 9646419Ssb155480 * a reference to it and return the entry; else returns NULL. 9656419Ssb155480 */ 9666495Sspeer static vnet_res_t * 9676419Ssb155480 vnet_fdbe_find(vnet_t *vnetp, struct ether_addr *addrp) 9681991Sheppo { 9696419Ssb155480 uint64_t key = 0; 9706495Sspeer vnet_res_t *vresp; 9716419Ssb155480 int rv; 9726419Ssb155480 9736495Sspeer KEY_HASH(key, addrp->ether_addr_octet); 9746419Ssb155480 9756419Ssb155480 rv = mod_hash_find_cb(vnetp->fdb_hashp, (mod_hash_key_t)key, 9766495Sspeer (mod_hash_val_t *)&vresp, vnet_fdbe_find_cb); 9771991Sheppo 9786419Ssb155480 if (rv != 0) 9796419Ssb155480 return (NULL); 9801991Sheppo 9816495Sspeer return (vresp); 9826419Ssb155480 } 9831991Sheppo 9846419Ssb155480 /* 9856419Ssb155480 * Callback function provided to mod_hash_find_cb(). After finding the fdb 9866419Ssb155480 * entry corresponding to the key (macaddr), this callback will be invoked by 9876419Ssb155480 * mod_hash_find_cb() to atomically increment the reference count on the fdb 9886419Ssb155480 * entry before returning the found entry. 9896419Ssb155480 */ 9906419Ssb155480 static void 9916419Ssb155480 vnet_fdbe_find_cb(mod_hash_key_t key, mod_hash_val_t val) 9926419Ssb155480 { 9936419Ssb155480 _NOTE(ARGUNUSED(key)) 9946495Sspeer VNET_FDBE_REFHOLD((vnet_res_t *)val); 9956495Sspeer } 9966495Sspeer 997*7896SSriharsha.Basavapatna@Sun.COM /* 998*7896SSriharsha.Basavapatna@Sun.COM * Frames received that are tagged with the pvid of the vnet device must be 999*7896SSriharsha.Basavapatna@Sun.COM * untagged before sending up the stack. This function walks the chain of rx 1000*7896SSriharsha.Basavapatna@Sun.COM * frames, untags any such frames and returns the updated chain. 1001*7896SSriharsha.Basavapatna@Sun.COM * 1002*7896SSriharsha.Basavapatna@Sun.COM * Arguments: 1003*7896SSriharsha.Basavapatna@Sun.COM * pvid: pvid of the vnet device for which packets are being received 1004*7896SSriharsha.Basavapatna@Sun.COM * mp: head of pkt chain to be validated and untagged 1005*7896SSriharsha.Basavapatna@Sun.COM * 1006*7896SSriharsha.Basavapatna@Sun.COM * Returns: 1007*7896SSriharsha.Basavapatna@Sun.COM * mp: head of updated chain of packets 1008*7896SSriharsha.Basavapatna@Sun.COM */ 1009*7896SSriharsha.Basavapatna@Sun.COM static void 1010*7896SSriharsha.Basavapatna@Sun.COM vnet_rx_frames_untag(uint16_t pvid, mblk_t **mp) 1011*7896SSriharsha.Basavapatna@Sun.COM { 1012*7896SSriharsha.Basavapatna@Sun.COM struct ether_vlan_header *evhp; 1013*7896SSriharsha.Basavapatna@Sun.COM mblk_t *bp; 1014*7896SSriharsha.Basavapatna@Sun.COM mblk_t *bpt; 1015*7896SSriharsha.Basavapatna@Sun.COM mblk_t *bph; 1016*7896SSriharsha.Basavapatna@Sun.COM mblk_t *bpn; 1017*7896SSriharsha.Basavapatna@Sun.COM 1018*7896SSriharsha.Basavapatna@Sun.COM bpn = bph = bpt = NULL; 1019*7896SSriharsha.Basavapatna@Sun.COM 1020*7896SSriharsha.Basavapatna@Sun.COM for (bp = *mp; bp != NULL; bp = bpn) { 1021*7896SSriharsha.Basavapatna@Sun.COM 1022*7896SSriharsha.Basavapatna@Sun.COM bpn = bp->b_next; 1023*7896SSriharsha.Basavapatna@Sun.COM bp->b_next = bp->b_prev = NULL; 1024*7896SSriharsha.Basavapatna@Sun.COM 1025*7896SSriharsha.Basavapatna@Sun.COM evhp = (struct ether_vlan_header *)bp->b_rptr; 1026*7896SSriharsha.Basavapatna@Sun.COM 1027*7896SSriharsha.Basavapatna@Sun.COM if (ntohs(evhp->ether_tpid) == ETHERTYPE_VLAN && 1028*7896SSriharsha.Basavapatna@Sun.COM VLAN_ID(ntohs(evhp->ether_tci)) == pvid) { 1029*7896SSriharsha.Basavapatna@Sun.COM 1030*7896SSriharsha.Basavapatna@Sun.COM bp = vnet_vlan_remove_tag(bp); 1031*7896SSriharsha.Basavapatna@Sun.COM if (bp == NULL) { 1032*7896SSriharsha.Basavapatna@Sun.COM continue; 1033*7896SSriharsha.Basavapatna@Sun.COM } 1034*7896SSriharsha.Basavapatna@Sun.COM 1035*7896SSriharsha.Basavapatna@Sun.COM } 1036*7896SSriharsha.Basavapatna@Sun.COM 1037*7896SSriharsha.Basavapatna@Sun.COM /* build a chain of processed packets */ 1038*7896SSriharsha.Basavapatna@Sun.COM if (bph == NULL) { 1039*7896SSriharsha.Basavapatna@Sun.COM bph = bpt = bp; 1040*7896SSriharsha.Basavapatna@Sun.COM } else { 1041*7896SSriharsha.Basavapatna@Sun.COM bpt->b_next = bp; 1042*7896SSriharsha.Basavapatna@Sun.COM bpt = bp; 1043*7896SSriharsha.Basavapatna@Sun.COM } 1044*7896SSriharsha.Basavapatna@Sun.COM 1045*7896SSriharsha.Basavapatna@Sun.COM } 1046*7896SSriharsha.Basavapatna@Sun.COM 1047*7896SSriharsha.Basavapatna@Sun.COM *mp = bph; 1048*7896SSriharsha.Basavapatna@Sun.COM } 1049*7896SSriharsha.Basavapatna@Sun.COM 10506495Sspeer static void 10516495Sspeer vnet_rx(vio_net_handle_t vrh, mblk_t *mp) 10526495Sspeer { 1053*7896SSriharsha.Basavapatna@Sun.COM vnet_res_t *vresp = (vnet_res_t *)vrh; 1054*7896SSriharsha.Basavapatna@Sun.COM vnet_t *vnetp = vresp->vnetp; 1055*7896SSriharsha.Basavapatna@Sun.COM 1056*7896SSriharsha.Basavapatna@Sun.COM if ((vnetp == NULL) || (vnetp->mh == 0)) { 1057*7896SSriharsha.Basavapatna@Sun.COM freemsgchain(mp); 1058*7896SSriharsha.Basavapatna@Sun.COM return; 1059*7896SSriharsha.Basavapatna@Sun.COM } 10606495Sspeer 1061*7896SSriharsha.Basavapatna@Sun.COM /* 1062*7896SSriharsha.Basavapatna@Sun.COM * Packets received over a hybrid resource need additional processing 1063*7896SSriharsha.Basavapatna@Sun.COM * to remove the tag, for the pvid case. The underlying resource is 1064*7896SSriharsha.Basavapatna@Sun.COM * not aware of the vnet's pvid and thus packets are received with the 1065*7896SSriharsha.Basavapatna@Sun.COM * vlan tag in the header; unlike packets that are received over a ldc 1066*7896SSriharsha.Basavapatna@Sun.COM * channel in which case the peer vnet/vsw would have already removed 1067*7896SSriharsha.Basavapatna@Sun.COM * the tag. 1068*7896SSriharsha.Basavapatna@Sun.COM */ 1069*7896SSriharsha.Basavapatna@Sun.COM if (vresp->type == VIO_NET_RES_HYBRID && 1070*7896SSriharsha.Basavapatna@Sun.COM vnetp->pvid != vnetp->default_vlan_id) { 1071*7896SSriharsha.Basavapatna@Sun.COM 1072*7896SSriharsha.Basavapatna@Sun.COM vnet_rx_frames_untag(vnetp->pvid, &mp); 1073*7896SSriharsha.Basavapatna@Sun.COM if (mp == NULL) { 1074*7896SSriharsha.Basavapatna@Sun.COM return; 1075*7896SSriharsha.Basavapatna@Sun.COM } 10766495Sspeer } 1077*7896SSriharsha.Basavapatna@Sun.COM 1078*7896SSriharsha.Basavapatna@Sun.COM mac_rx(vnetp->mh, NULL, mp); 10791991Sheppo } 10802311Sseb 10812311Sseb void 10826495Sspeer vnet_tx_update(vio_net_handle_t vrh) 10836495Sspeer { 10846495Sspeer vnet_res_t *vresp = (vnet_res_t *)vrh; 10856495Sspeer vnet_t *vnetp = vresp->vnetp; 10866495Sspeer 10876495Sspeer if ((vnetp != NULL) && (vnetp->mh != NULL)) { 10886495Sspeer mac_tx_update(vnetp->mh); 10896495Sspeer } 10906495Sspeer } 10916495Sspeer 10926495Sspeer /* 10937529SSriharsha.Basavapatna@Sun.COM * Update the new mtu of vnet into the mac layer. First check if the device has 10947529SSriharsha.Basavapatna@Sun.COM * been plumbed and if so fail the mtu update. Returns 0 on success. 10957529SSriharsha.Basavapatna@Sun.COM */ 10967529SSriharsha.Basavapatna@Sun.COM int 10977529SSriharsha.Basavapatna@Sun.COM vnet_mtu_update(vnet_t *vnetp, uint32_t mtu) 10987529SSriharsha.Basavapatna@Sun.COM { 10997529SSriharsha.Basavapatna@Sun.COM int rv; 11007529SSriharsha.Basavapatna@Sun.COM 11017529SSriharsha.Basavapatna@Sun.COM if (vnetp == NULL || vnetp->mh == NULL) { 11027529SSriharsha.Basavapatna@Sun.COM return (EINVAL); 11037529SSriharsha.Basavapatna@Sun.COM } 11047529SSriharsha.Basavapatna@Sun.COM 11057529SSriharsha.Basavapatna@Sun.COM WRITE_ENTER(&vnetp->vrwlock); 11067529SSriharsha.Basavapatna@Sun.COM 11077529SSriharsha.Basavapatna@Sun.COM if (vnetp->flags & VNET_STARTED) { 11087529SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 11097529SSriharsha.Basavapatna@Sun.COM cmn_err(CE_NOTE, "!vnet%d: Unable to process mtu " 11107529SSriharsha.Basavapatna@Sun.COM "update as the device is plumbed\n", 11117529SSriharsha.Basavapatna@Sun.COM vnetp->instance); 11127529SSriharsha.Basavapatna@Sun.COM return (EBUSY); 11137529SSriharsha.Basavapatna@Sun.COM } 11147529SSriharsha.Basavapatna@Sun.COM 11157529SSriharsha.Basavapatna@Sun.COM /* update mtu in the mac layer */ 11167529SSriharsha.Basavapatna@Sun.COM rv = mac_maxsdu_update(vnetp->mh, mtu); 11177529SSriharsha.Basavapatna@Sun.COM if (rv != 0) { 11187529SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 11197529SSriharsha.Basavapatna@Sun.COM cmn_err(CE_NOTE, 11207529SSriharsha.Basavapatna@Sun.COM "!vnet%d: Unable to update mtu with mac layer\n", 11217529SSriharsha.Basavapatna@Sun.COM vnetp->instance); 11227529SSriharsha.Basavapatna@Sun.COM return (EIO); 11237529SSriharsha.Basavapatna@Sun.COM } 11247529SSriharsha.Basavapatna@Sun.COM 11257529SSriharsha.Basavapatna@Sun.COM vnetp->mtu = mtu; 11267529SSriharsha.Basavapatna@Sun.COM 11277529SSriharsha.Basavapatna@Sun.COM RW_EXIT(&vnetp->vrwlock); 11287529SSriharsha.Basavapatna@Sun.COM 11297529SSriharsha.Basavapatna@Sun.COM return (0); 11307529SSriharsha.Basavapatna@Sun.COM } 11317529SSriharsha.Basavapatna@Sun.COM 11327529SSriharsha.Basavapatna@Sun.COM /* 11336495Sspeer * vio_net_resource_reg -- An interface called to register a resource 11346495Sspeer * with vnet. 11356495Sspeer * macp -- a GLDv3 mac_register that has all the details of 11366495Sspeer * a resource and its callbacks etc. 11376495Sspeer * type -- resource type. 11386495Sspeer * local_macaddr -- resource's MAC address. This is used to 11396495Sspeer * associate a resource with a corresponding vnet. 11406495Sspeer * remote_macaddr -- remote side MAC address. This is ignored for 11416495Sspeer * the Hybrid resources. 11426495Sspeer * vhp -- A handle returned to the caller. 11436495Sspeer * vcb -- A set of callbacks provided to the callers. 11446495Sspeer */ 11456495Sspeer int vio_net_resource_reg(mac_register_t *macp, vio_net_res_type_t type, 11466495Sspeer ether_addr_t local_macaddr, ether_addr_t rem_macaddr, vio_net_handle_t *vhp, 11476495Sspeer vio_net_callbacks_t *vcb) 11486495Sspeer { 11496495Sspeer vnet_t *vnetp; 11506495Sspeer vnet_res_t *vresp; 11516495Sspeer 11526495Sspeer vresp = kmem_zalloc(sizeof (vnet_res_t), KM_SLEEP); 11536495Sspeer ether_copy(local_macaddr, vresp->local_macaddr); 11546495Sspeer ether_copy(rem_macaddr, vresp->rem_macaddr); 11556495Sspeer vresp->type = type; 11566495Sspeer bcopy(macp, &vresp->macreg, sizeof (mac_register_t)); 11576495Sspeer 11586495Sspeer DBG1(NULL, "Resource Registerig type=0%X\n", type); 11596495Sspeer 11606495Sspeer READ_ENTER(&vnet_rw); 11616495Sspeer vnetp = vnet_headp; 11626495Sspeer while (vnetp != NULL) { 11636495Sspeer if (VNET_MATCH_RES(vresp, vnetp)) { 11646495Sspeer WRITE_ENTER(&vnetp->vrwlock); 11656495Sspeer vresp->vnetp = vnetp; 11666495Sspeer vresp->nextp = vnetp->vres_list; 11676495Sspeer vnetp->vres_list = vresp; 11686495Sspeer RW_EXIT(&vnetp->vrwlock); 11696495Sspeer break; 11706495Sspeer } 11716495Sspeer vnetp = vnetp->nextp; 11726495Sspeer } 11736495Sspeer RW_EXIT(&vnet_rw); 11746495Sspeer if (vresp->vnetp == NULL) { 11756495Sspeer DWARN(NULL, "No vnet instance"); 11766495Sspeer kmem_free(vresp, sizeof (vnet_res_t)); 11776495Sspeer return (ENXIO); 11786495Sspeer } 11796495Sspeer 11806495Sspeer *vhp = vresp; 11816495Sspeer vcb->vio_net_rx_cb = vnet_rx; 11826495Sspeer vcb->vio_net_tx_update = vnet_tx_update; 11836495Sspeer vcb->vio_net_report_err = vnet_handle_res_err; 11846495Sspeer 11856495Sspeer /* Dispatch a task to start resources */ 11866495Sspeer vnet_dispatch_res_task(vnetp); 11876495Sspeer return (0); 11886495Sspeer } 11896495Sspeer 11906495Sspeer /* 11916495Sspeer * vio_net_resource_unreg -- An interface to unregister a resource. 11926495Sspeer */ 11936495Sspeer void 11946495Sspeer vio_net_resource_unreg(vio_net_handle_t vhp) 11956495Sspeer { 11966495Sspeer vnet_res_t *vresp = (vnet_res_t *)vhp; 11976495Sspeer vnet_t *vnetp = vresp->vnetp; 11986495Sspeer vnet_res_t *vrp; 11996495Sspeer 12006495Sspeer DBG1(NULL, "Resource Registerig hdl=0x%p", vhp); 12016495Sspeer 12026495Sspeer ASSERT(vnetp != NULL); 12036495Sspeer vnet_fdbe_del(vnetp, vresp); 12046495Sspeer 12056495Sspeer WRITE_ENTER(&vnetp->vrwlock); 12066495Sspeer if (vresp == vnetp->vres_list) { 12076495Sspeer vnetp->vres_list = vresp->nextp; 12086495Sspeer } else { 12096495Sspeer vrp = vnetp->vres_list; 12106495Sspeer while (vrp->nextp != NULL) { 12116495Sspeer if (vrp->nextp == vresp) { 12126495Sspeer vrp->nextp = vresp->nextp; 12136495Sspeer break; 12146495Sspeer } 12156495Sspeer vrp = vrp->nextp; 12166495Sspeer } 12176495Sspeer } 12186495Sspeer vresp->vnetp = NULL; 12196495Sspeer vresp->nextp = NULL; 12206495Sspeer RW_EXIT(&vnetp->vrwlock); 12216495Sspeer KMEM_FREE(vresp); 12226495Sspeer } 12236495Sspeer 12246495Sspeer /* 12256495Sspeer * vnet_dds_rx -- an interface called by vgen to DDS messages. 12266495Sspeer */ 12276495Sspeer void 12286495Sspeer vnet_dds_rx(void *arg, void *dmsg) 12292311Sseb { 12302311Sseb vnet_t *vnetp = arg; 12316495Sspeer vdds_process_dds_msg(vnetp, dmsg); 12322311Sseb } 12332311Sseb 12346495Sspeer /* 12356495Sspeer * vnet_send_dds_msg -- An interface provided to DDS to send 12366495Sspeer * DDS messages. This simply sends meessages via vgen. 12376495Sspeer */ 12386495Sspeer int 12396495Sspeer vnet_send_dds_msg(vnet_t *vnetp, void *dmsg) 12406495Sspeer { 12416495Sspeer int rv; 12426495Sspeer 12436495Sspeer if (vnetp->vgenhdl != NULL) { 12446495Sspeer rv = vgen_dds_tx(vnetp->vgenhdl, dmsg); 12456495Sspeer } 12466495Sspeer return (rv); 12476495Sspeer } 12486495Sspeer 12496495Sspeer /* 12506495Sspeer * vnet_handle_res_err -- A callback function called by a resource 12516495Sspeer * to report an error. For example, vgen can call to report 12526495Sspeer * an LDC down/reset event. This will trigger cleanup of associated 12536495Sspeer * Hybrid resource. 12546495Sspeer */ 12556495Sspeer /* ARGSUSED */ 12566495Sspeer static void 12576495Sspeer vnet_handle_res_err(vio_net_handle_t vrh, vio_net_err_val_t err) 12586495Sspeer { 12596495Sspeer vnet_res_t *vresp = (vnet_res_t *)vrh; 12606495Sspeer vnet_t *vnetp = vresp->vnetp; 12617819SRaghuram.Kothakota@Sun.COM int rv; 12626495Sspeer 12636495Sspeer if (vnetp == NULL) { 12646495Sspeer return; 12656495Sspeer } 12666495Sspeer if ((vresp->type != VIO_NET_RES_LDC_SERVICE) && 12676495Sspeer (vresp->type != VIO_NET_RES_HYBRID)) { 12686495Sspeer return; 12696495Sspeer } 12707819SRaghuram.Kothakota@Sun.COM rv = ddi_taskq_dispatch(vnetp->taskqp, vdds_cleanup_hybrid_res, 12717819SRaghuram.Kothakota@Sun.COM vnetp, DDI_NOSLEEP); 12727819SRaghuram.Kothakota@Sun.COM if (rv != DDI_SUCCESS) { 12737819SRaghuram.Kothakota@Sun.COM cmn_err(CE_WARN, 12747819SRaghuram.Kothakota@Sun.COM "vnet%d:Failed to dispatch task to cleanup hybrid resource", 12757819SRaghuram.Kothakota@Sun.COM vnetp->instance); 12767819SRaghuram.Kothakota@Sun.COM } 12776495Sspeer } 12786495Sspeer 12796495Sspeer /* 12806495Sspeer * vnet_dispatch_res_task -- A function to dispatch tasks start resources. 12816495Sspeer */ 12826495Sspeer static void 12836495Sspeer vnet_dispatch_res_task(vnet_t *vnetp) 12846495Sspeer { 12856495Sspeer int rv; 12866495Sspeer 12876495Sspeer WRITE_ENTER(&vnetp->vrwlock); 12886495Sspeer if (vnetp->flags & VNET_STARTED) { 12896495Sspeer rv = ddi_taskq_dispatch(vnetp->taskqp, vnet_res_start_task, 12906495Sspeer vnetp, DDI_NOSLEEP); 12916495Sspeer if (rv != DDI_SUCCESS) { 12926495Sspeer cmn_err(CE_WARN, 12936495Sspeer "vnet%d:Can't dispatch start resource task", 12946495Sspeer vnetp->instance); 12956495Sspeer } 12966495Sspeer } 12976495Sspeer RW_EXIT(&vnetp->vrwlock); 12986495Sspeer } 12996495Sspeer 13006495Sspeer /* 13016495Sspeer * vnet_res_start_task -- A taskq callback function that starts a resource. 13026495Sspeer */ 13036495Sspeer static void 13046495Sspeer vnet_res_start_task(void *arg) 13052311Sseb { 13062311Sseb vnet_t *vnetp = arg; 13076495Sspeer 13086495Sspeer WRITE_ENTER(&vnetp->vrwlock); 13096495Sspeer if (vnetp->flags & VNET_STARTED) { 13106495Sspeer vnet_start_resources(vnetp); 13116495Sspeer } 13126495Sspeer RW_EXIT(&vnetp->vrwlock); 13132311Sseb } 13146495Sspeer 13156495Sspeer /* 13166495Sspeer * vnet_start_resources -- starts all resources associated with 13176495Sspeer * a vnet. 13186495Sspeer */ 13196495Sspeer static void 13206495Sspeer vnet_start_resources(vnet_t *vnetp) 13216495Sspeer { 13226495Sspeer mac_register_t *macp; 13236495Sspeer mac_callbacks_t *cbp; 13246495Sspeer vnet_res_t *vresp; 13256495Sspeer int rv; 13266495Sspeer 13276495Sspeer DBG1(vnetp, "enter\n"); 13286495Sspeer 13296495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; vresp = vresp->nextp) { 13306495Sspeer /* skip if it is already started */ 13316495Sspeer if (vresp->flags & VNET_STARTED) { 13326495Sspeer continue; 13336495Sspeer } 13346495Sspeer macp = &vresp->macreg; 13356495Sspeer cbp = macp->m_callbacks; 13366495Sspeer rv = cbp->mc_start(macp->m_driver); 13376495Sspeer if (rv == 0) { 13386495Sspeer /* 13396495Sspeer * Successfully started the resource, so now 13406495Sspeer * add it to the fdb. 13416495Sspeer */ 13426495Sspeer vresp->flags |= VNET_STARTED; 13436495Sspeer vnet_fdbe_add(vnetp, vresp); 13446495Sspeer } 13456495Sspeer } 13466495Sspeer 13476495Sspeer DBG1(vnetp, "exit\n"); 13486495Sspeer 13496495Sspeer } 13506495Sspeer 13516495Sspeer /* 13526495Sspeer * vnet_stop_resources -- stop all resources associated with a vnet. 13536495Sspeer */ 13546495Sspeer static void 13556495Sspeer vnet_stop_resources(vnet_t *vnetp) 13566495Sspeer { 13576495Sspeer vnet_res_t *vresp; 13586495Sspeer vnet_res_t *nvresp; 13596495Sspeer mac_register_t *macp; 13606495Sspeer mac_callbacks_t *cbp; 13616495Sspeer 13626495Sspeer DBG1(vnetp, "enter\n"); 13636495Sspeer 13646495Sspeer for (vresp = vnetp->vres_list; vresp != NULL; ) { 13656495Sspeer nvresp = vresp->nextp; 13666495Sspeer if (vresp->flags & VNET_STARTED) { 13676495Sspeer macp = &vresp->macreg; 13686495Sspeer cbp = macp->m_callbacks; 13696495Sspeer cbp->mc_stop(macp->m_driver); 13706495Sspeer vresp->flags &= ~VNET_STARTED; 13716495Sspeer } 13726495Sspeer vresp = nvresp; 13736495Sspeer } 13746495Sspeer DBG1(vnetp, "exit\n"); 13756495Sspeer } 1376