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 /* 236f09f0feSWENTAO YANG * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 241ae08745Sheppo * Use is subject to license terms. 251ae08745Sheppo */ 261ae08745Sheppo 271ae08745Sheppo #include <sys/types.h> 281ae08745Sheppo #include <sys/errno.h> 291ae08745Sheppo #include <sys/debug.h> 301ae08745Sheppo #include <sys/time.h> 311ae08745Sheppo #include <sys/sysmacros.h> 321ae08745Sheppo #include <sys/systm.h> 331ae08745Sheppo #include <sys/user.h> 341ae08745Sheppo #include <sys/stropts.h> 351ae08745Sheppo #include <sys/stream.h> 361ae08745Sheppo #include <sys/strlog.h> 371ae08745Sheppo #include <sys/strsubr.h> 381ae08745Sheppo #include <sys/cmn_err.h> 391ae08745Sheppo #include <sys/cpu.h> 401ae08745Sheppo #include <sys/kmem.h> 411ae08745Sheppo #include <sys/conf.h> 421ae08745Sheppo #include <sys/ddi.h> 431ae08745Sheppo #include <sys/sunddi.h> 441ae08745Sheppo #include <sys/ksynch.h> 451ae08745Sheppo #include <sys/stat.h> 461ae08745Sheppo #include <sys/kstat.h> 471ae08745Sheppo #include <sys/vtrace.h> 481ae08745Sheppo #include <sys/strsun.h> 491ae08745Sheppo #include <sys/dlpi.h> 501ae08745Sheppo #include <sys/ethernet.h> 511ae08745Sheppo #include <net/if.h> 521ae08745Sheppo #include <sys/varargs.h> 531ae08745Sheppo #include <sys/machsystm.h> 541ae08745Sheppo #include <sys/modctl.h> 551ae08745Sheppo #include <sys/modhash.h> 56da14cebeSEric Cheng #include <sys/mac_provider.h> 57ba2e4443Sseb #include <sys/mac_ether.h> 581ae08745Sheppo #include <sys/taskq.h> 591ae08745Sheppo #include <sys/note.h> 601ae08745Sheppo #include <sys/mach_descrip.h> 61da14cebeSEric Cheng #include <sys/mac_provider.h> 621ae08745Sheppo #include <sys/mdeg.h> 631ae08745Sheppo #include <sys/ldc.h> 641ae08745Sheppo #include <sys/vsw_fdb.h> 651ae08745Sheppo #include <sys/vsw.h> 661ae08745Sheppo #include <sys/vio_mailbox.h> 671ae08745Sheppo #include <sys/vnet_mailbox.h> 681ae08745Sheppo #include <sys/vnet_common.h> 69d10e4ef2Snarayan #include <sys/vio_util.h> 70d10e4ef2Snarayan #include <sys/sdt.h> 7119b65a69Ssb155480 #include <sys/atomic.h> 7206db247cSraghuram #include <sys/callb.h> 73c1c61f44Ssb155480 #include <sys/vlan.h> 741ae08745Sheppo 751ae08745Sheppo /* 761ae08745Sheppo * Function prototypes. 771ae08745Sheppo */ 781ae08745Sheppo static int vsw_attach(dev_info_t *, ddi_attach_cmd_t); 791ae08745Sheppo static int vsw_detach(dev_info_t *, ddi_detach_cmd_t); 806f09f0feSWENTAO YANG static int vsw_unattach(vsw_t *vswp); 8134683adeSsg70180 static int vsw_get_md_physname(vsw_t *, md_t *, mde_cookie_t, char *); 82da14cebeSEric Cheng static int vsw_get_md_smodes(vsw_t *, md_t *, mde_cookie_t, uint8_t *); 836f09f0feSWENTAO YANG static int vsw_mod_cleanup(void); 841ae08745Sheppo 851ae08745Sheppo /* MDEG routines */ 8634683adeSsg70180 static int vsw_mdeg_register(vsw_t *vswp); 871ae08745Sheppo static void vsw_mdeg_unregister(vsw_t *vswp); 881ae08745Sheppo static int vsw_mdeg_cb(void *cb_argp, mdeg_result_t *); 8934683adeSsg70180 static int vsw_port_mdeg_cb(void *cb_argp, mdeg_result_t *); 9019b65a69Ssb155480 static int vsw_get_initial_md_properties(vsw_t *vswp, md_t *, mde_cookie_t); 91c1c61f44Ssb155480 static int vsw_read_mdprops(vsw_t *vswp); 92c1c61f44Ssb155480 static void vsw_vlan_read_ids(void *arg, int type, md_t *mdp, 93da14cebeSEric Cheng mde_cookie_t node, uint16_t *pvidp, vsw_vlanid_t **vidspp, 94c1c61f44Ssb155480 uint16_t *nvidsp, uint16_t *default_idp); 95c1c61f44Ssb155480 static int vsw_port_read_props(vsw_port_t *portp, vsw_t *vswp, 96c1c61f44Ssb155480 md_t *mdp, mde_cookie_t *node); 97f0ca1d9aSsb155480 static void vsw_read_pri_eth_types(vsw_t *vswp, md_t *mdp, 98f0ca1d9aSsb155480 mde_cookie_t node); 997b1f684aSSriharsha Basavapatna static void vsw_mtu_read(vsw_t *vswp, md_t *mdp, mde_cookie_t node, 1007b1f684aSSriharsha Basavapatna uint32_t *mtu); 1017b1f684aSSriharsha Basavapatna static int vsw_mtu_update(vsw_t *vswp, uint32_t mtu); 102*1107ea93SSriharsha Basavapatna static void vsw_linkprop_read(vsw_t *vswp, md_t *mdp, mde_cookie_t node, 103*1107ea93SSriharsha Basavapatna boolean_t *pls); 10434683adeSsg70180 static void vsw_update_md_prop(vsw_t *, md_t *, mde_cookie_t); 10519b65a69Ssb155480 static void vsw_save_lmacaddr(vsw_t *vswp, uint64_t macaddr); 106da14cebeSEric Cheng static boolean_t vsw_cmp_vids(vsw_vlanid_t *vids1, 107da14cebeSEric Cheng vsw_vlanid_t *vids2, int nvids); 1081ae08745Sheppo 10906db247cSraghuram /* Mac driver related routines */ 11006db247cSraghuram static int vsw_mac_register(vsw_t *); 11106db247cSraghuram static int vsw_mac_unregister(vsw_t *); 11206db247cSraghuram static int vsw_m_stat(void *, uint_t, uint64_t *); 11306db247cSraghuram static void vsw_m_stop(void *arg); 11406db247cSraghuram static int vsw_m_start(void *arg); 11506db247cSraghuram static int vsw_m_unicst(void *arg, const uint8_t *); 11606db247cSraghuram static int vsw_m_multicst(void *arg, boolean_t, const uint8_t *); 11706db247cSraghuram static int vsw_m_promisc(void *arg, boolean_t); 11806db247cSraghuram static mblk_t *vsw_m_tx(void *arg, mblk_t *); 119*1107ea93SSriharsha Basavapatna static void vsw_mac_link_update(vsw_t *vswp, link_state_t link_state); 120f0ca1d9aSsb155480 void vsw_mac_rx(vsw_t *vswp, mac_resource_handle_t mrh, 121f0ca1d9aSsb155480 mblk_t *mp, vsw_macrx_flags_t flags); 122*1107ea93SSriharsha Basavapatna void vsw_physlink_state_update(vsw_t *vswp); 1231ae08745Sheppo 12406db247cSraghuram /* 12506db247cSraghuram * Functions imported from other files. 12606db247cSraghuram */ 127808f26a8SSriharsha Basavapatna extern void vsw_setup_switching_thread(void *arg); 128808f26a8SSriharsha Basavapatna extern int vsw_setup_switching_start(vsw_t *vswp); 129808f26a8SSriharsha Basavapatna extern void vsw_setup_switching_stop(vsw_t *vswp); 13006db247cSraghuram extern int vsw_setup_switching(vsw_t *); 1317a327842Swentaoy extern void vsw_switch_frame_nop(vsw_t *vswp, mblk_t *mp, int caller, 1327a327842Swentaoy vsw_port_t *port, mac_resource_handle_t mrh); 13306db247cSraghuram extern int vsw_add_mcst(vsw_t *, uint8_t, uint64_t, void *); 13406db247cSraghuram extern int vsw_del_mcst(vsw_t *, uint8_t, uint64_t, void *); 13506db247cSraghuram extern void vsw_del_mcst_vsw(vsw_t *); 13606db247cSraghuram extern mcst_addr_t *vsw_del_addr(uint8_t devtype, void *arg, uint64_t addr); 1376f09f0feSWENTAO YANG extern void vsw_detach_ports(vsw_t *vswp); 13806db247cSraghuram extern int vsw_port_add(vsw_t *vswp, md_t *mdp, mde_cookie_t *node); 13906db247cSraghuram extern int vsw_port_detach(vsw_t *vswp, int p_instance); 140c1c61f44Ssb155480 static int vsw_port_update(vsw_t *vswp, md_t *curr_mdp, mde_cookie_t curr_mdex, 141c1c61f44Ssb155480 md_t *prev_mdp, mde_cookie_t prev_mdex); 142c1c61f44Ssb155480 extern int vsw_port_attach(vsw_port_t *port); 14306db247cSraghuram extern vsw_port_t *vsw_lookup_port(vsw_t *vswp, int p_instance); 14406db247cSraghuram extern int vsw_mac_open(vsw_t *vswp); 14506db247cSraghuram extern void vsw_mac_close(vsw_t *vswp); 146da14cebeSEric Cheng extern void vsw_mac_cleanup_ports(vsw_t *vswp); 14706db247cSraghuram extern void vsw_unset_addrs(vsw_t *vswp); 14871bdf936SWENTAO YANG extern void vsw_setup_layer2_post_process(vsw_t *vswp); 149c1c61f44Ssb155480 extern void vsw_create_vlans(void *arg, int type); 150c1c61f44Ssb155480 extern void vsw_destroy_vlans(void *arg, int type); 151c1c61f44Ssb155480 extern void vsw_vlan_add_ids(void *arg, int type); 152c1c61f44Ssb155480 extern void vsw_vlan_remove_ids(void *arg, int type); 153c1c61f44Ssb155480 extern void vsw_vlan_unaware_port_reset(vsw_port_t *portp); 154c1c61f44Ssb155480 extern uint32_t vsw_vlan_frame_untag(void *arg, int type, mblk_t **np, 155c1c61f44Ssb155480 mblk_t **npt); 156c1c61f44Ssb155480 extern mblk_t *vsw_vlan_frame_pretag(void *arg, int type, mblk_t *mp); 157678453a8Sspeer extern void vsw_hio_cleanup(vsw_t *vswp); 158da14cebeSEric Cheng extern void vsw_hio_start_ports(vsw_t *vswp); 159da14cebeSEric Cheng extern void vsw_hio_port_update(vsw_port_t *portp, boolean_t hio_enabled); 160da14cebeSEric Cheng extern int vsw_mac_multicast_add(vsw_t *, vsw_port_t *, mcst_addr_t *, int); 161da14cebeSEric Cheng extern void vsw_mac_multicast_remove(vsw_t *, vsw_port_t *, mcst_addr_t *, int); 162da14cebeSEric Cheng extern void vsw_mac_port_reconfig_vlans(vsw_port_t *portp, uint16_t new_pvid, 163da14cebeSEric Cheng vsw_vlanid_t *new_vids, int new_nvids); 164da14cebeSEric Cheng extern int vsw_mac_client_init(vsw_t *vswp, vsw_port_t *port, int type); 165da14cebeSEric Cheng extern void vsw_mac_client_cleanup(vsw_t *vswp, vsw_port_t *port, int type); 166da14cebeSEric Cheng extern void vsw_if_mac_reconfig(vsw_t *vswp, boolean_t update_vlans, 167da14cebeSEric Cheng uint16_t new_pvid, vsw_vlanid_t *new_vids, int new_nvids); 1687b1f684aSSriharsha Basavapatna extern void vsw_reset_ports(vsw_t *vswp); 1697b1f684aSSriharsha Basavapatna extern void vsw_port_reset(vsw_port_t *portp); 170*1107ea93SSriharsha Basavapatna extern void vsw_physlink_update_ports(vsw_t *vswp); 171678453a8Sspeer void vsw_hio_port_update(vsw_port_t *portp, boolean_t hio_enabled); 17206db247cSraghuram 17306db247cSraghuram /* 17406db247cSraghuram * Internal tunables. 17506db247cSraghuram */ 176445b4c2eSsb155480 int vsw_num_handshakes = VNET_NUM_HANDSHAKES; /* # of handshake attempts */ 1771ae08745Sheppo int vsw_wretries = 100; /* # of write attempts */ 178d10e4ef2Snarayan int vsw_desc_delay = 0; /* delay in us */ 179d10e4ef2Snarayan int vsw_read_attempts = 5; /* # of reads of descriptor */ 18019b65a69Ssb155480 int vsw_setup_switching_delay = 3; /* setup sw timeout interval in sec */ 1810e8b4070Ssb155480 int vsw_mac_open_retries = 300; /* max # of mac_open() retries */ 1820e8b4070Ssb155480 /* 300*3 = 900sec(15min) of max tmout */ 18306db247cSraghuram int vsw_ldc_tx_delay = 5; /* delay(ticks) for tx retries */ 18406db247cSraghuram int vsw_ldc_tx_retries = 10; /* # of ldc tx retries */ 1856f09f0feSWENTAO YANG int vsw_ldc_retries = 5; /* # of ldc_close() retries */ 1866f09f0feSWENTAO YANG int vsw_ldc_delay = 1000; /* 1 ms delay for ldc_close() */ 18706db247cSraghuram boolean_t vsw_ldc_rxthr_enabled = B_TRUE; /* LDC Rx thread enabled */ 18806db247cSraghuram boolean_t vsw_ldc_txthr_enabled = B_TRUE; /* LDC Tx thread enabled */ 189d10e4ef2Snarayan 190c1c61f44Ssb155480 uint32_t vsw_fdb_nchains = 8; /* # of chains in fdb hash table */ 191c1c61f44Ssb155480 uint32_t vsw_vlan_nchains = 4; /* # of chains in vlan id hash table */ 192c1c61f44Ssb155480 uint32_t vsw_ethermtu = 1500; /* mtu of the device */ 193c1c61f44Ssb155480 194c1c61f44Ssb155480 /* delay in usec to wait for all references on a fdb entry to be dropped */ 195c1c61f44Ssb155480 uint32_t vsw_fdbe_refcnt_delay = 10; 196c1c61f44Ssb155480 197c1c61f44Ssb155480 /* 198c1c61f44Ssb155480 * Default vlan id. This is only used internally when the "default-vlan-id" 199c1c61f44Ssb155480 * property is not present in the MD device node. Therefore, this should not be 200c1c61f44Ssb155480 * used as a tunable; if this value is changed, the corresponding variable 201c1c61f44Ssb155480 * should be updated to the same value in all vnets connected to this vsw. 202c1c61f44Ssb155480 */ 203c1c61f44Ssb155480 uint16_t vsw_default_vlan_id = 1; 204c1c61f44Ssb155480 205f0ca1d9aSsb155480 /* 206f0ca1d9aSsb155480 * Workaround for a version handshake bug in obp's vnet. 207f0ca1d9aSsb155480 * If vsw initiates version negotiation starting from the highest version, 208f0ca1d9aSsb155480 * obp sends a nack and terminates version handshake. To workaround 209f0ca1d9aSsb155480 * this, we do not initiate version handshake when the channel comes up. 210f0ca1d9aSsb155480 * Instead, we wait for the peer to send its version info msg and go through 211f0ca1d9aSsb155480 * the version protocol exchange. If we successfully negotiate a version, 212f0ca1d9aSsb155480 * before sending the ack, we send our version info msg to the peer 213f0ca1d9aSsb155480 * using the <major,minor> version that we are about to ack. 214f0ca1d9aSsb155480 */ 215f0ca1d9aSsb155480 boolean_t vsw_obp_ver_proto_workaround = B_TRUE; 216f0ca1d9aSsb155480 217f0ca1d9aSsb155480 /* 218f0ca1d9aSsb155480 * In the absence of "priority-ether-types" property in MD, the following 219f0ca1d9aSsb155480 * internal tunable can be set to specify a single priority ethertype. 220f0ca1d9aSsb155480 */ 221f0ca1d9aSsb155480 uint64_t vsw_pri_eth_type = 0; 222f0ca1d9aSsb155480 223f0ca1d9aSsb155480 /* 224f0ca1d9aSsb155480 * Number of transmit priority buffers that are preallocated per device. 225f0ca1d9aSsb155480 * This number is chosen to be a small value to throttle transmission 226f0ca1d9aSsb155480 * of priority packets. Note: Must be a power of 2 for vio_create_mblks(). 227f0ca1d9aSsb155480 */ 228f0ca1d9aSsb155480 uint32_t vsw_pri_tx_nmblks = 64; 229d10e4ef2Snarayan 23051aa9d07Ssb155480 /* 23151aa9d07Ssb155480 * Number of RARP packets sent to announce macaddr to the physical switch, 23251aa9d07Ssb155480 * after vsw's physical device is changed dynamically or after a guest (client 23351aa9d07Ssb155480 * vnet) is live migrated in. 23451aa9d07Ssb155480 */ 23551aa9d07Ssb155480 uint32_t vsw_publish_macaddr_count = 3; 23651aa9d07Ssb155480 237678453a8Sspeer boolean_t vsw_hio_enabled = B_TRUE; /* Enable/disable HybridIO */ 238678453a8Sspeer int vsw_hio_max_cleanup_retries = 10; /* Max retries for HybridIO cleanp */ 239678453a8Sspeer int vsw_hio_cleanup_delay = 10000; /* 10ms */ 240678453a8Sspeer 241f0ca1d9aSsb155480 /* Number of transmit descriptors - must be power of 2 */ 242f0ca1d9aSsb155480 uint32_t vsw_ntxds = VSW_RING_NUM_EL; 243f0ca1d9aSsb155480 24406db247cSraghuram /* 24506db247cSraghuram * Max number of mblks received in one receive operation. 24606db247cSraghuram */ 24706db247cSraghuram uint32_t vsw_chain_len = (VSW_NUM_MBLKS * 0.6); 24806db247cSraghuram 24906db247cSraghuram /* 2507b1f684aSSriharsha Basavapatna * Internal tunables for receive buffer pools, that is, the size and number of 2517b1f684aSSriharsha Basavapatna * mblks for each pool. At least 3 sizes must be specified if these are used. 2527b1f684aSSriharsha Basavapatna * The sizes must be specified in increasing order. Non-zero value of the first 2537b1f684aSSriharsha Basavapatna * size will be used as a hint to use these values instead of the algorithm 2547b1f684aSSriharsha Basavapatna * that determines the sizes based on MTU. 25506db247cSraghuram */ 2567b1f684aSSriharsha Basavapatna uint32_t vsw_mblk_size1 = 0; 2577b1f684aSSriharsha Basavapatna uint32_t vsw_mblk_size2 = 0; 2587b1f684aSSriharsha Basavapatna uint32_t vsw_mblk_size3 = 0; 2597b1f684aSSriharsha Basavapatna uint32_t vsw_mblk_size4 = 0; 26006db247cSraghuram uint32_t vsw_num_mblks1 = VSW_NUM_MBLKS; /* number of mblks for pool1 */ 26106db247cSraghuram uint32_t vsw_num_mblks2 = VSW_NUM_MBLKS; /* number of mblks for pool2 */ 26206db247cSraghuram uint32_t vsw_num_mblks3 = VSW_NUM_MBLKS; /* number of mblks for pool3 */ 2637b1f684aSSriharsha Basavapatna uint32_t vsw_num_mblks4 = VSW_NUM_MBLKS; /* number of mblks for pool4 */ 2647b1f684aSSriharsha Basavapatna 2657b1f684aSSriharsha Basavapatna /* 2667b1f684aSSriharsha Basavapatna * Set this to non-zero to enable additional internal receive buffer pools 2677b1f684aSSriharsha Basavapatna * based on the MTU of the device for better performance at the cost of more 2687b1f684aSSriharsha Basavapatna * memory consumption. This is turned off by default, to use allocb(9F) for 2697b1f684aSSriharsha Basavapatna * receive buffer allocations of sizes > 2K. 2707b1f684aSSriharsha Basavapatna */ 2717b1f684aSSriharsha Basavapatna boolean_t vsw_jumbo_rxpools = B_FALSE; 27206db247cSraghuram 27306db247cSraghuram /* 274f0ca1d9aSsb155480 * vsw_max_tx_qcount is the maximum # of packets that can be queued 275f0ca1d9aSsb155480 * before the tx worker thread begins processing the queue. Its value 276f0ca1d9aSsb155480 * is chosen to be 4x the default length of tx descriptor ring. 277f0ca1d9aSsb155480 */ 278f0ca1d9aSsb155480 uint32_t vsw_max_tx_qcount = 4 * VSW_RING_NUM_EL; 279f0ca1d9aSsb155480 280f0ca1d9aSsb155480 /* 28106db247cSraghuram * MAC callbacks 28206db247cSraghuram */ 283ba2e4443Sseb static mac_callbacks_t vsw_m_callbacks = { 284ba2e4443Sseb 0, 285ba2e4443Sseb vsw_m_stat, 286ba2e4443Sseb vsw_m_start, 287ba2e4443Sseb vsw_m_stop, 288ba2e4443Sseb vsw_m_promisc, 289ba2e4443Sseb vsw_m_multicst, 290ba2e4443Sseb vsw_m_unicst, 291ba2e4443Sseb vsw_m_tx, 292ba2e4443Sseb NULL, 293ba2e4443Sseb NULL, 294ba2e4443Sseb NULL 295ba2e4443Sseb }; 296ba2e4443Sseb 2971ae08745Sheppo static struct cb_ops vsw_cb_ops = { 2981ae08745Sheppo nulldev, /* cb_open */ 2991ae08745Sheppo nulldev, /* cb_close */ 3001ae08745Sheppo nodev, /* cb_strategy */ 3011ae08745Sheppo nodev, /* cb_print */ 3021ae08745Sheppo nodev, /* cb_dump */ 3031ae08745Sheppo nodev, /* cb_read */ 3041ae08745Sheppo nodev, /* cb_write */ 3051ae08745Sheppo nodev, /* cb_ioctl */ 3061ae08745Sheppo nodev, /* cb_devmap */ 3071ae08745Sheppo nodev, /* cb_mmap */ 3081ae08745Sheppo nodev, /* cb_segmap */ 3091ae08745Sheppo nochpoll, /* cb_chpoll */ 3101ae08745Sheppo ddi_prop_op, /* cb_prop_op */ 3111ae08745Sheppo NULL, /* cb_stream */ 3121ae08745Sheppo D_MP, /* cb_flag */ 3131ae08745Sheppo CB_REV, /* rev */ 3141ae08745Sheppo nodev, /* int (*cb_aread)() */ 3151ae08745Sheppo nodev /* int (*cb_awrite)() */ 3161ae08745Sheppo }; 3171ae08745Sheppo 3181ae08745Sheppo static struct dev_ops vsw_ops = { 3191ae08745Sheppo DEVO_REV, /* devo_rev */ 3201ae08745Sheppo 0, /* devo_refcnt */ 32171184a40SWENTAO YANG NULL, /* devo_getinfo */ 3221ae08745Sheppo nulldev, /* devo_identify */ 3231ae08745Sheppo nulldev, /* devo_probe */ 3241ae08745Sheppo vsw_attach, /* devo_attach */ 3251ae08745Sheppo vsw_detach, /* devo_detach */ 3261ae08745Sheppo nodev, /* devo_reset */ 3271ae08745Sheppo &vsw_cb_ops, /* devo_cb_ops */ 3281ae08745Sheppo (struct bus_ops *)NULL, /* devo_bus_ops */ 3291ae08745Sheppo ddi_power /* devo_power */ 3301ae08745Sheppo }; 3311ae08745Sheppo 3321ae08745Sheppo extern struct mod_ops mod_driverops; 3331ae08745Sheppo static struct modldrv vswmodldrv = { 3341ae08745Sheppo &mod_driverops, 335205eeb1aSlm66018 "sun4v Virtual Switch", 3361ae08745Sheppo &vsw_ops, 3371ae08745Sheppo }; 3381ae08745Sheppo 3391ae08745Sheppo #define LDC_ENTER_LOCK(ldcp) \ 3401ae08745Sheppo mutex_enter(&((ldcp)->ldc_cblock));\ 34106db247cSraghuram mutex_enter(&((ldcp)->ldc_rxlock));\ 3421ae08745Sheppo mutex_enter(&((ldcp)->ldc_txlock)); 3431ae08745Sheppo #define LDC_EXIT_LOCK(ldcp) \ 3441ae08745Sheppo mutex_exit(&((ldcp)->ldc_txlock));\ 34506db247cSraghuram mutex_exit(&((ldcp)->ldc_rxlock));\ 3461ae08745Sheppo mutex_exit(&((ldcp)->ldc_cblock)); 3471ae08745Sheppo 3481ae08745Sheppo /* Driver soft state ptr */ 3491ae08745Sheppo static void *vsw_state; 3501ae08745Sheppo 3511ae08745Sheppo /* 3521ae08745Sheppo * Linked list of "vsw_t" structures - one per instance. 3531ae08745Sheppo */ 3541ae08745Sheppo vsw_t *vsw_head = NULL; 3556f09f0feSWENTAO YANG vio_mblk_pool_t *vsw_rx_poolp = NULL; 3561ae08745Sheppo krwlock_t vsw_rw; 3571ae08745Sheppo 3581ae08745Sheppo /* 3591ae08745Sheppo * Property names 3601ae08745Sheppo */ 3611ae08745Sheppo static char vdev_propname[] = "virtual-device"; 3621ae08745Sheppo static char vsw_propname[] = "virtual-network-switch"; 3631ae08745Sheppo static char physdev_propname[] = "vsw-phys-dev"; 3641ae08745Sheppo static char smode_propname[] = "vsw-switch-mode"; 3651ae08745Sheppo static char macaddr_propname[] = "local-mac-address"; 3661ae08745Sheppo static char remaddr_propname[] = "remote-mac-address"; 3671ae08745Sheppo static char ldcids_propname[] = "ldc-ids"; 3681ae08745Sheppo static char chan_propname[] = "channel-endpoint"; 3691ae08745Sheppo static char id_propname[] = "id"; 3701ae08745Sheppo static char reg_propname[] = "reg"; 371f0ca1d9aSsb155480 static char pri_types_propname[] = "priority-ether-types"; 372c1c61f44Ssb155480 static char vsw_pvid_propname[] = "port-vlan-id"; 373c1c61f44Ssb155480 static char vsw_vid_propname[] = "vlan-id"; 374c1c61f44Ssb155480 static char vsw_dvid_propname[] = "default-vlan-id"; 375c1c61f44Ssb155480 static char port_pvid_propname[] = "remote-port-vlan-id"; 376c1c61f44Ssb155480 static char port_vid_propname[] = "remote-vlan-id"; 377678453a8Sspeer static char hybrid_propname[] = "hybrid"; 3787b1f684aSSriharsha Basavapatna static char vsw_mtu_propname[] = "mtu"; 379*1107ea93SSriharsha Basavapatna static char vsw_linkprop_propname[] = "linkprop"; 3801ae08745Sheppo 3811ae08745Sheppo /* 3821ae08745Sheppo * Matching criteria passed to the MDEG to register interest 3831ae08745Sheppo * in changes to 'virtual-device-port' nodes identified by their 3841ae08745Sheppo * 'id' property. 3851ae08745Sheppo */ 3861ae08745Sheppo static md_prop_match_t vport_prop_match[] = { 3871ae08745Sheppo { MDET_PROP_VAL, "id" }, 3881ae08745Sheppo { MDET_LIST_END, NULL } 3891ae08745Sheppo }; 3901ae08745Sheppo 3911ae08745Sheppo static mdeg_node_match_t vport_match = { "virtual-device-port", 3921ae08745Sheppo vport_prop_match }; 3931ae08745Sheppo 3941ae08745Sheppo /* 39534683adeSsg70180 * Matching criteria passed to the MDEG to register interest 39634683adeSsg70180 * in changes to 'virtual-device' nodes (i.e. vsw nodes) identified 39734683adeSsg70180 * by their 'name' and 'cfg-handle' properties. 39834683adeSsg70180 */ 39934683adeSsg70180 static md_prop_match_t vdev_prop_match[] = { 40034683adeSsg70180 { MDET_PROP_STR, "name" }, 40134683adeSsg70180 { MDET_PROP_VAL, "cfg-handle" }, 40234683adeSsg70180 { MDET_LIST_END, NULL } 40334683adeSsg70180 }; 40434683adeSsg70180 40534683adeSsg70180 static mdeg_node_match_t vdev_match = { "virtual-device", 40634683adeSsg70180 vdev_prop_match }; 40734683adeSsg70180 40834683adeSsg70180 40934683adeSsg70180 /* 4101ae08745Sheppo * Specification of an MD node passed to the MDEG to filter any 4111ae08745Sheppo * 'vport' nodes that do not belong to the specified node. This 4121ae08745Sheppo * template is copied for each vsw instance and filled in with 4131ae08745Sheppo * the appropriate 'cfg-handle' value before being passed to the MDEG. 4141ae08745Sheppo */ 4151ae08745Sheppo static mdeg_prop_spec_t vsw_prop_template[] = { 4161ae08745Sheppo { MDET_PROP_STR, "name", vsw_propname }, 4171ae08745Sheppo { MDET_PROP_VAL, "cfg-handle", NULL }, 4181ae08745Sheppo { MDET_LIST_END, NULL, NULL } 4191ae08745Sheppo }; 4201ae08745Sheppo 4211ae08745Sheppo #define VSW_SET_MDEG_PROP_INST(specp, val) (specp)[1].ps_val = (val); 4221ae08745Sheppo 42306db247cSraghuram #ifdef DEBUG 4247636cb21Slm66018 /* 4251ae08745Sheppo * Print debug messages - set to 0x1f to enable all msgs 4261ae08745Sheppo * or 0x0 to turn all off. 4271ae08745Sheppo */ 4281ae08745Sheppo int vswdbg = 0x0; 4291ae08745Sheppo 4301ae08745Sheppo /* 4311ae08745Sheppo * debug levels: 4321ae08745Sheppo * 0x01: Function entry/exit tracing 4331ae08745Sheppo * 0x02: Internal function messages 4341ae08745Sheppo * 0x04: Verbose internal messages 4351ae08745Sheppo * 0x08: Warning messages 4361ae08745Sheppo * 0x10: Error messages 4371ae08745Sheppo */ 4381ae08745Sheppo 43906db247cSraghuram void 4401ae08745Sheppo vswdebug(vsw_t *vswp, const char *fmt, ...) 4411ae08745Sheppo { 4421ae08745Sheppo char buf[512]; 4431ae08745Sheppo va_list ap; 4441ae08745Sheppo 4451ae08745Sheppo va_start(ap, fmt); 4461ae08745Sheppo (void) vsprintf(buf, fmt, ap); 4471ae08745Sheppo va_end(ap); 4481ae08745Sheppo 4491ae08745Sheppo if (vswp == NULL) 4501ae08745Sheppo cmn_err(CE_CONT, "%s\n", buf); 4511ae08745Sheppo else 4521ae08745Sheppo cmn_err(CE_CONT, "vsw%d: %s\n", vswp->instance, buf); 4531ae08745Sheppo } 4541ae08745Sheppo 4551ae08745Sheppo #endif /* DEBUG */ 4561ae08745Sheppo 4571ae08745Sheppo static struct modlinkage modlinkage = { 4581ae08745Sheppo MODREV_1, 4591ae08745Sheppo &vswmodldrv, 4601ae08745Sheppo NULL 4611ae08745Sheppo }; 4621ae08745Sheppo 4631ae08745Sheppo int 4641ae08745Sheppo _init(void) 4651ae08745Sheppo { 4661ae08745Sheppo int status; 4671ae08745Sheppo 4681ae08745Sheppo rw_init(&vsw_rw, NULL, RW_DRIVER, NULL); 4691ae08745Sheppo 4701ae08745Sheppo status = ddi_soft_state_init(&vsw_state, sizeof (vsw_t), 1); 4711ae08745Sheppo if (status != 0) { 4721ae08745Sheppo return (status); 4731ae08745Sheppo } 4741ae08745Sheppo 47506db247cSraghuram mac_init_ops(&vsw_ops, DRV_NAME); 4761ae08745Sheppo status = mod_install(&modlinkage); 4771ae08745Sheppo if (status != 0) { 4781ae08745Sheppo ddi_soft_state_fini(&vsw_state); 4791ae08745Sheppo } 4801ae08745Sheppo return (status); 4811ae08745Sheppo } 4821ae08745Sheppo 4831ae08745Sheppo int 4841ae08745Sheppo _fini(void) 4851ae08745Sheppo { 4861ae08745Sheppo int status; 4871ae08745Sheppo 4886f09f0feSWENTAO YANG status = vsw_mod_cleanup(); 4896f09f0feSWENTAO YANG if (status != 0) 4906f09f0feSWENTAO YANG return (status); 4916f09f0feSWENTAO YANG 4921ae08745Sheppo status = mod_remove(&modlinkage); 4931ae08745Sheppo if (status != 0) 4941ae08745Sheppo return (status); 4951ae08745Sheppo mac_fini_ops(&vsw_ops); 4961ae08745Sheppo ddi_soft_state_fini(&vsw_state); 4971ae08745Sheppo 4981ae08745Sheppo rw_destroy(&vsw_rw); 4991ae08745Sheppo 5001ae08745Sheppo return (status); 5011ae08745Sheppo } 5021ae08745Sheppo 5031ae08745Sheppo int 5041ae08745Sheppo _info(struct modinfo *modinfop) 5051ae08745Sheppo { 5061ae08745Sheppo return (mod_info(&modlinkage, modinfop)); 5071ae08745Sheppo } 5081ae08745Sheppo 5091ae08745Sheppo static int 5101ae08745Sheppo vsw_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 5111ae08745Sheppo { 5121ae08745Sheppo vsw_t *vswp; 51334683adeSsg70180 int instance; 5141ae08745Sheppo char hashname[MAXNAMELEN]; 5151ae08745Sheppo char qname[TASKQ_NAMELEN]; 5166f09f0feSWENTAO YANG vsw_attach_progress_t progress = PROG_init; 51719b65a69Ssb155480 int rv; 5181ae08745Sheppo 5191ae08745Sheppo switch (cmd) { 5201ae08745Sheppo case DDI_ATTACH: 5211ae08745Sheppo break; 5221ae08745Sheppo case DDI_RESUME: 5231ae08745Sheppo /* nothing to do for this non-device */ 5241ae08745Sheppo return (DDI_SUCCESS); 5251ae08745Sheppo case DDI_PM_RESUME: 5261ae08745Sheppo default: 5271ae08745Sheppo return (DDI_FAILURE); 5281ae08745Sheppo } 5291ae08745Sheppo 5301ae08745Sheppo instance = ddi_get_instance(dip); 5311ae08745Sheppo if (ddi_soft_state_zalloc(vsw_state, instance) != DDI_SUCCESS) { 5321ae08745Sheppo DERR(NULL, "vsw%d: ddi_soft_state_zalloc failed", instance); 5331ae08745Sheppo return (DDI_FAILURE); 5341ae08745Sheppo } 5351ae08745Sheppo vswp = ddi_get_soft_state(vsw_state, instance); 5361ae08745Sheppo 5371ae08745Sheppo if (vswp == NULL) { 5381ae08745Sheppo DERR(NULL, "vsw%d: ddi_get_soft_state failed", instance); 5391ae08745Sheppo goto vsw_attach_fail; 5401ae08745Sheppo } 5411ae08745Sheppo 5421ae08745Sheppo vswp->dip = dip; 5431ae08745Sheppo vswp->instance = instance; 544*1107ea93SSriharsha Basavapatna vswp->phys_link_state = LINK_STATE_UNKNOWN; 5451ae08745Sheppo ddi_set_driver_private(dip, (caddr_t)vswp); 5461ae08745Sheppo 547da14cebeSEric Cheng mutex_init(&vswp->mac_lock, NULL, MUTEX_DRIVER, NULL); 54819b65a69Ssb155480 mutex_init(&vswp->mca_lock, NULL, MUTEX_DRIVER, NULL); 549808f26a8SSriharsha Basavapatna mutex_init(&vswp->sw_thr_lock, NULL, MUTEX_DRIVER, NULL); 550808f26a8SSriharsha Basavapatna cv_init(&vswp->sw_thr_cv, NULL, CV_DRIVER, NULL); 551da14cebeSEric Cheng rw_init(&vswp->maccl_rwlock, NULL, RW_DRIVER, NULL); 5521ae08745Sheppo rw_init(&vswp->if_lockrw, NULL, RW_DRIVER, NULL); 55319b65a69Ssb155480 rw_init(&vswp->mfdbrw, NULL, RW_DRIVER, NULL); 55419b65a69Ssb155480 rw_init(&vswp->plist.lockrw, NULL, RW_DRIVER, NULL); 55519b65a69Ssb155480 55619b65a69Ssb155480 progress |= PROG_locks; 55719b65a69Ssb155480 55819b65a69Ssb155480 rv = vsw_read_mdprops(vswp); 55919b65a69Ssb155480 if (rv != 0) 56019b65a69Ssb155480 goto vsw_attach_fail; 56119b65a69Ssb155480 56219b65a69Ssb155480 progress |= PROG_readmd; 5631ae08745Sheppo 5641ae08745Sheppo /* setup the unicast forwarding database */ 5651ae08745Sheppo (void) snprintf(hashname, MAXNAMELEN, "vsw_unicst_table-%d", 5661ae08745Sheppo vswp->instance); 5671ae08745Sheppo D2(vswp, "creating unicast hash table (%s)...", hashname); 568c1c61f44Ssb155480 vswp->fdb_nchains = vsw_fdb_nchains; 569c1c61f44Ssb155480 vswp->fdb_hashp = mod_hash_create_ptrhash(hashname, vswp->fdb_nchains, 5701ae08745Sheppo mod_hash_null_valdtor, sizeof (void *)); 571c1c61f44Ssb155480 vsw_create_vlans((void *)vswp, VSW_LOCALDEV); 5721ae08745Sheppo progress |= PROG_fdb; 5731ae08745Sheppo 5741ae08745Sheppo /* setup the multicast fowarding database */ 5751ae08745Sheppo (void) snprintf(hashname, MAXNAMELEN, "vsw_mcst_table-%d", 5761ae08745Sheppo vswp->instance); 5771ae08745Sheppo D2(vswp, "creating multicast hash table %s)...", hashname); 578c1c61f44Ssb155480 vswp->mfdb = mod_hash_create_ptrhash(hashname, vsw_fdb_nchains, 5791ae08745Sheppo mod_hash_null_valdtor, sizeof (void *)); 5801ae08745Sheppo 5811ae08745Sheppo progress |= PROG_mfdb; 5821ae08745Sheppo 5831ae08745Sheppo /* 5841ae08745Sheppo * Create the taskq which will process all the VIO 5851ae08745Sheppo * control messages. 5861ae08745Sheppo */ 5871ae08745Sheppo (void) snprintf(qname, TASKQ_NAMELEN, "vsw_taskq%d", vswp->instance); 5881ae08745Sheppo if ((vswp->taskq_p = ddi_taskq_create(vswp->dip, qname, 1, 5891ae08745Sheppo TASKQ_DEFAULTPRI, 0)) == NULL) { 59034683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to create task queue", 59134683adeSsg70180 vswp->instance); 5921ae08745Sheppo goto vsw_attach_fail; 5931ae08745Sheppo } 5941ae08745Sheppo 5951ae08745Sheppo progress |= PROG_taskq; 5961ae08745Sheppo 597d10e4ef2Snarayan /* prevent auto-detaching */ 598d10e4ef2Snarayan if (ddi_prop_update_int(DDI_DEV_T_NONE, vswp->dip, 599d10e4ef2Snarayan DDI_NO_AUTODETACH, 1) != DDI_SUCCESS) { 60034683adeSsg70180 cmn_err(CE_NOTE, "!Unable to set \"%s\" property for " 601d10e4ef2Snarayan "instance %u", DDI_NO_AUTODETACH, instance); 602d10e4ef2Snarayan } 603d10e4ef2Snarayan 6041ae08745Sheppo /* 6057a327842Swentaoy * The null switching function is set to avoid panic until 6067a327842Swentaoy * switch mode is setup. 6077a327842Swentaoy */ 6087a327842Swentaoy vswp->vsw_switch_frame = vsw_switch_frame_nop; 6097a327842Swentaoy 6107a327842Swentaoy /* 611808f26a8SSriharsha Basavapatna * Setup the required switching mode, based on the mdprops that we read 612808f26a8SSriharsha Basavapatna * earlier. We start a thread to do this, to avoid calling mac_open() 613808f26a8SSriharsha Basavapatna * directly from attach(). 61419b65a69Ssb155480 */ 615808f26a8SSriharsha Basavapatna rv = vsw_setup_switching_start(vswp); 616808f26a8SSriharsha Basavapatna if (rv != 0) { 617808f26a8SSriharsha Basavapatna goto vsw_attach_fail; 618808f26a8SSriharsha Basavapatna } 61919b65a69Ssb155480 62019b65a69Ssb155480 progress |= PROG_swmode; 62119b65a69Ssb155480 62219b65a69Ssb155480 /* Register with mac layer as a provider */ 62319b65a69Ssb155480 rv = vsw_mac_register(vswp); 62419b65a69Ssb155480 if (rv != 0) 62519b65a69Ssb155480 goto vsw_attach_fail; 62619b65a69Ssb155480 62719b65a69Ssb155480 progress |= PROG_macreg; 62819b65a69Ssb155480 62919b65a69Ssb155480 /* 63034683adeSsg70180 * Now we have everything setup, register an interest in 63134683adeSsg70180 * specific MD nodes. 63234683adeSsg70180 * 63334683adeSsg70180 * The callback is invoked in 2 cases, firstly if upon mdeg 63434683adeSsg70180 * registration there are existing nodes which match our specified 63534683adeSsg70180 * criteria, and secondly if the MD is changed (and again, there 63634683adeSsg70180 * are nodes which we are interested in present within it. Note 63734683adeSsg70180 * that our callback will be invoked even if our specified nodes 63834683adeSsg70180 * have not actually changed). 63934683adeSsg70180 * 6401ae08745Sheppo */ 64119b65a69Ssb155480 rv = vsw_mdeg_register(vswp); 64219b65a69Ssb155480 if (rv != 0) 64334683adeSsg70180 goto vsw_attach_fail; 6441ae08745Sheppo 64519b65a69Ssb155480 progress |= PROG_mdreg; 64619b65a69Ssb155480 6476f09f0feSWENTAO YANG vswp->attach_progress = progress; 6486f09f0feSWENTAO YANG 64919b65a69Ssb155480 WRITE_ENTER(&vsw_rw); 65019b65a69Ssb155480 vswp->next = vsw_head; 65119b65a69Ssb155480 vsw_head = vswp; 65219b65a69Ssb155480 RW_EXIT(&vsw_rw); 65319b65a69Ssb155480 65419b65a69Ssb155480 ddi_report_dev(vswp->dip); 6551ae08745Sheppo return (DDI_SUCCESS); 6561ae08745Sheppo 6571ae08745Sheppo vsw_attach_fail: 6581ae08745Sheppo DERR(NULL, "vsw_attach: failed"); 6591ae08745Sheppo 6606f09f0feSWENTAO YANG vswp->attach_progress = progress; 6616f09f0feSWENTAO YANG (void) vsw_unattach(vswp); 6621ae08745Sheppo ddi_soft_state_free(vsw_state, instance); 6631ae08745Sheppo return (DDI_FAILURE); 6641ae08745Sheppo } 6651ae08745Sheppo 6661ae08745Sheppo static int 6671ae08745Sheppo vsw_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 6681ae08745Sheppo { 6691ae08745Sheppo vsw_t **vswpp, *vswp; 6701ae08745Sheppo int instance; 6711ae08745Sheppo 6721ae08745Sheppo instance = ddi_get_instance(dip); 6731ae08745Sheppo vswp = ddi_get_soft_state(vsw_state, instance); 6741ae08745Sheppo 6751ae08745Sheppo if (vswp == NULL) { 6761ae08745Sheppo return (DDI_FAILURE); 6771ae08745Sheppo } 6781ae08745Sheppo 6791ae08745Sheppo switch (cmd) { 6801ae08745Sheppo case DDI_DETACH: 6811ae08745Sheppo break; 6821ae08745Sheppo case DDI_SUSPEND: 6831ae08745Sheppo case DDI_PM_SUSPEND: 6841ae08745Sheppo default: 6851ae08745Sheppo return (DDI_FAILURE); 6861ae08745Sheppo } 6871ae08745Sheppo 6881ae08745Sheppo D2(vswp, "detaching instance %d", instance); 6891ae08745Sheppo 6906f09f0feSWENTAO YANG if (vsw_unattach(vswp) != 0) { 6911ae08745Sheppo return (DDI_FAILURE); 6921ae08745Sheppo } 693f0ca1d9aSsb155480 6941ae08745Sheppo ddi_remove_minor_node(dip, NULL); 6951ae08745Sheppo 6961ae08745Sheppo WRITE_ENTER(&vsw_rw); 6971ae08745Sheppo for (vswpp = &vsw_head; *vswpp; vswpp = &(*vswpp)->next) { 6981ae08745Sheppo if (*vswpp == vswp) { 6991ae08745Sheppo *vswpp = vswp->next; 7001ae08745Sheppo break; 7011ae08745Sheppo } 7021ae08745Sheppo } 7031ae08745Sheppo RW_EXIT(&vsw_rw); 7046f09f0feSWENTAO YANG 7051ae08745Sheppo ddi_soft_state_free(vsw_state, instance); 7061ae08745Sheppo 7071ae08745Sheppo return (DDI_SUCCESS); 7081ae08745Sheppo } 7091ae08745Sheppo 7101ae08745Sheppo /* 7116f09f0feSWENTAO YANG * Common routine to handle vsw_attach() failure and vsw_detach(). Note that 7126f09f0feSWENTAO YANG * the only reason this function could fail is if mac_unregister() fails. 7136f09f0feSWENTAO YANG * Otherwise, this function must ensure that all resources are freed and return 7146f09f0feSWENTAO YANG * success. 7156f09f0feSWENTAO YANG */ 7166f09f0feSWENTAO YANG static int 7176f09f0feSWENTAO YANG vsw_unattach(vsw_t *vswp) 7186f09f0feSWENTAO YANG { 7196f09f0feSWENTAO YANG vio_mblk_pool_t *poolp, *npoolp; 7206f09f0feSWENTAO YANG vsw_attach_progress_t progress; 7216f09f0feSWENTAO YANG 7226f09f0feSWENTAO YANG progress = vswp->attach_progress; 7236f09f0feSWENTAO YANG 7246f09f0feSWENTAO YANG /* 7256f09f0feSWENTAO YANG * Unregister from the gldv3 subsystem. This can fail, in particular 7266f09f0feSWENTAO YANG * if there are still any open references to this mac device; in which 7276f09f0feSWENTAO YANG * case we just return failure without continuing to detach further. 7286f09f0feSWENTAO YANG */ 7296f09f0feSWENTAO YANG if (progress & PROG_macreg) { 7306f09f0feSWENTAO YANG if (vsw_mac_unregister(vswp) != 0) { 7316f09f0feSWENTAO YANG cmn_err(CE_WARN, "!vsw%d: Unable to detach from " 7326f09f0feSWENTAO YANG "MAC layer", vswp->instance); 7336f09f0feSWENTAO YANG return (1); 7346f09f0feSWENTAO YANG } 7356f09f0feSWENTAO YANG progress &= ~PROG_macreg; 7366f09f0feSWENTAO YANG } 7376f09f0feSWENTAO YANG 7386f09f0feSWENTAO YANG /* 7396f09f0feSWENTAO YANG * Now that we have unregistered from gldv3, we must finish all other 7406f09f0feSWENTAO YANG * steps and successfully return from this function; otherwise we will 7416f09f0feSWENTAO YANG * end up leaving the device in a broken/unusable state. 7426f09f0feSWENTAO YANG * 7436f09f0feSWENTAO YANG * If we have registered with mdeg, unregister now to stop further 7446f09f0feSWENTAO YANG * callbacks to this vsw device and/or its ports. Then, detach any 7456f09f0feSWENTAO YANG * existing ports. 7466f09f0feSWENTAO YANG */ 7476f09f0feSWENTAO YANG if (progress & PROG_mdreg) { 7486f09f0feSWENTAO YANG vsw_mdeg_unregister(vswp); 7496f09f0feSWENTAO YANG vsw_detach_ports(vswp); 7506f09f0feSWENTAO YANG 7516f09f0feSWENTAO YANG /* 7526f09f0feSWENTAO YANG * At this point, we attempt to free receive mblk pools that 7536f09f0feSWENTAO YANG * couldn't be destroyed when the ports were detached; if this 7546f09f0feSWENTAO YANG * attempt also fails, we hook up the pool(s) to the module so 7556f09f0feSWENTAO YANG * they can be cleaned up in _fini(). 7566f09f0feSWENTAO YANG */ 7576f09f0feSWENTAO YANG poolp = vswp->rxh; 7586f09f0feSWENTAO YANG while (poolp != NULL) { 7596f09f0feSWENTAO YANG npoolp = vswp->rxh = poolp->nextp; 7606f09f0feSWENTAO YANG if (vio_destroy_mblks(poolp) != 0) { 7616f09f0feSWENTAO YANG WRITE_ENTER(&vsw_rw); 7626f09f0feSWENTAO YANG poolp->nextp = vsw_rx_poolp; 7636f09f0feSWENTAO YANG vsw_rx_poolp = poolp; 7646f09f0feSWENTAO YANG RW_EXIT(&vsw_rw); 7656f09f0feSWENTAO YANG } 7666f09f0feSWENTAO YANG poolp = npoolp; 7676f09f0feSWENTAO YANG } 7686f09f0feSWENTAO YANG progress &= ~PROG_mdreg; 7696f09f0feSWENTAO YANG } 7706f09f0feSWENTAO YANG 7716f09f0feSWENTAO YANG /* 7726f09f0feSWENTAO YANG * If we have started a thread to setup the switching mode, stop it, if 7736f09f0feSWENTAO YANG * it is still running. If it has finished setting up the switching 7746f09f0feSWENTAO YANG * mode, then we need to clean up some additional things if we are 7756f09f0feSWENTAO YANG * running in L2 mode: first free up any hybrid resources; then stop 7766f09f0feSWENTAO YANG * and close the underlying physical device. Note that we would have 7776f09f0feSWENTAO YANG * already released all per mac_client resources (ucast, mcast addrs, 7786f09f0feSWENTAO YANG * hio-shares etc) as all the ports are detached and if the vsw device 7796f09f0feSWENTAO YANG * itself was in use as an interface, it has been unplumbed (otherwise 7806f09f0feSWENTAO YANG * mac_unregister() above would fail). 7816f09f0feSWENTAO YANG */ 7826f09f0feSWENTAO YANG if (progress & PROG_swmode) { 7836f09f0feSWENTAO YANG 7846f09f0feSWENTAO YANG vsw_setup_switching_stop(vswp); 7856f09f0feSWENTAO YANG 7866f09f0feSWENTAO YANG if (vswp->hio_capable == B_TRUE) { 7876f09f0feSWENTAO YANG vsw_hio_cleanup(vswp); 7886f09f0feSWENTAO YANG vswp->hio_capable = B_FALSE; 7896f09f0feSWENTAO YANG } 7906f09f0feSWENTAO YANG 7916f09f0feSWENTAO YANG mutex_enter(&vswp->mac_lock); 7926f09f0feSWENTAO YANG vsw_mac_close(vswp); 7936f09f0feSWENTAO YANG mutex_exit(&vswp->mac_lock); 7946f09f0feSWENTAO YANG 7956f09f0feSWENTAO YANG progress &= ~PROG_swmode; 7966f09f0feSWENTAO YANG } 7976f09f0feSWENTAO YANG 7986f09f0feSWENTAO YANG /* 7996f09f0feSWENTAO YANG * By now any pending tasks have finished and the underlying 8006f09f0feSWENTAO YANG * ldc's have been destroyed, so its safe to delete the control 8016f09f0feSWENTAO YANG * message taskq. 8026f09f0feSWENTAO YANG */ 8036f09f0feSWENTAO YANG if (progress & PROG_taskq) { 8046f09f0feSWENTAO YANG ddi_taskq_destroy(vswp->taskq_p); 8056f09f0feSWENTAO YANG progress &= ~PROG_taskq; 8066f09f0feSWENTAO YANG } 8076f09f0feSWENTAO YANG 8086f09f0feSWENTAO YANG /* Destroy the multicast hash table */ 8096f09f0feSWENTAO YANG if (progress & PROG_mfdb) { 8106f09f0feSWENTAO YANG mod_hash_destroy_hash(vswp->mfdb); 8116f09f0feSWENTAO YANG progress &= ~PROG_mfdb; 8126f09f0feSWENTAO YANG } 8136f09f0feSWENTAO YANG 8146f09f0feSWENTAO YANG /* Destroy the vlan hash table and fdb */ 8156f09f0feSWENTAO YANG if (progress & PROG_fdb) { 8166f09f0feSWENTAO YANG vsw_destroy_vlans(vswp, VSW_LOCALDEV); 8176f09f0feSWENTAO YANG mod_hash_destroy_hash(vswp->fdb_hashp); 8186f09f0feSWENTAO YANG progress &= ~PROG_fdb; 8196f09f0feSWENTAO YANG } 8206f09f0feSWENTAO YANG 8216f09f0feSWENTAO YANG if (progress & PROG_readmd) { 8226f09f0feSWENTAO YANG if (VSW_PRI_ETH_DEFINED(vswp)) { 8236f09f0feSWENTAO YANG kmem_free(vswp->pri_types, 8246f09f0feSWENTAO YANG sizeof (uint16_t) * vswp->pri_num_types); 8256f09f0feSWENTAO YANG (void) vio_destroy_mblks(vswp->pri_tx_vmp); 8266f09f0feSWENTAO YANG } 8276f09f0feSWENTAO YANG progress &= ~PROG_readmd; 8286f09f0feSWENTAO YANG } 8296f09f0feSWENTAO YANG 8306f09f0feSWENTAO YANG if (progress & PROG_locks) { 8316f09f0feSWENTAO YANG rw_destroy(&vswp->plist.lockrw); 8326f09f0feSWENTAO YANG rw_destroy(&vswp->mfdbrw); 8336f09f0feSWENTAO YANG rw_destroy(&vswp->if_lockrw); 8346f09f0feSWENTAO YANG rw_destroy(&vswp->maccl_rwlock); 8356f09f0feSWENTAO YANG cv_destroy(&vswp->sw_thr_cv); 8366f09f0feSWENTAO YANG mutex_destroy(&vswp->sw_thr_lock); 8376f09f0feSWENTAO YANG mutex_destroy(&vswp->mca_lock); 8386f09f0feSWENTAO YANG mutex_destroy(&vswp->mac_lock); 8396f09f0feSWENTAO YANG progress &= ~PROG_locks; 8406f09f0feSWENTAO YANG } 8416f09f0feSWENTAO YANG 8426f09f0feSWENTAO YANG vswp->attach_progress = progress; 8436f09f0feSWENTAO YANG 8446f09f0feSWENTAO YANG return (0); 8456f09f0feSWENTAO YANG } 8466f09f0feSWENTAO YANG 8476f09f0feSWENTAO YANG /* 8486f09f0feSWENTAO YANG * one time cleanup. 8496f09f0feSWENTAO YANG */ 8506f09f0feSWENTAO YANG static int 8516f09f0feSWENTAO YANG vsw_mod_cleanup(void) 8526f09f0feSWENTAO YANG { 8536f09f0feSWENTAO YANG vio_mblk_pool_t *poolp, *npoolp; 8546f09f0feSWENTAO YANG 8556f09f0feSWENTAO YANG /* 8566f09f0feSWENTAO YANG * If any rx mblk pools are still in use, return 8576f09f0feSWENTAO YANG * error and stop the module from unloading. 8586f09f0feSWENTAO YANG */ 8596f09f0feSWENTAO YANG WRITE_ENTER(&vsw_rw); 8606f09f0feSWENTAO YANG poolp = vsw_rx_poolp; 8616f09f0feSWENTAO YANG while (poolp != NULL) { 8626f09f0feSWENTAO YANG npoolp = vsw_rx_poolp = poolp->nextp; 8636f09f0feSWENTAO YANG if (vio_destroy_mblks(poolp) != 0) { 8646f09f0feSWENTAO YANG vsw_rx_poolp = poolp; 8656f09f0feSWENTAO YANG RW_EXIT(&vsw_rw); 8666f09f0feSWENTAO YANG return (EBUSY); 8676f09f0feSWENTAO YANG } 8686f09f0feSWENTAO YANG poolp = npoolp; 8696f09f0feSWENTAO YANG } 8706f09f0feSWENTAO YANG RW_EXIT(&vsw_rw); 8716f09f0feSWENTAO YANG 8726f09f0feSWENTAO YANG return (0); 8736f09f0feSWENTAO YANG } 8746f09f0feSWENTAO YANG 8756f09f0feSWENTAO YANG /* 87634683adeSsg70180 * Get the value of the "vsw-phys-dev" property in the specified 87734683adeSsg70180 * node. This property is the name of the physical device that 87834683adeSsg70180 * the virtual switch will use to talk to the outside world. 87934683adeSsg70180 * 88034683adeSsg70180 * Note it is valid for this property to be NULL (but the property 88134683adeSsg70180 * itself must exist). Callers of this routine should verify that 88234683adeSsg70180 * the value returned is what they expected (i.e. either NULL or non NULL). 88334683adeSsg70180 * 88434683adeSsg70180 * On success returns value of the property in region pointed to by 88534683adeSsg70180 * the 'name' argument, and with return value of 0. Otherwise returns 1. 8861ae08745Sheppo */ 88734683adeSsg70180 static int 88834683adeSsg70180 vsw_get_md_physname(vsw_t *vswp, md_t *mdp, mde_cookie_t node, char *name) 8891ae08745Sheppo { 89034683adeSsg70180 int len = 0; 891f2b610cfSwentaoy int instance; 8921ae08745Sheppo char *physname = NULL; 8931ae08745Sheppo char *dev; 894f2b610cfSwentaoy const char *dev_name; 895f2b610cfSwentaoy char myname[MAXNAMELEN]; 896f2b610cfSwentaoy 897f2b610cfSwentaoy dev_name = ddi_driver_name(vswp->dip); 898f2b610cfSwentaoy instance = ddi_get_instance(vswp->dip); 899f2b610cfSwentaoy (void) snprintf(myname, MAXNAMELEN, "%s%d", dev_name, instance); 9001ae08745Sheppo 90134683adeSsg70180 if (md_get_prop_data(mdp, node, physdev_propname, 9021ae08745Sheppo (uint8_t **)(&physname), &len) != 0) { 90334683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to get name(s) of physical " 90434683adeSsg70180 "device(s) from MD", vswp->instance); 90534683adeSsg70180 return (1); 9061ae08745Sheppo } else if ((strlen(physname) + 1) > LIFNAMSIZ) { 90734683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: %s is too long a device name", 90834683adeSsg70180 vswp->instance, physname); 90934683adeSsg70180 return (1); 910f2b610cfSwentaoy } else if (strcmp(myname, physname) == 0) { 911f2b610cfSwentaoy /* 912f2b610cfSwentaoy * Prevent the vswitch from opening itself as the 913f2b610cfSwentaoy * network device. 914f2b610cfSwentaoy */ 915f2b610cfSwentaoy cmn_err(CE_WARN, "!vsw%d: %s is an invalid device name", 916f2b610cfSwentaoy vswp->instance, physname); 917f2b610cfSwentaoy return (1); 9181ae08745Sheppo } else { 91934683adeSsg70180 (void) strncpy(name, physname, strlen(physname) + 1); 9201ae08745Sheppo D2(vswp, "%s: using first device specified (%s)", 92134683adeSsg70180 __func__, physname); 9221ae08745Sheppo } 9231ae08745Sheppo 9241ae08745Sheppo #ifdef DEBUG 9251ae08745Sheppo /* 9261ae08745Sheppo * As a temporary measure to aid testing we check to see if there 9271ae08745Sheppo * is a vsw.conf file present. If there is we use the value of the 9281ae08745Sheppo * vsw_physname property in the file as the name of the physical 9291ae08745Sheppo * device, overriding the value from the MD. 9301ae08745Sheppo * 9311ae08745Sheppo * There may be multiple devices listed, but for the moment 9321ae08745Sheppo * we just use the first one. 9331ae08745Sheppo */ 9341ae08745Sheppo if (ddi_prop_lookup_string(DDI_DEV_T_ANY, vswp->dip, 0, 9351ae08745Sheppo "vsw_physname", &dev) == DDI_PROP_SUCCESS) { 9361ae08745Sheppo if ((strlen(dev) + 1) > LIFNAMSIZ) { 93734683adeSsg70180 cmn_err(CE_WARN, "vsw%d: %s is too long a device name", 93834683adeSsg70180 vswp->instance, dev); 93934683adeSsg70180 ddi_prop_free(dev); 94034683adeSsg70180 return (1); 9411ae08745Sheppo } else { 94234683adeSsg70180 cmn_err(CE_NOTE, "vsw%d: Using device name (%s) from " 94334683adeSsg70180 "config file", vswp->instance, dev); 9441ae08745Sheppo 94534683adeSsg70180 (void) strncpy(name, dev, strlen(dev) + 1); 9461ae08745Sheppo } 9471ae08745Sheppo 9481ae08745Sheppo ddi_prop_free(dev); 9491ae08745Sheppo } 9501ae08745Sheppo #endif 9511ae08745Sheppo 95234683adeSsg70180 return (0); 95334683adeSsg70180 } 954e1ebb9ecSlm66018 955e1ebb9ecSlm66018 /* 95634683adeSsg70180 * Read the 'vsw-switch-mode' property from the specified MD node. 95734683adeSsg70180 * 958da14cebeSEric Cheng * Returns 0 on success, otherwise returns 1. 959e1ebb9ecSlm66018 */ 96034683adeSsg70180 static int 961da14cebeSEric Cheng vsw_get_md_smodes(vsw_t *vswp, md_t *mdp, mde_cookie_t node, uint8_t *mode) 96234683adeSsg70180 { 96334683adeSsg70180 int len = 0; 96434683adeSsg70180 char *smode = NULL; 96534683adeSsg70180 char *curr_mode = NULL; 96634683adeSsg70180 96734683adeSsg70180 D1(vswp, "%s: enter", __func__); 9681ae08745Sheppo 9691ae08745Sheppo /* 9701ae08745Sheppo * Get the switch-mode property. The modes are listed in 9711ae08745Sheppo * decreasing order of preference, i.e. prefered mode is 9721ae08745Sheppo * first item in list. 9731ae08745Sheppo */ 9741ae08745Sheppo len = 0; 97534683adeSsg70180 if (md_get_prop_data(mdp, node, smode_propname, 9761ae08745Sheppo (uint8_t **)(&smode), &len) != 0) { 9771ae08745Sheppo /* 978e1ebb9ecSlm66018 * Unable to get switch-mode property from MD, nothing 979e1ebb9ecSlm66018 * more we can do. 9801ae08745Sheppo */ 98134683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to get switch mode property" 98234683adeSsg70180 " from the MD", vswp->instance); 98334683adeSsg70180 return (1); 984e1ebb9ecSlm66018 } 985e1ebb9ecSlm66018 9861ae08745Sheppo curr_mode = smode; 9871ae08745Sheppo /* 9881ae08745Sheppo * Modes of operation: 9891ae08745Sheppo * 'switched' - layer 2 switching, underlying HW in 990e1ebb9ecSlm66018 * programmed mode. 9911ae08745Sheppo * 'promiscuous' - layer 2 switching, underlying HW in 9921ae08745Sheppo * promiscuous mode. 9931ae08745Sheppo * 'routed' - layer 3 (i.e. IP) routing, underlying HW 9941ae08745Sheppo * in non-promiscuous mode. 9951ae08745Sheppo */ 996da14cebeSEric Cheng while (curr_mode < (smode + len)) { 9971ae08745Sheppo D2(vswp, "%s: curr_mode = [%s]", __func__, curr_mode); 998e1ebb9ecSlm66018 if (strcmp(curr_mode, "switched") == 0) { 999da14cebeSEric Cheng *mode = VSW_LAYER2; 1000e1ebb9ecSlm66018 } else if (strcmp(curr_mode, "promiscuous") == 0) { 1001da14cebeSEric Cheng *mode = VSW_LAYER2 | VSW_LAYER2_PROMISC; 1002e1ebb9ecSlm66018 } else if (strcmp(curr_mode, "routed") == 0) { 1003da14cebeSEric Cheng *mode = VSW_LAYER3; 1004e1ebb9ecSlm66018 } else { 1005da14cebeSEric Cheng cmn_err(CE_WARN, "!vsw%d: Unknown switch mode %s, " 1006da14cebeSEric Cheng "setting to default switched mode", 1007da14cebeSEric Cheng vswp->instance, curr_mode); 1008da14cebeSEric Cheng *mode = VSW_LAYER2; 10091ae08745Sheppo } 10101ae08745Sheppo curr_mode += strlen(curr_mode) + 1; 10111ae08745Sheppo } 10121ae08745Sheppo 1013da14cebeSEric Cheng D2(vswp, "%s: %d mode", __func__, *mode); 10141ae08745Sheppo 10151ae08745Sheppo D1(vswp, "%s: exit", __func__); 101634683adeSsg70180 101734683adeSsg70180 return (0); 10181ae08745Sheppo } 10191ae08745Sheppo 1020e1ebb9ecSlm66018 /* 10211ae08745Sheppo * Register with the MAC layer as a network device, so we 10221ae08745Sheppo * can be plumbed if necessary. 10231ae08745Sheppo */ 10241ae08745Sheppo static int 10251ae08745Sheppo vsw_mac_register(vsw_t *vswp) 10261ae08745Sheppo { 1027ba2e4443Sseb mac_register_t *macp; 1028ba2e4443Sseb int rv; 10291ae08745Sheppo 10301ae08745Sheppo D1(vswp, "%s: enter", __func__); 10311ae08745Sheppo 1032ba2e4443Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 1033ba2e4443Sseb return (EINVAL); 1034ba2e4443Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 10351ae08745Sheppo macp->m_driver = vswp; 1036ba2e4443Sseb macp->m_dip = vswp->dip; 1037ba2e4443Sseb macp->m_src_addr = (uint8_t *)&vswp->if_addr; 1038ba2e4443Sseb macp->m_callbacks = &vsw_m_callbacks; 1039ba2e4443Sseb macp->m_min_sdu = 0; 10407b1f684aSSriharsha Basavapatna macp->m_max_sdu = vswp->mtu; 1041c1c61f44Ssb155480 macp->m_margin = VLAN_TAGSZ; 1042ba2e4443Sseb rv = mac_register(macp, &vswp->if_mh); 1043ba2e4443Sseb mac_free(macp); 104419b65a69Ssb155480 if (rv != 0) { 104519b65a69Ssb155480 /* 104619b65a69Ssb155480 * Treat this as a non-fatal error as we may be 104719b65a69Ssb155480 * able to operate in some other mode. 104819b65a69Ssb155480 */ 104919b65a69Ssb155480 cmn_err(CE_NOTE, "!vsw%d: Unable to register as " 105019b65a69Ssb155480 "a provider with MAC layer", vswp->instance); 105119b65a69Ssb155480 return (rv); 105219b65a69Ssb155480 } 105319b65a69Ssb155480 1054ba2e4443Sseb vswp->if_state |= VSW_IF_REG; 10551ae08745Sheppo 10561ae08745Sheppo D1(vswp, "%s: exit", __func__); 10571ae08745Sheppo 10581ae08745Sheppo return (rv); 10591ae08745Sheppo } 10601ae08745Sheppo 10611ae08745Sheppo static int 10621ae08745Sheppo vsw_mac_unregister(vsw_t *vswp) 10631ae08745Sheppo { 10641ae08745Sheppo int rv = 0; 10651ae08745Sheppo 10661ae08745Sheppo D1(vswp, "%s: enter", __func__); 10671ae08745Sheppo 10681ae08745Sheppo WRITE_ENTER(&vswp->if_lockrw); 10691ae08745Sheppo 1070ba2e4443Sseb if (vswp->if_state & VSW_IF_REG) { 1071ba2e4443Sseb rv = mac_unregister(vswp->if_mh); 10721ae08745Sheppo if (rv != 0) { 10731ae08745Sheppo DWARN(vswp, "%s: unable to unregister from MAC " 10741ae08745Sheppo "framework", __func__); 10751ae08745Sheppo 10761ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 10771ae08745Sheppo D1(vswp, "%s: fail exit", __func__); 10781ae08745Sheppo return (rv); 10791ae08745Sheppo } 10801ae08745Sheppo 1081ba2e4443Sseb /* mark i/f as down and unregistered */ 1082ba2e4443Sseb vswp->if_state &= ~(VSW_IF_UP | VSW_IF_REG); 10831ae08745Sheppo } 10841ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 10851ae08745Sheppo 10861ae08745Sheppo D1(vswp, "%s: exit", __func__); 10871ae08745Sheppo 10881ae08745Sheppo return (rv); 10891ae08745Sheppo } 10901ae08745Sheppo 1091ba2e4443Sseb static int 1092ba2e4443Sseb vsw_m_stat(void *arg, uint_t stat, uint64_t *val) 10931ae08745Sheppo { 10941ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 10951ae08745Sheppo 10961ae08745Sheppo D1(vswp, "%s: enter", __func__); 10971ae08745Sheppo 1098da14cebeSEric Cheng mutex_enter(&vswp->mac_lock); 109934683adeSsg70180 if (vswp->mh == NULL) { 1100da14cebeSEric Cheng mutex_exit(&vswp->mac_lock); 1101ba2e4443Sseb return (EINVAL); 110234683adeSsg70180 } 11031ae08745Sheppo 11041ae08745Sheppo /* return stats from underlying device */ 1105ba2e4443Sseb *val = mac_stat_get(vswp->mh, stat); 110634683adeSsg70180 1107da14cebeSEric Cheng mutex_exit(&vswp->mac_lock); 110834683adeSsg70180 1109ba2e4443Sseb return (0); 11101ae08745Sheppo } 11111ae08745Sheppo 11121ae08745Sheppo static void 11131ae08745Sheppo vsw_m_stop(void *arg) 11141ae08745Sheppo { 11151ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 11161ae08745Sheppo 11171ae08745Sheppo D1(vswp, "%s: enter", __func__); 11181ae08745Sheppo 11191ae08745Sheppo WRITE_ENTER(&vswp->if_lockrw); 11201ae08745Sheppo vswp->if_state &= ~VSW_IF_UP; 11211ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 11221ae08745Sheppo 1123da14cebeSEric Cheng /* Cleanup and close the mac client */ 1124da14cebeSEric Cheng vsw_mac_client_cleanup(vswp, NULL, VSW_LOCALDEV); 11255f94e909Ssg70180 11261ae08745Sheppo D1(vswp, "%s: exit (state = %d)", __func__, vswp->if_state); 11271ae08745Sheppo } 11281ae08745Sheppo 11291ae08745Sheppo static int 11301ae08745Sheppo vsw_m_start(void *arg) 11311ae08745Sheppo { 1132da14cebeSEric Cheng int rv; 11331ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 11341ae08745Sheppo 11351ae08745Sheppo D1(vswp, "%s: enter", __func__); 11361ae08745Sheppo 11371ae08745Sheppo WRITE_ENTER(&vswp->if_lockrw); 11381ae08745Sheppo 113919b65a69Ssb155480 vswp->if_state |= VSW_IF_UP; 114019b65a69Ssb155480 114119b65a69Ssb155480 if (vswp->switching_setup_done == B_FALSE) { 114219b65a69Ssb155480 /* 114319b65a69Ssb155480 * If the switching mode has not been setup yet, just 114419b65a69Ssb155480 * return. The unicast address will be programmed 114519b65a69Ssb155480 * after the physical device is successfully setup by the 114619b65a69Ssb155480 * timeout handler. 114719b65a69Ssb155480 */ 114819b65a69Ssb155480 RW_EXIT(&vswp->if_lockrw); 114919b65a69Ssb155480 return (0); 115019b65a69Ssb155480 } 115119b65a69Ssb155480 115219b65a69Ssb155480 /* if in layer2 mode, program unicast address. */ 115319b65a69Ssb155480 if (vswp->mh != NULL) { 1154da14cebeSEric Cheng /* Init a mac client and program addresses */ 1155da14cebeSEric Cheng rv = vsw_mac_client_init(vswp, NULL, VSW_LOCALDEV); 1156da14cebeSEric Cheng if (rv != 0) { 1157da14cebeSEric Cheng cmn_err(CE_NOTE, 1158da14cebeSEric Cheng "!vsw%d: failed to program interface " 1159da14cebeSEric Cheng "unicast address\n", vswp->instance); 1160da14cebeSEric Cheng } 116119b65a69Ssb155480 } 116219b65a69Ssb155480 116319b65a69Ssb155480 RW_EXIT(&vswp->if_lockrw); 11645f94e909Ssg70180 11651ae08745Sheppo D1(vswp, "%s: exit (state = %d)", __func__, vswp->if_state); 11661ae08745Sheppo return (0); 11671ae08745Sheppo } 11681ae08745Sheppo 11691ae08745Sheppo /* 11701ae08745Sheppo * Change the local interface address. 11715f94e909Ssg70180 * 11725f94e909Ssg70180 * Note: we don't support this entry point. The local 11735f94e909Ssg70180 * mac address of the switch can only be changed via its 11745f94e909Ssg70180 * MD node properties. 11751ae08745Sheppo */ 11761ae08745Sheppo static int 11771ae08745Sheppo vsw_m_unicst(void *arg, const uint8_t *macaddr) 11781ae08745Sheppo { 11795f94e909Ssg70180 _NOTE(ARGUNUSED(arg, macaddr)) 11801ae08745Sheppo 11815f94e909Ssg70180 return (DDI_FAILURE); 11821ae08745Sheppo } 11831ae08745Sheppo 11841ae08745Sheppo static int 11851ae08745Sheppo vsw_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 11861ae08745Sheppo { 11871ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 11881ae08745Sheppo mcst_addr_t *mcst_p = NULL; 11891ae08745Sheppo uint64_t addr = 0x0; 1190e1ebb9ecSlm66018 int i, ret = 0; 11911ae08745Sheppo 11921ae08745Sheppo D1(vswp, "%s: enter", __func__); 11931ae08745Sheppo 11941ae08745Sheppo /* 11951ae08745Sheppo * Convert address into form that can be used 11961ae08745Sheppo * as hash table key. 11971ae08745Sheppo */ 11981ae08745Sheppo for (i = 0; i < ETHERADDRL; i++) { 11991ae08745Sheppo addr = (addr << 8) | mca[i]; 12001ae08745Sheppo } 12011ae08745Sheppo 12021ae08745Sheppo D2(vswp, "%s: addr = 0x%llx", __func__, addr); 12031ae08745Sheppo 12041ae08745Sheppo if (add) { 12051ae08745Sheppo D2(vswp, "%s: adding multicast", __func__); 12061ae08745Sheppo if (vsw_add_mcst(vswp, VSW_LOCALDEV, addr, NULL) == 0) { 12071ae08745Sheppo /* 12081ae08745Sheppo * Update the list of multicast addresses 12091ae08745Sheppo * contained within the vsw_t structure to 12101ae08745Sheppo * include this new one. 12111ae08745Sheppo */ 12121ae08745Sheppo mcst_p = kmem_zalloc(sizeof (mcst_addr_t), KM_NOSLEEP); 12131ae08745Sheppo if (mcst_p == NULL) { 12141ae08745Sheppo DERR(vswp, "%s unable to alloc mem", __func__); 121519b65a69Ssb155480 (void) vsw_del_mcst(vswp, 121619b65a69Ssb155480 VSW_LOCALDEV, addr, NULL); 12171ae08745Sheppo return (1); 12181ae08745Sheppo } 12191ae08745Sheppo mcst_p->addr = addr; 122019b65a69Ssb155480 ether_copy(mca, &mcst_p->mca); 12211ae08745Sheppo 12221ae08745Sheppo /* 12231ae08745Sheppo * Call into the underlying driver to program the 12241ae08745Sheppo * address into HW. 12251ae08745Sheppo */ 1226da14cebeSEric Cheng ret = vsw_mac_multicast_add(vswp, NULL, mcst_p, 1227da14cebeSEric Cheng VSW_LOCALDEV); 1228e1ebb9ecSlm66018 if (ret != 0) { 122919b65a69Ssb155480 (void) vsw_del_mcst(vswp, 123019b65a69Ssb155480 VSW_LOCALDEV, addr, NULL); 123119b65a69Ssb155480 kmem_free(mcst_p, sizeof (*mcst_p)); 123219b65a69Ssb155480 return (ret); 1233e1ebb9ecSlm66018 } 123419b65a69Ssb155480 123519b65a69Ssb155480 mutex_enter(&vswp->mca_lock); 123619b65a69Ssb155480 mcst_p->nextp = vswp->mcap; 123719b65a69Ssb155480 vswp->mcap = mcst_p; 123819b65a69Ssb155480 mutex_exit(&vswp->mca_lock); 12391ae08745Sheppo } else { 1240da14cebeSEric Cheng cmn_err(CE_WARN, "!vsw%d: unable to add multicast " 124134683adeSsg70180 "address", vswp->instance); 1242e1ebb9ecSlm66018 } 1243e1ebb9ecSlm66018 return (ret); 1244e1ebb9ecSlm66018 } 1245e1ebb9ecSlm66018 12461ae08745Sheppo D2(vswp, "%s: removing multicast", __func__); 12471ae08745Sheppo /* 12481ae08745Sheppo * Remove the address from the hash table.. 12491ae08745Sheppo */ 12501ae08745Sheppo if (vsw_del_mcst(vswp, VSW_LOCALDEV, addr, NULL) == 0) { 12511ae08745Sheppo 12521ae08745Sheppo /* 12531ae08745Sheppo * ..and then from the list maintained in the 12541ae08745Sheppo * vsw_t structure. 12551ae08745Sheppo */ 125619b65a69Ssb155480 mcst_p = vsw_del_addr(VSW_LOCALDEV, vswp, addr); 125719b65a69Ssb155480 ASSERT(mcst_p != NULL); 12581ae08745Sheppo 1259da14cebeSEric Cheng vsw_mac_multicast_remove(vswp, NULL, mcst_p, VSW_LOCALDEV); 126019b65a69Ssb155480 kmem_free(mcst_p, sizeof (*mcst_p)); 12611ae08745Sheppo } 12621ae08745Sheppo 12631ae08745Sheppo D1(vswp, "%s: exit", __func__); 12641ae08745Sheppo 12651ae08745Sheppo return (0); 12661ae08745Sheppo } 12671ae08745Sheppo 12681ae08745Sheppo static int 12691ae08745Sheppo vsw_m_promisc(void *arg, boolean_t on) 12701ae08745Sheppo { 12711ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 12721ae08745Sheppo 12731ae08745Sheppo D1(vswp, "%s: enter", __func__); 12741ae08745Sheppo 12751ae08745Sheppo WRITE_ENTER(&vswp->if_lockrw); 12761ae08745Sheppo if (on) 12771ae08745Sheppo vswp->if_state |= VSW_IF_PROMISC; 12781ae08745Sheppo else 12791ae08745Sheppo vswp->if_state &= ~VSW_IF_PROMISC; 12801ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 12811ae08745Sheppo 12821ae08745Sheppo D1(vswp, "%s: exit", __func__); 12831ae08745Sheppo 12841ae08745Sheppo return (0); 12851ae08745Sheppo } 12861ae08745Sheppo 12871ae08745Sheppo static mblk_t * 12881ae08745Sheppo vsw_m_tx(void *arg, mblk_t *mp) 12891ae08745Sheppo { 12901ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 12911ae08745Sheppo 12921ae08745Sheppo D1(vswp, "%s: enter", __func__); 12931ae08745Sheppo 1294c1c61f44Ssb155480 mp = vsw_vlan_frame_pretag(vswp, VSW_LOCALDEV, mp); 1295c1c61f44Ssb155480 1296c1c61f44Ssb155480 if (mp == NULL) { 1297c1c61f44Ssb155480 return (NULL); 1298c1c61f44Ssb155480 } 1299c1c61f44Ssb155480 130034683adeSsg70180 vswp->vsw_switch_frame(vswp, mp, VSW_LOCALDEV, NULL, NULL); 13011ae08745Sheppo 13021ae08745Sheppo D1(vswp, "%s: exit", __func__); 13031ae08745Sheppo 13041ae08745Sheppo return (NULL); 13051ae08745Sheppo } 13061ae08745Sheppo 13071ae08745Sheppo /* 13081ae08745Sheppo * Register for machine description (MD) updates. 130934683adeSsg70180 * 131034683adeSsg70180 * Returns 0 on success, 1 on failure. 13111ae08745Sheppo */ 131234683adeSsg70180 static int 13131ae08745Sheppo vsw_mdeg_register(vsw_t *vswp) 13141ae08745Sheppo { 13151ae08745Sheppo mdeg_prop_spec_t *pspecp; 13161ae08745Sheppo mdeg_node_spec_t *inst_specp; 131734683adeSsg70180 mdeg_handle_t mdeg_hdl, mdeg_port_hdl; 13181ae08745Sheppo size_t templatesz; 131919b65a69Ssb155480 int rv; 13201ae08745Sheppo 13211ae08745Sheppo D1(vswp, "%s: enter", __func__); 13221ae08745Sheppo 132334683adeSsg70180 /* 13241ae08745Sheppo * Allocate and initialize a per-instance copy 13251ae08745Sheppo * of the global property spec array that will 13261ae08745Sheppo * uniquely identify this vsw instance. 13271ae08745Sheppo */ 13281ae08745Sheppo templatesz = sizeof (vsw_prop_template); 13291ae08745Sheppo pspecp = kmem_zalloc(templatesz, KM_SLEEP); 13301ae08745Sheppo 13311ae08745Sheppo bcopy(vsw_prop_template, pspecp, templatesz); 13321ae08745Sheppo 133319b65a69Ssb155480 VSW_SET_MDEG_PROP_INST(pspecp, vswp->regprop); 13341ae08745Sheppo 13351ae08745Sheppo /* initialize the complete prop spec structure */ 13361ae08745Sheppo inst_specp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_SLEEP); 13371ae08745Sheppo inst_specp->namep = "virtual-device"; 13381ae08745Sheppo inst_specp->specp = pspecp; 13391ae08745Sheppo 134019b65a69Ssb155480 D2(vswp, "%s: instance %d registering with mdeg", __func__, 134119b65a69Ssb155480 vswp->regprop); 134234683adeSsg70180 /* 134334683adeSsg70180 * Register an interest in 'virtual-device' nodes with a 134434683adeSsg70180 * 'name' property of 'virtual-network-switch' 134534683adeSsg70180 */ 134634683adeSsg70180 rv = mdeg_register(inst_specp, &vdev_match, vsw_mdeg_cb, 13471ae08745Sheppo (void *)vswp, &mdeg_hdl); 134834683adeSsg70180 if (rv != MDEG_SUCCESS) { 134934683adeSsg70180 DERR(vswp, "%s: mdeg_register failed (%d) for vsw node", 135034683adeSsg70180 __func__, rv); 135134683adeSsg70180 goto mdeg_reg_fail; 135234683adeSsg70180 } 13531ae08745Sheppo 135434683adeSsg70180 /* 135534683adeSsg70180 * Register an interest in 'vsw-port' nodes. 135634683adeSsg70180 */ 135734683adeSsg70180 rv = mdeg_register(inst_specp, &vport_match, vsw_port_mdeg_cb, 135834683adeSsg70180 (void *)vswp, &mdeg_port_hdl); 13591ae08745Sheppo if (rv != MDEG_SUCCESS) { 13601ae08745Sheppo DERR(vswp, "%s: mdeg_register failed (%d)\n", __func__, rv); 136134683adeSsg70180 (void) mdeg_unregister(mdeg_hdl); 136234683adeSsg70180 goto mdeg_reg_fail; 13631ae08745Sheppo } 13641ae08745Sheppo 13651ae08745Sheppo /* save off data that will be needed later */ 13661ae08745Sheppo vswp->inst_spec = inst_specp; 13671ae08745Sheppo vswp->mdeg_hdl = mdeg_hdl; 136834683adeSsg70180 vswp->mdeg_port_hdl = mdeg_port_hdl; 13691ae08745Sheppo 13701ae08745Sheppo D1(vswp, "%s: exit", __func__); 137134683adeSsg70180 return (0); 137234683adeSsg70180 137334683adeSsg70180 mdeg_reg_fail: 137434683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to register MDEG callbacks", 137534683adeSsg70180 vswp->instance); 137634683adeSsg70180 kmem_free(pspecp, templatesz); 137734683adeSsg70180 kmem_free(inst_specp, sizeof (mdeg_node_spec_t)); 137834683adeSsg70180 137934683adeSsg70180 vswp->mdeg_hdl = NULL; 138034683adeSsg70180 vswp->mdeg_port_hdl = NULL; 138134683adeSsg70180 138234683adeSsg70180 return (1); 13831ae08745Sheppo } 13841ae08745Sheppo 13851ae08745Sheppo static void 13861ae08745Sheppo vsw_mdeg_unregister(vsw_t *vswp) 13871ae08745Sheppo { 13881ae08745Sheppo D1(vswp, "vsw_mdeg_unregister: enter"); 13891ae08745Sheppo 139034683adeSsg70180 if (vswp->mdeg_hdl != NULL) 13911ae08745Sheppo (void) mdeg_unregister(vswp->mdeg_hdl); 13921ae08745Sheppo 139334683adeSsg70180 if (vswp->mdeg_port_hdl != NULL) 139434683adeSsg70180 (void) mdeg_unregister(vswp->mdeg_port_hdl); 139534683adeSsg70180 139634683adeSsg70180 if (vswp->inst_spec != NULL) { 13971ae08745Sheppo if (vswp->inst_spec->specp != NULL) { 13981ae08745Sheppo (void) kmem_free(vswp->inst_spec->specp, 13991ae08745Sheppo sizeof (vsw_prop_template)); 14001ae08745Sheppo vswp->inst_spec->specp = NULL; 14011ae08745Sheppo } 14021ae08745Sheppo 1403205eeb1aSlm66018 (void) kmem_free(vswp->inst_spec, sizeof (mdeg_node_spec_t)); 14041ae08745Sheppo vswp->inst_spec = NULL; 14051ae08745Sheppo } 14061ae08745Sheppo 14071ae08745Sheppo D1(vswp, "vsw_mdeg_unregister: exit"); 14081ae08745Sheppo } 14091ae08745Sheppo 141034683adeSsg70180 /* 141134683adeSsg70180 * Mdeg callback invoked for the vsw node itself. 141234683adeSsg70180 */ 14131ae08745Sheppo static int 14141ae08745Sheppo vsw_mdeg_cb(void *cb_argp, mdeg_result_t *resp) 14151ae08745Sheppo { 14161ae08745Sheppo vsw_t *vswp; 14171ae08745Sheppo md_t *mdp; 14181ae08745Sheppo mde_cookie_t node; 14191ae08745Sheppo uint64_t inst; 142034683adeSsg70180 char *node_name = NULL; 14211ae08745Sheppo 14221ae08745Sheppo if (resp == NULL) 14231ae08745Sheppo return (MDEG_FAILURE); 14241ae08745Sheppo 14251ae08745Sheppo vswp = (vsw_t *)cb_argp; 14261ae08745Sheppo 142734683adeSsg70180 D1(vswp, "%s: added %d : removed %d : curr matched %d" 142834683adeSsg70180 " : prev matched %d", __func__, resp->added.nelem, 142934683adeSsg70180 resp->removed.nelem, resp->match_curr.nelem, 143034683adeSsg70180 resp->match_prev.nelem); 143134683adeSsg70180 143234683adeSsg70180 /* 143319b65a69Ssb155480 * We get an initial callback for this node as 'added' 143419b65a69Ssb155480 * after registering with mdeg. Note that we would have 143519b65a69Ssb155480 * already gathered information about this vsw node by 143619b65a69Ssb155480 * walking MD earlier during attach (in vsw_read_mdprops()). 143719b65a69Ssb155480 * So, there is a window where the properties of this 143819b65a69Ssb155480 * node might have changed when we get this initial 'added' 143919b65a69Ssb155480 * callback. We handle this as if an update occured 144019b65a69Ssb155480 * and invoke the same function which handles updates to 144119b65a69Ssb155480 * the properties of this vsw-node if any. 144219b65a69Ssb155480 * 144334683adeSsg70180 * A non-zero 'match' value indicates that the MD has been 144419b65a69Ssb155480 * updated and that a virtual-network-switch node is 144519b65a69Ssb155480 * present which may or may not have been updated. It is 144619b65a69Ssb155480 * up to the clients to examine their own nodes and 144719b65a69Ssb155480 * determine if they have changed. 144834683adeSsg70180 */ 144919b65a69Ssb155480 if (resp->added.nelem != 0) { 145034683adeSsg70180 145119b65a69Ssb155480 if (resp->added.nelem != 1) { 145219b65a69Ssb155480 cmn_err(CE_NOTE, "!vsw%d: number of nodes added " 145319b65a69Ssb155480 "invalid: %d\n", vswp->instance, resp->added.nelem); 145419b65a69Ssb155480 return (MDEG_FAILURE); 145519b65a69Ssb155480 } 145619b65a69Ssb155480 145719b65a69Ssb155480 mdp = resp->added.mdp; 145819b65a69Ssb155480 node = resp->added.mdep[0]; 145919b65a69Ssb155480 146019b65a69Ssb155480 } else if (resp->match_curr.nelem != 0) { 146119b65a69Ssb155480 146219b65a69Ssb155480 if (resp->match_curr.nelem != 1) { 146319b65a69Ssb155480 cmn_err(CE_NOTE, "!vsw%d: number of nodes updated " 146419b65a69Ssb155480 "invalid: %d\n", vswp->instance, 146519b65a69Ssb155480 resp->match_curr.nelem); 146619b65a69Ssb155480 return (MDEG_FAILURE); 146719b65a69Ssb155480 } 146819b65a69Ssb155480 146919b65a69Ssb155480 mdp = resp->match_curr.mdp; 147019b65a69Ssb155480 node = resp->match_curr.mdep[0]; 147119b65a69Ssb155480 147219b65a69Ssb155480 } else { 147319b65a69Ssb155480 return (MDEG_FAILURE); 147419b65a69Ssb155480 } 147519b65a69Ssb155480 147619b65a69Ssb155480 /* Validate name and instance */ 147734683adeSsg70180 if (md_get_prop_str(mdp, node, "name", &node_name) != 0) { 147819b65a69Ssb155480 DERR(vswp, "%s: unable to get node name\n", __func__); 147919b65a69Ssb155480 return (MDEG_FAILURE); 148019b65a69Ssb155480 } 148119b65a69Ssb155480 148219b65a69Ssb155480 /* is this a virtual-network-switch? */ 148319b65a69Ssb155480 if (strcmp(node_name, vsw_propname) != 0) { 148419b65a69Ssb155480 DERR(vswp, "%s: Invalid node name: %s\n", 148519b65a69Ssb155480 __func__, node_name); 148619b65a69Ssb155480 return (MDEG_FAILURE); 148734683adeSsg70180 } 148834683adeSsg70180 148934683adeSsg70180 if (md_get_prop_val(mdp, node, "cfg-handle", &inst)) { 149019b65a69Ssb155480 DERR(vswp, "%s: prop(cfg-handle) not found\n", 149119b65a69Ssb155480 __func__); 149219b65a69Ssb155480 return (MDEG_FAILURE); 149334683adeSsg70180 } 149434683adeSsg70180 149519b65a69Ssb155480 /* is this the right instance of vsw? */ 149619b65a69Ssb155480 if (inst != vswp->regprop) { 149719b65a69Ssb155480 DERR(vswp, "%s: Invalid cfg-handle: %lx\n", 149819b65a69Ssb155480 __func__, inst); 149919b65a69Ssb155480 return (MDEG_FAILURE); 150019b65a69Ssb155480 } 150134683adeSsg70180 150234683adeSsg70180 vsw_update_md_prop(vswp, mdp, node); 150334683adeSsg70180 150434683adeSsg70180 return (MDEG_SUCCESS); 150534683adeSsg70180 } 150634683adeSsg70180 150734683adeSsg70180 /* 150834683adeSsg70180 * Mdeg callback invoked for changes to the vsw-port nodes 150934683adeSsg70180 * under the vsw node. 151034683adeSsg70180 */ 151134683adeSsg70180 static int 151234683adeSsg70180 vsw_port_mdeg_cb(void *cb_argp, mdeg_result_t *resp) 151334683adeSsg70180 { 151434683adeSsg70180 vsw_t *vswp; 151534683adeSsg70180 int idx; 151634683adeSsg70180 md_t *mdp; 151734683adeSsg70180 mde_cookie_t node; 151834683adeSsg70180 uint64_t inst; 15191ef0bbb5Snarayan int rv; 152034683adeSsg70180 152134683adeSsg70180 if ((resp == NULL) || (cb_argp == NULL)) 152234683adeSsg70180 return (MDEG_FAILURE); 152334683adeSsg70180 152434683adeSsg70180 vswp = (vsw_t *)cb_argp; 152534683adeSsg70180 152634683adeSsg70180 D2(vswp, "%s: added %d : removed %d : curr matched %d" 152734683adeSsg70180 " : prev matched %d", __func__, resp->added.nelem, 152834683adeSsg70180 resp->removed.nelem, resp->match_curr.nelem, 15291ae08745Sheppo resp->match_prev.nelem); 15301ae08745Sheppo 15311ae08745Sheppo /* process added ports */ 15321ae08745Sheppo for (idx = 0; idx < resp->added.nelem; idx++) { 15331ae08745Sheppo mdp = resp->added.mdp; 15341ae08745Sheppo node = resp->added.mdep[idx]; 15351ae08745Sheppo 15361ae08745Sheppo D2(vswp, "%s: adding node(%d) 0x%lx", __func__, idx, node); 15371ae08745Sheppo 15381ef0bbb5Snarayan if ((rv = vsw_port_add(vswp, mdp, &node)) != 0) { 153934683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to add new port " 15401ef0bbb5Snarayan "(0x%lx), err=%d", vswp->instance, node, rv); 15411ae08745Sheppo } 15421ae08745Sheppo } 15431ae08745Sheppo 15441ae08745Sheppo /* process removed ports */ 15451ae08745Sheppo for (idx = 0; idx < resp->removed.nelem; idx++) { 15461ae08745Sheppo mdp = resp->removed.mdp; 15471ae08745Sheppo node = resp->removed.mdep[idx]; 15481ae08745Sheppo 15491ae08745Sheppo if (md_get_prop_val(mdp, node, id_propname, &inst)) { 155034683adeSsg70180 DERR(vswp, "%s: prop(%s) not found in port(%d)", 15511ae08745Sheppo __func__, id_propname, idx); 15521ae08745Sheppo continue; 15531ae08745Sheppo } 15541ae08745Sheppo 15551ae08745Sheppo D2(vswp, "%s: removing node(%d) 0x%lx", __func__, idx, node); 15561ae08745Sheppo 15571ae08745Sheppo if (vsw_port_detach(vswp, inst) != 0) { 155834683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to remove port %ld", 155934683adeSsg70180 vswp->instance, inst); 15601ae08745Sheppo } 15611ae08745Sheppo } 15621ae08745Sheppo 1563c1c61f44Ssb155480 for (idx = 0; idx < resp->match_curr.nelem; idx++) { 1564c1c61f44Ssb155480 (void) vsw_port_update(vswp, resp->match_curr.mdp, 1565c1c61f44Ssb155480 resp->match_curr.mdep[idx], 1566c1c61f44Ssb155480 resp->match_prev.mdp, 1567c1c61f44Ssb155480 resp->match_prev.mdep[idx]); 1568c1c61f44Ssb155480 } 15691ae08745Sheppo 15701ae08745Sheppo D1(vswp, "%s: exit", __func__); 15711ae08745Sheppo 15721ae08745Sheppo return (MDEG_SUCCESS); 15731ae08745Sheppo } 15741ae08745Sheppo 15751ae08745Sheppo /* 157619b65a69Ssb155480 * Scan the machine description for this instance of vsw 157719b65a69Ssb155480 * and read its properties. Called only from vsw_attach(). 157819b65a69Ssb155480 * Returns: 0 on success, 1 on failure. 157919b65a69Ssb155480 */ 158019b65a69Ssb155480 static int 158119b65a69Ssb155480 vsw_read_mdprops(vsw_t *vswp) 158219b65a69Ssb155480 { 158319b65a69Ssb155480 md_t *mdp = NULL; 158419b65a69Ssb155480 mde_cookie_t rootnode; 158519b65a69Ssb155480 mde_cookie_t *listp = NULL; 158619b65a69Ssb155480 uint64_t inst; 158719b65a69Ssb155480 uint64_t cfgh; 158819b65a69Ssb155480 char *name; 158919b65a69Ssb155480 int rv = 1; 159019b65a69Ssb155480 int num_nodes = 0; 159119b65a69Ssb155480 int num_devs = 0; 159219b65a69Ssb155480 int listsz = 0; 159319b65a69Ssb155480 int i; 159419b65a69Ssb155480 159519b65a69Ssb155480 /* 159619b65a69Ssb155480 * In each 'virtual-device' node in the MD there is a 159719b65a69Ssb155480 * 'cfg-handle' property which is the MD's concept of 159819b65a69Ssb155480 * an instance number (this may be completely different from 159919b65a69Ssb155480 * the device drivers instance #). OBP reads that value and 160019b65a69Ssb155480 * stores it in the 'reg' property of the appropriate node in 160119b65a69Ssb155480 * the device tree. We first read this reg property and use this 160219b65a69Ssb155480 * to compare against the 'cfg-handle' property of vsw nodes 160319b65a69Ssb155480 * in MD to get to this specific vsw instance and then read 160419b65a69Ssb155480 * other properties that we are interested in. 160519b65a69Ssb155480 * We also cache the value of 'reg' property and use it later 160619b65a69Ssb155480 * to register callbacks with mdeg (see vsw_mdeg_register()) 160719b65a69Ssb155480 */ 160819b65a69Ssb155480 inst = ddi_prop_get_int(DDI_DEV_T_ANY, vswp->dip, 160919b65a69Ssb155480 DDI_PROP_DONTPASS, reg_propname, -1); 161019b65a69Ssb155480 if (inst == -1) { 161119b65a69Ssb155480 cmn_err(CE_NOTE, "!vsw%d: Unable to read %s property from " 161219b65a69Ssb155480 "OBP device tree", vswp->instance, reg_propname); 161319b65a69Ssb155480 return (rv); 161419b65a69Ssb155480 } 161519b65a69Ssb155480 161619b65a69Ssb155480 vswp->regprop = inst; 161719b65a69Ssb155480 161819b65a69Ssb155480 if ((mdp = md_get_handle()) == NULL) { 161919b65a69Ssb155480 DWARN(vswp, "%s: cannot init MD\n", __func__); 162019b65a69Ssb155480 return (rv); 162119b65a69Ssb155480 } 162219b65a69Ssb155480 162319b65a69Ssb155480 num_nodes = md_node_count(mdp); 162419b65a69Ssb155480 ASSERT(num_nodes > 0); 162519b65a69Ssb155480 162619b65a69Ssb155480 listsz = num_nodes * sizeof (mde_cookie_t); 162719b65a69Ssb155480 listp = (mde_cookie_t *)kmem_zalloc(listsz, KM_SLEEP); 162819b65a69Ssb155480 162919b65a69Ssb155480 rootnode = md_root_node(mdp); 163019b65a69Ssb155480 163119b65a69Ssb155480 /* search for all "virtual_device" nodes */ 163219b65a69Ssb155480 num_devs = md_scan_dag(mdp, rootnode, 163319b65a69Ssb155480 md_find_name(mdp, vdev_propname), 163419b65a69Ssb155480 md_find_name(mdp, "fwd"), listp); 163519b65a69Ssb155480 if (num_devs <= 0) { 163619b65a69Ssb155480 DWARN(vswp, "%s: invalid num_devs:%d\n", __func__, num_devs); 163719b65a69Ssb155480 goto vsw_readmd_exit; 163819b65a69Ssb155480 } 163919b65a69Ssb155480 164019b65a69Ssb155480 /* 164119b65a69Ssb155480 * Now loop through the list of virtual-devices looking for 164219b65a69Ssb155480 * devices with name "virtual-network-switch" and for each 164319b65a69Ssb155480 * such device compare its instance with what we have from 164419b65a69Ssb155480 * the 'reg' property to find the right node in MD and then 164519b65a69Ssb155480 * read all its properties. 164619b65a69Ssb155480 */ 164719b65a69Ssb155480 for (i = 0; i < num_devs; i++) { 164819b65a69Ssb155480 164919b65a69Ssb155480 if (md_get_prop_str(mdp, listp[i], "name", &name) != 0) { 165019b65a69Ssb155480 DWARN(vswp, "%s: name property not found\n", 165119b65a69Ssb155480 __func__); 165219b65a69Ssb155480 goto vsw_readmd_exit; 165319b65a69Ssb155480 } 165419b65a69Ssb155480 165519b65a69Ssb155480 /* is this a virtual-network-switch? */ 165619b65a69Ssb155480 if (strcmp(name, vsw_propname) != 0) 165719b65a69Ssb155480 continue; 165819b65a69Ssb155480 165919b65a69Ssb155480 if (md_get_prop_val(mdp, listp[i], "cfg-handle", &cfgh) != 0) { 166019b65a69Ssb155480 DWARN(vswp, "%s: cfg-handle property not found\n", 166119b65a69Ssb155480 __func__); 166219b65a69Ssb155480 goto vsw_readmd_exit; 166319b65a69Ssb155480 } 166419b65a69Ssb155480 166519b65a69Ssb155480 /* is this the required instance of vsw? */ 166619b65a69Ssb155480 if (inst != cfgh) 166719b65a69Ssb155480 continue; 166819b65a69Ssb155480 166919b65a69Ssb155480 /* now read all properties of this vsw instance */ 167019b65a69Ssb155480 rv = vsw_get_initial_md_properties(vswp, mdp, listp[i]); 167119b65a69Ssb155480 break; 167219b65a69Ssb155480 } 167319b65a69Ssb155480 167419b65a69Ssb155480 vsw_readmd_exit: 167519b65a69Ssb155480 167619b65a69Ssb155480 kmem_free(listp, listsz); 167719b65a69Ssb155480 (void) md_fini_handle(mdp); 167819b65a69Ssb155480 return (rv); 167919b65a69Ssb155480 } 168019b65a69Ssb155480 168119b65a69Ssb155480 /* 168234683adeSsg70180 * Read the initial start-of-day values from the specified MD node. 168334683adeSsg70180 */ 168419b65a69Ssb155480 static int 168534683adeSsg70180 vsw_get_initial_md_properties(vsw_t *vswp, md_t *mdp, mde_cookie_t node) 168634683adeSsg70180 { 168734683adeSsg70180 uint64_t macaddr = 0; 168834683adeSsg70180 168934683adeSsg70180 D1(vswp, "%s: enter", __func__); 169034683adeSsg70180 169119b65a69Ssb155480 if (vsw_get_md_physname(vswp, mdp, node, vswp->physname) != 0) { 169219b65a69Ssb155480 return (1); 169334683adeSsg70180 } 169434683adeSsg70180 169534683adeSsg70180 /* mac address for vswitch device itself */ 169634683adeSsg70180 if (md_get_prop_val(mdp, node, macaddr_propname, &macaddr) != 0) { 169734683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to get MAC address from MD", 169834683adeSsg70180 vswp->instance); 169919b65a69Ssb155480 return (1); 170019b65a69Ssb155480 } 170134683adeSsg70180 170219b65a69Ssb155480 vsw_save_lmacaddr(vswp, macaddr); 170334683adeSsg70180 1704da14cebeSEric Cheng if (vsw_get_md_smodes(vswp, mdp, node, &vswp->smode)) { 17051ef0bbb5Snarayan DWARN(vswp, "%s: Unable to read %s property from MD, " 17061ef0bbb5Snarayan "defaulting to 'switched' mode", 17071ef0bbb5Snarayan __func__, smode_propname); 170834683adeSsg70180 1709da14cebeSEric Cheng vswp->smode = VSW_LAYER2; 171034683adeSsg70180 } 171134683adeSsg70180 1712*1107ea93SSriharsha Basavapatna /* 1713*1107ea93SSriharsha Basavapatna * Read the 'linkprop' property to know if this 1714*1107ea93SSriharsha Basavapatna * vsw device wants to get physical link updates. 1715*1107ea93SSriharsha Basavapatna */ 1716*1107ea93SSriharsha Basavapatna vsw_linkprop_read(vswp, mdp, node, &vswp->pls_update); 1717*1107ea93SSriharsha Basavapatna 17187b1f684aSSriharsha Basavapatna /* read mtu */ 17197b1f684aSSriharsha Basavapatna vsw_mtu_read(vswp, mdp, node, &vswp->mtu); 17207b1f684aSSriharsha Basavapatna if (vswp->mtu < ETHERMTU || vswp->mtu > VNET_MAX_MTU) { 17217b1f684aSSriharsha Basavapatna vswp->mtu = ETHERMTU; 17227b1f684aSSriharsha Basavapatna } 17237b1f684aSSriharsha Basavapatna vswp->max_frame_size = vswp->mtu + sizeof (struct ether_header) + 17247b1f684aSSriharsha Basavapatna VLAN_TAGSZ; 17257b1f684aSSriharsha Basavapatna 1726c1c61f44Ssb155480 /* read vlan id properties of this vsw instance */ 1727c1c61f44Ssb155480 vsw_vlan_read_ids(vswp, VSW_LOCALDEV, mdp, node, &vswp->pvid, 1728c1c61f44Ssb155480 &vswp->vids, &vswp->nvids, &vswp->default_vlan_id); 1729c1c61f44Ssb155480 1730c1c61f44Ssb155480 /* read priority-ether-types */ 1731f0ca1d9aSsb155480 vsw_read_pri_eth_types(vswp, mdp, node); 1732f0ca1d9aSsb155480 173334683adeSsg70180 D1(vswp, "%s: exit", __func__); 173419b65a69Ssb155480 return (0); 173534683adeSsg70180 } 173634683adeSsg70180 173734683adeSsg70180 /* 1738c1c61f44Ssb155480 * Read vlan id properties of the given MD node. 1739c1c61f44Ssb155480 * Arguments: 1740c1c61f44Ssb155480 * arg: device argument(vsw device or a port) 1741c1c61f44Ssb155480 * type: type of arg; VSW_LOCALDEV(vsw device) or VSW_VNETPORT(port) 1742c1c61f44Ssb155480 * mdp: machine description 1743c1c61f44Ssb155480 * node: md node cookie 1744c1c61f44Ssb155480 * 1745c1c61f44Ssb155480 * Returns: 1746c1c61f44Ssb155480 * pvidp: port-vlan-id of the node 1747c1c61f44Ssb155480 * vidspp: list of vlan-ids of the node 1748c1c61f44Ssb155480 * nvidsp: # of vlan-ids in the list 1749c1c61f44Ssb155480 * default_idp: default-vlan-id of the node(if node is vsw device) 1750c1c61f44Ssb155480 */ 1751c1c61f44Ssb155480 static void 1752c1c61f44Ssb155480 vsw_vlan_read_ids(void *arg, int type, md_t *mdp, mde_cookie_t node, 1753da14cebeSEric Cheng uint16_t *pvidp, vsw_vlanid_t **vidspp, uint16_t *nvidsp, 1754c1c61f44Ssb155480 uint16_t *default_idp) 1755c1c61f44Ssb155480 { 1756c1c61f44Ssb155480 vsw_t *vswp; 1757c1c61f44Ssb155480 vsw_port_t *portp; 1758c1c61f44Ssb155480 char *pvid_propname; 1759c1c61f44Ssb155480 char *vid_propname; 1760c1c61f44Ssb155480 uint_t nvids = 0; 1761c1c61f44Ssb155480 uint32_t vids_size; 1762c1c61f44Ssb155480 int rv; 1763c1c61f44Ssb155480 int i; 1764c1c61f44Ssb155480 uint64_t *data; 1765c1c61f44Ssb155480 uint64_t val; 1766c1c61f44Ssb155480 int size; 1767c1c61f44Ssb155480 int inst; 1768c1c61f44Ssb155480 1769c1c61f44Ssb155480 if (type == VSW_LOCALDEV) { 1770c1c61f44Ssb155480 1771c1c61f44Ssb155480 vswp = (vsw_t *)arg; 1772c1c61f44Ssb155480 pvid_propname = vsw_pvid_propname; 1773c1c61f44Ssb155480 vid_propname = vsw_vid_propname; 1774c1c61f44Ssb155480 inst = vswp->instance; 1775c1c61f44Ssb155480 1776c1c61f44Ssb155480 } else if (type == VSW_VNETPORT) { 1777c1c61f44Ssb155480 1778c1c61f44Ssb155480 portp = (vsw_port_t *)arg; 1779c1c61f44Ssb155480 vswp = portp->p_vswp; 1780c1c61f44Ssb155480 pvid_propname = port_pvid_propname; 1781c1c61f44Ssb155480 vid_propname = port_vid_propname; 1782c1c61f44Ssb155480 inst = portp->p_instance; 1783c1c61f44Ssb155480 1784c1c61f44Ssb155480 } else { 1785c1c61f44Ssb155480 return; 1786c1c61f44Ssb155480 } 1787c1c61f44Ssb155480 1788c1c61f44Ssb155480 if (type == VSW_LOCALDEV && default_idp != NULL) { 1789c1c61f44Ssb155480 rv = md_get_prop_val(mdp, node, vsw_dvid_propname, &val); 1790c1c61f44Ssb155480 if (rv != 0) { 1791c1c61f44Ssb155480 DWARN(vswp, "%s: prop(%s) not found", __func__, 1792c1c61f44Ssb155480 vsw_dvid_propname); 1793c1c61f44Ssb155480 1794c1c61f44Ssb155480 *default_idp = vsw_default_vlan_id; 1795c1c61f44Ssb155480 } else { 1796c1c61f44Ssb155480 *default_idp = val & 0xFFF; 1797c1c61f44Ssb155480 D2(vswp, "%s: %s(%d): (%d)\n", __func__, 1798c1c61f44Ssb155480 vsw_dvid_propname, inst, *default_idp); 1799c1c61f44Ssb155480 } 1800c1c61f44Ssb155480 } 1801c1c61f44Ssb155480 1802c1c61f44Ssb155480 rv = md_get_prop_val(mdp, node, pvid_propname, &val); 1803c1c61f44Ssb155480 if (rv != 0) { 1804c1c61f44Ssb155480 DWARN(vswp, "%s: prop(%s) not found", __func__, pvid_propname); 1805c1c61f44Ssb155480 *pvidp = vsw_default_vlan_id; 1806c1c61f44Ssb155480 } else { 1807c1c61f44Ssb155480 1808c1c61f44Ssb155480 *pvidp = val & 0xFFF; 1809c1c61f44Ssb155480 D2(vswp, "%s: %s(%d): (%d)\n", __func__, 1810c1c61f44Ssb155480 pvid_propname, inst, *pvidp); 1811c1c61f44Ssb155480 } 1812c1c61f44Ssb155480 1813c1c61f44Ssb155480 rv = md_get_prop_data(mdp, node, vid_propname, (uint8_t **)&data, 1814c1c61f44Ssb155480 &size); 1815c1c61f44Ssb155480 if (rv != 0) { 1816c1c61f44Ssb155480 D2(vswp, "%s: prop(%s) not found", __func__, vid_propname); 1817c1c61f44Ssb155480 size = 0; 1818c1c61f44Ssb155480 } else { 1819c1c61f44Ssb155480 size /= sizeof (uint64_t); 1820c1c61f44Ssb155480 } 1821c1c61f44Ssb155480 nvids = size; 1822c1c61f44Ssb155480 1823c1c61f44Ssb155480 if (nvids != 0) { 1824c1c61f44Ssb155480 D2(vswp, "%s: %s(%d): ", __func__, vid_propname, inst); 1825da14cebeSEric Cheng vids_size = sizeof (vsw_vlanid_t) * nvids; 1826c1c61f44Ssb155480 *vidspp = kmem_zalloc(vids_size, KM_SLEEP); 1827c1c61f44Ssb155480 for (i = 0; i < nvids; i++) { 1828da14cebeSEric Cheng (*vidspp)[i].vl_vid = data[i] & 0xFFFF; 1829da14cebeSEric Cheng (*vidspp)[i].vl_set = B_FALSE; 1830da14cebeSEric Cheng D2(vswp, " %d ", (*vidspp)[i].vl_vid); 1831c1c61f44Ssb155480 } 1832c1c61f44Ssb155480 D2(vswp, "\n"); 1833c1c61f44Ssb155480 } 1834c1c61f44Ssb155480 1835c1c61f44Ssb155480 *nvidsp = nvids; 1836c1c61f44Ssb155480 } 1837c1c61f44Ssb155480 1838c1c61f44Ssb155480 /* 1839f0ca1d9aSsb155480 * This function reads "priority-ether-types" property from md. This property 1840f0ca1d9aSsb155480 * is used to enable support for priority frames. Applications which need 1841f0ca1d9aSsb155480 * guaranteed and timely delivery of certain high priority frames to/from 1842f0ca1d9aSsb155480 * a vnet or vsw within ldoms, should configure this property by providing 1843f0ca1d9aSsb155480 * the ether type(s) for which the priority facility is needed. 1844f0ca1d9aSsb155480 * Normal data frames are delivered over a ldc channel using the descriptor 1845f0ca1d9aSsb155480 * ring mechanism which is constrained by factors such as descriptor ring size, 1846f0ca1d9aSsb155480 * the rate at which the ring is processed at the peer ldc end point, etc. 1847f0ca1d9aSsb155480 * The priority mechanism provides an Out-Of-Band path to send/receive frames 1848f0ca1d9aSsb155480 * as raw pkt data (VIO_PKT_DATA) messages over the channel, avoiding the 1849f0ca1d9aSsb155480 * descriptor ring path and enables a more reliable and timely delivery of 1850f0ca1d9aSsb155480 * frames to the peer. 1851f0ca1d9aSsb155480 */ 1852f0ca1d9aSsb155480 static void 1853f0ca1d9aSsb155480 vsw_read_pri_eth_types(vsw_t *vswp, md_t *mdp, mde_cookie_t node) 1854f0ca1d9aSsb155480 { 1855f0ca1d9aSsb155480 int rv; 1856f0ca1d9aSsb155480 uint16_t *types; 1857f0ca1d9aSsb155480 uint64_t *data; 1858f0ca1d9aSsb155480 int size; 1859f0ca1d9aSsb155480 int i; 1860f0ca1d9aSsb155480 size_t mblk_sz; 1861f0ca1d9aSsb155480 1862f0ca1d9aSsb155480 rv = md_get_prop_data(mdp, node, pri_types_propname, 1863f0ca1d9aSsb155480 (uint8_t **)&data, &size); 1864f0ca1d9aSsb155480 if (rv != 0) { 1865f0ca1d9aSsb155480 /* 1866f0ca1d9aSsb155480 * Property may not exist if we are running pre-ldoms1.1 f/w. 1867f0ca1d9aSsb155480 * Check if 'vsw_pri_eth_type' has been set in that case. 1868f0ca1d9aSsb155480 */ 1869f0ca1d9aSsb155480 if (vsw_pri_eth_type != 0) { 1870f0ca1d9aSsb155480 size = sizeof (vsw_pri_eth_type); 1871f0ca1d9aSsb155480 data = &vsw_pri_eth_type; 1872f0ca1d9aSsb155480 } else { 1873f0ca1d9aSsb155480 D3(vswp, "%s: prop(%s) not found", __func__, 1874f0ca1d9aSsb155480 pri_types_propname); 1875f0ca1d9aSsb155480 size = 0; 1876f0ca1d9aSsb155480 } 1877f0ca1d9aSsb155480 } 1878f0ca1d9aSsb155480 1879f0ca1d9aSsb155480 if (size == 0) { 1880f0ca1d9aSsb155480 vswp->pri_num_types = 0; 1881f0ca1d9aSsb155480 return; 1882f0ca1d9aSsb155480 } 1883f0ca1d9aSsb155480 1884f0ca1d9aSsb155480 /* 1885f0ca1d9aSsb155480 * we have some priority-ether-types defined; 1886f0ca1d9aSsb155480 * allocate a table of these types and also 1887f0ca1d9aSsb155480 * allocate a pool of mblks to transmit these 1888f0ca1d9aSsb155480 * priority packets. 1889f0ca1d9aSsb155480 */ 1890f0ca1d9aSsb155480 size /= sizeof (uint64_t); 1891f0ca1d9aSsb155480 vswp->pri_num_types = size; 1892f0ca1d9aSsb155480 vswp->pri_types = kmem_zalloc(size * sizeof (uint16_t), KM_SLEEP); 1893f0ca1d9aSsb155480 for (i = 0, types = vswp->pri_types; i < size; i++) { 1894f0ca1d9aSsb155480 types[i] = data[i] & 0xFFFF; 1895f0ca1d9aSsb155480 } 1896f0ca1d9aSsb155480 mblk_sz = (VIO_PKT_DATA_HDRSIZE + ETHERMAX + 7) & ~7; 1897f0ca1d9aSsb155480 (void) vio_create_mblks(vsw_pri_tx_nmblks, mblk_sz, &vswp->pri_tx_vmp); 1898f0ca1d9aSsb155480 } 1899f0ca1d9aSsb155480 19007b1f684aSSriharsha Basavapatna static void 19017b1f684aSSriharsha Basavapatna vsw_mtu_read(vsw_t *vswp, md_t *mdp, mde_cookie_t node, uint32_t *mtu) 19027b1f684aSSriharsha Basavapatna { 19037b1f684aSSriharsha Basavapatna int rv; 19047b1f684aSSriharsha Basavapatna int inst; 19057b1f684aSSriharsha Basavapatna uint64_t val; 19067b1f684aSSriharsha Basavapatna char *mtu_propname; 19077b1f684aSSriharsha Basavapatna 19087b1f684aSSriharsha Basavapatna mtu_propname = vsw_mtu_propname; 19097b1f684aSSriharsha Basavapatna inst = vswp->instance; 19107b1f684aSSriharsha Basavapatna 19117b1f684aSSriharsha Basavapatna rv = md_get_prop_val(mdp, node, mtu_propname, &val); 19127b1f684aSSriharsha Basavapatna if (rv != 0) { 19137b1f684aSSriharsha Basavapatna D3(vswp, "%s: prop(%s) not found", __func__, mtu_propname); 19147b1f684aSSriharsha Basavapatna *mtu = vsw_ethermtu; 19157b1f684aSSriharsha Basavapatna } else { 19167b1f684aSSriharsha Basavapatna 19177b1f684aSSriharsha Basavapatna *mtu = val & 0xFFFF; 19187b1f684aSSriharsha Basavapatna D2(vswp, "%s: %s(%d): (%d)\n", __func__, 19197b1f684aSSriharsha Basavapatna mtu_propname, inst, *mtu); 19207b1f684aSSriharsha Basavapatna } 19217b1f684aSSriharsha Basavapatna } 19227b1f684aSSriharsha Basavapatna 19237b1f684aSSriharsha Basavapatna /* 19247b1f684aSSriharsha Basavapatna * Update the mtu of the vsw device. We first check if the device has been 19257b1f684aSSriharsha Basavapatna * plumbed and if so fail the mtu update. Otherwise, we continue to update the 19267b1f684aSSriharsha Basavapatna * new mtu and reset all ports to initiate handshake re-negotiation with peers 19277b1f684aSSriharsha Basavapatna * using the new mtu. 19287b1f684aSSriharsha Basavapatna */ 19297b1f684aSSriharsha Basavapatna static int 19307b1f684aSSriharsha Basavapatna vsw_mtu_update(vsw_t *vswp, uint32_t mtu) 19317b1f684aSSriharsha Basavapatna { 19327b1f684aSSriharsha Basavapatna int rv; 19337b1f684aSSriharsha Basavapatna 19347b1f684aSSriharsha Basavapatna WRITE_ENTER(&vswp->if_lockrw); 19357b1f684aSSriharsha Basavapatna 19367b1f684aSSriharsha Basavapatna if (vswp->if_state & VSW_IF_UP) { 19377b1f684aSSriharsha Basavapatna 19387b1f684aSSriharsha Basavapatna RW_EXIT(&vswp->if_lockrw); 19397b1f684aSSriharsha Basavapatna 19407b1f684aSSriharsha Basavapatna cmn_err(CE_NOTE, "!vsw%d: Unable to process mtu update" 19417b1f684aSSriharsha Basavapatna " as the device is plumbed\n", vswp->instance); 19427b1f684aSSriharsha Basavapatna return (EBUSY); 19437b1f684aSSriharsha Basavapatna 19447b1f684aSSriharsha Basavapatna } else { 19457b1f684aSSriharsha Basavapatna 19467b1f684aSSriharsha Basavapatna D2(vswp, "%s: curr_mtu(%d) new_mtu(%d)\n", 19477b1f684aSSriharsha Basavapatna __func__, vswp->mtu, mtu); 19487b1f684aSSriharsha Basavapatna 19497b1f684aSSriharsha Basavapatna vswp->mtu = mtu; 19507b1f684aSSriharsha Basavapatna vswp->max_frame_size = vswp->mtu + 19517b1f684aSSriharsha Basavapatna sizeof (struct ether_header) + VLAN_TAGSZ; 19527b1f684aSSriharsha Basavapatna 19537b1f684aSSriharsha Basavapatna rv = mac_maxsdu_update(vswp->if_mh, mtu); 19547b1f684aSSriharsha Basavapatna if (rv != 0) { 19557b1f684aSSriharsha Basavapatna cmn_err(CE_NOTE, 19567b1f684aSSriharsha Basavapatna "!vsw%d: Unable to update mtu with mac" 19577b1f684aSSriharsha Basavapatna " layer\n", vswp->instance); 19587b1f684aSSriharsha Basavapatna } 19597b1f684aSSriharsha Basavapatna 19607b1f684aSSriharsha Basavapatna RW_EXIT(&vswp->if_lockrw); 19617b1f684aSSriharsha Basavapatna 19627b1f684aSSriharsha Basavapatna /* Reset ports to renegotiate with the new mtu */ 19637b1f684aSSriharsha Basavapatna vsw_reset_ports(vswp); 19647b1f684aSSriharsha Basavapatna 19657b1f684aSSriharsha Basavapatna } 19667b1f684aSSriharsha Basavapatna 19677b1f684aSSriharsha Basavapatna return (0); 19687b1f684aSSriharsha Basavapatna } 19697b1f684aSSriharsha Basavapatna 1970*1107ea93SSriharsha Basavapatna static void 1971*1107ea93SSriharsha Basavapatna vsw_linkprop_read(vsw_t *vswp, md_t *mdp, mde_cookie_t node, 1972*1107ea93SSriharsha Basavapatna boolean_t *pls) 1973*1107ea93SSriharsha Basavapatna { 1974*1107ea93SSriharsha Basavapatna int rv; 1975*1107ea93SSriharsha Basavapatna uint64_t val; 1976*1107ea93SSriharsha Basavapatna char *linkpropname; 1977*1107ea93SSriharsha Basavapatna 1978*1107ea93SSriharsha Basavapatna linkpropname = vsw_linkprop_propname; 1979*1107ea93SSriharsha Basavapatna 1980*1107ea93SSriharsha Basavapatna rv = md_get_prop_val(mdp, node, linkpropname, &val); 1981*1107ea93SSriharsha Basavapatna if (rv != 0) { 1982*1107ea93SSriharsha Basavapatna D3(vswp, "%s: prop(%s) not found", __func__, linkpropname); 1983*1107ea93SSriharsha Basavapatna *pls = B_FALSE; 1984*1107ea93SSriharsha Basavapatna } else { 1985*1107ea93SSriharsha Basavapatna 1986*1107ea93SSriharsha Basavapatna *pls = (val & 0x1) ? B_TRUE : B_FALSE; 1987*1107ea93SSriharsha Basavapatna D2(vswp, "%s: %s(%d): (%d)\n", __func__, linkpropname, 1988*1107ea93SSriharsha Basavapatna vswp->instance, *pls); 1989*1107ea93SSriharsha Basavapatna } 1990*1107ea93SSriharsha Basavapatna } 1991*1107ea93SSriharsha Basavapatna 1992*1107ea93SSriharsha Basavapatna static void 1993*1107ea93SSriharsha Basavapatna vsw_mac_link_update(vsw_t *vswp, link_state_t link_state) 1994*1107ea93SSriharsha Basavapatna { 1995*1107ea93SSriharsha Basavapatna READ_ENTER(&vswp->if_lockrw); 1996*1107ea93SSriharsha Basavapatna if ((vswp->if_state & VSW_IF_UP) == 0) { 1997*1107ea93SSriharsha Basavapatna RW_EXIT(&vswp->if_lockrw); 1998*1107ea93SSriharsha Basavapatna return; 1999*1107ea93SSriharsha Basavapatna } 2000*1107ea93SSriharsha Basavapatna RW_EXIT(&vswp->if_lockrw); 2001*1107ea93SSriharsha Basavapatna 2002*1107ea93SSriharsha Basavapatna mac_link_update(vswp->if_mh, link_state); 2003*1107ea93SSriharsha Basavapatna } 2004*1107ea93SSriharsha Basavapatna 2005*1107ea93SSriharsha Basavapatna void 2006*1107ea93SSriharsha Basavapatna vsw_physlink_state_update(vsw_t *vswp) 2007*1107ea93SSriharsha Basavapatna { 2008*1107ea93SSriharsha Basavapatna if (vswp->pls_update == B_TRUE) { 2009*1107ea93SSriharsha Basavapatna vsw_mac_link_update(vswp, vswp->phys_link_state); 2010*1107ea93SSriharsha Basavapatna } 2011*1107ea93SSriharsha Basavapatna vsw_physlink_update_ports(vswp); 2012*1107ea93SSriharsha Basavapatna } 2013*1107ea93SSriharsha Basavapatna 2014f0ca1d9aSsb155480 /* 201534683adeSsg70180 * Check to see if the relevant properties in the specified node have 201634683adeSsg70180 * changed, and if so take the appropriate action. 201734683adeSsg70180 * 201834683adeSsg70180 * If any of the properties are missing or invalid we don't take 201934683adeSsg70180 * any action, as this function should only be invoked when modifications 202034683adeSsg70180 * have been made to what we assume is a working configuration, which 202134683adeSsg70180 * we leave active. 202234683adeSsg70180 * 202334683adeSsg70180 * Note it is legal for this routine to be invoked even if none of the 202434683adeSsg70180 * properties in the port node within the MD have actually changed. 202534683adeSsg70180 */ 202634683adeSsg70180 static void 202734683adeSsg70180 vsw_update_md_prop(vsw_t *vswp, md_t *mdp, mde_cookie_t node) 202834683adeSsg70180 { 202934683adeSsg70180 char physname[LIFNAMSIZ]; 203034683adeSsg70180 char drv[LIFNAMSIZ]; 203134683adeSsg70180 uint_t ddi_instance; 2032da14cebeSEric Cheng uint8_t new_smode; 2033da14cebeSEric Cheng int i; 203434683adeSsg70180 uint64_t macaddr = 0; 203534683adeSsg70180 enum {MD_init = 0x1, 203634683adeSsg70180 MD_physname = 0x2, 203734683adeSsg70180 MD_macaddr = 0x4, 2038c1c61f44Ssb155480 MD_smode = 0x8, 20397b1f684aSSriharsha Basavapatna MD_vlans = 0x10, 2040*1107ea93SSriharsha Basavapatna MD_mtu = 0x20, 2041*1107ea93SSriharsha Basavapatna MD_pls = 0x40} updated; 204219b65a69Ssb155480 int rv; 2043c1c61f44Ssb155480 uint16_t pvid; 2044da14cebeSEric Cheng vsw_vlanid_t *vids; 2045c1c61f44Ssb155480 uint16_t nvids; 20467b1f684aSSriharsha Basavapatna uint32_t mtu; 2047*1107ea93SSriharsha Basavapatna boolean_t pls_update; 204834683adeSsg70180 204934683adeSsg70180 updated = MD_init; 205034683adeSsg70180 205134683adeSsg70180 D1(vswp, "%s: enter", __func__); 205234683adeSsg70180 205334683adeSsg70180 /* 205434683adeSsg70180 * Check if name of physical device in MD has changed. 205534683adeSsg70180 */ 205634683adeSsg70180 if (vsw_get_md_physname(vswp, mdp, node, (char *)&physname) == 0) { 205734683adeSsg70180 /* 205834683adeSsg70180 * Do basic sanity check on new device name/instance, 205934683adeSsg70180 * if its non NULL. It is valid for the device name to 206034683adeSsg70180 * have changed from a non NULL to a NULL value, i.e. 206134683adeSsg70180 * the vsw is being changed to 'routed' mode. 206234683adeSsg70180 */ 206334683adeSsg70180 if ((strlen(physname) != 0) && 206419b65a69Ssb155480 (ddi_parse(physname, drv, 206519b65a69Ssb155480 &ddi_instance) != DDI_SUCCESS)) { 20661ef0bbb5Snarayan cmn_err(CE_WARN, "!vsw%d: physical device %s is not" 206734683adeSsg70180 " a valid device name/instance", 206834683adeSsg70180 vswp->instance, physname); 206934683adeSsg70180 goto fail_reconf; 207034683adeSsg70180 } 207134683adeSsg70180 207234683adeSsg70180 if (strcmp(physname, vswp->physname)) { 207334683adeSsg70180 D2(vswp, "%s: device name changed from %s to %s", 207434683adeSsg70180 __func__, vswp->physname, physname); 207534683adeSsg70180 207634683adeSsg70180 updated |= MD_physname; 207734683adeSsg70180 } else { 207834683adeSsg70180 D2(vswp, "%s: device name unchanged at %s", 207934683adeSsg70180 __func__, vswp->physname); 208034683adeSsg70180 } 208134683adeSsg70180 } else { 208234683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to read name of physical " 208334683adeSsg70180 "device from updated MD.", vswp->instance); 208434683adeSsg70180 goto fail_reconf; 208534683adeSsg70180 } 208634683adeSsg70180 208734683adeSsg70180 /* 208834683adeSsg70180 * Check if MAC address has changed. 208934683adeSsg70180 */ 209034683adeSsg70180 if (md_get_prop_val(mdp, node, macaddr_propname, &macaddr) != 0) { 209134683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to get MAC address from MD", 209234683adeSsg70180 vswp->instance); 209334683adeSsg70180 goto fail_reconf; 209434683adeSsg70180 } else { 209519b65a69Ssb155480 uint64_t maddr = macaddr; 209634683adeSsg70180 READ_ENTER(&vswp->if_lockrw); 209734683adeSsg70180 for (i = ETHERADDRL - 1; i >= 0; i--) { 209819b65a69Ssb155480 if (vswp->if_addr.ether_addr_octet[i] 209919b65a69Ssb155480 != (macaddr & 0xFF)) { 210034683adeSsg70180 D2(vswp, "%s: octet[%d] 0x%x != 0x%x", 210134683adeSsg70180 __func__, i, 210234683adeSsg70180 vswp->if_addr.ether_addr_octet[i], 210334683adeSsg70180 (macaddr & 0xFF)); 210434683adeSsg70180 updated |= MD_macaddr; 210519b65a69Ssb155480 macaddr = maddr; 210634683adeSsg70180 break; 210734683adeSsg70180 } 210834683adeSsg70180 macaddr >>= 8; 210934683adeSsg70180 } 211034683adeSsg70180 RW_EXIT(&vswp->if_lockrw); 211119b65a69Ssb155480 if (updated & MD_macaddr) { 211219b65a69Ssb155480 vsw_save_lmacaddr(vswp, macaddr); 211319b65a69Ssb155480 } 211434683adeSsg70180 } 211534683adeSsg70180 211634683adeSsg70180 /* 211734683adeSsg70180 * Check if switching modes have changed. 211834683adeSsg70180 */ 2119da14cebeSEric Cheng if (vsw_get_md_smodes(vswp, mdp, node, &new_smode)) { 212034683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to read %s property from MD", 212134683adeSsg70180 vswp->instance, smode_propname); 212234683adeSsg70180 goto fail_reconf; 212334683adeSsg70180 } else { 2124da14cebeSEric Cheng if (new_smode != vswp->smode) { 2125da14cebeSEric Cheng D2(vswp, "%s: switching mode changed from %d to %d", 2126da14cebeSEric Cheng __func__, vswp->smode, new_smode); 212734683adeSsg70180 212834683adeSsg70180 updated |= MD_smode; 212934683adeSsg70180 } 213034683adeSsg70180 } 213134683adeSsg70180 2132c1c61f44Ssb155480 /* Read the vlan ids */ 2133c1c61f44Ssb155480 vsw_vlan_read_ids(vswp, VSW_LOCALDEV, mdp, node, &pvid, &vids, 2134c1c61f44Ssb155480 &nvids, NULL); 2135c1c61f44Ssb155480 2136c1c61f44Ssb155480 /* Determine if there are any vlan id updates */ 2137c1c61f44Ssb155480 if ((pvid != vswp->pvid) || /* pvid changed? */ 2138c1c61f44Ssb155480 (nvids != vswp->nvids) || /* # of vids changed? */ 2139c1c61f44Ssb155480 ((nvids != 0) && (vswp->nvids != 0) && /* vids changed? */ 2140da14cebeSEric Cheng !vsw_cmp_vids(vids, vswp->vids, nvids))) { 2141c1c61f44Ssb155480 updated |= MD_vlans; 2142c1c61f44Ssb155480 } 2143c1c61f44Ssb155480 21447b1f684aSSriharsha Basavapatna /* Read mtu */ 21457b1f684aSSriharsha Basavapatna vsw_mtu_read(vswp, mdp, node, &mtu); 21467b1f684aSSriharsha Basavapatna if (mtu != vswp->mtu) { 21477b1f684aSSriharsha Basavapatna if (mtu >= ETHERMTU && mtu <= VNET_MAX_MTU) { 21487b1f684aSSriharsha Basavapatna updated |= MD_mtu; 21497b1f684aSSriharsha Basavapatna } else { 21507b1f684aSSriharsha Basavapatna cmn_err(CE_NOTE, "!vsw%d: Unable to process mtu update" 21517b1f684aSSriharsha Basavapatna " as the specified value:%d is invalid\n", 21527b1f684aSSriharsha Basavapatna vswp->instance, mtu); 21537b1f684aSSriharsha Basavapatna } 21547b1f684aSSriharsha Basavapatna } 21557b1f684aSSriharsha Basavapatna 215634683adeSsg70180 /* 2157*1107ea93SSriharsha Basavapatna * Read the 'linkprop' property. 2158*1107ea93SSriharsha Basavapatna */ 2159*1107ea93SSriharsha Basavapatna vsw_linkprop_read(vswp, mdp, node, &pls_update); 2160*1107ea93SSriharsha Basavapatna if (pls_update != vswp->pls_update) { 2161*1107ea93SSriharsha Basavapatna updated |= MD_pls; 2162*1107ea93SSriharsha Basavapatna } 2163*1107ea93SSriharsha Basavapatna 2164*1107ea93SSriharsha Basavapatna /* 216534683adeSsg70180 * Now make any changes which are needed... 216634683adeSsg70180 */ 2167*1107ea93SSriharsha Basavapatna if (updated & MD_pls) { 2168*1107ea93SSriharsha Basavapatna 2169*1107ea93SSriharsha Basavapatna /* save the updated property. */ 2170*1107ea93SSriharsha Basavapatna vswp->pls_update = pls_update; 2171*1107ea93SSriharsha Basavapatna 2172*1107ea93SSriharsha Basavapatna if (pls_update == B_FALSE) { 2173*1107ea93SSriharsha Basavapatna /* 2174*1107ea93SSriharsha Basavapatna * Phys link state update is now disabled for this vsw 2175*1107ea93SSriharsha Basavapatna * interface. If we had previously reported a link-down 2176*1107ea93SSriharsha Basavapatna * to the stack, undo that by sending a link-up. 2177*1107ea93SSriharsha Basavapatna */ 2178*1107ea93SSriharsha Basavapatna if (vswp->phys_link_state == LINK_STATE_DOWN) { 2179*1107ea93SSriharsha Basavapatna vsw_mac_link_update(vswp, LINK_STATE_UP); 2180*1107ea93SSriharsha Basavapatna } 2181*1107ea93SSriharsha Basavapatna } else { 2182*1107ea93SSriharsha Basavapatna /* 2183*1107ea93SSriharsha Basavapatna * Phys link state update is now enabled. Send up an 2184*1107ea93SSriharsha Basavapatna * update based on the current phys link state. 2185*1107ea93SSriharsha Basavapatna */ 2186*1107ea93SSriharsha Basavapatna vsw_mac_link_update(vswp, vswp->phys_link_state); 2187*1107ea93SSriharsha Basavapatna } 2188*1107ea93SSriharsha Basavapatna 2189*1107ea93SSriharsha Basavapatna } 219034683adeSsg70180 2191da14cebeSEric Cheng if (updated & (MD_physname | MD_smode | MD_mtu)) { 219234683adeSsg70180 219334683adeSsg70180 /* 2194808f26a8SSriharsha Basavapatna * Stop any pending thread to setup switching mode. 219534683adeSsg70180 */ 2196808f26a8SSriharsha Basavapatna vsw_setup_switching_stop(vswp); 219719b65a69Ssb155480 2198678453a8Sspeer /* Cleanup HybridIO */ 2199678453a8Sspeer vsw_hio_cleanup(vswp); 2200678453a8Sspeer 220119b65a69Ssb155480 /* 220219b65a69Ssb155480 * Remove unicst, mcst addrs of vsw interface 2203da14cebeSEric Cheng * and ports from the physdev. This also closes 2204da14cebeSEric Cheng * the corresponding mac clients. 220519b65a69Ssb155480 */ 220619b65a69Ssb155480 vsw_unset_addrs(vswp); 220719b65a69Ssb155480 220819b65a69Ssb155480 /* 220919b65a69Ssb155480 * Stop, detach and close the old device.. 221019b65a69Ssb155480 */ 2211da14cebeSEric Cheng mutex_enter(&vswp->mac_lock); 221219b65a69Ssb155480 vsw_mac_close(vswp); 2213da14cebeSEric Cheng mutex_exit(&vswp->mac_lock); 221434683adeSsg70180 221534683adeSsg70180 /* 221634683adeSsg70180 * Update phys name. 221734683adeSsg70180 */ 221834683adeSsg70180 if (updated & MD_physname) { 221934683adeSsg70180 cmn_err(CE_NOTE, "!vsw%d: changing from %s to %s", 222034683adeSsg70180 vswp->instance, vswp->physname, physname); 222134683adeSsg70180 (void) strncpy(vswp->physname, 222234683adeSsg70180 physname, strlen(physname) + 1); 222334683adeSsg70180 } 222434683adeSsg70180 222534683adeSsg70180 /* 222634683adeSsg70180 * Update array with the new switch mode values. 222734683adeSsg70180 */ 222834683adeSsg70180 if (updated & MD_smode) { 2229da14cebeSEric Cheng vswp->smode = new_smode; 2230da14cebeSEric Cheng } 223134683adeSsg70180 2232da14cebeSEric Cheng /* Update mtu */ 2233da14cebeSEric Cheng if (updated & MD_mtu) { 2234da14cebeSEric Cheng rv = vsw_mtu_update(vswp, mtu); 2235da14cebeSEric Cheng if (rv != 0) { 2236da14cebeSEric Cheng goto fail_update; 2237da14cebeSEric Cheng } 223834683adeSsg70180 } 223934683adeSsg70180 224034683adeSsg70180 /* 224134683adeSsg70180 * ..and attach, start the new device. 224234683adeSsg70180 */ 224319b65a69Ssb155480 rv = vsw_setup_switching(vswp); 224419b65a69Ssb155480 if (rv == EAGAIN) { 224519b65a69Ssb155480 /* 224619b65a69Ssb155480 * Unable to setup switching mode. 2247808f26a8SSriharsha Basavapatna * As the error is EAGAIN, schedule a thread to retry 224819b65a69Ssb155480 * and return. Programming addresses of ports and 2249808f26a8SSriharsha Basavapatna * vsw interface will be done by the thread when the 2250808f26a8SSriharsha Basavapatna * switching setup completes successfully. 225119b65a69Ssb155480 */ 2252808f26a8SSriharsha Basavapatna if (vsw_setup_switching_start(vswp) != 0) { 2253808f26a8SSriharsha Basavapatna goto fail_update; 2254808f26a8SSriharsha Basavapatna } 225519b65a69Ssb155480 return; 225619b65a69Ssb155480 225719b65a69Ssb155480 } else if (rv) { 225834683adeSsg70180 goto fail_update; 225919b65a69Ssb155480 } 226034683adeSsg70180 226171bdf936SWENTAO YANG vsw_setup_layer2_post_process(vswp); 226219b65a69Ssb155480 } else if (updated & MD_macaddr) { 226319b65a69Ssb155480 /* 226419b65a69Ssb155480 * We enter here if only MD_macaddr is exclusively updated. 226519b65a69Ssb155480 * If MD_physname and/or MD_smode are also updated, then 226619b65a69Ssb155480 * as part of that, we would have implicitly processed 226719b65a69Ssb155480 * MD_macaddr update (above). 226819b65a69Ssb155480 */ 226934683adeSsg70180 cmn_err(CE_NOTE, "!vsw%d: changing mac address to 0x%lx", 227034683adeSsg70180 vswp->instance, macaddr); 227134683adeSsg70180 227219b65a69Ssb155480 READ_ENTER(&vswp->if_lockrw); 227319b65a69Ssb155480 if (vswp->if_state & VSW_IF_UP) { 2274da14cebeSEric Cheng /* reconfigure with new address */ 2275da14cebeSEric Cheng vsw_if_mac_reconfig(vswp, B_FALSE, 0, NULL, 0); 227634683adeSsg70180 22775f94e909Ssg70180 /* 227834683adeSsg70180 * Notify the MAC layer of the changed address. 227934683adeSsg70180 */ 228019b65a69Ssb155480 mac_unicst_update(vswp->if_mh, 228119b65a69Ssb155480 (uint8_t *)&vswp->if_addr); 228219b65a69Ssb155480 228319b65a69Ssb155480 } 228419b65a69Ssb155480 RW_EXIT(&vswp->if_lockrw); 228519b65a69Ssb155480 228634683adeSsg70180 } 228734683adeSsg70180 2288c1c61f44Ssb155480 if (updated & MD_vlans) { 2289c1c61f44Ssb155480 /* Remove existing vlan ids from the hash table. */ 2290c1c61f44Ssb155480 vsw_vlan_remove_ids(vswp, VSW_LOCALDEV); 2291c1c61f44Ssb155480 2292da14cebeSEric Cheng if (vswp->if_state & VSW_IF_UP) { 2293da14cebeSEric Cheng vsw_if_mac_reconfig(vswp, B_TRUE, pvid, vids, nvids); 2294da14cebeSEric Cheng } else { 2295c1c61f44Ssb155480 if (vswp->nvids != 0) { 2296da14cebeSEric Cheng kmem_free(vswp->vids, 2297da14cebeSEric Cheng sizeof (vsw_vlanid_t) * vswp->nvids); 2298c1c61f44Ssb155480 } 2299c1c61f44Ssb155480 vswp->vids = vids; 2300da14cebeSEric Cheng vswp->nvids = nvids; 2301da14cebeSEric Cheng vswp->pvid = pvid; 2302c1c61f44Ssb155480 } 2303c1c61f44Ssb155480 2304c1c61f44Ssb155480 /* add these new vlan ids into hash table */ 2305c1c61f44Ssb155480 vsw_vlan_add_ids(vswp, VSW_LOCALDEV); 2306c1c61f44Ssb155480 } else { 2307c1c61f44Ssb155480 if (nvids != 0) { 2308da14cebeSEric Cheng kmem_free(vids, sizeof (vsw_vlanid_t) * nvids); 2309c1c61f44Ssb155480 } 2310c1c61f44Ssb155480 } 2311c1c61f44Ssb155480 231234683adeSsg70180 return; 231334683adeSsg70180 231434683adeSsg70180 fail_reconf: 231534683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: configuration unchanged", vswp->instance); 231634683adeSsg70180 return; 231734683adeSsg70180 231834683adeSsg70180 fail_update: 23191ef0bbb5Snarayan cmn_err(CE_WARN, "!vsw%d: re-configuration failed", 232034683adeSsg70180 vswp->instance); 232134683adeSsg70180 } 232234683adeSsg70180 232334683adeSsg70180 /* 2324c1c61f44Ssb155480 * Read the port's md properties. 23251ae08745Sheppo */ 2326c1c61f44Ssb155480 static int 2327c1c61f44Ssb155480 vsw_port_read_props(vsw_port_t *portp, vsw_t *vswp, 2328c1c61f44Ssb155480 md_t *mdp, mde_cookie_t *node) 23291ae08745Sheppo { 23301ae08745Sheppo uint64_t ldc_id; 23311ae08745Sheppo uint8_t *addrp; 23321ae08745Sheppo int i, addrsz; 23331ae08745Sheppo int num_nodes = 0, nchan = 0; 23341ae08745Sheppo int listsz = 0; 23351ae08745Sheppo mde_cookie_t *listp = NULL; 23361ae08745Sheppo struct ether_addr ea; 23371ae08745Sheppo uint64_t macaddr; 23381ae08745Sheppo uint64_t inst = 0; 2339678453a8Sspeer uint64_t val; 23401ae08745Sheppo 23411ae08745Sheppo if (md_get_prop_val(mdp, *node, id_propname, &inst)) { 23421ae08745Sheppo DWARN(vswp, "%s: prop(%s) not found", __func__, 23431ae08745Sheppo id_propname); 23441ae08745Sheppo return (1); 23451ae08745Sheppo } 23461ae08745Sheppo 23471ae08745Sheppo /* 23481ae08745Sheppo * Find the channel endpoint node(s) (which should be under this 23491ae08745Sheppo * port node) which contain the channel id(s). 23501ae08745Sheppo */ 23511ae08745Sheppo if ((num_nodes = md_node_count(mdp)) <= 0) { 23521ae08745Sheppo DERR(vswp, "%s: invalid number of nodes found (%d)", 23531ae08745Sheppo __func__, num_nodes); 23541ae08745Sheppo return (1); 23551ae08745Sheppo } 23561ae08745Sheppo 235734683adeSsg70180 D2(vswp, "%s: %d nodes found", __func__, num_nodes); 235834683adeSsg70180 23591ae08745Sheppo /* allocate enough space for node list */ 23601ae08745Sheppo listsz = num_nodes * sizeof (mde_cookie_t); 23611ae08745Sheppo listp = kmem_zalloc(listsz, KM_SLEEP); 23621ae08745Sheppo 2363205eeb1aSlm66018 nchan = md_scan_dag(mdp, *node, md_find_name(mdp, chan_propname), 23641ae08745Sheppo md_find_name(mdp, "fwd"), listp); 23651ae08745Sheppo 23661ae08745Sheppo if (nchan <= 0) { 23671ae08745Sheppo DWARN(vswp, "%s: no %s nodes found", __func__, chan_propname); 23681ae08745Sheppo kmem_free(listp, listsz); 23691ae08745Sheppo return (1); 23701ae08745Sheppo } 23711ae08745Sheppo 23721ae08745Sheppo D2(vswp, "%s: %d %s nodes found", __func__, nchan, chan_propname); 23731ae08745Sheppo 23741ae08745Sheppo /* use property from first node found */ 23751ae08745Sheppo if (md_get_prop_val(mdp, listp[0], id_propname, &ldc_id)) { 23761ae08745Sheppo DWARN(vswp, "%s: prop(%s) not found\n", __func__, 23771ae08745Sheppo id_propname); 23781ae08745Sheppo kmem_free(listp, listsz); 23791ae08745Sheppo return (1); 23801ae08745Sheppo } 23811ae08745Sheppo 23821ae08745Sheppo /* don't need list any more */ 23831ae08745Sheppo kmem_free(listp, listsz); 23841ae08745Sheppo 23851ae08745Sheppo D2(vswp, "%s: ldc_id 0x%llx", __func__, ldc_id); 23861ae08745Sheppo 23871ae08745Sheppo /* read mac-address property */ 23881ae08745Sheppo if (md_get_prop_data(mdp, *node, remaddr_propname, 23891ae08745Sheppo &addrp, &addrsz)) { 23901ae08745Sheppo DWARN(vswp, "%s: prop(%s) not found", 23911ae08745Sheppo __func__, remaddr_propname); 23921ae08745Sheppo return (1); 23931ae08745Sheppo } 23941ae08745Sheppo 23951ae08745Sheppo if (addrsz < ETHERADDRL) { 23961ae08745Sheppo DWARN(vswp, "%s: invalid address size", __func__); 23971ae08745Sheppo return (1); 23981ae08745Sheppo } 23991ae08745Sheppo 24001ae08745Sheppo macaddr = *((uint64_t *)addrp); 24011ae08745Sheppo D2(vswp, "%s: remote mac address 0x%llx", __func__, macaddr); 24021ae08745Sheppo 24031ae08745Sheppo for (i = ETHERADDRL - 1; i >= 0; i--) { 24041ae08745Sheppo ea.ether_addr_octet[i] = macaddr & 0xFF; 24051ae08745Sheppo macaddr >>= 8; 24061ae08745Sheppo } 24071ae08745Sheppo 2408c1c61f44Ssb155480 /* now update all properties into the port */ 2409c1c61f44Ssb155480 portp->p_vswp = vswp; 2410c1c61f44Ssb155480 portp->p_instance = inst; 2411da14cebeSEric Cheng portp->addr_set = B_FALSE; 2412c1c61f44Ssb155480 ether_copy(&ea, &portp->p_macaddr); 2413c1c61f44Ssb155480 if (nchan > VSW_PORT_MAX_LDCS) { 2414c1c61f44Ssb155480 D2(vswp, "%s: using first of %d ldc ids", 2415c1c61f44Ssb155480 __func__, nchan); 2416c1c61f44Ssb155480 nchan = VSW_PORT_MAX_LDCS; 2417c1c61f44Ssb155480 } 2418c1c61f44Ssb155480 portp->num_ldcs = nchan; 2419c1c61f44Ssb155480 portp->ldc_ids = 2420c1c61f44Ssb155480 kmem_zalloc(sizeof (uint64_t) * nchan, KM_SLEEP); 2421c1c61f44Ssb155480 bcopy(&ldc_id, (portp->ldc_ids), sizeof (uint64_t) * nchan); 2422c1c61f44Ssb155480 2423c1c61f44Ssb155480 /* read vlan id properties of this port node */ 2424c1c61f44Ssb155480 vsw_vlan_read_ids(portp, VSW_VNETPORT, mdp, *node, &portp->pvid, 2425c1c61f44Ssb155480 &portp->vids, &portp->nvids, NULL); 2426c1c61f44Ssb155480 2427678453a8Sspeer /* Check if hybrid property is present */ 2428678453a8Sspeer if (md_get_prop_val(mdp, *node, hybrid_propname, &val) == 0) { 2429678453a8Sspeer D1(vswp, "%s: prop(%s) found\n", __func__, hybrid_propname); 2430678453a8Sspeer portp->p_hio_enabled = B_TRUE; 2431678453a8Sspeer } else { 2432678453a8Sspeer portp->p_hio_enabled = B_FALSE; 2433678453a8Sspeer } 2434678453a8Sspeer /* 2435678453a8Sspeer * Port hio capability determined after version 2436678453a8Sspeer * negotiation, i.e., when we know the peer is HybridIO capable. 2437678453a8Sspeer */ 2438678453a8Sspeer portp->p_hio_capable = B_FALSE; 2439c1c61f44Ssb155480 return (0); 2440c1c61f44Ssb155480 } 2441c1c61f44Ssb155480 2442c1c61f44Ssb155480 /* 2443c1c61f44Ssb155480 * Add a new port to the system. 2444c1c61f44Ssb155480 * 2445c1c61f44Ssb155480 * Returns 0 on success, 1 on failure. 2446c1c61f44Ssb155480 */ 2447c1c61f44Ssb155480 int 2448c1c61f44Ssb155480 vsw_port_add(vsw_t *vswp, md_t *mdp, mde_cookie_t *node) 2449c1c61f44Ssb155480 { 2450c1c61f44Ssb155480 vsw_port_t *portp; 2451c1c61f44Ssb155480 int rv; 2452c1c61f44Ssb155480 2453c1c61f44Ssb155480 portp = kmem_zalloc(sizeof (vsw_port_t), KM_SLEEP); 2454c1c61f44Ssb155480 2455c1c61f44Ssb155480 rv = vsw_port_read_props(portp, vswp, mdp, node); 2456c1c61f44Ssb155480 if (rv != 0) { 2457c1c61f44Ssb155480 kmem_free(portp, sizeof (*portp)); 2458c1c61f44Ssb155480 return (1); 2459c1c61f44Ssb155480 } 2460c1c61f44Ssb155480 2461c1c61f44Ssb155480 rv = vsw_port_attach(portp); 2462c1c61f44Ssb155480 if (rv != 0) { 24631ae08745Sheppo DERR(vswp, "%s: failed to attach port", __func__); 24641ae08745Sheppo return (1); 24651ae08745Sheppo } 24661ae08745Sheppo 2467c1c61f44Ssb155480 return (0); 2468c1c61f44Ssb155480 } 24691ae08745Sheppo 2470c1c61f44Ssb155480 static int 2471c1c61f44Ssb155480 vsw_port_update(vsw_t *vswp, md_t *curr_mdp, mde_cookie_t curr_mdex, 2472c1c61f44Ssb155480 md_t *prev_mdp, mde_cookie_t prev_mdex) 2473c1c61f44Ssb155480 { 2474c1c61f44Ssb155480 uint64_t cport_num; 2475c1c61f44Ssb155480 uint64_t pport_num; 2476c1c61f44Ssb155480 vsw_port_list_t *plistp; 2477c1c61f44Ssb155480 vsw_port_t *portp; 2478c1c61f44Ssb155480 boolean_t updated_vlans = B_FALSE; 2479c1c61f44Ssb155480 uint16_t pvid; 2480da14cebeSEric Cheng vsw_vlanid_t *vids; 2481c1c61f44Ssb155480 uint16_t nvids; 2482678453a8Sspeer uint64_t val; 2483678453a8Sspeer boolean_t hio_enabled = B_FALSE; 2484c1c61f44Ssb155480 2485c1c61f44Ssb155480 /* 2486c1c61f44Ssb155480 * For now, we get port updates only if vlan ids changed. 2487c1c61f44Ssb155480 * We read the port num and do some sanity check. 2488c1c61f44Ssb155480 */ 2489c1c61f44Ssb155480 if (md_get_prop_val(curr_mdp, curr_mdex, id_propname, &cport_num)) { 2490c1c61f44Ssb155480 return (1); 2491c1c61f44Ssb155480 } 2492c1c61f44Ssb155480 2493c1c61f44Ssb155480 if (md_get_prop_val(prev_mdp, prev_mdex, id_propname, &pport_num)) { 2494c1c61f44Ssb155480 return (1); 2495c1c61f44Ssb155480 } 2496c1c61f44Ssb155480 if (cport_num != pport_num) 2497c1c61f44Ssb155480 return (1); 2498c1c61f44Ssb155480 2499c1c61f44Ssb155480 plistp = &(vswp->plist); 2500c1c61f44Ssb155480 2501c1c61f44Ssb155480 READ_ENTER(&plistp->lockrw); 2502c1c61f44Ssb155480 2503c1c61f44Ssb155480 portp = vsw_lookup_port(vswp, cport_num); 2504c1c61f44Ssb155480 if (portp == NULL) { 2505c1c61f44Ssb155480 RW_EXIT(&plistp->lockrw); 2506c1c61f44Ssb155480 return (1); 2507c1c61f44Ssb155480 } 2508c1c61f44Ssb155480 2509c1c61f44Ssb155480 /* Read the vlan ids */ 2510c1c61f44Ssb155480 vsw_vlan_read_ids(portp, VSW_VNETPORT, curr_mdp, curr_mdex, &pvid, 2511c1c61f44Ssb155480 &vids, &nvids, NULL); 2512c1c61f44Ssb155480 2513c1c61f44Ssb155480 /* Determine if there are any vlan id updates */ 2514c1c61f44Ssb155480 if ((pvid != portp->pvid) || /* pvid changed? */ 2515c1c61f44Ssb155480 (nvids != portp->nvids) || /* # of vids changed? */ 2516c1c61f44Ssb155480 ((nvids != 0) && (portp->nvids != 0) && /* vids changed? */ 2517da14cebeSEric Cheng !vsw_cmp_vids(vids, portp->vids, nvids))) { 2518c1c61f44Ssb155480 updated_vlans = B_TRUE; 2519c1c61f44Ssb155480 } 2520c1c61f44Ssb155480 2521678453a8Sspeer if (updated_vlans == B_TRUE) { 2522c1c61f44Ssb155480 2523c1c61f44Ssb155480 /* Remove existing vlan ids from the hash table. */ 2524c1c61f44Ssb155480 vsw_vlan_remove_ids(portp, VSW_VNETPORT); 2525c1c61f44Ssb155480 2526da14cebeSEric Cheng /* Reconfigure vlans with network device */ 2527da14cebeSEric Cheng vsw_mac_port_reconfig_vlans(portp, pvid, vids, nvids); 2528c1c61f44Ssb155480 2529c1c61f44Ssb155480 /* add these new vlan ids into hash table */ 2530c1c61f44Ssb155480 vsw_vlan_add_ids(portp, VSW_VNETPORT); 2531c1c61f44Ssb155480 2532c1c61f44Ssb155480 /* reset the port if it is vlan unaware (ver < 1.3) */ 2533c1c61f44Ssb155480 vsw_vlan_unaware_port_reset(portp); 2534678453a8Sspeer } 2535678453a8Sspeer 2536678453a8Sspeer /* Check if hybrid property is present */ 2537678453a8Sspeer if (md_get_prop_val(curr_mdp, curr_mdex, hybrid_propname, &val) == 0) { 2538678453a8Sspeer D1(vswp, "%s: prop(%s) found\n", __func__, hybrid_propname); 2539678453a8Sspeer hio_enabled = B_TRUE; 2540678453a8Sspeer } 2541678453a8Sspeer 2542678453a8Sspeer if (portp->p_hio_enabled != hio_enabled) { 2543678453a8Sspeer vsw_hio_port_update(portp, hio_enabled); 2544678453a8Sspeer } 2545c1c61f44Ssb155480 2546c1c61f44Ssb155480 RW_EXIT(&plistp->lockrw); 25471ae08745Sheppo 25481ae08745Sheppo return (0); 25491ae08745Sheppo } 25501ae08745Sheppo 25511ae08745Sheppo /* 255206db247cSraghuram * vsw_mac_rx -- A common function to send packets to the interface. 255306db247cSraghuram * By default this function check if the interface is UP or not, the 255406db247cSraghuram * rest of the behaviour depends on the flags as below: 25551ae08745Sheppo * 255606db247cSraghuram * VSW_MACRX_PROMISC -- Check if the promisc mode set or not. 255706db247cSraghuram * VSW_MACRX_COPYMSG -- Make a copy of the message(s). 255806db247cSraghuram * VSW_MACRX_FREEMSG -- Free if the messages cannot be sent up the stack. 25591ae08745Sheppo */ 25601ae08745Sheppo void 2561f0ca1d9aSsb155480 vsw_mac_rx(vsw_t *vswp, mac_resource_handle_t mrh, 2562f0ca1d9aSsb155480 mblk_t *mp, vsw_macrx_flags_t flags) 25631ae08745Sheppo { 2564c1c61f44Ssb155480 mblk_t *mpt; 2565c1c61f44Ssb155480 256606db247cSraghuram D1(vswp, "%s:enter\n", __func__); 25671ae08745Sheppo READ_ENTER(&vswp->if_lockrw); 256806db247cSraghuram /* Check if the interface is up */ 256906db247cSraghuram if (!(vswp->if_state & VSW_IF_UP)) { 25701ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 257106db247cSraghuram /* Free messages only if FREEMSG flag specified */ 257206db247cSraghuram if (flags & VSW_MACRX_FREEMSG) { 257306db247cSraghuram freemsgchain(mp); 257406db247cSraghuram } 257506db247cSraghuram D1(vswp, "%s:exit\n", __func__); 257606db247cSraghuram return; 257706db247cSraghuram } 257806db247cSraghuram /* 257906db247cSraghuram * If PROMISC flag is passed, then check if 258006db247cSraghuram * the interface is in the PROMISC mode. 258106db247cSraghuram * If not, drop the messages. 258206db247cSraghuram */ 258306db247cSraghuram if (flags & VSW_MACRX_PROMISC) { 258406db247cSraghuram if (!(vswp->if_state & VSW_IF_PROMISC)) { 258506db247cSraghuram RW_EXIT(&vswp->if_lockrw); 258606db247cSraghuram /* Free messages only if FREEMSG flag specified */ 258706db247cSraghuram if (flags & VSW_MACRX_FREEMSG) { 258806db247cSraghuram freemsgchain(mp); 258906db247cSraghuram } 259006db247cSraghuram D1(vswp, "%s:exit\n", __func__); 259106db247cSraghuram return; 259206db247cSraghuram } 259306db247cSraghuram } 259406db247cSraghuram RW_EXIT(&vswp->if_lockrw); 259506db247cSraghuram /* 259606db247cSraghuram * If COPYMSG flag is passed, then make a copy 259706db247cSraghuram * of the message chain and send up the copy. 259806db247cSraghuram */ 259906db247cSraghuram if (flags & VSW_MACRX_COPYMSG) { 260006db247cSraghuram mp = copymsgchain(mp); 2601f0ca1d9aSsb155480 if (mp == NULL) { 260206db247cSraghuram D1(vswp, "%s:exit\n", __func__); 260306db247cSraghuram return; 260406db247cSraghuram } 260506db247cSraghuram } 260606db247cSraghuram 2607f0ca1d9aSsb155480 D2(vswp, "%s: sending up stack", __func__); 2608c1c61f44Ssb155480 2609c1c61f44Ssb155480 mpt = NULL; 2610c1c61f44Ssb155480 (void) vsw_vlan_frame_untag(vswp, VSW_LOCALDEV, &mp, &mpt); 2611c1c61f44Ssb155480 if (mp != NULL) { 2612ba2e4443Sseb mac_rx(vswp->if_mh, mrh, mp); 2613c1c61f44Ssb155480 } 261406db247cSraghuram D1(vswp, "%s:exit\n", __func__); 26151ae08745Sheppo } 26161ae08745Sheppo 261706db247cSraghuram /* copy mac address of vsw into soft state structure */ 26181ae08745Sheppo static void 261906db247cSraghuram vsw_save_lmacaddr(vsw_t *vswp, uint64_t macaddr) 26201ae08745Sheppo { 26211ae08745Sheppo int i; 26221ae08745Sheppo 262306db247cSraghuram WRITE_ENTER(&vswp->if_lockrw); 262406db247cSraghuram for (i = ETHERADDRL - 1; i >= 0; i--) { 262506db247cSraghuram vswp->if_addr.ether_addr_octet[i] = macaddr & 0xFF; 262606db247cSraghuram macaddr >>= 8; 26271ae08745Sheppo } 262806db247cSraghuram RW_EXIT(&vswp->if_lockrw); 26291ae08745Sheppo } 2630da14cebeSEric Cheng 2631da14cebeSEric Cheng /* Compare VLAN ids, array size expected to be same. */ 2632da14cebeSEric Cheng static boolean_t 2633da14cebeSEric Cheng vsw_cmp_vids(vsw_vlanid_t *vids1, vsw_vlanid_t *vids2, int nvids) 2634da14cebeSEric Cheng { 2635da14cebeSEric Cheng int i, j; 2636da14cebeSEric Cheng uint16_t vid; 2637da14cebeSEric Cheng 2638da14cebeSEric Cheng for (i = 0; i < nvids; i++) { 2639da14cebeSEric Cheng vid = vids1[i].vl_vid; 2640da14cebeSEric Cheng for (j = 0; j < nvids; j++) { 2641da14cebeSEric Cheng if (vid == vids2[i].vl_vid) 2642da14cebeSEric Cheng break; 2643da14cebeSEric Cheng } 2644da14cebeSEric Cheng if (j == nvids) { 2645da14cebeSEric Cheng return (B_FALSE); 2646da14cebeSEric Cheng } 2647da14cebeSEric Cheng } 2648da14cebeSEric Cheng return (B_TRUE); 2649da14cebeSEric Cheng } 2650