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 /* 23f0ca1d9aSsb155480 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 241ae08745Sheppo * Use is subject to license terms. 251ae08745Sheppo */ 261ae08745Sheppo 271ae08745Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 281ae08745Sheppo 291ae08745Sheppo #include <sys/types.h> 301ae08745Sheppo #include <sys/errno.h> 311ae08745Sheppo #include <sys/debug.h> 321ae08745Sheppo #include <sys/time.h> 331ae08745Sheppo #include <sys/sysmacros.h> 341ae08745Sheppo #include <sys/systm.h> 351ae08745Sheppo #include <sys/user.h> 361ae08745Sheppo #include <sys/stropts.h> 371ae08745Sheppo #include <sys/stream.h> 381ae08745Sheppo #include <sys/strlog.h> 391ae08745Sheppo #include <sys/strsubr.h> 401ae08745Sheppo #include <sys/cmn_err.h> 411ae08745Sheppo #include <sys/cpu.h> 421ae08745Sheppo #include <sys/kmem.h> 431ae08745Sheppo #include <sys/conf.h> 441ae08745Sheppo #include <sys/ddi.h> 451ae08745Sheppo #include <sys/sunddi.h> 461ae08745Sheppo #include <sys/ksynch.h> 471ae08745Sheppo #include <sys/stat.h> 481ae08745Sheppo #include <sys/kstat.h> 491ae08745Sheppo #include <sys/vtrace.h> 501ae08745Sheppo #include <sys/strsun.h> 511ae08745Sheppo #include <sys/dlpi.h> 521ae08745Sheppo #include <sys/ethernet.h> 531ae08745Sheppo #include <net/if.h> 541ae08745Sheppo #include <sys/varargs.h> 551ae08745Sheppo #include <sys/machsystm.h> 561ae08745Sheppo #include <sys/modctl.h> 571ae08745Sheppo #include <sys/modhash.h> 581ae08745Sheppo #include <sys/mac.h> 59ba2e4443Sseb #include <sys/mac_ether.h> 601ae08745Sheppo #include <sys/taskq.h> 611ae08745Sheppo #include <sys/note.h> 621ae08745Sheppo #include <sys/mach_descrip.h> 631ae08745Sheppo #include <sys/mac.h> 641ae08745Sheppo #include <sys/mdeg.h> 651ae08745Sheppo #include <sys/ldc.h> 661ae08745Sheppo #include <sys/vsw_fdb.h> 671ae08745Sheppo #include <sys/vsw.h> 681ae08745Sheppo #include <sys/vio_mailbox.h> 691ae08745Sheppo #include <sys/vnet_mailbox.h> 701ae08745Sheppo #include <sys/vnet_common.h> 71d10e4ef2Snarayan #include <sys/vio_util.h> 72d10e4ef2Snarayan #include <sys/sdt.h> 7319b65a69Ssb155480 #include <sys/atomic.h> 7406db247cSraghuram #include <sys/callb.h> 75*c1c61f44Ssb155480 #include <sys/vlan.h> 761ae08745Sheppo 771ae08745Sheppo /* 781ae08745Sheppo * Function prototypes. 791ae08745Sheppo */ 801ae08745Sheppo static int vsw_attach(dev_info_t *, ddi_attach_cmd_t); 811ae08745Sheppo static int vsw_detach(dev_info_t *, ddi_detach_cmd_t); 821ae08745Sheppo static int vsw_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 8334683adeSsg70180 static int vsw_get_md_physname(vsw_t *, md_t *, mde_cookie_t, char *); 8434683adeSsg70180 static int vsw_get_md_smodes(vsw_t *, md_t *, mde_cookie_t, uint8_t *, int *); 851ae08745Sheppo 861ae08745Sheppo /* MDEG routines */ 8734683adeSsg70180 static int vsw_mdeg_register(vsw_t *vswp); 881ae08745Sheppo static void vsw_mdeg_unregister(vsw_t *vswp); 891ae08745Sheppo static int vsw_mdeg_cb(void *cb_argp, mdeg_result_t *); 9034683adeSsg70180 static int vsw_port_mdeg_cb(void *cb_argp, mdeg_result_t *); 9119b65a69Ssb155480 static int vsw_get_initial_md_properties(vsw_t *vswp, md_t *, mde_cookie_t); 92*c1c61f44Ssb155480 static int vsw_read_mdprops(vsw_t *vswp); 93*c1c61f44Ssb155480 static void vsw_vlan_read_ids(void *arg, int type, md_t *mdp, 94*c1c61f44Ssb155480 mde_cookie_t node, uint16_t *pvidp, uint16_t **vidspp, 95*c1c61f44Ssb155480 uint16_t *nvidsp, uint16_t *default_idp); 96*c1c61f44Ssb155480 static int vsw_port_read_props(vsw_port_t *portp, vsw_t *vswp, 97*c1c61f44Ssb155480 md_t *mdp, mde_cookie_t *node); 98f0ca1d9aSsb155480 static void vsw_read_pri_eth_types(vsw_t *vswp, md_t *mdp, 99f0ca1d9aSsb155480 mde_cookie_t node); 10034683adeSsg70180 static void vsw_update_md_prop(vsw_t *, md_t *, mde_cookie_t); 10119b65a69Ssb155480 static void vsw_save_lmacaddr(vsw_t *vswp, uint64_t macaddr); 1021ae08745Sheppo 10306db247cSraghuram /* Mac driver related routines */ 10406db247cSraghuram static int vsw_mac_register(vsw_t *); 10506db247cSraghuram static int vsw_mac_unregister(vsw_t *); 10606db247cSraghuram static int vsw_m_stat(void *, uint_t, uint64_t *); 10706db247cSraghuram static void vsw_m_stop(void *arg); 10806db247cSraghuram static int vsw_m_start(void *arg); 10906db247cSraghuram static int vsw_m_unicst(void *arg, const uint8_t *); 11006db247cSraghuram static int vsw_m_multicst(void *arg, boolean_t, const uint8_t *); 11106db247cSraghuram static int vsw_m_promisc(void *arg, boolean_t); 11206db247cSraghuram static mblk_t *vsw_m_tx(void *arg, mblk_t *); 113f0ca1d9aSsb155480 void vsw_mac_rx(vsw_t *vswp, mac_resource_handle_t mrh, 114f0ca1d9aSsb155480 mblk_t *mp, vsw_macrx_flags_t flags); 1151ae08745Sheppo 11606db247cSraghuram /* 11706db247cSraghuram * Functions imported from other files. 11806db247cSraghuram */ 11906db247cSraghuram extern void vsw_setup_switching_timeout(void *arg); 12006db247cSraghuram extern void vsw_stop_switching_timeout(vsw_t *vswp); 12106db247cSraghuram extern int vsw_setup_switching(vsw_t *); 12206db247cSraghuram extern int vsw_add_mcst(vsw_t *, uint8_t, uint64_t, void *); 12306db247cSraghuram extern int vsw_del_mcst(vsw_t *, uint8_t, uint64_t, void *); 12406db247cSraghuram extern void vsw_del_mcst_vsw(vsw_t *); 12506db247cSraghuram extern mcst_addr_t *vsw_del_addr(uint8_t devtype, void *arg, uint64_t addr); 12606db247cSraghuram extern int vsw_detach_ports(vsw_t *vswp); 12706db247cSraghuram extern int vsw_port_add(vsw_t *vswp, md_t *mdp, mde_cookie_t *node); 12806db247cSraghuram extern int vsw_port_detach(vsw_t *vswp, int p_instance); 129*c1c61f44Ssb155480 static int vsw_port_update(vsw_t *vswp, md_t *curr_mdp, mde_cookie_t curr_mdex, 130*c1c61f44Ssb155480 md_t *prev_mdp, mde_cookie_t prev_mdex); 131*c1c61f44Ssb155480 extern int vsw_port_attach(vsw_port_t *port); 13206db247cSraghuram extern vsw_port_t *vsw_lookup_port(vsw_t *vswp, int p_instance); 13306db247cSraghuram extern int vsw_mac_attach(vsw_t *vswp); 13406db247cSraghuram extern void vsw_mac_detach(vsw_t *vswp); 13506db247cSraghuram extern int vsw_mac_open(vsw_t *vswp); 13606db247cSraghuram extern void vsw_mac_close(vsw_t *vswp); 13706db247cSraghuram extern int vsw_set_hw(vsw_t *, vsw_port_t *, int); 13806db247cSraghuram extern int vsw_unset_hw(vsw_t *, vsw_port_t *, int); 13906db247cSraghuram extern void vsw_reconfig_hw(vsw_t *); 14006db247cSraghuram extern void vsw_unset_addrs(vsw_t *vswp); 14106db247cSraghuram extern void vsw_set_addrs(vsw_t *vswp); 142*c1c61f44Ssb155480 extern void vsw_create_vlans(void *arg, int type); 143*c1c61f44Ssb155480 extern void vsw_destroy_vlans(void *arg, int type); 144*c1c61f44Ssb155480 extern void vsw_vlan_add_ids(void *arg, int type); 145*c1c61f44Ssb155480 extern void vsw_vlan_remove_ids(void *arg, int type); 146*c1c61f44Ssb155480 extern void vsw_vlan_unaware_port_reset(vsw_port_t *portp); 147*c1c61f44Ssb155480 extern uint32_t vsw_vlan_frame_untag(void *arg, int type, mblk_t **np, 148*c1c61f44Ssb155480 mblk_t **npt); 149*c1c61f44Ssb155480 extern mblk_t *vsw_vlan_frame_pretag(void *arg, int type, mblk_t *mp); 15006db247cSraghuram 15106db247cSraghuram /* 15206db247cSraghuram * Internal tunables. 15306db247cSraghuram */ 154445b4c2eSsb155480 int vsw_num_handshakes = VNET_NUM_HANDSHAKES; /* # of handshake attempts */ 1551ae08745Sheppo int vsw_wretries = 100; /* # of write attempts */ 156d10e4ef2Snarayan int vsw_desc_delay = 0; /* delay in us */ 157d10e4ef2Snarayan int vsw_read_attempts = 5; /* # of reads of descriptor */ 15819b65a69Ssb155480 int vsw_mac_open_retries = 20; /* max # of mac_open() retries */ 15919b65a69Ssb155480 int vsw_setup_switching_delay = 3; /* setup sw timeout interval in sec */ 16006db247cSraghuram int vsw_ldc_tx_delay = 5; /* delay(ticks) for tx retries */ 16106db247cSraghuram int vsw_ldc_tx_retries = 10; /* # of ldc tx retries */ 16206db247cSraghuram boolean_t vsw_ldc_rxthr_enabled = B_TRUE; /* LDC Rx thread enabled */ 16306db247cSraghuram boolean_t vsw_ldc_txthr_enabled = B_TRUE; /* LDC Tx thread enabled */ 164d10e4ef2Snarayan 165*c1c61f44Ssb155480 uint32_t vsw_fdb_nchains = 8; /* # of chains in fdb hash table */ 166*c1c61f44Ssb155480 uint32_t vsw_vlan_nchains = 4; /* # of chains in vlan id hash table */ 167*c1c61f44Ssb155480 uint32_t vsw_ethermtu = 1500; /* mtu of the device */ 168*c1c61f44Ssb155480 169*c1c61f44Ssb155480 /* delay in usec to wait for all references on a fdb entry to be dropped */ 170*c1c61f44Ssb155480 uint32_t vsw_fdbe_refcnt_delay = 10; 171*c1c61f44Ssb155480 172*c1c61f44Ssb155480 /* 173*c1c61f44Ssb155480 * Default vlan id. This is only used internally when the "default-vlan-id" 174*c1c61f44Ssb155480 * property is not present in the MD device node. Therefore, this should not be 175*c1c61f44Ssb155480 * used as a tunable; if this value is changed, the corresponding variable 176*c1c61f44Ssb155480 * should be updated to the same value in all vnets connected to this vsw. 177*c1c61f44Ssb155480 */ 178*c1c61f44Ssb155480 uint16_t vsw_default_vlan_id = 1; 179*c1c61f44Ssb155480 180f0ca1d9aSsb155480 /* 181f0ca1d9aSsb155480 * Workaround for a version handshake bug in obp's vnet. 182f0ca1d9aSsb155480 * If vsw initiates version negotiation starting from the highest version, 183f0ca1d9aSsb155480 * obp sends a nack and terminates version handshake. To workaround 184f0ca1d9aSsb155480 * this, we do not initiate version handshake when the channel comes up. 185f0ca1d9aSsb155480 * Instead, we wait for the peer to send its version info msg and go through 186f0ca1d9aSsb155480 * the version protocol exchange. If we successfully negotiate a version, 187f0ca1d9aSsb155480 * before sending the ack, we send our version info msg to the peer 188f0ca1d9aSsb155480 * using the <major,minor> version that we are about to ack. 189f0ca1d9aSsb155480 */ 190f0ca1d9aSsb155480 boolean_t vsw_obp_ver_proto_workaround = B_TRUE; 191f0ca1d9aSsb155480 192f0ca1d9aSsb155480 /* 193f0ca1d9aSsb155480 * In the absence of "priority-ether-types" property in MD, the following 194f0ca1d9aSsb155480 * internal tunable can be set to specify a single priority ethertype. 195f0ca1d9aSsb155480 */ 196f0ca1d9aSsb155480 uint64_t vsw_pri_eth_type = 0; 197f0ca1d9aSsb155480 198f0ca1d9aSsb155480 /* 199f0ca1d9aSsb155480 * Number of transmit priority buffers that are preallocated per device. 200f0ca1d9aSsb155480 * This number is chosen to be a small value to throttle transmission 201f0ca1d9aSsb155480 * of priority packets. Note: Must be a power of 2 for vio_create_mblks(). 202f0ca1d9aSsb155480 */ 203f0ca1d9aSsb155480 uint32_t vsw_pri_tx_nmblks = 64; 204d10e4ef2Snarayan 20506db247cSraghuram /* 20606db247cSraghuram * External tunables. 20706db247cSraghuram */ 20806db247cSraghuram /* 20906db247cSraghuram * Enable/disable thread per ring. This is a mode selection 21006db247cSraghuram * that is done a vsw driver attach time. 21106db247cSraghuram */ 21206db247cSraghuram boolean_t vsw_multi_ring_enable = B_FALSE; 21306db247cSraghuram int vsw_mac_rx_rings = VSW_MAC_RX_RINGS; 21406db247cSraghuram 215f0ca1d9aSsb155480 /* Number of transmit descriptors - must be power of 2 */ 216f0ca1d9aSsb155480 uint32_t vsw_ntxds = VSW_RING_NUM_EL; 217f0ca1d9aSsb155480 21806db247cSraghuram /* 21906db247cSraghuram * Max number of mblks received in one receive operation. 22006db247cSraghuram */ 22106db247cSraghuram uint32_t vsw_chain_len = (VSW_NUM_MBLKS * 0.6); 22206db247cSraghuram 22306db247cSraghuram /* 22406db247cSraghuram * Tunables for three different pools, that is, the size and 22506db247cSraghuram * number of mblks for each pool. 22606db247cSraghuram */ 22706db247cSraghuram uint32_t vsw_mblk_size1 = VSW_MBLK_SZ_128; /* size=128 for pool1 */ 22806db247cSraghuram uint32_t vsw_mblk_size2 = VSW_MBLK_SZ_256; /* size=256 for pool2 */ 22906db247cSraghuram uint32_t vsw_mblk_size3 = VSW_MBLK_SZ_2048; /* size=2048 for pool3 */ 23006db247cSraghuram uint32_t vsw_num_mblks1 = VSW_NUM_MBLKS; /* number of mblks for pool1 */ 23106db247cSraghuram uint32_t vsw_num_mblks2 = VSW_NUM_MBLKS; /* number of mblks for pool2 */ 23206db247cSraghuram uint32_t vsw_num_mblks3 = VSW_NUM_MBLKS; /* number of mblks for pool3 */ 23306db247cSraghuram 23406db247cSraghuram /* 235f0ca1d9aSsb155480 * vsw_max_tx_qcount is the maximum # of packets that can be queued 236f0ca1d9aSsb155480 * before the tx worker thread begins processing the queue. Its value 237f0ca1d9aSsb155480 * is chosen to be 4x the default length of tx descriptor ring. 238f0ca1d9aSsb155480 */ 239f0ca1d9aSsb155480 uint32_t vsw_max_tx_qcount = 4 * VSW_RING_NUM_EL; 240f0ca1d9aSsb155480 241f0ca1d9aSsb155480 /* 24206db247cSraghuram * MAC callbacks 24306db247cSraghuram */ 244ba2e4443Sseb static mac_callbacks_t vsw_m_callbacks = { 245ba2e4443Sseb 0, 246ba2e4443Sseb vsw_m_stat, 247ba2e4443Sseb vsw_m_start, 248ba2e4443Sseb vsw_m_stop, 249ba2e4443Sseb vsw_m_promisc, 250ba2e4443Sseb vsw_m_multicst, 251ba2e4443Sseb vsw_m_unicst, 252ba2e4443Sseb vsw_m_tx, 253ba2e4443Sseb NULL, 254ba2e4443Sseb NULL, 255ba2e4443Sseb NULL 256ba2e4443Sseb }; 257ba2e4443Sseb 2581ae08745Sheppo static struct cb_ops vsw_cb_ops = { 2591ae08745Sheppo nulldev, /* cb_open */ 2601ae08745Sheppo nulldev, /* cb_close */ 2611ae08745Sheppo nodev, /* cb_strategy */ 2621ae08745Sheppo nodev, /* cb_print */ 2631ae08745Sheppo nodev, /* cb_dump */ 2641ae08745Sheppo nodev, /* cb_read */ 2651ae08745Sheppo nodev, /* cb_write */ 2661ae08745Sheppo nodev, /* cb_ioctl */ 2671ae08745Sheppo nodev, /* cb_devmap */ 2681ae08745Sheppo nodev, /* cb_mmap */ 2691ae08745Sheppo nodev, /* cb_segmap */ 2701ae08745Sheppo nochpoll, /* cb_chpoll */ 2711ae08745Sheppo ddi_prop_op, /* cb_prop_op */ 2721ae08745Sheppo NULL, /* cb_stream */ 2731ae08745Sheppo D_MP, /* cb_flag */ 2741ae08745Sheppo CB_REV, /* rev */ 2751ae08745Sheppo nodev, /* int (*cb_aread)() */ 2761ae08745Sheppo nodev /* int (*cb_awrite)() */ 2771ae08745Sheppo }; 2781ae08745Sheppo 2791ae08745Sheppo static struct dev_ops vsw_ops = { 2801ae08745Sheppo DEVO_REV, /* devo_rev */ 2811ae08745Sheppo 0, /* devo_refcnt */ 2821ae08745Sheppo vsw_getinfo, /* devo_getinfo */ 2831ae08745Sheppo nulldev, /* devo_identify */ 2841ae08745Sheppo nulldev, /* devo_probe */ 2851ae08745Sheppo vsw_attach, /* devo_attach */ 2861ae08745Sheppo vsw_detach, /* devo_detach */ 2871ae08745Sheppo nodev, /* devo_reset */ 2881ae08745Sheppo &vsw_cb_ops, /* devo_cb_ops */ 2891ae08745Sheppo (struct bus_ops *)NULL, /* devo_bus_ops */ 2901ae08745Sheppo ddi_power /* devo_power */ 2911ae08745Sheppo }; 2921ae08745Sheppo 2931ae08745Sheppo extern struct mod_ops mod_driverops; 2941ae08745Sheppo static struct modldrv vswmodldrv = { 2951ae08745Sheppo &mod_driverops, 296205eeb1aSlm66018 "sun4v Virtual Switch", 2971ae08745Sheppo &vsw_ops, 2981ae08745Sheppo }; 2991ae08745Sheppo 3001ae08745Sheppo #define LDC_ENTER_LOCK(ldcp) \ 3011ae08745Sheppo mutex_enter(&((ldcp)->ldc_cblock));\ 30206db247cSraghuram mutex_enter(&((ldcp)->ldc_rxlock));\ 3031ae08745Sheppo mutex_enter(&((ldcp)->ldc_txlock)); 3041ae08745Sheppo #define LDC_EXIT_LOCK(ldcp) \ 3051ae08745Sheppo mutex_exit(&((ldcp)->ldc_txlock));\ 30606db247cSraghuram mutex_exit(&((ldcp)->ldc_rxlock));\ 3071ae08745Sheppo mutex_exit(&((ldcp)->ldc_cblock)); 3081ae08745Sheppo 3091ae08745Sheppo /* Driver soft state ptr */ 3101ae08745Sheppo static void *vsw_state; 3111ae08745Sheppo 3121ae08745Sheppo /* 3131ae08745Sheppo * Linked list of "vsw_t" structures - one per instance. 3141ae08745Sheppo */ 3151ae08745Sheppo vsw_t *vsw_head = NULL; 3161ae08745Sheppo krwlock_t vsw_rw; 3171ae08745Sheppo 3181ae08745Sheppo /* 3191ae08745Sheppo * Property names 3201ae08745Sheppo */ 3211ae08745Sheppo static char vdev_propname[] = "virtual-device"; 3221ae08745Sheppo static char vsw_propname[] = "virtual-network-switch"; 3231ae08745Sheppo static char physdev_propname[] = "vsw-phys-dev"; 3241ae08745Sheppo static char smode_propname[] = "vsw-switch-mode"; 3251ae08745Sheppo static char macaddr_propname[] = "local-mac-address"; 3261ae08745Sheppo static char remaddr_propname[] = "remote-mac-address"; 3271ae08745Sheppo static char ldcids_propname[] = "ldc-ids"; 3281ae08745Sheppo static char chan_propname[] = "channel-endpoint"; 3291ae08745Sheppo static char id_propname[] = "id"; 3301ae08745Sheppo static char reg_propname[] = "reg"; 331f0ca1d9aSsb155480 static char pri_types_propname[] = "priority-ether-types"; 332*c1c61f44Ssb155480 static char vsw_pvid_propname[] = "port-vlan-id"; 333*c1c61f44Ssb155480 static char vsw_vid_propname[] = "vlan-id"; 334*c1c61f44Ssb155480 static char vsw_dvid_propname[] = "default-vlan-id"; 335*c1c61f44Ssb155480 static char port_pvid_propname[] = "remote-port-vlan-id"; 336*c1c61f44Ssb155480 static char port_vid_propname[] = "remote-vlan-id"; 3371ae08745Sheppo 3381ae08745Sheppo /* 3391ae08745Sheppo * Matching criteria passed to the MDEG to register interest 3401ae08745Sheppo * in changes to 'virtual-device-port' nodes identified by their 3411ae08745Sheppo * 'id' property. 3421ae08745Sheppo */ 3431ae08745Sheppo static md_prop_match_t vport_prop_match[] = { 3441ae08745Sheppo { MDET_PROP_VAL, "id" }, 3451ae08745Sheppo { MDET_LIST_END, NULL } 3461ae08745Sheppo }; 3471ae08745Sheppo 3481ae08745Sheppo static mdeg_node_match_t vport_match = { "virtual-device-port", 3491ae08745Sheppo vport_prop_match }; 3501ae08745Sheppo 3511ae08745Sheppo /* 35234683adeSsg70180 * Matching criteria passed to the MDEG to register interest 35334683adeSsg70180 * in changes to 'virtual-device' nodes (i.e. vsw nodes) identified 35434683adeSsg70180 * by their 'name' and 'cfg-handle' properties. 35534683adeSsg70180 */ 35634683adeSsg70180 static md_prop_match_t vdev_prop_match[] = { 35734683adeSsg70180 { MDET_PROP_STR, "name" }, 35834683adeSsg70180 { MDET_PROP_VAL, "cfg-handle" }, 35934683adeSsg70180 { MDET_LIST_END, NULL } 36034683adeSsg70180 }; 36134683adeSsg70180 36234683adeSsg70180 static mdeg_node_match_t vdev_match = { "virtual-device", 36334683adeSsg70180 vdev_prop_match }; 36434683adeSsg70180 36534683adeSsg70180 36634683adeSsg70180 /* 3671ae08745Sheppo * Specification of an MD node passed to the MDEG to filter any 3681ae08745Sheppo * 'vport' nodes that do not belong to the specified node. This 3691ae08745Sheppo * template is copied for each vsw instance and filled in with 3701ae08745Sheppo * the appropriate 'cfg-handle' value before being passed to the MDEG. 3711ae08745Sheppo */ 3721ae08745Sheppo static mdeg_prop_spec_t vsw_prop_template[] = { 3731ae08745Sheppo { MDET_PROP_STR, "name", vsw_propname }, 3741ae08745Sheppo { MDET_PROP_VAL, "cfg-handle", NULL }, 3751ae08745Sheppo { MDET_LIST_END, NULL, NULL } 3761ae08745Sheppo }; 3771ae08745Sheppo 3781ae08745Sheppo #define VSW_SET_MDEG_PROP_INST(specp, val) (specp)[1].ps_val = (val); 3791ae08745Sheppo 38006db247cSraghuram #ifdef DEBUG 3817636cb21Slm66018 /* 3821ae08745Sheppo * Print debug messages - set to 0x1f to enable all msgs 3831ae08745Sheppo * or 0x0 to turn all off. 3841ae08745Sheppo */ 3851ae08745Sheppo int vswdbg = 0x0; 3861ae08745Sheppo 3871ae08745Sheppo /* 3881ae08745Sheppo * debug levels: 3891ae08745Sheppo * 0x01: Function entry/exit tracing 3901ae08745Sheppo * 0x02: Internal function messages 3911ae08745Sheppo * 0x04: Verbose internal messages 3921ae08745Sheppo * 0x08: Warning messages 3931ae08745Sheppo * 0x10: Error messages 3941ae08745Sheppo */ 3951ae08745Sheppo 39606db247cSraghuram void 3971ae08745Sheppo vswdebug(vsw_t *vswp, const char *fmt, ...) 3981ae08745Sheppo { 3991ae08745Sheppo char buf[512]; 4001ae08745Sheppo va_list ap; 4011ae08745Sheppo 4021ae08745Sheppo va_start(ap, fmt); 4031ae08745Sheppo (void) vsprintf(buf, fmt, ap); 4041ae08745Sheppo va_end(ap); 4051ae08745Sheppo 4061ae08745Sheppo if (vswp == NULL) 4071ae08745Sheppo cmn_err(CE_CONT, "%s\n", buf); 4081ae08745Sheppo else 4091ae08745Sheppo cmn_err(CE_CONT, "vsw%d: %s\n", vswp->instance, buf); 4101ae08745Sheppo } 4111ae08745Sheppo 4121ae08745Sheppo #endif /* DEBUG */ 4131ae08745Sheppo 4141ae08745Sheppo static struct modlinkage modlinkage = { 4151ae08745Sheppo MODREV_1, 4161ae08745Sheppo &vswmodldrv, 4171ae08745Sheppo NULL 4181ae08745Sheppo }; 4191ae08745Sheppo 4201ae08745Sheppo int 4211ae08745Sheppo _init(void) 4221ae08745Sheppo { 4231ae08745Sheppo int status; 4241ae08745Sheppo 4251ae08745Sheppo rw_init(&vsw_rw, NULL, RW_DRIVER, NULL); 4261ae08745Sheppo 4271ae08745Sheppo status = ddi_soft_state_init(&vsw_state, sizeof (vsw_t), 1); 4281ae08745Sheppo if (status != 0) { 4291ae08745Sheppo return (status); 4301ae08745Sheppo } 4311ae08745Sheppo 43206db247cSraghuram mac_init_ops(&vsw_ops, DRV_NAME); 4331ae08745Sheppo status = mod_install(&modlinkage); 4341ae08745Sheppo if (status != 0) { 4351ae08745Sheppo ddi_soft_state_fini(&vsw_state); 4361ae08745Sheppo } 4371ae08745Sheppo return (status); 4381ae08745Sheppo } 4391ae08745Sheppo 4401ae08745Sheppo int 4411ae08745Sheppo _fini(void) 4421ae08745Sheppo { 4431ae08745Sheppo int status; 4441ae08745Sheppo 4451ae08745Sheppo status = mod_remove(&modlinkage); 4461ae08745Sheppo if (status != 0) 4471ae08745Sheppo return (status); 4481ae08745Sheppo mac_fini_ops(&vsw_ops); 4491ae08745Sheppo ddi_soft_state_fini(&vsw_state); 4501ae08745Sheppo 4511ae08745Sheppo rw_destroy(&vsw_rw); 4521ae08745Sheppo 4531ae08745Sheppo return (status); 4541ae08745Sheppo } 4551ae08745Sheppo 4561ae08745Sheppo int 4571ae08745Sheppo _info(struct modinfo *modinfop) 4581ae08745Sheppo { 4591ae08745Sheppo return (mod_info(&modlinkage, modinfop)); 4601ae08745Sheppo } 4611ae08745Sheppo 4621ae08745Sheppo static int 4631ae08745Sheppo vsw_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 4641ae08745Sheppo { 4651ae08745Sheppo vsw_t *vswp; 46634683adeSsg70180 int instance; 4671ae08745Sheppo char hashname[MAXNAMELEN]; 4681ae08745Sheppo char qname[TASKQ_NAMELEN]; 4697636cb21Slm66018 enum { PROG_init = 0x00, 47019b65a69Ssb155480 PROG_locks = 0x01, 47119b65a69Ssb155480 PROG_readmd = 0x02, 47219b65a69Ssb155480 PROG_fdb = 0x04, 47319b65a69Ssb155480 PROG_mfdb = 0x08, 47419b65a69Ssb155480 PROG_taskq = 0x10, 475f0ca1d9aSsb155480 PROG_swmode = 0x20, 476f0ca1d9aSsb155480 PROG_macreg = 0x40, 477f0ca1d9aSsb155480 PROG_mdreg = 0x80} 4781ae08745Sheppo progress; 4791ae08745Sheppo 4801ae08745Sheppo progress = PROG_init; 48119b65a69Ssb155480 int rv; 4821ae08745Sheppo 4831ae08745Sheppo switch (cmd) { 4841ae08745Sheppo case DDI_ATTACH: 4851ae08745Sheppo break; 4861ae08745Sheppo case DDI_RESUME: 4871ae08745Sheppo /* nothing to do for this non-device */ 4881ae08745Sheppo return (DDI_SUCCESS); 4891ae08745Sheppo case DDI_PM_RESUME: 4901ae08745Sheppo default: 4911ae08745Sheppo return (DDI_FAILURE); 4921ae08745Sheppo } 4931ae08745Sheppo 4941ae08745Sheppo instance = ddi_get_instance(dip); 4951ae08745Sheppo if (ddi_soft_state_zalloc(vsw_state, instance) != DDI_SUCCESS) { 4961ae08745Sheppo DERR(NULL, "vsw%d: ddi_soft_state_zalloc failed", instance); 4971ae08745Sheppo return (DDI_FAILURE); 4981ae08745Sheppo } 4991ae08745Sheppo vswp = ddi_get_soft_state(vsw_state, instance); 5001ae08745Sheppo 5011ae08745Sheppo if (vswp == NULL) { 5021ae08745Sheppo DERR(NULL, "vsw%d: ddi_get_soft_state failed", instance); 5031ae08745Sheppo goto vsw_attach_fail; 5041ae08745Sheppo } 5051ae08745Sheppo 5061ae08745Sheppo vswp->dip = dip; 5071ae08745Sheppo vswp->instance = instance; 5081ae08745Sheppo ddi_set_driver_private(dip, (caddr_t)vswp); 5091ae08745Sheppo 5105f94e909Ssg70180 mutex_init(&vswp->hw_lock, NULL, MUTEX_DRIVER, NULL); 51134683adeSsg70180 mutex_init(&vswp->mac_lock, NULL, MUTEX_DRIVER, NULL); 51219b65a69Ssb155480 mutex_init(&vswp->mca_lock, NULL, MUTEX_DRIVER, NULL); 51319b65a69Ssb155480 mutex_init(&vswp->swtmout_lock, NULL, MUTEX_DRIVER, NULL); 5141ae08745Sheppo rw_init(&vswp->if_lockrw, NULL, RW_DRIVER, NULL); 51519b65a69Ssb155480 rw_init(&vswp->mfdbrw, NULL, RW_DRIVER, NULL); 51619b65a69Ssb155480 rw_init(&vswp->plist.lockrw, NULL, RW_DRIVER, NULL); 51719b65a69Ssb155480 51819b65a69Ssb155480 progress |= PROG_locks; 51919b65a69Ssb155480 52019b65a69Ssb155480 rv = vsw_read_mdprops(vswp); 52119b65a69Ssb155480 if (rv != 0) 52219b65a69Ssb155480 goto vsw_attach_fail; 52319b65a69Ssb155480 52419b65a69Ssb155480 progress |= PROG_readmd; 5251ae08745Sheppo 5261ae08745Sheppo /* setup the unicast forwarding database */ 5271ae08745Sheppo (void) snprintf(hashname, MAXNAMELEN, "vsw_unicst_table-%d", 5281ae08745Sheppo vswp->instance); 5291ae08745Sheppo D2(vswp, "creating unicast hash table (%s)...", hashname); 530*c1c61f44Ssb155480 vswp->fdb_nchains = vsw_fdb_nchains; 531*c1c61f44Ssb155480 vswp->fdb_hashp = mod_hash_create_ptrhash(hashname, vswp->fdb_nchains, 5321ae08745Sheppo mod_hash_null_valdtor, sizeof (void *)); 533*c1c61f44Ssb155480 vsw_create_vlans((void *)vswp, VSW_LOCALDEV); 5341ae08745Sheppo progress |= PROG_fdb; 5351ae08745Sheppo 5361ae08745Sheppo /* setup the multicast fowarding database */ 5371ae08745Sheppo (void) snprintf(hashname, MAXNAMELEN, "vsw_mcst_table-%d", 5381ae08745Sheppo vswp->instance); 5391ae08745Sheppo D2(vswp, "creating multicast hash table %s)...", hashname); 540*c1c61f44Ssb155480 vswp->mfdb = mod_hash_create_ptrhash(hashname, vsw_fdb_nchains, 5411ae08745Sheppo mod_hash_null_valdtor, sizeof (void *)); 5421ae08745Sheppo 5431ae08745Sheppo progress |= PROG_mfdb; 5441ae08745Sheppo 5451ae08745Sheppo /* 5461ae08745Sheppo * Create the taskq which will process all the VIO 5471ae08745Sheppo * control messages. 5481ae08745Sheppo */ 5491ae08745Sheppo (void) snprintf(qname, TASKQ_NAMELEN, "vsw_taskq%d", vswp->instance); 5501ae08745Sheppo if ((vswp->taskq_p = ddi_taskq_create(vswp->dip, qname, 1, 5511ae08745Sheppo TASKQ_DEFAULTPRI, 0)) == NULL) { 55234683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to create task queue", 55334683adeSsg70180 vswp->instance); 5541ae08745Sheppo goto vsw_attach_fail; 5551ae08745Sheppo } 5561ae08745Sheppo 5571ae08745Sheppo progress |= PROG_taskq; 5581ae08745Sheppo 559d10e4ef2Snarayan /* prevent auto-detaching */ 560d10e4ef2Snarayan if (ddi_prop_update_int(DDI_DEV_T_NONE, vswp->dip, 561d10e4ef2Snarayan DDI_NO_AUTODETACH, 1) != DDI_SUCCESS) { 56234683adeSsg70180 cmn_err(CE_NOTE, "!Unable to set \"%s\" property for " 563d10e4ef2Snarayan "instance %u", DDI_NO_AUTODETACH, instance); 564d10e4ef2Snarayan } 565d10e4ef2Snarayan 5661ae08745Sheppo /* 56719b65a69Ssb155480 * Setup the required switching mode, 56819b65a69Ssb155480 * based on the mdprops that we read earlier. 56919b65a69Ssb155480 */ 57019b65a69Ssb155480 rv = vsw_setup_switching(vswp); 57119b65a69Ssb155480 if (rv == EAGAIN) { 57219b65a69Ssb155480 /* 57319b65a69Ssb155480 * Unable to setup switching mode; 57419b65a69Ssb155480 * as the error is EAGAIN, schedule a timeout to retry. 57519b65a69Ssb155480 */ 57619b65a69Ssb155480 mutex_enter(&vswp->swtmout_lock); 57719b65a69Ssb155480 57819b65a69Ssb155480 vswp->swtmout_enabled = B_TRUE; 57919b65a69Ssb155480 vswp->swtmout_id = 58019b65a69Ssb155480 timeout(vsw_setup_switching_timeout, vswp, 58119b65a69Ssb155480 (vsw_setup_switching_delay * drv_usectohz(MICROSEC))); 58219b65a69Ssb155480 58319b65a69Ssb155480 mutex_exit(&vswp->swtmout_lock); 58419b65a69Ssb155480 } else if (rv != 0) { 58519b65a69Ssb155480 goto vsw_attach_fail; 58619b65a69Ssb155480 } 58719b65a69Ssb155480 58819b65a69Ssb155480 progress |= PROG_swmode; 58919b65a69Ssb155480 59019b65a69Ssb155480 /* Register with mac layer as a provider */ 59119b65a69Ssb155480 rv = vsw_mac_register(vswp); 59219b65a69Ssb155480 if (rv != 0) 59319b65a69Ssb155480 goto vsw_attach_fail; 59419b65a69Ssb155480 59519b65a69Ssb155480 progress |= PROG_macreg; 59619b65a69Ssb155480 59719b65a69Ssb155480 /* 59834683adeSsg70180 * Now we have everything setup, register an interest in 59934683adeSsg70180 * specific MD nodes. 60034683adeSsg70180 * 60134683adeSsg70180 * The callback is invoked in 2 cases, firstly if upon mdeg 60234683adeSsg70180 * registration there are existing nodes which match our specified 60334683adeSsg70180 * criteria, and secondly if the MD is changed (and again, there 60434683adeSsg70180 * are nodes which we are interested in present within it. Note 60534683adeSsg70180 * that our callback will be invoked even if our specified nodes 60634683adeSsg70180 * have not actually changed). 60734683adeSsg70180 * 6081ae08745Sheppo */ 60919b65a69Ssb155480 rv = vsw_mdeg_register(vswp); 61019b65a69Ssb155480 if (rv != 0) 61134683adeSsg70180 goto vsw_attach_fail; 6121ae08745Sheppo 61319b65a69Ssb155480 progress |= PROG_mdreg; 61419b65a69Ssb155480 61519b65a69Ssb155480 WRITE_ENTER(&vsw_rw); 61619b65a69Ssb155480 vswp->next = vsw_head; 61719b65a69Ssb155480 vsw_head = vswp; 61819b65a69Ssb155480 RW_EXIT(&vsw_rw); 61919b65a69Ssb155480 62019b65a69Ssb155480 ddi_report_dev(vswp->dip); 6211ae08745Sheppo return (DDI_SUCCESS); 6221ae08745Sheppo 6231ae08745Sheppo vsw_attach_fail: 6241ae08745Sheppo DERR(NULL, "vsw_attach: failed"); 6251ae08745Sheppo 62619b65a69Ssb155480 if (progress & PROG_mdreg) { 62719b65a69Ssb155480 vsw_mdeg_unregister(vswp); 62819b65a69Ssb155480 (void) vsw_detach_ports(vswp); 62919b65a69Ssb155480 } 63019b65a69Ssb155480 63119b65a69Ssb155480 if (progress & PROG_macreg) 63219b65a69Ssb155480 (void) vsw_mac_unregister(vswp); 63319b65a69Ssb155480 63419b65a69Ssb155480 if (progress & PROG_swmode) { 63519b65a69Ssb155480 vsw_stop_switching_timeout(vswp); 63619b65a69Ssb155480 mutex_enter(&vswp->mac_lock); 63719b65a69Ssb155480 vsw_mac_detach(vswp); 63819b65a69Ssb155480 vsw_mac_close(vswp); 63919b65a69Ssb155480 mutex_exit(&vswp->mac_lock); 64019b65a69Ssb155480 } 64119b65a69Ssb155480 6421ae08745Sheppo if (progress & PROG_taskq) 6431ae08745Sheppo ddi_taskq_destroy(vswp->taskq_p); 6441ae08745Sheppo 64519b65a69Ssb155480 if (progress & PROG_mfdb) 6461ae08745Sheppo mod_hash_destroy_hash(vswp->mfdb); 6471ae08745Sheppo 648*c1c61f44Ssb155480 if (progress & PROG_fdb) { 649*c1c61f44Ssb155480 vsw_destroy_vlans(vswp, VSW_LOCALDEV); 650*c1c61f44Ssb155480 mod_hash_destroy_hash(vswp->fdb_hashp); 651*c1c61f44Ssb155480 } 6521ae08745Sheppo 653f0ca1d9aSsb155480 if (progress & PROG_readmd) { 654f0ca1d9aSsb155480 if (VSW_PRI_ETH_DEFINED(vswp)) { 655f0ca1d9aSsb155480 kmem_free(vswp->pri_types, 656f0ca1d9aSsb155480 sizeof (uint16_t) * vswp->pri_num_types); 657f0ca1d9aSsb155480 } 658f0ca1d9aSsb155480 (void) vio_destroy_mblks(vswp->pri_tx_vmp); 659f0ca1d9aSsb155480 } 660f0ca1d9aSsb155480 66119b65a69Ssb155480 if (progress & PROG_locks) { 66219b65a69Ssb155480 rw_destroy(&vswp->plist.lockrw); 66319b65a69Ssb155480 rw_destroy(&vswp->mfdbrw); 6641ae08745Sheppo rw_destroy(&vswp->if_lockrw); 66519b65a69Ssb155480 mutex_destroy(&vswp->swtmout_lock); 66619b65a69Ssb155480 mutex_destroy(&vswp->mca_lock); 66734683adeSsg70180 mutex_destroy(&vswp->mac_lock); 6685f94e909Ssg70180 mutex_destroy(&vswp->hw_lock); 66934683adeSsg70180 } 6701ae08745Sheppo 6711ae08745Sheppo ddi_soft_state_free(vsw_state, instance); 6721ae08745Sheppo return (DDI_FAILURE); 6731ae08745Sheppo } 6741ae08745Sheppo 6751ae08745Sheppo static int 6761ae08745Sheppo vsw_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 6771ae08745Sheppo { 678d10e4ef2Snarayan vio_mblk_pool_t *poolp, *npoolp; 6791ae08745Sheppo vsw_t **vswpp, *vswp; 6801ae08745Sheppo int instance; 6811ae08745Sheppo 6821ae08745Sheppo instance = ddi_get_instance(dip); 6831ae08745Sheppo vswp = ddi_get_soft_state(vsw_state, instance); 6841ae08745Sheppo 6851ae08745Sheppo if (vswp == NULL) { 6861ae08745Sheppo return (DDI_FAILURE); 6871ae08745Sheppo } 6881ae08745Sheppo 6891ae08745Sheppo switch (cmd) { 6901ae08745Sheppo case DDI_DETACH: 6911ae08745Sheppo break; 6921ae08745Sheppo case DDI_SUSPEND: 6931ae08745Sheppo case DDI_PM_SUSPEND: 6941ae08745Sheppo default: 6951ae08745Sheppo return (DDI_FAILURE); 6961ae08745Sheppo } 6971ae08745Sheppo 6981ae08745Sheppo D2(vswp, "detaching instance %d", instance); 6991ae08745Sheppo 70019b65a69Ssb155480 /* Stop any pending timeout to setup switching mode. */ 70119b65a69Ssb155480 vsw_stop_switching_timeout(vswp); 70219b65a69Ssb155480 70334683adeSsg70180 if (vswp->if_state & VSW_IF_REG) { 7041ae08745Sheppo if (vsw_mac_unregister(vswp) != 0) { 70534683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to detach from " 70634683adeSsg70180 "MAC layer", vswp->instance); 7071ae08745Sheppo return (DDI_FAILURE); 7081ae08745Sheppo } 709d10e4ef2Snarayan } 7101ae08745Sheppo 7111ae08745Sheppo vsw_mdeg_unregister(vswp); 7121ae08745Sheppo 713e1ebb9ecSlm66018 /* remove mac layer callback */ 71434683adeSsg70180 mutex_enter(&vswp->mac_lock); 715e1ebb9ecSlm66018 if ((vswp->mh != NULL) && (vswp->mrh != NULL)) { 7161f8aaf0dSethindra mac_rx_remove(vswp->mh, vswp->mrh, B_TRUE); 717e1ebb9ecSlm66018 vswp->mrh = NULL; 7181ae08745Sheppo } 71934683adeSsg70180 mutex_exit(&vswp->mac_lock); 7201ae08745Sheppo 7211ae08745Sheppo if (vsw_detach_ports(vswp) != 0) { 7221ef0bbb5Snarayan cmn_err(CE_WARN, "!vsw%d: Unable to unconfigure ports", 72334683adeSsg70180 vswp->instance); 7241ae08745Sheppo return (DDI_FAILURE); 7251ae08745Sheppo } 7261ae08745Sheppo 72734683adeSsg70180 rw_destroy(&vswp->if_lockrw); 72834683adeSsg70180 7295f94e909Ssg70180 mutex_destroy(&vswp->hw_lock); 7305f94e909Ssg70180 7311ae08745Sheppo /* 732e1ebb9ecSlm66018 * Now that the ports have been deleted, stop and close 733e1ebb9ecSlm66018 * the physical device. 734e1ebb9ecSlm66018 */ 73534683adeSsg70180 mutex_enter(&vswp->mac_lock); 736e1ebb9ecSlm66018 73719b65a69Ssb155480 vsw_mac_detach(vswp); 73819b65a69Ssb155480 vsw_mac_close(vswp); 73919b65a69Ssb155480 74034683adeSsg70180 mutex_exit(&vswp->mac_lock); 74119b65a69Ssb155480 74234683adeSsg70180 mutex_destroy(&vswp->mac_lock); 74319b65a69Ssb155480 mutex_destroy(&vswp->swtmout_lock); 744e1ebb9ecSlm66018 745e1ebb9ecSlm66018 /* 746d10e4ef2Snarayan * Destroy any free pools that may still exist. 747d10e4ef2Snarayan */ 748d10e4ef2Snarayan poolp = vswp->rxh; 749d10e4ef2Snarayan while (poolp != NULL) { 750d10e4ef2Snarayan npoolp = vswp->rxh = poolp->nextp; 751d10e4ef2Snarayan if (vio_destroy_mblks(poolp) != 0) { 752d10e4ef2Snarayan vswp->rxh = poolp; 753d10e4ef2Snarayan return (DDI_FAILURE); 754d10e4ef2Snarayan } 755d10e4ef2Snarayan poolp = npoolp; 756d10e4ef2Snarayan } 757d10e4ef2Snarayan 758d10e4ef2Snarayan /* 7591ae08745Sheppo * Remove this instance from any entries it may be on in 7601ae08745Sheppo * the hash table by using the list of addresses maintained 7611ae08745Sheppo * in the vsw_t structure. 7621ae08745Sheppo */ 7631ae08745Sheppo vsw_del_mcst_vsw(vswp); 7641ae08745Sheppo 7651ae08745Sheppo vswp->mcap = NULL; 7661ae08745Sheppo mutex_destroy(&vswp->mca_lock); 7671ae08745Sheppo 7681ae08745Sheppo /* 7691ae08745Sheppo * By now any pending tasks have finished and the underlying 7701ae08745Sheppo * ldc's have been destroyed, so its safe to delete the control 7711ae08745Sheppo * message taskq. 7721ae08745Sheppo */ 7731ae08745Sheppo if (vswp->taskq_p != NULL) 7741ae08745Sheppo ddi_taskq_destroy(vswp->taskq_p); 7751ae08745Sheppo 7761ae08745Sheppo /* 7771ae08745Sheppo * At this stage all the data pointers in the hash table 7781ae08745Sheppo * should be NULL, as all the ports have been removed and will 7791ae08745Sheppo * have deleted themselves from the port lists which the data 7801ae08745Sheppo * pointers point to. Hence we can destroy the table using the 7811ae08745Sheppo * default destructors. 7821ae08745Sheppo */ 7831ae08745Sheppo D2(vswp, "vsw_detach: destroying hash tables.."); 784*c1c61f44Ssb155480 vsw_destroy_vlans(vswp, VSW_LOCALDEV); 785*c1c61f44Ssb155480 mod_hash_destroy_hash(vswp->fdb_hashp); 786*c1c61f44Ssb155480 vswp->fdb_hashp = NULL; 7871ae08745Sheppo 7881ae08745Sheppo WRITE_ENTER(&vswp->mfdbrw); 7891ae08745Sheppo mod_hash_destroy_hash(vswp->mfdb); 7901ae08745Sheppo vswp->mfdb = NULL; 7911ae08745Sheppo RW_EXIT(&vswp->mfdbrw); 7921ae08745Sheppo rw_destroy(&vswp->mfdbrw); 7931ae08745Sheppo 794f0ca1d9aSsb155480 /* free pri_types table */ 795f0ca1d9aSsb155480 if (VSW_PRI_ETH_DEFINED(vswp)) { 796f0ca1d9aSsb155480 kmem_free(vswp->pri_types, 797f0ca1d9aSsb155480 sizeof (uint16_t) * vswp->pri_num_types); 798f0ca1d9aSsb155480 (void) vio_destroy_mblks(vswp->pri_tx_vmp); 799f0ca1d9aSsb155480 } 800f0ca1d9aSsb155480 8011ae08745Sheppo ddi_remove_minor_node(dip, NULL); 8021ae08745Sheppo 8031ae08745Sheppo rw_destroy(&vswp->plist.lockrw); 8041ae08745Sheppo WRITE_ENTER(&vsw_rw); 8051ae08745Sheppo for (vswpp = &vsw_head; *vswpp; vswpp = &(*vswpp)->next) { 8061ae08745Sheppo if (*vswpp == vswp) { 8071ae08745Sheppo *vswpp = vswp->next; 8081ae08745Sheppo break; 8091ae08745Sheppo } 8101ae08745Sheppo } 8111ae08745Sheppo RW_EXIT(&vsw_rw); 8121ae08745Sheppo ddi_soft_state_free(vsw_state, instance); 8131ae08745Sheppo 8141ae08745Sheppo return (DDI_SUCCESS); 8151ae08745Sheppo } 8161ae08745Sheppo 8171ae08745Sheppo static int 8181ae08745Sheppo vsw_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 8191ae08745Sheppo { 8201ae08745Sheppo _NOTE(ARGUNUSED(dip)) 8211ae08745Sheppo 8221ae08745Sheppo vsw_t *vswp = NULL; 8231ae08745Sheppo dev_t dev = (dev_t)arg; 8241ae08745Sheppo int instance; 8251ae08745Sheppo 8261ae08745Sheppo instance = getminor(dev); 8271ae08745Sheppo 8281ae08745Sheppo switch (infocmd) { 8291ae08745Sheppo case DDI_INFO_DEVT2DEVINFO: 8301ae08745Sheppo if ((vswp = ddi_get_soft_state(vsw_state, instance)) == NULL) { 8311ae08745Sheppo *result = NULL; 8321ae08745Sheppo return (DDI_FAILURE); 8331ae08745Sheppo } 8341ae08745Sheppo *result = vswp->dip; 8351ae08745Sheppo return (DDI_SUCCESS); 8361ae08745Sheppo 8371ae08745Sheppo case DDI_INFO_DEVT2INSTANCE: 8381ae08745Sheppo *result = (void *)(uintptr_t)instance; 8391ae08745Sheppo return (DDI_SUCCESS); 8401ae08745Sheppo 8411ae08745Sheppo default: 8421ae08745Sheppo *result = NULL; 8431ae08745Sheppo return (DDI_FAILURE); 8441ae08745Sheppo } 8451ae08745Sheppo } 8461ae08745Sheppo 8471ae08745Sheppo /* 84834683adeSsg70180 * Get the value of the "vsw-phys-dev" property in the specified 84934683adeSsg70180 * node. This property is the name of the physical device that 85034683adeSsg70180 * the virtual switch will use to talk to the outside world. 85134683adeSsg70180 * 85234683adeSsg70180 * Note it is valid for this property to be NULL (but the property 85334683adeSsg70180 * itself must exist). Callers of this routine should verify that 85434683adeSsg70180 * the value returned is what they expected (i.e. either NULL or non NULL). 85534683adeSsg70180 * 85634683adeSsg70180 * On success returns value of the property in region pointed to by 85734683adeSsg70180 * the 'name' argument, and with return value of 0. Otherwise returns 1. 8581ae08745Sheppo */ 85934683adeSsg70180 static int 86034683adeSsg70180 vsw_get_md_physname(vsw_t *vswp, md_t *mdp, mde_cookie_t node, char *name) 8611ae08745Sheppo { 86234683adeSsg70180 int len = 0; 863f2b610cfSwentaoy int instance; 8641ae08745Sheppo char *physname = NULL; 8651ae08745Sheppo char *dev; 866f2b610cfSwentaoy const char *dev_name; 867f2b610cfSwentaoy char myname[MAXNAMELEN]; 868f2b610cfSwentaoy 869f2b610cfSwentaoy dev_name = ddi_driver_name(vswp->dip); 870f2b610cfSwentaoy instance = ddi_get_instance(vswp->dip); 871f2b610cfSwentaoy (void) snprintf(myname, MAXNAMELEN, "%s%d", dev_name, instance); 8721ae08745Sheppo 87334683adeSsg70180 if (md_get_prop_data(mdp, node, physdev_propname, 8741ae08745Sheppo (uint8_t **)(&physname), &len) != 0) { 87534683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to get name(s) of physical " 87634683adeSsg70180 "device(s) from MD", vswp->instance); 87734683adeSsg70180 return (1); 8781ae08745Sheppo } else if ((strlen(physname) + 1) > LIFNAMSIZ) { 87934683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: %s is too long a device name", 88034683adeSsg70180 vswp->instance, physname); 88134683adeSsg70180 return (1); 882f2b610cfSwentaoy } else if (strcmp(myname, physname) == 0) { 883f2b610cfSwentaoy /* 884f2b610cfSwentaoy * Prevent the vswitch from opening itself as the 885f2b610cfSwentaoy * network device. 886f2b610cfSwentaoy */ 887f2b610cfSwentaoy cmn_err(CE_WARN, "!vsw%d: %s is an invalid device name", 888f2b610cfSwentaoy vswp->instance, physname); 889f2b610cfSwentaoy return (1); 8901ae08745Sheppo } else { 89134683adeSsg70180 (void) strncpy(name, physname, strlen(physname) + 1); 8921ae08745Sheppo D2(vswp, "%s: using first device specified (%s)", 89334683adeSsg70180 __func__, physname); 8941ae08745Sheppo } 8951ae08745Sheppo 8961ae08745Sheppo #ifdef DEBUG 8971ae08745Sheppo /* 8981ae08745Sheppo * As a temporary measure to aid testing we check to see if there 8991ae08745Sheppo * is a vsw.conf file present. If there is we use the value of the 9001ae08745Sheppo * vsw_physname property in the file as the name of the physical 9011ae08745Sheppo * device, overriding the value from the MD. 9021ae08745Sheppo * 9031ae08745Sheppo * There may be multiple devices listed, but for the moment 9041ae08745Sheppo * we just use the first one. 9051ae08745Sheppo */ 9061ae08745Sheppo if (ddi_prop_lookup_string(DDI_DEV_T_ANY, vswp->dip, 0, 9071ae08745Sheppo "vsw_physname", &dev) == DDI_PROP_SUCCESS) { 9081ae08745Sheppo if ((strlen(dev) + 1) > LIFNAMSIZ) { 90934683adeSsg70180 cmn_err(CE_WARN, "vsw%d: %s is too long a device name", 91034683adeSsg70180 vswp->instance, dev); 91134683adeSsg70180 ddi_prop_free(dev); 91234683adeSsg70180 return (1); 9131ae08745Sheppo } else { 91434683adeSsg70180 cmn_err(CE_NOTE, "vsw%d: Using device name (%s) from " 91534683adeSsg70180 "config file", vswp->instance, dev); 9161ae08745Sheppo 91734683adeSsg70180 (void) strncpy(name, dev, strlen(dev) + 1); 9181ae08745Sheppo } 9191ae08745Sheppo 9201ae08745Sheppo ddi_prop_free(dev); 9211ae08745Sheppo } 9221ae08745Sheppo #endif 9231ae08745Sheppo 92434683adeSsg70180 return (0); 92534683adeSsg70180 } 926e1ebb9ecSlm66018 927e1ebb9ecSlm66018 /* 92834683adeSsg70180 * Read the 'vsw-switch-mode' property from the specified MD node. 92934683adeSsg70180 * 93034683adeSsg70180 * Returns 0 on success and the number of modes found in 'found', 93134683adeSsg70180 * otherwise returns 1. 932e1ebb9ecSlm66018 */ 93334683adeSsg70180 static int 93434683adeSsg70180 vsw_get_md_smodes(vsw_t *vswp, md_t *mdp, mde_cookie_t node, 93534683adeSsg70180 uint8_t *modes, int *found) 93634683adeSsg70180 { 93734683adeSsg70180 int len = 0; 93834683adeSsg70180 int smode_num = 0; 93934683adeSsg70180 char *smode = NULL; 94034683adeSsg70180 char *curr_mode = NULL; 94134683adeSsg70180 94234683adeSsg70180 D1(vswp, "%s: enter", __func__); 9431ae08745Sheppo 9441ae08745Sheppo /* 9451ae08745Sheppo * Get the switch-mode property. The modes are listed in 9461ae08745Sheppo * decreasing order of preference, i.e. prefered mode is 9471ae08745Sheppo * first item in list. 9481ae08745Sheppo */ 9491ae08745Sheppo len = 0; 95034683adeSsg70180 smode_num = 0; 95134683adeSsg70180 if (md_get_prop_data(mdp, node, smode_propname, 9521ae08745Sheppo (uint8_t **)(&smode), &len) != 0) { 9531ae08745Sheppo /* 954e1ebb9ecSlm66018 * Unable to get switch-mode property from MD, nothing 955e1ebb9ecSlm66018 * more we can do. 9561ae08745Sheppo */ 95734683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to get switch mode property" 95834683adeSsg70180 " from the MD", vswp->instance); 95934683adeSsg70180 *found = 0; 96034683adeSsg70180 return (1); 961e1ebb9ecSlm66018 } 962e1ebb9ecSlm66018 9631ae08745Sheppo curr_mode = smode; 9641ae08745Sheppo /* 9651ae08745Sheppo * Modes of operation: 9661ae08745Sheppo * 'switched' - layer 2 switching, underlying HW in 967e1ebb9ecSlm66018 * programmed mode. 9681ae08745Sheppo * 'promiscuous' - layer 2 switching, underlying HW in 9691ae08745Sheppo * promiscuous mode. 9701ae08745Sheppo * 'routed' - layer 3 (i.e. IP) routing, underlying HW 9711ae08745Sheppo * in non-promiscuous mode. 9721ae08745Sheppo */ 97334683adeSsg70180 while ((curr_mode < (smode + len)) && (smode_num < NUM_SMODES)) { 9741ae08745Sheppo D2(vswp, "%s: curr_mode = [%s]", __func__, curr_mode); 975e1ebb9ecSlm66018 if (strcmp(curr_mode, "switched") == 0) { 97634683adeSsg70180 modes[smode_num++] = VSW_LAYER2; 977e1ebb9ecSlm66018 } else if (strcmp(curr_mode, "promiscuous") == 0) { 97834683adeSsg70180 modes[smode_num++] = VSW_LAYER2_PROMISC; 979e1ebb9ecSlm66018 } else if (strcmp(curr_mode, "routed") == 0) { 98034683adeSsg70180 modes[smode_num++] = VSW_LAYER3; 981e1ebb9ecSlm66018 } else { 9821ef0bbb5Snarayan DWARN(vswp, "%s: Unknown switch mode %s, " 9831ef0bbb5Snarayan "setting to default 'switched' mode", 9841ef0bbb5Snarayan __func__, curr_mode); 98534683adeSsg70180 modes[smode_num++] = VSW_LAYER2; 9861ae08745Sheppo } 9871ae08745Sheppo curr_mode += strlen(curr_mode) + 1; 9881ae08745Sheppo } 98934683adeSsg70180 *found = smode_num; 9901ae08745Sheppo 99134683adeSsg70180 D2(vswp, "%s: %d modes found", __func__, smode_num); 9921ae08745Sheppo 9931ae08745Sheppo D1(vswp, "%s: exit", __func__); 99434683adeSsg70180 99534683adeSsg70180 return (0); 9961ae08745Sheppo } 9971ae08745Sheppo 998e1ebb9ecSlm66018 /* 9991ae08745Sheppo * Register with the MAC layer as a network device, so we 10001ae08745Sheppo * can be plumbed if necessary. 10011ae08745Sheppo */ 10021ae08745Sheppo static int 10031ae08745Sheppo vsw_mac_register(vsw_t *vswp) 10041ae08745Sheppo { 1005ba2e4443Sseb mac_register_t *macp; 1006ba2e4443Sseb int rv; 10071ae08745Sheppo 10081ae08745Sheppo D1(vswp, "%s: enter", __func__); 10091ae08745Sheppo 1010ba2e4443Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 1011ba2e4443Sseb return (EINVAL); 1012ba2e4443Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 10131ae08745Sheppo macp->m_driver = vswp; 1014ba2e4443Sseb macp->m_dip = vswp->dip; 1015ba2e4443Sseb macp->m_src_addr = (uint8_t *)&vswp->if_addr; 1016ba2e4443Sseb macp->m_callbacks = &vsw_m_callbacks; 1017ba2e4443Sseb macp->m_min_sdu = 0; 1018*c1c61f44Ssb155480 macp->m_max_sdu = vsw_ethermtu; 1019*c1c61f44Ssb155480 macp->m_margin = VLAN_TAGSZ; 1020ba2e4443Sseb rv = mac_register(macp, &vswp->if_mh); 1021ba2e4443Sseb mac_free(macp); 102219b65a69Ssb155480 if (rv != 0) { 102319b65a69Ssb155480 /* 102419b65a69Ssb155480 * Treat this as a non-fatal error as we may be 102519b65a69Ssb155480 * able to operate in some other mode. 102619b65a69Ssb155480 */ 102719b65a69Ssb155480 cmn_err(CE_NOTE, "!vsw%d: Unable to register as " 102819b65a69Ssb155480 "a provider with MAC layer", vswp->instance); 102919b65a69Ssb155480 return (rv); 103019b65a69Ssb155480 } 103119b65a69Ssb155480 1032ba2e4443Sseb vswp->if_state |= VSW_IF_REG; 10331ae08745Sheppo 1034*c1c61f44Ssb155480 vswp->max_frame_size = vsw_ethermtu + sizeof (struct ether_header) 1035*c1c61f44Ssb155480 + VLAN_TAGSZ; 1036*c1c61f44Ssb155480 10371ae08745Sheppo D1(vswp, "%s: exit", __func__); 10381ae08745Sheppo 10391ae08745Sheppo return (rv); 10401ae08745Sheppo } 10411ae08745Sheppo 10421ae08745Sheppo static int 10431ae08745Sheppo vsw_mac_unregister(vsw_t *vswp) 10441ae08745Sheppo { 10451ae08745Sheppo int rv = 0; 10461ae08745Sheppo 10471ae08745Sheppo D1(vswp, "%s: enter", __func__); 10481ae08745Sheppo 10491ae08745Sheppo WRITE_ENTER(&vswp->if_lockrw); 10501ae08745Sheppo 1051ba2e4443Sseb if (vswp->if_state & VSW_IF_REG) { 1052ba2e4443Sseb rv = mac_unregister(vswp->if_mh); 10531ae08745Sheppo if (rv != 0) { 10541ae08745Sheppo DWARN(vswp, "%s: unable to unregister from MAC " 10551ae08745Sheppo "framework", __func__); 10561ae08745Sheppo 10571ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 10581ae08745Sheppo D1(vswp, "%s: fail exit", __func__); 10591ae08745Sheppo return (rv); 10601ae08745Sheppo } 10611ae08745Sheppo 1062ba2e4443Sseb /* mark i/f as down and unregistered */ 1063ba2e4443Sseb vswp->if_state &= ~(VSW_IF_UP | VSW_IF_REG); 10641ae08745Sheppo } 10651ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 10661ae08745Sheppo 10671ae08745Sheppo D1(vswp, "%s: exit", __func__); 10681ae08745Sheppo 10691ae08745Sheppo return (rv); 10701ae08745Sheppo } 10711ae08745Sheppo 1072ba2e4443Sseb static int 1073ba2e4443Sseb vsw_m_stat(void *arg, uint_t stat, uint64_t *val) 10741ae08745Sheppo { 10751ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 10761ae08745Sheppo 10771ae08745Sheppo D1(vswp, "%s: enter", __func__); 10781ae08745Sheppo 107934683adeSsg70180 mutex_enter(&vswp->mac_lock); 108034683adeSsg70180 if (vswp->mh == NULL) { 108134683adeSsg70180 mutex_exit(&vswp->mac_lock); 1082ba2e4443Sseb return (EINVAL); 108334683adeSsg70180 } 10841ae08745Sheppo 10851ae08745Sheppo /* return stats from underlying device */ 1086ba2e4443Sseb *val = mac_stat_get(vswp->mh, stat); 108734683adeSsg70180 108834683adeSsg70180 mutex_exit(&vswp->mac_lock); 108934683adeSsg70180 1090ba2e4443Sseb return (0); 10911ae08745Sheppo } 10921ae08745Sheppo 10931ae08745Sheppo static void 10941ae08745Sheppo vsw_m_stop(void *arg) 10951ae08745Sheppo { 10961ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 10971ae08745Sheppo 10981ae08745Sheppo D1(vswp, "%s: enter", __func__); 10991ae08745Sheppo 11001ae08745Sheppo WRITE_ENTER(&vswp->if_lockrw); 11011ae08745Sheppo vswp->if_state &= ~VSW_IF_UP; 11021ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 11031ae08745Sheppo 11045f94e909Ssg70180 mutex_enter(&vswp->hw_lock); 11055f94e909Ssg70180 11065f94e909Ssg70180 (void) vsw_unset_hw(vswp, NULL, VSW_LOCALDEV); 11075f94e909Ssg70180 11085f94e909Ssg70180 if (vswp->recfg_reqd) 11095f94e909Ssg70180 vsw_reconfig_hw(vswp); 11105f94e909Ssg70180 11115f94e909Ssg70180 mutex_exit(&vswp->hw_lock); 11125f94e909Ssg70180 11131ae08745Sheppo D1(vswp, "%s: exit (state = %d)", __func__, vswp->if_state); 11141ae08745Sheppo } 11151ae08745Sheppo 11161ae08745Sheppo static int 11171ae08745Sheppo vsw_m_start(void *arg) 11181ae08745Sheppo { 11191ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 11201ae08745Sheppo 11211ae08745Sheppo D1(vswp, "%s: enter", __func__); 11221ae08745Sheppo 11231ae08745Sheppo WRITE_ENTER(&vswp->if_lockrw); 11241ae08745Sheppo 112519b65a69Ssb155480 vswp->if_state |= VSW_IF_UP; 112619b65a69Ssb155480 112719b65a69Ssb155480 if (vswp->switching_setup_done == B_FALSE) { 112819b65a69Ssb155480 /* 112919b65a69Ssb155480 * If the switching mode has not been setup yet, just 113019b65a69Ssb155480 * return. The unicast address will be programmed 113119b65a69Ssb155480 * after the physical device is successfully setup by the 113219b65a69Ssb155480 * timeout handler. 113319b65a69Ssb155480 */ 113419b65a69Ssb155480 RW_EXIT(&vswp->if_lockrw); 113519b65a69Ssb155480 return (0); 113619b65a69Ssb155480 } 113719b65a69Ssb155480 113819b65a69Ssb155480 /* if in layer2 mode, program unicast address. */ 113919b65a69Ssb155480 if (vswp->mh != NULL) { 11405f94e909Ssg70180 mutex_enter(&vswp->hw_lock); 11415f94e909Ssg70180 (void) vsw_set_hw(vswp, NULL, VSW_LOCALDEV); 11425f94e909Ssg70180 mutex_exit(&vswp->hw_lock); 114319b65a69Ssb155480 } 114419b65a69Ssb155480 114519b65a69Ssb155480 RW_EXIT(&vswp->if_lockrw); 11465f94e909Ssg70180 11471ae08745Sheppo D1(vswp, "%s: exit (state = %d)", __func__, vswp->if_state); 11481ae08745Sheppo return (0); 11491ae08745Sheppo } 11501ae08745Sheppo 11511ae08745Sheppo /* 11521ae08745Sheppo * Change the local interface address. 11535f94e909Ssg70180 * 11545f94e909Ssg70180 * Note: we don't support this entry point. The local 11555f94e909Ssg70180 * mac address of the switch can only be changed via its 11565f94e909Ssg70180 * MD node properties. 11571ae08745Sheppo */ 11581ae08745Sheppo static int 11591ae08745Sheppo vsw_m_unicst(void *arg, const uint8_t *macaddr) 11601ae08745Sheppo { 11615f94e909Ssg70180 _NOTE(ARGUNUSED(arg, macaddr)) 11621ae08745Sheppo 11635f94e909Ssg70180 return (DDI_FAILURE); 11641ae08745Sheppo } 11651ae08745Sheppo 11661ae08745Sheppo static int 11671ae08745Sheppo vsw_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 11681ae08745Sheppo { 11691ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 11701ae08745Sheppo mcst_addr_t *mcst_p = NULL; 11711ae08745Sheppo uint64_t addr = 0x0; 1172e1ebb9ecSlm66018 int i, ret = 0; 11731ae08745Sheppo 11741ae08745Sheppo D1(vswp, "%s: enter", __func__); 11751ae08745Sheppo 11761ae08745Sheppo /* 11771ae08745Sheppo * Convert address into form that can be used 11781ae08745Sheppo * as hash table key. 11791ae08745Sheppo */ 11801ae08745Sheppo for (i = 0; i < ETHERADDRL; i++) { 11811ae08745Sheppo addr = (addr << 8) | mca[i]; 11821ae08745Sheppo } 11831ae08745Sheppo 11841ae08745Sheppo D2(vswp, "%s: addr = 0x%llx", __func__, addr); 11851ae08745Sheppo 11861ae08745Sheppo if (add) { 11871ae08745Sheppo D2(vswp, "%s: adding multicast", __func__); 11881ae08745Sheppo if (vsw_add_mcst(vswp, VSW_LOCALDEV, addr, NULL) == 0) { 11891ae08745Sheppo /* 11901ae08745Sheppo * Update the list of multicast addresses 11911ae08745Sheppo * contained within the vsw_t structure to 11921ae08745Sheppo * include this new one. 11931ae08745Sheppo */ 11941ae08745Sheppo mcst_p = kmem_zalloc(sizeof (mcst_addr_t), KM_NOSLEEP); 11951ae08745Sheppo if (mcst_p == NULL) { 11961ae08745Sheppo DERR(vswp, "%s unable to alloc mem", __func__); 119719b65a69Ssb155480 (void) vsw_del_mcst(vswp, 119819b65a69Ssb155480 VSW_LOCALDEV, addr, NULL); 11991ae08745Sheppo return (1); 12001ae08745Sheppo } 12011ae08745Sheppo mcst_p->addr = addr; 120219b65a69Ssb155480 ether_copy(mca, &mcst_p->mca); 12031ae08745Sheppo 12041ae08745Sheppo /* 12051ae08745Sheppo * Call into the underlying driver to program the 12061ae08745Sheppo * address into HW. 12071ae08745Sheppo */ 120834683adeSsg70180 mutex_enter(&vswp->mac_lock); 1209e1ebb9ecSlm66018 if (vswp->mh != NULL) { 1210e1ebb9ecSlm66018 ret = mac_multicst_add(vswp->mh, mca); 1211e1ebb9ecSlm66018 if (ret != 0) { 12121ef0bbb5Snarayan cmn_err(CE_NOTE, "!vsw%d: unable to " 121334683adeSsg70180 "add multicast address", 121434683adeSsg70180 vswp->instance); 121534683adeSsg70180 mutex_exit(&vswp->mac_lock); 121619b65a69Ssb155480 (void) vsw_del_mcst(vswp, 121719b65a69Ssb155480 VSW_LOCALDEV, addr, NULL); 121819b65a69Ssb155480 kmem_free(mcst_p, sizeof (*mcst_p)); 121919b65a69Ssb155480 return (ret); 1220e1ebb9ecSlm66018 } 122119b65a69Ssb155480 mcst_p->mac_added = B_TRUE; 12221ae08745Sheppo } 122334683adeSsg70180 mutex_exit(&vswp->mac_lock); 122419b65a69Ssb155480 122519b65a69Ssb155480 mutex_enter(&vswp->mca_lock); 122619b65a69Ssb155480 mcst_p->nextp = vswp->mcap; 122719b65a69Ssb155480 vswp->mcap = mcst_p; 122819b65a69Ssb155480 mutex_exit(&vswp->mca_lock); 12291ae08745Sheppo } else { 12301ef0bbb5Snarayan cmn_err(CE_NOTE, "!vsw%d: unable to add multicast " 123134683adeSsg70180 "address", vswp->instance); 1232e1ebb9ecSlm66018 } 1233e1ebb9ecSlm66018 return (ret); 1234e1ebb9ecSlm66018 } 1235e1ebb9ecSlm66018 12361ae08745Sheppo D2(vswp, "%s: removing multicast", __func__); 12371ae08745Sheppo /* 12381ae08745Sheppo * Remove the address from the hash table.. 12391ae08745Sheppo */ 12401ae08745Sheppo if (vsw_del_mcst(vswp, VSW_LOCALDEV, addr, NULL) == 0) { 12411ae08745Sheppo 12421ae08745Sheppo /* 12431ae08745Sheppo * ..and then from the list maintained in the 12441ae08745Sheppo * vsw_t structure. 12451ae08745Sheppo */ 124619b65a69Ssb155480 mcst_p = vsw_del_addr(VSW_LOCALDEV, vswp, addr); 124719b65a69Ssb155480 ASSERT(mcst_p != NULL); 12481ae08745Sheppo 124934683adeSsg70180 mutex_enter(&vswp->mac_lock); 125019b65a69Ssb155480 if (vswp->mh != NULL && mcst_p->mac_added) { 12511ae08745Sheppo (void) mac_multicst_remove(vswp->mh, mca); 125219b65a69Ssb155480 mcst_p->mac_added = B_FALSE; 125319b65a69Ssb155480 } 125434683adeSsg70180 mutex_exit(&vswp->mac_lock); 125519b65a69Ssb155480 kmem_free(mcst_p, sizeof (*mcst_p)); 12561ae08745Sheppo } 12571ae08745Sheppo 12581ae08745Sheppo D1(vswp, "%s: exit", __func__); 12591ae08745Sheppo 12601ae08745Sheppo return (0); 12611ae08745Sheppo } 12621ae08745Sheppo 12631ae08745Sheppo static int 12641ae08745Sheppo vsw_m_promisc(void *arg, boolean_t on) 12651ae08745Sheppo { 12661ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 12671ae08745Sheppo 12681ae08745Sheppo D1(vswp, "%s: enter", __func__); 12691ae08745Sheppo 12701ae08745Sheppo WRITE_ENTER(&vswp->if_lockrw); 12711ae08745Sheppo if (on) 12721ae08745Sheppo vswp->if_state |= VSW_IF_PROMISC; 12731ae08745Sheppo else 12741ae08745Sheppo vswp->if_state &= ~VSW_IF_PROMISC; 12751ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 12761ae08745Sheppo 12771ae08745Sheppo D1(vswp, "%s: exit", __func__); 12781ae08745Sheppo 12791ae08745Sheppo return (0); 12801ae08745Sheppo } 12811ae08745Sheppo 12821ae08745Sheppo static mblk_t * 12831ae08745Sheppo vsw_m_tx(void *arg, mblk_t *mp) 12841ae08745Sheppo { 12851ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 12861ae08745Sheppo 12871ae08745Sheppo D1(vswp, "%s: enter", __func__); 12881ae08745Sheppo 1289*c1c61f44Ssb155480 mp = vsw_vlan_frame_pretag(vswp, VSW_LOCALDEV, mp); 1290*c1c61f44Ssb155480 1291*c1c61f44Ssb155480 if (mp == NULL) { 1292*c1c61f44Ssb155480 return (NULL); 1293*c1c61f44Ssb155480 } 1294*c1c61f44Ssb155480 129534683adeSsg70180 vswp->vsw_switch_frame(vswp, mp, VSW_LOCALDEV, NULL, NULL); 12961ae08745Sheppo 12971ae08745Sheppo D1(vswp, "%s: exit", __func__); 12981ae08745Sheppo 12991ae08745Sheppo return (NULL); 13001ae08745Sheppo } 13011ae08745Sheppo 13021ae08745Sheppo /* 13031ae08745Sheppo * Register for machine description (MD) updates. 130434683adeSsg70180 * 130534683adeSsg70180 * Returns 0 on success, 1 on failure. 13061ae08745Sheppo */ 130734683adeSsg70180 static int 13081ae08745Sheppo vsw_mdeg_register(vsw_t *vswp) 13091ae08745Sheppo { 13101ae08745Sheppo mdeg_prop_spec_t *pspecp; 13111ae08745Sheppo mdeg_node_spec_t *inst_specp; 131234683adeSsg70180 mdeg_handle_t mdeg_hdl, mdeg_port_hdl; 13131ae08745Sheppo size_t templatesz; 131419b65a69Ssb155480 int rv; 13151ae08745Sheppo 13161ae08745Sheppo D1(vswp, "%s: enter", __func__); 13171ae08745Sheppo 131834683adeSsg70180 /* 13191ae08745Sheppo * Allocate and initialize a per-instance copy 13201ae08745Sheppo * of the global property spec array that will 13211ae08745Sheppo * uniquely identify this vsw instance. 13221ae08745Sheppo */ 13231ae08745Sheppo templatesz = sizeof (vsw_prop_template); 13241ae08745Sheppo pspecp = kmem_zalloc(templatesz, KM_SLEEP); 13251ae08745Sheppo 13261ae08745Sheppo bcopy(vsw_prop_template, pspecp, templatesz); 13271ae08745Sheppo 132819b65a69Ssb155480 VSW_SET_MDEG_PROP_INST(pspecp, vswp->regprop); 13291ae08745Sheppo 13301ae08745Sheppo /* initialize the complete prop spec structure */ 13311ae08745Sheppo inst_specp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_SLEEP); 13321ae08745Sheppo inst_specp->namep = "virtual-device"; 13331ae08745Sheppo inst_specp->specp = pspecp; 13341ae08745Sheppo 133519b65a69Ssb155480 D2(vswp, "%s: instance %d registering with mdeg", __func__, 133619b65a69Ssb155480 vswp->regprop); 133734683adeSsg70180 /* 133834683adeSsg70180 * Register an interest in 'virtual-device' nodes with a 133934683adeSsg70180 * 'name' property of 'virtual-network-switch' 134034683adeSsg70180 */ 134134683adeSsg70180 rv = mdeg_register(inst_specp, &vdev_match, vsw_mdeg_cb, 13421ae08745Sheppo (void *)vswp, &mdeg_hdl); 134334683adeSsg70180 if (rv != MDEG_SUCCESS) { 134434683adeSsg70180 DERR(vswp, "%s: mdeg_register failed (%d) for vsw node", 134534683adeSsg70180 __func__, rv); 134634683adeSsg70180 goto mdeg_reg_fail; 134734683adeSsg70180 } 13481ae08745Sheppo 134934683adeSsg70180 /* 135034683adeSsg70180 * Register an interest in 'vsw-port' nodes. 135134683adeSsg70180 */ 135234683adeSsg70180 rv = mdeg_register(inst_specp, &vport_match, vsw_port_mdeg_cb, 135334683adeSsg70180 (void *)vswp, &mdeg_port_hdl); 13541ae08745Sheppo if (rv != MDEG_SUCCESS) { 13551ae08745Sheppo DERR(vswp, "%s: mdeg_register failed (%d)\n", __func__, rv); 135634683adeSsg70180 (void) mdeg_unregister(mdeg_hdl); 135734683adeSsg70180 goto mdeg_reg_fail; 13581ae08745Sheppo } 13591ae08745Sheppo 13601ae08745Sheppo /* save off data that will be needed later */ 13611ae08745Sheppo vswp->inst_spec = inst_specp; 13621ae08745Sheppo vswp->mdeg_hdl = mdeg_hdl; 136334683adeSsg70180 vswp->mdeg_port_hdl = mdeg_port_hdl; 13641ae08745Sheppo 13651ae08745Sheppo D1(vswp, "%s: exit", __func__); 136634683adeSsg70180 return (0); 136734683adeSsg70180 136834683adeSsg70180 mdeg_reg_fail: 136934683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to register MDEG callbacks", 137034683adeSsg70180 vswp->instance); 137134683adeSsg70180 kmem_free(pspecp, templatesz); 137234683adeSsg70180 kmem_free(inst_specp, sizeof (mdeg_node_spec_t)); 137334683adeSsg70180 137434683adeSsg70180 vswp->mdeg_hdl = NULL; 137534683adeSsg70180 vswp->mdeg_port_hdl = NULL; 137634683adeSsg70180 137734683adeSsg70180 return (1); 13781ae08745Sheppo } 13791ae08745Sheppo 13801ae08745Sheppo static void 13811ae08745Sheppo vsw_mdeg_unregister(vsw_t *vswp) 13821ae08745Sheppo { 13831ae08745Sheppo D1(vswp, "vsw_mdeg_unregister: enter"); 13841ae08745Sheppo 138534683adeSsg70180 if (vswp->mdeg_hdl != NULL) 13861ae08745Sheppo (void) mdeg_unregister(vswp->mdeg_hdl); 13871ae08745Sheppo 138834683adeSsg70180 if (vswp->mdeg_port_hdl != NULL) 138934683adeSsg70180 (void) mdeg_unregister(vswp->mdeg_port_hdl); 139034683adeSsg70180 139134683adeSsg70180 if (vswp->inst_spec != NULL) { 13921ae08745Sheppo if (vswp->inst_spec->specp != NULL) { 13931ae08745Sheppo (void) kmem_free(vswp->inst_spec->specp, 13941ae08745Sheppo sizeof (vsw_prop_template)); 13951ae08745Sheppo vswp->inst_spec->specp = NULL; 13961ae08745Sheppo } 13971ae08745Sheppo 1398205eeb1aSlm66018 (void) kmem_free(vswp->inst_spec, sizeof (mdeg_node_spec_t)); 13991ae08745Sheppo vswp->inst_spec = NULL; 14001ae08745Sheppo } 14011ae08745Sheppo 14021ae08745Sheppo D1(vswp, "vsw_mdeg_unregister: exit"); 14031ae08745Sheppo } 14041ae08745Sheppo 140534683adeSsg70180 /* 140634683adeSsg70180 * Mdeg callback invoked for the vsw node itself. 140734683adeSsg70180 */ 14081ae08745Sheppo static int 14091ae08745Sheppo vsw_mdeg_cb(void *cb_argp, mdeg_result_t *resp) 14101ae08745Sheppo { 14111ae08745Sheppo vsw_t *vswp; 14121ae08745Sheppo md_t *mdp; 14131ae08745Sheppo mde_cookie_t node; 14141ae08745Sheppo uint64_t inst; 141534683adeSsg70180 char *node_name = NULL; 14161ae08745Sheppo 14171ae08745Sheppo if (resp == NULL) 14181ae08745Sheppo return (MDEG_FAILURE); 14191ae08745Sheppo 14201ae08745Sheppo vswp = (vsw_t *)cb_argp; 14211ae08745Sheppo 142234683adeSsg70180 D1(vswp, "%s: added %d : removed %d : curr matched %d" 142334683adeSsg70180 " : prev matched %d", __func__, resp->added.nelem, 142434683adeSsg70180 resp->removed.nelem, resp->match_curr.nelem, 142534683adeSsg70180 resp->match_prev.nelem); 142634683adeSsg70180 142734683adeSsg70180 /* 142819b65a69Ssb155480 * We get an initial callback for this node as 'added' 142919b65a69Ssb155480 * after registering with mdeg. Note that we would have 143019b65a69Ssb155480 * already gathered information about this vsw node by 143119b65a69Ssb155480 * walking MD earlier during attach (in vsw_read_mdprops()). 143219b65a69Ssb155480 * So, there is a window where the properties of this 143319b65a69Ssb155480 * node might have changed when we get this initial 'added' 143419b65a69Ssb155480 * callback. We handle this as if an update occured 143519b65a69Ssb155480 * and invoke the same function which handles updates to 143619b65a69Ssb155480 * the properties of this vsw-node if any. 143719b65a69Ssb155480 * 143834683adeSsg70180 * A non-zero 'match' value indicates that the MD has been 143919b65a69Ssb155480 * updated and that a virtual-network-switch node is 144019b65a69Ssb155480 * present which may or may not have been updated. It is 144119b65a69Ssb155480 * up to the clients to examine their own nodes and 144219b65a69Ssb155480 * determine if they have changed. 144334683adeSsg70180 */ 144419b65a69Ssb155480 if (resp->added.nelem != 0) { 144534683adeSsg70180 144619b65a69Ssb155480 if (resp->added.nelem != 1) { 144719b65a69Ssb155480 cmn_err(CE_NOTE, "!vsw%d: number of nodes added " 144819b65a69Ssb155480 "invalid: %d\n", vswp->instance, resp->added.nelem); 144919b65a69Ssb155480 return (MDEG_FAILURE); 145019b65a69Ssb155480 } 145119b65a69Ssb155480 145219b65a69Ssb155480 mdp = resp->added.mdp; 145319b65a69Ssb155480 node = resp->added.mdep[0]; 145419b65a69Ssb155480 145519b65a69Ssb155480 } else if (resp->match_curr.nelem != 0) { 145619b65a69Ssb155480 145719b65a69Ssb155480 if (resp->match_curr.nelem != 1) { 145819b65a69Ssb155480 cmn_err(CE_NOTE, "!vsw%d: number of nodes updated " 145919b65a69Ssb155480 "invalid: %d\n", vswp->instance, 146019b65a69Ssb155480 resp->match_curr.nelem); 146119b65a69Ssb155480 return (MDEG_FAILURE); 146219b65a69Ssb155480 } 146319b65a69Ssb155480 146419b65a69Ssb155480 mdp = resp->match_curr.mdp; 146519b65a69Ssb155480 node = resp->match_curr.mdep[0]; 146619b65a69Ssb155480 146719b65a69Ssb155480 } else { 146819b65a69Ssb155480 return (MDEG_FAILURE); 146919b65a69Ssb155480 } 147019b65a69Ssb155480 147119b65a69Ssb155480 /* Validate name and instance */ 147234683adeSsg70180 if (md_get_prop_str(mdp, node, "name", &node_name) != 0) { 147319b65a69Ssb155480 DERR(vswp, "%s: unable to get node name\n", __func__); 147419b65a69Ssb155480 return (MDEG_FAILURE); 147519b65a69Ssb155480 } 147619b65a69Ssb155480 147719b65a69Ssb155480 /* is this a virtual-network-switch? */ 147819b65a69Ssb155480 if (strcmp(node_name, vsw_propname) != 0) { 147919b65a69Ssb155480 DERR(vswp, "%s: Invalid node name: %s\n", 148019b65a69Ssb155480 __func__, node_name); 148119b65a69Ssb155480 return (MDEG_FAILURE); 148234683adeSsg70180 } 148334683adeSsg70180 148434683adeSsg70180 if (md_get_prop_val(mdp, node, "cfg-handle", &inst)) { 148519b65a69Ssb155480 DERR(vswp, "%s: prop(cfg-handle) not found\n", 148619b65a69Ssb155480 __func__); 148719b65a69Ssb155480 return (MDEG_FAILURE); 148834683adeSsg70180 } 148934683adeSsg70180 149019b65a69Ssb155480 /* is this the right instance of vsw? */ 149119b65a69Ssb155480 if (inst != vswp->regprop) { 149219b65a69Ssb155480 DERR(vswp, "%s: Invalid cfg-handle: %lx\n", 149319b65a69Ssb155480 __func__, inst); 149419b65a69Ssb155480 return (MDEG_FAILURE); 149519b65a69Ssb155480 } 149634683adeSsg70180 149734683adeSsg70180 vsw_update_md_prop(vswp, mdp, node); 149834683adeSsg70180 149934683adeSsg70180 return (MDEG_SUCCESS); 150034683adeSsg70180 } 150134683adeSsg70180 150234683adeSsg70180 /* 150334683adeSsg70180 * Mdeg callback invoked for changes to the vsw-port nodes 150434683adeSsg70180 * under the vsw node. 150534683adeSsg70180 */ 150634683adeSsg70180 static int 150734683adeSsg70180 vsw_port_mdeg_cb(void *cb_argp, mdeg_result_t *resp) 150834683adeSsg70180 { 150934683adeSsg70180 vsw_t *vswp; 151034683adeSsg70180 int idx; 151134683adeSsg70180 md_t *mdp; 151234683adeSsg70180 mde_cookie_t node; 151334683adeSsg70180 uint64_t inst; 15141ef0bbb5Snarayan int rv; 151534683adeSsg70180 151634683adeSsg70180 if ((resp == NULL) || (cb_argp == NULL)) 151734683adeSsg70180 return (MDEG_FAILURE); 151834683adeSsg70180 151934683adeSsg70180 vswp = (vsw_t *)cb_argp; 152034683adeSsg70180 152134683adeSsg70180 D2(vswp, "%s: added %d : removed %d : curr matched %d" 152234683adeSsg70180 " : prev matched %d", __func__, resp->added.nelem, 152334683adeSsg70180 resp->removed.nelem, resp->match_curr.nelem, 15241ae08745Sheppo resp->match_prev.nelem); 15251ae08745Sheppo 15261ae08745Sheppo /* process added ports */ 15271ae08745Sheppo for (idx = 0; idx < resp->added.nelem; idx++) { 15281ae08745Sheppo mdp = resp->added.mdp; 15291ae08745Sheppo node = resp->added.mdep[idx]; 15301ae08745Sheppo 15311ae08745Sheppo D2(vswp, "%s: adding node(%d) 0x%lx", __func__, idx, node); 15321ae08745Sheppo 15331ef0bbb5Snarayan if ((rv = vsw_port_add(vswp, mdp, &node)) != 0) { 153434683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to add new port " 15351ef0bbb5Snarayan "(0x%lx), err=%d", vswp->instance, node, rv); 15361ae08745Sheppo } 15371ae08745Sheppo } 15381ae08745Sheppo 15391ae08745Sheppo /* process removed ports */ 15401ae08745Sheppo for (idx = 0; idx < resp->removed.nelem; idx++) { 15411ae08745Sheppo mdp = resp->removed.mdp; 15421ae08745Sheppo node = resp->removed.mdep[idx]; 15431ae08745Sheppo 15441ae08745Sheppo if (md_get_prop_val(mdp, node, id_propname, &inst)) { 154534683adeSsg70180 DERR(vswp, "%s: prop(%s) not found in port(%d)", 15461ae08745Sheppo __func__, id_propname, idx); 15471ae08745Sheppo continue; 15481ae08745Sheppo } 15491ae08745Sheppo 15501ae08745Sheppo D2(vswp, "%s: removing node(%d) 0x%lx", __func__, idx, node); 15511ae08745Sheppo 15521ae08745Sheppo if (vsw_port_detach(vswp, inst) != 0) { 155334683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to remove port %ld", 155434683adeSsg70180 vswp->instance, inst); 15551ae08745Sheppo } 15561ae08745Sheppo } 15571ae08745Sheppo 1558*c1c61f44Ssb155480 for (idx = 0; idx < resp->match_curr.nelem; idx++) { 1559*c1c61f44Ssb155480 (void) vsw_port_update(vswp, resp->match_curr.mdp, 1560*c1c61f44Ssb155480 resp->match_curr.mdep[idx], 1561*c1c61f44Ssb155480 resp->match_prev.mdp, 1562*c1c61f44Ssb155480 resp->match_prev.mdep[idx]); 1563*c1c61f44Ssb155480 } 15641ae08745Sheppo 15651ae08745Sheppo D1(vswp, "%s: exit", __func__); 15661ae08745Sheppo 15671ae08745Sheppo return (MDEG_SUCCESS); 15681ae08745Sheppo } 15691ae08745Sheppo 15701ae08745Sheppo /* 157119b65a69Ssb155480 * Scan the machine description for this instance of vsw 157219b65a69Ssb155480 * and read its properties. Called only from vsw_attach(). 157319b65a69Ssb155480 * Returns: 0 on success, 1 on failure. 157419b65a69Ssb155480 */ 157519b65a69Ssb155480 static int 157619b65a69Ssb155480 vsw_read_mdprops(vsw_t *vswp) 157719b65a69Ssb155480 { 157819b65a69Ssb155480 md_t *mdp = NULL; 157919b65a69Ssb155480 mde_cookie_t rootnode; 158019b65a69Ssb155480 mde_cookie_t *listp = NULL; 158119b65a69Ssb155480 uint64_t inst; 158219b65a69Ssb155480 uint64_t cfgh; 158319b65a69Ssb155480 char *name; 158419b65a69Ssb155480 int rv = 1; 158519b65a69Ssb155480 int num_nodes = 0; 158619b65a69Ssb155480 int num_devs = 0; 158719b65a69Ssb155480 int listsz = 0; 158819b65a69Ssb155480 int i; 158919b65a69Ssb155480 159019b65a69Ssb155480 /* 159119b65a69Ssb155480 * In each 'virtual-device' node in the MD there is a 159219b65a69Ssb155480 * 'cfg-handle' property which is the MD's concept of 159319b65a69Ssb155480 * an instance number (this may be completely different from 159419b65a69Ssb155480 * the device drivers instance #). OBP reads that value and 159519b65a69Ssb155480 * stores it in the 'reg' property of the appropriate node in 159619b65a69Ssb155480 * the device tree. We first read this reg property and use this 159719b65a69Ssb155480 * to compare against the 'cfg-handle' property of vsw nodes 159819b65a69Ssb155480 * in MD to get to this specific vsw instance and then read 159919b65a69Ssb155480 * other properties that we are interested in. 160019b65a69Ssb155480 * We also cache the value of 'reg' property and use it later 160119b65a69Ssb155480 * to register callbacks with mdeg (see vsw_mdeg_register()) 160219b65a69Ssb155480 */ 160319b65a69Ssb155480 inst = ddi_prop_get_int(DDI_DEV_T_ANY, vswp->dip, 160419b65a69Ssb155480 DDI_PROP_DONTPASS, reg_propname, -1); 160519b65a69Ssb155480 if (inst == -1) { 160619b65a69Ssb155480 cmn_err(CE_NOTE, "!vsw%d: Unable to read %s property from " 160719b65a69Ssb155480 "OBP device tree", vswp->instance, reg_propname); 160819b65a69Ssb155480 return (rv); 160919b65a69Ssb155480 } 161019b65a69Ssb155480 161119b65a69Ssb155480 vswp->regprop = inst; 161219b65a69Ssb155480 161319b65a69Ssb155480 if ((mdp = md_get_handle()) == NULL) { 161419b65a69Ssb155480 DWARN(vswp, "%s: cannot init MD\n", __func__); 161519b65a69Ssb155480 return (rv); 161619b65a69Ssb155480 } 161719b65a69Ssb155480 161819b65a69Ssb155480 num_nodes = md_node_count(mdp); 161919b65a69Ssb155480 ASSERT(num_nodes > 0); 162019b65a69Ssb155480 162119b65a69Ssb155480 listsz = num_nodes * sizeof (mde_cookie_t); 162219b65a69Ssb155480 listp = (mde_cookie_t *)kmem_zalloc(listsz, KM_SLEEP); 162319b65a69Ssb155480 162419b65a69Ssb155480 rootnode = md_root_node(mdp); 162519b65a69Ssb155480 162619b65a69Ssb155480 /* search for all "virtual_device" nodes */ 162719b65a69Ssb155480 num_devs = md_scan_dag(mdp, rootnode, 162819b65a69Ssb155480 md_find_name(mdp, vdev_propname), 162919b65a69Ssb155480 md_find_name(mdp, "fwd"), listp); 163019b65a69Ssb155480 if (num_devs <= 0) { 163119b65a69Ssb155480 DWARN(vswp, "%s: invalid num_devs:%d\n", __func__, num_devs); 163219b65a69Ssb155480 goto vsw_readmd_exit; 163319b65a69Ssb155480 } 163419b65a69Ssb155480 163519b65a69Ssb155480 /* 163619b65a69Ssb155480 * Now loop through the list of virtual-devices looking for 163719b65a69Ssb155480 * devices with name "virtual-network-switch" and for each 163819b65a69Ssb155480 * such device compare its instance with what we have from 163919b65a69Ssb155480 * the 'reg' property to find the right node in MD and then 164019b65a69Ssb155480 * read all its properties. 164119b65a69Ssb155480 */ 164219b65a69Ssb155480 for (i = 0; i < num_devs; i++) { 164319b65a69Ssb155480 164419b65a69Ssb155480 if (md_get_prop_str(mdp, listp[i], "name", &name) != 0) { 164519b65a69Ssb155480 DWARN(vswp, "%s: name property not found\n", 164619b65a69Ssb155480 __func__); 164719b65a69Ssb155480 goto vsw_readmd_exit; 164819b65a69Ssb155480 } 164919b65a69Ssb155480 165019b65a69Ssb155480 /* is this a virtual-network-switch? */ 165119b65a69Ssb155480 if (strcmp(name, vsw_propname) != 0) 165219b65a69Ssb155480 continue; 165319b65a69Ssb155480 165419b65a69Ssb155480 if (md_get_prop_val(mdp, listp[i], "cfg-handle", &cfgh) != 0) { 165519b65a69Ssb155480 DWARN(vswp, "%s: cfg-handle property not found\n", 165619b65a69Ssb155480 __func__); 165719b65a69Ssb155480 goto vsw_readmd_exit; 165819b65a69Ssb155480 } 165919b65a69Ssb155480 166019b65a69Ssb155480 /* is this the required instance of vsw? */ 166119b65a69Ssb155480 if (inst != cfgh) 166219b65a69Ssb155480 continue; 166319b65a69Ssb155480 166419b65a69Ssb155480 /* now read all properties of this vsw instance */ 166519b65a69Ssb155480 rv = vsw_get_initial_md_properties(vswp, mdp, listp[i]); 166619b65a69Ssb155480 break; 166719b65a69Ssb155480 } 166819b65a69Ssb155480 166919b65a69Ssb155480 vsw_readmd_exit: 167019b65a69Ssb155480 167119b65a69Ssb155480 kmem_free(listp, listsz); 167219b65a69Ssb155480 (void) md_fini_handle(mdp); 167319b65a69Ssb155480 return (rv); 167419b65a69Ssb155480 } 167519b65a69Ssb155480 167619b65a69Ssb155480 /* 167734683adeSsg70180 * Read the initial start-of-day values from the specified MD node. 167834683adeSsg70180 */ 167919b65a69Ssb155480 static int 168034683adeSsg70180 vsw_get_initial_md_properties(vsw_t *vswp, md_t *mdp, mde_cookie_t node) 168134683adeSsg70180 { 168234683adeSsg70180 int i; 168334683adeSsg70180 uint64_t macaddr = 0; 168434683adeSsg70180 168534683adeSsg70180 D1(vswp, "%s: enter", __func__); 168634683adeSsg70180 168719b65a69Ssb155480 if (vsw_get_md_physname(vswp, mdp, node, vswp->physname) != 0) { 168819b65a69Ssb155480 return (1); 168934683adeSsg70180 } 169034683adeSsg70180 169134683adeSsg70180 /* mac address for vswitch device itself */ 169234683adeSsg70180 if (md_get_prop_val(mdp, node, macaddr_propname, &macaddr) != 0) { 169334683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to get MAC address from MD", 169434683adeSsg70180 vswp->instance); 169519b65a69Ssb155480 return (1); 169619b65a69Ssb155480 } 169734683adeSsg70180 169819b65a69Ssb155480 vsw_save_lmacaddr(vswp, macaddr); 169934683adeSsg70180 1700205eeb1aSlm66018 if (vsw_get_md_smodes(vswp, mdp, node, vswp->smode, &vswp->smode_num)) { 17011ef0bbb5Snarayan DWARN(vswp, "%s: Unable to read %s property from MD, " 17021ef0bbb5Snarayan "defaulting to 'switched' mode", 17031ef0bbb5Snarayan __func__, smode_propname); 170434683adeSsg70180 170534683adeSsg70180 for (i = 0; i < NUM_SMODES; i++) 170634683adeSsg70180 vswp->smode[i] = VSW_LAYER2; 170734683adeSsg70180 170834683adeSsg70180 vswp->smode_num = NUM_SMODES; 170934683adeSsg70180 } else { 171034683adeSsg70180 ASSERT(vswp->smode_num != 0); 171134683adeSsg70180 } 171234683adeSsg70180 1713*c1c61f44Ssb155480 /* read vlan id properties of this vsw instance */ 1714*c1c61f44Ssb155480 vsw_vlan_read_ids(vswp, VSW_LOCALDEV, mdp, node, &vswp->pvid, 1715*c1c61f44Ssb155480 &vswp->vids, &vswp->nvids, &vswp->default_vlan_id); 1716*c1c61f44Ssb155480 1717*c1c61f44Ssb155480 /* read priority-ether-types */ 1718f0ca1d9aSsb155480 vsw_read_pri_eth_types(vswp, mdp, node); 1719f0ca1d9aSsb155480 172034683adeSsg70180 D1(vswp, "%s: exit", __func__); 172119b65a69Ssb155480 return (0); 172234683adeSsg70180 } 172334683adeSsg70180 172434683adeSsg70180 /* 1725*c1c61f44Ssb155480 * Read vlan id properties of the given MD node. 1726*c1c61f44Ssb155480 * Arguments: 1727*c1c61f44Ssb155480 * arg: device argument(vsw device or a port) 1728*c1c61f44Ssb155480 * type: type of arg; VSW_LOCALDEV(vsw device) or VSW_VNETPORT(port) 1729*c1c61f44Ssb155480 * mdp: machine description 1730*c1c61f44Ssb155480 * node: md node cookie 1731*c1c61f44Ssb155480 * 1732*c1c61f44Ssb155480 * Returns: 1733*c1c61f44Ssb155480 * pvidp: port-vlan-id of the node 1734*c1c61f44Ssb155480 * vidspp: list of vlan-ids of the node 1735*c1c61f44Ssb155480 * nvidsp: # of vlan-ids in the list 1736*c1c61f44Ssb155480 * default_idp: default-vlan-id of the node(if node is vsw device) 1737*c1c61f44Ssb155480 */ 1738*c1c61f44Ssb155480 static void 1739*c1c61f44Ssb155480 vsw_vlan_read_ids(void *arg, int type, md_t *mdp, mde_cookie_t node, 1740*c1c61f44Ssb155480 uint16_t *pvidp, uint16_t **vidspp, uint16_t *nvidsp, 1741*c1c61f44Ssb155480 uint16_t *default_idp) 1742*c1c61f44Ssb155480 { 1743*c1c61f44Ssb155480 vsw_t *vswp; 1744*c1c61f44Ssb155480 vsw_port_t *portp; 1745*c1c61f44Ssb155480 char *pvid_propname; 1746*c1c61f44Ssb155480 char *vid_propname; 1747*c1c61f44Ssb155480 uint_t nvids = 0; 1748*c1c61f44Ssb155480 uint32_t vids_size; 1749*c1c61f44Ssb155480 int rv; 1750*c1c61f44Ssb155480 int i; 1751*c1c61f44Ssb155480 uint64_t *data; 1752*c1c61f44Ssb155480 uint64_t val; 1753*c1c61f44Ssb155480 int size; 1754*c1c61f44Ssb155480 int inst; 1755*c1c61f44Ssb155480 1756*c1c61f44Ssb155480 if (type == VSW_LOCALDEV) { 1757*c1c61f44Ssb155480 1758*c1c61f44Ssb155480 vswp = (vsw_t *)arg; 1759*c1c61f44Ssb155480 pvid_propname = vsw_pvid_propname; 1760*c1c61f44Ssb155480 vid_propname = vsw_vid_propname; 1761*c1c61f44Ssb155480 inst = vswp->instance; 1762*c1c61f44Ssb155480 1763*c1c61f44Ssb155480 } else if (type == VSW_VNETPORT) { 1764*c1c61f44Ssb155480 1765*c1c61f44Ssb155480 portp = (vsw_port_t *)arg; 1766*c1c61f44Ssb155480 vswp = portp->p_vswp; 1767*c1c61f44Ssb155480 pvid_propname = port_pvid_propname; 1768*c1c61f44Ssb155480 vid_propname = port_vid_propname; 1769*c1c61f44Ssb155480 inst = portp->p_instance; 1770*c1c61f44Ssb155480 1771*c1c61f44Ssb155480 } else { 1772*c1c61f44Ssb155480 return; 1773*c1c61f44Ssb155480 } 1774*c1c61f44Ssb155480 1775*c1c61f44Ssb155480 if (type == VSW_LOCALDEV && default_idp != NULL) { 1776*c1c61f44Ssb155480 rv = md_get_prop_val(mdp, node, vsw_dvid_propname, &val); 1777*c1c61f44Ssb155480 if (rv != 0) { 1778*c1c61f44Ssb155480 DWARN(vswp, "%s: prop(%s) not found", __func__, 1779*c1c61f44Ssb155480 vsw_dvid_propname); 1780*c1c61f44Ssb155480 1781*c1c61f44Ssb155480 *default_idp = vsw_default_vlan_id; 1782*c1c61f44Ssb155480 } else { 1783*c1c61f44Ssb155480 *default_idp = val & 0xFFF; 1784*c1c61f44Ssb155480 D2(vswp, "%s: %s(%d): (%d)\n", __func__, 1785*c1c61f44Ssb155480 vsw_dvid_propname, inst, *default_idp); 1786*c1c61f44Ssb155480 } 1787*c1c61f44Ssb155480 } 1788*c1c61f44Ssb155480 1789*c1c61f44Ssb155480 rv = md_get_prop_val(mdp, node, pvid_propname, &val); 1790*c1c61f44Ssb155480 if (rv != 0) { 1791*c1c61f44Ssb155480 DWARN(vswp, "%s: prop(%s) not found", __func__, pvid_propname); 1792*c1c61f44Ssb155480 *pvidp = vsw_default_vlan_id; 1793*c1c61f44Ssb155480 } else { 1794*c1c61f44Ssb155480 1795*c1c61f44Ssb155480 *pvidp = val & 0xFFF; 1796*c1c61f44Ssb155480 D2(vswp, "%s: %s(%d): (%d)\n", __func__, 1797*c1c61f44Ssb155480 pvid_propname, inst, *pvidp); 1798*c1c61f44Ssb155480 } 1799*c1c61f44Ssb155480 1800*c1c61f44Ssb155480 rv = md_get_prop_data(mdp, node, vid_propname, (uint8_t **)&data, 1801*c1c61f44Ssb155480 &size); 1802*c1c61f44Ssb155480 if (rv != 0) { 1803*c1c61f44Ssb155480 D2(vswp, "%s: prop(%s) not found", __func__, vid_propname); 1804*c1c61f44Ssb155480 size = 0; 1805*c1c61f44Ssb155480 } else { 1806*c1c61f44Ssb155480 size /= sizeof (uint64_t); 1807*c1c61f44Ssb155480 } 1808*c1c61f44Ssb155480 nvids = size; 1809*c1c61f44Ssb155480 1810*c1c61f44Ssb155480 if (nvids != 0) { 1811*c1c61f44Ssb155480 D2(vswp, "%s: %s(%d): ", __func__, vid_propname, inst); 1812*c1c61f44Ssb155480 vids_size = sizeof (uint16_t) * nvids; 1813*c1c61f44Ssb155480 *vidspp = kmem_zalloc(vids_size, KM_SLEEP); 1814*c1c61f44Ssb155480 for (i = 0; i < nvids; i++) { 1815*c1c61f44Ssb155480 (*vidspp)[i] = data[i] & 0xFFFF; 1816*c1c61f44Ssb155480 D2(vswp, " %d ", (*vidspp)[i]); 1817*c1c61f44Ssb155480 } 1818*c1c61f44Ssb155480 D2(vswp, "\n"); 1819*c1c61f44Ssb155480 } 1820*c1c61f44Ssb155480 1821*c1c61f44Ssb155480 *nvidsp = nvids; 1822*c1c61f44Ssb155480 } 1823*c1c61f44Ssb155480 1824*c1c61f44Ssb155480 /* 1825f0ca1d9aSsb155480 * This function reads "priority-ether-types" property from md. This property 1826f0ca1d9aSsb155480 * is used to enable support for priority frames. Applications which need 1827f0ca1d9aSsb155480 * guaranteed and timely delivery of certain high priority frames to/from 1828f0ca1d9aSsb155480 * a vnet or vsw within ldoms, should configure this property by providing 1829f0ca1d9aSsb155480 * the ether type(s) for which the priority facility is needed. 1830f0ca1d9aSsb155480 * Normal data frames are delivered over a ldc channel using the descriptor 1831f0ca1d9aSsb155480 * ring mechanism which is constrained by factors such as descriptor ring size, 1832f0ca1d9aSsb155480 * the rate at which the ring is processed at the peer ldc end point, etc. 1833f0ca1d9aSsb155480 * The priority mechanism provides an Out-Of-Band path to send/receive frames 1834f0ca1d9aSsb155480 * as raw pkt data (VIO_PKT_DATA) messages over the channel, avoiding the 1835f0ca1d9aSsb155480 * descriptor ring path and enables a more reliable and timely delivery of 1836f0ca1d9aSsb155480 * frames to the peer. 1837f0ca1d9aSsb155480 */ 1838f0ca1d9aSsb155480 static void 1839f0ca1d9aSsb155480 vsw_read_pri_eth_types(vsw_t *vswp, md_t *mdp, mde_cookie_t node) 1840f0ca1d9aSsb155480 { 1841f0ca1d9aSsb155480 int rv; 1842f0ca1d9aSsb155480 uint16_t *types; 1843f0ca1d9aSsb155480 uint64_t *data; 1844f0ca1d9aSsb155480 int size; 1845f0ca1d9aSsb155480 int i; 1846f0ca1d9aSsb155480 size_t mblk_sz; 1847f0ca1d9aSsb155480 1848f0ca1d9aSsb155480 rv = md_get_prop_data(mdp, node, pri_types_propname, 1849f0ca1d9aSsb155480 (uint8_t **)&data, &size); 1850f0ca1d9aSsb155480 if (rv != 0) { 1851f0ca1d9aSsb155480 /* 1852f0ca1d9aSsb155480 * Property may not exist if we are running pre-ldoms1.1 f/w. 1853f0ca1d9aSsb155480 * Check if 'vsw_pri_eth_type' has been set in that case. 1854f0ca1d9aSsb155480 */ 1855f0ca1d9aSsb155480 if (vsw_pri_eth_type != 0) { 1856f0ca1d9aSsb155480 size = sizeof (vsw_pri_eth_type); 1857f0ca1d9aSsb155480 data = &vsw_pri_eth_type; 1858f0ca1d9aSsb155480 } else { 1859f0ca1d9aSsb155480 D3(vswp, "%s: prop(%s) not found", __func__, 1860f0ca1d9aSsb155480 pri_types_propname); 1861f0ca1d9aSsb155480 size = 0; 1862f0ca1d9aSsb155480 } 1863f0ca1d9aSsb155480 } 1864f0ca1d9aSsb155480 1865f0ca1d9aSsb155480 if (size == 0) { 1866f0ca1d9aSsb155480 vswp->pri_num_types = 0; 1867f0ca1d9aSsb155480 return; 1868f0ca1d9aSsb155480 } 1869f0ca1d9aSsb155480 1870f0ca1d9aSsb155480 /* 1871f0ca1d9aSsb155480 * we have some priority-ether-types defined; 1872f0ca1d9aSsb155480 * allocate a table of these types and also 1873f0ca1d9aSsb155480 * allocate a pool of mblks to transmit these 1874f0ca1d9aSsb155480 * priority packets. 1875f0ca1d9aSsb155480 */ 1876f0ca1d9aSsb155480 size /= sizeof (uint64_t); 1877f0ca1d9aSsb155480 vswp->pri_num_types = size; 1878f0ca1d9aSsb155480 vswp->pri_types = kmem_zalloc(size * sizeof (uint16_t), KM_SLEEP); 1879f0ca1d9aSsb155480 for (i = 0, types = vswp->pri_types; i < size; i++) { 1880f0ca1d9aSsb155480 types[i] = data[i] & 0xFFFF; 1881f0ca1d9aSsb155480 } 1882f0ca1d9aSsb155480 mblk_sz = (VIO_PKT_DATA_HDRSIZE + ETHERMAX + 7) & ~7; 1883f0ca1d9aSsb155480 (void) vio_create_mblks(vsw_pri_tx_nmblks, mblk_sz, &vswp->pri_tx_vmp); 1884f0ca1d9aSsb155480 } 1885f0ca1d9aSsb155480 1886f0ca1d9aSsb155480 /* 188734683adeSsg70180 * Check to see if the relevant properties in the specified node have 188834683adeSsg70180 * changed, and if so take the appropriate action. 188934683adeSsg70180 * 189034683adeSsg70180 * If any of the properties are missing or invalid we don't take 189134683adeSsg70180 * any action, as this function should only be invoked when modifications 189234683adeSsg70180 * have been made to what we assume is a working configuration, which 189334683adeSsg70180 * we leave active. 189434683adeSsg70180 * 189534683adeSsg70180 * Note it is legal for this routine to be invoked even if none of the 189634683adeSsg70180 * properties in the port node within the MD have actually changed. 189734683adeSsg70180 */ 189834683adeSsg70180 static void 189934683adeSsg70180 vsw_update_md_prop(vsw_t *vswp, md_t *mdp, mde_cookie_t node) 190034683adeSsg70180 { 190134683adeSsg70180 char physname[LIFNAMSIZ]; 190234683adeSsg70180 char drv[LIFNAMSIZ]; 190334683adeSsg70180 uint_t ddi_instance; 190434683adeSsg70180 uint8_t new_smode[NUM_SMODES]; 190534683adeSsg70180 int i, smode_num = 0; 190634683adeSsg70180 uint64_t macaddr = 0; 190734683adeSsg70180 enum {MD_init = 0x1, 190834683adeSsg70180 MD_physname = 0x2, 190934683adeSsg70180 MD_macaddr = 0x4, 1910*c1c61f44Ssb155480 MD_smode = 0x8, 1911*c1c61f44Ssb155480 MD_vlans = 0x10} updated; 191219b65a69Ssb155480 int rv; 1913*c1c61f44Ssb155480 uint16_t pvid; 1914*c1c61f44Ssb155480 uint16_t *vids; 1915*c1c61f44Ssb155480 uint16_t nvids; 191634683adeSsg70180 191734683adeSsg70180 updated = MD_init; 191834683adeSsg70180 191934683adeSsg70180 D1(vswp, "%s: enter", __func__); 192034683adeSsg70180 192134683adeSsg70180 /* 192234683adeSsg70180 * Check if name of physical device in MD has changed. 192334683adeSsg70180 */ 192434683adeSsg70180 if (vsw_get_md_physname(vswp, mdp, node, (char *)&physname) == 0) { 192534683adeSsg70180 /* 192634683adeSsg70180 * Do basic sanity check on new device name/instance, 192734683adeSsg70180 * if its non NULL. It is valid for the device name to 192834683adeSsg70180 * have changed from a non NULL to a NULL value, i.e. 192934683adeSsg70180 * the vsw is being changed to 'routed' mode. 193034683adeSsg70180 */ 193134683adeSsg70180 if ((strlen(physname) != 0) && 193219b65a69Ssb155480 (ddi_parse(physname, drv, 193319b65a69Ssb155480 &ddi_instance) != DDI_SUCCESS)) { 19341ef0bbb5Snarayan cmn_err(CE_WARN, "!vsw%d: physical device %s is not" 193534683adeSsg70180 " a valid device name/instance", 193634683adeSsg70180 vswp->instance, physname); 193734683adeSsg70180 goto fail_reconf; 193834683adeSsg70180 } 193934683adeSsg70180 194034683adeSsg70180 if (strcmp(physname, vswp->physname)) { 194134683adeSsg70180 D2(vswp, "%s: device name changed from %s to %s", 194234683adeSsg70180 __func__, vswp->physname, physname); 194334683adeSsg70180 194434683adeSsg70180 updated |= MD_physname; 194534683adeSsg70180 } else { 194634683adeSsg70180 D2(vswp, "%s: device name unchanged at %s", 194734683adeSsg70180 __func__, vswp->physname); 194834683adeSsg70180 } 194934683adeSsg70180 } else { 195034683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to read name of physical " 195134683adeSsg70180 "device from updated MD.", vswp->instance); 195234683adeSsg70180 goto fail_reconf; 195334683adeSsg70180 } 195434683adeSsg70180 195534683adeSsg70180 /* 195634683adeSsg70180 * Check if MAC address has changed. 195734683adeSsg70180 */ 195834683adeSsg70180 if (md_get_prop_val(mdp, node, macaddr_propname, &macaddr) != 0) { 195934683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to get MAC address from MD", 196034683adeSsg70180 vswp->instance); 196134683adeSsg70180 goto fail_reconf; 196234683adeSsg70180 } else { 196319b65a69Ssb155480 uint64_t maddr = macaddr; 196434683adeSsg70180 READ_ENTER(&vswp->if_lockrw); 196534683adeSsg70180 for (i = ETHERADDRL - 1; i >= 0; i--) { 196619b65a69Ssb155480 if (vswp->if_addr.ether_addr_octet[i] 196719b65a69Ssb155480 != (macaddr & 0xFF)) { 196834683adeSsg70180 D2(vswp, "%s: octet[%d] 0x%x != 0x%x", 196934683adeSsg70180 __func__, i, 197034683adeSsg70180 vswp->if_addr.ether_addr_octet[i], 197134683adeSsg70180 (macaddr & 0xFF)); 197234683adeSsg70180 updated |= MD_macaddr; 197319b65a69Ssb155480 macaddr = maddr; 197434683adeSsg70180 break; 197534683adeSsg70180 } 197634683adeSsg70180 macaddr >>= 8; 197734683adeSsg70180 } 197834683adeSsg70180 RW_EXIT(&vswp->if_lockrw); 197919b65a69Ssb155480 if (updated & MD_macaddr) { 198019b65a69Ssb155480 vsw_save_lmacaddr(vswp, macaddr); 198119b65a69Ssb155480 } 198234683adeSsg70180 } 198334683adeSsg70180 198434683adeSsg70180 /* 198534683adeSsg70180 * Check if switching modes have changed. 198634683adeSsg70180 */ 198719b65a69Ssb155480 if (vsw_get_md_smodes(vswp, mdp, node, 198819b65a69Ssb155480 new_smode, &smode_num)) { 198934683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to read %s property from MD", 199034683adeSsg70180 vswp->instance, smode_propname); 199134683adeSsg70180 goto fail_reconf; 199234683adeSsg70180 } else { 199334683adeSsg70180 ASSERT(smode_num != 0); 199434683adeSsg70180 if (smode_num != vswp->smode_num) { 199534683adeSsg70180 D2(vswp, "%s: number of modes changed from %d to %d", 199634683adeSsg70180 __func__, vswp->smode_num, smode_num); 199734683adeSsg70180 } 199834683adeSsg70180 199934683adeSsg70180 for (i = 0; i < smode_num; i++) { 200034683adeSsg70180 if (new_smode[i] != vswp->smode[i]) { 200134683adeSsg70180 D2(vswp, "%s: mode changed from %d to %d", 200234683adeSsg70180 __func__, vswp->smode[i], new_smode[i]); 200334683adeSsg70180 updated |= MD_smode; 200434683adeSsg70180 break; 200534683adeSsg70180 } 200634683adeSsg70180 } 200734683adeSsg70180 } 200834683adeSsg70180 2009*c1c61f44Ssb155480 /* Read the vlan ids */ 2010*c1c61f44Ssb155480 vsw_vlan_read_ids(vswp, VSW_LOCALDEV, mdp, node, &pvid, &vids, 2011*c1c61f44Ssb155480 &nvids, NULL); 2012*c1c61f44Ssb155480 2013*c1c61f44Ssb155480 /* Determine if there are any vlan id updates */ 2014*c1c61f44Ssb155480 if ((pvid != vswp->pvid) || /* pvid changed? */ 2015*c1c61f44Ssb155480 (nvids != vswp->nvids) || /* # of vids changed? */ 2016*c1c61f44Ssb155480 ((nvids != 0) && (vswp->nvids != 0) && /* vids changed? */ 2017*c1c61f44Ssb155480 bcmp(vids, vswp->vids, sizeof (uint16_t) * nvids))) { 2018*c1c61f44Ssb155480 updated |= MD_vlans; 2019*c1c61f44Ssb155480 } 2020*c1c61f44Ssb155480 202134683adeSsg70180 /* 202234683adeSsg70180 * Now make any changes which are needed... 202334683adeSsg70180 */ 202434683adeSsg70180 202534683adeSsg70180 if (updated & (MD_physname | MD_smode)) { 202634683adeSsg70180 202734683adeSsg70180 /* 202819b65a69Ssb155480 * Stop any pending timeout to setup switching mode. 202934683adeSsg70180 */ 203019b65a69Ssb155480 vsw_stop_switching_timeout(vswp); 203119b65a69Ssb155480 203219b65a69Ssb155480 /* 203319b65a69Ssb155480 * Remove unicst, mcst addrs of vsw interface 203419b65a69Ssb155480 * and ports from the physdev. 203519b65a69Ssb155480 */ 203619b65a69Ssb155480 vsw_unset_addrs(vswp); 203719b65a69Ssb155480 203819b65a69Ssb155480 /* 203919b65a69Ssb155480 * Stop, detach and close the old device.. 204019b65a69Ssb155480 */ 204119b65a69Ssb155480 mutex_enter(&vswp->mac_lock); 204219b65a69Ssb155480 204334683adeSsg70180 vsw_mac_detach(vswp); 204419b65a69Ssb155480 vsw_mac_close(vswp); 204519b65a69Ssb155480 204619b65a69Ssb155480 mutex_exit(&vswp->mac_lock); 204734683adeSsg70180 204834683adeSsg70180 /* 204934683adeSsg70180 * Update phys name. 205034683adeSsg70180 */ 205134683adeSsg70180 if (updated & MD_physname) { 205234683adeSsg70180 cmn_err(CE_NOTE, "!vsw%d: changing from %s to %s", 205334683adeSsg70180 vswp->instance, vswp->physname, physname); 205434683adeSsg70180 (void) strncpy(vswp->physname, 205534683adeSsg70180 physname, strlen(physname) + 1); 205634683adeSsg70180 } 205734683adeSsg70180 205834683adeSsg70180 /* 205934683adeSsg70180 * Update array with the new switch mode values. 206034683adeSsg70180 */ 206134683adeSsg70180 if (updated & MD_smode) { 206234683adeSsg70180 for (i = 0; i < smode_num; i++) 206334683adeSsg70180 vswp->smode[i] = new_smode[i]; 206434683adeSsg70180 206534683adeSsg70180 vswp->smode_num = smode_num; 206634683adeSsg70180 vswp->smode_idx = 0; 206734683adeSsg70180 } 206834683adeSsg70180 206934683adeSsg70180 /* 207034683adeSsg70180 * ..and attach, start the new device. 207134683adeSsg70180 */ 207219b65a69Ssb155480 rv = vsw_setup_switching(vswp); 207319b65a69Ssb155480 if (rv == EAGAIN) { 207419b65a69Ssb155480 /* 207519b65a69Ssb155480 * Unable to setup switching mode. 207619b65a69Ssb155480 * As the error is EAGAIN, schedule a timeout to retry 207719b65a69Ssb155480 * and return. Programming addresses of ports and 207819b65a69Ssb155480 * vsw interface will be done when the timeout handler 207919b65a69Ssb155480 * completes successfully. 208019b65a69Ssb155480 */ 208119b65a69Ssb155480 mutex_enter(&vswp->swtmout_lock); 208219b65a69Ssb155480 208319b65a69Ssb155480 vswp->swtmout_enabled = B_TRUE; 208419b65a69Ssb155480 vswp->swtmout_id = 208519b65a69Ssb155480 timeout(vsw_setup_switching_timeout, vswp, 208619b65a69Ssb155480 (vsw_setup_switching_delay * 208719b65a69Ssb155480 drv_usectohz(MICROSEC))); 208819b65a69Ssb155480 208919b65a69Ssb155480 mutex_exit(&vswp->swtmout_lock); 209019b65a69Ssb155480 209119b65a69Ssb155480 return; 209219b65a69Ssb155480 209319b65a69Ssb155480 } else if (rv) { 209434683adeSsg70180 goto fail_update; 209519b65a69Ssb155480 } 209634683adeSsg70180 209734683adeSsg70180 /* 209819b65a69Ssb155480 * program unicst, mcst addrs of vsw interface 209919b65a69Ssb155480 * and ports in the physdev. 210034683adeSsg70180 */ 210119b65a69Ssb155480 vsw_set_addrs(vswp); 210234683adeSsg70180 210319b65a69Ssb155480 } else if (updated & MD_macaddr) { 210419b65a69Ssb155480 /* 210519b65a69Ssb155480 * We enter here if only MD_macaddr is exclusively updated. 210619b65a69Ssb155480 * If MD_physname and/or MD_smode are also updated, then 210719b65a69Ssb155480 * as part of that, we would have implicitly processed 210819b65a69Ssb155480 * MD_macaddr update (above). 210919b65a69Ssb155480 */ 211034683adeSsg70180 cmn_err(CE_NOTE, "!vsw%d: changing mac address to 0x%lx", 211134683adeSsg70180 vswp->instance, macaddr); 211234683adeSsg70180 211319b65a69Ssb155480 READ_ENTER(&vswp->if_lockrw); 211419b65a69Ssb155480 if (vswp->if_state & VSW_IF_UP) { 211534683adeSsg70180 21165f94e909Ssg70180 mutex_enter(&vswp->hw_lock); 211719b65a69Ssb155480 /* 211819b65a69Ssb155480 * Remove old mac address of vsw interface 211919b65a69Ssb155480 * from the physdev 212019b65a69Ssb155480 */ 21215f94e909Ssg70180 (void) vsw_unset_hw(vswp, NULL, VSW_LOCALDEV); 212219b65a69Ssb155480 /* 212319b65a69Ssb155480 * Program new mac address of vsw interface 212419b65a69Ssb155480 * in the physdev 212519b65a69Ssb155480 */ 212619b65a69Ssb155480 rv = vsw_set_hw(vswp, NULL, VSW_LOCALDEV); 21275f94e909Ssg70180 mutex_exit(&vswp->hw_lock); 212819b65a69Ssb155480 if (rv != 0) { 212919b65a69Ssb155480 cmn_err(CE_NOTE, 213019b65a69Ssb155480 "!vsw%d: failed to program interface " 213119b65a69Ssb155480 "unicast address\n", vswp->instance); 213219b65a69Ssb155480 } 21335f94e909Ssg70180 /* 213434683adeSsg70180 * Notify the MAC layer of the changed address. 213534683adeSsg70180 */ 213619b65a69Ssb155480 mac_unicst_update(vswp->if_mh, 213719b65a69Ssb155480 (uint8_t *)&vswp->if_addr); 213819b65a69Ssb155480 213919b65a69Ssb155480 } 214019b65a69Ssb155480 RW_EXIT(&vswp->if_lockrw); 214119b65a69Ssb155480 214234683adeSsg70180 } 214334683adeSsg70180 2144*c1c61f44Ssb155480 if (updated & MD_vlans) { 2145*c1c61f44Ssb155480 /* Remove existing vlan ids from the hash table. */ 2146*c1c61f44Ssb155480 vsw_vlan_remove_ids(vswp, VSW_LOCALDEV); 2147*c1c61f44Ssb155480 2148*c1c61f44Ssb155480 /* save the new vlan ids */ 2149*c1c61f44Ssb155480 vswp->pvid = pvid; 2150*c1c61f44Ssb155480 if (vswp->nvids != 0) { 2151*c1c61f44Ssb155480 kmem_free(vswp->vids, sizeof (uint16_t) * vswp->nvids); 2152*c1c61f44Ssb155480 vswp->nvids = 0; 2153*c1c61f44Ssb155480 } 2154*c1c61f44Ssb155480 if (nvids != 0) { 2155*c1c61f44Ssb155480 vswp->nvids = nvids; 2156*c1c61f44Ssb155480 vswp->vids = vids; 2157*c1c61f44Ssb155480 } 2158*c1c61f44Ssb155480 2159*c1c61f44Ssb155480 /* add these new vlan ids into hash table */ 2160*c1c61f44Ssb155480 vsw_vlan_add_ids(vswp, VSW_LOCALDEV); 2161*c1c61f44Ssb155480 } else { 2162*c1c61f44Ssb155480 if (nvids != 0) { 2163*c1c61f44Ssb155480 kmem_free(vids, sizeof (uint16_t) * nvids); 2164*c1c61f44Ssb155480 } 2165*c1c61f44Ssb155480 } 2166*c1c61f44Ssb155480 216734683adeSsg70180 return; 216834683adeSsg70180 216934683adeSsg70180 fail_reconf: 217034683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: configuration unchanged", vswp->instance); 217134683adeSsg70180 return; 217234683adeSsg70180 217334683adeSsg70180 fail_update: 21741ef0bbb5Snarayan cmn_err(CE_WARN, "!vsw%d: re-configuration failed", 217534683adeSsg70180 vswp->instance); 217634683adeSsg70180 } 217734683adeSsg70180 217834683adeSsg70180 /* 2179*c1c61f44Ssb155480 * Read the port's md properties. 21801ae08745Sheppo */ 2181*c1c61f44Ssb155480 static int 2182*c1c61f44Ssb155480 vsw_port_read_props(vsw_port_t *portp, vsw_t *vswp, 2183*c1c61f44Ssb155480 md_t *mdp, mde_cookie_t *node) 21841ae08745Sheppo { 21851ae08745Sheppo uint64_t ldc_id; 21861ae08745Sheppo uint8_t *addrp; 21871ae08745Sheppo int i, addrsz; 21881ae08745Sheppo int num_nodes = 0, nchan = 0; 21891ae08745Sheppo int listsz = 0; 21901ae08745Sheppo mde_cookie_t *listp = NULL; 21911ae08745Sheppo struct ether_addr ea; 21921ae08745Sheppo uint64_t macaddr; 21931ae08745Sheppo uint64_t inst = 0; 21941ae08745Sheppo 21951ae08745Sheppo if (md_get_prop_val(mdp, *node, id_propname, &inst)) { 21961ae08745Sheppo DWARN(vswp, "%s: prop(%s) not found", __func__, 21971ae08745Sheppo id_propname); 21981ae08745Sheppo return (1); 21991ae08745Sheppo } 22001ae08745Sheppo 22011ae08745Sheppo /* 22021ae08745Sheppo * Find the channel endpoint node(s) (which should be under this 22031ae08745Sheppo * port node) which contain the channel id(s). 22041ae08745Sheppo */ 22051ae08745Sheppo if ((num_nodes = md_node_count(mdp)) <= 0) { 22061ae08745Sheppo DERR(vswp, "%s: invalid number of nodes found (%d)", 22071ae08745Sheppo __func__, num_nodes); 22081ae08745Sheppo return (1); 22091ae08745Sheppo } 22101ae08745Sheppo 221134683adeSsg70180 D2(vswp, "%s: %d nodes found", __func__, num_nodes); 221234683adeSsg70180 22131ae08745Sheppo /* allocate enough space for node list */ 22141ae08745Sheppo listsz = num_nodes * sizeof (mde_cookie_t); 22151ae08745Sheppo listp = kmem_zalloc(listsz, KM_SLEEP); 22161ae08745Sheppo 2217205eeb1aSlm66018 nchan = md_scan_dag(mdp, *node, md_find_name(mdp, chan_propname), 22181ae08745Sheppo md_find_name(mdp, "fwd"), listp); 22191ae08745Sheppo 22201ae08745Sheppo if (nchan <= 0) { 22211ae08745Sheppo DWARN(vswp, "%s: no %s nodes found", __func__, chan_propname); 22221ae08745Sheppo kmem_free(listp, listsz); 22231ae08745Sheppo return (1); 22241ae08745Sheppo } 22251ae08745Sheppo 22261ae08745Sheppo D2(vswp, "%s: %d %s nodes found", __func__, nchan, chan_propname); 22271ae08745Sheppo 22281ae08745Sheppo /* use property from first node found */ 22291ae08745Sheppo if (md_get_prop_val(mdp, listp[0], id_propname, &ldc_id)) { 22301ae08745Sheppo DWARN(vswp, "%s: prop(%s) not found\n", __func__, 22311ae08745Sheppo id_propname); 22321ae08745Sheppo kmem_free(listp, listsz); 22331ae08745Sheppo return (1); 22341ae08745Sheppo } 22351ae08745Sheppo 22361ae08745Sheppo /* don't need list any more */ 22371ae08745Sheppo kmem_free(listp, listsz); 22381ae08745Sheppo 22391ae08745Sheppo D2(vswp, "%s: ldc_id 0x%llx", __func__, ldc_id); 22401ae08745Sheppo 22411ae08745Sheppo /* read mac-address property */ 22421ae08745Sheppo if (md_get_prop_data(mdp, *node, remaddr_propname, 22431ae08745Sheppo &addrp, &addrsz)) { 22441ae08745Sheppo DWARN(vswp, "%s: prop(%s) not found", 22451ae08745Sheppo __func__, remaddr_propname); 22461ae08745Sheppo return (1); 22471ae08745Sheppo } 22481ae08745Sheppo 22491ae08745Sheppo if (addrsz < ETHERADDRL) { 22501ae08745Sheppo DWARN(vswp, "%s: invalid address size", __func__); 22511ae08745Sheppo return (1); 22521ae08745Sheppo } 22531ae08745Sheppo 22541ae08745Sheppo macaddr = *((uint64_t *)addrp); 22551ae08745Sheppo D2(vswp, "%s: remote mac address 0x%llx", __func__, macaddr); 22561ae08745Sheppo 22571ae08745Sheppo for (i = ETHERADDRL - 1; i >= 0; i--) { 22581ae08745Sheppo ea.ether_addr_octet[i] = macaddr & 0xFF; 22591ae08745Sheppo macaddr >>= 8; 22601ae08745Sheppo } 22611ae08745Sheppo 2262*c1c61f44Ssb155480 /* now update all properties into the port */ 2263*c1c61f44Ssb155480 portp->p_vswp = vswp; 2264*c1c61f44Ssb155480 portp->p_instance = inst; 2265*c1c61f44Ssb155480 portp->addr_set = VSW_ADDR_UNSET; 2266*c1c61f44Ssb155480 ether_copy(&ea, &portp->p_macaddr); 2267*c1c61f44Ssb155480 if (nchan > VSW_PORT_MAX_LDCS) { 2268*c1c61f44Ssb155480 D2(vswp, "%s: using first of %d ldc ids", 2269*c1c61f44Ssb155480 __func__, nchan); 2270*c1c61f44Ssb155480 nchan = VSW_PORT_MAX_LDCS; 2271*c1c61f44Ssb155480 } 2272*c1c61f44Ssb155480 portp->num_ldcs = nchan; 2273*c1c61f44Ssb155480 portp->ldc_ids = 2274*c1c61f44Ssb155480 kmem_zalloc(sizeof (uint64_t) * nchan, KM_SLEEP); 2275*c1c61f44Ssb155480 bcopy(&ldc_id, (portp->ldc_ids), sizeof (uint64_t) * nchan); 2276*c1c61f44Ssb155480 2277*c1c61f44Ssb155480 /* read vlan id properties of this port node */ 2278*c1c61f44Ssb155480 vsw_vlan_read_ids(portp, VSW_VNETPORT, mdp, *node, &portp->pvid, 2279*c1c61f44Ssb155480 &portp->vids, &portp->nvids, NULL); 2280*c1c61f44Ssb155480 2281*c1c61f44Ssb155480 return (0); 2282*c1c61f44Ssb155480 } 2283*c1c61f44Ssb155480 2284*c1c61f44Ssb155480 /* 2285*c1c61f44Ssb155480 * Add a new port to the system. 2286*c1c61f44Ssb155480 * 2287*c1c61f44Ssb155480 * Returns 0 on success, 1 on failure. 2288*c1c61f44Ssb155480 */ 2289*c1c61f44Ssb155480 int 2290*c1c61f44Ssb155480 vsw_port_add(vsw_t *vswp, md_t *mdp, mde_cookie_t *node) 2291*c1c61f44Ssb155480 { 2292*c1c61f44Ssb155480 vsw_port_t *portp; 2293*c1c61f44Ssb155480 int rv; 2294*c1c61f44Ssb155480 2295*c1c61f44Ssb155480 portp = kmem_zalloc(sizeof (vsw_port_t), KM_SLEEP); 2296*c1c61f44Ssb155480 2297*c1c61f44Ssb155480 rv = vsw_port_read_props(portp, vswp, mdp, node); 2298*c1c61f44Ssb155480 if (rv != 0) { 2299*c1c61f44Ssb155480 kmem_free(portp, sizeof (*portp)); 2300*c1c61f44Ssb155480 return (1); 2301*c1c61f44Ssb155480 } 2302*c1c61f44Ssb155480 2303*c1c61f44Ssb155480 rv = vsw_port_attach(portp); 2304*c1c61f44Ssb155480 if (rv != 0) { 23051ae08745Sheppo DERR(vswp, "%s: failed to attach port", __func__); 23061ae08745Sheppo return (1); 23071ae08745Sheppo } 23081ae08745Sheppo 2309*c1c61f44Ssb155480 return (0); 2310*c1c61f44Ssb155480 } 23111ae08745Sheppo 2312*c1c61f44Ssb155480 static int 2313*c1c61f44Ssb155480 vsw_port_update(vsw_t *vswp, md_t *curr_mdp, mde_cookie_t curr_mdex, 2314*c1c61f44Ssb155480 md_t *prev_mdp, mde_cookie_t prev_mdex) 2315*c1c61f44Ssb155480 { 2316*c1c61f44Ssb155480 uint64_t cport_num; 2317*c1c61f44Ssb155480 uint64_t pport_num; 2318*c1c61f44Ssb155480 vsw_port_list_t *plistp; 2319*c1c61f44Ssb155480 vsw_port_t *portp; 2320*c1c61f44Ssb155480 boolean_t updated_vlans = B_FALSE; 2321*c1c61f44Ssb155480 uint16_t pvid; 2322*c1c61f44Ssb155480 uint16_t *vids; 2323*c1c61f44Ssb155480 uint16_t nvids; 2324*c1c61f44Ssb155480 2325*c1c61f44Ssb155480 /* 2326*c1c61f44Ssb155480 * For now, we get port updates only if vlan ids changed. 2327*c1c61f44Ssb155480 * We read the port num and do some sanity check. 2328*c1c61f44Ssb155480 */ 2329*c1c61f44Ssb155480 if (md_get_prop_val(curr_mdp, curr_mdex, id_propname, &cport_num)) { 2330*c1c61f44Ssb155480 return (1); 2331*c1c61f44Ssb155480 } 2332*c1c61f44Ssb155480 2333*c1c61f44Ssb155480 if (md_get_prop_val(prev_mdp, prev_mdex, id_propname, &pport_num)) { 2334*c1c61f44Ssb155480 return (1); 2335*c1c61f44Ssb155480 } 2336*c1c61f44Ssb155480 if (cport_num != pport_num) 2337*c1c61f44Ssb155480 return (1); 2338*c1c61f44Ssb155480 2339*c1c61f44Ssb155480 plistp = &(vswp->plist); 2340*c1c61f44Ssb155480 2341*c1c61f44Ssb155480 READ_ENTER(&plistp->lockrw); 2342*c1c61f44Ssb155480 2343*c1c61f44Ssb155480 portp = vsw_lookup_port(vswp, cport_num); 2344*c1c61f44Ssb155480 if (portp == NULL) { 2345*c1c61f44Ssb155480 RW_EXIT(&plistp->lockrw); 2346*c1c61f44Ssb155480 return (1); 2347*c1c61f44Ssb155480 } 2348*c1c61f44Ssb155480 2349*c1c61f44Ssb155480 /* Read the vlan ids */ 2350*c1c61f44Ssb155480 vsw_vlan_read_ids(portp, VSW_VNETPORT, curr_mdp, curr_mdex, &pvid, 2351*c1c61f44Ssb155480 &vids, &nvids, NULL); 2352*c1c61f44Ssb155480 2353*c1c61f44Ssb155480 /* Determine if there are any vlan id updates */ 2354*c1c61f44Ssb155480 if ((pvid != portp->pvid) || /* pvid changed? */ 2355*c1c61f44Ssb155480 (nvids != portp->nvids) || /* # of vids changed? */ 2356*c1c61f44Ssb155480 ((nvids != 0) && (portp->nvids != 0) && /* vids changed? */ 2357*c1c61f44Ssb155480 bcmp(vids, portp->vids, sizeof (uint16_t) * nvids))) { 2358*c1c61f44Ssb155480 updated_vlans = B_TRUE; 2359*c1c61f44Ssb155480 } 2360*c1c61f44Ssb155480 2361*c1c61f44Ssb155480 if (updated_vlans == B_FALSE) { 2362*c1c61f44Ssb155480 RW_EXIT(&plistp->lockrw); 2363*c1c61f44Ssb155480 return (1); 2364*c1c61f44Ssb155480 } 2365*c1c61f44Ssb155480 2366*c1c61f44Ssb155480 /* Remove existing vlan ids from the hash table. */ 2367*c1c61f44Ssb155480 vsw_vlan_remove_ids(portp, VSW_VNETPORT); 2368*c1c61f44Ssb155480 2369*c1c61f44Ssb155480 /* save the new vlan ids */ 2370*c1c61f44Ssb155480 portp->pvid = pvid; 2371*c1c61f44Ssb155480 if (portp->nvids != 0) { 2372*c1c61f44Ssb155480 kmem_free(portp->vids, sizeof (uint16_t) * portp->nvids); 2373*c1c61f44Ssb155480 portp->nvids = 0; 2374*c1c61f44Ssb155480 } 2375*c1c61f44Ssb155480 if (nvids != 0) { 2376*c1c61f44Ssb155480 portp->vids = kmem_zalloc(sizeof (uint16_t) * nvids, KM_SLEEP); 2377*c1c61f44Ssb155480 bcopy(vids, portp->vids, sizeof (uint16_t) * nvids); 2378*c1c61f44Ssb155480 portp->nvids = nvids; 2379*c1c61f44Ssb155480 kmem_free(vids, sizeof (uint16_t) * nvids); 2380*c1c61f44Ssb155480 } 2381*c1c61f44Ssb155480 2382*c1c61f44Ssb155480 /* add these new vlan ids into hash table */ 2383*c1c61f44Ssb155480 vsw_vlan_add_ids(portp, VSW_VNETPORT); 2384*c1c61f44Ssb155480 2385*c1c61f44Ssb155480 /* reset the port if it is vlan unaware (ver < 1.3) */ 2386*c1c61f44Ssb155480 vsw_vlan_unaware_port_reset(portp); 2387*c1c61f44Ssb155480 2388*c1c61f44Ssb155480 RW_EXIT(&plistp->lockrw); 23891ae08745Sheppo 23901ae08745Sheppo return (0); 23911ae08745Sheppo } 23921ae08745Sheppo 23931ae08745Sheppo /* 239406db247cSraghuram * vsw_mac_rx -- A common function to send packets to the interface. 239506db247cSraghuram * By default this function check if the interface is UP or not, the 239606db247cSraghuram * rest of the behaviour depends on the flags as below: 23971ae08745Sheppo * 239806db247cSraghuram * VSW_MACRX_PROMISC -- Check if the promisc mode set or not. 239906db247cSraghuram * VSW_MACRX_COPYMSG -- Make a copy of the message(s). 240006db247cSraghuram * VSW_MACRX_FREEMSG -- Free if the messages cannot be sent up the stack. 24011ae08745Sheppo */ 24021ae08745Sheppo void 2403f0ca1d9aSsb155480 vsw_mac_rx(vsw_t *vswp, mac_resource_handle_t mrh, 2404f0ca1d9aSsb155480 mblk_t *mp, vsw_macrx_flags_t flags) 24051ae08745Sheppo { 2406*c1c61f44Ssb155480 mblk_t *mpt; 2407*c1c61f44Ssb155480 240806db247cSraghuram D1(vswp, "%s:enter\n", __func__); 24091ae08745Sheppo READ_ENTER(&vswp->if_lockrw); 241006db247cSraghuram /* Check if the interface is up */ 241106db247cSraghuram if (!(vswp->if_state & VSW_IF_UP)) { 24121ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 241306db247cSraghuram /* Free messages only if FREEMSG flag specified */ 241406db247cSraghuram if (flags & VSW_MACRX_FREEMSG) { 241506db247cSraghuram freemsgchain(mp); 241606db247cSraghuram } 241706db247cSraghuram D1(vswp, "%s:exit\n", __func__); 241806db247cSraghuram return; 241906db247cSraghuram } 242006db247cSraghuram /* 242106db247cSraghuram * If PROMISC flag is passed, then check if 242206db247cSraghuram * the interface is in the PROMISC mode. 242306db247cSraghuram * If not, drop the messages. 242406db247cSraghuram */ 242506db247cSraghuram if (flags & VSW_MACRX_PROMISC) { 242606db247cSraghuram if (!(vswp->if_state & VSW_IF_PROMISC)) { 242706db247cSraghuram RW_EXIT(&vswp->if_lockrw); 242806db247cSraghuram /* Free messages only if FREEMSG flag specified */ 242906db247cSraghuram if (flags & VSW_MACRX_FREEMSG) { 243006db247cSraghuram freemsgchain(mp); 243106db247cSraghuram } 243206db247cSraghuram D1(vswp, "%s:exit\n", __func__); 243306db247cSraghuram return; 243406db247cSraghuram } 243506db247cSraghuram } 243606db247cSraghuram RW_EXIT(&vswp->if_lockrw); 243706db247cSraghuram /* 243806db247cSraghuram * If COPYMSG flag is passed, then make a copy 243906db247cSraghuram * of the message chain and send up the copy. 244006db247cSraghuram */ 244106db247cSraghuram if (flags & VSW_MACRX_COPYMSG) { 244206db247cSraghuram mp = copymsgchain(mp); 2443f0ca1d9aSsb155480 if (mp == NULL) { 244406db247cSraghuram D1(vswp, "%s:exit\n", __func__); 244506db247cSraghuram return; 244606db247cSraghuram } 244706db247cSraghuram } 244806db247cSraghuram 2449f0ca1d9aSsb155480 D2(vswp, "%s: sending up stack", __func__); 2450*c1c61f44Ssb155480 2451*c1c61f44Ssb155480 mpt = NULL; 2452*c1c61f44Ssb155480 (void) vsw_vlan_frame_untag(vswp, VSW_LOCALDEV, &mp, &mpt); 2453*c1c61f44Ssb155480 if (mp != NULL) { 2454ba2e4443Sseb mac_rx(vswp->if_mh, mrh, mp); 2455*c1c61f44Ssb155480 } 245606db247cSraghuram D1(vswp, "%s:exit\n", __func__); 24571ae08745Sheppo } 24581ae08745Sheppo 245906db247cSraghuram /* copy mac address of vsw into soft state structure */ 24601ae08745Sheppo static void 246106db247cSraghuram vsw_save_lmacaddr(vsw_t *vswp, uint64_t macaddr) 24621ae08745Sheppo { 24631ae08745Sheppo int i; 24641ae08745Sheppo 246506db247cSraghuram WRITE_ENTER(&vswp->if_lockrw); 246606db247cSraghuram for (i = ETHERADDRL - 1; i >= 0; i--) { 246706db247cSraghuram vswp->if_addr.ether_addr_octet[i] = macaddr & 0xFF; 246806db247cSraghuram macaddr >>= 8; 24691ae08745Sheppo } 247006db247cSraghuram RW_EXIT(&vswp->if_lockrw); 24711ae08745Sheppo } 2472