15373Sraghuram /* 25373Sraghuram * CDDL HEADER START 35373Sraghuram * 45373Sraghuram * The contents of this file are subject to the terms of the 55373Sraghuram * Common Development and Distribution License (the "License"). 65373Sraghuram * You may not use this file except in compliance with the License. 75373Sraghuram * 85373Sraghuram * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95373Sraghuram * or http://www.opensolaris.org/os/licensing. 105373Sraghuram * See the License for the specific language governing permissions 115373Sraghuram * and limitations under the License. 125373Sraghuram * 135373Sraghuram * When distributing Covered Code, include this CDDL HEADER in each 145373Sraghuram * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155373Sraghuram * If applicable, add the following below this CDDL HEADER, with the 165373Sraghuram * fields enclosed by brackets "[]" replaced with your own identifying 175373Sraghuram * information: Portions Copyright [yyyy] [name of copyright owner] 185373Sraghuram * 195373Sraghuram * CDDL HEADER END 205373Sraghuram */ 215373Sraghuram 225373Sraghuram /* 239024SVenu.Iyer@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 245373Sraghuram * Use is subject to license terms. 255373Sraghuram */ 265373Sraghuram 275373Sraghuram #include <sys/types.h> 285373Sraghuram #include <sys/errno.h> 295373Sraghuram #include <sys/debug.h> 305373Sraghuram #include <sys/time.h> 315373Sraghuram #include <sys/sysmacros.h> 325373Sraghuram #include <sys/systm.h> 335373Sraghuram #include <sys/user.h> 345373Sraghuram #include <sys/stropts.h> 355373Sraghuram #include <sys/stream.h> 365373Sraghuram #include <sys/strlog.h> 375373Sraghuram #include <sys/strsubr.h> 385373Sraghuram #include <sys/cmn_err.h> 395373Sraghuram #include <sys/cpu.h> 405373Sraghuram #include <sys/kmem.h> 415373Sraghuram #include <sys/conf.h> 425373Sraghuram #include <sys/ddi.h> 435373Sraghuram #include <sys/sunddi.h> 445373Sraghuram #include <sys/ksynch.h> 455373Sraghuram #include <sys/stat.h> 465373Sraghuram #include <sys/kstat.h> 475373Sraghuram #include <sys/vtrace.h> 485373Sraghuram #include <sys/strsun.h> 495373Sraghuram #include <sys/dlpi.h> 505373Sraghuram #include <sys/ethernet.h> 515373Sraghuram #include <net/if.h> 527027Ssb155480 #include <netinet/arp.h> 537027Ssb155480 #include <inet/arp.h> 545373Sraghuram #include <sys/varargs.h> 555373Sraghuram #include <sys/machsystm.h> 565373Sraghuram #include <sys/modctl.h> 575373Sraghuram #include <sys/modhash.h> 588275SEric Cheng #include <sys/mac_client.h> 598275SEric Cheng #include <sys/mac_provider.h> 609336SSriharsha.Basavapatna@Sun.COM #include <sys/mac_client_priv.h> 615373Sraghuram #include <sys/mac_ether.h> 625373Sraghuram #include <sys/taskq.h> 635373Sraghuram #include <sys/note.h> 645373Sraghuram #include <sys/mach_descrip.h> 655373Sraghuram #include <sys/mac.h> 66*10795SWentao.Yang@Sun.COM #include <sys/mac_flow.h> 675373Sraghuram #include <sys/mdeg.h> 685373Sraghuram #include <sys/vsw.h> 698275SEric Cheng #include <sys/vlan.h> 705373Sraghuram 715373Sraghuram /* MAC Ring table functions. */ 728275SEric Cheng static void vsw_port_rx_cb(void *, mac_resource_handle_t, mblk_t *, 738275SEric Cheng boolean_t); 748275SEric Cheng static void vsw_if_rx_cb(void *, mac_resource_handle_t, mblk_t *, boolean_t); 755373Sraghuram 765373Sraghuram /* MAC layer routines */ 778275SEric Cheng static int vsw_set_port_hw_addr(vsw_port_t *port); 788275SEric Cheng static int vsw_set_if_hw_addr(vsw_t *vswp); 798275SEric Cheng static void vsw_unset_hw_addr(vsw_t *, vsw_port_t *, int); 808275SEric Cheng static int vsw_maccl_open(vsw_t *vswp, vsw_port_t *port, int type); 818275SEric Cheng static void vsw_maccl_close(vsw_t *vswp, vsw_port_t *port, int type); 828275SEric Cheng static void vsw_mac_multicast_add_all(vsw_t *vswp, vsw_port_t *portp, int type); 838275SEric Cheng static void vsw_mac_multicast_remove_all(vsw_t *vswp, 848275SEric Cheng vsw_port_t *portp, int type); 858275SEric Cheng static void vsw_mac_add_vlans(vsw_t *vswp, mac_client_handle_t mch, 868275SEric Cheng uint8_t *macaddr, uint16_t flags, vsw_vlanid_t *vids, int nvids); 878275SEric Cheng static void vsw_mac_remove_vlans(mac_client_handle_t mch, vsw_vlanid_t *vids, 888275SEric Cheng int nvids); 897529SSriharsha.Basavapatna@Sun.COM static void vsw_mac_set_mtu(vsw_t *vswp, uint32_t mtu); 90*10795SWentao.Yang@Sun.COM static void vsw_maccl_set_bandwidth(vsw_t *vswp, vsw_port_t *port, int type, 91*10795SWentao.Yang@Sun.COM uint64_t maxbw); 929336SSriharsha.Basavapatna@Sun.COM static int vsw_notify_add(vsw_t *vswp); 939336SSriharsha.Basavapatna@Sun.COM static int vsw_notify_rem(vsw_t *vswp); 949336SSriharsha.Basavapatna@Sun.COM static void vsw_notify_cb(void *arg, mac_notify_type_t type); 959336SSriharsha.Basavapatna@Sun.COM static void vsw_notify_link(vsw_t *vswp); 965373Sraghuram 975373Sraghuram /* Support functions */ 985373Sraghuram int vsw_set_hw(vsw_t *, vsw_port_t *, int); 998275SEric Cheng void vsw_unset_hw(vsw_t *, vsw_port_t *, int); 1005373Sraghuram void vsw_reconfig_hw(vsw_t *); 1015373Sraghuram int vsw_mac_open(vsw_t *vswp); 1025373Sraghuram void vsw_mac_close(vsw_t *vswp); 1038275SEric Cheng int vsw_mac_multicast_add(vsw_t *vswp, vsw_port_t *port, mcst_addr_t *mcst_p, 1048275SEric Cheng int type); 1058275SEric Cheng void vsw_mac_multicast_remove(vsw_t *vswp, vsw_port_t *port, 1068275SEric Cheng mcst_addr_t *mcst_p, int type); 1078275SEric Cheng int vsw_mac_client_init(vsw_t *vswp, vsw_port_t *port, int type); 1088275SEric Cheng void vsw_mac_client_cleanup(vsw_t *vswp, vsw_port_t *port, int type); 1098275SEric Cheng void vsw_mac_cleanup_ports(vsw_t *vswp); 1105373Sraghuram void vsw_unset_addrs(vsw_t *vswp); 1115373Sraghuram void vsw_set_addrs(vsw_t *vswp); 1128275SEric Cheng mblk_t *vsw_tx_msg(vsw_t *, mblk_t *, int, vsw_port_t *); 1138275SEric Cheng void vsw_publish_macaddr(vsw_t *vswp, vsw_port_t *portp); 1148275SEric Cheng void vsw_port_mac_reconfig(vsw_port_t *portp, boolean_t update_vlans, 1158275SEric Cheng uint16_t new_pvid, vsw_vlanid_t *new_vids, int new_nvids); 1168275SEric Cheng void vsw_mac_port_reconfig_vlans(vsw_port_t *portp, uint16_t new_pvid, 1178275SEric Cheng vsw_vlanid_t *new_vids, int new_nvids); 1188275SEric Cheng void vsw_if_mac_reconfig(vsw_t *vswp, boolean_t update_vlans, 1198275SEric Cheng uint16_t new_pvid, vsw_vlanid_t *new_vids, int new_nvids); 120*10795SWentao.Yang@Sun.COM void vsw_update_bandwidth(vsw_t *vswp, vsw_port_t *port, int type, 121*10795SWentao.Yang@Sun.COM uint64_t maxbw); 1225373Sraghuram 1238275SEric Cheng /* 1248275SEric Cheng * Functions imported from other files. 1258275SEric Cheng */ 1268275SEric Cheng extern int vsw_portsend(vsw_port_t *port, mblk_t *mp); 1278275SEric Cheng extern void vsw_hio_stop_port(vsw_port_t *portp); 1288275SEric Cheng extern void vsw_hio_port_reset(vsw_port_t *portp, boolean_t immediate); 1298275SEric Cheng extern uint32_t vsw_publish_macaddr_count; 1308275SEric Cheng extern uint32_t vsw_vlan_frame_untag(void *arg, int type, mblk_t **np, 1318275SEric Cheng mblk_t **npt); 1329336SSriharsha.Basavapatna@Sun.COM extern void vsw_physlink_state_update(vsw_t *vswp); 1337529SSriharsha.Basavapatna@Sun.COM static char mac_mtu_propname[] = "mtu"; 1347529SSriharsha.Basavapatna@Sun.COM 1355373Sraghuram /* 1365373Sraghuram * Tunables used in this file. 1375373Sraghuram */ 1385373Sraghuram extern int vsw_mac_open_retries; 1398275SEric Cheng 1408275SEric Cheng #define WRITE_MACCL_ENTER(vswp, port, type) \ 1418275SEric Cheng (type == VSW_LOCALDEV) ? rw_enter(&vswp->maccl_rwlock, RW_WRITER) :\ 1428275SEric Cheng rw_enter(&port->maccl_rwlock, RW_WRITER) 1438275SEric Cheng 1448275SEric Cheng #define READ_MACCL_ENTER(vswp, port, type) \ 1458275SEric Cheng (type == VSW_LOCALDEV) ? rw_enter(&vswp->maccl_rwlock, RW_READER) :\ 1468275SEric Cheng rw_enter(&port->maccl_rwlock, RW_READER) 1478275SEric Cheng 1488275SEric Cheng #define RW_MACCL_EXIT(vswp, port, type) \ 1498275SEric Cheng (type == VSW_LOCALDEV) ? rw_exit(&vswp->maccl_rwlock) : \ 1508275SEric Cheng rw_exit(&port->maccl_rwlock) 1518275SEric Cheng 1525373Sraghuram 1535373Sraghuram /* 1548275SEric Cheng * Locking strategy in this file is explained as follows: 1558275SEric Cheng * - A global lock(vswp->mac_lock) is used to protect the 1568275SEric Cheng * MAC calls that deal with entire device. That is, the 1578275SEric Cheng * operations that deal with mac_handle which include 1588275SEric Cheng * mac_open()/close() and mac_client_open(). 1598275SEric Cheng * 1608275SEric Cheng * - A per port/interface RW lock(maccl_rwlock) is used protect 1618275SEric Cheng * the operations that deal with the MAC client. 1625373Sraghuram * 1638275SEric Cheng * When both mac_lock and maccl_rwlock need to be held, the 1648275SEric Cheng * mac_lock need be acquired first and then maccl_rwlock. That is, 1658275SEric Cheng * mac_lock---->maccl_rwlock 1668275SEric Cheng * 1678275SEric Cheng * The 'mca_lock' that protects the mcast list is also acquired 1688275SEric Cheng * within the context of maccl_rwlock. The hierarchy for this 1698275SEric Cheng * one is as below: 1708275SEric Cheng * maccl_rwlock---->mca_lock 1715373Sraghuram */ 1725373Sraghuram 1735373Sraghuram 1745373Sraghuram /* 1755373Sraghuram * Program unicast and multicast addresses of vsw interface and the ports 1768275SEric Cheng * into the network device. 1775373Sraghuram */ 1785373Sraghuram void 1795373Sraghuram vsw_set_addrs(vsw_t *vswp) 1805373Sraghuram { 1815373Sraghuram vsw_port_list_t *plist = &vswp->plist; 1825373Sraghuram vsw_port_t *port; 1835373Sraghuram int rv; 1845373Sraghuram 1855373Sraghuram READ_ENTER(&vswp->if_lockrw); 1865373Sraghuram 1875373Sraghuram if (vswp->if_state & VSW_IF_UP) { 1885373Sraghuram 1898275SEric Cheng /* Open a mac client and program addresses */ 1908275SEric Cheng rv = vsw_mac_client_init(vswp, NULL, VSW_LOCALDEV); 1918275SEric Cheng if (rv != 0) { 1928275SEric Cheng cmn_err(CE_NOTE, 1938275SEric Cheng "!vsw%d: failed to program interface " 1948275SEric Cheng "unicast address\n", vswp->instance); 1958275SEric Cheng } 1968275SEric Cheng 1978275SEric Cheng /* 1988275SEric Cheng * Notify the MAC layer of the changed address. 1998275SEric Cheng */ 2008275SEric Cheng if (rv == 0) { 2015373Sraghuram mac_unicst_update(vswp->if_mh, 2025373Sraghuram (uint8_t *)&vswp->if_addr); 2035373Sraghuram } 2045373Sraghuram 2055373Sraghuram } 2065373Sraghuram 2075373Sraghuram RW_EXIT(&vswp->if_lockrw); 2085373Sraghuram 2095373Sraghuram WRITE_ENTER(&plist->lockrw); 2105373Sraghuram 2118275SEric Cheng /* program unicast address of ports in the network device */ 2125373Sraghuram for (port = plist->head; port != NULL; port = port->p_next) { 2138275SEric Cheng if (port->addr_set) /* addr already set */ 2145373Sraghuram continue; 2158275SEric Cheng 2168275SEric Cheng /* Open a mac client and program addresses */ 2178275SEric Cheng rv = vsw_mac_client_init(vswp, port, VSW_VNETPORT); 2188275SEric Cheng if (rv != 0) { 2195373Sraghuram cmn_err(CE_NOTE, 2208275SEric Cheng "!vsw%d: failed to program port(%d) " 2218275SEric Cheng "unicast address\n", vswp->instance, 2228275SEric Cheng port->p_instance); 2235373Sraghuram } 2245373Sraghuram } 2257027Ssb155480 /* announce macaddr of vnets to the physical switch */ 2267027Ssb155480 if (vsw_publish_macaddr_count != 0) { /* enabled */ 2277027Ssb155480 for (port = plist->head; port != NULL; port = port->p_next) { 2288275SEric Cheng vsw_publish_macaddr(vswp, port); 2297027Ssb155480 } 2307027Ssb155480 } 2317027Ssb155480 2325373Sraghuram RW_EXIT(&plist->lockrw); 2335373Sraghuram } 2345373Sraghuram 2355373Sraghuram /* 2368275SEric Cheng * Remove unicast, multicast addresses and close mac clients 2378275SEric Cheng * for the vsw interface and all ports. 2385373Sraghuram */ 2395373Sraghuram void 2405373Sraghuram vsw_unset_addrs(vsw_t *vswp) 2415373Sraghuram { 2425373Sraghuram READ_ENTER(&vswp->if_lockrw); 2435373Sraghuram if (vswp->if_state & VSW_IF_UP) { 2445373Sraghuram 2458275SEric Cheng /* Cleanup and close the mac client for the interface */ 2468275SEric Cheng vsw_mac_client_cleanup(vswp, NULL, VSW_LOCALDEV); 2475373Sraghuram } 2485373Sraghuram RW_EXIT(&vswp->if_lockrw); 2495373Sraghuram 2508275SEric Cheng /* Cleanup and close the mac clients for all ports */ 2518275SEric Cheng vsw_mac_cleanup_ports(vswp); 2525373Sraghuram } 2535373Sraghuram 2545373Sraghuram /* 2558275SEric Cheng * Open the underlying network device for access in layer2 mode. 2565373Sraghuram * Returns: 2578275SEric Cheng * 0 on success 2588275SEric Cheng * EAGAIN if mac_open() fails due to the device being not available yet. 2598275SEric Cheng * EIO on any other failures. 2605373Sraghuram */ 2615373Sraghuram int 2625373Sraghuram vsw_mac_open(vsw_t *vswp) 2635373Sraghuram { 2648275SEric Cheng int rv; 2655373Sraghuram 2668275SEric Cheng ASSERT(MUTEX_HELD(&vswp->mac_lock)); 2675373Sraghuram 2685373Sraghuram if (vswp->mh != NULL) { 2695373Sraghuram /* already open */ 2705373Sraghuram return (0); 2715373Sraghuram } 2725373Sraghuram 2735373Sraghuram if (vswp->mac_open_retries++ >= vsw_mac_open_retries) { 2745373Sraghuram /* exceeded max retries */ 2755373Sraghuram return (EIO); 2765373Sraghuram } 2775373Sraghuram 2785895Syz147064 if ((rv = mac_open_by_linkname(vswp->physname, &vswp->mh)) != 0) { 2795373Sraghuram /* 2805895Syz147064 * If mac_open() failed and the error indicates that either 2815895Syz147064 * the dlmgmtd door or the device is not available yet, we 2825895Syz147064 * return EAGAIN to indicate that mac_open() needs to be 2835895Syz147064 * retried. For example, this may happen during boot up, if 2845895Syz147064 * the required link aggregation groups(devices) have not 2855895Syz147064 * been created yet. 2865373Sraghuram */ 2875895Syz147064 if (rv == ENOENT || rv == EBADF) { 2885373Sraghuram return (EAGAIN); 2895373Sraghuram } else { 2909336SSriharsha.Basavapatna@Sun.COM cmn_err(CE_WARN, "!vsw%d: mac_open %s failed rv:%x\n", 2915373Sraghuram vswp->instance, vswp->physname, rv); 2925373Sraghuram return (EIO); 2935373Sraghuram } 2945373Sraghuram } 2958275SEric Cheng vswp->mac_open_retries = 0; 2965373Sraghuram 2978275SEric Cheng vsw_mac_set_mtu(vswp, vswp->mtu); 2985373Sraghuram 2999336SSriharsha.Basavapatna@Sun.COM rv = vsw_notify_add(vswp); 3009336SSriharsha.Basavapatna@Sun.COM if (rv != 0) { 3019336SSriharsha.Basavapatna@Sun.COM cmn_err(CE_CONT, "!vsw%d: mac_notify_add %s failed rv:%x\n", 3029336SSriharsha.Basavapatna@Sun.COM vswp->instance, vswp->physname, rv); 3039336SSriharsha.Basavapatna@Sun.COM } 3049336SSriharsha.Basavapatna@Sun.COM 3055373Sraghuram return (0); 3065373Sraghuram } 3075373Sraghuram 3085373Sraghuram /* 3095373Sraghuram * Close the underlying physical device. 3105373Sraghuram */ 3115373Sraghuram void 3125373Sraghuram vsw_mac_close(vsw_t *vswp) 3135373Sraghuram { 3148275SEric Cheng ASSERT(MUTEX_HELD(&vswp->mac_lock)); 3155373Sraghuram 3165373Sraghuram if (vswp->mh != NULL) { 3179336SSriharsha.Basavapatna@Sun.COM if (vswp->mnh != 0) { 3189336SSriharsha.Basavapatna@Sun.COM (void) vsw_notify_rem(vswp); 3199336SSriharsha.Basavapatna@Sun.COM vswp->mnh = 0; 3209336SSriharsha.Basavapatna@Sun.COM } 3218275SEric Cheng if (vswp->mtu != vswp->mtu_physdev_orig) { 3228275SEric Cheng vsw_mac_set_mtu(vswp, vswp->mtu_physdev_orig); 3238275SEric Cheng } 3245373Sraghuram mac_close(vswp->mh); 3255373Sraghuram vswp->mh = NULL; 3265373Sraghuram } 3275373Sraghuram } 3285373Sraghuram 3295373Sraghuram /* 3308275SEric Cheng * Add multicast addr. 3318275SEric Cheng */ 3328275SEric Cheng int 3338275SEric Cheng vsw_mac_multicast_add(vsw_t *vswp, vsw_port_t *port, mcst_addr_t *mcst_p, 3348275SEric Cheng int type) 3358275SEric Cheng { 3368275SEric Cheng int ret = 0; 3378275SEric Cheng mac_client_handle_t mch; 3388275SEric Cheng 3398275SEric Cheng WRITE_MACCL_ENTER(vswp, port, type); 3408275SEric Cheng 3418275SEric Cheng mch = (type == VSW_LOCALDEV) ? vswp->mch : port->p_mch; 3428275SEric Cheng 3438275SEric Cheng if (mch != NULL) { 3448275SEric Cheng ret = mac_multicast_add(mch, mcst_p->mca.ether_addr_octet); 3458275SEric Cheng if (ret != 0) { 3468275SEric Cheng cmn_err(CE_WARN, "!vsw%d: unable to " 3478275SEric Cheng "program multicast address(%s) err=%d", 3488275SEric Cheng vswp->instance, 3498275SEric Cheng ether_sprintf((void *)&mcst_p->mca), ret); 3508275SEric Cheng RW_MACCL_EXIT(vswp, port, type); 3518275SEric Cheng return (ret); 3528275SEric Cheng } 3538275SEric Cheng mcst_p->mac_added = B_TRUE; 3548275SEric Cheng } 3558275SEric Cheng 3568275SEric Cheng RW_MACCL_EXIT(vswp, port, type); 3578275SEric Cheng return (ret); 3588275SEric Cheng } 3598275SEric Cheng 3608275SEric Cheng /* 3618275SEric Cheng * Remove multicast addr. 3628275SEric Cheng */ 3638275SEric Cheng void 3648275SEric Cheng vsw_mac_multicast_remove(vsw_t *vswp, vsw_port_t *port, mcst_addr_t *mcst_p, 3658275SEric Cheng int type) 3668275SEric Cheng { 3678275SEric Cheng mac_client_handle_t mch; 3688275SEric Cheng 3698275SEric Cheng WRITE_MACCL_ENTER(vswp, port, type); 3708275SEric Cheng mch = (type == VSW_LOCALDEV) ? vswp->mch : port->p_mch; 3718275SEric Cheng 3728275SEric Cheng if (mch != NULL && mcst_p->mac_added) { 3738275SEric Cheng mac_multicast_remove(mch, mcst_p->mca.ether_addr_octet); 3748275SEric Cheng mcst_p->mac_added = B_FALSE; 3758275SEric Cheng } 3768275SEric Cheng RW_MACCL_EXIT(vswp, port, type); 3778275SEric Cheng } 3788275SEric Cheng 3798275SEric Cheng 3808275SEric Cheng /* 3818275SEric Cheng * Add all multicast addresses of the port. 3828275SEric Cheng */ 3838275SEric Cheng static void 3848275SEric Cheng vsw_mac_multicast_add_all(vsw_t *vswp, vsw_port_t *portp, int type) 3858275SEric Cheng { 3868275SEric Cheng mcst_addr_t *mcap; 3878275SEric Cheng mac_client_handle_t mch; 3888275SEric Cheng kmutex_t *mca_lockp; 3898275SEric Cheng int rv; 3908275SEric Cheng 3918275SEric Cheng ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT)); 3928275SEric Cheng if (type == VSW_LOCALDEV) { 3938275SEric Cheng ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock)); 3948275SEric Cheng mch = vswp->mch; 3958275SEric Cheng mcap = vswp->mcap; 3968275SEric Cheng mca_lockp = &vswp->mca_lock; 3978275SEric Cheng } else { 3988275SEric Cheng ASSERT(RW_WRITE_HELD(&portp->maccl_rwlock)); 3998275SEric Cheng mch = portp->p_mch; 4008275SEric Cheng mcap = portp->mcap; 4018275SEric Cheng mca_lockp = &portp->mca_lock; 4028275SEric Cheng } 4038275SEric Cheng 4048275SEric Cheng if (mch == NULL) 4058275SEric Cheng return; 4068275SEric Cheng 4078275SEric Cheng mutex_enter(mca_lockp); 4088275SEric Cheng for (mcap = mcap; mcap != NULL; mcap = mcap->nextp) { 4098275SEric Cheng if (mcap->mac_added) 4108275SEric Cheng continue; 4118275SEric Cheng rv = mac_multicast_add(mch, (uchar_t *)&mcap->mca); 4128275SEric Cheng if (rv == 0) { 4138275SEric Cheng mcap->mac_added = B_TRUE; 4148275SEric Cheng } else { 4158275SEric Cheng cmn_err(CE_WARN, "!vsw%d: unable to program " 4168275SEric Cheng "multicast address(%s) err=%d", vswp->instance, 4178275SEric Cheng ether_sprintf((void *)&mcap->mca), rv); 4188275SEric Cheng } 4198275SEric Cheng } 4208275SEric Cheng mutex_exit(mca_lockp); 4218275SEric Cheng } 4228275SEric Cheng 4238275SEric Cheng /* 4248275SEric Cheng * Remove all multicast addresses of the port. 4258275SEric Cheng */ 4268275SEric Cheng static void 4278275SEric Cheng vsw_mac_multicast_remove_all(vsw_t *vswp, vsw_port_t *portp, int type) 4288275SEric Cheng { 4298275SEric Cheng mac_client_handle_t mch; 4308275SEric Cheng mcst_addr_t *mcap; 4318275SEric Cheng kmutex_t *mca_lockp; 4328275SEric Cheng 4338275SEric Cheng ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT)); 4348275SEric Cheng if (type == VSW_LOCALDEV) { 4358275SEric Cheng ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock)); 4368275SEric Cheng mch = vswp->mch; 4378275SEric Cheng mcap = vswp->mcap; 4388275SEric Cheng mca_lockp = &vswp->mca_lock; 4398275SEric Cheng } else { 4408275SEric Cheng ASSERT(RW_WRITE_HELD(&portp->maccl_rwlock)); 4418275SEric Cheng mch = portp->p_mch; 4428275SEric Cheng mcap = portp->mcap; 4438275SEric Cheng mca_lockp = &portp->mca_lock; 4448275SEric Cheng } 4458275SEric Cheng 4468275SEric Cheng if (mch == NULL) 4478275SEric Cheng return; 4488275SEric Cheng 4498275SEric Cheng mutex_enter(mca_lockp); 4508275SEric Cheng for (; mcap != NULL; mcap = mcap->nextp) { 4518275SEric Cheng if (!mcap->mac_added) 4528275SEric Cheng continue; 4538275SEric Cheng (void) mac_multicast_remove(mch, (uchar_t *)&mcap->mca); 4548275SEric Cheng mcap->mac_added = B_FALSE; 4558275SEric Cheng } 4568275SEric Cheng mutex_exit(mca_lockp); 4578275SEric Cheng } 4588275SEric Cheng 459*10795SWentao.Yang@Sun.COM void 460*10795SWentao.Yang@Sun.COM vsw_update_bandwidth(vsw_t *vswp, vsw_port_t *port, int type, uint64_t maxbw) 461*10795SWentao.Yang@Sun.COM { 462*10795SWentao.Yang@Sun.COM ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT)); 463*10795SWentao.Yang@Sun.COM 464*10795SWentao.Yang@Sun.COM WRITE_MACCL_ENTER(vswp, port, type); 465*10795SWentao.Yang@Sun.COM vsw_maccl_set_bandwidth(vswp, port, type, maxbw); 466*10795SWentao.Yang@Sun.COM RW_MACCL_EXIT(vswp, port, type); 467*10795SWentao.Yang@Sun.COM } 468*10795SWentao.Yang@Sun.COM 4698275SEric Cheng /* 4708275SEric Cheng * Open a mac client and program uncast and multicast addresses 4718275SEric Cheng * for a port or the interface. 4728275SEric Cheng * Returns: 4738275SEric Cheng * 0 on success 4748275SEric Cheng * non-zero for failure. 4755373Sraghuram */ 4765373Sraghuram int 4778275SEric Cheng vsw_mac_client_init(vsw_t *vswp, vsw_port_t *port, int type) 4785373Sraghuram { 4798275SEric Cheng int rv; 4808275SEric Cheng 4818275SEric Cheng mutex_enter(&vswp->mac_lock); 4828275SEric Cheng WRITE_MACCL_ENTER(vswp, port, type); 4838275SEric Cheng rv = vsw_maccl_open(vswp, port, type); 4845373Sraghuram 4858275SEric Cheng /* Release mac_lock now */ 4868275SEric Cheng mutex_exit(&vswp->mac_lock); 4875373Sraghuram 4888275SEric Cheng if (rv == 0) { 4898275SEric Cheng (void) vsw_set_hw(vswp, port, type); 4908275SEric Cheng vsw_mac_multicast_add_all(vswp, port, type); 4918275SEric Cheng } 4928275SEric Cheng RW_MACCL_EXIT(vswp, port, type); 4938275SEric Cheng return (rv); 4948275SEric Cheng } 4955373Sraghuram 4968275SEric Cheng /* 4978275SEric Cheng * Open a MAC client for a port or an interface. 4988275SEric Cheng * The flags and their purpose as below: 4998275SEric Cheng * 5008275SEric Cheng * MAC_OPEN_FLAGS_NO_HWRINGS -- This flag is used by default 5018275SEric Cheng * for all ports/interface so that they are associated with 5028275SEric Cheng * default group & resources. It will not be used for the 5038275SEric Cheng * ports that have HybridIO is enabled so that the h/w resources 5048275SEric Cheng * assigned to it. 5058275SEric Cheng * 5068275SEric Cheng * MAC_OPEN_FLAGS_SHARES_DESIRED -- This flag is used to indicate 5078275SEric Cheng * that a port desires a Share. This will be the case with the 5088275SEric Cheng * the ports that have hybrid mode enabled. This will only cause 5098275SEric Cheng * MAC layer to allocate a share and corresponding resources 5108275SEric Cheng * ahead of time. 5118275SEric Cheng * 5129024SVenu.Iyer@Sun.COM * MAC_UNICAST_TAG_DISABLE -- This flag is used for VLAN 5138275SEric Cheng * support. It will cause MAC to not add any tags, but expect 5148275SEric Cheng * vsw to tag the packets. 5158275SEric Cheng * 5169024SVenu.Iyer@Sun.COM * MAC_UNICAST_STRIP_DISABLE -- This flag is used for VLAN 5178275SEric Cheng * support. It will case the MAC layer to not strip the tags. 5188275SEric Cheng * Vsw may have to strip the tag for pvid case. 5198275SEric Cheng */ 5208275SEric Cheng static int 5218275SEric Cheng vsw_maccl_open(vsw_t *vswp, vsw_port_t *port, int type) 5228275SEric Cheng { 5238275SEric Cheng int rv = 0; 5248275SEric Cheng int instance; 5258275SEric Cheng char mac_cl_name[MAXNAMELEN]; 5268275SEric Cheng const char *dev_name; 5278275SEric Cheng mac_client_handle_t *mchp; 5289024SVenu.Iyer@Sun.COM uint64_t flags = MAC_OPEN_FLAGS_NO_HWRINGS; 5297529SSriharsha.Basavapatna@Sun.COM 5308275SEric Cheng ASSERT(MUTEX_HELD(&vswp->mac_lock)); 5318275SEric Cheng if (vswp->mh == NULL) { 5325373Sraghuram /* 5338275SEric Cheng * In case net-dev is changed (either set to nothing or 5348275SEric Cheng * using aggregation device), return success here as the 5358275SEric Cheng * timeout mechanism will handle it. 5365373Sraghuram */ 5378275SEric Cheng return (0); 5385373Sraghuram } 5395373Sraghuram 5408275SEric Cheng mchp = (type == VSW_LOCALDEV) ? &vswp->mch : &port->p_mch; 5418275SEric Cheng if (*mchp != NULL) { 5428275SEric Cheng /* already open */ 5438275SEric Cheng return (0); 5448275SEric Cheng } 5458275SEric Cheng dev_name = ddi_driver_name(vswp->dip); 5468275SEric Cheng instance = ddi_get_instance(vswp->dip); 5478275SEric Cheng if (type == VSW_VNETPORT) { 5488275SEric Cheng if (port->p_hio_enabled == B_TRUE) { 5498275SEric Cheng flags &= ~MAC_OPEN_FLAGS_NO_HWRINGS; 5508275SEric Cheng flags |= MAC_OPEN_FLAGS_SHARES_DESIRED; 5518275SEric Cheng } 5528275SEric Cheng (void) snprintf(mac_cl_name, MAXNAMELEN, "%s%d%s%d", dev_name, 5538275SEric Cheng instance, "_port", port->p_instance); 5548275SEric Cheng } else { 5558275SEric Cheng (void) snprintf(mac_cl_name, MAXNAMELEN, "%s%s%d", 5568275SEric Cheng dev_name, "_if", instance); 5575373Sraghuram } 5585373Sraghuram 5598275SEric Cheng rv = mac_client_open(vswp->mh, mchp, mac_cl_name, flags); 5608275SEric Cheng if (rv != 0) { 5618275SEric Cheng cmn_err(CE_NOTE, "!vsw%d:%s mac_client_open() failed\n", 5628275SEric Cheng vswp->instance, mac_cl_name); 5638275SEric Cheng } 5648275SEric Cheng return (rv); 5655373Sraghuram } 5665373Sraghuram 5678275SEric Cheng /* 5688275SEric Cheng * Clean up by removing uncast, multicast addresses and 5698275SEric Cheng * closing the MAC client for a port or the interface. 5708275SEric Cheng */ 5715373Sraghuram void 5728275SEric Cheng vsw_mac_client_cleanup(vsw_t *vswp, vsw_port_t *port, int type) 5735373Sraghuram { 5748275SEric Cheng WRITE_MACCL_ENTER(vswp, port, type); 5759943SWentao.Yang@Sun.COM vsw_mac_multicast_remove_all(vswp, port, type); 5768275SEric Cheng vsw_unset_hw(vswp, port, type); 5778275SEric Cheng vsw_maccl_close(vswp, port, type); 5788275SEric Cheng RW_MACCL_EXIT(vswp, port, type); 5798275SEric Cheng } 5805373Sraghuram 5818275SEric Cheng /* 5828275SEric Cheng * Close a MAC client for a port or an interface. 5838275SEric Cheng */ 5848275SEric Cheng static void 5858275SEric Cheng vsw_maccl_close(vsw_t *vswp, vsw_port_t *port, int type) 5868275SEric Cheng { 5878275SEric Cheng mac_client_handle_t *mchp; 5885373Sraghuram 5898275SEric Cheng ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT)); 5908275SEric Cheng 5918275SEric Cheng mchp = (type == VSW_LOCALDEV) ? &vswp->mch : &port->p_mch; 5928275SEric Cheng if (*mchp != NULL) { 5938275SEric Cheng mac_client_close(*mchp, 0); 5948275SEric Cheng *mchp = NULL; 5955373Sraghuram } 5968275SEric Cheng } 5975373Sraghuram 5988275SEric Cheng /* 5998275SEric Cheng * Cleanup MAC client related stuff for all ports. 6008275SEric Cheng */ 6018275SEric Cheng void 6028275SEric Cheng vsw_mac_cleanup_ports(vsw_t *vswp) 6038275SEric Cheng { 6048275SEric Cheng vsw_port_list_t *plist = &vswp->plist; 6058275SEric Cheng vsw_port_t *port; 6065373Sraghuram 6078275SEric Cheng READ_ENTER(&plist->lockrw); 6088275SEric Cheng for (port = plist->head; port != NULL; port = port->p_next) { 6098275SEric Cheng vsw_mac_client_cleanup(vswp, port, VSW_VNETPORT); 6108275SEric Cheng } 6118275SEric Cheng RW_EXIT(&plist->lockrw); 6125373Sraghuram } 6135373Sraghuram 6145373Sraghuram /* 6155373Sraghuram * Depending on the mode specified, the capabilites and capacity 6165373Sraghuram * of the underlying device setup the physical device. 6175373Sraghuram * 6185373Sraghuram * If in layer 3 mode, then do nothing. 6195373Sraghuram * 6208275SEric Cheng * If in layer 2 mode, open a mac client and program the mac-address 6218275SEric Cheng * and vlan-ids. The MAC layer will take care of programming 6228275SEric Cheng * the address into h/w or set the h/w into promiscuous mode. 6235373Sraghuram * 6245373Sraghuram * Returns 0 success, 1 on failure. 6255373Sraghuram */ 6265373Sraghuram int 6275373Sraghuram vsw_set_hw(vsw_t *vswp, vsw_port_t *port, int type) 6285373Sraghuram { 6298275SEric Cheng int err = 1; 6305373Sraghuram 6315373Sraghuram D1(vswp, "%s: enter", __func__); 6325373Sraghuram 6335373Sraghuram ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT)); 6345373Sraghuram 6358275SEric Cheng if (vswp->smode == VSW_LAYER3) 6365373Sraghuram return (0); 6375373Sraghuram 6385373Sraghuram if (type == VSW_VNETPORT) { 6395373Sraghuram ASSERT(port != NULL); 6408275SEric Cheng err = vsw_set_port_hw_addr(port); 6415373Sraghuram } else { 6428275SEric Cheng err = vsw_set_if_hw_addr(vswp); 6435373Sraghuram } 6445373Sraghuram 6455373Sraghuram D1(vswp, "%s: exit", __func__); 6468275SEric Cheng return (err); 6475373Sraghuram } 6485373Sraghuram 6495373Sraghuram /* 6505373Sraghuram * If in layer 3 mode do nothing. 6515373Sraghuram * 6525373Sraghuram * If in layer 2 switched mode remove the address from the physical 6535373Sraghuram * device. 6545373Sraghuram * 6555373Sraghuram * If in layer 2 promiscuous mode disable promisc mode. 6565373Sraghuram * 6575373Sraghuram * Returns 0 on success. 6585373Sraghuram */ 6598275SEric Cheng void 6605373Sraghuram vsw_unset_hw(vsw_t *vswp, vsw_port_t *port, int type) 6615373Sraghuram { 6628275SEric Cheng D1(vswp, "%s: enter", __func__); 6638275SEric Cheng 6648275SEric Cheng ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT)); 6658275SEric Cheng 6668275SEric Cheng if (vswp->smode == VSW_LAYER3) 6678275SEric Cheng return; 6688275SEric Cheng 6698275SEric Cheng if (type == VSW_VNETPORT) { 6708275SEric Cheng ASSERT(port != NULL); 6718275SEric Cheng vsw_unset_hw_addr(vswp, port, type); 6728275SEric Cheng } else { 6738275SEric Cheng vsw_unset_hw_addr(vswp, NULL, type); 6748275SEric Cheng } 6758275SEric Cheng 6768275SEric Cheng D1(vswp, "%s: exit", __func__); 6778275SEric Cheng } 6788275SEric Cheng 6798275SEric Cheng /* 6808275SEric Cheng * Program the macaddress and vlans of a port. 6818275SEric Cheng * 6828275SEric Cheng * Returns 0 on sucess, 1 on failure. 6838275SEric Cheng */ 6848275SEric Cheng static int 6858275SEric Cheng vsw_set_port_hw_addr(vsw_port_t *port) 6868275SEric Cheng { 6878275SEric Cheng vsw_t *vswp = port->p_vswp; 6888275SEric Cheng mac_diag_t diag; 6898275SEric Cheng uint8_t *macaddr; 6908275SEric Cheng uint16_t vid = VLAN_ID_NONE; 6918275SEric Cheng int rv; 6929024SVenu.Iyer@Sun.COM uint16_t mac_flags = MAC_UNICAST_TAG_DISABLE | 6939024SVenu.Iyer@Sun.COM MAC_UNICAST_STRIP_DISABLE; 6945373Sraghuram 6955373Sraghuram D1(vswp, "%s: enter", __func__); 6965373Sraghuram 6978275SEric Cheng ASSERT(RW_WRITE_HELD(&port->maccl_rwlock)); 6988275SEric Cheng if (port->p_mch == NULL) 6995373Sraghuram return (0); 7005373Sraghuram 7018275SEric Cheng /* 7028275SEric Cheng * If the port has a specific 'pvid', then 7038275SEric Cheng * register with that vlan-id, otherwise register 7048275SEric Cheng * with VLAN_ID_NONE. 7058275SEric Cheng */ 7068275SEric Cheng if (port->pvid != vswp->default_vlan_id) { 7078275SEric Cheng vid = port->pvid; 7088275SEric Cheng } 7098275SEric Cheng macaddr = (uint8_t *)port->p_macaddr.ether_addr_octet; 7105373Sraghuram 7118275SEric Cheng if (!(vswp->smode & VSW_LAYER2_PROMISC)) { 7128275SEric Cheng mac_flags |= MAC_UNICAST_HW; 7138275SEric Cheng } 7145373Sraghuram 7158275SEric Cheng if (port->addr_set == B_FALSE) { 7168275SEric Cheng port->p_muh = NULL; 7178275SEric Cheng rv = mac_unicast_add(port->p_mch, macaddr, mac_flags, 7188275SEric Cheng &port->p_muh, vid, &diag); 7195373Sraghuram 7208275SEric Cheng if (rv != 0) { 7218275SEric Cheng cmn_err(CE_WARN, "vsw%d: Failed to program" 7228275SEric Cheng "macaddr,vid(%s, %d) err=%d", 7238275SEric Cheng vswp->instance, ether_sprintf((void *)macaddr), 7248275SEric Cheng vid, rv); 7258275SEric Cheng return (rv); 7265373Sraghuram } 7278275SEric Cheng port->addr_set = B_TRUE; 7285373Sraghuram 7298275SEric Cheng D2(vswp, "%s:programmed macaddr(%s) vid(%d) into device %s", 7308275SEric Cheng __func__, ether_sprintf((void *)macaddr), vid, 7318275SEric Cheng vswp->physname); 7325373Sraghuram } 7335373Sraghuram 7348275SEric Cheng /* Add vlans to the MAC layer */ 7358275SEric Cheng vsw_mac_add_vlans(vswp, port->p_mch, macaddr, 7368275SEric Cheng mac_flags, port->vids, port->nvids); 7378275SEric Cheng 738*10795SWentao.Yang@Sun.COM /* Configure bandwidth to the MAC layer */ 739*10795SWentao.Yang@Sun.COM vsw_maccl_set_bandwidth(NULL, port, VSW_VNETPORT, port->p_bandwidth); 740*10795SWentao.Yang@Sun.COM 7418275SEric Cheng mac_rx_set(port->p_mch, vsw_port_rx_cb, (void *)port); 7428275SEric Cheng 7435373Sraghuram D1(vswp, "%s: exit", __func__); 7445373Sraghuram return (rv); 7455373Sraghuram } 7465373Sraghuram 7475373Sraghuram /* 7488275SEric Cheng * Program the macaddress and vlans of a port. 7495373Sraghuram * 7505373Sraghuram * Returns 0 on sucess, 1 on failure. 7515373Sraghuram */ 7525373Sraghuram static int 7538275SEric Cheng vsw_set_if_hw_addr(vsw_t *vswp) 7545373Sraghuram { 7558275SEric Cheng mac_diag_t diag; 7568275SEric Cheng uint8_t *macaddr; 7578275SEric Cheng uint8_t primary_addr[ETHERADDRL]; 7588275SEric Cheng uint16_t vid = VLAN_ID_NONE; 7598275SEric Cheng int rv; 7609024SVenu.Iyer@Sun.COM uint16_t mac_flags = MAC_UNICAST_TAG_DISABLE | 7619024SVenu.Iyer@Sun.COM MAC_UNICAST_STRIP_DISABLE; 7625373Sraghuram 7635373Sraghuram D1(vswp, "%s: enter", __func__); 7645373Sraghuram 7658275SEric Cheng ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock)); 7668275SEric Cheng if (vswp->mch == NULL) 7678275SEric Cheng return (0); 7685373Sraghuram 7698275SEric Cheng macaddr = (uint8_t *)vswp->if_addr.ether_addr_octet; 7705373Sraghuram 7718275SEric Cheng /* check if it is the primary macaddr of the card. */ 7728275SEric Cheng mac_unicast_primary_get(vswp->mh, primary_addr); 7738275SEric Cheng if (ether_cmp((void *)primary_addr, (void*)macaddr) == 0) { 7748275SEric Cheng mac_flags |= MAC_UNICAST_PRIMARY; 7758275SEric Cheng } 7765373Sraghuram 7775373Sraghuram /* 7788275SEric Cheng * If the interface has a specific 'pvid', then 7798275SEric Cheng * register with that vlan-id, otherwise register 7808275SEric Cheng * with VLAN_ID_NONE. 7815373Sraghuram */ 7828275SEric Cheng if (vswp->pvid != vswp->default_vlan_id) { 7838275SEric Cheng vid = vswp->pvid; 7848275SEric Cheng } 7858275SEric Cheng 7868275SEric Cheng if (!(vswp->smode & VSW_LAYER2_PROMISC)) { 7878275SEric Cheng mac_flags |= MAC_UNICAST_HW; 7885373Sraghuram } 7898275SEric Cheng 7908275SEric Cheng if (vswp->addr_set == B_FALSE) { 7918275SEric Cheng vswp->muh = NULL; 7928275SEric Cheng rv = mac_unicast_add(vswp->mch, macaddr, mac_flags, 7938275SEric Cheng &vswp->muh, vid, &diag); 7948275SEric Cheng 7958275SEric Cheng if (rv != 0) { 7968275SEric Cheng cmn_err(CE_WARN, "vsw%d: Failed to program" 7978275SEric Cheng "macaddr,vid(%s, %d) err=%d", 7988275SEric Cheng vswp->instance, ether_sprintf((void *)macaddr), 7998275SEric Cheng vid, rv); 8008275SEric Cheng return (rv); 8018275SEric Cheng } 8028275SEric Cheng vswp->addr_set = B_TRUE; 8038275SEric Cheng 8048275SEric Cheng D2(vswp, "%s:programmed macaddr(%s) vid(%d) into device %s", 8058275SEric Cheng __func__, ether_sprintf((void *)macaddr), vid, 8068275SEric Cheng vswp->physname); 8078275SEric Cheng } 8088275SEric Cheng 8098275SEric Cheng vsw_mac_add_vlans(vswp, vswp->mch, macaddr, mac_flags, 8108275SEric Cheng vswp->vids, vswp->nvids); 8118275SEric Cheng 812*10795SWentao.Yang@Sun.COM vsw_maccl_set_bandwidth(vswp, NULL, VSW_LOCALDEV, vswp->bandwidth); 813*10795SWentao.Yang@Sun.COM 8148275SEric Cheng mac_rx_set(vswp->mch, vsw_if_rx_cb, (void *)vswp); 8158275SEric Cheng 8165373Sraghuram D1(vswp, "%s: exit", __func__); 8175373Sraghuram return (rv); 8185373Sraghuram } 8195373Sraghuram 8205373Sraghuram /* 8215373Sraghuram * Remove a unicast mac address which has previously been programmed 8225373Sraghuram * into HW. 8235373Sraghuram * 8245373Sraghuram * Returns 0 on sucess, 1 on failure. 8255373Sraghuram */ 8268275SEric Cheng static void 8278275SEric Cheng vsw_unset_hw_addr(vsw_t *vswp, vsw_port_t *port, int type) 8285373Sraghuram { 8298275SEric Cheng vsw_vlanid_t *vids; 8308275SEric Cheng int nvids; 8318275SEric Cheng mac_client_handle_t mch = NULL; 8325373Sraghuram 8335373Sraghuram D1(vswp, "%s: enter", __func__); 8345373Sraghuram 8355373Sraghuram ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT)); 8365373Sraghuram 8375373Sraghuram if (type == VSW_VNETPORT) { 8385373Sraghuram ASSERT(port != NULL); 8398275SEric Cheng ASSERT(RW_WRITE_HELD(&port->maccl_rwlock)); 8408275SEric Cheng vids = port->vids; 8418275SEric Cheng nvids = port->nvids; 8425373Sraghuram } else { 8438275SEric Cheng ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock)); 8448275SEric Cheng vids = vswp->vids; 8458275SEric Cheng nvids = vswp->nvids; 8468275SEric Cheng } 8478275SEric Cheng 8488275SEric Cheng /* First clear the callback */ 8498275SEric Cheng if (type == VSW_LOCALDEV) { 8508275SEric Cheng mch = vswp->mch; 8518275SEric Cheng } else if (type == VSW_VNETPORT) { 8528275SEric Cheng mch = port->p_mch; 8538275SEric Cheng } 8548275SEric Cheng 8558275SEric Cheng 8568275SEric Cheng if (mch == NULL) { 8578275SEric Cheng return; 8588275SEric Cheng } 8598275SEric Cheng 8608275SEric Cheng mac_rx_clear(mch); 8618275SEric Cheng 8628275SEric Cheng /* Remove vlans */ 8638275SEric Cheng vsw_mac_remove_vlans(mch, vids, nvids); 8648275SEric Cheng 8658275SEric Cheng if ((type == VSW_LOCALDEV) && (vswp->addr_set == B_TRUE)) { 8668275SEric Cheng (void) mac_unicast_remove(vswp->mch, vswp->muh); 8678275SEric Cheng vswp->muh = NULL; 8688275SEric Cheng D2(vswp, "removed vsw interface mac-addr from " 8698275SEric Cheng "the device %s", vswp->physname); 8708275SEric Cheng vswp->addr_set = B_FALSE; 8718275SEric Cheng 8728275SEric Cheng } else if ((type == VSW_VNETPORT) && (port->addr_set == B_TRUE)) { 8738275SEric Cheng (void) mac_unicast_remove(port->p_mch, port->p_muh); 8748275SEric Cheng port->p_muh = NULL; 8758275SEric Cheng D2(vswp, "removed port(0x%p) mac-addr from " 8768275SEric Cheng "the device %s", port, vswp->physname); 8778275SEric Cheng port->addr_set = B_FALSE; 8785373Sraghuram } 8795373Sraghuram 8805373Sraghuram D1(vswp, "%s: exit", __func__); 8815373Sraghuram } 8825373Sraghuram 8835373Sraghuram /* 8848275SEric Cheng * receive callback routine for vsw interface. Invoked by MAC layer when there 8858275SEric Cheng * are pkts being passed up from physical device for this vsw interface. 8865373Sraghuram */ 8878275SEric Cheng /* ARGSUSED */ 8888275SEric Cheng static void 8898275SEric Cheng vsw_if_rx_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp, 8908275SEric Cheng boolean_t loopback) 8915373Sraghuram { 8928275SEric Cheng _NOTE(ARGUNUSED(mrh)) 8935373Sraghuram 8948275SEric Cheng vsw_t *vswp = (vsw_t *)arg; 8958275SEric Cheng mblk_t *mpt; 8968275SEric Cheng int count; 8975373Sraghuram 8988275SEric Cheng ASSERT(vswp != NULL); 8995373Sraghuram 9005373Sraghuram D1(vswp, "%s: enter", __func__); 9015373Sraghuram 9028275SEric Cheng READ_ENTER(&vswp->if_lockrw); 9038275SEric Cheng if (vswp->if_state & VSW_IF_UP) { 9048275SEric Cheng RW_EXIT(&vswp->if_lockrw); 9058275SEric Cheng count = vsw_vlan_frame_untag(vswp, VSW_LOCALDEV, &mp, &mpt); 9068275SEric Cheng if (count != 0) { 9078275SEric Cheng mac_rx(vswp->if_mh, NULL, mp); 9088275SEric Cheng } 9098275SEric Cheng } else { 9108275SEric Cheng RW_EXIT(&vswp->if_lockrw); 9118275SEric Cheng freemsgchain(mp); 9125373Sraghuram } 9135373Sraghuram 9145373Sraghuram D1(vswp, "%s: exit", __func__); 9155373Sraghuram } 9165373Sraghuram 9175373Sraghuram /* 9188275SEric Cheng * receive callback routine for port. Invoked by MAC layer when there 9198275SEric Cheng * are pkts being passed up from physical device for this port. 9205373Sraghuram */ 9218275SEric Cheng /* ARGSUSED */ 9228275SEric Cheng static void 9238275SEric Cheng vsw_port_rx_cb(void *arg, mac_resource_handle_t mrh, mblk_t *mp, 9248275SEric Cheng boolean_t loopback) 9255373Sraghuram { 9268275SEric Cheng _NOTE(ARGUNUSED(mrh)) 9275373Sraghuram 9288275SEric Cheng vsw_t *vswp; 9298275SEric Cheng vsw_port_t *port = arg; 9305373Sraghuram 9318275SEric Cheng ASSERT(port != NULL); 9325373Sraghuram 9338275SEric Cheng vswp = port->p_vswp; 9348275SEric Cheng 9358275SEric Cheng D1(vswp, "vsw_port_rx_cb: enter"); 9365373Sraghuram 9378275SEric Cheng /* 9388275SEric Cheng * Send the packets to the peer directly. 9398275SEric Cheng */ 9408275SEric Cheng (void) vsw_portsend(port, mp); 9415373Sraghuram 9428275SEric Cheng D1(vswp, "vsw_port_rx_cb: exit"); 9435373Sraghuram } 9445373Sraghuram 9455373Sraghuram /* 9468275SEric Cheng * Send a message out over the physical device 9478275SEric Cheng * via the MAC layer. 9485373Sraghuram * 9498275SEric Cheng * Returns any mblks that it was unable to transmit. 9505373Sraghuram */ 9518275SEric Cheng mblk_t * 9528275SEric Cheng vsw_tx_msg(vsw_t *vswp, mblk_t *mp, int caller, vsw_port_t *port) 9535373Sraghuram { 9548275SEric Cheng mac_client_handle_t mch; 9558275SEric Cheng mac_unicast_handle_t muh; 9565373Sraghuram 9578275SEric Cheng READ_MACCL_ENTER(vswp, port, caller); 9585373Sraghuram 9598275SEric Cheng mch = (caller == VSW_LOCALDEV) ? vswp->mch : port->p_mch; 9608275SEric Cheng muh = (caller == VSW_LOCALDEV) ? vswp->muh : port->p_muh; 9615373Sraghuram 9629217SWentao.Yang@Sun.COM if (mch == NULL || muh == NULL) { 9639217SWentao.Yang@Sun.COM RW_MACCL_EXIT(vswp, port, caller); 9649217SWentao.Yang@Sun.COM return (mp); 9658275SEric Cheng } 9665373Sraghuram 9679217SWentao.Yang@Sun.COM /* packets are sent or dropped */ 9689217SWentao.Yang@Sun.COM (void) mac_tx(mch, mp, 0, MAC_DROP_ON_NO_DESC, NULL); 9698275SEric Cheng RW_MACCL_EXIT(vswp, port, caller); 9708275SEric Cheng return (NULL); 9715373Sraghuram } 9725373Sraghuram 9735373Sraghuram /* 9748275SEric Cheng * vsw_port_mac_reconfig -- Cleanup and close the MAC client 9758275SEric Cheng * and reopen and re-configure the MAC client with new flags etc. 9768275SEric Cheng * This function is useful for two different purposes: 9778275SEric Cheng * 1) To update the MAC client with new vlan-ids. This is done 9788275SEric Cheng * by freeing the existing vlan-ids and reopen with the new 9798275SEric Cheng * vlan-ids. 9808275SEric Cheng * 9818275SEric Cheng * 2) If the Hybrid mode status of a port changes, then the 9828275SEric Cheng * MAC client need to be closed and re-opened, otherwise, 9838275SEric Cheng * Share related resources may not be freed(hybird mode disabled) 9848275SEric Cheng * or assigned(hybrid mode enabled). To accomplish this, 9858275SEric Cheng * this function simply closes and reopens the MAC client. 9868275SEric Cheng * The reopen will result in using the flags based on the 9878275SEric Cheng * new hybrid mode of the port. 9885373Sraghuram */ 9898275SEric Cheng void 9908275SEric Cheng vsw_port_mac_reconfig(vsw_port_t *portp, boolean_t update_vlans, 9918275SEric Cheng uint16_t new_pvid, vsw_vlanid_t *new_vids, int new_nvids) 9925373Sraghuram { 9938275SEric Cheng vsw_t *vswp = portp->p_vswp; 9948275SEric Cheng int rv; 9955373Sraghuram 9965373Sraghuram D1(vswp, "%s: enter", __func__); 9975373Sraghuram /* 9988275SEric Cheng * Remove the multi-cast addresses, unicast address 9998275SEric Cheng * and close the mac-client. 10005373Sraghuram */ 10018275SEric Cheng mutex_enter(&vswp->mac_lock); 10028275SEric Cheng WRITE_ENTER(&portp->maccl_rwlock); 10038275SEric Cheng vsw_mac_multicast_remove_all(vswp, portp, VSW_VNETPORT); 10048275SEric Cheng vsw_unset_hw(vswp, portp, VSW_VNETPORT); 10058275SEric Cheng vsw_maccl_close(vswp, portp, VSW_VNETPORT); 10065373Sraghuram 10078275SEric Cheng if (update_vlans == B_TRUE) { 10088275SEric Cheng if (portp->nvids != 0) { 10098275SEric Cheng kmem_free(portp->vids, 10108275SEric Cheng sizeof (vsw_vlanid_t) * portp->nvids); 10118275SEric Cheng portp->vids = NULL; 10128275SEric Cheng portp->nvids = 0; 10135373Sraghuram } 10148275SEric Cheng portp->vids = new_vids; 10158275SEric Cheng portp->nvids = new_nvids; 10168275SEric Cheng portp->pvid = new_pvid; 10175373Sraghuram } 10185373Sraghuram 10195373Sraghuram /* 10208275SEric Cheng * Now re-open the mac-client and 10218275SEric Cheng * configure unicast addr and multicast addrs. 10225373Sraghuram */ 10238275SEric Cheng rv = vsw_maccl_open(vswp, portp, VSW_VNETPORT); 10248275SEric Cheng if (rv != 0) { 10258275SEric Cheng goto recret; 10265373Sraghuram } 10275373Sraghuram 10288275SEric Cheng if (vsw_set_hw(vswp, portp, VSW_VNETPORT)) { 10298275SEric Cheng cmn_err(CE_NOTE, "!vsw%d: port:%d failed to " 10308275SEric Cheng "set unicast address\n", vswp->instance, portp->p_instance); 10318275SEric Cheng goto recret; 10328275SEric Cheng } 10335373Sraghuram 10348275SEric Cheng vsw_mac_multicast_add_all(vswp, portp, VSW_VNETPORT); 10355373Sraghuram 10368275SEric Cheng recret: 10378275SEric Cheng RW_EXIT(&portp->maccl_rwlock); 10388275SEric Cheng mutex_exit(&vswp->mac_lock); 10395373Sraghuram D1(vswp, "%s: exit", __func__); 10405373Sraghuram } 10415373Sraghuram 10425373Sraghuram /* 10438275SEric Cheng * vsw_if_mac_reconfig -- Reconfigure the vsw interfaace's mac-client 10448275SEric Cheng * by closing and re-opening it. This function is used handle the 10458275SEric Cheng * following two cases: 10465373Sraghuram * 10478275SEric Cheng * 1) Handle the MAC address change for the interface. 10488275SEric Cheng * 2) Handle vlan update. 10495373Sraghuram */ 10508275SEric Cheng void 10518275SEric Cheng vsw_if_mac_reconfig(vsw_t *vswp, boolean_t update_vlans, 10528275SEric Cheng uint16_t new_pvid, vsw_vlanid_t *new_vids, int new_nvids) 10535373Sraghuram { 10548275SEric Cheng int rv; 10555373Sraghuram 10568275SEric Cheng D1(vswp, "%s: enter", __func__); 10578275SEric Cheng /* 10588275SEric Cheng * Remove the multi-cast addresses, unicast address 10598275SEric Cheng * and close the mac-client. 10608275SEric Cheng */ 10618275SEric Cheng mutex_enter(&vswp->mac_lock); 10628275SEric Cheng WRITE_ENTER(&vswp->maccl_rwlock); 10638275SEric Cheng vsw_mac_multicast_remove_all(vswp, NULL, VSW_LOCALDEV); 10648275SEric Cheng vsw_unset_hw(vswp, NULL, VSW_LOCALDEV); 10658275SEric Cheng vsw_maccl_close(vswp, NULL, VSW_LOCALDEV); 10665373Sraghuram 10678275SEric Cheng if (update_vlans == B_TRUE) { 10688275SEric Cheng if (vswp->nvids != 0) { 10698275SEric Cheng kmem_free(vswp->vids, 10708275SEric Cheng sizeof (vsw_vlanid_t) * vswp->nvids); 10718275SEric Cheng vswp->vids = NULL; 10728275SEric Cheng vswp->nvids = 0; 10738275SEric Cheng } 10748275SEric Cheng vswp->vids = new_vids; 10758275SEric Cheng vswp->nvids = new_nvids; 10768275SEric Cheng vswp->pvid = new_pvid; 10778275SEric Cheng } 10785373Sraghuram 10798275SEric Cheng /* 10808275SEric Cheng * Now re-open the mac-client and 10818275SEric Cheng * configure unicast addr and multicast addrs. 10828275SEric Cheng */ 10838275SEric Cheng rv = vsw_maccl_open(vswp, NULL, VSW_LOCALDEV); 10848275SEric Cheng if (rv != 0) { 10858275SEric Cheng goto ifrecret; 10868275SEric Cheng } 10875373Sraghuram 10888275SEric Cheng if (vsw_set_hw(vswp, NULL, VSW_LOCALDEV)) { 10898275SEric Cheng cmn_err(CE_NOTE, "!vsw%d:failed to set unicast address\n", 10908275SEric Cheng vswp->instance); 10918275SEric Cheng goto ifrecret; 10928275SEric Cheng } 10938275SEric Cheng 10948275SEric Cheng vsw_mac_multicast_add_all(vswp, NULL, VSW_LOCALDEV); 10958275SEric Cheng 10968275SEric Cheng ifrecret: 10978275SEric Cheng RW_EXIT(&vswp->maccl_rwlock); 10988275SEric Cheng mutex_exit(&vswp->mac_lock); 10998275SEric Cheng D1(vswp, "%s: exit", __func__); 11005373Sraghuram } 11015373Sraghuram 11025373Sraghuram /* 11038275SEric Cheng * vsw_mac_port_reconfig_vlans -- Reconfigure a port to handle 11048275SEric Cheng * vlan configuration update. As the removal of the last unicast-address,vid 11058275SEric Cheng * from the MAC client results in releasing all resources, it expects 11068275SEric Cheng * no Shares to be associated with such MAC client. 11075373Sraghuram * 11088275SEric Cheng * To handle vlan configuration update for a port that already has 11098275SEric Cheng * a Share bound, then we need to free that share prior to reconfiguration. 11108275SEric Cheng * Initiate the hybrdIO setup again after the completion of reconfiguration. 11115373Sraghuram */ 11128275SEric Cheng void 11138275SEric Cheng vsw_mac_port_reconfig_vlans(vsw_port_t *portp, uint16_t new_pvid, 11148275SEric Cheng vsw_vlanid_t *new_vids, int new_nvids) 11155373Sraghuram { 11168275SEric Cheng /* 11178275SEric Cheng * As the reconfiguration involves the close of 11188275SEric Cheng * mac client, cleanup HybridIO and later restart 11198275SEric Cheng * HybridIO setup again. 11208275SEric Cheng */ 11218275SEric Cheng if (portp->p_hio_enabled == B_TRUE) { 11228275SEric Cheng vsw_hio_stop_port(portp); 11238275SEric Cheng } 11248275SEric Cheng vsw_port_mac_reconfig(portp, B_TRUE, new_pvid, new_vids, new_nvids); 11258275SEric Cheng if (portp->p_hio_enabled == B_TRUE) { 11268275SEric Cheng /* reset to setup the HybridIO again. */ 11278275SEric Cheng vsw_hio_port_reset(portp, B_FALSE); 11288275SEric Cheng } 11298275SEric Cheng } 11308275SEric Cheng 11318275SEric Cheng /* Add vlans to MAC client */ 11328275SEric Cheng static void 11338275SEric Cheng vsw_mac_add_vlans(vsw_t *vswp, mac_client_handle_t mch, uint8_t *macaddr, 11348275SEric Cheng uint16_t flags, vsw_vlanid_t *vids, int nvids) 11358275SEric Cheng { 11368275SEric Cheng vsw_vlanid_t *vidp; 11378275SEric Cheng mac_diag_t diag; 11388275SEric Cheng int rv; 11398275SEric Cheng int i; 11405373Sraghuram 11419024SVenu.Iyer@Sun.COM flags |= MAC_UNICAST_TAG_DISABLE | MAC_UNICAST_STRIP_DISABLE; 11429024SVenu.Iyer@Sun.COM 11438275SEric Cheng /* Add vlans to the MAC layer */ 11448275SEric Cheng for (i = 0; i < nvids; i++) { 11458275SEric Cheng vidp = &vids[i]; 11468275SEric Cheng 11478275SEric Cheng if (vidp->vl_set == B_TRUE) { 11488275SEric Cheng continue; 11498275SEric Cheng } 11505373Sraghuram 11518275SEric Cheng rv = mac_unicast_add(mch, macaddr, flags, 11528275SEric Cheng &vidp->vl_muh, vidp->vl_vid, &diag); 11538275SEric Cheng if (rv != 0) { 11548275SEric Cheng cmn_err(CE_WARN, "vsw%d: Failed to program" 11558275SEric Cheng "macaddr,vid(%s, %d) err=%d", 11568275SEric Cheng vswp->instance, ether_sprintf((void *)macaddr), 11578275SEric Cheng vidp->vl_vid, rv); 11588275SEric Cheng } else { 11598275SEric Cheng vidp->vl_set = B_TRUE; 11608275SEric Cheng D2(vswp, "%s:programmed macaddr(%s) vid(%d) " 11618275SEric Cheng "into device %s", __func__, 11628275SEric Cheng ether_sprintf((void *)macaddr), 11638275SEric Cheng vidp->vl_vid, vswp->physname); 11648275SEric Cheng } 11655373Sraghuram } 11668275SEric Cheng } 11678275SEric Cheng 11688275SEric Cheng /* Remove vlans from the MAC client */ 11698275SEric Cheng static void 11708275SEric Cheng vsw_mac_remove_vlans(mac_client_handle_t mch, vsw_vlanid_t *vids, int nvids) 11718275SEric Cheng { 11728275SEric Cheng int i; 11738275SEric Cheng vsw_vlanid_t *vidp; 11745373Sraghuram 11758275SEric Cheng for (i = 0; i < nvids; i++) { 11768275SEric Cheng vidp = &vids[i]; 11778275SEric Cheng if (vidp->vl_set == B_FALSE) { 11788275SEric Cheng continue; 11798275SEric Cheng } 11808275SEric Cheng mac_unicast_remove(mch, vidp->vl_muh); 11818275SEric Cheng vidp->vl_set = B_FALSE; 11828275SEric Cheng } 11835373Sraghuram } 11847027Ssb155480 11857027Ssb155480 #define ARH_FIXED_LEN 8 /* Length of fixed part of ARP header(see arp.h) */ 11867027Ssb155480 11877027Ssb155480 /* 11887027Ssb155480 * Send a gratuitous RARP packet to notify the physical switch to update its 11897027Ssb155480 * Layer2 forwarding table for the given mac address. This is done to allow the 11907027Ssb155480 * switch to quickly learn the macaddr-port association when a guest is live 11917027Ssb155480 * migrated or when vsw's physical device is changed dynamically. Any protocol 11927027Ssb155480 * packet would serve this purpose, but we choose RARP, as it allows us to 11937027Ssb155480 * accomplish this within L2 (ie, no need to specify IP addr etc in the packet) 11947027Ssb155480 * The macaddr of vnet is retained across migration. Hence, we don't need to 11957027Ssb155480 * update the arp cache of other hosts within the broadcast domain. Note that 11967027Ssb155480 * it is harmless to send these RARP packets during normal port attach of a 11977027Ssb155480 * client vnet. This can can be turned off if needed, by setting 11987027Ssb155480 * vsw_publish_macaddr_count to zero in /etc/system. 11997027Ssb155480 */ 12007027Ssb155480 void 12018275SEric Cheng vsw_publish_macaddr(vsw_t *vswp, vsw_port_t *portp) 12027027Ssb155480 { 12037027Ssb155480 mblk_t *mp; 12047027Ssb155480 mblk_t *bp; 12057027Ssb155480 struct arphdr *arh; 12067027Ssb155480 struct ether_header *ehp; 12077027Ssb155480 int count = 0; 12087027Ssb155480 int plen = 4; 12097027Ssb155480 uint8_t *cp; 12107027Ssb155480 12117027Ssb155480 mp = allocb(ETHERMIN, BPRI_MED); 12127027Ssb155480 if (mp == NULL) { 12137027Ssb155480 return; 12147027Ssb155480 } 12157027Ssb155480 12167027Ssb155480 /* Initialize eth header */ 12177027Ssb155480 ehp = (struct ether_header *)mp->b_rptr; 12187027Ssb155480 bcopy(ðerbroadcastaddr, &ehp->ether_dhost, ETHERADDRL); 12198275SEric Cheng bcopy(&portp->p_macaddr, &ehp->ether_shost, ETHERADDRL); 12207027Ssb155480 ehp->ether_type = htons(ETHERTYPE_REVARP); 12217027Ssb155480 12227027Ssb155480 /* Initialize arp packet */ 12237027Ssb155480 arh = (struct arphdr *)(mp->b_rptr + sizeof (struct ether_header)); 12247027Ssb155480 cp = (uint8_t *)arh; 12257027Ssb155480 12267027Ssb155480 arh->ar_hrd = htons(ARPHRD_ETHER); /* Hardware type: ethernet */ 12277027Ssb155480 arh->ar_pro = htons(ETHERTYPE_IP); /* Protocol type: IP */ 12287027Ssb155480 arh->ar_hln = ETHERADDRL; /* Length of hardware address: 6 */ 12297027Ssb155480 arh->ar_pln = plen; /* Length of protocol address: 4 */ 12307027Ssb155480 arh->ar_op = htons(REVARP_REQUEST); /* Opcode: REVARP Request */ 12317027Ssb155480 12327027Ssb155480 cp += ARH_FIXED_LEN; 12337027Ssb155480 12347027Ssb155480 /* Sender's hardware address and protocol address */ 12358275SEric Cheng bcopy(&portp->p_macaddr, cp, ETHERADDRL); 12367027Ssb155480 cp += ETHERADDRL; 12377027Ssb155480 bzero(cp, plen); /* INADDR_ANY */ 12387027Ssb155480 cp += plen; 12397027Ssb155480 12407027Ssb155480 /* Target hardware address and protocol address */ 12418275SEric Cheng bcopy(&portp->p_macaddr, cp, ETHERADDRL); 12427027Ssb155480 cp += ETHERADDRL; 12437027Ssb155480 bzero(cp, plen); /* INADDR_ANY */ 12447027Ssb155480 cp += plen; 12457027Ssb155480 12467027Ssb155480 mp->b_wptr += ETHERMIN; /* total size is 42; round up to ETHERMIN */ 12477027Ssb155480 12487027Ssb155480 for (count = 0; count < vsw_publish_macaddr_count; count++) { 12497027Ssb155480 12507027Ssb155480 bp = dupmsg(mp); 12517027Ssb155480 if (bp == NULL) { 12527027Ssb155480 continue; 12537027Ssb155480 } 12547027Ssb155480 12557027Ssb155480 /* transmit the packet */ 12568275SEric Cheng bp = vsw_tx_msg(vswp, bp, VSW_VNETPORT, portp); 12577027Ssb155480 if (bp != NULL) { 12587027Ssb155480 freemsg(bp); 12597027Ssb155480 } 12607027Ssb155480 } 12617027Ssb155480 12627027Ssb155480 freemsg(mp); 12637027Ssb155480 } 12647529SSriharsha.Basavapatna@Sun.COM 12657529SSriharsha.Basavapatna@Sun.COM static void 12667529SSriharsha.Basavapatna@Sun.COM vsw_mac_set_mtu(vsw_t *vswp, uint32_t mtu) 12677529SSriharsha.Basavapatna@Sun.COM { 12688275SEric Cheng uint_t mtu_orig; 12698275SEric Cheng int rv; 12707529SSriharsha.Basavapatna@Sun.COM 12718275SEric Cheng rv = mac_set_mtu(vswp->mh, mtu, &mtu_orig); 12727529SSriharsha.Basavapatna@Sun.COM if (rv != 0) { 12737529SSriharsha.Basavapatna@Sun.COM cmn_err(CE_NOTE, 12747529SSriharsha.Basavapatna@Sun.COM "!vsw%d: Unable to set the mtu:%d, in the " 12757529SSriharsha.Basavapatna@Sun.COM "physical device:%s\n", 12767529SSriharsha.Basavapatna@Sun.COM vswp->instance, mtu, vswp->physname); 12778275SEric Cheng return; 12787529SSriharsha.Basavapatna@Sun.COM } 12798275SEric Cheng 12808275SEric Cheng /* save the original mtu of physdev to reset it back later if needed */ 12818275SEric Cheng vswp->mtu_physdev_orig = mtu_orig; 12827529SSriharsha.Basavapatna@Sun.COM } 12839336SSriharsha.Basavapatna@Sun.COM 12849336SSriharsha.Basavapatna@Sun.COM /* 12859336SSriharsha.Basavapatna@Sun.COM * Register a callback with underlying mac layer for notifications. 12869336SSriharsha.Basavapatna@Sun.COM * We are currently interested in only link-state events. 12879336SSriharsha.Basavapatna@Sun.COM */ 12889336SSriharsha.Basavapatna@Sun.COM static int 12899336SSriharsha.Basavapatna@Sun.COM vsw_notify_add(vsw_t *vswp) 12909336SSriharsha.Basavapatna@Sun.COM { 12919336SSriharsha.Basavapatna@Sun.COM mac_notify_handle_t mnh; 12929336SSriharsha.Basavapatna@Sun.COM uint32_t note; 12939336SSriharsha.Basavapatna@Sun.COM 12949336SSriharsha.Basavapatna@Sun.COM /* 12959336SSriharsha.Basavapatna@Sun.COM * Check if the underlying MAC supports link update notification. 12969336SSriharsha.Basavapatna@Sun.COM */ 12979336SSriharsha.Basavapatna@Sun.COM note = mac_no_notification(vswp->mh); 12989336SSriharsha.Basavapatna@Sun.COM if ((note & (DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN)) != 0) { 12999336SSriharsha.Basavapatna@Sun.COM vswp->phys_no_link_update = B_TRUE; 13009336SSriharsha.Basavapatna@Sun.COM } else { 13019336SSriharsha.Basavapatna@Sun.COM vswp->phys_no_link_update = B_FALSE; 13029336SSriharsha.Basavapatna@Sun.COM } 13039336SSriharsha.Basavapatna@Sun.COM 13049336SSriharsha.Basavapatna@Sun.COM /* 13059336SSriharsha.Basavapatna@Sun.COM * Read the current link state of the device and cache it. 13069336SSriharsha.Basavapatna@Sun.COM */ 13079336SSriharsha.Basavapatna@Sun.COM vswp->phys_link_state = vswp->phys_no_link_update ? LINK_STATE_UP : 13089336SSriharsha.Basavapatna@Sun.COM mac_stat_get(vswp->mh, MAC_STAT_LINK_STATE); 13099336SSriharsha.Basavapatna@Sun.COM 13109336SSriharsha.Basavapatna@Sun.COM /* 13119336SSriharsha.Basavapatna@Sun.COM * Add notify callback function, if link update is supported. 13129336SSriharsha.Basavapatna@Sun.COM */ 13139336SSriharsha.Basavapatna@Sun.COM if (vswp->phys_no_link_update == B_TRUE) { 13149336SSriharsha.Basavapatna@Sun.COM return (0); 13159336SSriharsha.Basavapatna@Sun.COM } 13169336SSriharsha.Basavapatna@Sun.COM 13179336SSriharsha.Basavapatna@Sun.COM mnh = mac_notify_add(vswp->mh, vsw_notify_cb, vswp); 13189336SSriharsha.Basavapatna@Sun.COM if (mnh == 0) { 13199336SSriharsha.Basavapatna@Sun.COM /* failed */ 13209336SSriharsha.Basavapatna@Sun.COM return (1); 13219336SSriharsha.Basavapatna@Sun.COM } 13229336SSriharsha.Basavapatna@Sun.COM 13239336SSriharsha.Basavapatna@Sun.COM vswp->mnh = mnh; 13249336SSriharsha.Basavapatna@Sun.COM return (0); 13259336SSriharsha.Basavapatna@Sun.COM } 13269336SSriharsha.Basavapatna@Sun.COM 13279336SSriharsha.Basavapatna@Sun.COM /* 13289336SSriharsha.Basavapatna@Sun.COM * Remove notify callback. 13299336SSriharsha.Basavapatna@Sun.COM */ 13309336SSriharsha.Basavapatna@Sun.COM static int 13319336SSriharsha.Basavapatna@Sun.COM vsw_notify_rem(vsw_t *vswp) 13329336SSriharsha.Basavapatna@Sun.COM { 13339336SSriharsha.Basavapatna@Sun.COM int rv; 13349336SSriharsha.Basavapatna@Sun.COM 13359336SSriharsha.Basavapatna@Sun.COM rv = mac_notify_remove(vswp->mnh, B_FALSE); 13369336SSriharsha.Basavapatna@Sun.COM return (rv); 13379336SSriharsha.Basavapatna@Sun.COM } 13389336SSriharsha.Basavapatna@Sun.COM 13399336SSriharsha.Basavapatna@Sun.COM /* 13409336SSriharsha.Basavapatna@Sun.COM * Notification callback invoked by the MAC service 13419336SSriharsha.Basavapatna@Sun.COM * module. Note that we process only link state updates. 13429336SSriharsha.Basavapatna@Sun.COM */ 13439336SSriharsha.Basavapatna@Sun.COM static void 13449336SSriharsha.Basavapatna@Sun.COM vsw_notify_cb(void *arg, mac_notify_type_t type) 13459336SSriharsha.Basavapatna@Sun.COM { 13469336SSriharsha.Basavapatna@Sun.COM vsw_t *vswp = arg; 13479336SSriharsha.Basavapatna@Sun.COM 13489336SSriharsha.Basavapatna@Sun.COM switch (type) { 13499336SSriharsha.Basavapatna@Sun.COM 13509336SSriharsha.Basavapatna@Sun.COM case MAC_NOTE_LINK: 13519336SSriharsha.Basavapatna@Sun.COM vsw_notify_link(vswp); 13529336SSriharsha.Basavapatna@Sun.COM break; 13539336SSriharsha.Basavapatna@Sun.COM 13549336SSriharsha.Basavapatna@Sun.COM default: 13559336SSriharsha.Basavapatna@Sun.COM break; 13569336SSriharsha.Basavapatna@Sun.COM 13579336SSriharsha.Basavapatna@Sun.COM } 13589336SSriharsha.Basavapatna@Sun.COM } 13599336SSriharsha.Basavapatna@Sun.COM 13609336SSriharsha.Basavapatna@Sun.COM /* 13619336SSriharsha.Basavapatna@Sun.COM * Invoked upon receiving a MAC_NOTE_LINK 13629336SSriharsha.Basavapatna@Sun.COM * notification for the underlying physical device. 13639336SSriharsha.Basavapatna@Sun.COM */ 13649336SSriharsha.Basavapatna@Sun.COM static void 13659336SSriharsha.Basavapatna@Sun.COM vsw_notify_link(vsw_t *vswp) 13669336SSriharsha.Basavapatna@Sun.COM { 13679336SSriharsha.Basavapatna@Sun.COM link_state_t link_state; 13689336SSriharsha.Basavapatna@Sun.COM 13699336SSriharsha.Basavapatna@Sun.COM /* link state change notification */ 13709336SSriharsha.Basavapatna@Sun.COM link_state = mac_stat_get(vswp->mh, MAC_STAT_LINK_STATE); 13719336SSriharsha.Basavapatna@Sun.COM 13729336SSriharsha.Basavapatna@Sun.COM if (vswp->phys_link_state != link_state) { 13739336SSriharsha.Basavapatna@Sun.COM D3(vswp, "%s: phys_link_state(%d)\n", 13749336SSriharsha.Basavapatna@Sun.COM __func__, vswp->phys_link_state); 13759336SSriharsha.Basavapatna@Sun.COM 13769336SSriharsha.Basavapatna@Sun.COM vswp->phys_link_state = link_state; 13779336SSriharsha.Basavapatna@Sun.COM vsw_physlink_state_update(vswp); 13789336SSriharsha.Basavapatna@Sun.COM } 13799336SSriharsha.Basavapatna@Sun.COM } 1380*10795SWentao.Yang@Sun.COM 1381*10795SWentao.Yang@Sun.COM /* 1382*10795SWentao.Yang@Sun.COM * Configure the bandwidth limit on the vsw or vnet devices via the MAC layer. 1383*10795SWentao.Yang@Sun.COM * Note that bandwidth limit is not supported on a HybridIO enabled 1384*10795SWentao.Yang@Sun.COM * vnet, as the HybridIO assigns a specific unit of hardware resource 1385*10795SWentao.Yang@Sun.COM * that cannot be changed to limit bandwidth. 1386*10795SWentao.Yang@Sun.COM */ 1387*10795SWentao.Yang@Sun.COM static void 1388*10795SWentao.Yang@Sun.COM vsw_maccl_set_bandwidth(vsw_t *vswp, vsw_port_t *port, int type, uint64_t maxbw) 1389*10795SWentao.Yang@Sun.COM { 1390*10795SWentao.Yang@Sun.COM int rv = 0; 1391*10795SWentao.Yang@Sun.COM uint64_t *bw; 1392*10795SWentao.Yang@Sun.COM mac_resource_props_t mrp; 1393*10795SWentao.Yang@Sun.COM mac_client_handle_t mch; 1394*10795SWentao.Yang@Sun.COM 1395*10795SWentao.Yang@Sun.COM ASSERT((type == VSW_LOCALDEV) || (type == VSW_VNETPORT)); 1396*10795SWentao.Yang@Sun.COM 1397*10795SWentao.Yang@Sun.COM if (type == VSW_VNETPORT) { 1398*10795SWentao.Yang@Sun.COM ASSERT(RW_WRITE_HELD(&port->maccl_rwlock)); 1399*10795SWentao.Yang@Sun.COM mch = port->p_mch; 1400*10795SWentao.Yang@Sun.COM bw = &port->p_bandwidth; 1401*10795SWentao.Yang@Sun.COM } else { 1402*10795SWentao.Yang@Sun.COM ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock)); 1403*10795SWentao.Yang@Sun.COM mch = vswp->mch; 1404*10795SWentao.Yang@Sun.COM bw = &vswp->bandwidth; 1405*10795SWentao.Yang@Sun.COM } 1406*10795SWentao.Yang@Sun.COM 1407*10795SWentao.Yang@Sun.COM if (mch == NULL) { 1408*10795SWentao.Yang@Sun.COM return; 1409*10795SWentao.Yang@Sun.COM } 1410*10795SWentao.Yang@Sun.COM 1411*10795SWentao.Yang@Sun.COM if (maxbw >= MRP_MAXBW_MINVAL || maxbw == 0) { 1412*10795SWentao.Yang@Sun.COM bzero(&mrp, sizeof (mac_resource_props_t)); 1413*10795SWentao.Yang@Sun.COM if (maxbw == 0) { 1414*10795SWentao.Yang@Sun.COM mrp.mrp_maxbw = MRP_MAXBW_RESETVAL; 1415*10795SWentao.Yang@Sun.COM } else { 1416*10795SWentao.Yang@Sun.COM mrp.mrp_maxbw = maxbw; 1417*10795SWentao.Yang@Sun.COM } 1418*10795SWentao.Yang@Sun.COM mrp.mrp_mask |= MRP_MAXBW; 1419*10795SWentao.Yang@Sun.COM 1420*10795SWentao.Yang@Sun.COM rv = mac_client_set_resources(mch, &mrp); 1421*10795SWentao.Yang@Sun.COM if (rv != 0) { 1422*10795SWentao.Yang@Sun.COM if (type == VSW_VNETPORT) { 1423*10795SWentao.Yang@Sun.COM cmn_err(CE_NOTE, "!port%d: cannot set " 1424*10795SWentao.Yang@Sun.COM "bandwidth limit to (%ld), error(%d)\n", 1425*10795SWentao.Yang@Sun.COM port->p_instance, maxbw, rv); 1426*10795SWentao.Yang@Sun.COM } else { 1427*10795SWentao.Yang@Sun.COM cmn_err(CE_NOTE, "!vsw%d: cannot set " 1428*10795SWentao.Yang@Sun.COM "bandwidth limit to (%ld), error(%d)\n", 1429*10795SWentao.Yang@Sun.COM vswp->instance, maxbw, rv); 1430*10795SWentao.Yang@Sun.COM } 1431*10795SWentao.Yang@Sun.COM } else { 1432*10795SWentao.Yang@Sun.COM /* 1433*10795SWentao.Yang@Sun.COM * update with successfully configured bandwidth. 1434*10795SWentao.Yang@Sun.COM */ 1435*10795SWentao.Yang@Sun.COM *bw = maxbw; 1436*10795SWentao.Yang@Sun.COM } 1437*10795SWentao.Yang@Sun.COM } 1438*10795SWentao.Yang@Sun.COM } 1439