xref: /titanic_52/usr/src/uts/sun4v/io/vsw_phys.c (revision 0dc2366f7b9f9f36e10909b1e95edbf2a261c2ac)
106db247cSraghuram /*
206db247cSraghuram  * CDDL HEADER START
306db247cSraghuram  *
406db247cSraghuram  * The contents of this file are subject to the terms of the
506db247cSraghuram  * Common Development and Distribution License (the "License").
606db247cSraghuram  * You may not use this file except in compliance with the License.
706db247cSraghuram  *
806db247cSraghuram  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
906db247cSraghuram  * or http://www.opensolaris.org/os/licensing.
1006db247cSraghuram  * See the License for the specific language governing permissions
1106db247cSraghuram  * and limitations under the License.
1206db247cSraghuram  *
1306db247cSraghuram  * When distributing Covered Code, include this CDDL HEADER in each
1406db247cSraghuram  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1506db247cSraghuram  * If applicable, add the following below this CDDL HEADER, with the
1606db247cSraghuram  * fields enclosed by brackets "[]" replaced with your own identifying
1706db247cSraghuram  * information: Portions Copyright [yyyy] [name of copyright owner]
1806db247cSraghuram  *
1906db247cSraghuram  * CDDL HEADER END
2006db247cSraghuram  */
2106db247cSraghuram 
2206db247cSraghuram /*
23*0dc2366fSVenugopal Iyer  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
2406db247cSraghuram  * Use is subject to license terms.
2506db247cSraghuram  */
2606db247cSraghuram 
2706db247cSraghuram #include <sys/types.h>
2806db247cSraghuram #include <sys/errno.h>
2906db247cSraghuram #include <sys/debug.h>
3006db247cSraghuram #include <sys/time.h>
3106db247cSraghuram #include <sys/sysmacros.h>
3206db247cSraghuram #include <sys/systm.h>
3306db247cSraghuram #include <sys/user.h>
3406db247cSraghuram #include <sys/stropts.h>
3506db247cSraghuram #include <sys/stream.h>
3606db247cSraghuram #include <sys/strlog.h>
3706db247cSraghuram #include <sys/strsubr.h>
3806db247cSraghuram #include <sys/cmn_err.h>
3906db247cSraghuram #include <sys/cpu.h>
4006db247cSraghuram #include <sys/kmem.h>
4106db247cSraghuram #include <sys/conf.h>
4206db247cSraghuram #include <sys/ddi.h>
4306db247cSraghuram #include <sys/sunddi.h>
4406db247cSraghuram #include <sys/ksynch.h>
4506db247cSraghuram #include <sys/stat.h>
4606db247cSraghuram #include <sys/kstat.h>
4706db247cSraghuram #include <sys/vtrace.h>
4806db247cSraghuram #include <sys/strsun.h>
4906db247cSraghuram #include <sys/dlpi.h>
5006db247cSraghuram #include <sys/ethernet.h>
5106db247cSraghuram #include <net/if.h>
5251aa9d07Ssb155480 #include <netinet/arp.h>
5351aa9d07Ssb155480 #include <inet/arp.h>
5406db247cSraghuram #include <sys/varargs.h>
5506db247cSraghuram #include <sys/machsystm.h>
5606db247cSraghuram #include <sys/modctl.h>
5706db247cSraghuram #include <sys/modhash.h>
58da14cebeSEric Cheng #include <sys/mac_client.h>
59da14cebeSEric Cheng #include <sys/mac_provider.h>
601107ea93SSriharsha Basavapatna #include <sys/mac_client_priv.h>
6106db247cSraghuram #include <sys/mac_ether.h>
6206db247cSraghuram #include <sys/taskq.h>
6306db247cSraghuram #include <sys/note.h>
6406db247cSraghuram #include <sys/mach_descrip.h>
6506db247cSraghuram #include <sys/mac.h>
66bce0a86eSWENTAO YANG #include <sys/mac_flow.h>
6706db247cSraghuram #include <sys/mdeg.h>
6806db247cSraghuram #include <sys/vsw.h>
69da14cebeSEric Cheng #include <sys/vlan.h>
7006db247cSraghuram 
7106db247cSraghuram /* MAC Ring table functions. */
72da14cebeSEric Cheng static void vsw_port_rx_cb(void *, mac_resource_handle_t, mblk_t *,
73da14cebeSEric Cheng     boolean_t);
74da14cebeSEric Cheng static void vsw_if_rx_cb(void *, mac_resource_handle_t, mblk_t *, boolean_t);
7506db247cSraghuram 
7606db247cSraghuram /* MAC layer routines */
77da14cebeSEric Cheng static int vsw_set_port_hw_addr(vsw_port_t *port);
78da14cebeSEric Cheng static int vsw_set_if_hw_addr(vsw_t *vswp);
79da14cebeSEric Cheng static	void vsw_unset_hw_addr(vsw_t *, vsw_port_t *, int);
80da14cebeSEric Cheng static int vsw_maccl_open(vsw_t *vswp, vsw_port_t *port, int type);
81da14cebeSEric Cheng static void vsw_maccl_close(vsw_t *vswp, vsw_port_t *port, int type);
82da14cebeSEric Cheng static void vsw_mac_multicast_add_all(vsw_t *vswp, vsw_port_t *portp, int type);
83da14cebeSEric Cheng static void vsw_mac_multicast_remove_all(vsw_t *vswp,
84da14cebeSEric Cheng     vsw_port_t *portp, int type);
85da14cebeSEric Cheng static void vsw_mac_add_vlans(vsw_t *vswp, mac_client_handle_t mch,
86da14cebeSEric Cheng     uint8_t *macaddr, uint16_t flags, vsw_vlanid_t *vids, int nvids);
87da14cebeSEric Cheng static void vsw_mac_remove_vlans(mac_client_handle_t mch, vsw_vlanid_t *vids,
88da14cebeSEric Cheng     int nvids);
897b1f684aSSriharsha Basavapatna static	void vsw_mac_set_mtu(vsw_t *vswp, uint32_t mtu);
90bce0a86eSWENTAO YANG static void vsw_maccl_set_bandwidth(vsw_t *vswp, vsw_port_t *port, int type,
91bce0a86eSWENTAO YANG     uint64_t maxbw);
921107ea93SSriharsha Basavapatna static int vsw_notify_add(vsw_t *vswp);
931107ea93SSriharsha Basavapatna static int vsw_notify_rem(vsw_t *vswp);
941107ea93SSriharsha Basavapatna static void vsw_notify_cb(void *arg, mac_notify_type_t type);
951107ea93SSriharsha Basavapatna static void vsw_notify_link(vsw_t *vswp);
9606db247cSraghuram 
9706db247cSraghuram /* Support functions */
9806db247cSraghuram int vsw_set_hw(vsw_t *, vsw_port_t *, int);
99da14cebeSEric Cheng void vsw_unset_hw(vsw_t *, vsw_port_t *, int);
10006db247cSraghuram void vsw_reconfig_hw(vsw_t *);
10106db247cSraghuram int vsw_mac_open(vsw_t *vswp);
10206db247cSraghuram void vsw_mac_close(vsw_t *vswp);
103da14cebeSEric Cheng int vsw_mac_multicast_add(vsw_t *vswp, vsw_port_t *port, mcst_addr_t *mcst_p,
104da14cebeSEric Cheng     int type);
105da14cebeSEric Cheng void vsw_mac_multicast_remove(vsw_t *vswp, vsw_port_t *port,
106da14cebeSEric Cheng     mcst_addr_t *mcst_p, int type);
107da14cebeSEric Cheng int vsw_mac_client_init(vsw_t *vswp, vsw_port_t *port, int type);
108da14cebeSEric Cheng void vsw_mac_client_cleanup(vsw_t *vswp, vsw_port_t *port, int type);
109da14cebeSEric Cheng void vsw_mac_cleanup_ports(vsw_t *vswp);
11006db247cSraghuram void vsw_unset_addrs(vsw_t *vswp);
11106db247cSraghuram void vsw_set_addrs(vsw_t *vswp);
112da14cebeSEric Cheng mblk_t *vsw_tx_msg(vsw_t *, mblk_t *, int, vsw_port_t *);
113da14cebeSEric Cheng void vsw_publish_macaddr(vsw_t *vswp, vsw_port_t *portp);
114da14cebeSEric Cheng void vsw_port_mac_reconfig(vsw_port_t *portp, boolean_t update_vlans,
115da14cebeSEric Cheng     uint16_t new_pvid, vsw_vlanid_t *new_vids, int new_nvids);
116da14cebeSEric Cheng void vsw_mac_port_reconfig_vlans(vsw_port_t *portp, uint16_t new_pvid,
117da14cebeSEric Cheng     vsw_vlanid_t *new_vids, int new_nvids);
118da14cebeSEric Cheng void vsw_if_mac_reconfig(vsw_t *vswp, boolean_t update_vlans,
119da14cebeSEric Cheng     uint16_t new_pvid, vsw_vlanid_t *new_vids, int new_nvids);
120bce0a86eSWENTAO YANG void vsw_update_bandwidth(vsw_t *vswp, vsw_port_t *port, int type,
121bce0a86eSWENTAO YANG     uint64_t maxbw);
12206db247cSraghuram 
123da14cebeSEric Cheng /*
124da14cebeSEric Cheng  * Functions imported from other files.
125da14cebeSEric Cheng  */
126da14cebeSEric Cheng extern int vsw_portsend(vsw_port_t *port, mblk_t *mp);
127da14cebeSEric Cheng extern void vsw_hio_stop_port(vsw_port_t *portp);
128da14cebeSEric Cheng extern void vsw_hio_port_reset(vsw_port_t *portp, boolean_t immediate);
129da14cebeSEric Cheng extern uint32_t vsw_publish_macaddr_count;
130da14cebeSEric Cheng extern uint32_t vsw_vlan_frame_untag(void *arg, int type, mblk_t **np,
131da14cebeSEric Cheng 	mblk_t **npt);
1321107ea93SSriharsha Basavapatna extern void vsw_physlink_state_update(vsw_t *vswp);
1337b1f684aSSriharsha Basavapatna static char mac_mtu_propname[] = "mtu";
1347b1f684aSSriharsha Basavapatna 
13506db247cSraghuram /*
13606db247cSraghuram  * Tunables used in this file.
13706db247cSraghuram  */
13806db247cSraghuram extern int vsw_mac_open_retries;
139da14cebeSEric Cheng 
140da14cebeSEric Cheng #define	WRITE_MACCL_ENTER(vswp, port, type)	\
141da14cebeSEric Cheng 	(type == VSW_LOCALDEV) ?  rw_enter(&vswp->maccl_rwlock, RW_WRITER) :\
142da14cebeSEric Cheng 	rw_enter(&port->maccl_rwlock, RW_WRITER)
143da14cebeSEric Cheng 
144da14cebeSEric Cheng #define	READ_MACCL_ENTER(vswp, port, type)	\
145da14cebeSEric Cheng 	(type == VSW_LOCALDEV) ?  rw_enter(&vswp->maccl_rwlock, RW_READER) :\
146da14cebeSEric Cheng 	rw_enter(&port->maccl_rwlock, RW_READER)
147da14cebeSEric Cheng 
148da14cebeSEric Cheng #define	RW_MACCL_EXIT(vswp, port, type)	\
149da14cebeSEric Cheng 	(type == VSW_LOCALDEV) ?  rw_exit(&vswp->maccl_rwlock) :	\
150da14cebeSEric Cheng 	rw_exit(&port->maccl_rwlock)
151da14cebeSEric Cheng 
15206db247cSraghuram 
15306db247cSraghuram /*
154da14cebeSEric Cheng  * Locking strategy in this file is explained as follows:
155da14cebeSEric Cheng  *	 - A global lock(vswp->mac_lock) is used to protect the
156da14cebeSEric Cheng  *	   MAC calls that deal with entire device. That is, the
157da14cebeSEric Cheng  *	   operations that deal with mac_handle which include
158da14cebeSEric Cheng  *	   mac_open()/close() and mac_client_open().
15906db247cSraghuram  *
160da14cebeSEric Cheng  *	- A per port/interface RW lock(maccl_rwlock) is used protect
161da14cebeSEric Cheng  *	  the operations that deal with the MAC client.
162da14cebeSEric Cheng  *
163da14cebeSEric Cheng  *	When both mac_lock and maccl_rwlock need to be held, the
164da14cebeSEric Cheng  *	mac_lock need be acquired first and then maccl_rwlock. That is,
165da14cebeSEric Cheng  *		mac_lock---->maccl_rwlock
166da14cebeSEric Cheng  *
167da14cebeSEric Cheng  *	The 'mca_lock' that protects the mcast list is also acquired
168da14cebeSEric Cheng  *	within the context of maccl_rwlock. The hierarchy for this
169da14cebeSEric Cheng  *	one is as below:
170da14cebeSEric Cheng  *		maccl_rwlock---->mca_lock
17106db247cSraghuram  */
17206db247cSraghuram 
17306db247cSraghuram 
17406db247cSraghuram /*
17506db247cSraghuram  * Program unicast and multicast addresses of vsw interface and the ports
176da14cebeSEric Cheng  * into the network device.
17706db247cSraghuram  */
17806db247cSraghuram void
17906db247cSraghuram vsw_set_addrs(vsw_t *vswp)
18006db247cSraghuram {
18106db247cSraghuram 	vsw_port_list_t	*plist = &vswp->plist;
18206db247cSraghuram 	vsw_port_t	*port;
18306db247cSraghuram 	int		rv;
18406db247cSraghuram 
18506db247cSraghuram 	READ_ENTER(&vswp->if_lockrw);
18606db247cSraghuram 
18706db247cSraghuram 	if (vswp->if_state & VSW_IF_UP) {
18806db247cSraghuram 
189da14cebeSEric Cheng 		/* Open a mac client and program addresses */
190da14cebeSEric Cheng 		rv = vsw_mac_client_init(vswp, NULL, VSW_LOCALDEV);
19106db247cSraghuram 		if (rv != 0) {
19206db247cSraghuram 			cmn_err(CE_NOTE,
19306db247cSraghuram 			    "!vsw%d: failed to program interface "
19406db247cSraghuram 			    "unicast address\n", vswp->instance);
19506db247cSraghuram 		}
196da14cebeSEric Cheng 
19706db247cSraghuram 		/*
19806db247cSraghuram 		 * Notify the MAC layer of the changed address.
19906db247cSraghuram 		 */
200da14cebeSEric Cheng 		if (rv == 0) {
20106db247cSraghuram 			mac_unicst_update(vswp->if_mh,
20206db247cSraghuram 			    (uint8_t *)&vswp->if_addr);
20306db247cSraghuram 		}
20406db247cSraghuram 
20506db247cSraghuram 	}
20606db247cSraghuram 
20706db247cSraghuram 	RW_EXIT(&vswp->if_lockrw);
20806db247cSraghuram 
20906db247cSraghuram 	WRITE_ENTER(&plist->lockrw);
21006db247cSraghuram 
211da14cebeSEric Cheng 	/* program unicast address of ports in the network device */
21206db247cSraghuram 	for (port = plist->head; port != NULL; port = port->p_next) {
213da14cebeSEric Cheng 		if (port->addr_set) /* addr already set */
21406db247cSraghuram 			continue;
215da14cebeSEric Cheng 
216da14cebeSEric Cheng 		/* Open a mac client and program addresses */
217da14cebeSEric Cheng 		rv = vsw_mac_client_init(vswp, port, VSW_VNETPORT);
218da14cebeSEric Cheng 		if (rv != 0) {
21906db247cSraghuram 			cmn_err(CE_NOTE,
220da14cebeSEric Cheng 			    "!vsw%d: failed to program port(%d) "
221da14cebeSEric Cheng 			    "unicast address\n", vswp->instance,
222da14cebeSEric Cheng 			    port->p_instance);
22306db247cSraghuram 		}
22406db247cSraghuram 	}
22551aa9d07Ssb155480 	/* announce macaddr of vnets to the physical switch */
22651aa9d07Ssb155480 	if (vsw_publish_macaddr_count != 0) {	/* enabled */
22751aa9d07Ssb155480 		for (port = plist->head; port != NULL; port = port->p_next) {
228da14cebeSEric Cheng 			vsw_publish_macaddr(vswp, port);
22951aa9d07Ssb155480 		}
23051aa9d07Ssb155480 	}
23151aa9d07Ssb155480 
23206db247cSraghuram 	RW_EXIT(&plist->lockrw);
23306db247cSraghuram }
23406db247cSraghuram 
23506db247cSraghuram /*
236da14cebeSEric Cheng  * Remove unicast, multicast addresses and close mac clients
237da14cebeSEric Cheng  * for the vsw interface and all ports.
23806db247cSraghuram  */
23906db247cSraghuram void
24006db247cSraghuram vsw_unset_addrs(vsw_t *vswp)
24106db247cSraghuram {
24206db247cSraghuram 	READ_ENTER(&vswp->if_lockrw);
24306db247cSraghuram 	if (vswp->if_state & VSW_IF_UP) {
24406db247cSraghuram 
245da14cebeSEric Cheng 		/* Cleanup and close the mac client for the interface */
246da14cebeSEric Cheng 		vsw_mac_client_cleanup(vswp, NULL, VSW_LOCALDEV);
24706db247cSraghuram 	}
24806db247cSraghuram 	RW_EXIT(&vswp->if_lockrw);
24906db247cSraghuram 
250da14cebeSEric Cheng 	/* Cleanup and close the mac clients for all ports */
251da14cebeSEric Cheng 	vsw_mac_cleanup_ports(vswp);
25206db247cSraghuram }
25306db247cSraghuram 
25406db247cSraghuram /*
255da14cebeSEric Cheng  * Open the underlying network device for access in layer2 mode.
25606db247cSraghuram  * Returns:
25706db247cSraghuram  *	0 on success
25806db247cSraghuram  *	EAGAIN if mac_open() fails due to the device being not available yet.
25906db247cSraghuram  *	EIO on any other failures.
26006db247cSraghuram  */
26106db247cSraghuram int
26206db247cSraghuram vsw_mac_open(vsw_t *vswp)
26306db247cSraghuram {
26406db247cSraghuram 	int			rv;
26506db247cSraghuram 
266da14cebeSEric Cheng 	ASSERT(MUTEX_HELD(&vswp->mac_lock));
26706db247cSraghuram 
26806db247cSraghuram 	if (vswp->mh != NULL) {
26906db247cSraghuram 		/* already open */
27006db247cSraghuram 		return (0);
27106db247cSraghuram 	}
27206db247cSraghuram 
27306db247cSraghuram 	if (vswp->mac_open_retries++ >= vsw_mac_open_retries) {
27406db247cSraghuram 		/* exceeded max retries */
27506db247cSraghuram 		return (EIO);
27606db247cSraghuram 	}
27706db247cSraghuram 
278d62bc4baSyz147064 	if ((rv = mac_open_by_linkname(vswp->physname, &vswp->mh)) != 0) {
27906db247cSraghuram 		/*
280d62bc4baSyz147064 		 * If mac_open() failed and the error indicates that either
281d62bc4baSyz147064 		 * the dlmgmtd door or the device is not available yet, we
282d62bc4baSyz147064 		 * return EAGAIN to indicate that mac_open() needs to be
283d62bc4baSyz147064 		 * retried. For example, this may happen during boot up, if
284d62bc4baSyz147064 		 * the required link aggregation groups(devices) have not
285d62bc4baSyz147064 		 * been created yet.
28606db247cSraghuram 		 */
287d62bc4baSyz147064 		if (rv == ENOENT || rv == EBADF) {
28806db247cSraghuram 			return (EAGAIN);
28906db247cSraghuram 		} else {
2901107ea93SSriharsha Basavapatna 			cmn_err(CE_WARN, "!vsw%d: mac_open %s failed rv:%x\n",
29106db247cSraghuram 			    vswp->instance, vswp->physname, rv);
29206db247cSraghuram 			return (EIO);
29306db247cSraghuram 		}
29406db247cSraghuram 	}
29506db247cSraghuram 	vswp->mac_open_retries = 0;
29606db247cSraghuram 
297da14cebeSEric Cheng 	vsw_mac_set_mtu(vswp, vswp->mtu);
298da14cebeSEric Cheng 
2991107ea93SSriharsha Basavapatna 	rv = vsw_notify_add(vswp);
3001107ea93SSriharsha Basavapatna 	if (rv != 0) {
3011107ea93SSriharsha Basavapatna 		cmn_err(CE_CONT, "!vsw%d: mac_notify_add %s failed rv:%x\n",
3021107ea93SSriharsha Basavapatna 		    vswp->instance, vswp->physname, rv);
3031107ea93SSriharsha Basavapatna 	}
3041107ea93SSriharsha Basavapatna 
30506db247cSraghuram 	return (0);
30606db247cSraghuram }
30706db247cSraghuram 
30806db247cSraghuram /*
30906db247cSraghuram  * Close the underlying physical device.
31006db247cSraghuram  */
31106db247cSraghuram void
31206db247cSraghuram vsw_mac_close(vsw_t *vswp)
31306db247cSraghuram {
314da14cebeSEric Cheng 	ASSERT(MUTEX_HELD(&vswp->mac_lock));
31506db247cSraghuram 
31606db247cSraghuram 	if (vswp->mh != NULL) {
3171107ea93SSriharsha Basavapatna 		if (vswp->mnh != 0) {
3181107ea93SSriharsha Basavapatna 			(void) vsw_notify_rem(vswp);
3191107ea93SSriharsha Basavapatna 			vswp->mnh = 0;
3201107ea93SSriharsha Basavapatna 		}
321da14cebeSEric Cheng 		if (vswp->mtu != vswp->mtu_physdev_orig) {
322da14cebeSEric Cheng 			vsw_mac_set_mtu(vswp, vswp->mtu_physdev_orig);
323da14cebeSEric Cheng 		}
32406db247cSraghuram 		mac_close(vswp->mh);
32506db247cSraghuram 		vswp->mh = NULL;
32606db247cSraghuram 	}
32706db247cSraghuram }
32806db247cSraghuram 
32906db247cSraghuram /*
330da14cebeSEric Cheng  * Add multicast addr.
33106db247cSraghuram  */
33206db247cSraghuram int
333da14cebeSEric Cheng vsw_mac_multicast_add(vsw_t *vswp, vsw_port_t *port, mcst_addr_t *mcst_p,
334da14cebeSEric Cheng     int type)
33506db247cSraghuram {
336da14cebeSEric Cheng 	int			ret = 0;
337da14cebeSEric Cheng 	mac_client_handle_t	mch;
33806db247cSraghuram 
339da14cebeSEric Cheng 	WRITE_MACCL_ENTER(vswp, port, type);
34006db247cSraghuram 
341da14cebeSEric Cheng 	mch = (type == VSW_LOCALDEV) ? vswp->mch : port->p_mch;
34206db247cSraghuram 
343da14cebeSEric Cheng 	if (mch != NULL) {
344da14cebeSEric Cheng 		ret = mac_multicast_add(mch, mcst_p->mca.ether_addr_octet);
345da14cebeSEric Cheng 		if (ret != 0) {
346da14cebeSEric Cheng 			cmn_err(CE_WARN, "!vsw%d: unable to "
347da14cebeSEric Cheng 			    "program multicast address(%s) err=%d",
348da14cebeSEric Cheng 			    vswp->instance,
349da14cebeSEric Cheng 			    ether_sprintf((void *)&mcst_p->mca), ret);
350da14cebeSEric Cheng 			RW_MACCL_EXIT(vswp, port, type);
351da14cebeSEric Cheng 			return (ret);
352da14cebeSEric Cheng 		}
353da14cebeSEric Cheng 		mcst_p->mac_added = B_TRUE;
35406db247cSraghuram 	}
35506db247cSraghuram 
356da14cebeSEric Cheng 	RW_MACCL_EXIT(vswp, port, type);
357da14cebeSEric Cheng 	return (ret);
35806db247cSraghuram }
35906db247cSraghuram 
360da14cebeSEric Cheng /*
361da14cebeSEric Cheng  * Remove multicast addr.
362da14cebeSEric Cheng  */
36306db247cSraghuram void
364da14cebeSEric Cheng vsw_mac_multicast_remove(vsw_t *vswp, vsw_port_t *port, mcst_addr_t *mcst_p,
365da14cebeSEric Cheng     int type)
36606db247cSraghuram {
367da14cebeSEric Cheng 	mac_client_handle_t	mch;
36806db247cSraghuram 
369da14cebeSEric Cheng 	WRITE_MACCL_ENTER(vswp, port, type);
370da14cebeSEric Cheng 	mch = (type == VSW_LOCALDEV) ? vswp->mch : port->p_mch;
37106db247cSraghuram 
372da14cebeSEric Cheng 	if (mch != NULL && mcst_p->mac_added) {
373da14cebeSEric Cheng 		mac_multicast_remove(mch, mcst_p->mca.ether_addr_octet);
374da14cebeSEric Cheng 		mcst_p->mac_added = B_FALSE;
375da14cebeSEric Cheng 	}
376da14cebeSEric Cheng 	RW_MACCL_EXIT(vswp, port, type);
37706db247cSraghuram }
37806db247cSraghuram 
379da14cebeSEric Cheng 
380da14cebeSEric Cheng /*
381da14cebeSEric Cheng  * Add all multicast addresses of the port.
382da14cebeSEric Cheng  */
383da14cebeSEric Cheng static void
384da14cebeSEric Cheng vsw_mac_multicast_add_all(vsw_t *vswp, vsw_port_t *portp, int type)
385da14cebeSEric Cheng {
386da14cebeSEric Cheng 	mcst_addr_t		*mcap;
387da14cebeSEric Cheng 	mac_client_handle_t	mch;
388da14cebeSEric Cheng 	kmutex_t		*mca_lockp;
389da14cebeSEric Cheng 	int			rv;
390da14cebeSEric Cheng 
391da14cebeSEric Cheng 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
392da14cebeSEric Cheng 	if (type == VSW_LOCALDEV) {
393da14cebeSEric Cheng 		ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock));
394da14cebeSEric Cheng 		mch = vswp->mch;
395da14cebeSEric Cheng 		mcap = vswp->mcap;
396da14cebeSEric Cheng 		mca_lockp = &vswp->mca_lock;
397da14cebeSEric Cheng 	} else {
398da14cebeSEric Cheng 		ASSERT(RW_WRITE_HELD(&portp->maccl_rwlock));
399da14cebeSEric Cheng 		mch = portp->p_mch;
400da14cebeSEric Cheng 		mcap = portp->mcap;
401da14cebeSEric Cheng 		mca_lockp = &portp->mca_lock;
402da14cebeSEric Cheng 	}
403da14cebeSEric Cheng 
404da14cebeSEric Cheng 	if (mch == NULL)
405da14cebeSEric Cheng 		return;
406da14cebeSEric Cheng 
407da14cebeSEric Cheng 	mutex_enter(mca_lockp);
408da14cebeSEric Cheng 	for (mcap = mcap; mcap != NULL; mcap = mcap->nextp) {
409da14cebeSEric Cheng 		if (mcap->mac_added)
410da14cebeSEric Cheng 			continue;
411da14cebeSEric Cheng 		rv = mac_multicast_add(mch, (uchar_t *)&mcap->mca);
412da14cebeSEric Cheng 		if (rv == 0) {
413da14cebeSEric Cheng 			mcap->mac_added = B_TRUE;
414da14cebeSEric Cheng 		} else {
415da14cebeSEric Cheng 			cmn_err(CE_WARN, "!vsw%d: unable to program "
416da14cebeSEric Cheng 			    "multicast address(%s) err=%d", vswp->instance,
417da14cebeSEric Cheng 			    ether_sprintf((void *)&mcap->mca), rv);
418da14cebeSEric Cheng 		}
419da14cebeSEric Cheng 	}
420da14cebeSEric Cheng 	mutex_exit(mca_lockp);
421da14cebeSEric Cheng }
422da14cebeSEric Cheng 
423da14cebeSEric Cheng /*
424da14cebeSEric Cheng  * Remove all multicast addresses of the port.
425da14cebeSEric Cheng  */
426da14cebeSEric Cheng static void
427da14cebeSEric Cheng vsw_mac_multicast_remove_all(vsw_t *vswp, vsw_port_t *portp, int type)
428da14cebeSEric Cheng {
429da14cebeSEric Cheng 	mac_client_handle_t	mch;
430da14cebeSEric Cheng 	mcst_addr_t		*mcap;
431da14cebeSEric Cheng 	kmutex_t		*mca_lockp;
432da14cebeSEric Cheng 
433da14cebeSEric Cheng 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
434da14cebeSEric Cheng 	if (type == VSW_LOCALDEV) {
435da14cebeSEric Cheng 		ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock));
436da14cebeSEric Cheng 		mch = vswp->mch;
437da14cebeSEric Cheng 		mcap = vswp->mcap;
438da14cebeSEric Cheng 		mca_lockp = &vswp->mca_lock;
439da14cebeSEric Cheng 	} else {
440da14cebeSEric Cheng 		ASSERT(RW_WRITE_HELD(&portp->maccl_rwlock));
441da14cebeSEric Cheng 		mch = portp->p_mch;
442da14cebeSEric Cheng 		mcap = portp->mcap;
443da14cebeSEric Cheng 		mca_lockp = &portp->mca_lock;
444da14cebeSEric Cheng 	}
445da14cebeSEric Cheng 
446da14cebeSEric Cheng 	if (mch == NULL)
447da14cebeSEric Cheng 		return;
448da14cebeSEric Cheng 
449da14cebeSEric Cheng 	mutex_enter(mca_lockp);
450da14cebeSEric Cheng 	for (; mcap != NULL; mcap = mcap->nextp) {
451da14cebeSEric Cheng 		if (!mcap->mac_added)
452da14cebeSEric Cheng 			continue;
453da14cebeSEric Cheng 		(void) mac_multicast_remove(mch, (uchar_t *)&mcap->mca);
454da14cebeSEric Cheng 		mcap->mac_added = B_FALSE;
455da14cebeSEric Cheng 	}
456da14cebeSEric Cheng 	mutex_exit(mca_lockp);
457da14cebeSEric Cheng }
458da14cebeSEric Cheng 
459bce0a86eSWENTAO YANG void
460bce0a86eSWENTAO YANG vsw_update_bandwidth(vsw_t *vswp, vsw_port_t *port, int type, uint64_t maxbw)
461bce0a86eSWENTAO YANG {
462bce0a86eSWENTAO YANG 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
463bce0a86eSWENTAO YANG 
464bce0a86eSWENTAO YANG 	WRITE_MACCL_ENTER(vswp, port, type);
465bce0a86eSWENTAO YANG 	vsw_maccl_set_bandwidth(vswp, port, type, maxbw);
466bce0a86eSWENTAO YANG 	RW_MACCL_EXIT(vswp, port, type);
467bce0a86eSWENTAO YANG }
468bce0a86eSWENTAO YANG 
469da14cebeSEric Cheng /*
470da14cebeSEric Cheng  * Open a mac client and program uncast and multicast addresses
471da14cebeSEric Cheng  * for a port or the interface.
472da14cebeSEric Cheng  * Returns:
473da14cebeSEric Cheng  *	0 on success
474da14cebeSEric Cheng  *	non-zero for failure.
475da14cebeSEric Cheng  */
476da14cebeSEric Cheng int
477da14cebeSEric Cheng vsw_mac_client_init(vsw_t *vswp, vsw_port_t *port, int type)
478da14cebeSEric Cheng {
479da14cebeSEric Cheng 	int rv;
480da14cebeSEric Cheng 
481da14cebeSEric Cheng 	mutex_enter(&vswp->mac_lock);
482da14cebeSEric Cheng 	WRITE_MACCL_ENTER(vswp, port, type);
483da14cebeSEric Cheng 	rv = vsw_maccl_open(vswp, port, type);
484da14cebeSEric Cheng 
485da14cebeSEric Cheng 	/* Release mac_lock now */
486da14cebeSEric Cheng 	mutex_exit(&vswp->mac_lock);
487da14cebeSEric Cheng 
488da14cebeSEric Cheng 	if (rv == 0) {
489da14cebeSEric Cheng 		(void) vsw_set_hw(vswp, port, type);
490da14cebeSEric Cheng 		vsw_mac_multicast_add_all(vswp, port, type);
491da14cebeSEric Cheng 	}
492da14cebeSEric Cheng 	RW_MACCL_EXIT(vswp, port, type);
493da14cebeSEric Cheng 	return (rv);
494da14cebeSEric Cheng }
495da14cebeSEric Cheng 
496da14cebeSEric Cheng /*
497da14cebeSEric Cheng  * Open a MAC client for a port or an interface.
498da14cebeSEric Cheng  * The flags and their purpose as below:
499da14cebeSEric Cheng  *
500da14cebeSEric Cheng  *	MAC_OPEN_FLAGS_SHARES_DESIRED -- This flag is used to indicate
501da14cebeSEric Cheng  *	that a port desires a Share. This will be the case with the
502da14cebeSEric Cheng  *	the ports that have hybrid mode enabled. This will only cause
503da14cebeSEric Cheng  *	MAC layer to allocate a share and corresponding resources
504*0dc2366fSVenugopal Iyer  *	ahead of time. Ports that are not HybridIO enabled are
505*0dc2366fSVenugopal Iyer  *	associated with default group & resources.
506da14cebeSEric Cheng  *
5074c91d6c6SVenugopal Iyer  *	MAC_UNICAST_TAG_DISABLE -- This flag is used for VLAN
508da14cebeSEric Cheng  *	support. It will cause MAC to not add any tags, but expect
509da14cebeSEric Cheng  *	vsw to tag the packets.
510da14cebeSEric Cheng  *
5114c91d6c6SVenugopal Iyer  *	MAC_UNICAST_STRIP_DISABLE -- This flag is used for VLAN
512da14cebeSEric Cheng  *	support. It will case the MAC layer to not strip the tags.
513da14cebeSEric Cheng  *	Vsw may have to strip the tag for pvid case.
514da14cebeSEric Cheng  */
515da14cebeSEric Cheng static int
516da14cebeSEric Cheng vsw_maccl_open(vsw_t *vswp, vsw_port_t *port, int type)
517da14cebeSEric Cheng {
518da14cebeSEric Cheng 	int		rv = 0;
519da14cebeSEric Cheng 	int		instance;
520da14cebeSEric Cheng 	char		mac_cl_name[MAXNAMELEN];
521da14cebeSEric Cheng 	const char	*dev_name;
522da14cebeSEric Cheng 	mac_client_handle_t *mchp;
523*0dc2366fSVenugopal Iyer 	uint64_t flags = 0;
524da14cebeSEric Cheng 
525da14cebeSEric Cheng 	ASSERT(MUTEX_HELD(&vswp->mac_lock));
526da14cebeSEric Cheng 	if (vswp->mh == NULL) {
527da14cebeSEric Cheng 		/*
528da14cebeSEric Cheng 		 * In case net-dev is changed (either set to nothing or
529da14cebeSEric Cheng 		 * using aggregation device), return success here as the
530da14cebeSEric Cheng 		 * timeout mechanism will handle it.
531da14cebeSEric Cheng 		 */
532da14cebeSEric Cheng 		return (0);
533da14cebeSEric Cheng 	}
534da14cebeSEric Cheng 
535da14cebeSEric Cheng 	mchp = (type == VSW_LOCALDEV) ? &vswp->mch : &port->p_mch;
536da14cebeSEric Cheng 	if (*mchp != NULL) {
537da14cebeSEric Cheng 		/* already open */
538da14cebeSEric Cheng 		return (0);
539da14cebeSEric Cheng 	}
540da14cebeSEric Cheng 	dev_name = ddi_driver_name(vswp->dip);
541da14cebeSEric Cheng 	instance = ddi_get_instance(vswp->dip);
542da14cebeSEric Cheng 	if (type == VSW_VNETPORT) {
543*0dc2366fSVenugopal Iyer 		if (port->p_hio_enabled)
544da14cebeSEric Cheng 			flags |= MAC_OPEN_FLAGS_SHARES_DESIRED;
545da14cebeSEric Cheng 		(void) snprintf(mac_cl_name, MAXNAMELEN, "%s%d%s%d", dev_name,
546da14cebeSEric Cheng 		    instance, "_port", port->p_instance);
547da14cebeSEric Cheng 	} else {
548da14cebeSEric Cheng 		(void) snprintf(mac_cl_name, MAXNAMELEN, "%s%s%d",
549da14cebeSEric Cheng 		    dev_name, "_if", instance);
550da14cebeSEric Cheng 	}
551da14cebeSEric Cheng 
552da14cebeSEric Cheng 	rv = mac_client_open(vswp->mh, mchp, mac_cl_name, flags);
553da14cebeSEric Cheng 	if (rv != 0) {
554da14cebeSEric Cheng 		cmn_err(CE_NOTE, "!vsw%d:%s mac_client_open() failed\n",
555da14cebeSEric Cheng 		    vswp->instance, mac_cl_name);
556da14cebeSEric Cheng 	}
557*0dc2366fSVenugopal Iyer 
558*0dc2366fSVenugopal Iyer 	if (type != VSW_VNETPORT || !port->p_hio_enabled)
559*0dc2366fSVenugopal Iyer 		mac_client_set_rings(*mchp, MAC_RXRINGS_NONE, MAC_TXRINGS_NONE);
560*0dc2366fSVenugopal Iyer 
561da14cebeSEric Cheng 	return (rv);
562da14cebeSEric Cheng }
563da14cebeSEric Cheng 
564da14cebeSEric Cheng /*
565da14cebeSEric Cheng  * Clean up by removing uncast, multicast addresses and
566da14cebeSEric Cheng  * closing the MAC client for a port or the interface.
567da14cebeSEric Cheng  */
568da14cebeSEric Cheng void
569da14cebeSEric Cheng vsw_mac_client_cleanup(vsw_t *vswp, vsw_port_t *port, int type)
570da14cebeSEric Cheng {
571da14cebeSEric Cheng 	WRITE_MACCL_ENTER(vswp, port, type);
5727c9e7ed0SWENTAO YANG 	vsw_mac_multicast_remove_all(vswp, port, type);
573da14cebeSEric Cheng 	vsw_unset_hw(vswp, port, type);
574da14cebeSEric Cheng 	vsw_maccl_close(vswp, port, type);
575da14cebeSEric Cheng 	RW_MACCL_EXIT(vswp, port, type);
576da14cebeSEric Cheng }
577da14cebeSEric Cheng 
578da14cebeSEric Cheng /*
579da14cebeSEric Cheng  * Close a MAC client for a port or an interface.
580da14cebeSEric Cheng  */
581da14cebeSEric Cheng static void
582da14cebeSEric Cheng vsw_maccl_close(vsw_t *vswp, vsw_port_t *port, int type)
583da14cebeSEric Cheng {
584da14cebeSEric Cheng 	mac_client_handle_t *mchp;
585da14cebeSEric Cheng 
586da14cebeSEric Cheng 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
587da14cebeSEric Cheng 
588da14cebeSEric Cheng 	mchp = (type == VSW_LOCALDEV) ? &vswp->mch : &port->p_mch;
589da14cebeSEric Cheng 	if (*mchp != NULL) {
590da14cebeSEric Cheng 		mac_client_close(*mchp, 0);
591da14cebeSEric Cheng 		*mchp = NULL;
5927b1f684aSSriharsha Basavapatna 	}
59306db247cSraghuram }
59406db247cSraghuram 
595da14cebeSEric Cheng /*
596da14cebeSEric Cheng  * Cleanup MAC client related stuff for all ports.
597da14cebeSEric Cheng  */
598da14cebeSEric Cheng void
599da14cebeSEric Cheng vsw_mac_cleanup_ports(vsw_t *vswp)
600da14cebeSEric Cheng {
601da14cebeSEric Cheng 	vsw_port_list_t		*plist = &vswp->plist;
602da14cebeSEric Cheng 	vsw_port_t		*port;
60306db247cSraghuram 
604da14cebeSEric Cheng 	READ_ENTER(&plist->lockrw);
605da14cebeSEric Cheng 	for (port = plist->head; port != NULL; port = port->p_next) {
606da14cebeSEric Cheng 		vsw_mac_client_cleanup(vswp, port, VSW_VNETPORT);
607da14cebeSEric Cheng 	}
608da14cebeSEric Cheng 	RW_EXIT(&plist->lockrw);
60906db247cSraghuram }
61006db247cSraghuram 
61106db247cSraghuram /*
61206db247cSraghuram  * Depending on the mode specified, the capabilites and capacity
61306db247cSraghuram  * of the underlying device setup the physical device.
61406db247cSraghuram  *
61506db247cSraghuram  * If in layer 3 mode, then do nothing.
61606db247cSraghuram  *
617da14cebeSEric Cheng  * If in layer 2 mode, open a mac client and program the mac-address
618da14cebeSEric Cheng  * and vlan-ids. The MAC layer will take care of programming
619da14cebeSEric Cheng  * the address into h/w or set the h/w into promiscuous mode.
62006db247cSraghuram  *
62106db247cSraghuram  * Returns 0 success, 1 on failure.
62206db247cSraghuram  */
62306db247cSraghuram int
62406db247cSraghuram vsw_set_hw(vsw_t *vswp, vsw_port_t *port, int type)
62506db247cSraghuram {
626da14cebeSEric Cheng 	int			err = 1;
62706db247cSraghuram 
62806db247cSraghuram 	D1(vswp, "%s: enter", __func__);
62906db247cSraghuram 
63006db247cSraghuram 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
63106db247cSraghuram 
632da14cebeSEric Cheng 	if (vswp->smode == VSW_LAYER3)
63306db247cSraghuram 		return (0);
63406db247cSraghuram 
63506db247cSraghuram 	if (type == VSW_VNETPORT) {
63606db247cSraghuram 		ASSERT(port != NULL);
637da14cebeSEric Cheng 		err = vsw_set_port_hw_addr(port);
63806db247cSraghuram 	} else {
639da14cebeSEric Cheng 		err = vsw_set_if_hw_addr(vswp);
64006db247cSraghuram 	}
64106db247cSraghuram 
64206db247cSraghuram 	D1(vswp, "%s: exit", __func__);
643da14cebeSEric Cheng 	return (err);
64406db247cSraghuram }
64506db247cSraghuram 
64606db247cSraghuram /*
64706db247cSraghuram  * If in layer 3 mode do nothing.
64806db247cSraghuram  *
64906db247cSraghuram  * If in layer 2 switched mode remove the address from the physical
65006db247cSraghuram  * device.
65106db247cSraghuram  *
65206db247cSraghuram  * If in layer 2 promiscuous mode disable promisc mode.
65306db247cSraghuram  *
65406db247cSraghuram  * Returns 0 on success.
65506db247cSraghuram  */
656da14cebeSEric Cheng void
65706db247cSraghuram vsw_unset_hw(vsw_t *vswp, vsw_port_t *port, int type)
65806db247cSraghuram {
659da14cebeSEric Cheng 	D1(vswp, "%s: enter", __func__);
660da14cebeSEric Cheng 
661da14cebeSEric Cheng 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
662da14cebeSEric Cheng 
663da14cebeSEric Cheng 	if (vswp->smode == VSW_LAYER3)
664da14cebeSEric Cheng 		return;
665da14cebeSEric Cheng 
666da14cebeSEric Cheng 	if (type == VSW_VNETPORT) {
667da14cebeSEric Cheng 		ASSERT(port != NULL);
668da14cebeSEric Cheng 		vsw_unset_hw_addr(vswp, port, type);
669da14cebeSEric Cheng 	} else {
670da14cebeSEric Cheng 		vsw_unset_hw_addr(vswp, NULL, type);
671da14cebeSEric Cheng 	}
672da14cebeSEric Cheng 
673da14cebeSEric Cheng 	D1(vswp, "%s: exit", __func__);
674da14cebeSEric Cheng }
675da14cebeSEric Cheng 
676da14cebeSEric Cheng /*
677da14cebeSEric Cheng  * Program the macaddress and vlans of a port.
678da14cebeSEric Cheng  *
679da14cebeSEric Cheng  * Returns 0 on sucess, 1 on failure.
680da14cebeSEric Cheng  */
681da14cebeSEric Cheng static int
682da14cebeSEric Cheng vsw_set_port_hw_addr(vsw_port_t *port)
683da14cebeSEric Cheng {
684da14cebeSEric Cheng 	vsw_t			*vswp = port->p_vswp;
685da14cebeSEric Cheng 	mac_diag_t		diag;
686da14cebeSEric Cheng 	uint8_t			*macaddr;
687da14cebeSEric Cheng 	uint16_t		vid = VLAN_ID_NONE;
68806db247cSraghuram 	int			rv;
6894c91d6c6SVenugopal Iyer 	uint16_t		mac_flags = MAC_UNICAST_TAG_DISABLE |
6904c91d6c6SVenugopal Iyer 	    MAC_UNICAST_STRIP_DISABLE;
69106db247cSraghuram 
69206db247cSraghuram 	D1(vswp, "%s: enter", __func__);
69306db247cSraghuram 
694da14cebeSEric Cheng 	ASSERT(RW_WRITE_HELD(&port->maccl_rwlock));
695da14cebeSEric Cheng 	if (port->p_mch == NULL)
69606db247cSraghuram 		return (0);
69706db247cSraghuram 
698da14cebeSEric Cheng 	/*
699da14cebeSEric Cheng 	 * If the port has a specific 'pvid', then
700da14cebeSEric Cheng 	 * register with that vlan-id, otherwise register
701da14cebeSEric Cheng 	 * with VLAN_ID_NONE.
702da14cebeSEric Cheng 	 */
703da14cebeSEric Cheng 	if (port->pvid != vswp->default_vlan_id) {
704da14cebeSEric Cheng 		vid = port->pvid;
705da14cebeSEric Cheng 	}
706da14cebeSEric Cheng 	macaddr = (uint8_t *)port->p_macaddr.ether_addr_octet;
70706db247cSraghuram 
708da14cebeSEric Cheng 	if (!(vswp->smode & VSW_LAYER2_PROMISC)) {
709da14cebeSEric Cheng 		mac_flags |= MAC_UNICAST_HW;
71006db247cSraghuram 	}
71106db247cSraghuram 
712da14cebeSEric Cheng 	if (port->addr_set == B_FALSE) {
713da14cebeSEric Cheng 		port->p_muh = NULL;
714da14cebeSEric Cheng 		rv = mac_unicast_add(port->p_mch, macaddr, mac_flags,
715da14cebeSEric Cheng 		    &port->p_muh, vid, &diag);
71606db247cSraghuram 
717da14cebeSEric Cheng 		if (rv != 0) {
718da14cebeSEric Cheng 			cmn_err(CE_WARN, "vsw%d: Failed to program"
719da14cebeSEric Cheng 			    "macaddr,vid(%s, %d) err=%d",
720da14cebeSEric Cheng 			    vswp->instance, ether_sprintf((void *)macaddr),
721da14cebeSEric Cheng 			    vid, rv);
722da14cebeSEric Cheng 			return (rv);
723da14cebeSEric Cheng 		}
724da14cebeSEric Cheng 		port->addr_set = B_TRUE;
72506db247cSraghuram 
726da14cebeSEric Cheng 		D2(vswp, "%s:programmed macaddr(%s) vid(%d) into device %s",
727da14cebeSEric Cheng 		    __func__, ether_sprintf((void *)macaddr), vid,
728da14cebeSEric Cheng 		    vswp->physname);
72906db247cSraghuram 	}
73006db247cSraghuram 
731da14cebeSEric Cheng 	/* Add vlans to the MAC layer */
732da14cebeSEric Cheng 	vsw_mac_add_vlans(vswp, port->p_mch, macaddr,
733da14cebeSEric Cheng 	    mac_flags, port->vids, port->nvids);
73406db247cSraghuram 
735bce0a86eSWENTAO YANG 	/* Configure bandwidth to the MAC layer */
736bce0a86eSWENTAO YANG 	vsw_maccl_set_bandwidth(NULL, port, VSW_VNETPORT, port->p_bandwidth);
737bce0a86eSWENTAO YANG 
738da14cebeSEric Cheng 	mac_rx_set(port->p_mch, vsw_port_rx_cb, (void *)port);
73906db247cSraghuram 
74006db247cSraghuram 	D1(vswp, "%s: exit", __func__);
74106db247cSraghuram 	return (rv);
74206db247cSraghuram }
74306db247cSraghuram 
74406db247cSraghuram /*
745da14cebeSEric Cheng  * Program the macaddress and vlans of a port.
74606db247cSraghuram  *
74706db247cSraghuram  * Returns 0 on sucess, 1 on failure.
74806db247cSraghuram  */
74906db247cSraghuram static int
750da14cebeSEric Cheng vsw_set_if_hw_addr(vsw_t *vswp)
75106db247cSraghuram {
752da14cebeSEric Cheng 	mac_diag_t		diag;
753da14cebeSEric Cheng 	uint8_t			*macaddr;
754da14cebeSEric Cheng 	uint8_t			primary_addr[ETHERADDRL];
755da14cebeSEric Cheng 	uint16_t		vid = VLAN_ID_NONE;
756da14cebeSEric Cheng 	int			rv;
7574c91d6c6SVenugopal Iyer 	uint16_t		mac_flags = MAC_UNICAST_TAG_DISABLE |
7584c91d6c6SVenugopal Iyer 	    MAC_UNICAST_STRIP_DISABLE;
75906db247cSraghuram 
76006db247cSraghuram 	D1(vswp, "%s: enter", __func__);
76106db247cSraghuram 
762da14cebeSEric Cheng 	ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock));
763da14cebeSEric Cheng 	if (vswp->mch == NULL)
764da14cebeSEric Cheng 		return (0);
76506db247cSraghuram 
766da14cebeSEric Cheng 	macaddr = (uint8_t *)vswp->if_addr.ether_addr_octet;
76706db247cSraghuram 
768da14cebeSEric Cheng 	/* check if it is the primary macaddr of the card. */
769da14cebeSEric Cheng 	mac_unicast_primary_get(vswp->mh, primary_addr);
770da14cebeSEric Cheng 	if (ether_cmp((void *)primary_addr, (void*)macaddr) == 0) {
771da14cebeSEric Cheng 		mac_flags |= MAC_UNICAST_PRIMARY;
772da14cebeSEric Cheng 	}
77306db247cSraghuram 
77406db247cSraghuram 	/*
775da14cebeSEric Cheng 	 * If the interface has a specific 'pvid', then
776da14cebeSEric Cheng 	 * register with that vlan-id, otherwise register
777da14cebeSEric Cheng 	 * with VLAN_ID_NONE.
77806db247cSraghuram 	 */
779da14cebeSEric Cheng 	if (vswp->pvid != vswp->default_vlan_id) {
780da14cebeSEric Cheng 		vid = vswp->pvid;
78106db247cSraghuram 	}
782da14cebeSEric Cheng 
783da14cebeSEric Cheng 	if (!(vswp->smode & VSW_LAYER2_PROMISC)) {
784da14cebeSEric Cheng 		mac_flags |= MAC_UNICAST_HW;
785da14cebeSEric Cheng 	}
786da14cebeSEric Cheng 
787da14cebeSEric Cheng 	if (vswp->addr_set == B_FALSE) {
788da14cebeSEric Cheng 		vswp->muh = NULL;
789da14cebeSEric Cheng 		rv = mac_unicast_add(vswp->mch, macaddr, mac_flags,
790da14cebeSEric Cheng 		    &vswp->muh, vid, &diag);
791da14cebeSEric Cheng 
792da14cebeSEric Cheng 		if (rv != 0) {
793da14cebeSEric Cheng 			cmn_err(CE_WARN, "vsw%d: Failed to program"
794da14cebeSEric Cheng 			    "macaddr,vid(%s, %d) err=%d",
795da14cebeSEric Cheng 			    vswp->instance, ether_sprintf((void *)macaddr),
796da14cebeSEric Cheng 			    vid, rv);
797da14cebeSEric Cheng 			return (rv);
798da14cebeSEric Cheng 		}
799da14cebeSEric Cheng 		vswp->addr_set = B_TRUE;
800da14cebeSEric Cheng 
801da14cebeSEric Cheng 		D2(vswp, "%s:programmed macaddr(%s) vid(%d) into device %s",
802da14cebeSEric Cheng 		    __func__, ether_sprintf((void *)macaddr), vid,
803da14cebeSEric Cheng 		    vswp->physname);
804da14cebeSEric Cheng 	}
805da14cebeSEric Cheng 
806da14cebeSEric Cheng 	vsw_mac_add_vlans(vswp, vswp->mch, macaddr, mac_flags,
807da14cebeSEric Cheng 	    vswp->vids, vswp->nvids);
808da14cebeSEric Cheng 
809bce0a86eSWENTAO YANG 	vsw_maccl_set_bandwidth(vswp, NULL, VSW_LOCALDEV, vswp->bandwidth);
810bce0a86eSWENTAO YANG 
811da14cebeSEric Cheng 	mac_rx_set(vswp->mch, vsw_if_rx_cb, (void *)vswp);
812da14cebeSEric Cheng 
81306db247cSraghuram 	D1(vswp, "%s: exit", __func__);
81406db247cSraghuram 	return (rv);
81506db247cSraghuram }
81606db247cSraghuram 
81706db247cSraghuram /*
81806db247cSraghuram  * Remove a unicast mac address which has previously been programmed
81906db247cSraghuram  * into HW.
82006db247cSraghuram  *
82106db247cSraghuram  * Returns 0 on sucess, 1 on failure.
82206db247cSraghuram  */
823da14cebeSEric Cheng static void
824da14cebeSEric Cheng vsw_unset_hw_addr(vsw_t *vswp, vsw_port_t *port, int type)
82506db247cSraghuram {
826da14cebeSEric Cheng 	vsw_vlanid_t		*vids;
827da14cebeSEric Cheng 	int			nvids;
828da14cebeSEric Cheng 	mac_client_handle_t	mch = NULL;
82906db247cSraghuram 
83006db247cSraghuram 	D1(vswp, "%s: enter", __func__);
83106db247cSraghuram 
83206db247cSraghuram 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
83306db247cSraghuram 
83406db247cSraghuram 	if (type == VSW_VNETPORT) {
83506db247cSraghuram 		ASSERT(port != NULL);
836da14cebeSEric Cheng 		ASSERT(RW_WRITE_HELD(&port->maccl_rwlock));
837da14cebeSEric Cheng 		vids = port->vids;
838da14cebeSEric Cheng 		nvids = port->nvids;
83906db247cSraghuram 	} else {
840da14cebeSEric Cheng 		ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock));
841da14cebeSEric Cheng 		vids = vswp->vids;
842da14cebeSEric Cheng 		nvids = vswp->nvids;
84306db247cSraghuram 	}
84406db247cSraghuram 
845da14cebeSEric Cheng 	/* First clear the callback */
846da14cebeSEric Cheng 	if (type == VSW_LOCALDEV) {
847da14cebeSEric Cheng 		mch = vswp->mch;
848da14cebeSEric Cheng 	} else if (type == VSW_VNETPORT) {
849da14cebeSEric Cheng 		mch = port->p_mch;
85006db247cSraghuram 	}
85106db247cSraghuram 
85206db247cSraghuram 
853da14cebeSEric Cheng 	if (mch == NULL) {
85406db247cSraghuram 		return;
85506db247cSraghuram 	}
85606db247cSraghuram 
857da14cebeSEric Cheng 	mac_rx_clear(mch);
85806db247cSraghuram 
859da14cebeSEric Cheng 	/* Remove vlans */
860da14cebeSEric Cheng 	vsw_mac_remove_vlans(mch, vids, nvids);
861da14cebeSEric Cheng 
862da14cebeSEric Cheng 	if ((type == VSW_LOCALDEV) && (vswp->addr_set == B_TRUE)) {
863da14cebeSEric Cheng 		(void) mac_unicast_remove(vswp->mch, vswp->muh);
864da14cebeSEric Cheng 		vswp->muh = NULL;
865da14cebeSEric Cheng 		D2(vswp, "removed vsw interface mac-addr from "
866da14cebeSEric Cheng 		    "the device %s", vswp->physname);
867da14cebeSEric Cheng 		vswp->addr_set = B_FALSE;
868da14cebeSEric Cheng 
869da14cebeSEric Cheng 	} else if ((type == VSW_VNETPORT) && (port->addr_set == B_TRUE)) {
870da14cebeSEric Cheng 		(void) mac_unicast_remove(port->p_mch, port->p_muh);
871da14cebeSEric Cheng 		port->p_muh = NULL;
872da14cebeSEric Cheng 		D2(vswp, "removed port(0x%p) mac-addr from "
873da14cebeSEric Cheng 		    "the device %s", port, vswp->physname);
874da14cebeSEric Cheng 		port->addr_set = B_FALSE;
87506db247cSraghuram 	}
87606db247cSraghuram 
87706db247cSraghuram 	D1(vswp, "%s: exit", __func__);
87806db247cSraghuram }
87906db247cSraghuram 
88006db247cSraghuram /*
881da14cebeSEric Cheng  * receive callback routine for vsw interface. Invoked by MAC layer when there
882da14cebeSEric Cheng  * are pkts being passed up from physical device for this vsw interface.
88306db247cSraghuram  */
884da14cebeSEric Cheng /* ARGSUSED */
88506db247cSraghuram static void
886da14cebeSEric Cheng vsw_if_rx_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
887da14cebeSEric Cheng     boolean_t loopback)
88806db247cSraghuram {
88906db247cSraghuram 	_NOTE(ARGUNUSED(mrh))
89006db247cSraghuram 
89106db247cSraghuram 	vsw_t		*vswp = (vsw_t *)arg;
892da14cebeSEric Cheng 	mblk_t		*mpt;
893da14cebeSEric Cheng 	int		count;
89406db247cSraghuram 
89506db247cSraghuram 	ASSERT(vswp != NULL);
89606db247cSraghuram 
897da14cebeSEric Cheng 	D1(vswp, "%s: enter", __func__);
89806db247cSraghuram 
899da14cebeSEric Cheng 	READ_ENTER(&vswp->if_lockrw);
900da14cebeSEric Cheng 	if (vswp->if_state & VSW_IF_UP) {
901da14cebeSEric Cheng 		RW_EXIT(&vswp->if_lockrw);
902da14cebeSEric Cheng 		count = vsw_vlan_frame_untag(vswp, VSW_LOCALDEV, &mp, &mpt);
903da14cebeSEric Cheng 		if (count != 0) {
904da14cebeSEric Cheng 			mac_rx(vswp->if_mh, NULL, mp);
905da14cebeSEric Cheng 		}
906da14cebeSEric Cheng 	} else {
907da14cebeSEric Cheng 		RW_EXIT(&vswp->if_lockrw);
908da14cebeSEric Cheng 		freemsgchain(mp);
909da14cebeSEric Cheng 	}
91006db247cSraghuram 
911da14cebeSEric Cheng 	D1(vswp, "%s: exit", __func__);
91206db247cSraghuram }
91306db247cSraghuram 
91406db247cSraghuram /*
915da14cebeSEric Cheng  * receive callback routine for port. Invoked by MAC layer when there
916da14cebeSEric Cheng  * are pkts being passed up from physical device for this port.
917da14cebeSEric Cheng  */
918da14cebeSEric Cheng /* ARGSUSED */
919da14cebeSEric Cheng static void
920da14cebeSEric Cheng vsw_port_rx_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp,
921da14cebeSEric Cheng     boolean_t loopback)
922da14cebeSEric Cheng {
923da14cebeSEric Cheng 	_NOTE(ARGUNUSED(mrh))
924da14cebeSEric Cheng 
925da14cebeSEric Cheng 	vsw_t		*vswp;
926da14cebeSEric Cheng 	vsw_port_t	*port = arg;
927da14cebeSEric Cheng 
928da14cebeSEric Cheng 	ASSERT(port != NULL);
929da14cebeSEric Cheng 
930da14cebeSEric Cheng 	vswp = port->p_vswp;
931da14cebeSEric Cheng 
932da14cebeSEric Cheng 	D1(vswp, "vsw_port_rx_cb: enter");
933da14cebeSEric Cheng 
934da14cebeSEric Cheng 	/*
935da14cebeSEric Cheng 	 * Send the packets to the peer directly.
936da14cebeSEric Cheng 	 */
937da14cebeSEric Cheng 	(void) vsw_portsend(port, mp);
938da14cebeSEric Cheng 
939da14cebeSEric Cheng 	D1(vswp, "vsw_port_rx_cb: exit");
940da14cebeSEric Cheng }
941da14cebeSEric Cheng 
942da14cebeSEric Cheng /*
943da14cebeSEric Cheng  * Send a message out over the physical device
944da14cebeSEric Cheng  * via the MAC layer.
94506db247cSraghuram  *
94606db247cSraghuram  * Returns any mblks that it was unable to transmit.
94706db247cSraghuram  */
94806db247cSraghuram mblk_t *
949da14cebeSEric Cheng vsw_tx_msg(vsw_t *vswp, mblk_t *mp, int caller, vsw_port_t *port)
95006db247cSraghuram {
951da14cebeSEric Cheng 	mac_client_handle_t	mch;
952da14cebeSEric Cheng 	mac_unicast_handle_t	muh;
95306db247cSraghuram 
954da14cebeSEric Cheng 	READ_MACCL_ENTER(vswp, port, caller);
95506db247cSraghuram 
956da14cebeSEric Cheng 	mch = (caller == VSW_LOCALDEV) ? vswp->mch : port->p_mch;
957da14cebeSEric Cheng 	muh = (caller == VSW_LOCALDEV) ? vswp->muh : port->p_muh;
958da14cebeSEric Cheng 
9596f09f0feSWENTAO YANG 	if (mch == NULL || muh == NULL) {
9606f09f0feSWENTAO YANG 		RW_MACCL_EXIT(vswp, port, caller);
9616f09f0feSWENTAO YANG 		return (mp);
96206db247cSraghuram 	}
96306db247cSraghuram 
9646f09f0feSWENTAO YANG 	/* packets are sent or dropped */
9656f09f0feSWENTAO YANG 	(void) mac_tx(mch, mp, 0, MAC_DROP_ON_NO_DESC, NULL);
966da14cebeSEric Cheng 	RW_MACCL_EXIT(vswp, port, caller);
967da14cebeSEric Cheng 	return (NULL);
968da14cebeSEric Cheng }
969da14cebeSEric Cheng 
970da14cebeSEric Cheng /*
971da14cebeSEric Cheng  * vsw_port_mac_reconfig -- Cleanup and close the MAC client
972da14cebeSEric Cheng  * and reopen and re-configure the MAC client with new flags etc.
973da14cebeSEric Cheng  * This function is useful for two different purposes:
974da14cebeSEric Cheng  *	1) To update the MAC client with new vlan-ids. This is done
975da14cebeSEric Cheng  *	   by freeing the existing vlan-ids and reopen with the new
976da14cebeSEric Cheng  *	   vlan-ids.
977da14cebeSEric Cheng  *
978da14cebeSEric Cheng  *	2) If the Hybrid mode status of a port changes, then the
979da14cebeSEric Cheng  *	   MAC client need to be closed and re-opened, otherwise,
980da14cebeSEric Cheng  *	   Share related resources may not be freed(hybird mode disabled)
981da14cebeSEric Cheng  *	   or assigned(hybrid mode enabled). To accomplish this,
982da14cebeSEric Cheng  *	   this function simply closes and reopens the MAC client.
983da14cebeSEric Cheng  *	   The reopen will result in using the flags based on the
984da14cebeSEric Cheng  *	   new hybrid mode of the port.
985da14cebeSEric Cheng  */
986da14cebeSEric Cheng void
987da14cebeSEric Cheng vsw_port_mac_reconfig(vsw_port_t *portp, boolean_t update_vlans,
988da14cebeSEric Cheng     uint16_t new_pvid, vsw_vlanid_t *new_vids, int new_nvids)
989da14cebeSEric Cheng {
990da14cebeSEric Cheng 	vsw_t *vswp = portp->p_vswp;
991da14cebeSEric Cheng 	int rv;
992da14cebeSEric Cheng 
993da14cebeSEric Cheng 	D1(vswp, "%s: enter", __func__);
994da14cebeSEric Cheng 	/*
995da14cebeSEric Cheng 	 * Remove the multi-cast addresses, unicast address
996da14cebeSEric Cheng 	 * and close the mac-client.
997da14cebeSEric Cheng 	 */
998da14cebeSEric Cheng 	mutex_enter(&vswp->mac_lock);
999da14cebeSEric Cheng 	WRITE_ENTER(&portp->maccl_rwlock);
1000da14cebeSEric Cheng 	vsw_mac_multicast_remove_all(vswp, portp, VSW_VNETPORT);
1001da14cebeSEric Cheng 	vsw_unset_hw(vswp, portp, VSW_VNETPORT);
1002da14cebeSEric Cheng 	vsw_maccl_close(vswp, portp, VSW_VNETPORT);
1003da14cebeSEric Cheng 
1004da14cebeSEric Cheng 	if (update_vlans == B_TRUE) {
1005da14cebeSEric Cheng 		if (portp->nvids != 0) {
1006da14cebeSEric Cheng 			kmem_free(portp->vids,
1007da14cebeSEric Cheng 			    sizeof (vsw_vlanid_t) * portp->nvids);
1008da14cebeSEric Cheng 			portp->vids = NULL;
1009da14cebeSEric Cheng 			portp->nvids = 0;
1010da14cebeSEric Cheng 		}
1011da14cebeSEric Cheng 		portp->vids = new_vids;
1012da14cebeSEric Cheng 		portp->nvids = new_nvids;
1013da14cebeSEric Cheng 		portp->pvid = new_pvid;
1014da14cebeSEric Cheng 	}
1015da14cebeSEric Cheng 
1016da14cebeSEric Cheng 	/*
1017da14cebeSEric Cheng 	 * Now re-open the mac-client and
1018da14cebeSEric Cheng 	 * configure unicast addr and multicast addrs.
1019da14cebeSEric Cheng 	 */
1020da14cebeSEric Cheng 	rv = vsw_maccl_open(vswp, portp, VSW_VNETPORT);
1021da14cebeSEric Cheng 	if (rv != 0) {
1022da14cebeSEric Cheng 		goto recret;
1023da14cebeSEric Cheng 	}
1024da14cebeSEric Cheng 
1025da14cebeSEric Cheng 	if (vsw_set_hw(vswp, portp, VSW_VNETPORT)) {
1026da14cebeSEric Cheng 		cmn_err(CE_NOTE, "!vsw%d: port:%d failed to "
1027da14cebeSEric Cheng 		    "set unicast address\n", vswp->instance, portp->p_instance);
1028da14cebeSEric Cheng 		goto recret;
1029da14cebeSEric Cheng 	}
1030da14cebeSEric Cheng 
1031da14cebeSEric Cheng 	vsw_mac_multicast_add_all(vswp, portp, VSW_VNETPORT);
1032da14cebeSEric Cheng 
1033da14cebeSEric Cheng recret:
1034da14cebeSEric Cheng 	RW_EXIT(&portp->maccl_rwlock);
1035da14cebeSEric Cheng 	mutex_exit(&vswp->mac_lock);
1036da14cebeSEric Cheng 	D1(vswp, "%s: exit", __func__);
1037da14cebeSEric Cheng }
1038da14cebeSEric Cheng 
1039da14cebeSEric Cheng /*
1040da14cebeSEric Cheng  * vsw_if_mac_reconfig -- Reconfigure the vsw interfaace's mac-client
1041da14cebeSEric Cheng  * by closing and re-opening it. This function is used handle the
1042da14cebeSEric Cheng  * following two cases:
1043da14cebeSEric Cheng  *
1044da14cebeSEric Cheng  *	1) Handle the MAC address change for the interface.
1045da14cebeSEric Cheng  *	2) Handle vlan update.
1046da14cebeSEric Cheng  */
1047da14cebeSEric Cheng void
1048da14cebeSEric Cheng vsw_if_mac_reconfig(vsw_t *vswp, boolean_t update_vlans,
1049da14cebeSEric Cheng     uint16_t new_pvid, vsw_vlanid_t *new_vids, int new_nvids)
1050da14cebeSEric Cheng {
1051da14cebeSEric Cheng 	int rv;
1052da14cebeSEric Cheng 
1053da14cebeSEric Cheng 	D1(vswp, "%s: enter", __func__);
1054da14cebeSEric Cheng 	/*
1055da14cebeSEric Cheng 	 * Remove the multi-cast addresses, unicast address
1056da14cebeSEric Cheng 	 * and close the mac-client.
1057da14cebeSEric Cheng 	 */
1058da14cebeSEric Cheng 	mutex_enter(&vswp->mac_lock);
1059da14cebeSEric Cheng 	WRITE_ENTER(&vswp->maccl_rwlock);
1060da14cebeSEric Cheng 	vsw_mac_multicast_remove_all(vswp, NULL, VSW_LOCALDEV);
1061da14cebeSEric Cheng 	vsw_unset_hw(vswp, NULL, VSW_LOCALDEV);
1062da14cebeSEric Cheng 	vsw_maccl_close(vswp, NULL, VSW_LOCALDEV);
1063da14cebeSEric Cheng 
1064da14cebeSEric Cheng 	if (update_vlans == B_TRUE) {
1065da14cebeSEric Cheng 		if (vswp->nvids != 0) {
1066da14cebeSEric Cheng 			kmem_free(vswp->vids,
1067da14cebeSEric Cheng 			    sizeof (vsw_vlanid_t) * vswp->nvids);
1068da14cebeSEric Cheng 			vswp->vids = NULL;
1069da14cebeSEric Cheng 			vswp->nvids = 0;
1070da14cebeSEric Cheng 		}
1071da14cebeSEric Cheng 		vswp->vids = new_vids;
1072da14cebeSEric Cheng 		vswp->nvids = new_nvids;
1073da14cebeSEric Cheng 		vswp->pvid = new_pvid;
1074da14cebeSEric Cheng 	}
1075da14cebeSEric Cheng 
1076da14cebeSEric Cheng 	/*
1077da14cebeSEric Cheng 	 * Now re-open the mac-client and
1078da14cebeSEric Cheng 	 * configure unicast addr and multicast addrs.
1079da14cebeSEric Cheng 	 */
1080da14cebeSEric Cheng 	rv = vsw_maccl_open(vswp, NULL, VSW_LOCALDEV);
1081da14cebeSEric Cheng 	if (rv != 0) {
1082da14cebeSEric Cheng 		goto ifrecret;
1083da14cebeSEric Cheng 	}
1084da14cebeSEric Cheng 
1085da14cebeSEric Cheng 	if (vsw_set_hw(vswp, NULL, VSW_LOCALDEV)) {
1086da14cebeSEric Cheng 		cmn_err(CE_NOTE, "!vsw%d:failed to set unicast address\n",
1087da14cebeSEric Cheng 		    vswp->instance);
1088da14cebeSEric Cheng 		goto ifrecret;
1089da14cebeSEric Cheng 	}
1090da14cebeSEric Cheng 
1091da14cebeSEric Cheng 	vsw_mac_multicast_add_all(vswp, NULL, VSW_LOCALDEV);
1092da14cebeSEric Cheng 
1093da14cebeSEric Cheng ifrecret:
1094da14cebeSEric Cheng 	RW_EXIT(&vswp->maccl_rwlock);
1095da14cebeSEric Cheng 	mutex_exit(&vswp->mac_lock);
1096da14cebeSEric Cheng 	D1(vswp, "%s: exit", __func__);
1097da14cebeSEric Cheng }
1098da14cebeSEric Cheng 
1099da14cebeSEric Cheng /*
1100da14cebeSEric Cheng  * vsw_mac_port_reconfig_vlans -- Reconfigure a port to handle
1101da14cebeSEric Cheng  * vlan configuration update. As the removal of the last unicast-address,vid
1102da14cebeSEric Cheng  * from the MAC client results in releasing all resources, it expects
1103da14cebeSEric Cheng  * no Shares to be associated with such MAC client.
1104da14cebeSEric Cheng  *
1105da14cebeSEric Cheng  * To handle vlan configuration update for a port that already has
1106da14cebeSEric Cheng  * a Share bound, then we need to free that share prior to reconfiguration.
1107da14cebeSEric Cheng  * Initiate the hybrdIO setup again after the completion of reconfiguration.
1108da14cebeSEric Cheng  */
1109da14cebeSEric Cheng void
1110da14cebeSEric Cheng vsw_mac_port_reconfig_vlans(vsw_port_t *portp, uint16_t new_pvid,
1111da14cebeSEric Cheng     vsw_vlanid_t *new_vids, int new_nvids)
1112da14cebeSEric Cheng {
1113da14cebeSEric Cheng 	/*
1114da14cebeSEric Cheng 	 * As the reconfiguration involves the close of
1115da14cebeSEric Cheng 	 * mac client, cleanup HybridIO and later restart
1116da14cebeSEric Cheng 	 * HybridIO setup again.
1117da14cebeSEric Cheng 	 */
1118da14cebeSEric Cheng 	if (portp->p_hio_enabled == B_TRUE) {
1119da14cebeSEric Cheng 		vsw_hio_stop_port(portp);
1120da14cebeSEric Cheng 	}
1121da14cebeSEric Cheng 	vsw_port_mac_reconfig(portp, B_TRUE, new_pvid, new_vids, new_nvids);
1122da14cebeSEric Cheng 	if (portp->p_hio_enabled == B_TRUE) {
1123da14cebeSEric Cheng 		/* reset to setup the HybridIO again. */
1124da14cebeSEric Cheng 		vsw_hio_port_reset(portp, B_FALSE);
1125da14cebeSEric Cheng 	}
1126da14cebeSEric Cheng }
1127da14cebeSEric Cheng 
1128da14cebeSEric Cheng /* Add vlans to MAC client */
1129da14cebeSEric Cheng static void
1130da14cebeSEric Cheng vsw_mac_add_vlans(vsw_t *vswp, mac_client_handle_t mch, uint8_t *macaddr,
1131da14cebeSEric Cheng     uint16_t flags, vsw_vlanid_t *vids, int nvids)
1132da14cebeSEric Cheng {
1133da14cebeSEric Cheng 	vsw_vlanid_t	*vidp;
1134da14cebeSEric Cheng 	mac_diag_t	diag;
1135da14cebeSEric Cheng 	int		rv;
1136da14cebeSEric Cheng 	int		i;
1137da14cebeSEric Cheng 
11384c91d6c6SVenugopal Iyer 	flags |= MAC_UNICAST_TAG_DISABLE | MAC_UNICAST_STRIP_DISABLE;
11394c91d6c6SVenugopal Iyer 
1140da14cebeSEric Cheng 	/* Add vlans to the MAC layer */
1141da14cebeSEric Cheng 	for (i = 0; i < nvids; i++) {
1142da14cebeSEric Cheng 		vidp = &vids[i];
1143da14cebeSEric Cheng 
1144da14cebeSEric Cheng 		if (vidp->vl_set == B_TRUE) {
1145da14cebeSEric Cheng 			continue;
1146da14cebeSEric Cheng 		}
1147da14cebeSEric Cheng 
1148da14cebeSEric Cheng 		rv = mac_unicast_add(mch, macaddr, flags,
1149da14cebeSEric Cheng 		    &vidp->vl_muh, vidp->vl_vid, &diag);
1150da14cebeSEric Cheng 		if (rv != 0) {
1151da14cebeSEric Cheng 			cmn_err(CE_WARN, "vsw%d: Failed to program"
1152da14cebeSEric Cheng 			    "macaddr,vid(%s, %d) err=%d",
1153da14cebeSEric Cheng 			    vswp->instance, ether_sprintf((void *)macaddr),
1154da14cebeSEric Cheng 			    vidp->vl_vid, rv);
1155da14cebeSEric Cheng 		} else {
1156da14cebeSEric Cheng 			vidp->vl_set = B_TRUE;
1157da14cebeSEric Cheng 			D2(vswp, "%s:programmed macaddr(%s) vid(%d) "
1158da14cebeSEric Cheng 			    "into device %s", __func__,
1159da14cebeSEric Cheng 			    ether_sprintf((void *)macaddr),
1160da14cebeSEric Cheng 			    vidp->vl_vid, vswp->physname);
1161da14cebeSEric Cheng 		}
1162da14cebeSEric Cheng 	}
1163da14cebeSEric Cheng }
1164da14cebeSEric Cheng 
1165da14cebeSEric Cheng /* Remove vlans from the MAC client */
1166da14cebeSEric Cheng static void
1167da14cebeSEric Cheng vsw_mac_remove_vlans(mac_client_handle_t mch, vsw_vlanid_t *vids, int nvids)
1168da14cebeSEric Cheng {
1169da14cebeSEric Cheng 	int i;
1170da14cebeSEric Cheng 	vsw_vlanid_t *vidp;
1171da14cebeSEric Cheng 
1172da14cebeSEric Cheng 	for (i = 0; i < nvids; i++) {
1173da14cebeSEric Cheng 		vidp = &vids[i];
1174da14cebeSEric Cheng 		if (vidp->vl_set == B_FALSE) {
1175da14cebeSEric Cheng 			continue;
1176da14cebeSEric Cheng 		}
117707d06da5SSurya Prakki 		(void) mac_unicast_remove(mch, vidp->vl_muh);
1178da14cebeSEric Cheng 		vidp->vl_set = B_FALSE;
1179da14cebeSEric Cheng 	}
118006db247cSraghuram }
118151aa9d07Ssb155480 
118251aa9d07Ssb155480 #define	ARH_FIXED_LEN	8    /* Length of fixed part of ARP header(see arp.h) */
118351aa9d07Ssb155480 
118451aa9d07Ssb155480 /*
118551aa9d07Ssb155480  * Send a gratuitous RARP packet to notify the physical switch to update its
118651aa9d07Ssb155480  * Layer2 forwarding table for the given mac address. This is done to allow the
118751aa9d07Ssb155480  * switch to quickly learn the macaddr-port association when a guest is live
118851aa9d07Ssb155480  * migrated or when vsw's physical device is changed dynamically. Any protocol
118951aa9d07Ssb155480  * packet would serve this purpose, but we choose RARP, as it allows us to
119051aa9d07Ssb155480  * accomplish this within L2 (ie, no need to specify IP addr etc in the packet)
119151aa9d07Ssb155480  * The macaddr of vnet is retained across migration. Hence, we don't need to
119251aa9d07Ssb155480  * update the arp cache of other hosts within the broadcast domain. Note that
119351aa9d07Ssb155480  * it is harmless to send these RARP packets during normal port attach of a
119451aa9d07Ssb155480  * client vnet. This can can be turned off if needed, by setting
119551aa9d07Ssb155480  * vsw_publish_macaddr_count to zero in /etc/system.
119651aa9d07Ssb155480  */
119751aa9d07Ssb155480 void
1198da14cebeSEric Cheng vsw_publish_macaddr(vsw_t *vswp, vsw_port_t *portp)
119951aa9d07Ssb155480 {
120051aa9d07Ssb155480 	mblk_t			*mp;
120151aa9d07Ssb155480 	mblk_t			*bp;
120251aa9d07Ssb155480 	struct arphdr		*arh;
120351aa9d07Ssb155480 	struct	ether_header 	*ehp;
120451aa9d07Ssb155480 	int			count = 0;
120551aa9d07Ssb155480 	int			plen = 4;
120651aa9d07Ssb155480 	uint8_t			*cp;
120751aa9d07Ssb155480 
120851aa9d07Ssb155480 	mp = allocb(ETHERMIN, BPRI_MED);
120951aa9d07Ssb155480 	if (mp == NULL) {
121051aa9d07Ssb155480 		return;
121151aa9d07Ssb155480 	}
121251aa9d07Ssb155480 
121351aa9d07Ssb155480 	/* Initialize eth header */
121451aa9d07Ssb155480 	ehp = (struct  ether_header *)mp->b_rptr;
121551aa9d07Ssb155480 	bcopy(&etherbroadcastaddr, &ehp->ether_dhost, ETHERADDRL);
1216da14cebeSEric Cheng 	bcopy(&portp->p_macaddr, &ehp->ether_shost, ETHERADDRL);
121751aa9d07Ssb155480 	ehp->ether_type = htons(ETHERTYPE_REVARP);
121851aa9d07Ssb155480 
121951aa9d07Ssb155480 	/* Initialize arp packet */
122051aa9d07Ssb155480 	arh = (struct arphdr *)(mp->b_rptr + sizeof (struct ether_header));
122151aa9d07Ssb155480 	cp = (uint8_t *)arh;
122251aa9d07Ssb155480 
122351aa9d07Ssb155480 	arh->ar_hrd = htons(ARPHRD_ETHER);	/* Hardware type:  ethernet */
122451aa9d07Ssb155480 	arh->ar_pro = htons(ETHERTYPE_IP);	/* Protocol type:  IP */
122551aa9d07Ssb155480 	arh->ar_hln = ETHERADDRL;	/* Length of hardware address:  6 */
122651aa9d07Ssb155480 	arh->ar_pln = plen;		/* Length of protocol address:  4 */
122751aa9d07Ssb155480 	arh->ar_op = htons(REVARP_REQUEST);	/* Opcode: REVARP Request */
122851aa9d07Ssb155480 
122951aa9d07Ssb155480 	cp += ARH_FIXED_LEN;
123051aa9d07Ssb155480 
123151aa9d07Ssb155480 	/* Sender's hardware address and protocol address */
1232da14cebeSEric Cheng 	bcopy(&portp->p_macaddr, cp, ETHERADDRL);
123351aa9d07Ssb155480 	cp += ETHERADDRL;
123451aa9d07Ssb155480 	bzero(cp, plen);	/* INADDR_ANY */
123551aa9d07Ssb155480 	cp += plen;
123651aa9d07Ssb155480 
123751aa9d07Ssb155480 	/* Target hardware address and protocol address */
1238da14cebeSEric Cheng 	bcopy(&portp->p_macaddr, cp, ETHERADDRL);
123951aa9d07Ssb155480 	cp += ETHERADDRL;
124051aa9d07Ssb155480 	bzero(cp, plen);	/* INADDR_ANY */
124151aa9d07Ssb155480 	cp += plen;
124251aa9d07Ssb155480 
124351aa9d07Ssb155480 	mp->b_wptr += ETHERMIN;	/* total size is 42; round up to ETHERMIN */
124451aa9d07Ssb155480 
124551aa9d07Ssb155480 	for (count = 0; count < vsw_publish_macaddr_count; count++) {
124651aa9d07Ssb155480 
124751aa9d07Ssb155480 		bp = dupmsg(mp);
124851aa9d07Ssb155480 		if (bp == NULL) {
124951aa9d07Ssb155480 			continue;
125051aa9d07Ssb155480 		}
125151aa9d07Ssb155480 
125251aa9d07Ssb155480 		/* transmit the packet */
1253da14cebeSEric Cheng 		bp = vsw_tx_msg(vswp, bp, VSW_VNETPORT, portp);
125451aa9d07Ssb155480 		if (bp != NULL) {
125551aa9d07Ssb155480 			freemsg(bp);
125651aa9d07Ssb155480 		}
125751aa9d07Ssb155480 	}
125851aa9d07Ssb155480 
125951aa9d07Ssb155480 	freemsg(mp);
126051aa9d07Ssb155480 }
12617b1f684aSSriharsha Basavapatna 
12627b1f684aSSriharsha Basavapatna static void
12637b1f684aSSriharsha Basavapatna vsw_mac_set_mtu(vsw_t *vswp, uint32_t mtu)
12647b1f684aSSriharsha Basavapatna {
1265da14cebeSEric Cheng 	uint_t	mtu_orig;
12667b1f684aSSriharsha Basavapatna 	int	rv;
12677b1f684aSSriharsha Basavapatna 
1268da14cebeSEric Cheng 	rv = mac_set_mtu(vswp->mh, mtu, &mtu_orig);
12697b1f684aSSriharsha Basavapatna 	if (rv != 0) {
12707b1f684aSSriharsha Basavapatna 		cmn_err(CE_NOTE,
12717b1f684aSSriharsha Basavapatna 		    "!vsw%d: Unable to set the mtu:%d, in the "
12727b1f684aSSriharsha Basavapatna 		    "physical device:%s\n",
12737b1f684aSSriharsha Basavapatna 		    vswp->instance, mtu, vswp->physname);
1274da14cebeSEric Cheng 		return;
12757b1f684aSSriharsha Basavapatna 	}
1276da14cebeSEric Cheng 
1277da14cebeSEric Cheng 	/* save the original mtu of physdev to reset it back later if needed */
1278da14cebeSEric Cheng 	vswp->mtu_physdev_orig = mtu_orig;
12797b1f684aSSriharsha Basavapatna }
12801107ea93SSriharsha Basavapatna 
12811107ea93SSriharsha Basavapatna /*
12821107ea93SSriharsha Basavapatna  * Register a callback with underlying mac layer for notifications.
12831107ea93SSriharsha Basavapatna  * We are currently interested in only link-state events.
12841107ea93SSriharsha Basavapatna  */
12851107ea93SSriharsha Basavapatna static int
12861107ea93SSriharsha Basavapatna vsw_notify_add(vsw_t *vswp)
12871107ea93SSriharsha Basavapatna {
12881107ea93SSriharsha Basavapatna 	mac_notify_handle_t	mnh;
12891107ea93SSriharsha Basavapatna 	uint32_t		note;
12901107ea93SSriharsha Basavapatna 
12911107ea93SSriharsha Basavapatna 	/*
12921107ea93SSriharsha Basavapatna 	 * Check if the underlying MAC supports link update notification.
12931107ea93SSriharsha Basavapatna 	 */
12941107ea93SSriharsha Basavapatna 	note = mac_no_notification(vswp->mh);
12951107ea93SSriharsha Basavapatna 	if ((note & (DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN)) != 0) {
12961107ea93SSriharsha Basavapatna 		vswp->phys_no_link_update = B_TRUE;
12971107ea93SSriharsha Basavapatna 	} else {
12981107ea93SSriharsha Basavapatna 		vswp->phys_no_link_update = B_FALSE;
12991107ea93SSriharsha Basavapatna 	}
13001107ea93SSriharsha Basavapatna 
13011107ea93SSriharsha Basavapatna 	/*
13021107ea93SSriharsha Basavapatna 	 * Read the current link state of the device and cache it.
13031107ea93SSriharsha Basavapatna 	 */
13041107ea93SSriharsha Basavapatna 	vswp->phys_link_state = vswp->phys_no_link_update ? LINK_STATE_UP :
13051107ea93SSriharsha Basavapatna 	    mac_stat_get(vswp->mh, MAC_STAT_LINK_STATE);
13061107ea93SSriharsha Basavapatna 
13071107ea93SSriharsha Basavapatna 	/*
13081107ea93SSriharsha Basavapatna 	 * Add notify callback function, if link update is supported.
13091107ea93SSriharsha Basavapatna 	 */
13101107ea93SSriharsha Basavapatna 	if (vswp->phys_no_link_update == B_TRUE) {
13111107ea93SSriharsha Basavapatna 		return (0);
13121107ea93SSriharsha Basavapatna 	}
13131107ea93SSriharsha Basavapatna 
13141107ea93SSriharsha Basavapatna 	mnh = mac_notify_add(vswp->mh, vsw_notify_cb, vswp);
13151107ea93SSriharsha Basavapatna 	if (mnh == 0) {
13161107ea93SSriharsha Basavapatna 		/* failed */
13171107ea93SSriharsha Basavapatna 		return (1);
13181107ea93SSriharsha Basavapatna 	}
13191107ea93SSriharsha Basavapatna 
13201107ea93SSriharsha Basavapatna 	vswp->mnh = mnh;
13211107ea93SSriharsha Basavapatna 	return (0);
13221107ea93SSriharsha Basavapatna }
13231107ea93SSriharsha Basavapatna 
13241107ea93SSriharsha Basavapatna /*
13251107ea93SSriharsha Basavapatna  * Remove notify callback.
13261107ea93SSriharsha Basavapatna  */
13271107ea93SSriharsha Basavapatna static int
13281107ea93SSriharsha Basavapatna vsw_notify_rem(vsw_t *vswp)
13291107ea93SSriharsha Basavapatna {
13301107ea93SSriharsha Basavapatna 	int	rv;
13311107ea93SSriharsha Basavapatna 
13321107ea93SSriharsha Basavapatna 	rv = mac_notify_remove(vswp->mnh, B_FALSE);
13331107ea93SSriharsha Basavapatna 	return (rv);
13341107ea93SSriharsha Basavapatna }
13351107ea93SSriharsha Basavapatna 
13361107ea93SSriharsha Basavapatna /*
13371107ea93SSriharsha Basavapatna  * Notification callback invoked by the MAC service
13381107ea93SSriharsha Basavapatna  * module. Note that we process only link state updates.
13391107ea93SSriharsha Basavapatna  */
13401107ea93SSriharsha Basavapatna static void
13411107ea93SSriharsha Basavapatna vsw_notify_cb(void *arg, mac_notify_type_t type)
13421107ea93SSriharsha Basavapatna {
13431107ea93SSriharsha Basavapatna 	vsw_t	*vswp = arg;
13441107ea93SSriharsha Basavapatna 
13451107ea93SSriharsha Basavapatna 	switch (type) {
13461107ea93SSriharsha Basavapatna 
13471107ea93SSriharsha Basavapatna 	case MAC_NOTE_LINK:
13481107ea93SSriharsha Basavapatna 		vsw_notify_link(vswp);
13491107ea93SSriharsha Basavapatna 		break;
13501107ea93SSriharsha Basavapatna 
13511107ea93SSriharsha Basavapatna 	default:
13521107ea93SSriharsha Basavapatna 		break;
13531107ea93SSriharsha Basavapatna 
13541107ea93SSriharsha Basavapatna 	}
13551107ea93SSriharsha Basavapatna }
13561107ea93SSriharsha Basavapatna 
13571107ea93SSriharsha Basavapatna /*
13581107ea93SSriharsha Basavapatna  * Invoked upon receiving a MAC_NOTE_LINK
13591107ea93SSriharsha Basavapatna  * notification for the underlying physical device.
13601107ea93SSriharsha Basavapatna  */
13611107ea93SSriharsha Basavapatna static void
13621107ea93SSriharsha Basavapatna vsw_notify_link(vsw_t *vswp)
13631107ea93SSriharsha Basavapatna {
13641107ea93SSriharsha Basavapatna 	link_state_t	link_state;
13651107ea93SSriharsha Basavapatna 
13661107ea93SSriharsha Basavapatna 	/* link state change  notification */
13671107ea93SSriharsha Basavapatna 	link_state = mac_stat_get(vswp->mh, MAC_STAT_LINK_STATE);
13681107ea93SSriharsha Basavapatna 
13691107ea93SSriharsha Basavapatna 	if (vswp->phys_link_state != link_state) {
13701107ea93SSriharsha Basavapatna 		D3(vswp, "%s: phys_link_state(%d)\n",
13711107ea93SSriharsha Basavapatna 		    __func__, vswp->phys_link_state);
13721107ea93SSriharsha Basavapatna 
13731107ea93SSriharsha Basavapatna 		vswp->phys_link_state = link_state;
13741107ea93SSriharsha Basavapatna 		vsw_physlink_state_update(vswp);
13751107ea93SSriharsha Basavapatna 	}
13761107ea93SSriharsha Basavapatna }
1377bce0a86eSWENTAO YANG 
1378bce0a86eSWENTAO YANG /*
1379bce0a86eSWENTAO YANG  * Configure the bandwidth limit on the vsw or vnet devices via the MAC layer.
1380bce0a86eSWENTAO YANG  * Note that bandwidth limit is not supported on a HybridIO enabled
1381bce0a86eSWENTAO YANG  * vnet, as the HybridIO assigns a specific unit of hardware resource
1382bce0a86eSWENTAO YANG  * that cannot be changed to limit bandwidth.
1383bce0a86eSWENTAO YANG  */
1384bce0a86eSWENTAO YANG static void
1385bce0a86eSWENTAO YANG vsw_maccl_set_bandwidth(vsw_t *vswp, vsw_port_t *port, int type, uint64_t maxbw)
1386bce0a86eSWENTAO YANG {
1387bce0a86eSWENTAO YANG 	int			rv = 0;
1388bce0a86eSWENTAO YANG 	uint64_t		*bw;
1389*0dc2366fSVenugopal Iyer 	mac_resource_props_t	*mrp;
1390bce0a86eSWENTAO YANG 	mac_client_handle_t	mch;
1391bce0a86eSWENTAO YANG 
1392bce0a86eSWENTAO YANG 	ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT));
1393bce0a86eSWENTAO YANG 
1394bce0a86eSWENTAO YANG 	if (type == VSW_VNETPORT) {
1395bce0a86eSWENTAO YANG 		ASSERT(RW_WRITE_HELD(&port->maccl_rwlock));
1396bce0a86eSWENTAO YANG 		mch = port->p_mch;
1397bce0a86eSWENTAO YANG 		bw = &port->p_bandwidth;
1398bce0a86eSWENTAO YANG 	} else {
1399bce0a86eSWENTAO YANG 		ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock));
1400bce0a86eSWENTAO YANG 		mch = vswp->mch;
1401bce0a86eSWENTAO YANG 		bw = &vswp->bandwidth;
1402bce0a86eSWENTAO YANG 	}
1403bce0a86eSWENTAO YANG 
1404bce0a86eSWENTAO YANG 	if (mch == NULL) {
1405bce0a86eSWENTAO YANG 		return;
1406bce0a86eSWENTAO YANG 	}
1407bce0a86eSWENTAO YANG 
1408bce0a86eSWENTAO YANG 	if (maxbw >= MRP_MAXBW_MINVAL || maxbw == 0) {
1409*0dc2366fSVenugopal Iyer 		mrp = kmem_zalloc(sizeof (*mrp), KM_SLEEP);
1410bce0a86eSWENTAO YANG 		if (maxbw == 0) {
1411*0dc2366fSVenugopal Iyer 			mrp->mrp_maxbw = MRP_MAXBW_RESETVAL;
1412bce0a86eSWENTAO YANG 		} else {
1413*0dc2366fSVenugopal Iyer 			mrp->mrp_maxbw = maxbw;
1414bce0a86eSWENTAO YANG 		}
1415*0dc2366fSVenugopal Iyer 		mrp->mrp_mask |= MRP_MAXBW;
1416bce0a86eSWENTAO YANG 
1417*0dc2366fSVenugopal Iyer 		rv = mac_client_set_resources(mch, mrp);
1418bce0a86eSWENTAO YANG 		if (rv != 0) {
1419bce0a86eSWENTAO YANG 			if (type == VSW_VNETPORT) {
1420bce0a86eSWENTAO YANG 				cmn_err(CE_NOTE, "!port%d: cannot set "
1421bce0a86eSWENTAO YANG 				    "bandwidth limit to (%ld), error(%d)\n",
1422bce0a86eSWENTAO YANG 				    port->p_instance, maxbw, rv);
1423bce0a86eSWENTAO YANG 			} else {
1424bce0a86eSWENTAO YANG 				cmn_err(CE_NOTE, "!vsw%d: cannot set "
1425bce0a86eSWENTAO YANG 				    "bandwidth limit to (%ld), error(%d)\n",
1426bce0a86eSWENTAO YANG 				    vswp->instance, maxbw, rv);
1427bce0a86eSWENTAO YANG 			}
1428bce0a86eSWENTAO YANG 		} else {
1429bce0a86eSWENTAO YANG 			/*
1430bce0a86eSWENTAO YANG 			 * update with successfully configured bandwidth.
1431bce0a86eSWENTAO YANG 			 */
1432bce0a86eSWENTAO YANG 			*bw = maxbw;
1433bce0a86eSWENTAO YANG 		}
1434*0dc2366fSVenugopal Iyer 		kmem_free(mrp, sizeof (*mrp));
1435bce0a86eSWENTAO YANG 	}
1436bce0a86eSWENTAO YANG }
1437