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