xref: /onnv-gate/usr/src/uts/sun4v/io/vsw_phys.c (revision 11878:ac93462db6d7)
15373Sraghuram /*
25373Sraghuram  * CDDL HEADER START
35373Sraghuram  *
45373Sraghuram  * The contents of this file are subject to the terms of the
55373Sraghuram  * Common Development and Distribution License (the "License").
65373Sraghuram  * You may not use this file except in compliance with the License.
75373Sraghuram  *
85373Sraghuram  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95373Sraghuram  * or http://www.opensolaris.org/os/licensing.
105373Sraghuram  * See the License for the specific language governing permissions
115373Sraghuram  * and limitations under the License.
125373Sraghuram  *
135373Sraghuram  * When distributing Covered Code, include this CDDL HEADER in each
145373Sraghuram  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155373Sraghuram  * If applicable, add the following below this CDDL HEADER, with the
165373Sraghuram  * fields enclosed by brackets "[]" replaced with your own identifying
175373Sraghuram  * information: Portions Copyright [yyyy] [name of copyright owner]
185373Sraghuram  *
195373Sraghuram  * CDDL HEADER END
205373Sraghuram  */
215373Sraghuram 
225373Sraghuram /*
23*11878SVenu.Iyer@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
245373Sraghuram  * Use is subject to license terms.
255373Sraghuram  */
265373Sraghuram 
275373Sraghuram #include <sys/types.h>
285373Sraghuram #include <sys/errno.h>
295373Sraghuram #include <sys/debug.h>
305373Sraghuram #include <sys/time.h>
315373Sraghuram #include <sys/sysmacros.h>
325373Sraghuram #include <sys/systm.h>
335373Sraghuram #include <sys/user.h>
345373Sraghuram #include <sys/stropts.h>
355373Sraghuram #include <sys/stream.h>
365373Sraghuram #include <sys/strlog.h>
375373Sraghuram #include <sys/strsubr.h>
385373Sraghuram #include <sys/cmn_err.h>
395373Sraghuram #include <sys/cpu.h>
405373Sraghuram #include <sys/kmem.h>
415373Sraghuram #include <sys/conf.h>
425373Sraghuram #include <sys/ddi.h>
435373Sraghuram #include <sys/sunddi.h>
445373Sraghuram #include <sys/ksynch.h>
455373Sraghuram #include <sys/stat.h>
465373Sraghuram #include <sys/kstat.h>
475373Sraghuram #include <sys/vtrace.h>
485373Sraghuram #include <sys/strsun.h>
495373Sraghuram #include <sys/dlpi.h>
505373Sraghuram #include <sys/ethernet.h>
515373Sraghuram #include <net/if.h>
527027Ssb155480 #include <netinet/arp.h>
537027Ssb155480 #include <inet/arp.h>
545373Sraghuram #include <sys/varargs.h>
555373Sraghuram #include <sys/machsystm.h>
565373Sraghuram #include <sys/modctl.h>
575373Sraghuram #include <sys/modhash.h>
588275SEric Cheng #include <sys/mac_client.h>
598275SEric Cheng #include <sys/mac_provider.h>
609336SSriharsha.Basavapatna@Sun.COM #include <sys/mac_client_priv.h>
615373Sraghuram #include <sys/mac_ether.h>
625373Sraghuram #include <sys/taskq.h>
635373Sraghuram #include <sys/note.h>
645373Sraghuram #include <sys/mach_descrip.h>
655373Sraghuram #include <sys/mac.h>
6610795SWentao.Yang@Sun.COM #include <sys/mac_flow.h>
675373Sraghuram #include <sys/mdeg.h>
685373Sraghuram #include <sys/vsw.h>
698275SEric Cheng #include <sys/vlan.h>
705373Sraghuram 
715373Sraghuram /* MAC Ring table functions. */
728275SEric Cheng static void vsw_port_rx_cb(void *, mac_resource_handle_t, mblk_t *,
738275SEric Cheng     boolean_t);
748275SEric Cheng static void vsw_if_rx_cb(void *, mac_resource_handle_t, mblk_t *, boolean_t);
755373Sraghuram 
765373Sraghuram /* MAC layer routines */
778275SEric Cheng static int vsw_set_port_hw_addr(vsw_port_t *port);
788275SEric Cheng static int vsw_set_if_hw_addr(vsw_t *vswp);
798275SEric Cheng static	void vsw_unset_hw_addr(vsw_t *, vsw_port_t *, int);
808275SEric Cheng static int vsw_maccl_open(vsw_t *vswp, vsw_port_t *port, int type);
818275SEric Cheng static void vsw_maccl_close(vsw_t *vswp, vsw_port_t *port, int type);
828275SEric Cheng static void vsw_mac_multicast_add_all(vsw_t *vswp, vsw_port_t *portp, int type);
838275SEric Cheng static void vsw_mac_multicast_remove_all(vsw_t *vswp,
848275SEric Cheng     vsw_port_t *portp, int type);
858275SEric Cheng static void vsw_mac_add_vlans(vsw_t *vswp, mac_client_handle_t mch,
868275SEric Cheng     uint8_t *macaddr, uint16_t flags, vsw_vlanid_t *vids, int nvids);
878275SEric Cheng static void vsw_mac_remove_vlans(mac_client_handle_t mch, vsw_vlanid_t *vids,
888275SEric Cheng     int nvids);
897529SSriharsha.Basavapatna@Sun.COM static	void vsw_mac_set_mtu(vsw_t *vswp, uint32_t mtu);
9010795SWentao.Yang@Sun.COM static void vsw_maccl_set_bandwidth(vsw_t *vswp, vsw_port_t *port, int type,
9110795SWentao.Yang@Sun.COM     uint64_t maxbw);
929336SSriharsha.Basavapatna@Sun.COM static int vsw_notify_add(vsw_t *vswp);
939336SSriharsha.Basavapatna@Sun.COM static int vsw_notify_rem(vsw_t *vswp);
949336SSriharsha.Basavapatna@Sun.COM static void vsw_notify_cb(void *arg, mac_notify_type_t type);
959336SSriharsha.Basavapatna@Sun.COM static void vsw_notify_link(vsw_t *vswp);
965373Sraghuram 
975373Sraghuram /* Support functions */
985373Sraghuram int vsw_set_hw(vsw_t *, vsw_port_t *, int);
998275SEric Cheng void vsw_unset_hw(vsw_t *, vsw_port_t *, int);
1005373Sraghuram void vsw_reconfig_hw(vsw_t *);
1015373Sraghuram int vsw_mac_open(vsw_t *vswp);
1025373Sraghuram void vsw_mac_close(vsw_t *vswp);
1038275SEric Cheng int vsw_mac_multicast_add(vsw_t *vswp, vsw_port_t *port, mcst_addr_t *mcst_p,
1048275SEric Cheng     int type);
1058275SEric Cheng void vsw_mac_multicast_remove(vsw_t *vswp, vsw_port_t *port,
1068275SEric Cheng     mcst_addr_t *mcst_p, int type);
1078275SEric Cheng int vsw_mac_client_init(vsw_t *vswp, vsw_port_t *port, int type);
1088275SEric Cheng void vsw_mac_client_cleanup(vsw_t *vswp, vsw_port_t *port, int type);
1098275SEric Cheng void vsw_mac_cleanup_ports(vsw_t *vswp);
1105373Sraghuram void vsw_unset_addrs(vsw_t *vswp);
1115373Sraghuram void vsw_set_addrs(vsw_t *vswp);
1128275SEric Cheng mblk_t *vsw_tx_msg(vsw_t *, mblk_t *, int, vsw_port_t *);
1138275SEric Cheng void vsw_publish_macaddr(vsw_t *vswp, vsw_port_t *portp);
1148275SEric Cheng void vsw_port_mac_reconfig(vsw_port_t *portp, boolean_t update_vlans,
1158275SEric Cheng     uint16_t new_pvid, vsw_vlanid_t *new_vids, int new_nvids);
1168275SEric Cheng void vsw_mac_port_reconfig_vlans(vsw_port_t *portp, uint16_t new_pvid,
1178275SEric Cheng     vsw_vlanid_t *new_vids, int new_nvids);
1188275SEric Cheng void vsw_if_mac_reconfig(vsw_t *vswp, boolean_t update_vlans,
1198275SEric Cheng     uint16_t new_pvid, vsw_vlanid_t *new_vids, int new_nvids);
12010795SWentao.Yang@Sun.COM void vsw_update_bandwidth(vsw_t *vswp, vsw_port_t *port, int type,
12110795SWentao.Yang@Sun.COM     uint64_t maxbw);
1225373Sraghuram 
1238275SEric Cheng /*
1248275SEric Cheng  * Functions imported from other files.
1258275SEric Cheng  */
1268275SEric Cheng extern int vsw_portsend(vsw_port_t *port, mblk_t *mp);
1278275SEric Cheng extern void vsw_hio_stop_port(vsw_port_t *portp);
1288275SEric Cheng extern void vsw_hio_port_reset(vsw_port_t *portp, boolean_t immediate);
1298275SEric Cheng extern uint32_t vsw_publish_macaddr_count;
1308275SEric Cheng extern uint32_t vsw_vlan_frame_untag(void *arg, int type, mblk_t **np,
1318275SEric Cheng 	mblk_t **npt);
1329336SSriharsha.Basavapatna@Sun.COM extern void vsw_physlink_state_update(vsw_t *vswp);
1337529SSriharsha.Basavapatna@Sun.COM static char mac_mtu_propname[] = "mtu";
1347529SSriharsha.Basavapatna@Sun.COM 
1355373Sraghuram /*
1365373Sraghuram  * Tunables used in this file.
1375373Sraghuram  */
1385373Sraghuram extern int vsw_mac_open_retries;
1398275SEric Cheng 
1408275SEric Cheng #define	WRITE_MACCL_ENTER(vswp, port, type)	\
1418275SEric Cheng 	(type == VSW_LOCALDEV) ?  rw_enter(&vswp->maccl_rwlock, RW_WRITER) :\
1428275SEric Cheng 	rw_enter(&port->maccl_rwlock, RW_WRITER)
1438275SEric Cheng 
1448275SEric Cheng #define	READ_MACCL_ENTER(vswp, port, type)	\
1458275SEric Cheng 	(type == VSW_LOCALDEV) ?  rw_enter(&vswp->maccl_rwlock, RW_READER) :\
1468275SEric Cheng 	rw_enter(&port->maccl_rwlock, RW_READER)
1478275SEric Cheng 
1488275SEric Cheng #define	RW_MACCL_EXIT(vswp, port, type)	\
1498275SEric Cheng 	(type == VSW_LOCALDEV) ?  rw_exit(&vswp->maccl_rwlock) :	\
1508275SEric Cheng 	rw_exit(&port->maccl_rwlock)
1518275SEric Cheng 
1525373Sraghuram 
1535373Sraghuram /*
1548275SEric Cheng  * Locking strategy in this file is explained as follows:
1558275SEric Cheng  *	 - A global lock(vswp->mac_lock) is used to protect the
1568275SEric Cheng  *	   MAC calls that deal with entire device. That is, the
1578275SEric Cheng  *	   operations that deal with mac_handle which include
1588275SEric Cheng  *	   mac_open()/close() and mac_client_open().
1598275SEric Cheng  *
1608275SEric Cheng  *	- A per port/interface RW lock(maccl_rwlock) is used protect
1618275SEric Cheng  *	  the operations that deal with the MAC client.
1625373Sraghuram  *
1638275SEric Cheng  *	When both mac_lock and maccl_rwlock need to be held, the
1648275SEric Cheng  *	mac_lock need be acquired first and then maccl_rwlock. That is,
1658275SEric Cheng  *		mac_lock---->maccl_rwlock
1668275SEric Cheng  *
1678275SEric Cheng  *	The 'mca_lock' that protects the mcast list is also acquired
1688275SEric Cheng  *	within the context of maccl_rwlock. The hierarchy for this
1698275SEric Cheng  *	one is as below:
1708275SEric Cheng  *		maccl_rwlock---->mca_lock
1715373Sraghuram  */
1725373Sraghuram 
1735373Sraghuram 
1745373Sraghuram /*
1755373Sraghuram  * Program unicast and multicast addresses of vsw interface and the ports
1768275SEric Cheng  * into the network device.
1775373Sraghuram  */
1785373Sraghuram void
vsw_set_addrs(vsw_t * vswp)1795373Sraghuram vsw_set_addrs(vsw_t *vswp)
1805373Sraghuram {
1815373Sraghuram 	vsw_port_list_t	*plist = &vswp->plist;
1825373Sraghuram 	vsw_port_t	*port;
1835373Sraghuram 	int		rv;
1845373Sraghuram 
1855373Sraghuram 	READ_ENTER(&vswp->if_lockrw);
1865373Sraghuram 
1875373Sraghuram 	if (vswp->if_state & VSW_IF_UP) {
1885373Sraghuram 
1898275SEric Cheng 		/* Open a mac client and program addresses */
1908275SEric Cheng 		rv = vsw_mac_client_init(vswp, NULL, VSW_LOCALDEV);
1918275SEric Cheng 		if (rv != 0) {
1928275SEric Cheng 			cmn_err(CE_NOTE,
1938275SEric Cheng 			    "!vsw%d: failed to program interface "
1948275SEric Cheng 			    "unicast address\n", vswp->instance);
1958275SEric Cheng 		}
1968275SEric Cheng 
1978275SEric Cheng 		/*
1988275SEric Cheng 		 * Notify the MAC layer of the changed address.
1998275SEric Cheng 		 */
2008275SEric Cheng 		if (rv == 0) {
2015373Sraghuram 			mac_unicst_update(vswp->if_mh,
2025373Sraghuram 			    (uint8_t *)&vswp->if_addr);
2035373Sraghuram 		}
2045373Sraghuram 
2055373Sraghuram 	}
2065373Sraghuram 
2075373Sraghuram 	RW_EXIT(&vswp->if_lockrw);
2085373Sraghuram 
2095373Sraghuram 	WRITE_ENTER(&plist->lockrw);
2105373Sraghuram 
2118275SEric Cheng 	/* program unicast address of ports in the network device */
2125373Sraghuram 	for (port = plist->head; port != NULL; port = port->p_next) {
2138275SEric Cheng 		if (port->addr_set) /* addr already set */
2145373Sraghuram 			continue;
2158275SEric Cheng 
2168275SEric Cheng 		/* Open a mac client and program addresses */
2178275SEric Cheng 		rv = vsw_mac_client_init(vswp, port, VSW_VNETPORT);
2188275SEric Cheng 		if (rv != 0) {
2195373Sraghuram 			cmn_err(CE_NOTE,
2208275SEric Cheng 			    "!vsw%d: failed to program port(%d) "
2218275SEric Cheng 			    "unicast address\n", vswp->instance,
2228275SEric Cheng 			    port->p_instance);
2235373Sraghuram 		}
2245373Sraghuram 	}
2257027Ssb155480 	/* announce macaddr of vnets to the physical switch */
2267027Ssb155480 	if (vsw_publish_macaddr_count != 0) {	/* enabled */
2277027Ssb155480 		for (port = plist->head; port != NULL; port = port->p_next) {
2288275SEric Cheng 			vsw_publish_macaddr(vswp, port);
2297027Ssb155480 		}
2307027Ssb155480 	}
2317027Ssb155480 
2325373Sraghuram 	RW_EXIT(&plist->lockrw);
2335373Sraghuram }
2345373Sraghuram 
2355373Sraghuram /*
2368275SEric Cheng  * Remove unicast, multicast addresses and close mac clients
2378275SEric Cheng  * for the vsw interface and all ports.
2385373Sraghuram  */
2395373Sraghuram void
vsw_unset_addrs(vsw_t * vswp)2405373Sraghuram vsw_unset_addrs(vsw_t *vswp)
2415373Sraghuram {
2425373Sraghuram 	READ_ENTER(&vswp->if_lockrw);
2435373Sraghuram 	if (vswp->if_state & VSW_IF_UP) {
2445373Sraghuram 
2458275SEric Cheng 		/* Cleanup and close the mac client for the interface */
2468275SEric Cheng 		vsw_mac_client_cleanup(vswp, NULL, VSW_LOCALDEV);
2475373Sraghuram 	}
2485373Sraghuram 	RW_EXIT(&vswp->if_lockrw);
2495373Sraghuram 
2508275SEric Cheng 	/* Cleanup and close the mac clients for all ports */
2518275SEric Cheng 	vsw_mac_cleanup_ports(vswp);
2525373Sraghuram }
2535373Sraghuram 
2545373Sraghuram /*
2558275SEric Cheng  * Open the underlying network device for access in layer2 mode.
2565373Sraghuram  * Returns:
2578275SEric Cheng  *	0 on success
2588275SEric Cheng  *	EAGAIN if mac_open() fails due to the device being not available yet.
2598275SEric Cheng  *	EIO on any other failures.
2605373Sraghuram  */
2615373Sraghuram int
vsw_mac_open(vsw_t * vswp)2625373Sraghuram vsw_mac_open(vsw_t *vswp)
2635373Sraghuram {
2648275SEric Cheng 	int			rv;
2655373Sraghuram 
2668275SEric Cheng 	ASSERT(MUTEX_HELD(&vswp->mac_lock));
2675373Sraghuram 
2685373Sraghuram 	if (vswp->mh != NULL) {
2695373Sraghuram 		/* already open */
2705373Sraghuram 		return (0);
2715373Sraghuram 	}
2725373Sraghuram 
2735373Sraghuram 	if (vswp->mac_open_retries++ >= vsw_mac_open_retries) {
2745373Sraghuram 		/* exceeded max retries */
2755373Sraghuram 		return (EIO);
2765373Sraghuram 	}
2775373Sraghuram 
2785895Syz147064 	if ((rv = mac_open_by_linkname(vswp->physname, &vswp->mh)) != 0) {
2795373Sraghuram 		/*
2805895Syz147064 		 * If mac_open() failed and the error indicates that either
2815895Syz147064 		 * the dlmgmtd door or the device is not available yet, we
2825895Syz147064 		 * return EAGAIN to indicate that mac_open() needs to be
2835895Syz147064 		 * retried. For example, this may happen during boot up, if
2845895Syz147064 		 * the required link aggregation groups(devices) have not
2855895Syz147064 		 * been created yet.
2865373Sraghuram 		 */
2875895Syz147064 		if (rv == ENOENT || rv == EBADF) {
2885373Sraghuram 			return (EAGAIN);
2895373Sraghuram 		} else {
2909336SSriharsha.Basavapatna@Sun.COM 			cmn_err(CE_WARN, "!vsw%d: mac_open %s failed rv:%x\n",
2915373Sraghuram 			    vswp->instance, vswp->physname, rv);
2925373Sraghuram 			return (EIO);
2935373Sraghuram 		}
2945373Sraghuram 	}
2958275SEric Cheng 	vswp->mac_open_retries = 0;
2965373Sraghuram 
2978275SEric Cheng 	vsw_mac_set_mtu(vswp, vswp->mtu);
2985373Sraghuram 
2999336SSriharsha.Basavapatna@Sun.COM 	rv = vsw_notify_add(vswp);
3009336SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
3019336SSriharsha.Basavapatna@Sun.COM 		cmn_err(CE_CONT, "!vsw%d: mac_notify_add %s failed rv:%x\n",
3029336SSriharsha.Basavapatna@Sun.COM 		    vswp->instance, vswp->physname, rv);
3039336SSriharsha.Basavapatna@Sun.COM 	}
3049336SSriharsha.Basavapatna@Sun.COM 
3055373Sraghuram 	return (0);
3065373Sraghuram }
3075373Sraghuram 
3085373Sraghuram /*
3095373Sraghuram  * Close the underlying physical device.
3105373Sraghuram  */
3115373Sraghuram void
vsw_mac_close(vsw_t * vswp)3125373Sraghuram vsw_mac_close(vsw_t *vswp)
3135373Sraghuram {
3148275SEric Cheng 	ASSERT(MUTEX_HELD(&vswp->mac_lock));
3155373Sraghuram 
3165373Sraghuram 	if (vswp->mh != NULL) {
3179336SSriharsha.Basavapatna@Sun.COM 		if (vswp->mnh != 0) {
3189336SSriharsha.Basavapatna@Sun.COM 			(void) vsw_notify_rem(vswp);
3199336SSriharsha.Basavapatna@Sun.COM 			vswp->mnh = 0;
3209336SSriharsha.Basavapatna@Sun.COM 		}
3218275SEric Cheng 		if (vswp->mtu != vswp->mtu_physdev_orig) {
3228275SEric Cheng 			vsw_mac_set_mtu(vswp, vswp->mtu_physdev_orig);
3238275SEric Cheng 		}
3245373Sraghuram 		mac_close(vswp->mh);
3255373Sraghuram 		vswp->mh = NULL;
3265373Sraghuram 	}
3275373Sraghuram }
3285373Sraghuram 
3295373Sraghuram /*
3308275SEric Cheng  * Add multicast addr.
3318275SEric Cheng  */
3328275SEric Cheng int
vsw_mac_multicast_add(vsw_t * vswp,vsw_port_t * port,mcst_addr_t * mcst_p,int type)3338275SEric Cheng vsw_mac_multicast_add(vsw_t *vswp, vsw_port_t *port, mcst_addr_t *mcst_p,
3348275SEric Cheng     int type)
3358275SEric Cheng {
3368275SEric Cheng 	int			ret = 0;
3378275SEric Cheng 	mac_client_handle_t	mch;
3388275SEric Cheng 
3398275SEric Cheng 	WRITE_MACCL_ENTER(vswp, port, type);
3408275SEric Cheng 
3418275SEric Cheng 	mch = (type == VSW_LOCALDEV) ? vswp->mch : port->p_mch;
3428275SEric Cheng 
3438275SEric Cheng 	if (mch != NULL) {
3448275SEric Cheng 		ret = mac_multicast_add(mch, mcst_p->mca.ether_addr_octet);
3458275SEric Cheng 		if (ret != 0) {
3468275SEric Cheng 			cmn_err(CE_WARN, "!vsw%d: unable to "
3478275SEric Cheng 			    "program multicast address(%s) err=%d",
3488275SEric Cheng 			    vswp->instance,
3498275SEric Cheng 			    ether_sprintf((void *)&mcst_p->mca), ret);
3508275SEric Cheng 			RW_MACCL_EXIT(vswp, port, type);
3518275SEric Cheng 			return (ret);
3528275SEric Cheng 		}
3538275SEric Cheng 		mcst_p->mac_added = B_TRUE;
3548275SEric Cheng 	}
3558275SEric Cheng 
3568275SEric Cheng 	RW_MACCL_EXIT(vswp, port, type);
3578275SEric Cheng 	return (ret);
3588275SEric Cheng }
3598275SEric Cheng 
3608275SEric Cheng /*
3618275SEric Cheng  * Remove multicast addr.
3628275SEric Cheng  */
3638275SEric Cheng void
vsw_mac_multicast_remove(vsw_t * vswp,vsw_port_t * port,mcst_addr_t * mcst_p,int type)3648275SEric Cheng vsw_mac_multicast_remove(vsw_t *vswp, vsw_port_t *port, mcst_addr_t *mcst_p,
3658275SEric Cheng     int type)
3668275SEric Cheng {
3678275SEric Cheng 	mac_client_handle_t	mch;
3688275SEric Cheng 
3698275SEric Cheng 	WRITE_MACCL_ENTER(vswp, port, type);
3708275SEric Cheng 	mch = (type == VSW_LOCALDEV) ? vswp->mch : port->p_mch;
3718275SEric Cheng 
3728275SEric Cheng 	if (mch != NULL && mcst_p->mac_added) {
3738275SEric Cheng 		mac_multicast_remove(mch, mcst_p->mca.ether_addr_octet);
3748275SEric Cheng 		mcst_p->mac_added = B_FALSE;
3758275SEric Cheng 	}
3768275SEric Cheng 	RW_MACCL_EXIT(vswp, port, type);
3778275SEric Cheng }
3788275SEric Cheng 
3798275SEric Cheng 
3808275SEric Cheng /*
3818275SEric Cheng  * Add all multicast addresses of the port.
3828275SEric Cheng  */
3838275SEric Cheng static void
vsw_mac_multicast_add_all(vsw_t * vswp,vsw_port_t * portp,int type)3848275SEric Cheng vsw_mac_multicast_add_all(vsw_t *vswp, vsw_port_t *portp, int type)
3858275SEric Cheng {
3868275SEric Cheng 	mcst_addr_t		*mcap;
3878275SEric Cheng 	mac_client_handle_t	mch;
3888275SEric Cheng 	kmutex_t		*mca_lockp;
3898275SEric Cheng 	int			rv;
3908275SEric Cheng 
3918275SEric Cheng 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
3928275SEric Cheng 	if (type == VSW_LOCALDEV) {
3938275SEric Cheng 		ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock));
3948275SEric Cheng 		mch = vswp->mch;
3958275SEric Cheng 		mcap = vswp->mcap;
3968275SEric Cheng 		mca_lockp = &vswp->mca_lock;
3978275SEric Cheng 	} else {
3988275SEric Cheng 		ASSERT(RW_WRITE_HELD(&portp->maccl_rwlock));
3998275SEric Cheng 		mch = portp->p_mch;
4008275SEric Cheng 		mcap = portp->mcap;
4018275SEric Cheng 		mca_lockp = &portp->mca_lock;
4028275SEric Cheng 	}
4038275SEric Cheng 
4048275SEric Cheng 	if (mch == NULL)
4058275SEric Cheng 		return;
4068275SEric Cheng 
4078275SEric Cheng 	mutex_enter(mca_lockp);
4088275SEric Cheng 	for (mcap = mcap; mcap != NULL; mcap = mcap->nextp) {
4098275SEric Cheng 		if (mcap->mac_added)
4108275SEric Cheng 			continue;
4118275SEric Cheng 		rv = mac_multicast_add(mch, (uchar_t *)&mcap->mca);
4128275SEric Cheng 		if (rv == 0) {
4138275SEric Cheng 			mcap->mac_added = B_TRUE;
4148275SEric Cheng 		} else {
4158275SEric Cheng 			cmn_err(CE_WARN, "!vsw%d: unable to program "
4168275SEric Cheng 			    "multicast address(%s) err=%d", vswp->instance,
4178275SEric Cheng 			    ether_sprintf((void *)&mcap->mca), rv);
4188275SEric Cheng 		}
4198275SEric Cheng 	}
4208275SEric Cheng 	mutex_exit(mca_lockp);
4218275SEric Cheng }
4228275SEric Cheng 
4238275SEric Cheng /*
4248275SEric Cheng  * Remove all multicast addresses of the port.
4258275SEric Cheng  */
4268275SEric Cheng static void
vsw_mac_multicast_remove_all(vsw_t * vswp,vsw_port_t * portp,int type)4278275SEric Cheng vsw_mac_multicast_remove_all(vsw_t *vswp, vsw_port_t *portp, int type)
4288275SEric Cheng {
4298275SEric Cheng 	mac_client_handle_t	mch;
4308275SEric Cheng 	mcst_addr_t		*mcap;
4318275SEric Cheng 	kmutex_t		*mca_lockp;
4328275SEric Cheng 
4338275SEric Cheng 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
4348275SEric Cheng 	if (type == VSW_LOCALDEV) {
4358275SEric Cheng 		ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock));
4368275SEric Cheng 		mch = vswp->mch;
4378275SEric Cheng 		mcap = vswp->mcap;
4388275SEric Cheng 		mca_lockp = &vswp->mca_lock;
4398275SEric Cheng 	} else {
4408275SEric Cheng 		ASSERT(RW_WRITE_HELD(&portp->maccl_rwlock));
4418275SEric Cheng 		mch = portp->p_mch;
4428275SEric Cheng 		mcap = portp->mcap;
4438275SEric Cheng 		mca_lockp = &portp->mca_lock;
4448275SEric Cheng 	}
4458275SEric Cheng 
4468275SEric Cheng 	if (mch == NULL)
4478275SEric Cheng 		return;
4488275SEric Cheng 
4498275SEric Cheng 	mutex_enter(mca_lockp);
4508275SEric Cheng 	for (; mcap != NULL; mcap = mcap->nextp) {
4518275SEric Cheng 		if (!mcap->mac_added)
4528275SEric Cheng 			continue;
4538275SEric Cheng 		(void) mac_multicast_remove(mch, (uchar_t *)&mcap->mca);
4548275SEric Cheng 		mcap->mac_added = B_FALSE;
4558275SEric Cheng 	}
4568275SEric Cheng 	mutex_exit(mca_lockp);
4578275SEric Cheng }
4588275SEric Cheng 
45910795SWentao.Yang@Sun.COM void
vsw_update_bandwidth(vsw_t * vswp,vsw_port_t * port,int type,uint64_t maxbw)46010795SWentao.Yang@Sun.COM vsw_update_bandwidth(vsw_t *vswp, vsw_port_t *port, int type, uint64_t maxbw)
46110795SWentao.Yang@Sun.COM {
46210795SWentao.Yang@Sun.COM 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
46310795SWentao.Yang@Sun.COM 
46410795SWentao.Yang@Sun.COM 	WRITE_MACCL_ENTER(vswp, port, type);
46510795SWentao.Yang@Sun.COM 	vsw_maccl_set_bandwidth(vswp, port, type, maxbw);
46610795SWentao.Yang@Sun.COM 	RW_MACCL_EXIT(vswp, port, type);
46710795SWentao.Yang@Sun.COM }
46810795SWentao.Yang@Sun.COM 
4698275SEric Cheng /*
4708275SEric Cheng  * Open a mac client and program uncast and multicast addresses
4718275SEric Cheng  * for a port or the interface.
4728275SEric Cheng  * Returns:
4738275SEric Cheng  *	0 on success
4748275SEric Cheng  *	non-zero for failure.
4755373Sraghuram  */
4765373Sraghuram int
vsw_mac_client_init(vsw_t * vswp,vsw_port_t * port,int type)4778275SEric Cheng vsw_mac_client_init(vsw_t *vswp, vsw_port_t *port, int type)
4785373Sraghuram {
4798275SEric Cheng 	int rv;
4808275SEric Cheng 
4818275SEric Cheng 	mutex_enter(&vswp->mac_lock);
4828275SEric Cheng 	WRITE_MACCL_ENTER(vswp, port, type);
4838275SEric Cheng 	rv = vsw_maccl_open(vswp, port, type);
4845373Sraghuram 
4858275SEric Cheng 	/* Release mac_lock now */
4868275SEric Cheng 	mutex_exit(&vswp->mac_lock);
4875373Sraghuram 
4888275SEric Cheng 	if (rv == 0) {
4898275SEric Cheng 		(void) vsw_set_hw(vswp, port, type);
4908275SEric Cheng 		vsw_mac_multicast_add_all(vswp, port, type);
4918275SEric Cheng 	}
4928275SEric Cheng 	RW_MACCL_EXIT(vswp, port, type);
4938275SEric Cheng 	return (rv);
4948275SEric Cheng }
4955373Sraghuram 
4968275SEric Cheng /*
4978275SEric Cheng  * Open a MAC client for a port or an interface.
4988275SEric Cheng  * The flags and their purpose as below:
4998275SEric Cheng  *
5008275SEric Cheng  *	MAC_OPEN_FLAGS_SHARES_DESIRED -- This flag is used to indicate
5018275SEric Cheng  *	that a port desires a Share. This will be the case with the
5028275SEric Cheng  *	the ports that have hybrid mode enabled. This will only cause
5038275SEric Cheng  *	MAC layer to allocate a share and corresponding resources
504*11878SVenu.Iyer@Sun.COM  *	ahead of time. Ports that are not HybridIO enabled are
505*11878SVenu.Iyer@Sun.COM  *	associated with default group & resources.
5068275SEric Cheng  *
5079024SVenu.Iyer@Sun.COM  *	MAC_UNICAST_TAG_DISABLE -- This flag is used for VLAN
5088275SEric Cheng  *	support. It will cause MAC to not add any tags, but expect
5098275SEric Cheng  *	vsw to tag the packets.
5108275SEric Cheng  *
5119024SVenu.Iyer@Sun.COM  *	MAC_UNICAST_STRIP_DISABLE -- This flag is used for VLAN
5128275SEric Cheng  *	support. It will case the MAC layer to not strip the tags.
5138275SEric Cheng  *	Vsw may have to strip the tag for pvid case.
5148275SEric Cheng  */
5158275SEric Cheng static int
vsw_maccl_open(vsw_t * vswp,vsw_port_t * port,int type)5168275SEric Cheng vsw_maccl_open(vsw_t *vswp, vsw_port_t *port, int type)
5178275SEric Cheng {
5188275SEric Cheng 	int		rv = 0;
5198275SEric Cheng 	int		instance;
5208275SEric Cheng 	char		mac_cl_name[MAXNAMELEN];
5218275SEric Cheng 	const char	*dev_name;
5228275SEric Cheng 	mac_client_handle_t *mchp;
523*11878SVenu.Iyer@Sun.COM 	uint64_t flags = 0;
5247529SSriharsha.Basavapatna@Sun.COM 
5258275SEric Cheng 	ASSERT(MUTEX_HELD(&vswp->mac_lock));
5268275SEric Cheng 	if (vswp->mh == NULL) {
5275373Sraghuram 		/*
5288275SEric Cheng 		 * In case net-dev is changed (either set to nothing or
5298275SEric Cheng 		 * using aggregation device), return success here as the
5308275SEric Cheng 		 * timeout mechanism will handle it.
5315373Sraghuram 		 */
5328275SEric Cheng 		return (0);
5335373Sraghuram 	}
5345373Sraghuram 
5358275SEric Cheng 	mchp = (type == VSW_LOCALDEV) ? &vswp->mch : &port->p_mch;
5368275SEric Cheng 	if (*mchp != NULL) {
5378275SEric Cheng 		/* already open */
5388275SEric Cheng 		return (0);
5398275SEric Cheng 	}
5408275SEric Cheng 	dev_name = ddi_driver_name(vswp->dip);
5418275SEric Cheng 	instance = ddi_get_instance(vswp->dip);
5428275SEric Cheng 	if (type == VSW_VNETPORT) {
543*11878SVenu.Iyer@Sun.COM 		if (port->p_hio_enabled)
5448275SEric Cheng 			flags |= MAC_OPEN_FLAGS_SHARES_DESIRED;
5458275SEric Cheng 		(void) snprintf(mac_cl_name, MAXNAMELEN, "%s%d%s%d", dev_name,
5468275SEric Cheng 		    instance, "_port", port->p_instance);
5478275SEric Cheng 	} else {
5488275SEric Cheng 		(void) snprintf(mac_cl_name, MAXNAMELEN, "%s%s%d",
5498275SEric Cheng 		    dev_name, "_if", instance);
5505373Sraghuram 	}
5515373Sraghuram 
5528275SEric Cheng 	rv = mac_client_open(vswp->mh, mchp, mac_cl_name, flags);
5538275SEric Cheng 	if (rv != 0) {
5548275SEric Cheng 		cmn_err(CE_NOTE, "!vsw%d:%s mac_client_open() failed\n",
5558275SEric Cheng 		    vswp->instance, mac_cl_name);
5568275SEric Cheng 	}
557*11878SVenu.Iyer@Sun.COM 
558*11878SVenu.Iyer@Sun.COM 	if (type != VSW_VNETPORT || !port->p_hio_enabled)
559*11878SVenu.Iyer@Sun.COM 		mac_client_set_rings(*mchp, MAC_RXRINGS_NONE, MAC_TXRINGS_NONE);
560*11878SVenu.Iyer@Sun.COM 
5618275SEric Cheng 	return (rv);
5625373Sraghuram }
5635373Sraghuram 
5648275SEric Cheng /*
5658275SEric Cheng  * Clean up by removing uncast, multicast addresses and
5668275SEric Cheng  * closing the MAC client for a port or the interface.
5678275SEric Cheng  */
5685373Sraghuram void
vsw_mac_client_cleanup(vsw_t * vswp,vsw_port_t * port,int type)5698275SEric Cheng vsw_mac_client_cleanup(vsw_t *vswp, vsw_port_t *port, int type)
5705373Sraghuram {
5718275SEric Cheng 	WRITE_MACCL_ENTER(vswp, port, type);
5729943SWentao.Yang@Sun.COM 	vsw_mac_multicast_remove_all(vswp, port, type);
5738275SEric Cheng 	vsw_unset_hw(vswp, port, type);
5748275SEric Cheng 	vsw_maccl_close(vswp, port, type);
5758275SEric Cheng 	RW_MACCL_EXIT(vswp, port, type);
5768275SEric Cheng }
5775373Sraghuram 
5788275SEric Cheng /*
5798275SEric Cheng  * Close a MAC client for a port or an interface.
5808275SEric Cheng  */
5818275SEric Cheng static void
vsw_maccl_close(vsw_t * vswp,vsw_port_t * port,int type)5828275SEric Cheng vsw_maccl_close(vsw_t *vswp, vsw_port_t *port, int type)
5838275SEric Cheng {
5848275SEric Cheng 	mac_client_handle_t *mchp;
5855373Sraghuram 
5868275SEric Cheng 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
5878275SEric Cheng 
5888275SEric Cheng 	mchp = (type == VSW_LOCALDEV) ? &vswp->mch : &port->p_mch;
5898275SEric Cheng 	if (*mchp != NULL) {
5908275SEric Cheng 		mac_client_close(*mchp, 0);
5918275SEric Cheng 		*mchp = NULL;
5925373Sraghuram 	}
5938275SEric Cheng }
5945373Sraghuram 
5958275SEric Cheng /*
5968275SEric Cheng  * Cleanup MAC client related stuff for all ports.
5978275SEric Cheng  */
5988275SEric Cheng void
vsw_mac_cleanup_ports(vsw_t * vswp)5998275SEric Cheng vsw_mac_cleanup_ports(vsw_t *vswp)
6008275SEric Cheng {
6018275SEric Cheng 	vsw_port_list_t		*plist = &vswp->plist;
6028275SEric Cheng 	vsw_port_t		*port;
6035373Sraghuram 
6048275SEric Cheng 	READ_ENTER(&plist->lockrw);
6058275SEric Cheng 	for (port = plist->head; port != NULL; port = port->p_next) {
6068275SEric Cheng 		vsw_mac_client_cleanup(vswp, port, VSW_VNETPORT);
6078275SEric Cheng 	}
6088275SEric Cheng 	RW_EXIT(&plist->lockrw);
6095373Sraghuram }
6105373Sraghuram 
6115373Sraghuram /*
6125373Sraghuram  * Depending on the mode specified, the capabilites and capacity
6135373Sraghuram  * of the underlying device setup the physical device.
6145373Sraghuram  *
6155373Sraghuram  * If in layer 3 mode, then do nothing.
6165373Sraghuram  *
6178275SEric Cheng  * If in layer 2 mode, open a mac client and program the mac-address
6188275SEric Cheng  * and vlan-ids. The MAC layer will take care of programming
6198275SEric Cheng  * the address into h/w or set the h/w into promiscuous mode.
6205373Sraghuram  *
6215373Sraghuram  * Returns 0 success, 1 on failure.
6225373Sraghuram  */
6235373Sraghuram int
vsw_set_hw(vsw_t * vswp,vsw_port_t * port,int type)6245373Sraghuram vsw_set_hw(vsw_t *vswp, vsw_port_t *port, int type)
6255373Sraghuram {
6268275SEric Cheng 	int			err = 1;
6275373Sraghuram 
6285373Sraghuram 	D1(vswp, "%s: enter", __func__);
6295373Sraghuram 
6305373Sraghuram 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
6315373Sraghuram 
6328275SEric Cheng 	if (vswp->smode == VSW_LAYER3)
6335373Sraghuram 		return (0);
6345373Sraghuram 
6355373Sraghuram 	if (type == VSW_VNETPORT) {
6365373Sraghuram 		ASSERT(port != NULL);
6378275SEric Cheng 		err = vsw_set_port_hw_addr(port);
6385373Sraghuram 	} else {
6398275SEric Cheng 		err = vsw_set_if_hw_addr(vswp);
6405373Sraghuram 	}
6415373Sraghuram 
6425373Sraghuram 	D1(vswp, "%s: exit", __func__);
6438275SEric Cheng 	return (err);
6445373Sraghuram }
6455373Sraghuram 
6465373Sraghuram /*
6475373Sraghuram  * If in layer 3 mode do nothing.
6485373Sraghuram  *
6495373Sraghuram  * If in layer 2 switched mode remove the address from the physical
6505373Sraghuram  * device.
6515373Sraghuram  *
6525373Sraghuram  * If in layer 2 promiscuous mode disable promisc mode.
6535373Sraghuram  *
6545373Sraghuram  * Returns 0 on success.
6555373Sraghuram  */
6568275SEric Cheng void
vsw_unset_hw(vsw_t * vswp,vsw_port_t * port,int type)6575373Sraghuram vsw_unset_hw(vsw_t *vswp, vsw_port_t *port, int type)
6585373Sraghuram {
6598275SEric Cheng 	D1(vswp, "%s: enter", __func__);
6608275SEric Cheng 
6618275SEric Cheng 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
6628275SEric Cheng 
6638275SEric Cheng 	if (vswp->smode == VSW_LAYER3)
6648275SEric Cheng 		return;
6658275SEric Cheng 
6668275SEric Cheng 	if (type == VSW_VNETPORT) {
6678275SEric Cheng 		ASSERT(port != NULL);
6688275SEric Cheng 		vsw_unset_hw_addr(vswp, port, type);
6698275SEric Cheng 	} else {
6708275SEric Cheng 		vsw_unset_hw_addr(vswp, NULL, type);
6718275SEric Cheng 	}
6728275SEric Cheng 
6738275SEric Cheng 	D1(vswp, "%s: exit", __func__);
6748275SEric Cheng }
6758275SEric Cheng 
6768275SEric Cheng /*
6778275SEric Cheng  * Program the macaddress and vlans of a port.
6788275SEric Cheng  *
6798275SEric Cheng  * Returns 0 on sucess, 1 on failure.
6808275SEric Cheng  */
6818275SEric Cheng static int
vsw_set_port_hw_addr(vsw_port_t * port)6828275SEric Cheng vsw_set_port_hw_addr(vsw_port_t *port)
6838275SEric Cheng {
6848275SEric Cheng 	vsw_t			*vswp = port->p_vswp;
6858275SEric Cheng 	mac_diag_t		diag;
6868275SEric Cheng 	uint8_t			*macaddr;
6878275SEric Cheng 	uint16_t		vid = VLAN_ID_NONE;
6888275SEric Cheng 	int			rv;
6899024SVenu.Iyer@Sun.COM 	uint16_t		mac_flags = MAC_UNICAST_TAG_DISABLE |
6909024SVenu.Iyer@Sun.COM 	    MAC_UNICAST_STRIP_DISABLE;
6915373Sraghuram 
6925373Sraghuram 	D1(vswp, "%s: enter", __func__);
6935373Sraghuram 
6948275SEric Cheng 	ASSERT(RW_WRITE_HELD(&port->maccl_rwlock));
6958275SEric Cheng 	if (port->p_mch == NULL)
6965373Sraghuram 		return (0);
6975373Sraghuram 
6988275SEric Cheng 	/*
6998275SEric Cheng 	 * If the port has a specific 'pvid', then
7008275SEric Cheng 	 * register with that vlan-id, otherwise register
7018275SEric Cheng 	 * with VLAN_ID_NONE.
7028275SEric Cheng 	 */
7038275SEric Cheng 	if (port->pvid != vswp->default_vlan_id) {
7048275SEric Cheng 		vid = port->pvid;
7058275SEric Cheng 	}
7068275SEric Cheng 	macaddr = (uint8_t *)port->p_macaddr.ether_addr_octet;
7075373Sraghuram 
7088275SEric Cheng 	if (!(vswp->smode & VSW_LAYER2_PROMISC)) {
7098275SEric Cheng 		mac_flags |= MAC_UNICAST_HW;
7108275SEric Cheng 	}
7115373Sraghuram 
7128275SEric Cheng 	if (port->addr_set == B_FALSE) {
7138275SEric Cheng 		port->p_muh = NULL;
7148275SEric Cheng 		rv = mac_unicast_add(port->p_mch, macaddr, mac_flags,
7158275SEric Cheng 		    &port->p_muh, vid, &diag);
7165373Sraghuram 
7178275SEric Cheng 		if (rv != 0) {
7188275SEric Cheng 			cmn_err(CE_WARN, "vsw%d: Failed to program"
7198275SEric Cheng 			    "macaddr,vid(%s, %d) err=%d",
7208275SEric Cheng 			    vswp->instance, ether_sprintf((void *)macaddr),
7218275SEric Cheng 			    vid, rv);
7228275SEric Cheng 			return (rv);
7235373Sraghuram 		}
7248275SEric Cheng 		port->addr_set = B_TRUE;
7255373Sraghuram 
7268275SEric Cheng 		D2(vswp, "%s:programmed macaddr(%s) vid(%d) into device %s",
7278275SEric Cheng 		    __func__, ether_sprintf((void *)macaddr), vid,
7288275SEric Cheng 		    vswp->physname);
7295373Sraghuram 	}
7305373Sraghuram 
7318275SEric Cheng 	/* Add vlans to the MAC layer */
7328275SEric Cheng 	vsw_mac_add_vlans(vswp, port->p_mch, macaddr,
7338275SEric Cheng 	    mac_flags, port->vids, port->nvids);
7348275SEric Cheng 
73510795SWentao.Yang@Sun.COM 	/* Configure bandwidth to the MAC layer */
73610795SWentao.Yang@Sun.COM 	vsw_maccl_set_bandwidth(NULL, port, VSW_VNETPORT, port->p_bandwidth);
73710795SWentao.Yang@Sun.COM 
7388275SEric Cheng 	mac_rx_set(port->p_mch, vsw_port_rx_cb, (void *)port);
7398275SEric Cheng 
7405373Sraghuram 	D1(vswp, "%s: exit", __func__);
7415373Sraghuram 	return (rv);
7425373Sraghuram }
7435373Sraghuram 
7445373Sraghuram /*
7458275SEric Cheng  * Program the macaddress and vlans of a port.
7465373Sraghuram  *
7475373Sraghuram  * Returns 0 on sucess, 1 on failure.
7485373Sraghuram  */
7495373Sraghuram static int
vsw_set_if_hw_addr(vsw_t * vswp)7508275SEric Cheng vsw_set_if_hw_addr(vsw_t *vswp)
7515373Sraghuram {
7528275SEric Cheng 	mac_diag_t		diag;
7538275SEric Cheng 	uint8_t			*macaddr;
7548275SEric Cheng 	uint8_t			primary_addr[ETHERADDRL];
7558275SEric Cheng 	uint16_t		vid = VLAN_ID_NONE;
7568275SEric Cheng 	int			rv;
7579024SVenu.Iyer@Sun.COM 	uint16_t		mac_flags = MAC_UNICAST_TAG_DISABLE |
7589024SVenu.Iyer@Sun.COM 	    MAC_UNICAST_STRIP_DISABLE;
7595373Sraghuram 
7605373Sraghuram 	D1(vswp, "%s: enter", __func__);
7615373Sraghuram 
7628275SEric Cheng 	ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock));
7638275SEric Cheng 	if (vswp->mch == NULL)
7648275SEric Cheng 		return (0);
7655373Sraghuram 
7668275SEric Cheng 	macaddr = (uint8_t *)vswp->if_addr.ether_addr_octet;
7675373Sraghuram 
7688275SEric Cheng 	/* check if it is the primary macaddr of the card. */
7698275SEric Cheng 	mac_unicast_primary_get(vswp->mh, primary_addr);
7708275SEric Cheng 	if (ether_cmp((void *)primary_addr, (void*)macaddr) == 0) {
7718275SEric Cheng 		mac_flags |= MAC_UNICAST_PRIMARY;
7728275SEric Cheng 	}
7735373Sraghuram 
7745373Sraghuram 	/*
7758275SEric Cheng 	 * If the interface has a specific 'pvid', then
7768275SEric Cheng 	 * register with that vlan-id, otherwise register
7778275SEric Cheng 	 * with VLAN_ID_NONE.
7785373Sraghuram 	 */
7798275SEric Cheng 	if (vswp->pvid != vswp->default_vlan_id) {
7808275SEric Cheng 		vid = vswp->pvid;
7818275SEric Cheng 	}
7828275SEric Cheng 
7838275SEric Cheng 	if (!(vswp->smode & VSW_LAYER2_PROMISC)) {
7848275SEric Cheng 		mac_flags |= MAC_UNICAST_HW;
7855373Sraghuram 	}
7868275SEric Cheng 
7878275SEric Cheng 	if (vswp->addr_set == B_FALSE) {
7888275SEric Cheng 		vswp->muh = NULL;
7898275SEric Cheng 		rv = mac_unicast_add(vswp->mch, macaddr, mac_flags,
7908275SEric Cheng 		    &vswp->muh, vid, &diag);
7918275SEric Cheng 
7928275SEric Cheng 		if (rv != 0) {
7938275SEric Cheng 			cmn_err(CE_WARN, "vsw%d: Failed to program"
7948275SEric Cheng 			    "macaddr,vid(%s, %d) err=%d",
7958275SEric Cheng 			    vswp->instance, ether_sprintf((void *)macaddr),
7968275SEric Cheng 			    vid, rv);
7978275SEric Cheng 			return (rv);
7988275SEric Cheng 		}
7998275SEric Cheng 		vswp->addr_set = B_TRUE;
8008275SEric Cheng 
8018275SEric Cheng 		D2(vswp, "%s:programmed macaddr(%s) vid(%d) into device %s",
8028275SEric Cheng 		    __func__, ether_sprintf((void *)macaddr), vid,
8038275SEric Cheng 		    vswp->physname);
8048275SEric Cheng 	}
8058275SEric Cheng 
8068275SEric Cheng 	vsw_mac_add_vlans(vswp, vswp->mch, macaddr, mac_flags,
8078275SEric Cheng 	    vswp->vids, vswp->nvids);
8088275SEric Cheng 
80910795SWentao.Yang@Sun.COM 	vsw_maccl_set_bandwidth(vswp, NULL, VSW_LOCALDEV, vswp->bandwidth);
81010795SWentao.Yang@Sun.COM 
8118275SEric Cheng 	mac_rx_set(vswp->mch, vsw_if_rx_cb, (void *)vswp);
8128275SEric Cheng 
8135373Sraghuram 	D1(vswp, "%s: exit", __func__);
8145373Sraghuram 	return (rv);
8155373Sraghuram }
8165373Sraghuram 
8175373Sraghuram /*
8185373Sraghuram  * Remove a unicast mac address which has previously been programmed
8195373Sraghuram  * into HW.
8205373Sraghuram  *
8215373Sraghuram  * Returns 0 on sucess, 1 on failure.
8225373Sraghuram  */
8238275SEric Cheng static void
vsw_unset_hw_addr(vsw_t * vswp,vsw_port_t * port,int type)8248275SEric Cheng vsw_unset_hw_addr(vsw_t *vswp, vsw_port_t *port, int type)
8255373Sraghuram {
8268275SEric Cheng 	vsw_vlanid_t		*vids;
8278275SEric Cheng 	int			nvids;
8288275SEric Cheng 	mac_client_handle_t	mch = NULL;
8295373Sraghuram 
8305373Sraghuram 	D1(vswp, "%s: enter", __func__);
8315373Sraghuram 
8325373Sraghuram 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
8335373Sraghuram 
8345373Sraghuram 	if (type == VSW_VNETPORT) {
8355373Sraghuram 		ASSERT(port != NULL);
8368275SEric Cheng 		ASSERT(RW_WRITE_HELD(&port->maccl_rwlock));
8378275SEric Cheng 		vids = port->vids;
8388275SEric Cheng 		nvids = port->nvids;
8395373Sraghuram 	} else {
8408275SEric Cheng 		ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock));
8418275SEric Cheng 		vids = vswp->vids;
8428275SEric Cheng 		nvids = vswp->nvids;
8438275SEric Cheng 	}
8448275SEric Cheng 
8458275SEric Cheng 	/* First clear the callback */
8468275SEric Cheng 	if (type == VSW_LOCALDEV) {
8478275SEric Cheng 		mch = vswp->mch;
8488275SEric Cheng 	} else if (type == VSW_VNETPORT) {
8498275SEric Cheng 		mch = port->p_mch;
8508275SEric Cheng 	}
8518275SEric Cheng 
8528275SEric Cheng 
8538275SEric Cheng 	if (mch == NULL) {
8548275SEric Cheng 		return;
8558275SEric Cheng 	}
8568275SEric Cheng 
8578275SEric Cheng 	mac_rx_clear(mch);
8588275SEric Cheng 
8598275SEric Cheng 	/* Remove vlans */
8608275SEric Cheng 	vsw_mac_remove_vlans(mch, vids, nvids);
8618275SEric Cheng 
8628275SEric Cheng 	if ((type == VSW_LOCALDEV) && (vswp->addr_set == B_TRUE)) {
8638275SEric Cheng 		(void) mac_unicast_remove(vswp->mch, vswp->muh);
8648275SEric Cheng 		vswp->muh = NULL;
8658275SEric Cheng 		D2(vswp, "removed vsw interface mac-addr from "
8668275SEric Cheng 		    "the device %s", vswp->physname);
8678275SEric Cheng 		vswp->addr_set = B_FALSE;
8688275SEric Cheng 
8698275SEric Cheng 	} else if ((type == VSW_VNETPORT) && (port->addr_set == B_TRUE)) {
8708275SEric Cheng 		(void) mac_unicast_remove(port->p_mch, port->p_muh);
8718275SEric Cheng 		port->p_muh = NULL;
8728275SEric Cheng 		D2(vswp, "removed port(0x%p) mac-addr from "
8738275SEric Cheng 		    "the device %s", port, vswp->physname);
8748275SEric Cheng 		port->addr_set = B_FALSE;
8755373Sraghuram 	}
8765373Sraghuram 
8775373Sraghuram 	D1(vswp, "%s: exit", __func__);
8785373Sraghuram }
8795373Sraghuram 
8805373Sraghuram /*
8818275SEric Cheng  * receive callback routine for vsw interface. Invoked by MAC layer when there
8828275SEric Cheng  * are pkts being passed up from physical device for this vsw interface.
8835373Sraghuram  */
8848275SEric Cheng /* ARGSUSED */
8858275SEric Cheng static void
vsw_if_rx_cb(void * arg,mac_resource_handle_t mrh,mblk_t * mp,boolean_t loopback)8868275SEric Cheng vsw_if_rx_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
8878275SEric Cheng     boolean_t loopback)
8885373Sraghuram {
8898275SEric Cheng 	_NOTE(ARGUNUSED(mrh))
8905373Sraghuram 
8918275SEric Cheng 	vsw_t		*vswp = (vsw_t *)arg;
8928275SEric Cheng 	mblk_t		*mpt;
8938275SEric Cheng 	int		count;
8945373Sraghuram 
8958275SEric Cheng 	ASSERT(vswp != NULL);
8965373Sraghuram 
8975373Sraghuram 	D1(vswp, "%s: enter", __func__);
8985373Sraghuram 
8998275SEric Cheng 	READ_ENTER(&vswp->if_lockrw);
9008275SEric Cheng 	if (vswp->if_state & VSW_IF_UP) {
9018275SEric Cheng 		RW_EXIT(&vswp->if_lockrw);
9028275SEric Cheng 		count = vsw_vlan_frame_untag(vswp, VSW_LOCALDEV, &mp, &mpt);
9038275SEric Cheng 		if (count != 0) {
9048275SEric Cheng 			mac_rx(vswp->if_mh, NULL, mp);
9058275SEric Cheng 		}
9068275SEric Cheng 	} else {
9078275SEric Cheng 		RW_EXIT(&vswp->if_lockrw);
9088275SEric Cheng 		freemsgchain(mp);
9095373Sraghuram 	}
9105373Sraghuram 
9115373Sraghuram 	D1(vswp, "%s: exit", __func__);
9125373Sraghuram }
9135373Sraghuram 
9145373Sraghuram /*
9158275SEric Cheng  * receive callback routine for port. Invoked by MAC layer when there
9168275SEric Cheng  * are pkts being passed up from physical device for this port.
9175373Sraghuram  */
9188275SEric Cheng /* ARGSUSED */
9198275SEric Cheng static void
vsw_port_rx_cb(void * arg,mac_resource_handle_t mrh,mblk_t * mp,boolean_t loopback)9208275SEric Cheng vsw_port_rx_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
9218275SEric Cheng     boolean_t loopback)
9225373Sraghuram {
9238275SEric Cheng 	_NOTE(ARGUNUSED(mrh))
9245373Sraghuram 
9258275SEric Cheng 	vsw_t		*vswp;
9268275SEric Cheng 	vsw_port_t	*port = arg;
9275373Sraghuram 
9288275SEric Cheng 	ASSERT(port != NULL);
9295373Sraghuram 
9308275SEric Cheng 	vswp = port->p_vswp;
9318275SEric Cheng 
9328275SEric Cheng 	D1(vswp, "vsw_port_rx_cb: enter");
9335373Sraghuram 
9348275SEric Cheng 	/*
9358275SEric Cheng 	 * Send the packets to the peer directly.
9368275SEric Cheng 	 */
9378275SEric Cheng 	(void) vsw_portsend(port, mp);
9385373Sraghuram 
9398275SEric Cheng 	D1(vswp, "vsw_port_rx_cb: exit");
9405373Sraghuram }
9415373Sraghuram 
9425373Sraghuram /*
9438275SEric Cheng  * Send a message out over the physical device
9448275SEric Cheng  * via the MAC layer.
9455373Sraghuram  *
9468275SEric Cheng  * Returns any mblks that it was unable to transmit.
9475373Sraghuram  */
9488275SEric Cheng mblk_t *
vsw_tx_msg(vsw_t * vswp,mblk_t * mp,int caller,vsw_port_t * port)9498275SEric Cheng vsw_tx_msg(vsw_t *vswp, mblk_t *mp, int caller, vsw_port_t *port)
9505373Sraghuram {
9518275SEric Cheng 	mac_client_handle_t	mch;
9528275SEric Cheng 	mac_unicast_handle_t	muh;
9535373Sraghuram 
9548275SEric Cheng 	READ_MACCL_ENTER(vswp, port, caller);
9555373Sraghuram 
9568275SEric Cheng 	mch = (caller == VSW_LOCALDEV) ? vswp->mch : port->p_mch;
9578275SEric Cheng 	muh = (caller == VSW_LOCALDEV) ? vswp->muh : port->p_muh;
9585373Sraghuram 
9599217SWentao.Yang@Sun.COM 	if (mch == NULL || muh == NULL) {
9609217SWentao.Yang@Sun.COM 		RW_MACCL_EXIT(vswp, port, caller);
9619217SWentao.Yang@Sun.COM 		return (mp);
9628275SEric Cheng 	}
9635373Sraghuram 
9649217SWentao.Yang@Sun.COM 	/* packets are sent or dropped */
9659217SWentao.Yang@Sun.COM 	(void) mac_tx(mch, mp, 0, MAC_DROP_ON_NO_DESC, NULL);
9668275SEric Cheng 	RW_MACCL_EXIT(vswp, port, caller);
9678275SEric Cheng 	return (NULL);
9685373Sraghuram }
9695373Sraghuram 
9705373Sraghuram /*
9718275SEric Cheng  * vsw_port_mac_reconfig -- Cleanup and close the MAC client
9728275SEric Cheng  * and reopen and re-configure the MAC client with new flags etc.
9738275SEric Cheng  * This function is useful for two different purposes:
9748275SEric Cheng  *	1) To update the MAC client with new vlan-ids. This is done
9758275SEric Cheng  *	   by freeing the existing vlan-ids and reopen with the new
9768275SEric Cheng  *	   vlan-ids.
9778275SEric Cheng  *
9788275SEric Cheng  *	2) If the Hybrid mode status of a port changes, then the
9798275SEric Cheng  *	   MAC client need to be closed and re-opened, otherwise,
9808275SEric Cheng  *	   Share related resources may not be freed(hybird mode disabled)
9818275SEric Cheng  *	   or assigned(hybrid mode enabled). To accomplish this,
9828275SEric Cheng  *	   this function simply closes and reopens the MAC client.
9838275SEric Cheng  *	   The reopen will result in using the flags based on the
9848275SEric Cheng  *	   new hybrid mode of the port.
9855373Sraghuram  */
9868275SEric Cheng void
vsw_port_mac_reconfig(vsw_port_t * portp,boolean_t update_vlans,uint16_t new_pvid,vsw_vlanid_t * new_vids,int new_nvids)9878275SEric Cheng vsw_port_mac_reconfig(vsw_port_t *portp, boolean_t update_vlans,
9888275SEric Cheng     uint16_t new_pvid, vsw_vlanid_t *new_vids, int new_nvids)
9895373Sraghuram {
9908275SEric Cheng 	vsw_t *vswp = portp->p_vswp;
9918275SEric Cheng 	int rv;
9925373Sraghuram 
9935373Sraghuram 	D1(vswp, "%s: enter", __func__);
9945373Sraghuram 	/*
9958275SEric Cheng 	 * Remove the multi-cast addresses, unicast address
9968275SEric Cheng 	 * and close the mac-client.
9975373Sraghuram 	 */
9988275SEric Cheng 	mutex_enter(&vswp->mac_lock);
9998275SEric Cheng 	WRITE_ENTER(&portp->maccl_rwlock);
10008275SEric Cheng 	vsw_mac_multicast_remove_all(vswp, portp, VSW_VNETPORT);
10018275SEric Cheng 	vsw_unset_hw(vswp, portp, VSW_VNETPORT);
10028275SEric Cheng 	vsw_maccl_close(vswp, portp, VSW_VNETPORT);
10035373Sraghuram 
10048275SEric Cheng 	if (update_vlans == B_TRUE) {
10058275SEric Cheng 		if (portp->nvids != 0) {
10068275SEric Cheng 			kmem_free(portp->vids,
10078275SEric Cheng 			    sizeof (vsw_vlanid_t) * portp->nvids);
10088275SEric Cheng 			portp->vids = NULL;
10098275SEric Cheng 			portp->nvids = 0;
10105373Sraghuram 		}
10118275SEric Cheng 		portp->vids = new_vids;
10128275SEric Cheng 		portp->nvids = new_nvids;
10138275SEric Cheng 		portp->pvid = new_pvid;
10145373Sraghuram 	}
10155373Sraghuram 
10165373Sraghuram 	/*
10178275SEric Cheng 	 * Now re-open the mac-client and
10188275SEric Cheng 	 * configure unicast addr and multicast addrs.
10195373Sraghuram 	 */
10208275SEric Cheng 	rv = vsw_maccl_open(vswp, portp, VSW_VNETPORT);
10218275SEric Cheng 	if (rv != 0) {
10228275SEric Cheng 		goto recret;
10235373Sraghuram 	}
10245373Sraghuram 
10258275SEric Cheng 	if (vsw_set_hw(vswp, portp, VSW_VNETPORT)) {
10268275SEric Cheng 		cmn_err(CE_NOTE, "!vsw%d: port:%d failed to "
10278275SEric Cheng 		    "set unicast address\n", vswp->instance, portp->p_instance);
10288275SEric Cheng 		goto recret;
10298275SEric Cheng 	}
10305373Sraghuram 
10318275SEric Cheng 	vsw_mac_multicast_add_all(vswp, portp, VSW_VNETPORT);
10325373Sraghuram 
10338275SEric Cheng recret:
10348275SEric Cheng 	RW_EXIT(&portp->maccl_rwlock);
10358275SEric Cheng 	mutex_exit(&vswp->mac_lock);
10365373Sraghuram 	D1(vswp, "%s: exit", __func__);
10375373Sraghuram }
10385373Sraghuram 
10395373Sraghuram /*
10408275SEric Cheng  * vsw_if_mac_reconfig -- Reconfigure the vsw interfaace's mac-client
10418275SEric Cheng  * by closing and re-opening it. This function is used handle the
10428275SEric Cheng  * following two cases:
10435373Sraghuram  *
10448275SEric Cheng  *	1) Handle the MAC address change for the interface.
10458275SEric Cheng  *	2) Handle vlan update.
10465373Sraghuram  */
10478275SEric Cheng void
vsw_if_mac_reconfig(vsw_t * vswp,boolean_t update_vlans,uint16_t new_pvid,vsw_vlanid_t * new_vids,int new_nvids)10488275SEric Cheng vsw_if_mac_reconfig(vsw_t *vswp, boolean_t update_vlans,
10498275SEric Cheng     uint16_t new_pvid, vsw_vlanid_t *new_vids, int new_nvids)
10505373Sraghuram {
10518275SEric Cheng 	int rv;
10525373Sraghuram 
10538275SEric Cheng 	D1(vswp, "%s: enter", __func__);
10548275SEric Cheng 	/*
10558275SEric Cheng 	 * Remove the multi-cast addresses, unicast address
10568275SEric Cheng 	 * and close the mac-client.
10578275SEric Cheng 	 */
10588275SEric Cheng 	mutex_enter(&vswp->mac_lock);
10598275SEric Cheng 	WRITE_ENTER(&vswp->maccl_rwlock);
10608275SEric Cheng 	vsw_mac_multicast_remove_all(vswp, NULL, VSW_LOCALDEV);
10618275SEric Cheng 	vsw_unset_hw(vswp, NULL, VSW_LOCALDEV);
10628275SEric Cheng 	vsw_maccl_close(vswp, NULL, VSW_LOCALDEV);
10635373Sraghuram 
10648275SEric Cheng 	if (update_vlans == B_TRUE) {
10658275SEric Cheng 		if (vswp->nvids != 0) {
10668275SEric Cheng 			kmem_free(vswp->vids,
10678275SEric Cheng 			    sizeof (vsw_vlanid_t) * vswp->nvids);
10688275SEric Cheng 			vswp->vids = NULL;
10698275SEric Cheng 			vswp->nvids = 0;
10708275SEric Cheng 		}
10718275SEric Cheng 		vswp->vids = new_vids;
10728275SEric Cheng 		vswp->nvids = new_nvids;
10738275SEric Cheng 		vswp->pvid = new_pvid;
10748275SEric Cheng 	}
10755373Sraghuram 
10768275SEric Cheng 	/*
10778275SEric Cheng 	 * Now re-open the mac-client and
10788275SEric Cheng 	 * configure unicast addr and multicast addrs.
10798275SEric Cheng 	 */
10808275SEric Cheng 	rv = vsw_maccl_open(vswp, NULL, VSW_LOCALDEV);
10818275SEric Cheng 	if (rv != 0) {
10828275SEric Cheng 		goto ifrecret;
10838275SEric Cheng 	}
10845373Sraghuram 
10858275SEric Cheng 	if (vsw_set_hw(vswp, NULL, VSW_LOCALDEV)) {
10868275SEric Cheng 		cmn_err(CE_NOTE, "!vsw%d:failed to set unicast address\n",
10878275SEric Cheng 		    vswp->instance);
10888275SEric Cheng 		goto ifrecret;
10898275SEric Cheng 	}
10908275SEric Cheng 
10918275SEric Cheng 	vsw_mac_multicast_add_all(vswp, NULL, VSW_LOCALDEV);
10928275SEric Cheng 
10938275SEric Cheng ifrecret:
10948275SEric Cheng 	RW_EXIT(&vswp->maccl_rwlock);
10958275SEric Cheng 	mutex_exit(&vswp->mac_lock);
10968275SEric Cheng 	D1(vswp, "%s: exit", __func__);
10975373Sraghuram }
10985373Sraghuram 
10995373Sraghuram /*
11008275SEric Cheng  * vsw_mac_port_reconfig_vlans -- Reconfigure a port to handle
11018275SEric Cheng  * vlan configuration update. As the removal of the last unicast-address,vid
11028275SEric Cheng  * from the MAC client results in releasing all resources, it expects
11038275SEric Cheng  * no Shares to be associated with such MAC client.
11045373Sraghuram  *
11058275SEric Cheng  * To handle vlan configuration update for a port that already has
11068275SEric Cheng  * a Share bound, then we need to free that share prior to reconfiguration.
11078275SEric Cheng  * Initiate the hybrdIO setup again after the completion of reconfiguration.
11085373Sraghuram  */
11098275SEric Cheng void
vsw_mac_port_reconfig_vlans(vsw_port_t * portp,uint16_t new_pvid,vsw_vlanid_t * new_vids,int new_nvids)11108275SEric Cheng vsw_mac_port_reconfig_vlans(vsw_port_t *portp, uint16_t new_pvid,
11118275SEric Cheng     vsw_vlanid_t *new_vids, int new_nvids)
11125373Sraghuram {
11138275SEric Cheng 	/*
11148275SEric Cheng 	 * As the reconfiguration involves the close of
11158275SEric Cheng 	 * mac client, cleanup HybridIO and later restart
11168275SEric Cheng 	 * HybridIO setup again.
11178275SEric Cheng 	 */
11188275SEric Cheng 	if (portp->p_hio_enabled == B_TRUE) {
11198275SEric Cheng 		vsw_hio_stop_port(portp);
11208275SEric Cheng 	}
11218275SEric Cheng 	vsw_port_mac_reconfig(portp, B_TRUE, new_pvid, new_vids, new_nvids);
11228275SEric Cheng 	if (portp->p_hio_enabled == B_TRUE) {
11238275SEric Cheng 		/* reset to setup the HybridIO again. */
11248275SEric Cheng 		vsw_hio_port_reset(portp, B_FALSE);
11258275SEric Cheng 	}
11268275SEric Cheng }
11278275SEric Cheng 
11288275SEric Cheng /* Add vlans to MAC client */
11298275SEric Cheng static void
vsw_mac_add_vlans(vsw_t * vswp,mac_client_handle_t mch,uint8_t * macaddr,uint16_t flags,vsw_vlanid_t * vids,int nvids)11308275SEric Cheng vsw_mac_add_vlans(vsw_t *vswp, mac_client_handle_t mch, uint8_t *macaddr,
11318275SEric Cheng     uint16_t flags, vsw_vlanid_t *vids, int nvids)
11328275SEric Cheng {
11338275SEric Cheng 	vsw_vlanid_t	*vidp;
11348275SEric Cheng 	mac_diag_t	diag;
11358275SEric Cheng 	int		rv;
11368275SEric Cheng 	int		i;
11375373Sraghuram 
11389024SVenu.Iyer@Sun.COM 	flags |= MAC_UNICAST_TAG_DISABLE | MAC_UNICAST_STRIP_DISABLE;
11399024SVenu.Iyer@Sun.COM 
11408275SEric Cheng 	/* Add vlans to the MAC layer */
11418275SEric Cheng 	for (i = 0; i < nvids; i++) {
11428275SEric Cheng 		vidp = &vids[i];
11438275SEric Cheng 
11448275SEric Cheng 		if (vidp->vl_set == B_TRUE) {
11458275SEric Cheng 			continue;
11468275SEric Cheng 		}
11475373Sraghuram 
11488275SEric Cheng 		rv = mac_unicast_add(mch, macaddr, flags,
11498275SEric Cheng 		    &vidp->vl_muh, vidp->vl_vid, &diag);
11508275SEric Cheng 		if (rv != 0) {
11518275SEric Cheng 			cmn_err(CE_WARN, "vsw%d: Failed to program"
11528275SEric Cheng 			    "macaddr,vid(%s, %d) err=%d",
11538275SEric Cheng 			    vswp->instance, ether_sprintf((void *)macaddr),
11548275SEric Cheng 			    vidp->vl_vid, rv);
11558275SEric Cheng 		} else {
11568275SEric Cheng 			vidp->vl_set = B_TRUE;
11578275SEric Cheng 			D2(vswp, "%s:programmed macaddr(%s) vid(%d) "
11588275SEric Cheng 			    "into device %s", __func__,
11598275SEric Cheng 			    ether_sprintf((void *)macaddr),
11608275SEric Cheng 			    vidp->vl_vid, vswp->physname);
11618275SEric Cheng 		}
11625373Sraghuram 	}
11638275SEric Cheng }
11648275SEric Cheng 
11658275SEric Cheng /* Remove vlans from the MAC client */
11668275SEric Cheng static void
vsw_mac_remove_vlans(mac_client_handle_t mch,vsw_vlanid_t * vids,int nvids)11678275SEric Cheng vsw_mac_remove_vlans(mac_client_handle_t mch, vsw_vlanid_t *vids, int nvids)
11688275SEric Cheng {
11698275SEric Cheng 	int i;
11708275SEric Cheng 	vsw_vlanid_t *vidp;
11715373Sraghuram 
11728275SEric Cheng 	for (i = 0; i < nvids; i++) {
11738275SEric Cheng 		vidp = &vids[i];
11748275SEric Cheng 		if (vidp->vl_set == B_FALSE) {
11758275SEric Cheng 			continue;
11768275SEric Cheng 		}
117711311SSurya.Prakki@Sun.COM 		(void) mac_unicast_remove(mch, vidp->vl_muh);
11788275SEric Cheng 		vidp->vl_set = B_FALSE;
11798275SEric Cheng 	}
11805373Sraghuram }
11817027Ssb155480 
11827027Ssb155480 #define	ARH_FIXED_LEN	8    /* Length of fixed part of ARP header(see arp.h) */
11837027Ssb155480 
11847027Ssb155480 /*
11857027Ssb155480  * Send a gratuitous RARP packet to notify the physical switch to update its
11867027Ssb155480  * Layer2 forwarding table for the given mac address. This is done to allow the
11877027Ssb155480  * switch to quickly learn the macaddr-port association when a guest is live
11887027Ssb155480  * migrated or when vsw's physical device is changed dynamically. Any protocol
11897027Ssb155480  * packet would serve this purpose, but we choose RARP, as it allows us to
11907027Ssb155480  * accomplish this within L2 (ie, no need to specify IP addr etc in the packet)
11917027Ssb155480  * The macaddr of vnet is retained across migration. Hence, we don't need to
11927027Ssb155480  * update the arp cache of other hosts within the broadcast domain. Note that
11937027Ssb155480  * it is harmless to send these RARP packets during normal port attach of a
11947027Ssb155480  * client vnet. This can can be turned off if needed, by setting
11957027Ssb155480  * vsw_publish_macaddr_count to zero in /etc/system.
11967027Ssb155480  */
11977027Ssb155480 void
vsw_publish_macaddr(vsw_t * vswp,vsw_port_t * portp)11988275SEric Cheng vsw_publish_macaddr(vsw_t *vswp, vsw_port_t *portp)
11997027Ssb155480 {
12007027Ssb155480 	mblk_t			*mp;
12017027Ssb155480 	mblk_t			*bp;
12027027Ssb155480 	struct arphdr		*arh;
12037027Ssb155480 	struct	ether_header 	*ehp;
12047027Ssb155480 	int			count = 0;
12057027Ssb155480 	int			plen = 4;
12067027Ssb155480 	uint8_t			*cp;
12077027Ssb155480 
12087027Ssb155480 	mp = allocb(ETHERMIN, BPRI_MED);
12097027Ssb155480 	if (mp == NULL) {
12107027Ssb155480 		return;
12117027Ssb155480 	}
12127027Ssb155480 
12137027Ssb155480 	/* Initialize eth header */
12147027Ssb155480 	ehp = (struct  ether_header *)mp->b_rptr;
12157027Ssb155480 	bcopy(&etherbroadcastaddr, &ehp->ether_dhost, ETHERADDRL);
12168275SEric Cheng 	bcopy(&portp->p_macaddr, &ehp->ether_shost, ETHERADDRL);
12177027Ssb155480 	ehp->ether_type = htons(ETHERTYPE_REVARP);
12187027Ssb155480 
12197027Ssb155480 	/* Initialize arp packet */
12207027Ssb155480 	arh = (struct arphdr *)(mp->b_rptr + sizeof (struct ether_header));
12217027Ssb155480 	cp = (uint8_t *)arh;
12227027Ssb155480 
12237027Ssb155480 	arh->ar_hrd = htons(ARPHRD_ETHER);	/* Hardware type:  ethernet */
12247027Ssb155480 	arh->ar_pro = htons(ETHERTYPE_IP);	/* Protocol type:  IP */
12257027Ssb155480 	arh->ar_hln = ETHERADDRL;	/* Length of hardware address:  6 */
12267027Ssb155480 	arh->ar_pln = plen;		/* Length of protocol address:  4 */
12277027Ssb155480 	arh->ar_op = htons(REVARP_REQUEST);	/* Opcode: REVARP Request */
12287027Ssb155480 
12297027Ssb155480 	cp += ARH_FIXED_LEN;
12307027Ssb155480 
12317027Ssb155480 	/* Sender's hardware address and protocol address */
12328275SEric Cheng 	bcopy(&portp->p_macaddr, cp, ETHERADDRL);
12337027Ssb155480 	cp += ETHERADDRL;
12347027Ssb155480 	bzero(cp, plen);	/* INADDR_ANY */
12357027Ssb155480 	cp += plen;
12367027Ssb155480 
12377027Ssb155480 	/* Target hardware address and protocol address */
12388275SEric Cheng 	bcopy(&portp->p_macaddr, cp, ETHERADDRL);
12397027Ssb155480 	cp += ETHERADDRL;
12407027Ssb155480 	bzero(cp, plen);	/* INADDR_ANY */
12417027Ssb155480 	cp += plen;
12427027Ssb155480 
12437027Ssb155480 	mp->b_wptr += ETHERMIN;	/* total size is 42; round up to ETHERMIN */
12447027Ssb155480 
12457027Ssb155480 	for (count = 0; count < vsw_publish_macaddr_count; count++) {
12467027Ssb155480 
12477027Ssb155480 		bp = dupmsg(mp);
12487027Ssb155480 		if (bp == NULL) {
12497027Ssb155480 			continue;
12507027Ssb155480 		}
12517027Ssb155480 
12527027Ssb155480 		/* transmit the packet */
12538275SEric Cheng 		bp = vsw_tx_msg(vswp, bp, VSW_VNETPORT, portp);
12547027Ssb155480 		if (bp != NULL) {
12557027Ssb155480 			freemsg(bp);
12567027Ssb155480 		}
12577027Ssb155480 	}
12587027Ssb155480 
12597027Ssb155480 	freemsg(mp);
12607027Ssb155480 }
12617529SSriharsha.Basavapatna@Sun.COM 
12627529SSriharsha.Basavapatna@Sun.COM static void
vsw_mac_set_mtu(vsw_t * vswp,uint32_t mtu)12637529SSriharsha.Basavapatna@Sun.COM vsw_mac_set_mtu(vsw_t *vswp, uint32_t mtu)
12647529SSriharsha.Basavapatna@Sun.COM {
12658275SEric Cheng 	uint_t	mtu_orig;
12668275SEric Cheng 	int	rv;
12677529SSriharsha.Basavapatna@Sun.COM 
12688275SEric Cheng 	rv = mac_set_mtu(vswp->mh, mtu, &mtu_orig);
12697529SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
12707529SSriharsha.Basavapatna@Sun.COM 		cmn_err(CE_NOTE,
12717529SSriharsha.Basavapatna@Sun.COM 		    "!vsw%d: Unable to set the mtu:%d, in the "
12727529SSriharsha.Basavapatna@Sun.COM 		    "physical device:%s\n",
12737529SSriharsha.Basavapatna@Sun.COM 		    vswp->instance, mtu, vswp->physname);
12748275SEric Cheng 		return;
12757529SSriharsha.Basavapatna@Sun.COM 	}
12768275SEric Cheng 
12778275SEric Cheng 	/* save the original mtu of physdev to reset it back later if needed */
12788275SEric Cheng 	vswp->mtu_physdev_orig = mtu_orig;
12797529SSriharsha.Basavapatna@Sun.COM }
12809336SSriharsha.Basavapatna@Sun.COM 
12819336SSriharsha.Basavapatna@Sun.COM /*
12829336SSriharsha.Basavapatna@Sun.COM  * Register a callback with underlying mac layer for notifications.
12839336SSriharsha.Basavapatna@Sun.COM  * We are currently interested in only link-state events.
12849336SSriharsha.Basavapatna@Sun.COM  */
12859336SSriharsha.Basavapatna@Sun.COM static int
vsw_notify_add(vsw_t * vswp)12869336SSriharsha.Basavapatna@Sun.COM vsw_notify_add(vsw_t *vswp)
12879336SSriharsha.Basavapatna@Sun.COM {
12889336SSriharsha.Basavapatna@Sun.COM 	mac_notify_handle_t	mnh;
12899336SSriharsha.Basavapatna@Sun.COM 	uint32_t		note;
12909336SSriharsha.Basavapatna@Sun.COM 
12919336SSriharsha.Basavapatna@Sun.COM 	/*
12929336SSriharsha.Basavapatna@Sun.COM 	 * Check if the underlying MAC supports link update notification.
12939336SSriharsha.Basavapatna@Sun.COM 	 */
12949336SSriharsha.Basavapatna@Sun.COM 	note = mac_no_notification(vswp->mh);
12959336SSriharsha.Basavapatna@Sun.COM 	if ((note & (DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN)) != 0) {
12969336SSriharsha.Basavapatna@Sun.COM 		vswp->phys_no_link_update = B_TRUE;
12979336SSriharsha.Basavapatna@Sun.COM 	} else {
12989336SSriharsha.Basavapatna@Sun.COM 		vswp->phys_no_link_update = B_FALSE;
12999336SSriharsha.Basavapatna@Sun.COM 	}
13009336SSriharsha.Basavapatna@Sun.COM 
13019336SSriharsha.Basavapatna@Sun.COM 	/*
13029336SSriharsha.Basavapatna@Sun.COM 	 * Read the current link state of the device and cache it.
13039336SSriharsha.Basavapatna@Sun.COM 	 */
13049336SSriharsha.Basavapatna@Sun.COM 	vswp->phys_link_state = vswp->phys_no_link_update ? LINK_STATE_UP :
13059336SSriharsha.Basavapatna@Sun.COM 	    mac_stat_get(vswp->mh, MAC_STAT_LINK_STATE);
13069336SSriharsha.Basavapatna@Sun.COM 
13079336SSriharsha.Basavapatna@Sun.COM 	/*
13089336SSriharsha.Basavapatna@Sun.COM 	 * Add notify callback function, if link update is supported.
13099336SSriharsha.Basavapatna@Sun.COM 	 */
13109336SSriharsha.Basavapatna@Sun.COM 	if (vswp->phys_no_link_update == B_TRUE) {
13119336SSriharsha.Basavapatna@Sun.COM 		return (0);
13129336SSriharsha.Basavapatna@Sun.COM 	}
13139336SSriharsha.Basavapatna@Sun.COM 
13149336SSriharsha.Basavapatna@Sun.COM 	mnh = mac_notify_add(vswp->mh, vsw_notify_cb, vswp);
13159336SSriharsha.Basavapatna@Sun.COM 	if (mnh == 0) {
13169336SSriharsha.Basavapatna@Sun.COM 		/* failed */
13179336SSriharsha.Basavapatna@Sun.COM 		return (1);
13189336SSriharsha.Basavapatna@Sun.COM 	}
13199336SSriharsha.Basavapatna@Sun.COM 
13209336SSriharsha.Basavapatna@Sun.COM 	vswp->mnh = mnh;
13219336SSriharsha.Basavapatna@Sun.COM 	return (0);
13229336SSriharsha.Basavapatna@Sun.COM }
13239336SSriharsha.Basavapatna@Sun.COM 
13249336SSriharsha.Basavapatna@Sun.COM /*
13259336SSriharsha.Basavapatna@Sun.COM  * Remove notify callback.
13269336SSriharsha.Basavapatna@Sun.COM  */
13279336SSriharsha.Basavapatna@Sun.COM static int
vsw_notify_rem(vsw_t * vswp)13289336SSriharsha.Basavapatna@Sun.COM vsw_notify_rem(vsw_t *vswp)
13299336SSriharsha.Basavapatna@Sun.COM {
13309336SSriharsha.Basavapatna@Sun.COM 	int	rv;
13319336SSriharsha.Basavapatna@Sun.COM 
13329336SSriharsha.Basavapatna@Sun.COM 	rv = mac_notify_remove(vswp->mnh, B_FALSE);
13339336SSriharsha.Basavapatna@Sun.COM 	return (rv);
13349336SSriharsha.Basavapatna@Sun.COM }
13359336SSriharsha.Basavapatna@Sun.COM 
13369336SSriharsha.Basavapatna@Sun.COM /*
13379336SSriharsha.Basavapatna@Sun.COM  * Notification callback invoked by the MAC service
13389336SSriharsha.Basavapatna@Sun.COM  * module. Note that we process only link state updates.
13399336SSriharsha.Basavapatna@Sun.COM  */
13409336SSriharsha.Basavapatna@Sun.COM static void
vsw_notify_cb(void * arg,mac_notify_type_t type)13419336SSriharsha.Basavapatna@Sun.COM vsw_notify_cb(void *arg, mac_notify_type_t type)
13429336SSriharsha.Basavapatna@Sun.COM {
13439336SSriharsha.Basavapatna@Sun.COM 	vsw_t	*vswp = arg;
13449336SSriharsha.Basavapatna@Sun.COM 
13459336SSriharsha.Basavapatna@Sun.COM 	switch (type) {
13469336SSriharsha.Basavapatna@Sun.COM 
13479336SSriharsha.Basavapatna@Sun.COM 	case MAC_NOTE_LINK:
13489336SSriharsha.Basavapatna@Sun.COM 		vsw_notify_link(vswp);
13499336SSriharsha.Basavapatna@Sun.COM 		break;
13509336SSriharsha.Basavapatna@Sun.COM 
13519336SSriharsha.Basavapatna@Sun.COM 	default:
13529336SSriharsha.Basavapatna@Sun.COM 		break;
13539336SSriharsha.Basavapatna@Sun.COM 
13549336SSriharsha.Basavapatna@Sun.COM 	}
13559336SSriharsha.Basavapatna@Sun.COM }
13569336SSriharsha.Basavapatna@Sun.COM 
13579336SSriharsha.Basavapatna@Sun.COM /*
13589336SSriharsha.Basavapatna@Sun.COM  * Invoked upon receiving a MAC_NOTE_LINK
13599336SSriharsha.Basavapatna@Sun.COM  * notification for the underlying physical device.
13609336SSriharsha.Basavapatna@Sun.COM  */
13619336SSriharsha.Basavapatna@Sun.COM static void
vsw_notify_link(vsw_t * vswp)13629336SSriharsha.Basavapatna@Sun.COM vsw_notify_link(vsw_t *vswp)
13639336SSriharsha.Basavapatna@Sun.COM {
13649336SSriharsha.Basavapatna@Sun.COM 	link_state_t	link_state;
13659336SSriharsha.Basavapatna@Sun.COM 
13669336SSriharsha.Basavapatna@Sun.COM 	/* link state change  notification */
13679336SSriharsha.Basavapatna@Sun.COM 	link_state = mac_stat_get(vswp->mh, MAC_STAT_LINK_STATE);
13689336SSriharsha.Basavapatna@Sun.COM 
13699336SSriharsha.Basavapatna@Sun.COM 	if (vswp->phys_link_state != link_state) {
13709336SSriharsha.Basavapatna@Sun.COM 		D3(vswp, "%s: phys_link_state(%d)\n",
13719336SSriharsha.Basavapatna@Sun.COM 		    __func__, vswp->phys_link_state);
13729336SSriharsha.Basavapatna@Sun.COM 
13739336SSriharsha.Basavapatna@Sun.COM 		vswp->phys_link_state = link_state;
13749336SSriharsha.Basavapatna@Sun.COM 		vsw_physlink_state_update(vswp);
13759336SSriharsha.Basavapatna@Sun.COM 	}
13769336SSriharsha.Basavapatna@Sun.COM }
137710795SWentao.Yang@Sun.COM 
137810795SWentao.Yang@Sun.COM /*
137910795SWentao.Yang@Sun.COM  * Configure the bandwidth limit on the vsw or vnet devices via the MAC layer.
138010795SWentao.Yang@Sun.COM  * Note that bandwidth limit is not supported on a HybridIO enabled
138110795SWentao.Yang@Sun.COM  * vnet, as the HybridIO assigns a specific unit of hardware resource
138210795SWentao.Yang@Sun.COM  * that cannot be changed to limit bandwidth.
138310795SWentao.Yang@Sun.COM  */
138410795SWentao.Yang@Sun.COM static void
vsw_maccl_set_bandwidth(vsw_t * vswp,vsw_port_t * port,int type,uint64_t maxbw)138510795SWentao.Yang@Sun.COM vsw_maccl_set_bandwidth(vsw_t *vswp, vsw_port_t *port, int type, uint64_t maxbw)
138610795SWentao.Yang@Sun.COM {
138710795SWentao.Yang@Sun.COM 	int			rv = 0;
138810795SWentao.Yang@Sun.COM 	uint64_t		*bw;
1389*11878SVenu.Iyer@Sun.COM 	mac_resource_props_t	*mrp;
139010795SWentao.Yang@Sun.COM 	mac_client_handle_t	mch;
139110795SWentao.Yang@Sun.COM 
139210795SWentao.Yang@Sun.COM 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
139310795SWentao.Yang@Sun.COM 
139410795SWentao.Yang@Sun.COM 	if (type == VSW_VNETPORT) {
139510795SWentao.Yang@Sun.COM 		ASSERT(RW_WRITE_HELD(&port->maccl_rwlock));
139610795SWentao.Yang@Sun.COM 		mch = port->p_mch;
139710795SWentao.Yang@Sun.COM 		bw = &port->p_bandwidth;
139810795SWentao.Yang@Sun.COM 	} else {
139910795SWentao.Yang@Sun.COM 		ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock));
140010795SWentao.Yang@Sun.COM 		mch = vswp->mch;
140110795SWentao.Yang@Sun.COM 		bw = &vswp->bandwidth;
140210795SWentao.Yang@Sun.COM 	}
140310795SWentao.Yang@Sun.COM 
140410795SWentao.Yang@Sun.COM 	if (mch == NULL) {
140510795SWentao.Yang@Sun.COM 		return;
140610795SWentao.Yang@Sun.COM 	}
140710795SWentao.Yang@Sun.COM 
140810795SWentao.Yang@Sun.COM 	if (maxbw >= MRP_MAXBW_MINVAL || maxbw == 0) {
1409*11878SVenu.Iyer@Sun.COM 		mrp = kmem_zalloc(sizeof (*mrp), KM_SLEEP);
141010795SWentao.Yang@Sun.COM 		if (maxbw == 0) {
1411*11878SVenu.Iyer@Sun.COM 			mrp->mrp_maxbw = MRP_MAXBW_RESETVAL;
141210795SWentao.Yang@Sun.COM 		} else {
1413*11878SVenu.Iyer@Sun.COM 			mrp->mrp_maxbw = maxbw;
141410795SWentao.Yang@Sun.COM 		}
1415*11878SVenu.Iyer@Sun.COM 		mrp->mrp_mask |= MRP_MAXBW;
141610795SWentao.Yang@Sun.COM 
1417*11878SVenu.Iyer@Sun.COM 		rv = mac_client_set_resources(mch, mrp);
141810795SWentao.Yang@Sun.COM 		if (rv != 0) {
141910795SWentao.Yang@Sun.COM 			if (type == VSW_VNETPORT) {
142010795SWentao.Yang@Sun.COM 				cmn_err(CE_NOTE, "!port%d: cannot set "
142110795SWentao.Yang@Sun.COM 				    "bandwidth limit to (%ld), error(%d)\n",
142210795SWentao.Yang@Sun.COM 				    port->p_instance, maxbw, rv);
142310795SWentao.Yang@Sun.COM 			} else {
142410795SWentao.Yang@Sun.COM 				cmn_err(CE_NOTE, "!vsw%d: cannot set "
142510795SWentao.Yang@Sun.COM 				    "bandwidth limit to (%ld), error(%d)\n",
142610795SWentao.Yang@Sun.COM 				    vswp->instance, maxbw, rv);
142710795SWentao.Yang@Sun.COM 			}
142810795SWentao.Yang@Sun.COM 		} else {
142910795SWentao.Yang@Sun.COM 			/*
143010795SWentao.Yang@Sun.COM 			 * update with successfully configured bandwidth.
143110795SWentao.Yang@Sun.COM 			 */
143210795SWentao.Yang@Sun.COM 			*bw = maxbw;
143310795SWentao.Yang@Sun.COM 		}
1434*11878SVenu.Iyer@Sun.COM 		kmem_free(mrp, sizeof (*mrp));
143510795SWentao.Yang@Sun.COM 	}
143610795SWentao.Yang@Sun.COM }
1437