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