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 /* 230dc2366fSVenugopal Iyer * Copyright 2010 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 *); 8334b64c01SWENTAO YANG void vsw_destroy_rxpools(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); 95bce0a86eSWENTAO YANG static void vsw_port_read_bandwidth(vsw_port_t *portp, md_t *mdp, 96bce0a86eSWENTAO YANG mde_cookie_t node, uint64_t *bw); 97c1c61f44Ssb155480 static int vsw_port_read_props(vsw_port_t *portp, vsw_t *vswp, 98c1c61f44Ssb155480 md_t *mdp, mde_cookie_t *node); 99f0ca1d9aSsb155480 static void vsw_read_pri_eth_types(vsw_t *vswp, md_t *mdp, 100f0ca1d9aSsb155480 mde_cookie_t node); 1017b1f684aSSriharsha Basavapatna static void vsw_mtu_read(vsw_t *vswp, md_t *mdp, mde_cookie_t node, 1027b1f684aSSriharsha Basavapatna uint32_t *mtu); 1037b1f684aSSriharsha Basavapatna static int vsw_mtu_update(vsw_t *vswp, uint32_t mtu); 1041107ea93SSriharsha Basavapatna static void vsw_linkprop_read(vsw_t *vswp, md_t *mdp, mde_cookie_t node, 1051107ea93SSriharsha Basavapatna boolean_t *pls); 106bce0a86eSWENTAO YANG static void vsw_bandwidth_read(vsw_t *vswp, md_t *mdp, mde_cookie_t node, 107bce0a86eSWENTAO YANG uint64_t *bw); 10834683adeSsg70180 static void vsw_update_md_prop(vsw_t *, md_t *, mde_cookie_t); 10919b65a69Ssb155480 static void vsw_save_lmacaddr(vsw_t *vswp, uint64_t macaddr); 110da14cebeSEric Cheng static boolean_t vsw_cmp_vids(vsw_vlanid_t *vids1, 111da14cebeSEric Cheng vsw_vlanid_t *vids2, int nvids); 1121ae08745Sheppo 11306db247cSraghuram /* Mac driver related routines */ 11406db247cSraghuram static int vsw_mac_register(vsw_t *); 11506db247cSraghuram static int vsw_mac_unregister(vsw_t *); 11606db247cSraghuram static int vsw_m_stat(void *, uint_t, uint64_t *); 11706db247cSraghuram static void vsw_m_stop(void *arg); 11806db247cSraghuram static int vsw_m_start(void *arg); 11906db247cSraghuram static int vsw_m_unicst(void *arg, const uint8_t *); 12006db247cSraghuram static int vsw_m_multicst(void *arg, boolean_t, const uint8_t *); 12106db247cSraghuram static int vsw_m_promisc(void *arg, boolean_t); 12206db247cSraghuram static mblk_t *vsw_m_tx(void *arg, mblk_t *); 123d8a518c8SSriharsha Basavapatna void vsw_mac_link_update(vsw_t *vswp, link_state_t link_state); 124f0ca1d9aSsb155480 void vsw_mac_rx(vsw_t *vswp, mac_resource_handle_t mrh, 125f0ca1d9aSsb155480 mblk_t *mp, vsw_macrx_flags_t flags); 1261107ea93SSriharsha Basavapatna void vsw_physlink_state_update(vsw_t *vswp); 1271ae08745Sheppo 12806db247cSraghuram /* 12906db247cSraghuram * Functions imported from other files. 13006db247cSraghuram */ 131808f26a8SSriharsha Basavapatna extern void vsw_setup_switching_thread(void *arg); 132808f26a8SSriharsha Basavapatna extern int vsw_setup_switching_start(vsw_t *vswp); 133808f26a8SSriharsha Basavapatna extern void vsw_setup_switching_stop(vsw_t *vswp); 13406db247cSraghuram extern int vsw_setup_switching(vsw_t *); 1357a327842Swentaoy extern void vsw_switch_frame_nop(vsw_t *vswp, mblk_t *mp, int caller, 1367a327842Swentaoy vsw_port_t *port, mac_resource_handle_t mrh); 13706db247cSraghuram extern int vsw_add_mcst(vsw_t *, uint8_t, uint64_t, void *); 13806db247cSraghuram extern int vsw_del_mcst(vsw_t *, uint8_t, uint64_t, void *); 13906db247cSraghuram extern void vsw_del_mcst_vsw(vsw_t *); 14006db247cSraghuram extern mcst_addr_t *vsw_del_addr(uint8_t devtype, void *arg, uint64_t addr); 1416f09f0feSWENTAO YANG extern void vsw_detach_ports(vsw_t *vswp); 14206db247cSraghuram extern int vsw_port_add(vsw_t *vswp, md_t *mdp, mde_cookie_t *node); 14306db247cSraghuram extern int vsw_port_detach(vsw_t *vswp, int p_instance); 144c1c61f44Ssb155480 static int vsw_port_update(vsw_t *vswp, md_t *curr_mdp, mde_cookie_t curr_mdex, 145c1c61f44Ssb155480 md_t *prev_mdp, mde_cookie_t prev_mdex); 146c1c61f44Ssb155480 extern int vsw_port_attach(vsw_port_t *port); 14706db247cSraghuram extern vsw_port_t *vsw_lookup_port(vsw_t *vswp, int p_instance); 14806db247cSraghuram extern int vsw_mac_open(vsw_t *vswp); 14906db247cSraghuram extern void vsw_mac_close(vsw_t *vswp); 150da14cebeSEric Cheng extern void vsw_mac_cleanup_ports(vsw_t *vswp); 15106db247cSraghuram extern void vsw_unset_addrs(vsw_t *vswp); 152d8a518c8SSriharsha Basavapatna extern void vsw_setup_switching_post_process(vsw_t *vswp); 153c1c61f44Ssb155480 extern void vsw_create_vlans(void *arg, int type); 154c1c61f44Ssb155480 extern void vsw_destroy_vlans(void *arg, int type); 155c1c61f44Ssb155480 extern void vsw_vlan_add_ids(void *arg, int type); 156c1c61f44Ssb155480 extern void vsw_vlan_remove_ids(void *arg, int type); 157c1c61f44Ssb155480 extern void vsw_vlan_unaware_port_reset(vsw_port_t *portp); 158c1c61f44Ssb155480 extern uint32_t vsw_vlan_frame_untag(void *arg, int type, mblk_t **np, 159c1c61f44Ssb155480 mblk_t **npt); 160c1c61f44Ssb155480 extern mblk_t *vsw_vlan_frame_pretag(void *arg, int type, mblk_t *mp); 161678453a8Sspeer extern void vsw_hio_cleanup(vsw_t *vswp); 162da14cebeSEric Cheng extern void vsw_hio_start_ports(vsw_t *vswp); 163da14cebeSEric Cheng extern void vsw_hio_port_update(vsw_port_t *portp, boolean_t hio_enabled); 164da14cebeSEric Cheng extern int vsw_mac_multicast_add(vsw_t *, vsw_port_t *, mcst_addr_t *, int); 165da14cebeSEric Cheng extern void vsw_mac_multicast_remove(vsw_t *, vsw_port_t *, mcst_addr_t *, int); 166da14cebeSEric Cheng extern void vsw_mac_port_reconfig_vlans(vsw_port_t *portp, uint16_t new_pvid, 167da14cebeSEric Cheng vsw_vlanid_t *new_vids, int new_nvids); 168da14cebeSEric Cheng extern int vsw_mac_client_init(vsw_t *vswp, vsw_port_t *port, int type); 169da14cebeSEric Cheng extern void vsw_mac_client_cleanup(vsw_t *vswp, vsw_port_t *port, int type); 170da14cebeSEric Cheng extern void vsw_if_mac_reconfig(vsw_t *vswp, boolean_t update_vlans, 171da14cebeSEric Cheng uint16_t new_pvid, vsw_vlanid_t *new_vids, int new_nvids); 1727b1f684aSSriharsha Basavapatna extern void vsw_reset_ports(vsw_t *vswp); 1737b1f684aSSriharsha Basavapatna extern void vsw_port_reset(vsw_port_t *portp); 1741107ea93SSriharsha Basavapatna extern void vsw_physlink_update_ports(vsw_t *vswp); 175bce0a86eSWENTAO YANG extern void vsw_update_bandwidth(vsw_t *vswp, vsw_port_t *port, int type, 176bce0a86eSWENTAO YANG uint64_t maxbw); 17706db247cSraghuram 17806db247cSraghuram /* 17906db247cSraghuram * Internal tunables. 18006db247cSraghuram */ 181445b4c2eSsb155480 int vsw_num_handshakes = VNET_NUM_HANDSHAKES; /* # of handshake attempts */ 1821ae08745Sheppo int vsw_wretries = 100; /* # of write attempts */ 18319b65a69Ssb155480 int vsw_setup_switching_delay = 3; /* setup sw timeout interval in sec */ 1840e8b4070Ssb155480 int vsw_mac_open_retries = 300; /* max # of mac_open() retries */ 1850e8b4070Ssb155480 /* 300*3 = 900sec(15min) of max tmout */ 18606db247cSraghuram int vsw_ldc_tx_delay = 5; /* delay(ticks) for tx retries */ 18706db247cSraghuram int vsw_ldc_tx_retries = 10; /* # of ldc tx retries */ 1886f09f0feSWENTAO YANG int vsw_ldc_retries = 5; /* # of ldc_close() retries */ 1896f09f0feSWENTAO YANG int vsw_ldc_delay = 1000; /* 1 ms delay for ldc_close() */ 19006db247cSraghuram boolean_t vsw_ldc_rxthr_enabled = B_TRUE; /* LDC Rx thread enabled */ 19106db247cSraghuram boolean_t vsw_ldc_txthr_enabled = B_TRUE; /* LDC Tx thread enabled */ 19234b64c01SWENTAO YANG int vsw_rxpool_cleanup_delay = 100000; /* 100ms */ 19334b64c01SWENTAO YANG 194d10e4ef2Snarayan 195c1c61f44Ssb155480 uint32_t vsw_fdb_nchains = 8; /* # of chains in fdb hash table */ 196c1c61f44Ssb155480 uint32_t vsw_vlan_nchains = 4; /* # of chains in vlan id hash table */ 197c1c61f44Ssb155480 uint32_t vsw_ethermtu = 1500; /* mtu of the device */ 198c1c61f44Ssb155480 199c1c61f44Ssb155480 /* delay in usec to wait for all references on a fdb entry to be dropped */ 200c1c61f44Ssb155480 uint32_t vsw_fdbe_refcnt_delay = 10; 201c1c61f44Ssb155480 202c1c61f44Ssb155480 /* 203c1c61f44Ssb155480 * Default vlan id. This is only used internally when the "default-vlan-id" 204c1c61f44Ssb155480 * property is not present in the MD device node. Therefore, this should not be 205c1c61f44Ssb155480 * used as a tunable; if this value is changed, the corresponding variable 206c1c61f44Ssb155480 * should be updated to the same value in all vnets connected to this vsw. 207c1c61f44Ssb155480 */ 208c1c61f44Ssb155480 uint16_t vsw_default_vlan_id = 1; 209c1c61f44Ssb155480 210f0ca1d9aSsb155480 /* 211f0ca1d9aSsb155480 * Workaround for a version handshake bug in obp's vnet. 212f0ca1d9aSsb155480 * If vsw initiates version negotiation starting from the highest version, 213f0ca1d9aSsb155480 * obp sends a nack and terminates version handshake. To workaround 214f0ca1d9aSsb155480 * this, we do not initiate version handshake when the channel comes up. 215f0ca1d9aSsb155480 * Instead, we wait for the peer to send its version info msg and go through 216f0ca1d9aSsb155480 * the version protocol exchange. If we successfully negotiate a version, 217f0ca1d9aSsb155480 * before sending the ack, we send our version info msg to the peer 218f0ca1d9aSsb155480 * using the <major,minor> version that we are about to ack. 219f0ca1d9aSsb155480 */ 220f0ca1d9aSsb155480 boolean_t vsw_obp_ver_proto_workaround = B_TRUE; 221f0ca1d9aSsb155480 222f0ca1d9aSsb155480 /* 223f0ca1d9aSsb155480 * In the absence of "priority-ether-types" property in MD, the following 224f0ca1d9aSsb155480 * internal tunable can be set to specify a single priority ethertype. 225f0ca1d9aSsb155480 */ 226f0ca1d9aSsb155480 uint64_t vsw_pri_eth_type = 0; 227f0ca1d9aSsb155480 228f0ca1d9aSsb155480 /* 229f0ca1d9aSsb155480 * Number of transmit priority buffers that are preallocated per device. 230f0ca1d9aSsb155480 * This number is chosen to be a small value to throttle transmission 231f0ca1d9aSsb155480 * of priority packets. Note: Must be a power of 2 for vio_create_mblks(). 232f0ca1d9aSsb155480 */ 233f0ca1d9aSsb155480 uint32_t vsw_pri_tx_nmblks = 64; 234d10e4ef2Snarayan 23551aa9d07Ssb155480 /* 23651aa9d07Ssb155480 * Number of RARP packets sent to announce macaddr to the physical switch, 23751aa9d07Ssb155480 * after vsw's physical device is changed dynamically or after a guest (client 23851aa9d07Ssb155480 * vnet) is live migrated in. 23951aa9d07Ssb155480 */ 24051aa9d07Ssb155480 uint32_t vsw_publish_macaddr_count = 3; 24151aa9d07Ssb155480 242*7bd3a2e2SSriharsha Basavapatna /* 243*7bd3a2e2SSriharsha Basavapatna * Enable/disable HybridIO 244*7bd3a2e2SSriharsha Basavapatna */ 245*7bd3a2e2SSriharsha Basavapatna boolean_t vsw_hio_enabled = B_TRUE; 246678453a8Sspeer 247*7bd3a2e2SSriharsha Basavapatna /* 248*7bd3a2e2SSriharsha Basavapatna * Max retries for HybridIO cleanup 249*7bd3a2e2SSriharsha Basavapatna */ 250*7bd3a2e2SSriharsha Basavapatna int vsw_hio_max_cleanup_retries = 10; 251*7bd3a2e2SSriharsha Basavapatna 252*7bd3a2e2SSriharsha Basavapatna /* 253*7bd3a2e2SSriharsha Basavapatna * 10ms delay for HybridIO cleanup 254*7bd3a2e2SSriharsha Basavapatna */ 255*7bd3a2e2SSriharsha Basavapatna int vsw_hio_cleanup_delay = 10000; 256*7bd3a2e2SSriharsha Basavapatna 257*7bd3a2e2SSriharsha Basavapatna /* 258*7bd3a2e2SSriharsha Basavapatna * Descriptor ring modes of LDC data transfer: 259*7bd3a2e2SSriharsha Basavapatna * 260*7bd3a2e2SSriharsha Basavapatna * 1) TxDring mode: 261*7bd3a2e2SSriharsha Basavapatna * In versions < v1.6 of VIO Protocol, we support only TxDring mode. In this 262*7bd3a2e2SSriharsha Basavapatna * mode, we create a transmit descriptor ring and export it to the peer through 263*7bd3a2e2SSriharsha Basavapatna * dring registration process of handshake. The descriptor ring is exported 264*7bd3a2e2SSriharsha Basavapatna * using LDC shared memory. Each descriptor is associated with a data buffer. 265*7bd3a2e2SSriharsha Basavapatna * The data buffer is also exported over LDC and the cookies for this data 266*7bd3a2e2SSriharsha Basavapatna * buffer are provided in the descriptor. The peer maps this ring as its 267*7bd3a2e2SSriharsha Basavapatna * receive ring. Similarly, the peer exports a transmit descriptor ring which 268*7bd3a2e2SSriharsha Basavapatna * is mapped by this device as its receive ring. In this mode, in a given data 269*7bd3a2e2SSriharsha Basavapatna * transfer direction, the transmitter copies the data to the exported data 270*7bd3a2e2SSriharsha Basavapatna * buffer (owned by itself), bound to the descriptor. The receiver uses the LDC 271*7bd3a2e2SSriharsha Basavapatna * cookies specified in the descriptor to copy the data into the receiving 272*7bd3a2e2SSriharsha Basavapatna * guest through the hypervisor (ldc_mem_copy()). 273*7bd3a2e2SSriharsha Basavapatna * 274*7bd3a2e2SSriharsha Basavapatna * 2) RxDringData mode: 275*7bd3a2e2SSriharsha Basavapatna * In versions >= v1.6 of VIO Protocol, we also support RxDringData mode. In 276*7bd3a2e2SSriharsha Basavapatna * this mode, we create a receive descriptor ring and export it to the peer 277*7bd3a2e2SSriharsha Basavapatna * through dring registration process of handshake. In addition, we export a 278*7bd3a2e2SSriharsha Basavapatna * receive buffer area and provide that information also in the dring 279*7bd3a2e2SSriharsha Basavapatna * registration message. The descriptor ring and the data buffer area are 280*7bd3a2e2SSriharsha Basavapatna * exported using LDC shared memory. Each descriptor is associated with a data 281*7bd3a2e2SSriharsha Basavapatna * buffer in the data buffer area and the offset of the specific data buffer 282*7bd3a2e2SSriharsha Basavapatna * within this area is specified in the descriptor. The peer maps this ring 283*7bd3a2e2SSriharsha Basavapatna * along with the data buffer area as its transmit ring. Similarly, the peer 284*7bd3a2e2SSriharsha Basavapatna * exports a receive ring which is mapped by this device as its transmit ring, 285*7bd3a2e2SSriharsha Basavapatna * along with its buffer area. In this mode, in a given data transfer 286*7bd3a2e2SSriharsha Basavapatna * direction, the transmitter copies the data to the data buffer offset 287*7bd3a2e2SSriharsha Basavapatna * specified in the descriptor. The receiver simply picks up the data buffer 288*7bd3a2e2SSriharsha Basavapatna * (owned by itself) without any copy operation into the receiving guest. 289*7bd3a2e2SSriharsha Basavapatna * 290*7bd3a2e2SSriharsha Basavapatna * We provide a tunable to enable RxDringData mode for versions >= v1.6 of VIO 291*7bd3a2e2SSriharsha Basavapatna * Protocol. By default, this tunable is set to 1 (VIO_TX_DRING). To enable 292*7bd3a2e2SSriharsha Basavapatna * RxDringData mode set this tunable to 4 (VIO_RX_DRING_DATA). This enables us 293*7bd3a2e2SSriharsha Basavapatna * to negotiate RxDringData mode with peers that support versions >= v1.6. For 294*7bd3a2e2SSriharsha Basavapatna * peers that support version < v1.6, we continue to operate in TxDring mode 295*7bd3a2e2SSriharsha Basavapatna * with them though the tunable is enabled. 296*7bd3a2e2SSriharsha Basavapatna */ 297*7bd3a2e2SSriharsha Basavapatna uint8_t vsw_dring_mode = VIO_TX_DRING; 298*7bd3a2e2SSriharsha Basavapatna 299*7bd3a2e2SSriharsha Basavapatna /* 300*7bd3a2e2SSriharsha Basavapatna * Number of descriptors; must be power of 2. 301*7bd3a2e2SSriharsha Basavapatna */ 302*7bd3a2e2SSriharsha Basavapatna uint32_t vsw_num_descriptors = VSW_NUM_DESCRIPTORS; 303*7bd3a2e2SSriharsha Basavapatna 304*7bd3a2e2SSriharsha Basavapatna /* 305*7bd3a2e2SSriharsha Basavapatna * In RxDringData mode, # of buffers is determined by multiplying the # of 306*7bd3a2e2SSriharsha Basavapatna * descriptors with the factor below. Note that the factor must be > 1; i.e, 307*7bd3a2e2SSriharsha Basavapatna * the # of buffers must always be > # of descriptors. This is needed because, 308*7bd3a2e2SSriharsha Basavapatna * while the shared memory buffers are sent up the stack on the receiver, the 309*7bd3a2e2SSriharsha Basavapatna * sender needs additional buffers that can be used for further transmits. 310*7bd3a2e2SSriharsha Basavapatna * See vsw_setup_rx_dring() for details. 311*7bd3a2e2SSriharsha Basavapatna */ 312*7bd3a2e2SSriharsha Basavapatna uint32_t vsw_nrbufs_factor = 2; 313*7bd3a2e2SSriharsha Basavapatna 314*7bd3a2e2SSriharsha Basavapatna /* 315*7bd3a2e2SSriharsha Basavapatna * Delay when rx descr not ready; used in both dring modes. 316*7bd3a2e2SSriharsha Basavapatna */ 317*7bd3a2e2SSriharsha Basavapatna int vsw_recv_delay = 0; 318*7bd3a2e2SSriharsha Basavapatna 319*7bd3a2e2SSriharsha Basavapatna /* 320*7bd3a2e2SSriharsha Basavapatna * Retry when rx descr not ready; used in both dring modes. 321*7bd3a2e2SSriharsha Basavapatna */ 322*7bd3a2e2SSriharsha Basavapatna int vsw_recv_retries = 5; 323f0ca1d9aSsb155480 32406db247cSraghuram /* 32506db247cSraghuram * Max number of mblks received in one receive operation. 32606db247cSraghuram */ 32706db247cSraghuram uint32_t vsw_chain_len = (VSW_NUM_MBLKS * 0.6); 32806db247cSraghuram 32906db247cSraghuram /* 3307b1f684aSSriharsha Basavapatna * Internal tunables for receive buffer pools, that is, the size and number of 3317b1f684aSSriharsha Basavapatna * mblks for each pool. At least 3 sizes must be specified if these are used. 3327b1f684aSSriharsha Basavapatna * The sizes must be specified in increasing order. Non-zero value of the first 3337b1f684aSSriharsha Basavapatna * size will be used as a hint to use these values instead of the algorithm 334*7bd3a2e2SSriharsha Basavapatna * that determines the sizes based on MTU. Used in TxDring mode only. 33506db247cSraghuram */ 3367b1f684aSSriharsha Basavapatna uint32_t vsw_mblk_size1 = 0; 3377b1f684aSSriharsha Basavapatna uint32_t vsw_mblk_size2 = 0; 3387b1f684aSSriharsha Basavapatna uint32_t vsw_mblk_size3 = 0; 3397b1f684aSSriharsha Basavapatna uint32_t vsw_mblk_size4 = 0; 34006db247cSraghuram uint32_t vsw_num_mblks1 = VSW_NUM_MBLKS; /* number of mblks for pool1 */ 34106db247cSraghuram uint32_t vsw_num_mblks2 = VSW_NUM_MBLKS; /* number of mblks for pool2 */ 34206db247cSraghuram uint32_t vsw_num_mblks3 = VSW_NUM_MBLKS; /* number of mblks for pool3 */ 3437b1f684aSSriharsha Basavapatna uint32_t vsw_num_mblks4 = VSW_NUM_MBLKS; /* number of mblks for pool4 */ 3447b1f684aSSriharsha Basavapatna 3457b1f684aSSriharsha Basavapatna /* 3467b1f684aSSriharsha Basavapatna * Set this to non-zero to enable additional internal receive buffer pools 3477b1f684aSSriharsha Basavapatna * based on the MTU of the device for better performance at the cost of more 3487b1f684aSSriharsha Basavapatna * memory consumption. This is turned off by default, to use allocb(9F) for 3497b1f684aSSriharsha Basavapatna * receive buffer allocations of sizes > 2K. 3507b1f684aSSriharsha Basavapatna */ 3517b1f684aSSriharsha Basavapatna boolean_t vsw_jumbo_rxpools = B_FALSE; 35206db247cSraghuram 35306db247cSraghuram /* 354f0ca1d9aSsb155480 * vsw_max_tx_qcount is the maximum # of packets that can be queued 355f0ca1d9aSsb155480 * before the tx worker thread begins processing the queue. Its value 356f0ca1d9aSsb155480 * is chosen to be 4x the default length of tx descriptor ring. 357f0ca1d9aSsb155480 */ 358*7bd3a2e2SSriharsha Basavapatna uint32_t vsw_max_tx_qcount = 4 * VSW_NUM_DESCRIPTORS; 359f0ca1d9aSsb155480 360f0ca1d9aSsb155480 /* 36106db247cSraghuram * MAC callbacks 36206db247cSraghuram */ 363ba2e4443Sseb static mac_callbacks_t vsw_m_callbacks = { 364ba2e4443Sseb 0, 365ba2e4443Sseb vsw_m_stat, 366ba2e4443Sseb vsw_m_start, 367ba2e4443Sseb vsw_m_stop, 368ba2e4443Sseb vsw_m_promisc, 369ba2e4443Sseb vsw_m_multicst, 370ba2e4443Sseb vsw_m_unicst, 3710dc2366fSVenugopal Iyer vsw_m_tx 372ba2e4443Sseb }; 373ba2e4443Sseb 3741ae08745Sheppo static struct cb_ops vsw_cb_ops = { 3751ae08745Sheppo nulldev, /* cb_open */ 3761ae08745Sheppo nulldev, /* cb_close */ 3771ae08745Sheppo nodev, /* cb_strategy */ 3781ae08745Sheppo nodev, /* cb_print */ 3791ae08745Sheppo nodev, /* cb_dump */ 3801ae08745Sheppo nodev, /* cb_read */ 3811ae08745Sheppo nodev, /* cb_write */ 3821ae08745Sheppo nodev, /* cb_ioctl */ 3831ae08745Sheppo nodev, /* cb_devmap */ 3841ae08745Sheppo nodev, /* cb_mmap */ 3851ae08745Sheppo nodev, /* cb_segmap */ 3861ae08745Sheppo nochpoll, /* cb_chpoll */ 3871ae08745Sheppo ddi_prop_op, /* cb_prop_op */ 3881ae08745Sheppo NULL, /* cb_stream */ 3891ae08745Sheppo D_MP, /* cb_flag */ 3901ae08745Sheppo CB_REV, /* rev */ 3911ae08745Sheppo nodev, /* int (*cb_aread)() */ 3921ae08745Sheppo nodev /* int (*cb_awrite)() */ 3931ae08745Sheppo }; 3941ae08745Sheppo 3951ae08745Sheppo static struct dev_ops vsw_ops = { 3961ae08745Sheppo DEVO_REV, /* devo_rev */ 3971ae08745Sheppo 0, /* devo_refcnt */ 39871184a40SWENTAO YANG NULL, /* devo_getinfo */ 3991ae08745Sheppo nulldev, /* devo_identify */ 4001ae08745Sheppo nulldev, /* devo_probe */ 4011ae08745Sheppo vsw_attach, /* devo_attach */ 4021ae08745Sheppo vsw_detach, /* devo_detach */ 4031ae08745Sheppo nodev, /* devo_reset */ 4041ae08745Sheppo &vsw_cb_ops, /* devo_cb_ops */ 4051ae08745Sheppo (struct bus_ops *)NULL, /* devo_bus_ops */ 4061ae08745Sheppo ddi_power /* devo_power */ 4071ae08745Sheppo }; 4081ae08745Sheppo 4091ae08745Sheppo extern struct mod_ops mod_driverops; 4101ae08745Sheppo static struct modldrv vswmodldrv = { 4111ae08745Sheppo &mod_driverops, 412205eeb1aSlm66018 "sun4v Virtual Switch", 4131ae08745Sheppo &vsw_ops, 4141ae08745Sheppo }; 4151ae08745Sheppo 4161ae08745Sheppo #define LDC_ENTER_LOCK(ldcp) \ 4171ae08745Sheppo mutex_enter(&((ldcp)->ldc_cblock));\ 41806db247cSraghuram mutex_enter(&((ldcp)->ldc_rxlock));\ 4191ae08745Sheppo mutex_enter(&((ldcp)->ldc_txlock)); 4201ae08745Sheppo #define LDC_EXIT_LOCK(ldcp) \ 4211ae08745Sheppo mutex_exit(&((ldcp)->ldc_txlock));\ 42206db247cSraghuram mutex_exit(&((ldcp)->ldc_rxlock));\ 4231ae08745Sheppo mutex_exit(&((ldcp)->ldc_cblock)); 4241ae08745Sheppo 4251ae08745Sheppo /* Driver soft state ptr */ 4261ae08745Sheppo static void *vsw_state; 4271ae08745Sheppo 4281ae08745Sheppo /* 4291ae08745Sheppo * Linked list of "vsw_t" structures - one per instance. 4301ae08745Sheppo */ 4311ae08745Sheppo vsw_t *vsw_head = NULL; 4321ae08745Sheppo krwlock_t vsw_rw; 4331ae08745Sheppo 4341ae08745Sheppo /* 4351ae08745Sheppo * Property names 4361ae08745Sheppo */ 4371ae08745Sheppo static char vdev_propname[] = "virtual-device"; 4381ae08745Sheppo static char vsw_propname[] = "virtual-network-switch"; 4391ae08745Sheppo static char physdev_propname[] = "vsw-phys-dev"; 4401ae08745Sheppo static char smode_propname[] = "vsw-switch-mode"; 4411ae08745Sheppo static char macaddr_propname[] = "local-mac-address"; 4421ae08745Sheppo static char remaddr_propname[] = "remote-mac-address"; 4431ae08745Sheppo static char ldcids_propname[] = "ldc-ids"; 4441ae08745Sheppo static char chan_propname[] = "channel-endpoint"; 4451ae08745Sheppo static char id_propname[] = "id"; 4461ae08745Sheppo static char reg_propname[] = "reg"; 447f0ca1d9aSsb155480 static char pri_types_propname[] = "priority-ether-types"; 448c1c61f44Ssb155480 static char vsw_pvid_propname[] = "port-vlan-id"; 449c1c61f44Ssb155480 static char vsw_vid_propname[] = "vlan-id"; 450c1c61f44Ssb155480 static char vsw_dvid_propname[] = "default-vlan-id"; 451c1c61f44Ssb155480 static char port_pvid_propname[] = "remote-port-vlan-id"; 452c1c61f44Ssb155480 static char port_vid_propname[] = "remote-vlan-id"; 453678453a8Sspeer static char hybrid_propname[] = "hybrid"; 4547b1f684aSSriharsha Basavapatna static char vsw_mtu_propname[] = "mtu"; 4551107ea93SSriharsha Basavapatna static char vsw_linkprop_propname[] = "linkprop"; 456bce0a86eSWENTAO YANG static char vsw_maxbw_propname[] = "maxbw"; 457bce0a86eSWENTAO YANG static char port_maxbw_propname[] = "maxbw"; 4581ae08745Sheppo 4591ae08745Sheppo /* 4601ae08745Sheppo * Matching criteria passed to the MDEG to register interest 4611ae08745Sheppo * in changes to 'virtual-device-port' nodes identified by their 4621ae08745Sheppo * 'id' property. 4631ae08745Sheppo */ 4641ae08745Sheppo static md_prop_match_t vport_prop_match[] = { 4651ae08745Sheppo { MDET_PROP_VAL, "id" }, 4661ae08745Sheppo { MDET_LIST_END, NULL } 4671ae08745Sheppo }; 4681ae08745Sheppo 4691ae08745Sheppo static mdeg_node_match_t vport_match = { "virtual-device-port", 4701ae08745Sheppo vport_prop_match }; 4711ae08745Sheppo 4721ae08745Sheppo /* 47334683adeSsg70180 * Matching criteria passed to the MDEG to register interest 47434683adeSsg70180 * in changes to 'virtual-device' nodes (i.e. vsw nodes) identified 47534683adeSsg70180 * by their 'name' and 'cfg-handle' properties. 47634683adeSsg70180 */ 47734683adeSsg70180 static md_prop_match_t vdev_prop_match[] = { 47834683adeSsg70180 { MDET_PROP_STR, "name" }, 47934683adeSsg70180 { MDET_PROP_VAL, "cfg-handle" }, 48034683adeSsg70180 { MDET_LIST_END, NULL } 48134683adeSsg70180 }; 48234683adeSsg70180 48334683adeSsg70180 static mdeg_node_match_t vdev_match = { "virtual-device", 48434683adeSsg70180 vdev_prop_match }; 48534683adeSsg70180 48634683adeSsg70180 48734683adeSsg70180 /* 4881ae08745Sheppo * Specification of an MD node passed to the MDEG to filter any 4891ae08745Sheppo * 'vport' nodes that do not belong to the specified node. This 4901ae08745Sheppo * template is copied for each vsw instance and filled in with 4911ae08745Sheppo * the appropriate 'cfg-handle' value before being passed to the MDEG. 4921ae08745Sheppo */ 4931ae08745Sheppo static mdeg_prop_spec_t vsw_prop_template[] = { 4941ae08745Sheppo { MDET_PROP_STR, "name", vsw_propname }, 4951ae08745Sheppo { MDET_PROP_VAL, "cfg-handle", NULL }, 4961ae08745Sheppo { MDET_LIST_END, NULL, NULL } 4971ae08745Sheppo }; 4981ae08745Sheppo 4991ae08745Sheppo #define VSW_SET_MDEG_PROP_INST(specp, val) (specp)[1].ps_val = (val); 5001ae08745Sheppo 50106db247cSraghuram #ifdef DEBUG 5027636cb21Slm66018 /* 5031ae08745Sheppo * Print debug messages - set to 0x1f to enable all msgs 5041ae08745Sheppo * or 0x0 to turn all off. 5051ae08745Sheppo */ 5061ae08745Sheppo int vswdbg = 0x0; 5071ae08745Sheppo 5081ae08745Sheppo /* 5091ae08745Sheppo * debug levels: 5101ae08745Sheppo * 0x01: Function entry/exit tracing 5111ae08745Sheppo * 0x02: Internal function messages 5121ae08745Sheppo * 0x04: Verbose internal messages 5131ae08745Sheppo * 0x08: Warning messages 5141ae08745Sheppo * 0x10: Error messages 5151ae08745Sheppo */ 5161ae08745Sheppo 51706db247cSraghuram void 5181ae08745Sheppo vswdebug(vsw_t *vswp, const char *fmt, ...) 5191ae08745Sheppo { 5201ae08745Sheppo char buf[512]; 5211ae08745Sheppo va_list ap; 5221ae08745Sheppo 5231ae08745Sheppo va_start(ap, fmt); 5241ae08745Sheppo (void) vsprintf(buf, fmt, ap); 5251ae08745Sheppo va_end(ap); 5261ae08745Sheppo 5271ae08745Sheppo if (vswp == NULL) 5281ae08745Sheppo cmn_err(CE_CONT, "%s\n", buf); 5291ae08745Sheppo else 5301ae08745Sheppo cmn_err(CE_CONT, "vsw%d: %s\n", vswp->instance, buf); 5311ae08745Sheppo } 5321ae08745Sheppo 5331ae08745Sheppo #endif /* DEBUG */ 5341ae08745Sheppo 5351ae08745Sheppo static struct modlinkage modlinkage = { 5361ae08745Sheppo MODREV_1, 5371ae08745Sheppo &vswmodldrv, 5381ae08745Sheppo NULL 5391ae08745Sheppo }; 5401ae08745Sheppo 5411ae08745Sheppo int 5421ae08745Sheppo _init(void) 5431ae08745Sheppo { 5441ae08745Sheppo int status; 5451ae08745Sheppo 5461ae08745Sheppo rw_init(&vsw_rw, NULL, RW_DRIVER, NULL); 5471ae08745Sheppo 5481ae08745Sheppo status = ddi_soft_state_init(&vsw_state, sizeof (vsw_t), 1); 5491ae08745Sheppo if (status != 0) { 5501ae08745Sheppo return (status); 5511ae08745Sheppo } 5521ae08745Sheppo 55306db247cSraghuram mac_init_ops(&vsw_ops, DRV_NAME); 5541ae08745Sheppo status = mod_install(&modlinkage); 5551ae08745Sheppo if (status != 0) { 5561ae08745Sheppo ddi_soft_state_fini(&vsw_state); 5571ae08745Sheppo } 5581ae08745Sheppo return (status); 5591ae08745Sheppo } 5601ae08745Sheppo 5611ae08745Sheppo int 5621ae08745Sheppo _fini(void) 5631ae08745Sheppo { 5641ae08745Sheppo int status; 5651ae08745Sheppo 5661ae08745Sheppo status = mod_remove(&modlinkage); 5671ae08745Sheppo if (status != 0) 5681ae08745Sheppo return (status); 5691ae08745Sheppo mac_fini_ops(&vsw_ops); 5701ae08745Sheppo ddi_soft_state_fini(&vsw_state); 5711ae08745Sheppo 5721ae08745Sheppo rw_destroy(&vsw_rw); 5731ae08745Sheppo 5741ae08745Sheppo return (status); 5751ae08745Sheppo } 5761ae08745Sheppo 5771ae08745Sheppo int 5781ae08745Sheppo _info(struct modinfo *modinfop) 5791ae08745Sheppo { 5801ae08745Sheppo return (mod_info(&modlinkage, modinfop)); 5811ae08745Sheppo } 5821ae08745Sheppo 5831ae08745Sheppo static int 5841ae08745Sheppo vsw_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 5851ae08745Sheppo { 5861ae08745Sheppo vsw_t *vswp; 58734683adeSsg70180 int instance; 5881ae08745Sheppo char hashname[MAXNAMELEN]; 5891ae08745Sheppo char qname[TASKQ_NAMELEN]; 5906f09f0feSWENTAO YANG vsw_attach_progress_t progress = PROG_init; 59119b65a69Ssb155480 int rv; 5921ae08745Sheppo 5931ae08745Sheppo switch (cmd) { 5941ae08745Sheppo case DDI_ATTACH: 5951ae08745Sheppo break; 5961ae08745Sheppo case DDI_RESUME: 5971ae08745Sheppo /* nothing to do for this non-device */ 5981ae08745Sheppo return (DDI_SUCCESS); 5991ae08745Sheppo case DDI_PM_RESUME: 6001ae08745Sheppo default: 6011ae08745Sheppo return (DDI_FAILURE); 6021ae08745Sheppo } 6031ae08745Sheppo 6041ae08745Sheppo instance = ddi_get_instance(dip); 6051ae08745Sheppo if (ddi_soft_state_zalloc(vsw_state, instance) != DDI_SUCCESS) { 6061ae08745Sheppo DERR(NULL, "vsw%d: ddi_soft_state_zalloc failed", instance); 6071ae08745Sheppo return (DDI_FAILURE); 6081ae08745Sheppo } 6091ae08745Sheppo vswp = ddi_get_soft_state(vsw_state, instance); 6101ae08745Sheppo 6111ae08745Sheppo if (vswp == NULL) { 6121ae08745Sheppo DERR(NULL, "vsw%d: ddi_get_soft_state failed", instance); 6131ae08745Sheppo goto vsw_attach_fail; 6141ae08745Sheppo } 6151ae08745Sheppo 6161ae08745Sheppo vswp->dip = dip; 6171ae08745Sheppo vswp->instance = instance; 6181107ea93SSriharsha Basavapatna vswp->phys_link_state = LINK_STATE_UNKNOWN; 6191ae08745Sheppo ddi_set_driver_private(dip, (caddr_t)vswp); 6201ae08745Sheppo 621da14cebeSEric Cheng mutex_init(&vswp->mac_lock, NULL, MUTEX_DRIVER, NULL); 62219b65a69Ssb155480 mutex_init(&vswp->mca_lock, NULL, MUTEX_DRIVER, NULL); 623808f26a8SSriharsha Basavapatna mutex_init(&vswp->sw_thr_lock, NULL, MUTEX_DRIVER, NULL); 624808f26a8SSriharsha Basavapatna cv_init(&vswp->sw_thr_cv, NULL, CV_DRIVER, NULL); 625da14cebeSEric Cheng rw_init(&vswp->maccl_rwlock, NULL, RW_DRIVER, NULL); 6261ae08745Sheppo rw_init(&vswp->if_lockrw, NULL, RW_DRIVER, NULL); 62719b65a69Ssb155480 rw_init(&vswp->mfdbrw, NULL, RW_DRIVER, NULL); 62819b65a69Ssb155480 rw_init(&vswp->plist.lockrw, NULL, RW_DRIVER, NULL); 62919b65a69Ssb155480 63019b65a69Ssb155480 progress |= PROG_locks; 63119b65a69Ssb155480 63219b65a69Ssb155480 rv = vsw_read_mdprops(vswp); 63319b65a69Ssb155480 if (rv != 0) 63419b65a69Ssb155480 goto vsw_attach_fail; 63519b65a69Ssb155480 63619b65a69Ssb155480 progress |= PROG_readmd; 6371ae08745Sheppo 6381ae08745Sheppo /* setup the unicast forwarding database */ 6391ae08745Sheppo (void) snprintf(hashname, MAXNAMELEN, "vsw_unicst_table-%d", 6401ae08745Sheppo vswp->instance); 6411ae08745Sheppo D2(vswp, "creating unicast hash table (%s)...", hashname); 642c1c61f44Ssb155480 vswp->fdb_nchains = vsw_fdb_nchains; 643c1c61f44Ssb155480 vswp->fdb_hashp = mod_hash_create_ptrhash(hashname, vswp->fdb_nchains, 6441ae08745Sheppo mod_hash_null_valdtor, sizeof (void *)); 645c1c61f44Ssb155480 vsw_create_vlans((void *)vswp, VSW_LOCALDEV); 6461ae08745Sheppo progress |= PROG_fdb; 6471ae08745Sheppo 6481ae08745Sheppo /* setup the multicast fowarding database */ 6491ae08745Sheppo (void) snprintf(hashname, MAXNAMELEN, "vsw_mcst_table-%d", 6501ae08745Sheppo vswp->instance); 6511ae08745Sheppo D2(vswp, "creating multicast hash table %s)...", hashname); 652c1c61f44Ssb155480 vswp->mfdb = mod_hash_create_ptrhash(hashname, vsw_fdb_nchains, 6531ae08745Sheppo mod_hash_null_valdtor, sizeof (void *)); 6541ae08745Sheppo 6551ae08745Sheppo progress |= PROG_mfdb; 6561ae08745Sheppo 6571ae08745Sheppo /* 6581ae08745Sheppo * Create the taskq which will process all the VIO 6591ae08745Sheppo * control messages. 6601ae08745Sheppo */ 661*7bd3a2e2SSriharsha Basavapatna (void) snprintf(qname, TASKQ_NAMELEN, "taskq%d", vswp->instance); 6621ae08745Sheppo if ((vswp->taskq_p = ddi_taskq_create(vswp->dip, qname, 1, 6631ae08745Sheppo TASKQ_DEFAULTPRI, 0)) == NULL) { 66434683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to create task queue", 66534683adeSsg70180 vswp->instance); 6661ae08745Sheppo goto vsw_attach_fail; 6671ae08745Sheppo } 6681ae08745Sheppo 6691ae08745Sheppo progress |= PROG_taskq; 6701ae08745Sheppo 671*7bd3a2e2SSriharsha Basavapatna (void) snprintf(qname, TASKQ_NAMELEN, "rxpool_taskq%d", 67234b64c01SWENTAO YANG vswp->instance); 67334b64c01SWENTAO YANG if ((vswp->rxp_taskq = ddi_taskq_create(vswp->dip, qname, 1, 67434b64c01SWENTAO YANG TASKQ_DEFAULTPRI, 0)) == NULL) { 67534b64c01SWENTAO YANG cmn_err(CE_WARN, "!vsw%d: Unable to create rxp task queue", 67634b64c01SWENTAO YANG vswp->instance); 67734b64c01SWENTAO YANG goto vsw_attach_fail; 67834b64c01SWENTAO YANG } 67934b64c01SWENTAO YANG 68034b64c01SWENTAO YANG progress |= PROG_rxp_taskq; 68134b64c01SWENTAO YANG 682d10e4ef2Snarayan /* prevent auto-detaching */ 683d10e4ef2Snarayan if (ddi_prop_update_int(DDI_DEV_T_NONE, vswp->dip, 684d10e4ef2Snarayan DDI_NO_AUTODETACH, 1) != DDI_SUCCESS) { 68534683adeSsg70180 cmn_err(CE_NOTE, "!Unable to set \"%s\" property for " 686d10e4ef2Snarayan "instance %u", DDI_NO_AUTODETACH, instance); 687d10e4ef2Snarayan } 688d10e4ef2Snarayan 6891ae08745Sheppo /* 6907a327842Swentaoy * The null switching function is set to avoid panic until 6917a327842Swentaoy * switch mode is setup. 6927a327842Swentaoy */ 6937a327842Swentaoy vswp->vsw_switch_frame = vsw_switch_frame_nop; 6947a327842Swentaoy 6957a327842Swentaoy /* 696808f26a8SSriharsha Basavapatna * Setup the required switching mode, based on the mdprops that we read 697808f26a8SSriharsha Basavapatna * earlier. We start a thread to do this, to avoid calling mac_open() 698808f26a8SSriharsha Basavapatna * directly from attach(). 69919b65a69Ssb155480 */ 700808f26a8SSriharsha Basavapatna rv = vsw_setup_switching_start(vswp); 701808f26a8SSriharsha Basavapatna if (rv != 0) { 702808f26a8SSriharsha Basavapatna goto vsw_attach_fail; 703808f26a8SSriharsha Basavapatna } 70419b65a69Ssb155480 70519b65a69Ssb155480 progress |= PROG_swmode; 70619b65a69Ssb155480 70719b65a69Ssb155480 /* Register with mac layer as a provider */ 70819b65a69Ssb155480 rv = vsw_mac_register(vswp); 70919b65a69Ssb155480 if (rv != 0) 71019b65a69Ssb155480 goto vsw_attach_fail; 71119b65a69Ssb155480 71219b65a69Ssb155480 progress |= PROG_macreg; 71319b65a69Ssb155480 71419b65a69Ssb155480 /* 71534683adeSsg70180 * Now we have everything setup, register an interest in 71634683adeSsg70180 * specific MD nodes. 71734683adeSsg70180 * 71834683adeSsg70180 * The callback is invoked in 2 cases, firstly if upon mdeg 71934683adeSsg70180 * registration there are existing nodes which match our specified 72034683adeSsg70180 * criteria, and secondly if the MD is changed (and again, there 72134683adeSsg70180 * are nodes which we are interested in present within it. Note 72234683adeSsg70180 * that our callback will be invoked even if our specified nodes 72334683adeSsg70180 * have not actually changed). 72434683adeSsg70180 * 7251ae08745Sheppo */ 72619b65a69Ssb155480 rv = vsw_mdeg_register(vswp); 72719b65a69Ssb155480 if (rv != 0) 72834683adeSsg70180 goto vsw_attach_fail; 7291ae08745Sheppo 73019b65a69Ssb155480 progress |= PROG_mdreg; 73119b65a69Ssb155480 7326f09f0feSWENTAO YANG vswp->attach_progress = progress; 7336f09f0feSWENTAO YANG 73419b65a69Ssb155480 WRITE_ENTER(&vsw_rw); 73519b65a69Ssb155480 vswp->next = vsw_head; 73619b65a69Ssb155480 vsw_head = vswp; 73719b65a69Ssb155480 RW_EXIT(&vsw_rw); 73819b65a69Ssb155480 73919b65a69Ssb155480 ddi_report_dev(vswp->dip); 7401ae08745Sheppo return (DDI_SUCCESS); 7411ae08745Sheppo 7421ae08745Sheppo vsw_attach_fail: 7431ae08745Sheppo DERR(NULL, "vsw_attach: failed"); 7441ae08745Sheppo 7456f09f0feSWENTAO YANG vswp->attach_progress = progress; 7466f09f0feSWENTAO YANG (void) vsw_unattach(vswp); 7471ae08745Sheppo ddi_soft_state_free(vsw_state, instance); 7481ae08745Sheppo return (DDI_FAILURE); 7491ae08745Sheppo } 7501ae08745Sheppo 7511ae08745Sheppo static int 7521ae08745Sheppo vsw_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 7531ae08745Sheppo { 7541ae08745Sheppo vsw_t **vswpp, *vswp; 7551ae08745Sheppo int instance; 7561ae08745Sheppo 7571ae08745Sheppo instance = ddi_get_instance(dip); 7581ae08745Sheppo vswp = ddi_get_soft_state(vsw_state, instance); 7591ae08745Sheppo 7601ae08745Sheppo if (vswp == NULL) { 7611ae08745Sheppo return (DDI_FAILURE); 7621ae08745Sheppo } 7631ae08745Sheppo 7641ae08745Sheppo switch (cmd) { 7651ae08745Sheppo case DDI_DETACH: 7661ae08745Sheppo break; 7671ae08745Sheppo case DDI_SUSPEND: 7681ae08745Sheppo case DDI_PM_SUSPEND: 7691ae08745Sheppo default: 7701ae08745Sheppo return (DDI_FAILURE); 7711ae08745Sheppo } 7721ae08745Sheppo 7731ae08745Sheppo D2(vswp, "detaching instance %d", instance); 7741ae08745Sheppo 7756f09f0feSWENTAO YANG if (vsw_unattach(vswp) != 0) { 7761ae08745Sheppo return (DDI_FAILURE); 7771ae08745Sheppo } 778f0ca1d9aSsb155480 7791ae08745Sheppo ddi_remove_minor_node(dip, NULL); 7801ae08745Sheppo 7811ae08745Sheppo WRITE_ENTER(&vsw_rw); 7821ae08745Sheppo for (vswpp = &vsw_head; *vswpp; vswpp = &(*vswpp)->next) { 7831ae08745Sheppo if (*vswpp == vswp) { 7841ae08745Sheppo *vswpp = vswp->next; 7851ae08745Sheppo break; 7861ae08745Sheppo } 7871ae08745Sheppo } 7881ae08745Sheppo RW_EXIT(&vsw_rw); 7896f09f0feSWENTAO YANG 7901ae08745Sheppo ddi_soft_state_free(vsw_state, instance); 7911ae08745Sheppo 7921ae08745Sheppo return (DDI_SUCCESS); 7931ae08745Sheppo } 7941ae08745Sheppo 7951ae08745Sheppo /* 7966f09f0feSWENTAO YANG * Common routine to handle vsw_attach() failure and vsw_detach(). Note that 7976f09f0feSWENTAO YANG * the only reason this function could fail is if mac_unregister() fails. 7986f09f0feSWENTAO YANG * Otherwise, this function must ensure that all resources are freed and return 7996f09f0feSWENTAO YANG * success. 8006f09f0feSWENTAO YANG */ 8016f09f0feSWENTAO YANG static int 8026f09f0feSWENTAO YANG vsw_unattach(vsw_t *vswp) 8036f09f0feSWENTAO YANG { 8046f09f0feSWENTAO YANG vsw_attach_progress_t progress; 8056f09f0feSWENTAO YANG 8066f09f0feSWENTAO YANG progress = vswp->attach_progress; 8076f09f0feSWENTAO YANG 8086f09f0feSWENTAO YANG /* 8096f09f0feSWENTAO YANG * Unregister from the gldv3 subsystem. This can fail, in particular 8106f09f0feSWENTAO YANG * if there are still any open references to this mac device; in which 8116f09f0feSWENTAO YANG * case we just return failure without continuing to detach further. 8126f09f0feSWENTAO YANG */ 8136f09f0feSWENTAO YANG if (progress & PROG_macreg) { 8146f09f0feSWENTAO YANG if (vsw_mac_unregister(vswp) != 0) { 8156f09f0feSWENTAO YANG cmn_err(CE_WARN, "!vsw%d: Unable to detach from " 8166f09f0feSWENTAO YANG "MAC layer", vswp->instance); 8176f09f0feSWENTAO YANG return (1); 8186f09f0feSWENTAO YANG } 8196f09f0feSWENTAO YANG progress &= ~PROG_macreg; 8206f09f0feSWENTAO YANG } 8216f09f0feSWENTAO YANG 8226f09f0feSWENTAO YANG /* 8236f09f0feSWENTAO YANG * Now that we have unregistered from gldv3, we must finish all other 8246f09f0feSWENTAO YANG * steps and successfully return from this function; otherwise we will 8256f09f0feSWENTAO YANG * end up leaving the device in a broken/unusable state. 8266f09f0feSWENTAO YANG * 8276f09f0feSWENTAO YANG * If we have registered with mdeg, unregister now to stop further 8286f09f0feSWENTAO YANG * callbacks to this vsw device and/or its ports. Then, detach any 8296f09f0feSWENTAO YANG * existing ports. 8306f09f0feSWENTAO YANG */ 8316f09f0feSWENTAO YANG if (progress & PROG_mdreg) { 8326f09f0feSWENTAO YANG vsw_mdeg_unregister(vswp); 8336f09f0feSWENTAO YANG vsw_detach_ports(vswp); 8346f09f0feSWENTAO YANG progress &= ~PROG_mdreg; 8356f09f0feSWENTAO YANG } 8366f09f0feSWENTAO YANG 8376f09f0feSWENTAO YANG /* 8386f09f0feSWENTAO YANG * If we have started a thread to setup the switching mode, stop it, if 8396f09f0feSWENTAO YANG * it is still running. If it has finished setting up the switching 8406f09f0feSWENTAO YANG * mode, then we need to clean up some additional things if we are 8416f09f0feSWENTAO YANG * running in L2 mode: first free up any hybrid resources; then stop 8426f09f0feSWENTAO YANG * and close the underlying physical device. Note that we would have 8436f09f0feSWENTAO YANG * already released all per mac_client resources (ucast, mcast addrs, 8446f09f0feSWENTAO YANG * hio-shares etc) as all the ports are detached and if the vsw device 8456f09f0feSWENTAO YANG * itself was in use as an interface, it has been unplumbed (otherwise 8466f09f0feSWENTAO YANG * mac_unregister() above would fail). 8476f09f0feSWENTAO YANG */ 8486f09f0feSWENTAO YANG if (progress & PROG_swmode) { 8496f09f0feSWENTAO YANG 8506f09f0feSWENTAO YANG vsw_setup_switching_stop(vswp); 8516f09f0feSWENTAO YANG 8526f09f0feSWENTAO YANG if (vswp->hio_capable == B_TRUE) { 8536f09f0feSWENTAO YANG vsw_hio_cleanup(vswp); 8546f09f0feSWENTAO YANG vswp->hio_capable = B_FALSE; 8556f09f0feSWENTAO YANG } 8566f09f0feSWENTAO YANG 8576f09f0feSWENTAO YANG mutex_enter(&vswp->mac_lock); 8586f09f0feSWENTAO YANG vsw_mac_close(vswp); 8596f09f0feSWENTAO YANG mutex_exit(&vswp->mac_lock); 8606f09f0feSWENTAO YANG 8616f09f0feSWENTAO YANG progress &= ~PROG_swmode; 8626f09f0feSWENTAO YANG } 8636f09f0feSWENTAO YANG 8646f09f0feSWENTAO YANG /* 86534b64c01SWENTAO YANG * We now destroy the taskq used to clean up rx mblk pools that 86634b64c01SWENTAO YANG * couldn't be destroyed when the ports/channels were detached. 86734b64c01SWENTAO YANG * We implicitly wait for those tasks to complete in 86834b64c01SWENTAO YANG * ddi_taskq_destroy(). 86934b64c01SWENTAO YANG */ 87034b64c01SWENTAO YANG if (progress & PROG_rxp_taskq) { 87134b64c01SWENTAO YANG ddi_taskq_destroy(vswp->rxp_taskq); 87234b64c01SWENTAO YANG progress &= ~PROG_rxp_taskq; 87334b64c01SWENTAO YANG } 87434b64c01SWENTAO YANG 87534b64c01SWENTAO YANG /* 8766f09f0feSWENTAO YANG * By now any pending tasks have finished and the underlying 8776f09f0feSWENTAO YANG * ldc's have been destroyed, so its safe to delete the control 8786f09f0feSWENTAO YANG * message taskq. 8796f09f0feSWENTAO YANG */ 8806f09f0feSWENTAO YANG if (progress & PROG_taskq) { 8816f09f0feSWENTAO YANG ddi_taskq_destroy(vswp->taskq_p); 8826f09f0feSWENTAO YANG progress &= ~PROG_taskq; 8836f09f0feSWENTAO YANG } 8846f09f0feSWENTAO YANG 8856f09f0feSWENTAO YANG /* Destroy the multicast hash table */ 8866f09f0feSWENTAO YANG if (progress & PROG_mfdb) { 8876f09f0feSWENTAO YANG mod_hash_destroy_hash(vswp->mfdb); 8886f09f0feSWENTAO YANG progress &= ~PROG_mfdb; 8896f09f0feSWENTAO YANG } 8906f09f0feSWENTAO YANG 8916f09f0feSWENTAO YANG /* Destroy the vlan hash table and fdb */ 8926f09f0feSWENTAO YANG if (progress & PROG_fdb) { 8936f09f0feSWENTAO YANG vsw_destroy_vlans(vswp, VSW_LOCALDEV); 8946f09f0feSWENTAO YANG mod_hash_destroy_hash(vswp->fdb_hashp); 8956f09f0feSWENTAO YANG progress &= ~PROG_fdb; 8966f09f0feSWENTAO YANG } 8976f09f0feSWENTAO YANG 8986f09f0feSWENTAO YANG if (progress & PROG_readmd) { 8996f09f0feSWENTAO YANG if (VSW_PRI_ETH_DEFINED(vswp)) { 9006f09f0feSWENTAO YANG kmem_free(vswp->pri_types, 9016f09f0feSWENTAO YANG sizeof (uint16_t) * vswp->pri_num_types); 9026f09f0feSWENTAO YANG (void) vio_destroy_mblks(vswp->pri_tx_vmp); 9036f09f0feSWENTAO YANG } 9046f09f0feSWENTAO YANG progress &= ~PROG_readmd; 9056f09f0feSWENTAO YANG } 9066f09f0feSWENTAO YANG 9076f09f0feSWENTAO YANG if (progress & PROG_locks) { 9086f09f0feSWENTAO YANG rw_destroy(&vswp->plist.lockrw); 9096f09f0feSWENTAO YANG rw_destroy(&vswp->mfdbrw); 9106f09f0feSWENTAO YANG rw_destroy(&vswp->if_lockrw); 9116f09f0feSWENTAO YANG rw_destroy(&vswp->maccl_rwlock); 9126f09f0feSWENTAO YANG cv_destroy(&vswp->sw_thr_cv); 9136f09f0feSWENTAO YANG mutex_destroy(&vswp->sw_thr_lock); 9146f09f0feSWENTAO YANG mutex_destroy(&vswp->mca_lock); 9156f09f0feSWENTAO YANG mutex_destroy(&vswp->mac_lock); 9166f09f0feSWENTAO YANG progress &= ~PROG_locks; 9176f09f0feSWENTAO YANG } 9186f09f0feSWENTAO YANG 9196f09f0feSWENTAO YANG vswp->attach_progress = progress; 9206f09f0feSWENTAO YANG 9216f09f0feSWENTAO YANG return (0); 9226f09f0feSWENTAO YANG } 9236f09f0feSWENTAO YANG 92434b64c01SWENTAO YANG void 92534b64c01SWENTAO YANG vsw_destroy_rxpools(void *arg) 9266f09f0feSWENTAO YANG { 92734b64c01SWENTAO YANG vio_mblk_pool_t *poolp = (vio_mblk_pool_t *)arg; 92834b64c01SWENTAO YANG vio_mblk_pool_t *npoolp; 9296f09f0feSWENTAO YANG 9306f09f0feSWENTAO YANG while (poolp != NULL) { 93134b64c01SWENTAO YANG npoolp = poolp->nextp; 93234b64c01SWENTAO YANG while (vio_destroy_mblks(poolp) != 0) { 93334b64c01SWENTAO YANG drv_usecwait(vsw_rxpool_cleanup_delay); 9346f09f0feSWENTAO YANG } 9356f09f0feSWENTAO YANG poolp = npoolp; 9366f09f0feSWENTAO YANG } 9376f09f0feSWENTAO YANG } 9386f09f0feSWENTAO YANG 9396f09f0feSWENTAO YANG /* 94034683adeSsg70180 * Get the value of the "vsw-phys-dev" property in the specified 94134683adeSsg70180 * node. This property is the name of the physical device that 94234683adeSsg70180 * the virtual switch will use to talk to the outside world. 94334683adeSsg70180 * 94434683adeSsg70180 * Note it is valid for this property to be NULL (but the property 94534683adeSsg70180 * itself must exist). Callers of this routine should verify that 94634683adeSsg70180 * the value returned is what they expected (i.e. either NULL or non NULL). 94734683adeSsg70180 * 94834683adeSsg70180 * On success returns value of the property in region pointed to by 94934683adeSsg70180 * the 'name' argument, and with return value of 0. Otherwise returns 1. 9501ae08745Sheppo */ 95134683adeSsg70180 static int 95234683adeSsg70180 vsw_get_md_physname(vsw_t *vswp, md_t *mdp, mde_cookie_t node, char *name) 9531ae08745Sheppo { 95434683adeSsg70180 int len = 0; 955f2b610cfSwentaoy int instance; 9561ae08745Sheppo char *physname = NULL; 9571ae08745Sheppo char *dev; 958f2b610cfSwentaoy const char *dev_name; 959f2b610cfSwentaoy char myname[MAXNAMELEN]; 960f2b610cfSwentaoy 961f2b610cfSwentaoy dev_name = ddi_driver_name(vswp->dip); 962f2b610cfSwentaoy instance = ddi_get_instance(vswp->dip); 963f2b610cfSwentaoy (void) snprintf(myname, MAXNAMELEN, "%s%d", dev_name, instance); 9641ae08745Sheppo 96534683adeSsg70180 if (md_get_prop_data(mdp, node, physdev_propname, 9661ae08745Sheppo (uint8_t **)(&physname), &len) != 0) { 96734683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to get name(s) of physical " 96834683adeSsg70180 "device(s) from MD", vswp->instance); 96934683adeSsg70180 return (1); 9701ae08745Sheppo } else if ((strlen(physname) + 1) > LIFNAMSIZ) { 97134683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: %s is too long a device name", 97234683adeSsg70180 vswp->instance, physname); 97334683adeSsg70180 return (1); 974f2b610cfSwentaoy } else if (strcmp(myname, physname) == 0) { 975f2b610cfSwentaoy /* 976f2b610cfSwentaoy * Prevent the vswitch from opening itself as the 977f2b610cfSwentaoy * network device. 978f2b610cfSwentaoy */ 979f2b610cfSwentaoy cmn_err(CE_WARN, "!vsw%d: %s is an invalid device name", 980f2b610cfSwentaoy vswp->instance, physname); 981f2b610cfSwentaoy return (1); 9821ae08745Sheppo } else { 98334683adeSsg70180 (void) strncpy(name, physname, strlen(physname) + 1); 9841ae08745Sheppo D2(vswp, "%s: using first device specified (%s)", 98534683adeSsg70180 __func__, physname); 9861ae08745Sheppo } 9871ae08745Sheppo 9881ae08745Sheppo #ifdef DEBUG 9891ae08745Sheppo /* 9901ae08745Sheppo * As a temporary measure to aid testing we check to see if there 9911ae08745Sheppo * is a vsw.conf file present. If there is we use the value of the 9921ae08745Sheppo * vsw_physname property in the file as the name of the physical 9931ae08745Sheppo * device, overriding the value from the MD. 9941ae08745Sheppo * 9951ae08745Sheppo * There may be multiple devices listed, but for the moment 9961ae08745Sheppo * we just use the first one. 9971ae08745Sheppo */ 9981ae08745Sheppo if (ddi_prop_lookup_string(DDI_DEV_T_ANY, vswp->dip, 0, 9991ae08745Sheppo "vsw_physname", &dev) == DDI_PROP_SUCCESS) { 10001ae08745Sheppo if ((strlen(dev) + 1) > LIFNAMSIZ) { 100134683adeSsg70180 cmn_err(CE_WARN, "vsw%d: %s is too long a device name", 100234683adeSsg70180 vswp->instance, dev); 100334683adeSsg70180 ddi_prop_free(dev); 100434683adeSsg70180 return (1); 10051ae08745Sheppo } else { 100634683adeSsg70180 cmn_err(CE_NOTE, "vsw%d: Using device name (%s) from " 100734683adeSsg70180 "config file", vswp->instance, dev); 10081ae08745Sheppo 100934683adeSsg70180 (void) strncpy(name, dev, strlen(dev) + 1); 10101ae08745Sheppo } 10111ae08745Sheppo 10121ae08745Sheppo ddi_prop_free(dev); 10131ae08745Sheppo } 10141ae08745Sheppo #endif 10151ae08745Sheppo 101634683adeSsg70180 return (0); 101734683adeSsg70180 } 1018e1ebb9ecSlm66018 1019e1ebb9ecSlm66018 /* 102034683adeSsg70180 * Read the 'vsw-switch-mode' property from the specified MD node. 102134683adeSsg70180 * 1022da14cebeSEric Cheng * Returns 0 on success, otherwise returns 1. 1023e1ebb9ecSlm66018 */ 102434683adeSsg70180 static int 1025da14cebeSEric Cheng vsw_get_md_smodes(vsw_t *vswp, md_t *mdp, mde_cookie_t node, uint8_t *mode) 102634683adeSsg70180 { 102734683adeSsg70180 int len = 0; 102834683adeSsg70180 char *smode = NULL; 102934683adeSsg70180 char *curr_mode = NULL; 103034683adeSsg70180 103134683adeSsg70180 D1(vswp, "%s: enter", __func__); 10321ae08745Sheppo 10331ae08745Sheppo /* 10341ae08745Sheppo * Get the switch-mode property. The modes are listed in 10351ae08745Sheppo * decreasing order of preference, i.e. prefered mode is 10361ae08745Sheppo * first item in list. 10371ae08745Sheppo */ 10381ae08745Sheppo len = 0; 103934683adeSsg70180 if (md_get_prop_data(mdp, node, smode_propname, 10401ae08745Sheppo (uint8_t **)(&smode), &len) != 0) { 10411ae08745Sheppo /* 1042e1ebb9ecSlm66018 * Unable to get switch-mode property from MD, nothing 1043e1ebb9ecSlm66018 * more we can do. 10441ae08745Sheppo */ 104534683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to get switch mode property" 104634683adeSsg70180 " from the MD", vswp->instance); 104734683adeSsg70180 return (1); 1048e1ebb9ecSlm66018 } 1049e1ebb9ecSlm66018 10501ae08745Sheppo curr_mode = smode; 10511ae08745Sheppo /* 10521ae08745Sheppo * Modes of operation: 10531ae08745Sheppo * 'switched' - layer 2 switching, underlying HW in 1054e1ebb9ecSlm66018 * programmed mode. 10551ae08745Sheppo * 'promiscuous' - layer 2 switching, underlying HW in 10561ae08745Sheppo * promiscuous mode. 10571ae08745Sheppo * 'routed' - layer 3 (i.e. IP) routing, underlying HW 10581ae08745Sheppo * in non-promiscuous mode. 10591ae08745Sheppo */ 1060da14cebeSEric Cheng while (curr_mode < (smode + len)) { 10611ae08745Sheppo D2(vswp, "%s: curr_mode = [%s]", __func__, curr_mode); 1062e1ebb9ecSlm66018 if (strcmp(curr_mode, "switched") == 0) { 1063da14cebeSEric Cheng *mode = VSW_LAYER2; 1064e1ebb9ecSlm66018 } else if (strcmp(curr_mode, "promiscuous") == 0) { 1065da14cebeSEric Cheng *mode = VSW_LAYER2 | VSW_LAYER2_PROMISC; 1066e1ebb9ecSlm66018 } else if (strcmp(curr_mode, "routed") == 0) { 1067da14cebeSEric Cheng *mode = VSW_LAYER3; 1068e1ebb9ecSlm66018 } else { 1069da14cebeSEric Cheng cmn_err(CE_WARN, "!vsw%d: Unknown switch mode %s, " 1070da14cebeSEric Cheng "setting to default switched mode", 1071da14cebeSEric Cheng vswp->instance, curr_mode); 1072da14cebeSEric Cheng *mode = VSW_LAYER2; 10731ae08745Sheppo } 10741ae08745Sheppo curr_mode += strlen(curr_mode) + 1; 10751ae08745Sheppo } 10761ae08745Sheppo 1077da14cebeSEric Cheng D2(vswp, "%s: %d mode", __func__, *mode); 10781ae08745Sheppo 10791ae08745Sheppo D1(vswp, "%s: exit", __func__); 108034683adeSsg70180 108134683adeSsg70180 return (0); 10821ae08745Sheppo } 10831ae08745Sheppo 1084e1ebb9ecSlm66018 /* 10851ae08745Sheppo * Register with the MAC layer as a network device, so we 10861ae08745Sheppo * can be plumbed if necessary. 10871ae08745Sheppo */ 10881ae08745Sheppo static int 10891ae08745Sheppo vsw_mac_register(vsw_t *vswp) 10901ae08745Sheppo { 1091ba2e4443Sseb mac_register_t *macp; 1092ba2e4443Sseb int rv; 10931ae08745Sheppo 10941ae08745Sheppo D1(vswp, "%s: enter", __func__); 10951ae08745Sheppo 1096ba2e4443Sseb if ((macp = mac_alloc(MAC_VERSION)) == NULL) 1097ba2e4443Sseb return (EINVAL); 1098ba2e4443Sseb macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 10991ae08745Sheppo macp->m_driver = vswp; 1100ba2e4443Sseb macp->m_dip = vswp->dip; 1101ba2e4443Sseb macp->m_src_addr = (uint8_t *)&vswp->if_addr; 1102ba2e4443Sseb macp->m_callbacks = &vsw_m_callbacks; 1103ba2e4443Sseb macp->m_min_sdu = 0; 11047b1f684aSSriharsha Basavapatna macp->m_max_sdu = vswp->mtu; 1105c1c61f44Ssb155480 macp->m_margin = VLAN_TAGSZ; 1106ba2e4443Sseb rv = mac_register(macp, &vswp->if_mh); 1107ba2e4443Sseb mac_free(macp); 110819b65a69Ssb155480 if (rv != 0) { 110919b65a69Ssb155480 /* 111019b65a69Ssb155480 * Treat this as a non-fatal error as we may be 111119b65a69Ssb155480 * able to operate in some other mode. 111219b65a69Ssb155480 */ 111319b65a69Ssb155480 cmn_err(CE_NOTE, "!vsw%d: Unable to register as " 111419b65a69Ssb155480 "a provider with MAC layer", vswp->instance); 111519b65a69Ssb155480 return (rv); 111619b65a69Ssb155480 } 111719b65a69Ssb155480 1118ba2e4443Sseb vswp->if_state |= VSW_IF_REG; 11191ae08745Sheppo 11201ae08745Sheppo D1(vswp, "%s: exit", __func__); 11211ae08745Sheppo 11221ae08745Sheppo return (rv); 11231ae08745Sheppo } 11241ae08745Sheppo 11251ae08745Sheppo static int 11261ae08745Sheppo vsw_mac_unregister(vsw_t *vswp) 11271ae08745Sheppo { 11281ae08745Sheppo int rv = 0; 11291ae08745Sheppo 11301ae08745Sheppo D1(vswp, "%s: enter", __func__); 11311ae08745Sheppo 11321ae08745Sheppo WRITE_ENTER(&vswp->if_lockrw); 11331ae08745Sheppo 1134ba2e4443Sseb if (vswp->if_state & VSW_IF_REG) { 1135ba2e4443Sseb rv = mac_unregister(vswp->if_mh); 11361ae08745Sheppo if (rv != 0) { 11371ae08745Sheppo DWARN(vswp, "%s: unable to unregister from MAC " 11381ae08745Sheppo "framework", __func__); 11391ae08745Sheppo 11401ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 11411ae08745Sheppo D1(vswp, "%s: fail exit", __func__); 11421ae08745Sheppo return (rv); 11431ae08745Sheppo } 11441ae08745Sheppo 1145ba2e4443Sseb /* mark i/f as down and unregistered */ 1146ba2e4443Sseb vswp->if_state &= ~(VSW_IF_UP | VSW_IF_REG); 11471ae08745Sheppo } 11481ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 11491ae08745Sheppo 11501ae08745Sheppo D1(vswp, "%s: exit", __func__); 11511ae08745Sheppo 11521ae08745Sheppo return (rv); 11531ae08745Sheppo } 11541ae08745Sheppo 1155ba2e4443Sseb static int 1156ba2e4443Sseb vsw_m_stat(void *arg, uint_t stat, uint64_t *val) 11571ae08745Sheppo { 11581ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 11591ae08745Sheppo 11601ae08745Sheppo D1(vswp, "%s: enter", __func__); 11611ae08745Sheppo 1162da14cebeSEric Cheng mutex_enter(&vswp->mac_lock); 116334683adeSsg70180 if (vswp->mh == NULL) { 1164da14cebeSEric Cheng mutex_exit(&vswp->mac_lock); 1165ba2e4443Sseb return (EINVAL); 116634683adeSsg70180 } 11671ae08745Sheppo 11681ae08745Sheppo /* return stats from underlying device */ 1169ba2e4443Sseb *val = mac_stat_get(vswp->mh, stat); 117034683adeSsg70180 1171da14cebeSEric Cheng mutex_exit(&vswp->mac_lock); 117234683adeSsg70180 1173ba2e4443Sseb return (0); 11741ae08745Sheppo } 11751ae08745Sheppo 11761ae08745Sheppo static void 11771ae08745Sheppo vsw_m_stop(void *arg) 11781ae08745Sheppo { 11791ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 11801ae08745Sheppo 11811ae08745Sheppo D1(vswp, "%s: enter", __func__); 11821ae08745Sheppo 11831ae08745Sheppo WRITE_ENTER(&vswp->if_lockrw); 11841ae08745Sheppo vswp->if_state &= ~VSW_IF_UP; 11851ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 11861ae08745Sheppo 1187da14cebeSEric Cheng /* Cleanup and close the mac client */ 1188da14cebeSEric Cheng vsw_mac_client_cleanup(vswp, NULL, VSW_LOCALDEV); 11895f94e909Ssg70180 11901ae08745Sheppo D1(vswp, "%s: exit (state = %d)", __func__, vswp->if_state); 11911ae08745Sheppo } 11921ae08745Sheppo 11931ae08745Sheppo static int 11941ae08745Sheppo vsw_m_start(void *arg) 11951ae08745Sheppo { 1196da14cebeSEric Cheng int rv; 11971ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 11981ae08745Sheppo 11991ae08745Sheppo D1(vswp, "%s: enter", __func__); 12001ae08745Sheppo 12011ae08745Sheppo WRITE_ENTER(&vswp->if_lockrw); 12021ae08745Sheppo 120319b65a69Ssb155480 vswp->if_state |= VSW_IF_UP; 120419b65a69Ssb155480 120519b65a69Ssb155480 if (vswp->switching_setup_done == B_FALSE) { 120619b65a69Ssb155480 /* 120719b65a69Ssb155480 * If the switching mode has not been setup yet, just 120819b65a69Ssb155480 * return. The unicast address will be programmed 120919b65a69Ssb155480 * after the physical device is successfully setup by the 121019b65a69Ssb155480 * timeout handler. 121119b65a69Ssb155480 */ 121219b65a69Ssb155480 RW_EXIT(&vswp->if_lockrw); 121319b65a69Ssb155480 return (0); 121419b65a69Ssb155480 } 121519b65a69Ssb155480 121619b65a69Ssb155480 /* if in layer2 mode, program unicast address. */ 121719b65a69Ssb155480 if (vswp->mh != NULL) { 1218da14cebeSEric Cheng /* Init a mac client and program addresses */ 1219da14cebeSEric Cheng rv = vsw_mac_client_init(vswp, NULL, VSW_LOCALDEV); 1220da14cebeSEric Cheng if (rv != 0) { 1221da14cebeSEric Cheng cmn_err(CE_NOTE, 1222da14cebeSEric Cheng "!vsw%d: failed to program interface " 1223da14cebeSEric Cheng "unicast address\n", vswp->instance); 1224da14cebeSEric Cheng } 122519b65a69Ssb155480 } 122619b65a69Ssb155480 122719b65a69Ssb155480 RW_EXIT(&vswp->if_lockrw); 12285f94e909Ssg70180 12291ae08745Sheppo D1(vswp, "%s: exit (state = %d)", __func__, vswp->if_state); 12301ae08745Sheppo return (0); 12311ae08745Sheppo } 12321ae08745Sheppo 12331ae08745Sheppo /* 12341ae08745Sheppo * Change the local interface address. 12355f94e909Ssg70180 * 12365f94e909Ssg70180 * Note: we don't support this entry point. The local 12375f94e909Ssg70180 * mac address of the switch can only be changed via its 12385f94e909Ssg70180 * MD node properties. 12391ae08745Sheppo */ 12401ae08745Sheppo static int 12411ae08745Sheppo vsw_m_unicst(void *arg, const uint8_t *macaddr) 12421ae08745Sheppo { 12435f94e909Ssg70180 _NOTE(ARGUNUSED(arg, macaddr)) 12441ae08745Sheppo 12455f94e909Ssg70180 return (DDI_FAILURE); 12461ae08745Sheppo } 12471ae08745Sheppo 12481ae08745Sheppo static int 12491ae08745Sheppo vsw_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 12501ae08745Sheppo { 12511ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 12521ae08745Sheppo mcst_addr_t *mcst_p = NULL; 12531ae08745Sheppo uint64_t addr = 0x0; 1254e1ebb9ecSlm66018 int i, ret = 0; 12551ae08745Sheppo 12561ae08745Sheppo D1(vswp, "%s: enter", __func__); 12571ae08745Sheppo 12581ae08745Sheppo /* 12591ae08745Sheppo * Convert address into form that can be used 12601ae08745Sheppo * as hash table key. 12611ae08745Sheppo */ 12621ae08745Sheppo for (i = 0; i < ETHERADDRL; i++) { 12631ae08745Sheppo addr = (addr << 8) | mca[i]; 12641ae08745Sheppo } 12651ae08745Sheppo 12661ae08745Sheppo D2(vswp, "%s: addr = 0x%llx", __func__, addr); 12671ae08745Sheppo 12681ae08745Sheppo if (add) { 12691ae08745Sheppo D2(vswp, "%s: adding multicast", __func__); 12701ae08745Sheppo if (vsw_add_mcst(vswp, VSW_LOCALDEV, addr, NULL) == 0) { 12711ae08745Sheppo /* 12721ae08745Sheppo * Update the list of multicast addresses 12731ae08745Sheppo * contained within the vsw_t structure to 12741ae08745Sheppo * include this new one. 12751ae08745Sheppo */ 12761ae08745Sheppo mcst_p = kmem_zalloc(sizeof (mcst_addr_t), KM_NOSLEEP); 12771ae08745Sheppo if (mcst_p == NULL) { 12781ae08745Sheppo DERR(vswp, "%s unable to alloc mem", __func__); 127919b65a69Ssb155480 (void) vsw_del_mcst(vswp, 128019b65a69Ssb155480 VSW_LOCALDEV, addr, NULL); 12811ae08745Sheppo return (1); 12821ae08745Sheppo } 12831ae08745Sheppo mcst_p->addr = addr; 128419b65a69Ssb155480 ether_copy(mca, &mcst_p->mca); 12851ae08745Sheppo 12861ae08745Sheppo /* 12871ae08745Sheppo * Call into the underlying driver to program the 12881ae08745Sheppo * address into HW. 12891ae08745Sheppo */ 1290da14cebeSEric Cheng ret = vsw_mac_multicast_add(vswp, NULL, mcst_p, 1291da14cebeSEric Cheng VSW_LOCALDEV); 1292e1ebb9ecSlm66018 if (ret != 0) { 129319b65a69Ssb155480 (void) vsw_del_mcst(vswp, 129419b65a69Ssb155480 VSW_LOCALDEV, addr, NULL); 129519b65a69Ssb155480 kmem_free(mcst_p, sizeof (*mcst_p)); 129619b65a69Ssb155480 return (ret); 1297e1ebb9ecSlm66018 } 129819b65a69Ssb155480 129919b65a69Ssb155480 mutex_enter(&vswp->mca_lock); 130019b65a69Ssb155480 mcst_p->nextp = vswp->mcap; 130119b65a69Ssb155480 vswp->mcap = mcst_p; 130219b65a69Ssb155480 mutex_exit(&vswp->mca_lock); 13031ae08745Sheppo } else { 1304da14cebeSEric Cheng cmn_err(CE_WARN, "!vsw%d: unable to add multicast " 130534683adeSsg70180 "address", vswp->instance); 1306e1ebb9ecSlm66018 } 1307e1ebb9ecSlm66018 return (ret); 1308e1ebb9ecSlm66018 } 1309e1ebb9ecSlm66018 13101ae08745Sheppo D2(vswp, "%s: removing multicast", __func__); 13111ae08745Sheppo /* 13121ae08745Sheppo * Remove the address from the hash table.. 13131ae08745Sheppo */ 13141ae08745Sheppo if (vsw_del_mcst(vswp, VSW_LOCALDEV, addr, NULL) == 0) { 13151ae08745Sheppo 13161ae08745Sheppo /* 13171ae08745Sheppo * ..and then from the list maintained in the 13181ae08745Sheppo * vsw_t structure. 13191ae08745Sheppo */ 132019b65a69Ssb155480 mcst_p = vsw_del_addr(VSW_LOCALDEV, vswp, addr); 132119b65a69Ssb155480 ASSERT(mcst_p != NULL); 13221ae08745Sheppo 1323da14cebeSEric Cheng vsw_mac_multicast_remove(vswp, NULL, mcst_p, VSW_LOCALDEV); 132419b65a69Ssb155480 kmem_free(mcst_p, sizeof (*mcst_p)); 13251ae08745Sheppo } 13261ae08745Sheppo 13271ae08745Sheppo D1(vswp, "%s: exit", __func__); 13281ae08745Sheppo 13291ae08745Sheppo return (0); 13301ae08745Sheppo } 13311ae08745Sheppo 13321ae08745Sheppo static int 13331ae08745Sheppo vsw_m_promisc(void *arg, boolean_t on) 13341ae08745Sheppo { 13351ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 13361ae08745Sheppo 13371ae08745Sheppo D1(vswp, "%s: enter", __func__); 13381ae08745Sheppo 13391ae08745Sheppo WRITE_ENTER(&vswp->if_lockrw); 13401ae08745Sheppo if (on) 13411ae08745Sheppo vswp->if_state |= VSW_IF_PROMISC; 13421ae08745Sheppo else 13431ae08745Sheppo vswp->if_state &= ~VSW_IF_PROMISC; 13441ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 13451ae08745Sheppo 13461ae08745Sheppo D1(vswp, "%s: exit", __func__); 13471ae08745Sheppo 13481ae08745Sheppo return (0); 13491ae08745Sheppo } 13501ae08745Sheppo 13511ae08745Sheppo static mblk_t * 13521ae08745Sheppo vsw_m_tx(void *arg, mblk_t *mp) 13531ae08745Sheppo { 13541ae08745Sheppo vsw_t *vswp = (vsw_t *)arg; 13551ae08745Sheppo 13561ae08745Sheppo D1(vswp, "%s: enter", __func__); 13571ae08745Sheppo 1358c1c61f44Ssb155480 mp = vsw_vlan_frame_pretag(vswp, VSW_LOCALDEV, mp); 1359c1c61f44Ssb155480 1360c1c61f44Ssb155480 if (mp == NULL) { 1361c1c61f44Ssb155480 return (NULL); 1362c1c61f44Ssb155480 } 1363c1c61f44Ssb155480 136434683adeSsg70180 vswp->vsw_switch_frame(vswp, mp, VSW_LOCALDEV, NULL, NULL); 13651ae08745Sheppo 13661ae08745Sheppo D1(vswp, "%s: exit", __func__); 13671ae08745Sheppo 13681ae08745Sheppo return (NULL); 13691ae08745Sheppo } 13701ae08745Sheppo 13711ae08745Sheppo /* 13721ae08745Sheppo * Register for machine description (MD) updates. 137334683adeSsg70180 * 137434683adeSsg70180 * Returns 0 on success, 1 on failure. 13751ae08745Sheppo */ 137634683adeSsg70180 static int 13771ae08745Sheppo vsw_mdeg_register(vsw_t *vswp) 13781ae08745Sheppo { 13791ae08745Sheppo mdeg_prop_spec_t *pspecp; 13801ae08745Sheppo mdeg_node_spec_t *inst_specp; 138134683adeSsg70180 mdeg_handle_t mdeg_hdl, mdeg_port_hdl; 13821ae08745Sheppo size_t templatesz; 138319b65a69Ssb155480 int rv; 13841ae08745Sheppo 13851ae08745Sheppo D1(vswp, "%s: enter", __func__); 13861ae08745Sheppo 138734683adeSsg70180 /* 13881ae08745Sheppo * Allocate and initialize a per-instance copy 13891ae08745Sheppo * of the global property spec array that will 13901ae08745Sheppo * uniquely identify this vsw instance. 13911ae08745Sheppo */ 13921ae08745Sheppo templatesz = sizeof (vsw_prop_template); 13931ae08745Sheppo pspecp = kmem_zalloc(templatesz, KM_SLEEP); 13941ae08745Sheppo 13951ae08745Sheppo bcopy(vsw_prop_template, pspecp, templatesz); 13961ae08745Sheppo 139719b65a69Ssb155480 VSW_SET_MDEG_PROP_INST(pspecp, vswp->regprop); 13981ae08745Sheppo 13991ae08745Sheppo /* initialize the complete prop spec structure */ 14001ae08745Sheppo inst_specp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_SLEEP); 14011ae08745Sheppo inst_specp->namep = "virtual-device"; 14021ae08745Sheppo inst_specp->specp = pspecp; 14031ae08745Sheppo 140419b65a69Ssb155480 D2(vswp, "%s: instance %d registering with mdeg", __func__, 140519b65a69Ssb155480 vswp->regprop); 140634683adeSsg70180 /* 140734683adeSsg70180 * Register an interest in 'virtual-device' nodes with a 140834683adeSsg70180 * 'name' property of 'virtual-network-switch' 140934683adeSsg70180 */ 141034683adeSsg70180 rv = mdeg_register(inst_specp, &vdev_match, vsw_mdeg_cb, 14111ae08745Sheppo (void *)vswp, &mdeg_hdl); 141234683adeSsg70180 if (rv != MDEG_SUCCESS) { 141334683adeSsg70180 DERR(vswp, "%s: mdeg_register failed (%d) for vsw node", 141434683adeSsg70180 __func__, rv); 141534683adeSsg70180 goto mdeg_reg_fail; 141634683adeSsg70180 } 14171ae08745Sheppo 141834683adeSsg70180 /* 141934683adeSsg70180 * Register an interest in 'vsw-port' nodes. 142034683adeSsg70180 */ 142134683adeSsg70180 rv = mdeg_register(inst_specp, &vport_match, vsw_port_mdeg_cb, 142234683adeSsg70180 (void *)vswp, &mdeg_port_hdl); 14231ae08745Sheppo if (rv != MDEG_SUCCESS) { 14241ae08745Sheppo DERR(vswp, "%s: mdeg_register failed (%d)\n", __func__, rv); 142534683adeSsg70180 (void) mdeg_unregister(mdeg_hdl); 142634683adeSsg70180 goto mdeg_reg_fail; 14271ae08745Sheppo } 14281ae08745Sheppo 14291ae08745Sheppo /* save off data that will be needed later */ 14301ae08745Sheppo vswp->inst_spec = inst_specp; 14311ae08745Sheppo vswp->mdeg_hdl = mdeg_hdl; 143234683adeSsg70180 vswp->mdeg_port_hdl = mdeg_port_hdl; 14331ae08745Sheppo 14341ae08745Sheppo D1(vswp, "%s: exit", __func__); 143534683adeSsg70180 return (0); 143634683adeSsg70180 143734683adeSsg70180 mdeg_reg_fail: 143834683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to register MDEG callbacks", 143934683adeSsg70180 vswp->instance); 144034683adeSsg70180 kmem_free(pspecp, templatesz); 144134683adeSsg70180 kmem_free(inst_specp, sizeof (mdeg_node_spec_t)); 144234683adeSsg70180 144334683adeSsg70180 vswp->mdeg_hdl = NULL; 144434683adeSsg70180 vswp->mdeg_port_hdl = NULL; 144534683adeSsg70180 144634683adeSsg70180 return (1); 14471ae08745Sheppo } 14481ae08745Sheppo 14491ae08745Sheppo static void 14501ae08745Sheppo vsw_mdeg_unregister(vsw_t *vswp) 14511ae08745Sheppo { 14521ae08745Sheppo D1(vswp, "vsw_mdeg_unregister: enter"); 14531ae08745Sheppo 145434683adeSsg70180 if (vswp->mdeg_hdl != NULL) 14551ae08745Sheppo (void) mdeg_unregister(vswp->mdeg_hdl); 14561ae08745Sheppo 145734683adeSsg70180 if (vswp->mdeg_port_hdl != NULL) 145834683adeSsg70180 (void) mdeg_unregister(vswp->mdeg_port_hdl); 145934683adeSsg70180 146034683adeSsg70180 if (vswp->inst_spec != NULL) { 14611ae08745Sheppo if (vswp->inst_spec->specp != NULL) { 14621ae08745Sheppo (void) kmem_free(vswp->inst_spec->specp, 14631ae08745Sheppo sizeof (vsw_prop_template)); 14641ae08745Sheppo vswp->inst_spec->specp = NULL; 14651ae08745Sheppo } 14661ae08745Sheppo 1467205eeb1aSlm66018 (void) kmem_free(vswp->inst_spec, sizeof (mdeg_node_spec_t)); 14681ae08745Sheppo vswp->inst_spec = NULL; 14691ae08745Sheppo } 14701ae08745Sheppo 14711ae08745Sheppo D1(vswp, "vsw_mdeg_unregister: exit"); 14721ae08745Sheppo } 14731ae08745Sheppo 147434683adeSsg70180 /* 147534683adeSsg70180 * Mdeg callback invoked for the vsw node itself. 147634683adeSsg70180 */ 14771ae08745Sheppo static int 14781ae08745Sheppo vsw_mdeg_cb(void *cb_argp, mdeg_result_t *resp) 14791ae08745Sheppo { 14801ae08745Sheppo vsw_t *vswp; 14811ae08745Sheppo md_t *mdp; 14821ae08745Sheppo mde_cookie_t node; 14831ae08745Sheppo uint64_t inst; 148434683adeSsg70180 char *node_name = NULL; 14851ae08745Sheppo 14861ae08745Sheppo if (resp == NULL) 14871ae08745Sheppo return (MDEG_FAILURE); 14881ae08745Sheppo 14891ae08745Sheppo vswp = (vsw_t *)cb_argp; 14901ae08745Sheppo 149134683adeSsg70180 D1(vswp, "%s: added %d : removed %d : curr matched %d" 149234683adeSsg70180 " : prev matched %d", __func__, resp->added.nelem, 149334683adeSsg70180 resp->removed.nelem, resp->match_curr.nelem, 149434683adeSsg70180 resp->match_prev.nelem); 149534683adeSsg70180 149634683adeSsg70180 /* 149719b65a69Ssb155480 * We get an initial callback for this node as 'added' 149819b65a69Ssb155480 * after registering with mdeg. Note that we would have 149919b65a69Ssb155480 * already gathered information about this vsw node by 150019b65a69Ssb155480 * walking MD earlier during attach (in vsw_read_mdprops()). 150119b65a69Ssb155480 * So, there is a window where the properties of this 150219b65a69Ssb155480 * node might have changed when we get this initial 'added' 150319b65a69Ssb155480 * callback. We handle this as if an update occured 150419b65a69Ssb155480 * and invoke the same function which handles updates to 150519b65a69Ssb155480 * the properties of this vsw-node if any. 150619b65a69Ssb155480 * 150734683adeSsg70180 * A non-zero 'match' value indicates that the MD has been 150819b65a69Ssb155480 * updated and that a virtual-network-switch node is 150919b65a69Ssb155480 * present which may or may not have been updated. It is 151019b65a69Ssb155480 * up to the clients to examine their own nodes and 151119b65a69Ssb155480 * determine if they have changed. 151234683adeSsg70180 */ 151319b65a69Ssb155480 if (resp->added.nelem != 0) { 151434683adeSsg70180 151519b65a69Ssb155480 if (resp->added.nelem != 1) { 151619b65a69Ssb155480 cmn_err(CE_NOTE, "!vsw%d: number of nodes added " 151719b65a69Ssb155480 "invalid: %d\n", vswp->instance, resp->added.nelem); 151819b65a69Ssb155480 return (MDEG_FAILURE); 151919b65a69Ssb155480 } 152019b65a69Ssb155480 152119b65a69Ssb155480 mdp = resp->added.mdp; 152219b65a69Ssb155480 node = resp->added.mdep[0]; 152319b65a69Ssb155480 152419b65a69Ssb155480 } else if (resp->match_curr.nelem != 0) { 152519b65a69Ssb155480 152619b65a69Ssb155480 if (resp->match_curr.nelem != 1) { 152719b65a69Ssb155480 cmn_err(CE_NOTE, "!vsw%d: number of nodes updated " 152819b65a69Ssb155480 "invalid: %d\n", vswp->instance, 152919b65a69Ssb155480 resp->match_curr.nelem); 153019b65a69Ssb155480 return (MDEG_FAILURE); 153119b65a69Ssb155480 } 153219b65a69Ssb155480 153319b65a69Ssb155480 mdp = resp->match_curr.mdp; 153419b65a69Ssb155480 node = resp->match_curr.mdep[0]; 153519b65a69Ssb155480 153619b65a69Ssb155480 } else { 153719b65a69Ssb155480 return (MDEG_FAILURE); 153819b65a69Ssb155480 } 153919b65a69Ssb155480 154019b65a69Ssb155480 /* Validate name and instance */ 154134683adeSsg70180 if (md_get_prop_str(mdp, node, "name", &node_name) != 0) { 154219b65a69Ssb155480 DERR(vswp, "%s: unable to get node name\n", __func__); 154319b65a69Ssb155480 return (MDEG_FAILURE); 154419b65a69Ssb155480 } 154519b65a69Ssb155480 154619b65a69Ssb155480 /* is this a virtual-network-switch? */ 154719b65a69Ssb155480 if (strcmp(node_name, vsw_propname) != 0) { 154819b65a69Ssb155480 DERR(vswp, "%s: Invalid node name: %s\n", 154919b65a69Ssb155480 __func__, node_name); 155019b65a69Ssb155480 return (MDEG_FAILURE); 155134683adeSsg70180 } 155234683adeSsg70180 155334683adeSsg70180 if (md_get_prop_val(mdp, node, "cfg-handle", &inst)) { 155419b65a69Ssb155480 DERR(vswp, "%s: prop(cfg-handle) not found\n", 155519b65a69Ssb155480 __func__); 155619b65a69Ssb155480 return (MDEG_FAILURE); 155734683adeSsg70180 } 155834683adeSsg70180 155919b65a69Ssb155480 /* is this the right instance of vsw? */ 156019b65a69Ssb155480 if (inst != vswp->regprop) { 156119b65a69Ssb155480 DERR(vswp, "%s: Invalid cfg-handle: %lx\n", 156219b65a69Ssb155480 __func__, inst); 156319b65a69Ssb155480 return (MDEG_FAILURE); 156419b65a69Ssb155480 } 156534683adeSsg70180 156634683adeSsg70180 vsw_update_md_prop(vswp, mdp, node); 156734683adeSsg70180 156834683adeSsg70180 return (MDEG_SUCCESS); 156934683adeSsg70180 } 157034683adeSsg70180 157134683adeSsg70180 /* 157234683adeSsg70180 * Mdeg callback invoked for changes to the vsw-port nodes 157334683adeSsg70180 * under the vsw node. 157434683adeSsg70180 */ 157534683adeSsg70180 static int 157634683adeSsg70180 vsw_port_mdeg_cb(void *cb_argp, mdeg_result_t *resp) 157734683adeSsg70180 { 157834683adeSsg70180 vsw_t *vswp; 157934683adeSsg70180 int idx; 158034683adeSsg70180 md_t *mdp; 158134683adeSsg70180 mde_cookie_t node; 158234683adeSsg70180 uint64_t inst; 15831ef0bbb5Snarayan int rv; 158434683adeSsg70180 158534683adeSsg70180 if ((resp == NULL) || (cb_argp == NULL)) 158634683adeSsg70180 return (MDEG_FAILURE); 158734683adeSsg70180 158834683adeSsg70180 vswp = (vsw_t *)cb_argp; 158934683adeSsg70180 159034683adeSsg70180 D2(vswp, "%s: added %d : removed %d : curr matched %d" 159134683adeSsg70180 " : prev matched %d", __func__, resp->added.nelem, 159234683adeSsg70180 resp->removed.nelem, resp->match_curr.nelem, 15931ae08745Sheppo resp->match_prev.nelem); 15941ae08745Sheppo 15951ae08745Sheppo /* process added ports */ 15961ae08745Sheppo for (idx = 0; idx < resp->added.nelem; idx++) { 15971ae08745Sheppo mdp = resp->added.mdp; 15981ae08745Sheppo node = resp->added.mdep[idx]; 15991ae08745Sheppo 16001ae08745Sheppo D2(vswp, "%s: adding node(%d) 0x%lx", __func__, idx, node); 16011ae08745Sheppo 16021ef0bbb5Snarayan if ((rv = vsw_port_add(vswp, mdp, &node)) != 0) { 160334683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to add new port " 16041ef0bbb5Snarayan "(0x%lx), err=%d", vswp->instance, node, rv); 16051ae08745Sheppo } 16061ae08745Sheppo } 16071ae08745Sheppo 16081ae08745Sheppo /* process removed ports */ 16091ae08745Sheppo for (idx = 0; idx < resp->removed.nelem; idx++) { 16101ae08745Sheppo mdp = resp->removed.mdp; 16111ae08745Sheppo node = resp->removed.mdep[idx]; 16121ae08745Sheppo 16131ae08745Sheppo if (md_get_prop_val(mdp, node, id_propname, &inst)) { 161434683adeSsg70180 DERR(vswp, "%s: prop(%s) not found in port(%d)", 16151ae08745Sheppo __func__, id_propname, idx); 16161ae08745Sheppo continue; 16171ae08745Sheppo } 16181ae08745Sheppo 16191ae08745Sheppo D2(vswp, "%s: removing node(%d) 0x%lx", __func__, idx, node); 16201ae08745Sheppo 16211ae08745Sheppo if (vsw_port_detach(vswp, inst) != 0) { 162234683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to remove port %ld", 162334683adeSsg70180 vswp->instance, inst); 16241ae08745Sheppo } 16251ae08745Sheppo } 16261ae08745Sheppo 1627c1c61f44Ssb155480 for (idx = 0; idx < resp->match_curr.nelem; idx++) { 1628c1c61f44Ssb155480 (void) vsw_port_update(vswp, resp->match_curr.mdp, 1629c1c61f44Ssb155480 resp->match_curr.mdep[idx], 1630c1c61f44Ssb155480 resp->match_prev.mdp, 1631c1c61f44Ssb155480 resp->match_prev.mdep[idx]); 1632c1c61f44Ssb155480 } 16331ae08745Sheppo 16341ae08745Sheppo D1(vswp, "%s: exit", __func__); 16351ae08745Sheppo 16361ae08745Sheppo return (MDEG_SUCCESS); 16371ae08745Sheppo } 16381ae08745Sheppo 16391ae08745Sheppo /* 164019b65a69Ssb155480 * Scan the machine description for this instance of vsw 164119b65a69Ssb155480 * and read its properties. Called only from vsw_attach(). 164219b65a69Ssb155480 * Returns: 0 on success, 1 on failure. 164319b65a69Ssb155480 */ 164419b65a69Ssb155480 static int 164519b65a69Ssb155480 vsw_read_mdprops(vsw_t *vswp) 164619b65a69Ssb155480 { 164719b65a69Ssb155480 md_t *mdp = NULL; 164819b65a69Ssb155480 mde_cookie_t rootnode; 164919b65a69Ssb155480 mde_cookie_t *listp = NULL; 165019b65a69Ssb155480 uint64_t inst; 165119b65a69Ssb155480 uint64_t cfgh; 165219b65a69Ssb155480 char *name; 165319b65a69Ssb155480 int rv = 1; 165419b65a69Ssb155480 int num_nodes = 0; 165519b65a69Ssb155480 int num_devs = 0; 165619b65a69Ssb155480 int listsz = 0; 165719b65a69Ssb155480 int i; 165819b65a69Ssb155480 165919b65a69Ssb155480 /* 166019b65a69Ssb155480 * In each 'virtual-device' node in the MD there is a 166119b65a69Ssb155480 * 'cfg-handle' property which is the MD's concept of 166219b65a69Ssb155480 * an instance number (this may be completely different from 166319b65a69Ssb155480 * the device drivers instance #). OBP reads that value and 166419b65a69Ssb155480 * stores it in the 'reg' property of the appropriate node in 166519b65a69Ssb155480 * the device tree. We first read this reg property and use this 166619b65a69Ssb155480 * to compare against the 'cfg-handle' property of vsw nodes 166719b65a69Ssb155480 * in MD to get to this specific vsw instance and then read 166819b65a69Ssb155480 * other properties that we are interested in. 166919b65a69Ssb155480 * We also cache the value of 'reg' property and use it later 167019b65a69Ssb155480 * to register callbacks with mdeg (see vsw_mdeg_register()) 167119b65a69Ssb155480 */ 167219b65a69Ssb155480 inst = ddi_prop_get_int(DDI_DEV_T_ANY, vswp->dip, 167319b65a69Ssb155480 DDI_PROP_DONTPASS, reg_propname, -1); 167419b65a69Ssb155480 if (inst == -1) { 167519b65a69Ssb155480 cmn_err(CE_NOTE, "!vsw%d: Unable to read %s property from " 167619b65a69Ssb155480 "OBP device tree", vswp->instance, reg_propname); 167719b65a69Ssb155480 return (rv); 167819b65a69Ssb155480 } 167919b65a69Ssb155480 168019b65a69Ssb155480 vswp->regprop = inst; 168119b65a69Ssb155480 168219b65a69Ssb155480 if ((mdp = md_get_handle()) == NULL) { 168319b65a69Ssb155480 DWARN(vswp, "%s: cannot init MD\n", __func__); 168419b65a69Ssb155480 return (rv); 168519b65a69Ssb155480 } 168619b65a69Ssb155480 168719b65a69Ssb155480 num_nodes = md_node_count(mdp); 168819b65a69Ssb155480 ASSERT(num_nodes > 0); 168919b65a69Ssb155480 169019b65a69Ssb155480 listsz = num_nodes * sizeof (mde_cookie_t); 169119b65a69Ssb155480 listp = (mde_cookie_t *)kmem_zalloc(listsz, KM_SLEEP); 169219b65a69Ssb155480 169319b65a69Ssb155480 rootnode = md_root_node(mdp); 169419b65a69Ssb155480 169519b65a69Ssb155480 /* search for all "virtual_device" nodes */ 169619b65a69Ssb155480 num_devs = md_scan_dag(mdp, rootnode, 169719b65a69Ssb155480 md_find_name(mdp, vdev_propname), 169819b65a69Ssb155480 md_find_name(mdp, "fwd"), listp); 169919b65a69Ssb155480 if (num_devs <= 0) { 170019b65a69Ssb155480 DWARN(vswp, "%s: invalid num_devs:%d\n", __func__, num_devs); 170119b65a69Ssb155480 goto vsw_readmd_exit; 170219b65a69Ssb155480 } 170319b65a69Ssb155480 170419b65a69Ssb155480 /* 170519b65a69Ssb155480 * Now loop through the list of virtual-devices looking for 170619b65a69Ssb155480 * devices with name "virtual-network-switch" and for each 170719b65a69Ssb155480 * such device compare its instance with what we have from 170819b65a69Ssb155480 * the 'reg' property to find the right node in MD and then 170919b65a69Ssb155480 * read all its properties. 171019b65a69Ssb155480 */ 171119b65a69Ssb155480 for (i = 0; i < num_devs; i++) { 171219b65a69Ssb155480 171319b65a69Ssb155480 if (md_get_prop_str(mdp, listp[i], "name", &name) != 0) { 171419b65a69Ssb155480 DWARN(vswp, "%s: name property not found\n", 171519b65a69Ssb155480 __func__); 171619b65a69Ssb155480 goto vsw_readmd_exit; 171719b65a69Ssb155480 } 171819b65a69Ssb155480 171919b65a69Ssb155480 /* is this a virtual-network-switch? */ 172019b65a69Ssb155480 if (strcmp(name, vsw_propname) != 0) 172119b65a69Ssb155480 continue; 172219b65a69Ssb155480 172319b65a69Ssb155480 if (md_get_prop_val(mdp, listp[i], "cfg-handle", &cfgh) != 0) { 172419b65a69Ssb155480 DWARN(vswp, "%s: cfg-handle property not found\n", 172519b65a69Ssb155480 __func__); 172619b65a69Ssb155480 goto vsw_readmd_exit; 172719b65a69Ssb155480 } 172819b65a69Ssb155480 172919b65a69Ssb155480 /* is this the required instance of vsw? */ 173019b65a69Ssb155480 if (inst != cfgh) 173119b65a69Ssb155480 continue; 173219b65a69Ssb155480 173319b65a69Ssb155480 /* now read all properties of this vsw instance */ 173419b65a69Ssb155480 rv = vsw_get_initial_md_properties(vswp, mdp, listp[i]); 173519b65a69Ssb155480 break; 173619b65a69Ssb155480 } 173719b65a69Ssb155480 173819b65a69Ssb155480 vsw_readmd_exit: 173919b65a69Ssb155480 174019b65a69Ssb155480 kmem_free(listp, listsz); 174119b65a69Ssb155480 (void) md_fini_handle(mdp); 174219b65a69Ssb155480 return (rv); 174319b65a69Ssb155480 } 174419b65a69Ssb155480 174519b65a69Ssb155480 /* 174634683adeSsg70180 * Read the initial start-of-day values from the specified MD node. 174734683adeSsg70180 */ 174819b65a69Ssb155480 static int 174934683adeSsg70180 vsw_get_initial_md_properties(vsw_t *vswp, md_t *mdp, mde_cookie_t node) 175034683adeSsg70180 { 175134683adeSsg70180 uint64_t macaddr = 0; 175234683adeSsg70180 175334683adeSsg70180 D1(vswp, "%s: enter", __func__); 175434683adeSsg70180 175519b65a69Ssb155480 if (vsw_get_md_physname(vswp, mdp, node, vswp->physname) != 0) { 175619b65a69Ssb155480 return (1); 175734683adeSsg70180 } 175834683adeSsg70180 175934683adeSsg70180 /* mac address for vswitch device itself */ 176034683adeSsg70180 if (md_get_prop_val(mdp, node, macaddr_propname, &macaddr) != 0) { 176134683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to get MAC address from MD", 176234683adeSsg70180 vswp->instance); 176319b65a69Ssb155480 return (1); 176419b65a69Ssb155480 } 176534683adeSsg70180 176619b65a69Ssb155480 vsw_save_lmacaddr(vswp, macaddr); 176734683adeSsg70180 1768da14cebeSEric Cheng if (vsw_get_md_smodes(vswp, mdp, node, &vswp->smode)) { 17691ef0bbb5Snarayan DWARN(vswp, "%s: Unable to read %s property from MD, " 17701ef0bbb5Snarayan "defaulting to 'switched' mode", 17711ef0bbb5Snarayan __func__, smode_propname); 177234683adeSsg70180 1773da14cebeSEric Cheng vswp->smode = VSW_LAYER2; 177434683adeSsg70180 } 177534683adeSsg70180 17761107ea93SSriharsha Basavapatna /* 17771107ea93SSriharsha Basavapatna * Read the 'linkprop' property to know if this 17781107ea93SSriharsha Basavapatna * vsw device wants to get physical link updates. 17791107ea93SSriharsha Basavapatna */ 17801107ea93SSriharsha Basavapatna vsw_linkprop_read(vswp, mdp, node, &vswp->pls_update); 17811107ea93SSriharsha Basavapatna 17827b1f684aSSriharsha Basavapatna /* read mtu */ 17837b1f684aSSriharsha Basavapatna vsw_mtu_read(vswp, mdp, node, &vswp->mtu); 17847b1f684aSSriharsha Basavapatna if (vswp->mtu < ETHERMTU || vswp->mtu > VNET_MAX_MTU) { 17857b1f684aSSriharsha Basavapatna vswp->mtu = ETHERMTU; 17867b1f684aSSriharsha Basavapatna } 17877b1f684aSSriharsha Basavapatna vswp->max_frame_size = vswp->mtu + sizeof (struct ether_header) + 17887b1f684aSSriharsha Basavapatna VLAN_TAGSZ; 17897b1f684aSSriharsha Basavapatna 1790c1c61f44Ssb155480 /* read vlan id properties of this vsw instance */ 1791c1c61f44Ssb155480 vsw_vlan_read_ids(vswp, VSW_LOCALDEV, mdp, node, &vswp->pvid, 1792c1c61f44Ssb155480 &vswp->vids, &vswp->nvids, &vswp->default_vlan_id); 1793c1c61f44Ssb155480 1794c1c61f44Ssb155480 /* read priority-ether-types */ 1795f0ca1d9aSsb155480 vsw_read_pri_eth_types(vswp, mdp, node); 1796f0ca1d9aSsb155480 1797bce0a86eSWENTAO YANG /* read bandwidth property of this vsw instance */ 1798bce0a86eSWENTAO YANG vsw_bandwidth_read(vswp, mdp, node, &vswp->bandwidth); 1799bce0a86eSWENTAO YANG 180034683adeSsg70180 D1(vswp, "%s: exit", __func__); 180119b65a69Ssb155480 return (0); 180234683adeSsg70180 } 180334683adeSsg70180 180434683adeSsg70180 /* 1805c1c61f44Ssb155480 * Read vlan id properties of the given MD node. 1806c1c61f44Ssb155480 * Arguments: 1807c1c61f44Ssb155480 * arg: device argument(vsw device or a port) 1808c1c61f44Ssb155480 * type: type of arg; VSW_LOCALDEV(vsw device) or VSW_VNETPORT(port) 1809c1c61f44Ssb155480 * mdp: machine description 1810c1c61f44Ssb155480 * node: md node cookie 1811c1c61f44Ssb155480 * 1812c1c61f44Ssb155480 * Returns: 1813c1c61f44Ssb155480 * pvidp: port-vlan-id of the node 1814c1c61f44Ssb155480 * vidspp: list of vlan-ids of the node 1815c1c61f44Ssb155480 * nvidsp: # of vlan-ids in the list 1816c1c61f44Ssb155480 * default_idp: default-vlan-id of the node(if node is vsw device) 1817c1c61f44Ssb155480 */ 1818c1c61f44Ssb155480 static void 1819c1c61f44Ssb155480 vsw_vlan_read_ids(void *arg, int type, md_t *mdp, mde_cookie_t node, 1820da14cebeSEric Cheng uint16_t *pvidp, vsw_vlanid_t **vidspp, uint16_t *nvidsp, 1821c1c61f44Ssb155480 uint16_t *default_idp) 1822c1c61f44Ssb155480 { 1823c1c61f44Ssb155480 vsw_t *vswp; 1824c1c61f44Ssb155480 vsw_port_t *portp; 1825c1c61f44Ssb155480 char *pvid_propname; 1826c1c61f44Ssb155480 char *vid_propname; 1827c1c61f44Ssb155480 uint_t nvids = 0; 1828c1c61f44Ssb155480 uint32_t vids_size; 1829c1c61f44Ssb155480 int rv; 1830c1c61f44Ssb155480 int i; 1831c1c61f44Ssb155480 uint64_t *data; 1832c1c61f44Ssb155480 uint64_t val; 1833c1c61f44Ssb155480 int size; 1834c1c61f44Ssb155480 int inst; 1835c1c61f44Ssb155480 1836c1c61f44Ssb155480 if (type == VSW_LOCALDEV) { 1837c1c61f44Ssb155480 1838c1c61f44Ssb155480 vswp = (vsw_t *)arg; 1839c1c61f44Ssb155480 pvid_propname = vsw_pvid_propname; 1840c1c61f44Ssb155480 vid_propname = vsw_vid_propname; 1841c1c61f44Ssb155480 inst = vswp->instance; 1842c1c61f44Ssb155480 1843c1c61f44Ssb155480 } else if (type == VSW_VNETPORT) { 1844c1c61f44Ssb155480 1845c1c61f44Ssb155480 portp = (vsw_port_t *)arg; 1846c1c61f44Ssb155480 vswp = portp->p_vswp; 1847c1c61f44Ssb155480 pvid_propname = port_pvid_propname; 1848c1c61f44Ssb155480 vid_propname = port_vid_propname; 1849c1c61f44Ssb155480 inst = portp->p_instance; 1850c1c61f44Ssb155480 1851c1c61f44Ssb155480 } else { 1852c1c61f44Ssb155480 return; 1853c1c61f44Ssb155480 } 1854c1c61f44Ssb155480 1855c1c61f44Ssb155480 if (type == VSW_LOCALDEV && default_idp != NULL) { 1856c1c61f44Ssb155480 rv = md_get_prop_val(mdp, node, vsw_dvid_propname, &val); 1857c1c61f44Ssb155480 if (rv != 0) { 1858c1c61f44Ssb155480 DWARN(vswp, "%s: prop(%s) not found", __func__, 1859c1c61f44Ssb155480 vsw_dvid_propname); 1860c1c61f44Ssb155480 1861c1c61f44Ssb155480 *default_idp = vsw_default_vlan_id; 1862c1c61f44Ssb155480 } else { 1863c1c61f44Ssb155480 *default_idp = val & 0xFFF; 1864c1c61f44Ssb155480 D2(vswp, "%s: %s(%d): (%d)\n", __func__, 1865c1c61f44Ssb155480 vsw_dvid_propname, inst, *default_idp); 1866c1c61f44Ssb155480 } 1867c1c61f44Ssb155480 } 1868c1c61f44Ssb155480 1869c1c61f44Ssb155480 rv = md_get_prop_val(mdp, node, pvid_propname, &val); 1870c1c61f44Ssb155480 if (rv != 0) { 1871c1c61f44Ssb155480 DWARN(vswp, "%s: prop(%s) not found", __func__, pvid_propname); 1872c1c61f44Ssb155480 *pvidp = vsw_default_vlan_id; 1873c1c61f44Ssb155480 } else { 1874c1c61f44Ssb155480 1875c1c61f44Ssb155480 *pvidp = val & 0xFFF; 1876c1c61f44Ssb155480 D2(vswp, "%s: %s(%d): (%d)\n", __func__, 1877c1c61f44Ssb155480 pvid_propname, inst, *pvidp); 1878c1c61f44Ssb155480 } 1879c1c61f44Ssb155480 1880c1c61f44Ssb155480 rv = md_get_prop_data(mdp, node, vid_propname, (uint8_t **)&data, 1881c1c61f44Ssb155480 &size); 1882c1c61f44Ssb155480 if (rv != 0) { 1883c1c61f44Ssb155480 D2(vswp, "%s: prop(%s) not found", __func__, vid_propname); 1884c1c61f44Ssb155480 size = 0; 1885c1c61f44Ssb155480 } else { 1886c1c61f44Ssb155480 size /= sizeof (uint64_t); 1887c1c61f44Ssb155480 } 1888c1c61f44Ssb155480 nvids = size; 1889c1c61f44Ssb155480 1890c1c61f44Ssb155480 if (nvids != 0) { 1891c1c61f44Ssb155480 D2(vswp, "%s: %s(%d): ", __func__, vid_propname, inst); 1892da14cebeSEric Cheng vids_size = sizeof (vsw_vlanid_t) * nvids; 1893c1c61f44Ssb155480 *vidspp = kmem_zalloc(vids_size, KM_SLEEP); 1894c1c61f44Ssb155480 for (i = 0; i < nvids; i++) { 1895da14cebeSEric Cheng (*vidspp)[i].vl_vid = data[i] & 0xFFFF; 1896da14cebeSEric Cheng (*vidspp)[i].vl_set = B_FALSE; 1897da14cebeSEric Cheng D2(vswp, " %d ", (*vidspp)[i].vl_vid); 1898c1c61f44Ssb155480 } 1899c1c61f44Ssb155480 D2(vswp, "\n"); 1900c1c61f44Ssb155480 } 1901c1c61f44Ssb155480 1902c1c61f44Ssb155480 *nvidsp = nvids; 1903c1c61f44Ssb155480 } 1904c1c61f44Ssb155480 1905bce0a86eSWENTAO YANG static void 1906bce0a86eSWENTAO YANG vsw_port_read_bandwidth(vsw_port_t *portp, md_t *mdp, mde_cookie_t node, 1907bce0a86eSWENTAO YANG uint64_t *bw) 1908bce0a86eSWENTAO YANG { 1909bce0a86eSWENTAO YANG int rv; 1910bce0a86eSWENTAO YANG uint64_t val; 1911bce0a86eSWENTAO YANG vsw_t *vswp; 1912bce0a86eSWENTAO YANG 1913bce0a86eSWENTAO YANG vswp = portp->p_vswp; 1914bce0a86eSWENTAO YANG 1915bce0a86eSWENTAO YANG rv = md_get_prop_val(mdp, node, port_maxbw_propname, &val); 1916bce0a86eSWENTAO YANG 1917bce0a86eSWENTAO YANG if (rv != 0) { 1918bce0a86eSWENTAO YANG *bw = 0; 1919bce0a86eSWENTAO YANG D3(vswp, "%s: prop(%s) not found\n", __func__, 1920bce0a86eSWENTAO YANG port_maxbw_propname); 1921bce0a86eSWENTAO YANG } else { 1922bce0a86eSWENTAO YANG *bw = val; 1923bce0a86eSWENTAO YANG D3(vswp, "%s: %s nodes found", __func__, port_maxbw_propname); 1924bce0a86eSWENTAO YANG } 1925bce0a86eSWENTAO YANG } 1926bce0a86eSWENTAO YANG 1927c1c61f44Ssb155480 /* 1928f0ca1d9aSsb155480 * This function reads "priority-ether-types" property from md. This property 1929f0ca1d9aSsb155480 * is used to enable support for priority frames. Applications which need 1930f0ca1d9aSsb155480 * guaranteed and timely delivery of certain high priority frames to/from 1931f0ca1d9aSsb155480 * a vnet or vsw within ldoms, should configure this property by providing 1932f0ca1d9aSsb155480 * the ether type(s) for which the priority facility is needed. 1933f0ca1d9aSsb155480 * Normal data frames are delivered over a ldc channel using the descriptor 1934f0ca1d9aSsb155480 * ring mechanism which is constrained by factors such as descriptor ring size, 1935f0ca1d9aSsb155480 * the rate at which the ring is processed at the peer ldc end point, etc. 1936f0ca1d9aSsb155480 * The priority mechanism provides an Out-Of-Band path to send/receive frames 1937f0ca1d9aSsb155480 * as raw pkt data (VIO_PKT_DATA) messages over the channel, avoiding the 1938f0ca1d9aSsb155480 * descriptor ring path and enables a more reliable and timely delivery of 1939f0ca1d9aSsb155480 * frames to the peer. 1940f0ca1d9aSsb155480 */ 1941f0ca1d9aSsb155480 static void 1942f0ca1d9aSsb155480 vsw_read_pri_eth_types(vsw_t *vswp, md_t *mdp, mde_cookie_t node) 1943f0ca1d9aSsb155480 { 1944f0ca1d9aSsb155480 int rv; 1945f0ca1d9aSsb155480 uint16_t *types; 1946f0ca1d9aSsb155480 uint64_t *data; 1947f0ca1d9aSsb155480 int size; 1948f0ca1d9aSsb155480 int i; 1949f0ca1d9aSsb155480 size_t mblk_sz; 1950f0ca1d9aSsb155480 1951f0ca1d9aSsb155480 rv = md_get_prop_data(mdp, node, pri_types_propname, 1952f0ca1d9aSsb155480 (uint8_t **)&data, &size); 1953f0ca1d9aSsb155480 if (rv != 0) { 1954f0ca1d9aSsb155480 /* 1955f0ca1d9aSsb155480 * Property may not exist if we are running pre-ldoms1.1 f/w. 1956f0ca1d9aSsb155480 * Check if 'vsw_pri_eth_type' has been set in that case. 1957f0ca1d9aSsb155480 */ 1958f0ca1d9aSsb155480 if (vsw_pri_eth_type != 0) { 1959f0ca1d9aSsb155480 size = sizeof (vsw_pri_eth_type); 1960f0ca1d9aSsb155480 data = &vsw_pri_eth_type; 1961f0ca1d9aSsb155480 } else { 1962f0ca1d9aSsb155480 D3(vswp, "%s: prop(%s) not found", __func__, 1963f0ca1d9aSsb155480 pri_types_propname); 1964f0ca1d9aSsb155480 size = 0; 1965f0ca1d9aSsb155480 } 1966f0ca1d9aSsb155480 } 1967f0ca1d9aSsb155480 1968f0ca1d9aSsb155480 if (size == 0) { 1969f0ca1d9aSsb155480 vswp->pri_num_types = 0; 1970f0ca1d9aSsb155480 return; 1971f0ca1d9aSsb155480 } 1972f0ca1d9aSsb155480 1973f0ca1d9aSsb155480 /* 1974f0ca1d9aSsb155480 * we have some priority-ether-types defined; 1975f0ca1d9aSsb155480 * allocate a table of these types and also 1976f0ca1d9aSsb155480 * allocate a pool of mblks to transmit these 1977f0ca1d9aSsb155480 * priority packets. 1978f0ca1d9aSsb155480 */ 1979f0ca1d9aSsb155480 size /= sizeof (uint64_t); 1980f0ca1d9aSsb155480 vswp->pri_num_types = size; 1981f0ca1d9aSsb155480 vswp->pri_types = kmem_zalloc(size * sizeof (uint16_t), KM_SLEEP); 1982f0ca1d9aSsb155480 for (i = 0, types = vswp->pri_types; i < size; i++) { 1983f0ca1d9aSsb155480 types[i] = data[i] & 0xFFFF; 1984f0ca1d9aSsb155480 } 1985f0ca1d9aSsb155480 mblk_sz = (VIO_PKT_DATA_HDRSIZE + ETHERMAX + 7) & ~7; 1986*7bd3a2e2SSriharsha Basavapatna (void) vio_create_mblks(vsw_pri_tx_nmblks, mblk_sz, NULL, 1987*7bd3a2e2SSriharsha Basavapatna &vswp->pri_tx_vmp); 1988f0ca1d9aSsb155480 } 1989f0ca1d9aSsb155480 19907b1f684aSSriharsha Basavapatna static void 19917b1f684aSSriharsha Basavapatna vsw_mtu_read(vsw_t *vswp, md_t *mdp, mde_cookie_t node, uint32_t *mtu) 19927b1f684aSSriharsha Basavapatna { 19937b1f684aSSriharsha Basavapatna int rv; 19947b1f684aSSriharsha Basavapatna int inst; 19957b1f684aSSriharsha Basavapatna uint64_t val; 19967b1f684aSSriharsha Basavapatna char *mtu_propname; 19977b1f684aSSriharsha Basavapatna 19987b1f684aSSriharsha Basavapatna mtu_propname = vsw_mtu_propname; 19997b1f684aSSriharsha Basavapatna inst = vswp->instance; 20007b1f684aSSriharsha Basavapatna 20017b1f684aSSriharsha Basavapatna rv = md_get_prop_val(mdp, node, mtu_propname, &val); 20027b1f684aSSriharsha Basavapatna if (rv != 0) { 20037b1f684aSSriharsha Basavapatna D3(vswp, "%s: prop(%s) not found", __func__, mtu_propname); 20047b1f684aSSriharsha Basavapatna *mtu = vsw_ethermtu; 20057b1f684aSSriharsha Basavapatna } else { 20067b1f684aSSriharsha Basavapatna 20077b1f684aSSriharsha Basavapatna *mtu = val & 0xFFFF; 20087b1f684aSSriharsha Basavapatna D2(vswp, "%s: %s(%d): (%d)\n", __func__, 20097b1f684aSSriharsha Basavapatna mtu_propname, inst, *mtu); 20107b1f684aSSriharsha Basavapatna } 20117b1f684aSSriharsha Basavapatna } 20127b1f684aSSriharsha Basavapatna 20137b1f684aSSriharsha Basavapatna /* 20147b1f684aSSriharsha Basavapatna * Update the mtu of the vsw device. We first check if the device has been 20157b1f684aSSriharsha Basavapatna * plumbed and if so fail the mtu update. Otherwise, we continue to update the 20167b1f684aSSriharsha Basavapatna * new mtu and reset all ports to initiate handshake re-negotiation with peers 20177b1f684aSSriharsha Basavapatna * using the new mtu. 20187b1f684aSSriharsha Basavapatna */ 20197b1f684aSSriharsha Basavapatna static int 20207b1f684aSSriharsha Basavapatna vsw_mtu_update(vsw_t *vswp, uint32_t mtu) 20217b1f684aSSriharsha Basavapatna { 20227b1f684aSSriharsha Basavapatna int rv; 20237b1f684aSSriharsha Basavapatna 20247b1f684aSSriharsha Basavapatna WRITE_ENTER(&vswp->if_lockrw); 20257b1f684aSSriharsha Basavapatna 20267b1f684aSSriharsha Basavapatna if (vswp->if_state & VSW_IF_UP) { 20277b1f684aSSriharsha Basavapatna 20287b1f684aSSriharsha Basavapatna RW_EXIT(&vswp->if_lockrw); 20297b1f684aSSriharsha Basavapatna 20307b1f684aSSriharsha Basavapatna cmn_err(CE_NOTE, "!vsw%d: Unable to process mtu update" 20317b1f684aSSriharsha Basavapatna " as the device is plumbed\n", vswp->instance); 20327b1f684aSSriharsha Basavapatna return (EBUSY); 20337b1f684aSSriharsha Basavapatna 20347b1f684aSSriharsha Basavapatna } else { 20357b1f684aSSriharsha Basavapatna 20367b1f684aSSriharsha Basavapatna D2(vswp, "%s: curr_mtu(%d) new_mtu(%d)\n", 20377b1f684aSSriharsha Basavapatna __func__, vswp->mtu, mtu); 20387b1f684aSSriharsha Basavapatna 20397b1f684aSSriharsha Basavapatna vswp->mtu = mtu; 20407b1f684aSSriharsha Basavapatna vswp->max_frame_size = vswp->mtu + 20417b1f684aSSriharsha Basavapatna sizeof (struct ether_header) + VLAN_TAGSZ; 20427b1f684aSSriharsha Basavapatna 20437b1f684aSSriharsha Basavapatna rv = mac_maxsdu_update(vswp->if_mh, mtu); 20447b1f684aSSriharsha Basavapatna if (rv != 0) { 20457b1f684aSSriharsha Basavapatna cmn_err(CE_NOTE, 20467b1f684aSSriharsha Basavapatna "!vsw%d: Unable to update mtu with mac" 20477b1f684aSSriharsha Basavapatna " layer\n", vswp->instance); 20487b1f684aSSriharsha Basavapatna } 20497b1f684aSSriharsha Basavapatna 20507b1f684aSSriharsha Basavapatna RW_EXIT(&vswp->if_lockrw); 20517b1f684aSSriharsha Basavapatna 20527b1f684aSSriharsha Basavapatna /* Reset ports to renegotiate with the new mtu */ 20537b1f684aSSriharsha Basavapatna vsw_reset_ports(vswp); 20547b1f684aSSriharsha Basavapatna 20557b1f684aSSriharsha Basavapatna } 20567b1f684aSSriharsha Basavapatna 20577b1f684aSSriharsha Basavapatna return (0); 20587b1f684aSSriharsha Basavapatna } 20597b1f684aSSriharsha Basavapatna 20601107ea93SSriharsha Basavapatna static void 20611107ea93SSriharsha Basavapatna vsw_linkprop_read(vsw_t *vswp, md_t *mdp, mde_cookie_t node, 20621107ea93SSriharsha Basavapatna boolean_t *pls) 20631107ea93SSriharsha Basavapatna { 20641107ea93SSriharsha Basavapatna int rv; 20651107ea93SSriharsha Basavapatna uint64_t val; 20661107ea93SSriharsha Basavapatna char *linkpropname; 20671107ea93SSriharsha Basavapatna 20681107ea93SSriharsha Basavapatna linkpropname = vsw_linkprop_propname; 20691107ea93SSriharsha Basavapatna 20701107ea93SSriharsha Basavapatna rv = md_get_prop_val(mdp, node, linkpropname, &val); 20711107ea93SSriharsha Basavapatna if (rv != 0) { 20721107ea93SSriharsha Basavapatna D3(vswp, "%s: prop(%s) not found", __func__, linkpropname); 20731107ea93SSriharsha Basavapatna *pls = B_FALSE; 20741107ea93SSriharsha Basavapatna } else { 20751107ea93SSriharsha Basavapatna 20761107ea93SSriharsha Basavapatna *pls = (val & 0x1) ? B_TRUE : B_FALSE; 20771107ea93SSriharsha Basavapatna D2(vswp, "%s: %s(%d): (%d)\n", __func__, linkpropname, 20781107ea93SSriharsha Basavapatna vswp->instance, *pls); 20791107ea93SSriharsha Basavapatna } 20801107ea93SSriharsha Basavapatna } 20811107ea93SSriharsha Basavapatna 2082d8a518c8SSriharsha Basavapatna void 20831107ea93SSriharsha Basavapatna vsw_mac_link_update(vsw_t *vswp, link_state_t link_state) 20841107ea93SSriharsha Basavapatna { 20851107ea93SSriharsha Basavapatna READ_ENTER(&vswp->if_lockrw); 20861107ea93SSriharsha Basavapatna 2087d8a518c8SSriharsha Basavapatna if (vswp->if_state & VSW_IF_REG) { 20881107ea93SSriharsha Basavapatna mac_link_update(vswp->if_mh, link_state); 20891107ea93SSriharsha Basavapatna } 20901107ea93SSriharsha Basavapatna 2091d8a518c8SSriharsha Basavapatna RW_EXIT(&vswp->if_lockrw); 2092d8a518c8SSriharsha Basavapatna } 2093d8a518c8SSriharsha Basavapatna 20941107ea93SSriharsha Basavapatna void 20951107ea93SSriharsha Basavapatna vsw_physlink_state_update(vsw_t *vswp) 20961107ea93SSriharsha Basavapatna { 20971107ea93SSriharsha Basavapatna if (vswp->pls_update == B_TRUE) { 20981107ea93SSriharsha Basavapatna vsw_mac_link_update(vswp, vswp->phys_link_state); 20991107ea93SSriharsha Basavapatna } 21001107ea93SSriharsha Basavapatna vsw_physlink_update_ports(vswp); 21011107ea93SSriharsha Basavapatna } 21021107ea93SSriharsha Basavapatna 2103bce0a86eSWENTAO YANG static void 2104bce0a86eSWENTAO YANG vsw_bandwidth_read(vsw_t *vswp, md_t *mdp, mde_cookie_t node, uint64_t *bw) 2105bce0a86eSWENTAO YANG { 2106bce0a86eSWENTAO YANG /* read the vsw bandwidth from md */ 2107bce0a86eSWENTAO YANG int rv; 2108bce0a86eSWENTAO YANG uint64_t val; 2109bce0a86eSWENTAO YANG 2110bce0a86eSWENTAO YANG rv = md_get_prop_val(mdp, node, vsw_maxbw_propname, &val); 2111bce0a86eSWENTAO YANG if (rv != 0) { 2112bce0a86eSWENTAO YANG *bw = 0; 2113bce0a86eSWENTAO YANG D3(vswp, "%s: prop(%s) not found", __func__, 2114bce0a86eSWENTAO YANG vsw_maxbw_propname); 2115bce0a86eSWENTAO YANG } else { 2116bce0a86eSWENTAO YANG *bw = val; 2117bce0a86eSWENTAO YANG D3(vswp, "%s: %s(%d): (%ld)\n", __func__, 2118bce0a86eSWENTAO YANG vsw_maxbw_propname, vswp->instance, *bw); 2119bce0a86eSWENTAO YANG } 2120bce0a86eSWENTAO YANG } 2121bce0a86eSWENTAO YANG 2122f0ca1d9aSsb155480 /* 212334683adeSsg70180 * Check to see if the relevant properties in the specified node have 212434683adeSsg70180 * changed, and if so take the appropriate action. 212534683adeSsg70180 * 212634683adeSsg70180 * If any of the properties are missing or invalid we don't take 212734683adeSsg70180 * any action, as this function should only be invoked when modifications 212834683adeSsg70180 * have been made to what we assume is a working configuration, which 212934683adeSsg70180 * we leave active. 213034683adeSsg70180 * 213134683adeSsg70180 * Note it is legal for this routine to be invoked even if none of the 213234683adeSsg70180 * properties in the port node within the MD have actually changed. 213334683adeSsg70180 */ 213434683adeSsg70180 static void 213534683adeSsg70180 vsw_update_md_prop(vsw_t *vswp, md_t *mdp, mde_cookie_t node) 213634683adeSsg70180 { 213734683adeSsg70180 char physname[LIFNAMSIZ]; 213834683adeSsg70180 char drv[LIFNAMSIZ]; 213934683adeSsg70180 uint_t ddi_instance; 2140da14cebeSEric Cheng uint8_t new_smode; 2141da14cebeSEric Cheng int i; 214234683adeSsg70180 uint64_t macaddr = 0; 214334683adeSsg70180 enum {MD_init = 0x1, 214434683adeSsg70180 MD_physname = 0x2, 214534683adeSsg70180 MD_macaddr = 0x4, 2146c1c61f44Ssb155480 MD_smode = 0x8, 21477b1f684aSSriharsha Basavapatna MD_vlans = 0x10, 21481107ea93SSriharsha Basavapatna MD_mtu = 0x20, 2149bce0a86eSWENTAO YANG MD_pls = 0x40, 2150bce0a86eSWENTAO YANG MD_bw = 0x80} updated; 215119b65a69Ssb155480 int rv; 2152c1c61f44Ssb155480 uint16_t pvid; 2153da14cebeSEric Cheng vsw_vlanid_t *vids; 2154c1c61f44Ssb155480 uint16_t nvids; 21557b1f684aSSriharsha Basavapatna uint32_t mtu; 21561107ea93SSriharsha Basavapatna boolean_t pls_update; 2157bce0a86eSWENTAO YANG uint64_t maxbw; 215834683adeSsg70180 215934683adeSsg70180 updated = MD_init; 216034683adeSsg70180 216134683adeSsg70180 D1(vswp, "%s: enter", __func__); 216234683adeSsg70180 216334683adeSsg70180 /* 216434683adeSsg70180 * Check if name of physical device in MD has changed. 216534683adeSsg70180 */ 216634683adeSsg70180 if (vsw_get_md_physname(vswp, mdp, node, (char *)&physname) == 0) { 216734683adeSsg70180 /* 216834683adeSsg70180 * Do basic sanity check on new device name/instance, 216934683adeSsg70180 * if its non NULL. It is valid for the device name to 217034683adeSsg70180 * have changed from a non NULL to a NULL value, i.e. 217134683adeSsg70180 * the vsw is being changed to 'routed' mode. 217234683adeSsg70180 */ 217334683adeSsg70180 if ((strlen(physname) != 0) && 217419b65a69Ssb155480 (ddi_parse(physname, drv, 217519b65a69Ssb155480 &ddi_instance) != DDI_SUCCESS)) { 21761ef0bbb5Snarayan cmn_err(CE_WARN, "!vsw%d: physical device %s is not" 217734683adeSsg70180 " a valid device name/instance", 217834683adeSsg70180 vswp->instance, physname); 217934683adeSsg70180 goto fail_reconf; 218034683adeSsg70180 } 218134683adeSsg70180 218234683adeSsg70180 if (strcmp(physname, vswp->physname)) { 218334683adeSsg70180 D2(vswp, "%s: device name changed from %s to %s", 218434683adeSsg70180 __func__, vswp->physname, physname); 218534683adeSsg70180 218634683adeSsg70180 updated |= MD_physname; 218734683adeSsg70180 } else { 218834683adeSsg70180 D2(vswp, "%s: device name unchanged at %s", 218934683adeSsg70180 __func__, vswp->physname); 219034683adeSsg70180 } 219134683adeSsg70180 } else { 219234683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to read name of physical " 219334683adeSsg70180 "device from updated MD.", vswp->instance); 219434683adeSsg70180 goto fail_reconf; 219534683adeSsg70180 } 219634683adeSsg70180 219734683adeSsg70180 /* 219834683adeSsg70180 * Check if MAC address has changed. 219934683adeSsg70180 */ 220034683adeSsg70180 if (md_get_prop_val(mdp, node, macaddr_propname, &macaddr) != 0) { 220134683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to get MAC address from MD", 220234683adeSsg70180 vswp->instance); 220334683adeSsg70180 goto fail_reconf; 220434683adeSsg70180 } else { 220519b65a69Ssb155480 uint64_t maddr = macaddr; 220634683adeSsg70180 READ_ENTER(&vswp->if_lockrw); 220734683adeSsg70180 for (i = ETHERADDRL - 1; i >= 0; i--) { 220819b65a69Ssb155480 if (vswp->if_addr.ether_addr_octet[i] 220919b65a69Ssb155480 != (macaddr & 0xFF)) { 221034683adeSsg70180 D2(vswp, "%s: octet[%d] 0x%x != 0x%x", 221134683adeSsg70180 __func__, i, 221234683adeSsg70180 vswp->if_addr.ether_addr_octet[i], 221334683adeSsg70180 (macaddr & 0xFF)); 221434683adeSsg70180 updated |= MD_macaddr; 221519b65a69Ssb155480 macaddr = maddr; 221634683adeSsg70180 break; 221734683adeSsg70180 } 221834683adeSsg70180 macaddr >>= 8; 221934683adeSsg70180 } 222034683adeSsg70180 RW_EXIT(&vswp->if_lockrw); 222119b65a69Ssb155480 if (updated & MD_macaddr) { 222219b65a69Ssb155480 vsw_save_lmacaddr(vswp, macaddr); 222319b65a69Ssb155480 } 222434683adeSsg70180 } 222534683adeSsg70180 222634683adeSsg70180 /* 222734683adeSsg70180 * Check if switching modes have changed. 222834683adeSsg70180 */ 2229da14cebeSEric Cheng if (vsw_get_md_smodes(vswp, mdp, node, &new_smode)) { 223034683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: Unable to read %s property from MD", 223134683adeSsg70180 vswp->instance, smode_propname); 223234683adeSsg70180 goto fail_reconf; 223334683adeSsg70180 } else { 2234da14cebeSEric Cheng if (new_smode != vswp->smode) { 2235da14cebeSEric Cheng D2(vswp, "%s: switching mode changed from %d to %d", 2236da14cebeSEric Cheng __func__, vswp->smode, new_smode); 223734683adeSsg70180 223834683adeSsg70180 updated |= MD_smode; 223934683adeSsg70180 } 224034683adeSsg70180 } 224134683adeSsg70180 2242c1c61f44Ssb155480 /* Read the vlan ids */ 2243c1c61f44Ssb155480 vsw_vlan_read_ids(vswp, VSW_LOCALDEV, mdp, node, &pvid, &vids, 2244c1c61f44Ssb155480 &nvids, NULL); 2245c1c61f44Ssb155480 2246c1c61f44Ssb155480 /* Determine if there are any vlan id updates */ 2247c1c61f44Ssb155480 if ((pvid != vswp->pvid) || /* pvid changed? */ 2248c1c61f44Ssb155480 (nvids != vswp->nvids) || /* # of vids changed? */ 2249c1c61f44Ssb155480 ((nvids != 0) && (vswp->nvids != 0) && /* vids changed? */ 2250da14cebeSEric Cheng !vsw_cmp_vids(vids, vswp->vids, nvids))) { 2251c1c61f44Ssb155480 updated |= MD_vlans; 2252c1c61f44Ssb155480 } 2253c1c61f44Ssb155480 22547b1f684aSSriharsha Basavapatna /* Read mtu */ 22557b1f684aSSriharsha Basavapatna vsw_mtu_read(vswp, mdp, node, &mtu); 22567b1f684aSSriharsha Basavapatna if (mtu != vswp->mtu) { 22577b1f684aSSriharsha Basavapatna if (mtu >= ETHERMTU && mtu <= VNET_MAX_MTU) { 22587b1f684aSSriharsha Basavapatna updated |= MD_mtu; 22597b1f684aSSriharsha Basavapatna } else { 22607b1f684aSSriharsha Basavapatna cmn_err(CE_NOTE, "!vsw%d: Unable to process mtu update" 22617b1f684aSSriharsha Basavapatna " as the specified value:%d is invalid\n", 22627b1f684aSSriharsha Basavapatna vswp->instance, mtu); 22637b1f684aSSriharsha Basavapatna } 22647b1f684aSSriharsha Basavapatna } 22657b1f684aSSriharsha Basavapatna 226634683adeSsg70180 /* 22671107ea93SSriharsha Basavapatna * Read the 'linkprop' property. 22681107ea93SSriharsha Basavapatna */ 22691107ea93SSriharsha Basavapatna vsw_linkprop_read(vswp, mdp, node, &pls_update); 22701107ea93SSriharsha Basavapatna if (pls_update != vswp->pls_update) { 22711107ea93SSriharsha Basavapatna updated |= MD_pls; 22721107ea93SSriharsha Basavapatna } 22731107ea93SSriharsha Basavapatna 2274bce0a86eSWENTAO YANG /* Read bandwidth */ 2275bce0a86eSWENTAO YANG vsw_bandwidth_read(vswp, mdp, node, &maxbw); 2276bce0a86eSWENTAO YANG if (maxbw != vswp->bandwidth) { 2277bce0a86eSWENTAO YANG if (maxbw >= MRP_MAXBW_MINVAL || maxbw == 0) { 2278bce0a86eSWENTAO YANG updated |= MD_bw; 2279bce0a86eSWENTAO YANG } else { 2280bce0a86eSWENTAO YANG cmn_err(CE_NOTE, "!vsw%d: Unable to process bandwidth" 2281bce0a86eSWENTAO YANG " update as the specified value:%ld is invalid\n", 2282bce0a86eSWENTAO YANG vswp->instance, maxbw); 2283bce0a86eSWENTAO YANG } 2284bce0a86eSWENTAO YANG } 2285bce0a86eSWENTAO YANG 22861107ea93SSriharsha Basavapatna /* 228734683adeSsg70180 * Now make any changes which are needed... 228834683adeSsg70180 */ 22891107ea93SSriharsha Basavapatna if (updated & MD_pls) { 22901107ea93SSriharsha Basavapatna 22911107ea93SSriharsha Basavapatna /* save the updated property. */ 22921107ea93SSriharsha Basavapatna vswp->pls_update = pls_update; 22931107ea93SSriharsha Basavapatna 22941107ea93SSriharsha Basavapatna if (pls_update == B_FALSE) { 22951107ea93SSriharsha Basavapatna /* 22961107ea93SSriharsha Basavapatna * Phys link state update is now disabled for this vsw 22971107ea93SSriharsha Basavapatna * interface. If we had previously reported a link-down 22981107ea93SSriharsha Basavapatna * to the stack, undo that by sending a link-up. 22991107ea93SSriharsha Basavapatna */ 23001107ea93SSriharsha Basavapatna if (vswp->phys_link_state == LINK_STATE_DOWN) { 23011107ea93SSriharsha Basavapatna vsw_mac_link_update(vswp, LINK_STATE_UP); 23021107ea93SSriharsha Basavapatna } 23031107ea93SSriharsha Basavapatna } else { 23041107ea93SSriharsha Basavapatna /* 23051107ea93SSriharsha Basavapatna * Phys link state update is now enabled. Send up an 23061107ea93SSriharsha Basavapatna * update based on the current phys link state. 23071107ea93SSriharsha Basavapatna */ 2308d8a518c8SSriharsha Basavapatna if (vswp->smode & VSW_LAYER2) { 2309d8a518c8SSriharsha Basavapatna vsw_mac_link_update(vswp, 2310d8a518c8SSriharsha Basavapatna vswp->phys_link_state); 2311d8a518c8SSriharsha Basavapatna } 23121107ea93SSriharsha Basavapatna } 23131107ea93SSriharsha Basavapatna 23141107ea93SSriharsha Basavapatna } 231534683adeSsg70180 2316da14cebeSEric Cheng if (updated & (MD_physname | MD_smode | MD_mtu)) { 231734683adeSsg70180 231834683adeSsg70180 /* 2319808f26a8SSriharsha Basavapatna * Stop any pending thread to setup switching mode. 232034683adeSsg70180 */ 2321808f26a8SSriharsha Basavapatna vsw_setup_switching_stop(vswp); 232219b65a69Ssb155480 2323678453a8Sspeer /* Cleanup HybridIO */ 2324678453a8Sspeer vsw_hio_cleanup(vswp); 2325678453a8Sspeer 232619b65a69Ssb155480 /* 232719b65a69Ssb155480 * Remove unicst, mcst addrs of vsw interface 2328da14cebeSEric Cheng * and ports from the physdev. This also closes 2329da14cebeSEric Cheng * the corresponding mac clients. 233019b65a69Ssb155480 */ 233119b65a69Ssb155480 vsw_unset_addrs(vswp); 233219b65a69Ssb155480 233319b65a69Ssb155480 /* 233419b65a69Ssb155480 * Stop, detach and close the old device.. 233519b65a69Ssb155480 */ 2336da14cebeSEric Cheng mutex_enter(&vswp->mac_lock); 233719b65a69Ssb155480 vsw_mac_close(vswp); 2338da14cebeSEric Cheng mutex_exit(&vswp->mac_lock); 233934683adeSsg70180 234034683adeSsg70180 /* 234134683adeSsg70180 * Update phys name. 234234683adeSsg70180 */ 234334683adeSsg70180 if (updated & MD_physname) { 234434683adeSsg70180 cmn_err(CE_NOTE, "!vsw%d: changing from %s to %s", 234534683adeSsg70180 vswp->instance, vswp->physname, physname); 234634683adeSsg70180 (void) strncpy(vswp->physname, 234734683adeSsg70180 physname, strlen(physname) + 1); 234834683adeSsg70180 } 234934683adeSsg70180 235034683adeSsg70180 /* 235134683adeSsg70180 * Update array with the new switch mode values. 235234683adeSsg70180 */ 235334683adeSsg70180 if (updated & MD_smode) { 2354da14cebeSEric Cheng vswp->smode = new_smode; 2355da14cebeSEric Cheng } 235634683adeSsg70180 2357da14cebeSEric Cheng /* Update mtu */ 2358da14cebeSEric Cheng if (updated & MD_mtu) { 2359da14cebeSEric Cheng rv = vsw_mtu_update(vswp, mtu); 2360da14cebeSEric Cheng if (rv != 0) { 2361da14cebeSEric Cheng goto fail_update; 2362da14cebeSEric Cheng } 236334683adeSsg70180 } 236434683adeSsg70180 236534683adeSsg70180 /* 236634683adeSsg70180 * ..and attach, start the new device. 236734683adeSsg70180 */ 236819b65a69Ssb155480 rv = vsw_setup_switching(vswp); 236919b65a69Ssb155480 if (rv == EAGAIN) { 237019b65a69Ssb155480 /* 237119b65a69Ssb155480 * Unable to setup switching mode. 2372808f26a8SSriharsha Basavapatna * As the error is EAGAIN, schedule a thread to retry 237319b65a69Ssb155480 * and return. Programming addresses of ports and 2374808f26a8SSriharsha Basavapatna * vsw interface will be done by the thread when the 2375808f26a8SSriharsha Basavapatna * switching setup completes successfully. 237619b65a69Ssb155480 */ 2377808f26a8SSriharsha Basavapatna if (vsw_setup_switching_start(vswp) != 0) { 2378808f26a8SSriharsha Basavapatna goto fail_update; 2379808f26a8SSriharsha Basavapatna } 238019b65a69Ssb155480 return; 238119b65a69Ssb155480 238219b65a69Ssb155480 } else if (rv) { 238334683adeSsg70180 goto fail_update; 238419b65a69Ssb155480 } 238534683adeSsg70180 2386d8a518c8SSriharsha Basavapatna vsw_setup_switching_post_process(vswp); 238719b65a69Ssb155480 } else if (updated & MD_macaddr) { 238819b65a69Ssb155480 /* 238919b65a69Ssb155480 * We enter here if only MD_macaddr is exclusively updated. 239019b65a69Ssb155480 * If MD_physname and/or MD_smode are also updated, then 239119b65a69Ssb155480 * as part of that, we would have implicitly processed 239219b65a69Ssb155480 * MD_macaddr update (above). 239319b65a69Ssb155480 */ 239434683adeSsg70180 cmn_err(CE_NOTE, "!vsw%d: changing mac address to 0x%lx", 239534683adeSsg70180 vswp->instance, macaddr); 239634683adeSsg70180 239719b65a69Ssb155480 READ_ENTER(&vswp->if_lockrw); 239819b65a69Ssb155480 if (vswp->if_state & VSW_IF_UP) { 2399da14cebeSEric Cheng /* reconfigure with new address */ 2400da14cebeSEric Cheng vsw_if_mac_reconfig(vswp, B_FALSE, 0, NULL, 0); 240134683adeSsg70180 24025f94e909Ssg70180 /* 240334683adeSsg70180 * Notify the MAC layer of the changed address. 240434683adeSsg70180 */ 240519b65a69Ssb155480 mac_unicst_update(vswp->if_mh, 240619b65a69Ssb155480 (uint8_t *)&vswp->if_addr); 240719b65a69Ssb155480 240819b65a69Ssb155480 } 240919b65a69Ssb155480 RW_EXIT(&vswp->if_lockrw); 241019b65a69Ssb155480 241134683adeSsg70180 } 241234683adeSsg70180 2413c1c61f44Ssb155480 if (updated & MD_vlans) { 2414c1c61f44Ssb155480 /* Remove existing vlan ids from the hash table. */ 2415c1c61f44Ssb155480 vsw_vlan_remove_ids(vswp, VSW_LOCALDEV); 2416c1c61f44Ssb155480 2417da14cebeSEric Cheng if (vswp->if_state & VSW_IF_UP) { 2418da14cebeSEric Cheng vsw_if_mac_reconfig(vswp, B_TRUE, pvid, vids, nvids); 2419da14cebeSEric Cheng } else { 2420c1c61f44Ssb155480 if (vswp->nvids != 0) { 2421da14cebeSEric Cheng kmem_free(vswp->vids, 2422da14cebeSEric Cheng sizeof (vsw_vlanid_t) * vswp->nvids); 2423c1c61f44Ssb155480 } 2424c1c61f44Ssb155480 vswp->vids = vids; 2425da14cebeSEric Cheng vswp->nvids = nvids; 2426da14cebeSEric Cheng vswp->pvid = pvid; 2427c1c61f44Ssb155480 } 2428c1c61f44Ssb155480 2429c1c61f44Ssb155480 /* add these new vlan ids into hash table */ 2430c1c61f44Ssb155480 vsw_vlan_add_ids(vswp, VSW_LOCALDEV); 2431c1c61f44Ssb155480 } else { 2432c1c61f44Ssb155480 if (nvids != 0) { 2433da14cebeSEric Cheng kmem_free(vids, sizeof (vsw_vlanid_t) * nvids); 2434c1c61f44Ssb155480 } 2435c1c61f44Ssb155480 } 2436c1c61f44Ssb155480 2437bce0a86eSWENTAO YANG if (updated & MD_bw) { 2438bce0a86eSWENTAO YANG vsw_update_bandwidth(vswp, NULL, VSW_LOCALDEV, maxbw); 2439bce0a86eSWENTAO YANG } 2440bce0a86eSWENTAO YANG 244134683adeSsg70180 return; 244234683adeSsg70180 244334683adeSsg70180 fail_reconf: 244434683adeSsg70180 cmn_err(CE_WARN, "!vsw%d: configuration unchanged", vswp->instance); 244534683adeSsg70180 return; 244634683adeSsg70180 244734683adeSsg70180 fail_update: 24481ef0bbb5Snarayan cmn_err(CE_WARN, "!vsw%d: re-configuration failed", 244934683adeSsg70180 vswp->instance); 245034683adeSsg70180 } 245134683adeSsg70180 245234683adeSsg70180 /* 2453c1c61f44Ssb155480 * Read the port's md properties. 24541ae08745Sheppo */ 2455c1c61f44Ssb155480 static int 2456c1c61f44Ssb155480 vsw_port_read_props(vsw_port_t *portp, vsw_t *vswp, 2457c1c61f44Ssb155480 md_t *mdp, mde_cookie_t *node) 24581ae08745Sheppo { 24591ae08745Sheppo uint64_t ldc_id; 24601ae08745Sheppo uint8_t *addrp; 24611ae08745Sheppo int i, addrsz; 24621ae08745Sheppo int num_nodes = 0, nchan = 0; 24631ae08745Sheppo int listsz = 0; 24641ae08745Sheppo mde_cookie_t *listp = NULL; 24651ae08745Sheppo struct ether_addr ea; 24661ae08745Sheppo uint64_t macaddr; 24671ae08745Sheppo uint64_t inst = 0; 2468678453a8Sspeer uint64_t val; 24691ae08745Sheppo 24701ae08745Sheppo if (md_get_prop_val(mdp, *node, id_propname, &inst)) { 24711ae08745Sheppo DWARN(vswp, "%s: prop(%s) not found", __func__, 24721ae08745Sheppo id_propname); 24731ae08745Sheppo return (1); 24741ae08745Sheppo } 24751ae08745Sheppo 24761ae08745Sheppo /* 24771ae08745Sheppo * Find the channel endpoint node(s) (which should be under this 24781ae08745Sheppo * port node) which contain the channel id(s). 24791ae08745Sheppo */ 24801ae08745Sheppo if ((num_nodes = md_node_count(mdp)) <= 0) { 24811ae08745Sheppo DERR(vswp, "%s: invalid number of nodes found (%d)", 24821ae08745Sheppo __func__, num_nodes); 24831ae08745Sheppo return (1); 24841ae08745Sheppo } 24851ae08745Sheppo 248634683adeSsg70180 D2(vswp, "%s: %d nodes found", __func__, num_nodes); 248734683adeSsg70180 24881ae08745Sheppo /* allocate enough space for node list */ 24891ae08745Sheppo listsz = num_nodes * sizeof (mde_cookie_t); 24901ae08745Sheppo listp = kmem_zalloc(listsz, KM_SLEEP); 24911ae08745Sheppo 2492205eeb1aSlm66018 nchan = md_scan_dag(mdp, *node, md_find_name(mdp, chan_propname), 24931ae08745Sheppo md_find_name(mdp, "fwd"), listp); 24941ae08745Sheppo 24951ae08745Sheppo if (nchan <= 0) { 24961ae08745Sheppo DWARN(vswp, "%s: no %s nodes found", __func__, chan_propname); 24971ae08745Sheppo kmem_free(listp, listsz); 24981ae08745Sheppo return (1); 24991ae08745Sheppo } 25001ae08745Sheppo 25011ae08745Sheppo D2(vswp, "%s: %d %s nodes found", __func__, nchan, chan_propname); 25021ae08745Sheppo 25031ae08745Sheppo /* use property from first node found */ 25041ae08745Sheppo if (md_get_prop_val(mdp, listp[0], id_propname, &ldc_id)) { 25051ae08745Sheppo DWARN(vswp, "%s: prop(%s) not found\n", __func__, 25061ae08745Sheppo id_propname); 25071ae08745Sheppo kmem_free(listp, listsz); 25081ae08745Sheppo return (1); 25091ae08745Sheppo } 25101ae08745Sheppo 25111ae08745Sheppo /* don't need list any more */ 25121ae08745Sheppo kmem_free(listp, listsz); 25131ae08745Sheppo 25141ae08745Sheppo D2(vswp, "%s: ldc_id 0x%llx", __func__, ldc_id); 25151ae08745Sheppo 25161ae08745Sheppo /* read mac-address property */ 25171ae08745Sheppo if (md_get_prop_data(mdp, *node, remaddr_propname, 25181ae08745Sheppo &addrp, &addrsz)) { 25191ae08745Sheppo DWARN(vswp, "%s: prop(%s) not found", 25201ae08745Sheppo __func__, remaddr_propname); 25211ae08745Sheppo return (1); 25221ae08745Sheppo } 25231ae08745Sheppo 25241ae08745Sheppo if (addrsz < ETHERADDRL) { 25251ae08745Sheppo DWARN(vswp, "%s: invalid address size", __func__); 25261ae08745Sheppo return (1); 25271ae08745Sheppo } 25281ae08745Sheppo 25291ae08745Sheppo macaddr = *((uint64_t *)addrp); 25301ae08745Sheppo D2(vswp, "%s: remote mac address 0x%llx", __func__, macaddr); 25311ae08745Sheppo 25321ae08745Sheppo for (i = ETHERADDRL - 1; i >= 0; i--) { 25331ae08745Sheppo ea.ether_addr_octet[i] = macaddr & 0xFF; 25341ae08745Sheppo macaddr >>= 8; 25351ae08745Sheppo } 25361ae08745Sheppo 2537c1c61f44Ssb155480 /* now update all properties into the port */ 2538c1c61f44Ssb155480 portp->p_vswp = vswp; 2539c1c61f44Ssb155480 portp->p_instance = inst; 2540da14cebeSEric Cheng portp->addr_set = B_FALSE; 2541c1c61f44Ssb155480 ether_copy(&ea, &portp->p_macaddr); 2542c1c61f44Ssb155480 if (nchan > VSW_PORT_MAX_LDCS) { 2543c1c61f44Ssb155480 D2(vswp, "%s: using first of %d ldc ids", 2544c1c61f44Ssb155480 __func__, nchan); 2545c1c61f44Ssb155480 nchan = VSW_PORT_MAX_LDCS; 2546c1c61f44Ssb155480 } 2547c1c61f44Ssb155480 portp->num_ldcs = nchan; 2548c1c61f44Ssb155480 portp->ldc_ids = 2549c1c61f44Ssb155480 kmem_zalloc(sizeof (uint64_t) * nchan, KM_SLEEP); 2550c1c61f44Ssb155480 bcopy(&ldc_id, (portp->ldc_ids), sizeof (uint64_t) * nchan); 2551c1c61f44Ssb155480 2552c1c61f44Ssb155480 /* read vlan id properties of this port node */ 2553c1c61f44Ssb155480 vsw_vlan_read_ids(portp, VSW_VNETPORT, mdp, *node, &portp->pvid, 2554c1c61f44Ssb155480 &portp->vids, &portp->nvids, NULL); 2555c1c61f44Ssb155480 2556678453a8Sspeer /* Check if hybrid property is present */ 2557678453a8Sspeer if (md_get_prop_val(mdp, *node, hybrid_propname, &val) == 0) { 2558678453a8Sspeer D1(vswp, "%s: prop(%s) found\n", __func__, hybrid_propname); 2559678453a8Sspeer portp->p_hio_enabled = B_TRUE; 2560678453a8Sspeer } else { 2561678453a8Sspeer portp->p_hio_enabled = B_FALSE; 2562678453a8Sspeer } 2563678453a8Sspeer /* 2564678453a8Sspeer * Port hio capability determined after version 2565678453a8Sspeer * negotiation, i.e., when we know the peer is HybridIO capable. 2566678453a8Sspeer */ 2567678453a8Sspeer portp->p_hio_capable = B_FALSE; 2568bce0a86eSWENTAO YANG 2569bce0a86eSWENTAO YANG /* Read bandwidth of this port */ 2570bce0a86eSWENTAO YANG vsw_port_read_bandwidth(portp, mdp, *node, &portp->p_bandwidth); 2571bce0a86eSWENTAO YANG 2572c1c61f44Ssb155480 return (0); 2573c1c61f44Ssb155480 } 2574c1c61f44Ssb155480 2575c1c61f44Ssb155480 /* 2576c1c61f44Ssb155480 * Add a new port to the system. 2577c1c61f44Ssb155480 * 2578c1c61f44Ssb155480 * Returns 0 on success, 1 on failure. 2579c1c61f44Ssb155480 */ 2580c1c61f44Ssb155480 int 2581c1c61f44Ssb155480 vsw_port_add(vsw_t *vswp, md_t *mdp, mde_cookie_t *node) 2582c1c61f44Ssb155480 { 2583c1c61f44Ssb155480 vsw_port_t *portp; 2584c1c61f44Ssb155480 int rv; 2585c1c61f44Ssb155480 2586c1c61f44Ssb155480 portp = kmem_zalloc(sizeof (vsw_port_t), KM_SLEEP); 2587c1c61f44Ssb155480 2588c1c61f44Ssb155480 rv = vsw_port_read_props(portp, vswp, mdp, node); 2589c1c61f44Ssb155480 if (rv != 0) { 2590c1c61f44Ssb155480 kmem_free(portp, sizeof (*portp)); 2591c1c61f44Ssb155480 return (1); 2592c1c61f44Ssb155480 } 2593c1c61f44Ssb155480 2594c1c61f44Ssb155480 rv = vsw_port_attach(portp); 2595c1c61f44Ssb155480 if (rv != 0) { 25961ae08745Sheppo DERR(vswp, "%s: failed to attach port", __func__); 25971ae08745Sheppo return (1); 25981ae08745Sheppo } 25991ae08745Sheppo 2600c1c61f44Ssb155480 return (0); 2601c1c61f44Ssb155480 } 26021ae08745Sheppo 2603c1c61f44Ssb155480 static int 2604c1c61f44Ssb155480 vsw_port_update(vsw_t *vswp, md_t *curr_mdp, mde_cookie_t curr_mdex, 2605c1c61f44Ssb155480 md_t *prev_mdp, mde_cookie_t prev_mdex) 2606c1c61f44Ssb155480 { 2607c1c61f44Ssb155480 uint64_t cport_num; 2608c1c61f44Ssb155480 uint64_t pport_num; 2609c1c61f44Ssb155480 vsw_port_list_t *plistp; 2610c1c61f44Ssb155480 vsw_port_t *portp; 2611c1c61f44Ssb155480 uint16_t pvid; 2612da14cebeSEric Cheng vsw_vlanid_t *vids; 2613c1c61f44Ssb155480 uint16_t nvids; 2614678453a8Sspeer uint64_t val; 2615678453a8Sspeer boolean_t hio_enabled = B_FALSE; 2616bce0a86eSWENTAO YANG uint64_t maxbw; 2617bce0a86eSWENTAO YANG enum {P_MD_init = 0x1, 2618bce0a86eSWENTAO YANG P_MD_vlans = 0x2, 2619bce0a86eSWENTAO YANG P_MD_hio = 0x4, 2620bce0a86eSWENTAO YANG P_MD_maxbw = 0x8} updated; 2621bce0a86eSWENTAO YANG 2622bce0a86eSWENTAO YANG updated = P_MD_init; 2623c1c61f44Ssb155480 2624c1c61f44Ssb155480 /* 2625c1c61f44Ssb155480 * For now, we get port updates only if vlan ids changed. 2626c1c61f44Ssb155480 * We read the port num and do some sanity check. 2627c1c61f44Ssb155480 */ 2628c1c61f44Ssb155480 if (md_get_prop_val(curr_mdp, curr_mdex, id_propname, &cport_num)) { 2629c1c61f44Ssb155480 return (1); 2630c1c61f44Ssb155480 } 2631c1c61f44Ssb155480 2632c1c61f44Ssb155480 if (md_get_prop_val(prev_mdp, prev_mdex, id_propname, &pport_num)) { 2633c1c61f44Ssb155480 return (1); 2634c1c61f44Ssb155480 } 2635c1c61f44Ssb155480 if (cport_num != pport_num) 2636c1c61f44Ssb155480 return (1); 2637c1c61f44Ssb155480 2638c1c61f44Ssb155480 plistp = &(vswp->plist); 2639c1c61f44Ssb155480 2640c1c61f44Ssb155480 READ_ENTER(&plistp->lockrw); 2641c1c61f44Ssb155480 2642c1c61f44Ssb155480 portp = vsw_lookup_port(vswp, cport_num); 2643c1c61f44Ssb155480 if (portp == NULL) { 2644c1c61f44Ssb155480 RW_EXIT(&plistp->lockrw); 2645c1c61f44Ssb155480 return (1); 2646c1c61f44Ssb155480 } 2647c1c61f44Ssb155480 2648c1c61f44Ssb155480 /* Read the vlan ids */ 2649c1c61f44Ssb155480 vsw_vlan_read_ids(portp, VSW_VNETPORT, curr_mdp, curr_mdex, &pvid, 2650c1c61f44Ssb155480 &vids, &nvids, NULL); 2651c1c61f44Ssb155480 2652c1c61f44Ssb155480 /* Determine if there are any vlan id updates */ 2653c1c61f44Ssb155480 if ((pvid != portp->pvid) || /* pvid changed? */ 2654c1c61f44Ssb155480 (nvids != portp->nvids) || /* # of vids changed? */ 2655c1c61f44Ssb155480 ((nvids != 0) && (portp->nvids != 0) && /* vids changed? */ 2656da14cebeSEric Cheng !vsw_cmp_vids(vids, portp->vids, nvids))) { 2657bce0a86eSWENTAO YANG updated |= P_MD_vlans; 2658c1c61f44Ssb155480 } 2659c1c61f44Ssb155480 2660bce0a86eSWENTAO YANG /* Check if hybrid property is present */ 2661bce0a86eSWENTAO YANG if (md_get_prop_val(curr_mdp, curr_mdex, hybrid_propname, &val) == 0) { 2662bce0a86eSWENTAO YANG D1(vswp, "%s: prop(%s) found\n", __func__, hybrid_propname); 2663bce0a86eSWENTAO YANG hio_enabled = B_TRUE; 2664bce0a86eSWENTAO YANG } 2665c1c61f44Ssb155480 2666bce0a86eSWENTAO YANG if (portp->p_hio_enabled != hio_enabled) { 2667bce0a86eSWENTAO YANG updated |= P_MD_hio; 2668bce0a86eSWENTAO YANG } 2669bce0a86eSWENTAO YANG 2670bce0a86eSWENTAO YANG /* Check if maxbw property is present */ 2671bce0a86eSWENTAO YANG vsw_port_read_bandwidth(portp, curr_mdp, curr_mdex, &maxbw); 2672bce0a86eSWENTAO YANG if (maxbw != portp->p_bandwidth) { 2673bce0a86eSWENTAO YANG if (maxbw >= MRP_MAXBW_MINVAL || maxbw == 0) { 2674bce0a86eSWENTAO YANG updated |= P_MD_maxbw; 2675bce0a86eSWENTAO YANG } else { 2676bce0a86eSWENTAO YANG cmn_err(CE_NOTE, "!vsw%d: Unable to process bandwidth" 2677bce0a86eSWENTAO YANG " update for port %d as the specified value:%ld" 2678bce0a86eSWENTAO YANG " is invalid\n", 2679bce0a86eSWENTAO YANG vswp->instance, portp->p_instance, maxbw); 2680bce0a86eSWENTAO YANG } 2681bce0a86eSWENTAO YANG } 2682bce0a86eSWENTAO YANG 2683bce0a86eSWENTAO YANG if (updated & P_MD_vlans) { 2684c1c61f44Ssb155480 /* Remove existing vlan ids from the hash table. */ 2685c1c61f44Ssb155480 vsw_vlan_remove_ids(portp, VSW_VNETPORT); 2686c1c61f44Ssb155480 2687da14cebeSEric Cheng /* Reconfigure vlans with network device */ 2688da14cebeSEric Cheng vsw_mac_port_reconfig_vlans(portp, pvid, vids, nvids); 2689c1c61f44Ssb155480 2690c1c61f44Ssb155480 /* add these new vlan ids into hash table */ 2691c1c61f44Ssb155480 vsw_vlan_add_ids(portp, VSW_VNETPORT); 2692c1c61f44Ssb155480 2693c1c61f44Ssb155480 /* reset the port if it is vlan unaware (ver < 1.3) */ 2694c1c61f44Ssb155480 vsw_vlan_unaware_port_reset(portp); 2695678453a8Sspeer } 2696678453a8Sspeer 2697bce0a86eSWENTAO YANG if (updated & P_MD_hio) { 2698bce0a86eSWENTAO YANG vsw_hio_port_update(portp, hio_enabled); 2699678453a8Sspeer } 2700678453a8Sspeer 2701bce0a86eSWENTAO YANG if (updated & P_MD_maxbw) { 2702bce0a86eSWENTAO YANG vsw_update_bandwidth(NULL, portp, VSW_VNETPORT, maxbw); 2703678453a8Sspeer } 2704c1c61f44Ssb155480 2705c1c61f44Ssb155480 RW_EXIT(&plistp->lockrw); 27061ae08745Sheppo 27071ae08745Sheppo return (0); 27081ae08745Sheppo } 27091ae08745Sheppo 27101ae08745Sheppo /* 271106db247cSraghuram * vsw_mac_rx -- A common function to send packets to the interface. 271206db247cSraghuram * By default this function check if the interface is UP or not, the 271306db247cSraghuram * rest of the behaviour depends on the flags as below: 27141ae08745Sheppo * 271506db247cSraghuram * VSW_MACRX_PROMISC -- Check if the promisc mode set or not. 271606db247cSraghuram * VSW_MACRX_COPYMSG -- Make a copy of the message(s). 271706db247cSraghuram * VSW_MACRX_FREEMSG -- Free if the messages cannot be sent up the stack. 27181ae08745Sheppo */ 27191ae08745Sheppo void 2720f0ca1d9aSsb155480 vsw_mac_rx(vsw_t *vswp, mac_resource_handle_t mrh, 2721f0ca1d9aSsb155480 mblk_t *mp, vsw_macrx_flags_t flags) 27221ae08745Sheppo { 2723c1c61f44Ssb155480 mblk_t *mpt; 2724c1c61f44Ssb155480 272506db247cSraghuram D1(vswp, "%s:enter\n", __func__); 27261ae08745Sheppo READ_ENTER(&vswp->if_lockrw); 272706db247cSraghuram /* Check if the interface is up */ 272806db247cSraghuram if (!(vswp->if_state & VSW_IF_UP)) { 27291ae08745Sheppo RW_EXIT(&vswp->if_lockrw); 273006db247cSraghuram /* Free messages only if FREEMSG flag specified */ 273106db247cSraghuram if (flags & VSW_MACRX_FREEMSG) { 273206db247cSraghuram freemsgchain(mp); 273306db247cSraghuram } 273406db247cSraghuram D1(vswp, "%s:exit\n", __func__); 273506db247cSraghuram return; 273606db247cSraghuram } 273706db247cSraghuram /* 273806db247cSraghuram * If PROMISC flag is passed, then check if 273906db247cSraghuram * the interface is in the PROMISC mode. 274006db247cSraghuram * If not, drop the messages. 274106db247cSraghuram */ 274206db247cSraghuram if (flags & VSW_MACRX_PROMISC) { 274306db247cSraghuram if (!(vswp->if_state & VSW_IF_PROMISC)) { 274406db247cSraghuram RW_EXIT(&vswp->if_lockrw); 274506db247cSraghuram /* Free messages only if FREEMSG flag specified */ 274606db247cSraghuram if (flags & VSW_MACRX_FREEMSG) { 274706db247cSraghuram freemsgchain(mp); 274806db247cSraghuram } 274906db247cSraghuram D1(vswp, "%s:exit\n", __func__); 275006db247cSraghuram return; 275106db247cSraghuram } 275206db247cSraghuram } 275306db247cSraghuram RW_EXIT(&vswp->if_lockrw); 275406db247cSraghuram /* 275506db247cSraghuram * If COPYMSG flag is passed, then make a copy 275606db247cSraghuram * of the message chain and send up the copy. 275706db247cSraghuram */ 275806db247cSraghuram if (flags & VSW_MACRX_COPYMSG) { 275906db247cSraghuram mp = copymsgchain(mp); 2760f0ca1d9aSsb155480 if (mp == NULL) { 276106db247cSraghuram D1(vswp, "%s:exit\n", __func__); 276206db247cSraghuram return; 276306db247cSraghuram } 276406db247cSraghuram } 276506db247cSraghuram 2766f0ca1d9aSsb155480 D2(vswp, "%s: sending up stack", __func__); 2767c1c61f44Ssb155480 2768c1c61f44Ssb155480 mpt = NULL; 2769c1c61f44Ssb155480 (void) vsw_vlan_frame_untag(vswp, VSW_LOCALDEV, &mp, &mpt); 2770c1c61f44Ssb155480 if (mp != NULL) { 2771ba2e4443Sseb mac_rx(vswp->if_mh, mrh, mp); 2772c1c61f44Ssb155480 } 277306db247cSraghuram D1(vswp, "%s:exit\n", __func__); 27741ae08745Sheppo } 27751ae08745Sheppo 277606db247cSraghuram /* copy mac address of vsw into soft state structure */ 27771ae08745Sheppo static void 277806db247cSraghuram vsw_save_lmacaddr(vsw_t *vswp, uint64_t macaddr) 27791ae08745Sheppo { 27801ae08745Sheppo int i; 27811ae08745Sheppo 278206db247cSraghuram WRITE_ENTER(&vswp->if_lockrw); 278306db247cSraghuram for (i = ETHERADDRL - 1; i >= 0; i--) { 278406db247cSraghuram vswp->if_addr.ether_addr_octet[i] = macaddr & 0xFF; 278506db247cSraghuram macaddr >>= 8; 27861ae08745Sheppo } 278706db247cSraghuram RW_EXIT(&vswp->if_lockrw); 27881ae08745Sheppo } 2789da14cebeSEric Cheng 2790da14cebeSEric Cheng /* Compare VLAN ids, array size expected to be same. */ 2791da14cebeSEric Cheng static boolean_t 2792da14cebeSEric Cheng vsw_cmp_vids(vsw_vlanid_t *vids1, vsw_vlanid_t *vids2, int nvids) 2793da14cebeSEric Cheng { 2794da14cebeSEric Cheng int i, j; 2795da14cebeSEric Cheng uint16_t vid; 2796da14cebeSEric Cheng 2797da14cebeSEric Cheng for (i = 0; i < nvids; i++) { 2798da14cebeSEric Cheng vid = vids1[i].vl_vid; 2799da14cebeSEric Cheng for (j = 0; j < nvids; j++) { 2800da14cebeSEric Cheng if (vid == vids2[i].vl_vid) 2801da14cebeSEric Cheng break; 2802da14cebeSEric Cheng } 2803da14cebeSEric Cheng if (j == nvids) { 2804da14cebeSEric Cheng return (B_FALSE); 2805da14cebeSEric Cheng } 2806da14cebeSEric Cheng } 2807da14cebeSEric Cheng return (B_TRUE); 2808da14cebeSEric Cheng } 2809