xref: /onnv-gate/usr/src/uts/sun4v/io/vsw_phys.c (revision 10795:a68a30d0a8d6)
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 /*
239024SVenu.Iyer@Sun.COM  * Copyright 2009 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>
66*10795SWentao.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);
90*10795SWentao.Yang@Sun.COM static void vsw_maccl_set_bandwidth(vsw_t *vswp, vsw_port_t *port, int type,
91*10795SWentao.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);
120*10795SWentao.Yang@Sun.COM void vsw_update_bandwidth(vsw_t *vswp, vsw_port_t *port, int type,
121*10795SWentao.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
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
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
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
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
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
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
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
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 
459*10795SWentao.Yang@Sun.COM void
460*10795SWentao.Yang@Sun.COM vsw_update_bandwidth(vsw_t *vswp, vsw_port_t *port, int type, uint64_t maxbw)
461*10795SWentao.Yang@Sun.COM {
462*10795SWentao.Yang@Sun.COM 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
463*10795SWentao.Yang@Sun.COM 
464*10795SWentao.Yang@Sun.COM 	WRITE_MACCL_ENTER(vswp, port, type);
465*10795SWentao.Yang@Sun.COM 	vsw_maccl_set_bandwidth(vswp, port, type, maxbw);
466*10795SWentao.Yang@Sun.COM 	RW_MACCL_EXIT(vswp, port, type);
467*10795SWentao.Yang@Sun.COM }
468*10795SWentao.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
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_NO_HWRINGS -- This flag is used by default
5018275SEric Cheng  *	for all ports/interface so that they are associated with
5028275SEric Cheng  *	default group & resources. It will not be used for the
5038275SEric Cheng  *	ports that have HybridIO is enabled so that the h/w resources
5048275SEric Cheng  *	assigned to it.
5058275SEric Cheng  *
5068275SEric Cheng  *	MAC_OPEN_FLAGS_SHARES_DESIRED -- This flag is used to indicate
5078275SEric Cheng  *	that a port desires a Share. This will be the case with the
5088275SEric Cheng  *	the ports that have hybrid mode enabled. This will only cause
5098275SEric Cheng  *	MAC layer to allocate a share and corresponding resources
5108275SEric Cheng  *	ahead of time.
5118275SEric Cheng  *
5129024SVenu.Iyer@Sun.COM  *	MAC_UNICAST_TAG_DISABLE -- This flag is used for VLAN
5138275SEric Cheng  *	support. It will cause MAC to not add any tags, but expect
5148275SEric Cheng  *	vsw to tag the packets.
5158275SEric Cheng  *
5169024SVenu.Iyer@Sun.COM  *	MAC_UNICAST_STRIP_DISABLE -- This flag is used for VLAN
5178275SEric Cheng  *	support. It will case the MAC layer to not strip the tags.
5188275SEric Cheng  *	Vsw may have to strip the tag for pvid case.
5198275SEric Cheng  */
5208275SEric Cheng static int
5218275SEric Cheng vsw_maccl_open(vsw_t *vswp, vsw_port_t *port, int type)
5228275SEric Cheng {
5238275SEric Cheng 	int		rv = 0;
5248275SEric Cheng 	int		instance;
5258275SEric Cheng 	char		mac_cl_name[MAXNAMELEN];
5268275SEric Cheng 	const char	*dev_name;
5278275SEric Cheng 	mac_client_handle_t *mchp;
5289024SVenu.Iyer@Sun.COM 	uint64_t flags = MAC_OPEN_FLAGS_NO_HWRINGS;
5297529SSriharsha.Basavapatna@Sun.COM 
5308275SEric Cheng 	ASSERT(MUTEX_HELD(&vswp->mac_lock));
5318275SEric Cheng 	if (vswp->mh == NULL) {
5325373Sraghuram 		/*
5338275SEric Cheng 		 * In case net-dev is changed (either set to nothing or
5348275SEric Cheng 		 * using aggregation device), return success here as the
5358275SEric Cheng 		 * timeout mechanism will handle it.
5365373Sraghuram 		 */
5378275SEric Cheng 		return (0);
5385373Sraghuram 	}
5395373Sraghuram 
5408275SEric Cheng 	mchp = (type == VSW_LOCALDEV) ? &vswp->mch : &port->p_mch;
5418275SEric Cheng 	if (*mchp != NULL) {
5428275SEric Cheng 		/* already open */
5438275SEric Cheng 		return (0);
5448275SEric Cheng 	}
5458275SEric Cheng 	dev_name = ddi_driver_name(vswp->dip);
5468275SEric Cheng 	instance = ddi_get_instance(vswp->dip);
5478275SEric Cheng 	if (type == VSW_VNETPORT) {
5488275SEric Cheng 		if (port->p_hio_enabled == B_TRUE) {
5498275SEric Cheng 			flags &= ~MAC_OPEN_FLAGS_NO_HWRINGS;
5508275SEric Cheng 			flags |= MAC_OPEN_FLAGS_SHARES_DESIRED;
5518275SEric Cheng 		}
5528275SEric Cheng 		(void) snprintf(mac_cl_name, MAXNAMELEN, "%s%d%s%d", dev_name,
5538275SEric Cheng 		    instance, "_port", port->p_instance);
5548275SEric Cheng 	} else {
5558275SEric Cheng 		(void) snprintf(mac_cl_name, MAXNAMELEN, "%s%s%d",
5568275SEric Cheng 		    dev_name, "_if", instance);
5575373Sraghuram 	}
5585373Sraghuram 
5598275SEric Cheng 	rv = mac_client_open(vswp->mh, mchp, mac_cl_name, flags);
5608275SEric Cheng 	if (rv != 0) {
5618275SEric Cheng 		cmn_err(CE_NOTE, "!vsw%d:%s mac_client_open() failed\n",
5628275SEric Cheng 		    vswp->instance, mac_cl_name);
5638275SEric Cheng 	}
5648275SEric Cheng 	return (rv);
5655373Sraghuram }
5665373Sraghuram 
5678275SEric Cheng /*
5688275SEric Cheng  * Clean up by removing uncast, multicast addresses and
5698275SEric Cheng  * closing the MAC client for a port or the interface.
5708275SEric Cheng  */
5715373Sraghuram void
5728275SEric Cheng vsw_mac_client_cleanup(vsw_t *vswp, vsw_port_t *port, int type)
5735373Sraghuram {
5748275SEric Cheng 	WRITE_MACCL_ENTER(vswp, port, type);
5759943SWentao.Yang@Sun.COM 	vsw_mac_multicast_remove_all(vswp, port, type);
5768275SEric Cheng 	vsw_unset_hw(vswp, port, type);
5778275SEric Cheng 	vsw_maccl_close(vswp, port, type);
5788275SEric Cheng 	RW_MACCL_EXIT(vswp, port, type);
5798275SEric Cheng }
5805373Sraghuram 
5818275SEric Cheng /*
5828275SEric Cheng  * Close a MAC client for a port or an interface.
5838275SEric Cheng  */
5848275SEric Cheng static void
5858275SEric Cheng vsw_maccl_close(vsw_t *vswp, vsw_port_t *port, int type)
5868275SEric Cheng {
5878275SEric Cheng 	mac_client_handle_t *mchp;
5885373Sraghuram 
5898275SEric Cheng 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
5908275SEric Cheng 
5918275SEric Cheng 	mchp = (type == VSW_LOCALDEV) ? &vswp->mch : &port->p_mch;
5928275SEric Cheng 	if (*mchp != NULL) {
5938275SEric Cheng 		mac_client_close(*mchp, 0);
5948275SEric Cheng 		*mchp = NULL;
5955373Sraghuram 	}
5968275SEric Cheng }
5975373Sraghuram 
5988275SEric Cheng /*
5998275SEric Cheng  * Cleanup MAC client related stuff for all ports.
6008275SEric Cheng  */
6018275SEric Cheng void
6028275SEric Cheng vsw_mac_cleanup_ports(vsw_t *vswp)
6038275SEric Cheng {
6048275SEric Cheng 	vsw_port_list_t		*plist = &vswp->plist;
6058275SEric Cheng 	vsw_port_t		*port;
6065373Sraghuram 
6078275SEric Cheng 	READ_ENTER(&plist->lockrw);
6088275SEric Cheng 	for (port = plist->head; port != NULL; port = port->p_next) {
6098275SEric Cheng 		vsw_mac_client_cleanup(vswp, port, VSW_VNETPORT);
6108275SEric Cheng 	}
6118275SEric Cheng 	RW_EXIT(&plist->lockrw);
6125373Sraghuram }
6135373Sraghuram 
6145373Sraghuram /*
6155373Sraghuram  * Depending on the mode specified, the capabilites and capacity
6165373Sraghuram  * of the underlying device setup the physical device.
6175373Sraghuram  *
6185373Sraghuram  * If in layer 3 mode, then do nothing.
6195373Sraghuram  *
6208275SEric Cheng  * If in layer 2 mode, open a mac client and program the mac-address
6218275SEric Cheng  * and vlan-ids. The MAC layer will take care of programming
6228275SEric Cheng  * the address into h/w or set the h/w into promiscuous mode.
6235373Sraghuram  *
6245373Sraghuram  * Returns 0 success, 1 on failure.
6255373Sraghuram  */
6265373Sraghuram int
6275373Sraghuram vsw_set_hw(vsw_t *vswp, vsw_port_t *port, int type)
6285373Sraghuram {
6298275SEric Cheng 	int			err = 1;
6305373Sraghuram 
6315373Sraghuram 	D1(vswp, "%s: enter", __func__);
6325373Sraghuram 
6335373Sraghuram 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
6345373Sraghuram 
6358275SEric Cheng 	if (vswp->smode == VSW_LAYER3)
6365373Sraghuram 		return (0);
6375373Sraghuram 
6385373Sraghuram 	if (type == VSW_VNETPORT) {
6395373Sraghuram 		ASSERT(port != NULL);
6408275SEric Cheng 		err = vsw_set_port_hw_addr(port);
6415373Sraghuram 	} else {
6428275SEric Cheng 		err = vsw_set_if_hw_addr(vswp);
6435373Sraghuram 	}
6445373Sraghuram 
6455373Sraghuram 	D1(vswp, "%s: exit", __func__);
6468275SEric Cheng 	return (err);
6475373Sraghuram }
6485373Sraghuram 
6495373Sraghuram /*
6505373Sraghuram  * If in layer 3 mode do nothing.
6515373Sraghuram  *
6525373Sraghuram  * If in layer 2 switched mode remove the address from the physical
6535373Sraghuram  * device.
6545373Sraghuram  *
6555373Sraghuram  * If in layer 2 promiscuous mode disable promisc mode.
6565373Sraghuram  *
6575373Sraghuram  * Returns 0 on success.
6585373Sraghuram  */
6598275SEric Cheng void
6605373Sraghuram vsw_unset_hw(vsw_t *vswp, vsw_port_t *port, int type)
6615373Sraghuram {
6628275SEric Cheng 	D1(vswp, "%s: enter", __func__);
6638275SEric Cheng 
6648275SEric Cheng 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
6658275SEric Cheng 
6668275SEric Cheng 	if (vswp->smode == VSW_LAYER3)
6678275SEric Cheng 		return;
6688275SEric Cheng 
6698275SEric Cheng 	if (type == VSW_VNETPORT) {
6708275SEric Cheng 		ASSERT(port != NULL);
6718275SEric Cheng 		vsw_unset_hw_addr(vswp, port, type);
6728275SEric Cheng 	} else {
6738275SEric Cheng 		vsw_unset_hw_addr(vswp, NULL, type);
6748275SEric Cheng 	}
6758275SEric Cheng 
6768275SEric Cheng 	D1(vswp, "%s: exit", __func__);
6778275SEric Cheng }
6788275SEric Cheng 
6798275SEric Cheng /*
6808275SEric Cheng  * Program the macaddress and vlans of a port.
6818275SEric Cheng  *
6828275SEric Cheng  * Returns 0 on sucess, 1 on failure.
6838275SEric Cheng  */
6848275SEric Cheng static int
6858275SEric Cheng vsw_set_port_hw_addr(vsw_port_t *port)
6868275SEric Cheng {
6878275SEric Cheng 	vsw_t			*vswp = port->p_vswp;
6888275SEric Cheng 	mac_diag_t		diag;
6898275SEric Cheng 	uint8_t			*macaddr;
6908275SEric Cheng 	uint16_t		vid = VLAN_ID_NONE;
6918275SEric Cheng 	int			rv;
6929024SVenu.Iyer@Sun.COM 	uint16_t		mac_flags = MAC_UNICAST_TAG_DISABLE |
6939024SVenu.Iyer@Sun.COM 	    MAC_UNICAST_STRIP_DISABLE;
6945373Sraghuram 
6955373Sraghuram 	D1(vswp, "%s: enter", __func__);
6965373Sraghuram 
6978275SEric Cheng 	ASSERT(RW_WRITE_HELD(&port->maccl_rwlock));
6988275SEric Cheng 	if (port->p_mch == NULL)
6995373Sraghuram 		return (0);
7005373Sraghuram 
7018275SEric Cheng 	/*
7028275SEric Cheng 	 * If the port has a specific 'pvid', then
7038275SEric Cheng 	 * register with that vlan-id, otherwise register
7048275SEric Cheng 	 * with VLAN_ID_NONE.
7058275SEric Cheng 	 */
7068275SEric Cheng 	if (port->pvid != vswp->default_vlan_id) {
7078275SEric Cheng 		vid = port->pvid;
7088275SEric Cheng 	}
7098275SEric Cheng 	macaddr = (uint8_t *)port->p_macaddr.ether_addr_octet;
7105373Sraghuram 
7118275SEric Cheng 	if (!(vswp->smode & VSW_LAYER2_PROMISC)) {
7128275SEric Cheng 		mac_flags |= MAC_UNICAST_HW;
7138275SEric Cheng 	}
7145373Sraghuram 
7158275SEric Cheng 	if (port->addr_set == B_FALSE) {
7168275SEric Cheng 		port->p_muh = NULL;
7178275SEric Cheng 		rv = mac_unicast_add(port->p_mch, macaddr, mac_flags,
7188275SEric Cheng 		    &port->p_muh, vid, &diag);
7195373Sraghuram 
7208275SEric Cheng 		if (rv != 0) {
7218275SEric Cheng 			cmn_err(CE_WARN, "vsw%d: Failed to program"
7228275SEric Cheng 			    "macaddr,vid(%s, %d) err=%d",
7238275SEric Cheng 			    vswp->instance, ether_sprintf((void *)macaddr),
7248275SEric Cheng 			    vid, rv);
7258275SEric Cheng 			return (rv);
7265373Sraghuram 		}
7278275SEric Cheng 		port->addr_set = B_TRUE;
7285373Sraghuram 
7298275SEric Cheng 		D2(vswp, "%s:programmed macaddr(%s) vid(%d) into device %s",
7308275SEric Cheng 		    __func__, ether_sprintf((void *)macaddr), vid,
7318275SEric Cheng 		    vswp->physname);
7325373Sraghuram 	}
7335373Sraghuram 
7348275SEric Cheng 	/* Add vlans to the MAC layer */
7358275SEric Cheng 	vsw_mac_add_vlans(vswp, port->p_mch, macaddr,
7368275SEric Cheng 	    mac_flags, port->vids, port->nvids);
7378275SEric Cheng 
738*10795SWentao.Yang@Sun.COM 	/* Configure bandwidth to the MAC layer */
739*10795SWentao.Yang@Sun.COM 	vsw_maccl_set_bandwidth(NULL, port, VSW_VNETPORT, port->p_bandwidth);
740*10795SWentao.Yang@Sun.COM 
7418275SEric Cheng 	mac_rx_set(port->p_mch, vsw_port_rx_cb, (void *)port);
7428275SEric Cheng 
7435373Sraghuram 	D1(vswp, "%s: exit", __func__);
7445373Sraghuram 	return (rv);
7455373Sraghuram }
7465373Sraghuram 
7475373Sraghuram /*
7488275SEric Cheng  * Program the macaddress and vlans of a port.
7495373Sraghuram  *
7505373Sraghuram  * Returns 0 on sucess, 1 on failure.
7515373Sraghuram  */
7525373Sraghuram static int
7538275SEric Cheng vsw_set_if_hw_addr(vsw_t *vswp)
7545373Sraghuram {
7558275SEric Cheng 	mac_diag_t		diag;
7568275SEric Cheng 	uint8_t			*macaddr;
7578275SEric Cheng 	uint8_t			primary_addr[ETHERADDRL];
7588275SEric Cheng 	uint16_t		vid = VLAN_ID_NONE;
7598275SEric Cheng 	int			rv;
7609024SVenu.Iyer@Sun.COM 	uint16_t		mac_flags = MAC_UNICAST_TAG_DISABLE |
7619024SVenu.Iyer@Sun.COM 	    MAC_UNICAST_STRIP_DISABLE;
7625373Sraghuram 
7635373Sraghuram 	D1(vswp, "%s: enter", __func__);
7645373Sraghuram 
7658275SEric Cheng 	ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock));
7668275SEric Cheng 	if (vswp->mch == NULL)
7678275SEric Cheng 		return (0);
7685373Sraghuram 
7698275SEric Cheng 	macaddr = (uint8_t *)vswp->if_addr.ether_addr_octet;
7705373Sraghuram 
7718275SEric Cheng 	/* check if it is the primary macaddr of the card. */
7728275SEric Cheng 	mac_unicast_primary_get(vswp->mh, primary_addr);
7738275SEric Cheng 	if (ether_cmp((void *)primary_addr, (void*)macaddr) == 0) {
7748275SEric Cheng 		mac_flags |= MAC_UNICAST_PRIMARY;
7758275SEric Cheng 	}
7765373Sraghuram 
7775373Sraghuram 	/*
7788275SEric Cheng 	 * If the interface has a specific 'pvid', then
7798275SEric Cheng 	 * register with that vlan-id, otherwise register
7808275SEric Cheng 	 * with VLAN_ID_NONE.
7815373Sraghuram 	 */
7828275SEric Cheng 	if (vswp->pvid != vswp->default_vlan_id) {
7838275SEric Cheng 		vid = vswp->pvid;
7848275SEric Cheng 	}
7858275SEric Cheng 
7868275SEric Cheng 	if (!(vswp->smode & VSW_LAYER2_PROMISC)) {
7878275SEric Cheng 		mac_flags |= MAC_UNICAST_HW;
7885373Sraghuram 	}
7898275SEric Cheng 
7908275SEric Cheng 	if (vswp->addr_set == B_FALSE) {
7918275SEric Cheng 		vswp->muh = NULL;
7928275SEric Cheng 		rv = mac_unicast_add(vswp->mch, macaddr, mac_flags,
7938275SEric Cheng 		    &vswp->muh, vid, &diag);
7948275SEric Cheng 
7958275SEric Cheng 		if (rv != 0) {
7968275SEric Cheng 			cmn_err(CE_WARN, "vsw%d: Failed to program"
7978275SEric Cheng 			    "macaddr,vid(%s, %d) err=%d",
7988275SEric Cheng 			    vswp->instance, ether_sprintf((void *)macaddr),
7998275SEric Cheng 			    vid, rv);
8008275SEric Cheng 			return (rv);
8018275SEric Cheng 		}
8028275SEric Cheng 		vswp->addr_set = B_TRUE;
8038275SEric Cheng 
8048275SEric Cheng 		D2(vswp, "%s:programmed macaddr(%s) vid(%d) into device %s",
8058275SEric Cheng 		    __func__, ether_sprintf((void *)macaddr), vid,
8068275SEric Cheng 		    vswp->physname);
8078275SEric Cheng 	}
8088275SEric Cheng 
8098275SEric Cheng 	vsw_mac_add_vlans(vswp, vswp->mch, macaddr, mac_flags,
8108275SEric Cheng 	    vswp->vids, vswp->nvids);
8118275SEric Cheng 
812*10795SWentao.Yang@Sun.COM 	vsw_maccl_set_bandwidth(vswp, NULL, VSW_LOCALDEV, vswp->bandwidth);
813*10795SWentao.Yang@Sun.COM 
8148275SEric Cheng 	mac_rx_set(vswp->mch, vsw_if_rx_cb, (void *)vswp);
8158275SEric Cheng 
8165373Sraghuram 	D1(vswp, "%s: exit", __func__);
8175373Sraghuram 	return (rv);
8185373Sraghuram }
8195373Sraghuram 
8205373Sraghuram /*
8215373Sraghuram  * Remove a unicast mac address which has previously been programmed
8225373Sraghuram  * into HW.
8235373Sraghuram  *
8245373Sraghuram  * Returns 0 on sucess, 1 on failure.
8255373Sraghuram  */
8268275SEric Cheng static void
8278275SEric Cheng vsw_unset_hw_addr(vsw_t *vswp, vsw_port_t *port, int type)
8285373Sraghuram {
8298275SEric Cheng 	vsw_vlanid_t		*vids;
8308275SEric Cheng 	int			nvids;
8318275SEric Cheng 	mac_client_handle_t	mch = NULL;
8325373Sraghuram 
8335373Sraghuram 	D1(vswp, "%s: enter", __func__);
8345373Sraghuram 
8355373Sraghuram 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
8365373Sraghuram 
8375373Sraghuram 	if (type == VSW_VNETPORT) {
8385373Sraghuram 		ASSERT(port != NULL);
8398275SEric Cheng 		ASSERT(RW_WRITE_HELD(&port->maccl_rwlock));
8408275SEric Cheng 		vids = port->vids;
8418275SEric Cheng 		nvids = port->nvids;
8425373Sraghuram 	} else {
8438275SEric Cheng 		ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock));
8448275SEric Cheng 		vids = vswp->vids;
8458275SEric Cheng 		nvids = vswp->nvids;
8468275SEric Cheng 	}
8478275SEric Cheng 
8488275SEric Cheng 	/* First clear the callback */
8498275SEric Cheng 	if (type == VSW_LOCALDEV) {
8508275SEric Cheng 		mch = vswp->mch;
8518275SEric Cheng 	} else if (type == VSW_VNETPORT) {
8528275SEric Cheng 		mch = port->p_mch;
8538275SEric Cheng 	}
8548275SEric Cheng 
8558275SEric Cheng 
8568275SEric Cheng 	if (mch == NULL) {
8578275SEric Cheng 		return;
8588275SEric Cheng 	}
8598275SEric Cheng 
8608275SEric Cheng 	mac_rx_clear(mch);
8618275SEric Cheng 
8628275SEric Cheng 	/* Remove vlans */
8638275SEric Cheng 	vsw_mac_remove_vlans(mch, vids, nvids);
8648275SEric Cheng 
8658275SEric Cheng 	if ((type == VSW_LOCALDEV) && (vswp->addr_set == B_TRUE)) {
8668275SEric Cheng 		(void) mac_unicast_remove(vswp->mch, vswp->muh);
8678275SEric Cheng 		vswp->muh = NULL;
8688275SEric Cheng 		D2(vswp, "removed vsw interface mac-addr from "
8698275SEric Cheng 		    "the device %s", vswp->physname);
8708275SEric Cheng 		vswp->addr_set = B_FALSE;
8718275SEric Cheng 
8728275SEric Cheng 	} else if ((type == VSW_VNETPORT) && (port->addr_set == B_TRUE)) {
8738275SEric Cheng 		(void) mac_unicast_remove(port->p_mch, port->p_muh);
8748275SEric Cheng 		port->p_muh = NULL;
8758275SEric Cheng 		D2(vswp, "removed port(0x%p) mac-addr from "
8768275SEric Cheng 		    "the device %s", port, vswp->physname);
8778275SEric Cheng 		port->addr_set = B_FALSE;
8785373Sraghuram 	}
8795373Sraghuram 
8805373Sraghuram 	D1(vswp, "%s: exit", __func__);
8815373Sraghuram }
8825373Sraghuram 
8835373Sraghuram /*
8848275SEric Cheng  * receive callback routine for vsw interface. Invoked by MAC layer when there
8858275SEric Cheng  * are pkts being passed up from physical device for this vsw interface.
8865373Sraghuram  */
8878275SEric Cheng /* ARGSUSED */
8888275SEric Cheng static void
8898275SEric Cheng vsw_if_rx_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
8908275SEric Cheng     boolean_t loopback)
8915373Sraghuram {
8928275SEric Cheng 	_NOTE(ARGUNUSED(mrh))
8935373Sraghuram 
8948275SEric Cheng 	vsw_t		*vswp = (vsw_t *)arg;
8958275SEric Cheng 	mblk_t		*mpt;
8968275SEric Cheng 	int		count;
8975373Sraghuram 
8988275SEric Cheng 	ASSERT(vswp != NULL);
8995373Sraghuram 
9005373Sraghuram 	D1(vswp, "%s: enter", __func__);
9015373Sraghuram 
9028275SEric Cheng 	READ_ENTER(&vswp->if_lockrw);
9038275SEric Cheng 	if (vswp->if_state & VSW_IF_UP) {
9048275SEric Cheng 		RW_EXIT(&vswp->if_lockrw);
9058275SEric Cheng 		count = vsw_vlan_frame_untag(vswp, VSW_LOCALDEV, &mp, &mpt);
9068275SEric Cheng 		if (count != 0) {
9078275SEric Cheng 			mac_rx(vswp->if_mh, NULL, mp);
9088275SEric Cheng 		}
9098275SEric Cheng 	} else {
9108275SEric Cheng 		RW_EXIT(&vswp->if_lockrw);
9118275SEric Cheng 		freemsgchain(mp);
9125373Sraghuram 	}
9135373Sraghuram 
9145373Sraghuram 	D1(vswp, "%s: exit", __func__);
9155373Sraghuram }
9165373Sraghuram 
9175373Sraghuram /*
9188275SEric Cheng  * receive callback routine for port. Invoked by MAC layer when there
9198275SEric Cheng  * are pkts being passed up from physical device for this port.
9205373Sraghuram  */
9218275SEric Cheng /* ARGSUSED */
9228275SEric Cheng static void
9238275SEric Cheng vsw_port_rx_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
9248275SEric Cheng     boolean_t loopback)
9255373Sraghuram {
9268275SEric Cheng 	_NOTE(ARGUNUSED(mrh))
9275373Sraghuram 
9288275SEric Cheng 	vsw_t		*vswp;
9298275SEric Cheng 	vsw_port_t	*port = arg;
9305373Sraghuram 
9318275SEric Cheng 	ASSERT(port != NULL);
9325373Sraghuram 
9338275SEric Cheng 	vswp = port->p_vswp;
9348275SEric Cheng 
9358275SEric Cheng 	D1(vswp, "vsw_port_rx_cb: enter");
9365373Sraghuram 
9378275SEric Cheng 	/*
9388275SEric Cheng 	 * Send the packets to the peer directly.
9398275SEric Cheng 	 */
9408275SEric Cheng 	(void) vsw_portsend(port, mp);
9415373Sraghuram 
9428275SEric Cheng 	D1(vswp, "vsw_port_rx_cb: exit");
9435373Sraghuram }
9445373Sraghuram 
9455373Sraghuram /*
9468275SEric Cheng  * Send a message out over the physical device
9478275SEric Cheng  * via the MAC layer.
9485373Sraghuram  *
9498275SEric Cheng  * Returns any mblks that it was unable to transmit.
9505373Sraghuram  */
9518275SEric Cheng mblk_t *
9528275SEric Cheng vsw_tx_msg(vsw_t *vswp, mblk_t *mp, int caller, vsw_port_t *port)
9535373Sraghuram {
9548275SEric Cheng 	mac_client_handle_t	mch;
9558275SEric Cheng 	mac_unicast_handle_t	muh;
9565373Sraghuram 
9578275SEric Cheng 	READ_MACCL_ENTER(vswp, port, caller);
9585373Sraghuram 
9598275SEric Cheng 	mch = (caller == VSW_LOCALDEV) ? vswp->mch : port->p_mch;
9608275SEric Cheng 	muh = (caller == VSW_LOCALDEV) ? vswp->muh : port->p_muh;
9615373Sraghuram 
9629217SWentao.Yang@Sun.COM 	if (mch == NULL || muh == NULL) {
9639217SWentao.Yang@Sun.COM 		RW_MACCL_EXIT(vswp, port, caller);
9649217SWentao.Yang@Sun.COM 		return (mp);
9658275SEric Cheng 	}
9665373Sraghuram 
9679217SWentao.Yang@Sun.COM 	/* packets are sent or dropped */
9689217SWentao.Yang@Sun.COM 	(void) mac_tx(mch, mp, 0, MAC_DROP_ON_NO_DESC, NULL);
9698275SEric Cheng 	RW_MACCL_EXIT(vswp, port, caller);
9708275SEric Cheng 	return (NULL);
9715373Sraghuram }
9725373Sraghuram 
9735373Sraghuram /*
9748275SEric Cheng  * vsw_port_mac_reconfig -- Cleanup and close the MAC client
9758275SEric Cheng  * and reopen and re-configure the MAC client with new flags etc.
9768275SEric Cheng  * This function is useful for two different purposes:
9778275SEric Cheng  *	1) To update the MAC client with new vlan-ids. This is done
9788275SEric Cheng  *	   by freeing the existing vlan-ids and reopen with the new
9798275SEric Cheng  *	   vlan-ids.
9808275SEric Cheng  *
9818275SEric Cheng  *	2) If the Hybrid mode status of a port changes, then the
9828275SEric Cheng  *	   MAC client need to be closed and re-opened, otherwise,
9838275SEric Cheng  *	   Share related resources may not be freed(hybird mode disabled)
9848275SEric Cheng  *	   or assigned(hybrid mode enabled). To accomplish this,
9858275SEric Cheng  *	   this function simply closes and reopens the MAC client.
9868275SEric Cheng  *	   The reopen will result in using the flags based on the
9878275SEric Cheng  *	   new hybrid mode of the port.
9885373Sraghuram  */
9898275SEric Cheng void
9908275SEric Cheng vsw_port_mac_reconfig(vsw_port_t *portp, boolean_t update_vlans,
9918275SEric Cheng     uint16_t new_pvid, vsw_vlanid_t *new_vids, int new_nvids)
9925373Sraghuram {
9938275SEric Cheng 	vsw_t *vswp = portp->p_vswp;
9948275SEric Cheng 	int rv;
9955373Sraghuram 
9965373Sraghuram 	D1(vswp, "%s: enter", __func__);
9975373Sraghuram 	/*
9988275SEric Cheng 	 * Remove the multi-cast addresses, unicast address
9998275SEric Cheng 	 * and close the mac-client.
10005373Sraghuram 	 */
10018275SEric Cheng 	mutex_enter(&vswp->mac_lock);
10028275SEric Cheng 	WRITE_ENTER(&portp->maccl_rwlock);
10038275SEric Cheng 	vsw_mac_multicast_remove_all(vswp, portp, VSW_VNETPORT);
10048275SEric Cheng 	vsw_unset_hw(vswp, portp, VSW_VNETPORT);
10058275SEric Cheng 	vsw_maccl_close(vswp, portp, VSW_VNETPORT);
10065373Sraghuram 
10078275SEric Cheng 	if (update_vlans == B_TRUE) {
10088275SEric Cheng 		if (portp->nvids != 0) {
10098275SEric Cheng 			kmem_free(portp->vids,
10108275SEric Cheng 			    sizeof (vsw_vlanid_t) * portp->nvids);
10118275SEric Cheng 			portp->vids = NULL;
10128275SEric Cheng 			portp->nvids = 0;
10135373Sraghuram 		}
10148275SEric Cheng 		portp->vids = new_vids;
10158275SEric Cheng 		portp->nvids = new_nvids;
10168275SEric Cheng 		portp->pvid = new_pvid;
10175373Sraghuram 	}
10185373Sraghuram 
10195373Sraghuram 	/*
10208275SEric Cheng 	 * Now re-open the mac-client and
10218275SEric Cheng 	 * configure unicast addr and multicast addrs.
10225373Sraghuram 	 */
10238275SEric Cheng 	rv = vsw_maccl_open(vswp, portp, VSW_VNETPORT);
10248275SEric Cheng 	if (rv != 0) {
10258275SEric Cheng 		goto recret;
10265373Sraghuram 	}
10275373Sraghuram 
10288275SEric Cheng 	if (vsw_set_hw(vswp, portp, VSW_VNETPORT)) {
10298275SEric Cheng 		cmn_err(CE_NOTE, "!vsw%d: port:%d failed to "
10308275SEric Cheng 		    "set unicast address\n", vswp->instance, portp->p_instance);
10318275SEric Cheng 		goto recret;
10328275SEric Cheng 	}
10335373Sraghuram 
10348275SEric Cheng 	vsw_mac_multicast_add_all(vswp, portp, VSW_VNETPORT);
10355373Sraghuram 
10368275SEric Cheng recret:
10378275SEric Cheng 	RW_EXIT(&portp->maccl_rwlock);
10388275SEric Cheng 	mutex_exit(&vswp->mac_lock);
10395373Sraghuram 	D1(vswp, "%s: exit", __func__);
10405373Sraghuram }
10415373Sraghuram 
10425373Sraghuram /*
10438275SEric Cheng  * vsw_if_mac_reconfig -- Reconfigure the vsw interfaace's mac-client
10448275SEric Cheng  * by closing and re-opening it. This function is used handle the
10458275SEric Cheng  * following two cases:
10465373Sraghuram  *
10478275SEric Cheng  *	1) Handle the MAC address change for the interface.
10488275SEric Cheng  *	2) Handle vlan update.
10495373Sraghuram  */
10508275SEric Cheng void
10518275SEric Cheng vsw_if_mac_reconfig(vsw_t *vswp, boolean_t update_vlans,
10528275SEric Cheng     uint16_t new_pvid, vsw_vlanid_t *new_vids, int new_nvids)
10535373Sraghuram {
10548275SEric Cheng 	int rv;
10555373Sraghuram 
10568275SEric Cheng 	D1(vswp, "%s: enter", __func__);
10578275SEric Cheng 	/*
10588275SEric Cheng 	 * Remove the multi-cast addresses, unicast address
10598275SEric Cheng 	 * and close the mac-client.
10608275SEric Cheng 	 */
10618275SEric Cheng 	mutex_enter(&vswp->mac_lock);
10628275SEric Cheng 	WRITE_ENTER(&vswp->maccl_rwlock);
10638275SEric Cheng 	vsw_mac_multicast_remove_all(vswp, NULL, VSW_LOCALDEV);
10648275SEric Cheng 	vsw_unset_hw(vswp, NULL, VSW_LOCALDEV);
10658275SEric Cheng 	vsw_maccl_close(vswp, NULL, VSW_LOCALDEV);
10665373Sraghuram 
10678275SEric Cheng 	if (update_vlans == B_TRUE) {
10688275SEric Cheng 		if (vswp->nvids != 0) {
10698275SEric Cheng 			kmem_free(vswp->vids,
10708275SEric Cheng 			    sizeof (vsw_vlanid_t) * vswp->nvids);
10718275SEric Cheng 			vswp->vids = NULL;
10728275SEric Cheng 			vswp->nvids = 0;
10738275SEric Cheng 		}
10748275SEric Cheng 		vswp->vids = new_vids;
10758275SEric Cheng 		vswp->nvids = new_nvids;
10768275SEric Cheng 		vswp->pvid = new_pvid;
10778275SEric Cheng 	}
10785373Sraghuram 
10798275SEric Cheng 	/*
10808275SEric Cheng 	 * Now re-open the mac-client and
10818275SEric Cheng 	 * configure unicast addr and multicast addrs.
10828275SEric Cheng 	 */
10838275SEric Cheng 	rv = vsw_maccl_open(vswp, NULL, VSW_LOCALDEV);
10848275SEric Cheng 	if (rv != 0) {
10858275SEric Cheng 		goto ifrecret;
10868275SEric Cheng 	}
10875373Sraghuram 
10888275SEric Cheng 	if (vsw_set_hw(vswp, NULL, VSW_LOCALDEV)) {
10898275SEric Cheng 		cmn_err(CE_NOTE, "!vsw%d:failed to set unicast address\n",
10908275SEric Cheng 		    vswp->instance);
10918275SEric Cheng 		goto ifrecret;
10928275SEric Cheng 	}
10938275SEric Cheng 
10948275SEric Cheng 	vsw_mac_multicast_add_all(vswp, NULL, VSW_LOCALDEV);
10958275SEric Cheng 
10968275SEric Cheng ifrecret:
10978275SEric Cheng 	RW_EXIT(&vswp->maccl_rwlock);
10988275SEric Cheng 	mutex_exit(&vswp->mac_lock);
10998275SEric Cheng 	D1(vswp, "%s: exit", __func__);
11005373Sraghuram }
11015373Sraghuram 
11025373Sraghuram /*
11038275SEric Cheng  * vsw_mac_port_reconfig_vlans -- Reconfigure a port to handle
11048275SEric Cheng  * vlan configuration update. As the removal of the last unicast-address,vid
11058275SEric Cheng  * from the MAC client results in releasing all resources, it expects
11068275SEric Cheng  * no Shares to be associated with such MAC client.
11075373Sraghuram  *
11088275SEric Cheng  * To handle vlan configuration update for a port that already has
11098275SEric Cheng  * a Share bound, then we need to free that share prior to reconfiguration.
11108275SEric Cheng  * Initiate the hybrdIO setup again after the completion of reconfiguration.
11115373Sraghuram  */
11128275SEric Cheng void
11138275SEric Cheng vsw_mac_port_reconfig_vlans(vsw_port_t *portp, uint16_t new_pvid,
11148275SEric Cheng     vsw_vlanid_t *new_vids, int new_nvids)
11155373Sraghuram {
11168275SEric Cheng 	/*
11178275SEric Cheng 	 * As the reconfiguration involves the close of
11188275SEric Cheng 	 * mac client, cleanup HybridIO and later restart
11198275SEric Cheng 	 * HybridIO setup again.
11208275SEric Cheng 	 */
11218275SEric Cheng 	if (portp->p_hio_enabled == B_TRUE) {
11228275SEric Cheng 		vsw_hio_stop_port(portp);
11238275SEric Cheng 	}
11248275SEric Cheng 	vsw_port_mac_reconfig(portp, B_TRUE, new_pvid, new_vids, new_nvids);
11258275SEric Cheng 	if (portp->p_hio_enabled == B_TRUE) {
11268275SEric Cheng 		/* reset to setup the HybridIO again. */
11278275SEric Cheng 		vsw_hio_port_reset(portp, B_FALSE);
11288275SEric Cheng 	}
11298275SEric Cheng }
11308275SEric Cheng 
11318275SEric Cheng /* Add vlans to MAC client */
11328275SEric Cheng static void
11338275SEric Cheng vsw_mac_add_vlans(vsw_t *vswp, mac_client_handle_t mch, uint8_t *macaddr,
11348275SEric Cheng     uint16_t flags, vsw_vlanid_t *vids, int nvids)
11358275SEric Cheng {
11368275SEric Cheng 	vsw_vlanid_t	*vidp;
11378275SEric Cheng 	mac_diag_t	diag;
11388275SEric Cheng 	int		rv;
11398275SEric Cheng 	int		i;
11405373Sraghuram 
11419024SVenu.Iyer@Sun.COM 	flags |= MAC_UNICAST_TAG_DISABLE | MAC_UNICAST_STRIP_DISABLE;
11429024SVenu.Iyer@Sun.COM 
11438275SEric Cheng 	/* Add vlans to the MAC layer */
11448275SEric Cheng 	for (i = 0; i < nvids; i++) {
11458275SEric Cheng 		vidp = &vids[i];
11468275SEric Cheng 
11478275SEric Cheng 		if (vidp->vl_set == B_TRUE) {
11488275SEric Cheng 			continue;
11498275SEric Cheng 		}
11505373Sraghuram 
11518275SEric Cheng 		rv = mac_unicast_add(mch, macaddr, flags,
11528275SEric Cheng 		    &vidp->vl_muh, vidp->vl_vid, &diag);
11538275SEric Cheng 		if (rv != 0) {
11548275SEric Cheng 			cmn_err(CE_WARN, "vsw%d: Failed to program"
11558275SEric Cheng 			    "macaddr,vid(%s, %d) err=%d",
11568275SEric Cheng 			    vswp->instance, ether_sprintf((void *)macaddr),
11578275SEric Cheng 			    vidp->vl_vid, rv);
11588275SEric Cheng 		} else {
11598275SEric Cheng 			vidp->vl_set = B_TRUE;
11608275SEric Cheng 			D2(vswp, "%s:programmed macaddr(%s) vid(%d) "
11618275SEric Cheng 			    "into device %s", __func__,
11628275SEric Cheng 			    ether_sprintf((void *)macaddr),
11638275SEric Cheng 			    vidp->vl_vid, vswp->physname);
11648275SEric Cheng 		}
11655373Sraghuram 	}
11668275SEric Cheng }
11678275SEric Cheng 
11688275SEric Cheng /* Remove vlans from the MAC client */
11698275SEric Cheng static void
11708275SEric Cheng vsw_mac_remove_vlans(mac_client_handle_t mch, vsw_vlanid_t *vids, int nvids)
11718275SEric Cheng {
11728275SEric Cheng 	int i;
11738275SEric Cheng 	vsw_vlanid_t *vidp;
11745373Sraghuram 
11758275SEric Cheng 	for (i = 0; i < nvids; i++) {
11768275SEric Cheng 		vidp = &vids[i];
11778275SEric Cheng 		if (vidp->vl_set == B_FALSE) {
11788275SEric Cheng 			continue;
11798275SEric Cheng 		}
11808275SEric Cheng 		mac_unicast_remove(mch, vidp->vl_muh);
11818275SEric Cheng 		vidp->vl_set = B_FALSE;
11828275SEric Cheng 	}
11835373Sraghuram }
11847027Ssb155480 
11857027Ssb155480 #define	ARH_FIXED_LEN	8    /* Length of fixed part of ARP header(see arp.h) */
11867027Ssb155480 
11877027Ssb155480 /*
11887027Ssb155480  * Send a gratuitous RARP packet to notify the physical switch to update its
11897027Ssb155480  * Layer2 forwarding table for the given mac address. This is done to allow the
11907027Ssb155480  * switch to quickly learn the macaddr-port association when a guest is live
11917027Ssb155480  * migrated or when vsw's physical device is changed dynamically. Any protocol
11927027Ssb155480  * packet would serve this purpose, but we choose RARP, as it allows us to
11937027Ssb155480  * accomplish this within L2 (ie, no need to specify IP addr etc in the packet)
11947027Ssb155480  * The macaddr of vnet is retained across migration. Hence, we don't need to
11957027Ssb155480  * update the arp cache of other hosts within the broadcast domain. Note that
11967027Ssb155480  * it is harmless to send these RARP packets during normal port attach of a
11977027Ssb155480  * client vnet. This can can be turned off if needed, by setting
11987027Ssb155480  * vsw_publish_macaddr_count to zero in /etc/system.
11997027Ssb155480  */
12007027Ssb155480 void
12018275SEric Cheng vsw_publish_macaddr(vsw_t *vswp, vsw_port_t *portp)
12027027Ssb155480 {
12037027Ssb155480 	mblk_t			*mp;
12047027Ssb155480 	mblk_t			*bp;
12057027Ssb155480 	struct arphdr		*arh;
12067027Ssb155480 	struct	ether_header 	*ehp;
12077027Ssb155480 	int			count = 0;
12087027Ssb155480 	int			plen = 4;
12097027Ssb155480 	uint8_t			*cp;
12107027Ssb155480 
12117027Ssb155480 	mp = allocb(ETHERMIN, BPRI_MED);
12127027Ssb155480 	if (mp == NULL) {
12137027Ssb155480 		return;
12147027Ssb155480 	}
12157027Ssb155480 
12167027Ssb155480 	/* Initialize eth header */
12177027Ssb155480 	ehp = (struct  ether_header *)mp->b_rptr;
12187027Ssb155480 	bcopy(&etherbroadcastaddr, &ehp->ether_dhost, ETHERADDRL);
12198275SEric Cheng 	bcopy(&portp->p_macaddr, &ehp->ether_shost, ETHERADDRL);
12207027Ssb155480 	ehp->ether_type = htons(ETHERTYPE_REVARP);
12217027Ssb155480 
12227027Ssb155480 	/* Initialize arp packet */
12237027Ssb155480 	arh = (struct arphdr *)(mp->b_rptr + sizeof (struct ether_header));
12247027Ssb155480 	cp = (uint8_t *)arh;
12257027Ssb155480 
12267027Ssb155480 	arh->ar_hrd = htons(ARPHRD_ETHER);	/* Hardware type:  ethernet */
12277027Ssb155480 	arh->ar_pro = htons(ETHERTYPE_IP);	/* Protocol type:  IP */
12287027Ssb155480 	arh->ar_hln = ETHERADDRL;	/* Length of hardware address:  6 */
12297027Ssb155480 	arh->ar_pln = plen;		/* Length of protocol address:  4 */
12307027Ssb155480 	arh->ar_op = htons(REVARP_REQUEST);	/* Opcode: REVARP Request */
12317027Ssb155480 
12327027Ssb155480 	cp += ARH_FIXED_LEN;
12337027Ssb155480 
12347027Ssb155480 	/* Sender's hardware address and protocol address */
12358275SEric Cheng 	bcopy(&portp->p_macaddr, cp, ETHERADDRL);
12367027Ssb155480 	cp += ETHERADDRL;
12377027Ssb155480 	bzero(cp, plen);	/* INADDR_ANY */
12387027Ssb155480 	cp += plen;
12397027Ssb155480 
12407027Ssb155480 	/* Target hardware address and protocol address */
12418275SEric Cheng 	bcopy(&portp->p_macaddr, cp, ETHERADDRL);
12427027Ssb155480 	cp += ETHERADDRL;
12437027Ssb155480 	bzero(cp, plen);	/* INADDR_ANY */
12447027Ssb155480 	cp += plen;
12457027Ssb155480 
12467027Ssb155480 	mp->b_wptr += ETHERMIN;	/* total size is 42; round up to ETHERMIN */
12477027Ssb155480 
12487027Ssb155480 	for (count = 0; count < vsw_publish_macaddr_count; count++) {
12497027Ssb155480 
12507027Ssb155480 		bp = dupmsg(mp);
12517027Ssb155480 		if (bp == NULL) {
12527027Ssb155480 			continue;
12537027Ssb155480 		}
12547027Ssb155480 
12557027Ssb155480 		/* transmit the packet */
12568275SEric Cheng 		bp = vsw_tx_msg(vswp, bp, VSW_VNETPORT, portp);
12577027Ssb155480 		if (bp != NULL) {
12587027Ssb155480 			freemsg(bp);
12597027Ssb155480 		}
12607027Ssb155480 	}
12617027Ssb155480 
12627027Ssb155480 	freemsg(mp);
12637027Ssb155480 }
12647529SSriharsha.Basavapatna@Sun.COM 
12657529SSriharsha.Basavapatna@Sun.COM static void
12667529SSriharsha.Basavapatna@Sun.COM vsw_mac_set_mtu(vsw_t *vswp, uint32_t mtu)
12677529SSriharsha.Basavapatna@Sun.COM {
12688275SEric Cheng 	uint_t	mtu_orig;
12698275SEric Cheng 	int	rv;
12707529SSriharsha.Basavapatna@Sun.COM 
12718275SEric Cheng 	rv = mac_set_mtu(vswp->mh, mtu, &mtu_orig);
12727529SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
12737529SSriharsha.Basavapatna@Sun.COM 		cmn_err(CE_NOTE,
12747529SSriharsha.Basavapatna@Sun.COM 		    "!vsw%d: Unable to set the mtu:%d, in the "
12757529SSriharsha.Basavapatna@Sun.COM 		    "physical device:%s\n",
12767529SSriharsha.Basavapatna@Sun.COM 		    vswp->instance, mtu, vswp->physname);
12778275SEric Cheng 		return;
12787529SSriharsha.Basavapatna@Sun.COM 	}
12798275SEric Cheng 
12808275SEric Cheng 	/* save the original mtu of physdev to reset it back later if needed */
12818275SEric Cheng 	vswp->mtu_physdev_orig = mtu_orig;
12827529SSriharsha.Basavapatna@Sun.COM }
12839336SSriharsha.Basavapatna@Sun.COM 
12849336SSriharsha.Basavapatna@Sun.COM /*
12859336SSriharsha.Basavapatna@Sun.COM  * Register a callback with underlying mac layer for notifications.
12869336SSriharsha.Basavapatna@Sun.COM  * We are currently interested in only link-state events.
12879336SSriharsha.Basavapatna@Sun.COM  */
12889336SSriharsha.Basavapatna@Sun.COM static int
12899336SSriharsha.Basavapatna@Sun.COM vsw_notify_add(vsw_t *vswp)
12909336SSriharsha.Basavapatna@Sun.COM {
12919336SSriharsha.Basavapatna@Sun.COM 	mac_notify_handle_t	mnh;
12929336SSriharsha.Basavapatna@Sun.COM 	uint32_t		note;
12939336SSriharsha.Basavapatna@Sun.COM 
12949336SSriharsha.Basavapatna@Sun.COM 	/*
12959336SSriharsha.Basavapatna@Sun.COM 	 * Check if the underlying MAC supports link update notification.
12969336SSriharsha.Basavapatna@Sun.COM 	 */
12979336SSriharsha.Basavapatna@Sun.COM 	note = mac_no_notification(vswp->mh);
12989336SSriharsha.Basavapatna@Sun.COM 	if ((note & (DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN)) != 0) {
12999336SSriharsha.Basavapatna@Sun.COM 		vswp->phys_no_link_update = B_TRUE;
13009336SSriharsha.Basavapatna@Sun.COM 	} else {
13019336SSriharsha.Basavapatna@Sun.COM 		vswp->phys_no_link_update = B_FALSE;
13029336SSriharsha.Basavapatna@Sun.COM 	}
13039336SSriharsha.Basavapatna@Sun.COM 
13049336SSriharsha.Basavapatna@Sun.COM 	/*
13059336SSriharsha.Basavapatna@Sun.COM 	 * Read the current link state of the device and cache it.
13069336SSriharsha.Basavapatna@Sun.COM 	 */
13079336SSriharsha.Basavapatna@Sun.COM 	vswp->phys_link_state = vswp->phys_no_link_update ? LINK_STATE_UP :
13089336SSriharsha.Basavapatna@Sun.COM 	    mac_stat_get(vswp->mh, MAC_STAT_LINK_STATE);
13099336SSriharsha.Basavapatna@Sun.COM 
13109336SSriharsha.Basavapatna@Sun.COM 	/*
13119336SSriharsha.Basavapatna@Sun.COM 	 * Add notify callback function, if link update is supported.
13129336SSriharsha.Basavapatna@Sun.COM 	 */
13139336SSriharsha.Basavapatna@Sun.COM 	if (vswp->phys_no_link_update == B_TRUE) {
13149336SSriharsha.Basavapatna@Sun.COM 		return (0);
13159336SSriharsha.Basavapatna@Sun.COM 	}
13169336SSriharsha.Basavapatna@Sun.COM 
13179336SSriharsha.Basavapatna@Sun.COM 	mnh = mac_notify_add(vswp->mh, vsw_notify_cb, vswp);
13189336SSriharsha.Basavapatna@Sun.COM 	if (mnh == 0) {
13199336SSriharsha.Basavapatna@Sun.COM 		/* failed */
13209336SSriharsha.Basavapatna@Sun.COM 		return (1);
13219336SSriharsha.Basavapatna@Sun.COM 	}
13229336SSriharsha.Basavapatna@Sun.COM 
13239336SSriharsha.Basavapatna@Sun.COM 	vswp->mnh = mnh;
13249336SSriharsha.Basavapatna@Sun.COM 	return (0);
13259336SSriharsha.Basavapatna@Sun.COM }
13269336SSriharsha.Basavapatna@Sun.COM 
13279336SSriharsha.Basavapatna@Sun.COM /*
13289336SSriharsha.Basavapatna@Sun.COM  * Remove notify callback.
13299336SSriharsha.Basavapatna@Sun.COM  */
13309336SSriharsha.Basavapatna@Sun.COM static int
13319336SSriharsha.Basavapatna@Sun.COM vsw_notify_rem(vsw_t *vswp)
13329336SSriharsha.Basavapatna@Sun.COM {
13339336SSriharsha.Basavapatna@Sun.COM 	int	rv;
13349336SSriharsha.Basavapatna@Sun.COM 
13359336SSriharsha.Basavapatna@Sun.COM 	rv = mac_notify_remove(vswp->mnh, B_FALSE);
13369336SSriharsha.Basavapatna@Sun.COM 	return (rv);
13379336SSriharsha.Basavapatna@Sun.COM }
13389336SSriharsha.Basavapatna@Sun.COM 
13399336SSriharsha.Basavapatna@Sun.COM /*
13409336SSriharsha.Basavapatna@Sun.COM  * Notification callback invoked by the MAC service
13419336SSriharsha.Basavapatna@Sun.COM  * module. Note that we process only link state updates.
13429336SSriharsha.Basavapatna@Sun.COM  */
13439336SSriharsha.Basavapatna@Sun.COM static void
13449336SSriharsha.Basavapatna@Sun.COM vsw_notify_cb(void *arg, mac_notify_type_t type)
13459336SSriharsha.Basavapatna@Sun.COM {
13469336SSriharsha.Basavapatna@Sun.COM 	vsw_t	*vswp = arg;
13479336SSriharsha.Basavapatna@Sun.COM 
13489336SSriharsha.Basavapatna@Sun.COM 	switch (type) {
13499336SSriharsha.Basavapatna@Sun.COM 
13509336SSriharsha.Basavapatna@Sun.COM 	case MAC_NOTE_LINK:
13519336SSriharsha.Basavapatna@Sun.COM 		vsw_notify_link(vswp);
13529336SSriharsha.Basavapatna@Sun.COM 		break;
13539336SSriharsha.Basavapatna@Sun.COM 
13549336SSriharsha.Basavapatna@Sun.COM 	default:
13559336SSriharsha.Basavapatna@Sun.COM 		break;
13569336SSriharsha.Basavapatna@Sun.COM 
13579336SSriharsha.Basavapatna@Sun.COM 	}
13589336SSriharsha.Basavapatna@Sun.COM }
13599336SSriharsha.Basavapatna@Sun.COM 
13609336SSriharsha.Basavapatna@Sun.COM /*
13619336SSriharsha.Basavapatna@Sun.COM  * Invoked upon receiving a MAC_NOTE_LINK
13629336SSriharsha.Basavapatna@Sun.COM  * notification for the underlying physical device.
13639336SSriharsha.Basavapatna@Sun.COM  */
13649336SSriharsha.Basavapatna@Sun.COM static void
13659336SSriharsha.Basavapatna@Sun.COM vsw_notify_link(vsw_t *vswp)
13669336SSriharsha.Basavapatna@Sun.COM {
13679336SSriharsha.Basavapatna@Sun.COM 	link_state_t	link_state;
13689336SSriharsha.Basavapatna@Sun.COM 
13699336SSriharsha.Basavapatna@Sun.COM 	/* link state change  notification */
13709336SSriharsha.Basavapatna@Sun.COM 	link_state = mac_stat_get(vswp->mh, MAC_STAT_LINK_STATE);
13719336SSriharsha.Basavapatna@Sun.COM 
13729336SSriharsha.Basavapatna@Sun.COM 	if (vswp->phys_link_state != link_state) {
13739336SSriharsha.Basavapatna@Sun.COM 		D3(vswp, "%s: phys_link_state(%d)\n",
13749336SSriharsha.Basavapatna@Sun.COM 		    __func__, vswp->phys_link_state);
13759336SSriharsha.Basavapatna@Sun.COM 
13769336SSriharsha.Basavapatna@Sun.COM 		vswp->phys_link_state = link_state;
13779336SSriharsha.Basavapatna@Sun.COM 		vsw_physlink_state_update(vswp);
13789336SSriharsha.Basavapatna@Sun.COM 	}
13799336SSriharsha.Basavapatna@Sun.COM }
1380*10795SWentao.Yang@Sun.COM 
1381*10795SWentao.Yang@Sun.COM /*
1382*10795SWentao.Yang@Sun.COM  * Configure the bandwidth limit on the vsw or vnet devices via the MAC layer.
1383*10795SWentao.Yang@Sun.COM  * Note that bandwidth limit is not supported on a HybridIO enabled
1384*10795SWentao.Yang@Sun.COM  * vnet, as the HybridIO assigns a specific unit of hardware resource
1385*10795SWentao.Yang@Sun.COM  * that cannot be changed to limit bandwidth.
1386*10795SWentao.Yang@Sun.COM  */
1387*10795SWentao.Yang@Sun.COM static void
1388*10795SWentao.Yang@Sun.COM vsw_maccl_set_bandwidth(vsw_t *vswp, vsw_port_t *port, int type, uint64_t maxbw)
1389*10795SWentao.Yang@Sun.COM {
1390*10795SWentao.Yang@Sun.COM 	int			rv = 0;
1391*10795SWentao.Yang@Sun.COM 	uint64_t		*bw;
1392*10795SWentao.Yang@Sun.COM 	mac_resource_props_t	mrp;
1393*10795SWentao.Yang@Sun.COM 	mac_client_handle_t	mch;
1394*10795SWentao.Yang@Sun.COM 
1395*10795SWentao.Yang@Sun.COM 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
1396*10795SWentao.Yang@Sun.COM 
1397*10795SWentao.Yang@Sun.COM 	if (type == VSW_VNETPORT) {
1398*10795SWentao.Yang@Sun.COM 		ASSERT(RW_WRITE_HELD(&port->maccl_rwlock));
1399*10795SWentao.Yang@Sun.COM 		mch = port->p_mch;
1400*10795SWentao.Yang@Sun.COM 		bw = &port->p_bandwidth;
1401*10795SWentao.Yang@Sun.COM 	} else {
1402*10795SWentao.Yang@Sun.COM 		ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock));
1403*10795SWentao.Yang@Sun.COM 		mch = vswp->mch;
1404*10795SWentao.Yang@Sun.COM 		bw = &vswp->bandwidth;
1405*10795SWentao.Yang@Sun.COM 	}
1406*10795SWentao.Yang@Sun.COM 
1407*10795SWentao.Yang@Sun.COM 	if (mch == NULL) {
1408*10795SWentao.Yang@Sun.COM 		return;
1409*10795SWentao.Yang@Sun.COM 	}
1410*10795SWentao.Yang@Sun.COM 
1411*10795SWentao.Yang@Sun.COM 	if (maxbw >= MRP_MAXBW_MINVAL || maxbw == 0) {
1412*10795SWentao.Yang@Sun.COM 		bzero(&mrp, sizeof (mac_resource_props_t));
1413*10795SWentao.Yang@Sun.COM 		if (maxbw == 0) {
1414*10795SWentao.Yang@Sun.COM 			mrp.mrp_maxbw = MRP_MAXBW_RESETVAL;
1415*10795SWentao.Yang@Sun.COM 		} else {
1416*10795SWentao.Yang@Sun.COM 			mrp.mrp_maxbw = maxbw;
1417*10795SWentao.Yang@Sun.COM 		}
1418*10795SWentao.Yang@Sun.COM 		mrp.mrp_mask |= MRP_MAXBW;
1419*10795SWentao.Yang@Sun.COM 
1420*10795SWentao.Yang@Sun.COM 		rv = mac_client_set_resources(mch, &mrp);
1421*10795SWentao.Yang@Sun.COM 		if (rv != 0) {
1422*10795SWentao.Yang@Sun.COM 			if (type == VSW_VNETPORT) {
1423*10795SWentao.Yang@Sun.COM 				cmn_err(CE_NOTE, "!port%d: cannot set "
1424*10795SWentao.Yang@Sun.COM 				    "bandwidth limit to (%ld), error(%d)\n",
1425*10795SWentao.Yang@Sun.COM 				    port->p_instance, maxbw, rv);
1426*10795SWentao.Yang@Sun.COM 			} else {
1427*10795SWentao.Yang@Sun.COM 				cmn_err(CE_NOTE, "!vsw%d: cannot set "
1428*10795SWentao.Yang@Sun.COM 				    "bandwidth limit to (%ld), error(%d)\n",
1429*10795SWentao.Yang@Sun.COM 				    vswp->instance, maxbw, rv);
1430*10795SWentao.Yang@Sun.COM 			}
1431*10795SWentao.Yang@Sun.COM 		} else {
1432*10795SWentao.Yang@Sun.COM 			/*
1433*10795SWentao.Yang@Sun.COM 			 * update with successfully configured bandwidth.
1434*10795SWentao.Yang@Sun.COM 			 */
1435*10795SWentao.Yang@Sun.COM 			*bw = maxbw;
1436*10795SWentao.Yang@Sun.COM 		}
1437*10795SWentao.Yang@Sun.COM 	}
1438*10795SWentao.Yang@Sun.COM }
1439