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
vsw_set_addrs(vsw_t * vswp)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
vsw_unset_addrs(vsw_t * vswp)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
vsw_mac_open(vsw_t * vswp)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
vsw_mac_close(vsw_t * vswp)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
vsw_mac_multicast_add(vsw_t * vswp,vsw_port_t * port,mcst_addr_t * mcst_p,int type)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
vsw_mac_multicast_remove(vsw_t * vswp,vsw_port_t * port,mcst_addr_t * mcst_p,int type)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
vsw_mac_multicast_add_all(vsw_t * vswp,vsw_port_t * portp,int type)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
vsw_mac_multicast_remove_all(vsw_t * vswp,vsw_port_t * portp,int type)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
vsw_update_bandwidth(vsw_t * vswp,vsw_port_t * port,int type,uint64_t maxbw)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
vsw_mac_client_init(vsw_t * vswp,vsw_port_t * port,int type)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
vsw_maccl_open(vsw_t * vswp,vsw_port_t * port,int type)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
vsw_mac_client_cleanup(vsw_t * vswp,vsw_port_t * port,int type)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
vsw_maccl_close(vsw_t * vswp,vsw_port_t * port,int type)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
vsw_mac_cleanup_ports(vsw_t * vswp)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
vsw_set_hw(vsw_t * vswp,vsw_port_t * port,int type)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
vsw_unset_hw(vsw_t * vswp,vsw_port_t * port,int type)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
vsw_set_port_hw_addr(vsw_port_t * port)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
vsw_set_if_hw_addr(vsw_t * vswp)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
vsw_unset_hw_addr(vsw_t * vswp,vsw_port_t * port,int type)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
vsw_if_rx_cb(void * arg,mac_resource_handle_t mrh,mblk_t * mp,boolean_t loopback)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
vsw_port_rx_cb(void * arg,mac_resource_handle_t mrh,mblk_t * mp,boolean_t loopback)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 *
vsw_tx_msg(vsw_t * vswp,mblk_t * mp,int caller,vsw_port_t * port)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
vsw_port_mac_reconfig(vsw_port_t * portp,boolean_t update_vlans,uint16_t new_pvid,vsw_vlanid_t * new_vids,int new_nvids)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
vsw_if_mac_reconfig(vsw_t * vswp,boolean_t update_vlans,uint16_t new_pvid,vsw_vlanid_t * new_vids,int new_nvids)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
vsw_mac_port_reconfig_vlans(vsw_port_t * portp,uint16_t new_pvid,vsw_vlanid_t * new_vids,int new_nvids)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
vsw_mac_add_vlans(vsw_t * vswp,mac_client_handle_t mch,uint8_t * macaddr,uint16_t flags,vsw_vlanid_t * vids,int nvids)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
vsw_mac_remove_vlans(mac_client_handle_t mch,vsw_vlanid_t * vids,int nvids)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
vsw_publish_macaddr(vsw_t * vswp,vsw_port_t * portp)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(ðerbroadcastaddr, &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
vsw_mac_set_mtu(vsw_t * vswp,uint32_t mtu)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
vsw_notify_add(vsw_t * vswp)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
vsw_notify_rem(vsw_t * vswp)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
vsw_notify_cb(void * arg,mac_notify_type_t type)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
vsw_notify_link(vsw_t * vswp)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
vsw_maccl_set_bandwidth(vsw_t * vswp,vsw_port_t * port,int type,uint64_t maxbw)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