1da14cebeSEric Cheng /* 2da14cebeSEric Cheng * CDDL HEADER START 3da14cebeSEric Cheng * 4da14cebeSEric Cheng * The contents of this file are subject to the terms of the 5da14cebeSEric Cheng * Common Development and Distribution License (the "License"). 6da14cebeSEric Cheng * You may not use this file except in compliance with the License. 7da14cebeSEric Cheng * 8da14cebeSEric Cheng * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da14cebeSEric Cheng * or http://www.opensolaris.org/os/licensing. 10da14cebeSEric Cheng * See the License for the specific language governing permissions 11da14cebeSEric Cheng * and limitations under the License. 12da14cebeSEric Cheng * 13da14cebeSEric Cheng * When distributing Covered Code, include this CDDL HEADER in each 14da14cebeSEric Cheng * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da14cebeSEric Cheng * If applicable, add the following below this CDDL HEADER, with the 16da14cebeSEric Cheng * fields enclosed by brackets "[]" replaced with your own identifying 17da14cebeSEric Cheng * information: Portions Copyright [yyyy] [name of copyright owner] 18da14cebeSEric Cheng * 19da14cebeSEric Cheng * CDDL HEADER END 20da14cebeSEric Cheng */ 21da14cebeSEric Cheng 22da14cebeSEric Cheng /* 235adf34bdSRajagopal Kunhappan * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 24a776d98eSRobert Mustacchi * Copyright (c) 2014, Joyent, Inc. All rights reserved. 25*74d6c910SAndrew Stormont * Copyright 2017 RackTop Systems. 26da14cebeSEric Cheng */ 27da14cebeSEric Cheng 28da14cebeSEric Cheng /* 29da14cebeSEric Cheng * - General Introduction: 30da14cebeSEric Cheng * 31da14cebeSEric Cheng * This file contains the implementation of the MAC client kernel 32da14cebeSEric Cheng * API and related code. The MAC client API allows a kernel module 33da14cebeSEric Cheng * to gain access to a MAC instance (physical NIC, link aggregation, etc). 34da14cebeSEric Cheng * It allows a MAC client to associate itself with a MAC address, 35da14cebeSEric Cheng * VLANs, callback functions for data traffic and for promiscuous mode. 36da14cebeSEric Cheng * The MAC client API is also used to specify the properties associated 37da14cebeSEric Cheng * with a MAC client, such as bandwidth limits, priority, CPUS, etc. 38da14cebeSEric Cheng * These properties are further used to determine the hardware resources 39da14cebeSEric Cheng * to allocate to the various MAC clients. 40da14cebeSEric Cheng * 41da14cebeSEric Cheng * - Primary MAC clients: 42da14cebeSEric Cheng * 43da14cebeSEric Cheng * The MAC client API refers to "primary MAC clients". A primary MAC 44da14cebeSEric Cheng * client is a client which "owns" the primary MAC address of 45da14cebeSEric Cheng * the underlying MAC instance. The primary MAC address is called out 46da14cebeSEric Cheng * since it is associated with specific semantics: the primary MAC 47da14cebeSEric Cheng * address is the MAC address which is assigned to the IP interface 48da14cebeSEric Cheng * when it is plumbed, and the primary MAC address is assigned 49da14cebeSEric Cheng * to VLAN data-links. The primary address of a MAC instance can 50da14cebeSEric Cheng * also change dynamically from under the MAC client, for example 51da14cebeSEric Cheng * as a result of a change of state of a link aggregation. In that 52da14cebeSEric Cheng * case the MAC layer automatically updates all data-structures which 53da14cebeSEric Cheng * refer to the current value of the primary MAC address. Typical 54da14cebeSEric Cheng * primary MAC clients are dls, aggr, and xnb. A typical non-primary 55da14cebeSEric Cheng * MAC client is the vnic driver. 56da14cebeSEric Cheng * 57da14cebeSEric Cheng * - Virtual Switching: 58da14cebeSEric Cheng * 59da14cebeSEric Cheng * The MAC layer implements a virtual switch between the MAC clients 60da14cebeSEric Cheng * (primary and non-primary) defined on top of the same underlying 61da14cebeSEric Cheng * NIC (physical, link aggregation, etc). The virtual switch is 62da14cebeSEric Cheng * VLAN-aware, i.e. it allows multiple MAC clients to be member 63da14cebeSEric Cheng * of one or more VLANs, and the virtual switch will distribute 64da14cebeSEric Cheng * multicast tagged packets only to the member of the corresponding 65da14cebeSEric Cheng * VLANs. 66da14cebeSEric Cheng * 67da14cebeSEric Cheng * - Upper vs Lower MAC: 68da14cebeSEric Cheng * 69da14cebeSEric Cheng * Creating a VNIC on top of a MAC instance effectively causes 70da14cebeSEric Cheng * two MAC instances to be layered on top of each other, one for 71da14cebeSEric Cheng * the VNIC(s), one for the underlying MAC instance (physical NIC, 72da14cebeSEric Cheng * link aggregation, etc). In the code below we refer to the 73da14cebeSEric Cheng * underlying NIC as the "lower MAC", and we refer to VNICs as 74da14cebeSEric Cheng * the "upper MAC". 75da14cebeSEric Cheng * 76da14cebeSEric Cheng * - Pass-through for VNICs: 77da14cebeSEric Cheng * 78da14cebeSEric Cheng * When VNICs are created on top of an underlying MAC, this causes 79da14cebeSEric Cheng * a layering of two MAC instances. Since the lower MAC already 80da14cebeSEric Cheng * does the switching and demultiplexing to its MAC clients, the 81da14cebeSEric Cheng * upper MAC would simply have to pass packets to the layer below 82da14cebeSEric Cheng * or above it, which would introduce overhead. In order to avoid 83da14cebeSEric Cheng * this overhead, the MAC layer implements a pass-through mechanism 84da14cebeSEric Cheng * for VNICs. When a VNIC opens the lower MAC instance, it saves 85da14cebeSEric Cheng * the MAC client handle it optains from the MAC layer. When a MAC 86da14cebeSEric Cheng * client opens a VNIC (upper MAC), the MAC layer detects that 87da14cebeSEric Cheng * the MAC being opened is a VNIC, and gets the MAC client handle 88da14cebeSEric Cheng * that the VNIC driver obtained from the lower MAC. This exchange 891a41ca23SJerry Jelinek * is done through a private capability between the MAC layer 90da14cebeSEric Cheng * and the VNIC driver. The upper MAC then returns that handle 91da14cebeSEric Cheng * directly to its MAC client. Any operation done by the upper 92da14cebeSEric Cheng * MAC client is now done on the lower MAC client handle, which 93da14cebeSEric Cheng * allows the VNIC driver to be completely bypassed for the 94da14cebeSEric Cheng * performance sensitive data-path. 95da14cebeSEric Cheng * 961a41ca23SJerry Jelinek * - Secondary MACs for VNICs: 971a41ca23SJerry Jelinek * 981a41ca23SJerry Jelinek * VNICs support multiple upper mac clients to enable support for 991a41ca23SJerry Jelinek * multiple MAC addresses on the VNIC. When the VNIC is created the 1001a41ca23SJerry Jelinek * initial mac client is the primary upper mac. Any additional mac 1011a41ca23SJerry Jelinek * clients are secondary macs. These are kept in sync with the primary 1021a41ca23SJerry Jelinek * (for things such as the rx function and resource control settings) 1031a41ca23SJerry Jelinek * using the same private capability interface between the MAC layer 1041a41ca23SJerry Jelinek * and the VNIC layer. 1051a41ca23SJerry Jelinek * 106da14cebeSEric Cheng */ 107da14cebeSEric Cheng 108da14cebeSEric Cheng #include <sys/types.h> 109da14cebeSEric Cheng #include <sys/conf.h> 110da14cebeSEric Cheng #include <sys/id_space.h> 111da14cebeSEric Cheng #include <sys/esunddi.h> 112da14cebeSEric Cheng #include <sys/stat.h> 113da14cebeSEric Cheng #include <sys/mkdev.h> 114da14cebeSEric Cheng #include <sys/stream.h> 115da14cebeSEric Cheng #include <sys/strsun.h> 116da14cebeSEric Cheng #include <sys/strsubr.h> 117da14cebeSEric Cheng #include <sys/dlpi.h> 118da14cebeSEric Cheng #include <sys/modhash.h> 119da14cebeSEric Cheng #include <sys/mac_impl.h> 120da14cebeSEric Cheng #include <sys/mac_client_impl.h> 121da14cebeSEric Cheng #include <sys/mac_soft_ring.h> 1220dc2366fSVenugopal Iyer #include <sys/mac_stat.h> 123da14cebeSEric Cheng #include <sys/dls.h> 124da14cebeSEric Cheng #include <sys/dld.h> 125da14cebeSEric Cheng #include <sys/modctl.h> 126da14cebeSEric Cheng #include <sys/fs/dv_node.h> 127da14cebeSEric Cheng #include <sys/thread.h> 128da14cebeSEric Cheng #include <sys/proc.h> 129da14cebeSEric Cheng #include <sys/callb.h> 130da14cebeSEric Cheng #include <sys/cpuvar.h> 131da14cebeSEric Cheng #include <sys/atomic.h> 132da14cebeSEric Cheng #include <sys/sdt.h> 133da14cebeSEric Cheng #include <sys/mac_flow.h> 134da14cebeSEric Cheng #include <sys/ddi_intr_impl.h> 135da14cebeSEric Cheng #include <sys/disp.h> 136da14cebeSEric Cheng #include <sys/sdt.h> 137da14cebeSEric Cheng #include <sys/vnic.h> 138da14cebeSEric Cheng #include <sys/vnic_impl.h> 139da14cebeSEric Cheng #include <sys/vlan.h> 140da14cebeSEric Cheng #include <inet/ip.h> 141da14cebeSEric Cheng #include <inet/ip6.h> 142da14cebeSEric Cheng #include <sys/exacct.h> 143da14cebeSEric Cheng #include <sys/exacct_impl.h> 144da14cebeSEric Cheng #include <inet/nd.h> 145da14cebeSEric Cheng #include <sys/ethernet.h> 146da14cebeSEric Cheng 147da14cebeSEric Cheng kmem_cache_t *mac_client_impl_cache; 148da14cebeSEric Cheng kmem_cache_t *mac_promisc_impl_cache; 149da14cebeSEric Cheng 150da14cebeSEric Cheng static boolean_t mac_client_single_rcvr(mac_client_impl_t *); 151da14cebeSEric Cheng static flow_entry_t *mac_client_swap_mciflent(mac_client_impl_t *); 152da14cebeSEric Cheng static flow_entry_t *mac_client_get_flow(mac_client_impl_t *, 153da14cebeSEric Cheng mac_unicast_impl_t *); 154da14cebeSEric Cheng static void mac_client_remove_flow_from_list(mac_client_impl_t *, 155da14cebeSEric Cheng flow_entry_t *); 156da14cebeSEric Cheng static void mac_client_add_to_flow_list(mac_client_impl_t *, flow_entry_t *); 157da14cebeSEric Cheng static void mac_rename_flow_names(mac_client_impl_t *, const char *); 158da14cebeSEric Cheng static void mac_virtual_link_update(mac_impl_t *); 1590dc2366fSVenugopal Iyer static int mac_client_datapath_setup(mac_client_impl_t *, uint16_t, 1600dc2366fSVenugopal Iyer uint8_t *, mac_resource_props_t *, boolean_t, mac_unicast_impl_t *); 1610dc2366fSVenugopal Iyer static void mac_client_datapath_teardown(mac_client_handle_t, 1620dc2366fSVenugopal Iyer mac_unicast_impl_t *, flow_entry_t *); 1631a41ca23SJerry Jelinek static int mac_resource_ctl_set(mac_client_handle_t, mac_resource_props_t *); 164da14cebeSEric Cheng 165da14cebeSEric Cheng /* ARGSUSED */ 166da14cebeSEric Cheng static int 167da14cebeSEric Cheng i_mac_client_impl_ctor(void *buf, void *arg, int kmflag) 168da14cebeSEric Cheng { 169da14cebeSEric Cheng int i; 170da14cebeSEric Cheng mac_client_impl_t *mcip = buf; 171da14cebeSEric Cheng 172da14cebeSEric Cheng bzero(buf, MAC_CLIENT_IMPL_SIZE); 173da14cebeSEric Cheng mutex_init(&mcip->mci_tx_cb_lock, NULL, MUTEX_DRIVER, NULL); 174da14cebeSEric Cheng mcip->mci_tx_notify_cb_info.mcbi_lockp = &mcip->mci_tx_cb_lock; 175da14cebeSEric Cheng 176da14cebeSEric Cheng ASSERT(mac_tx_percpu_cnt >= 0); 177da14cebeSEric Cheng for (i = 0; i <= mac_tx_percpu_cnt; i++) { 178da14cebeSEric Cheng mutex_init(&mcip->mci_tx_pcpu[i].pcpu_tx_lock, NULL, 179da14cebeSEric Cheng MUTEX_DRIVER, NULL); 180da14cebeSEric Cheng } 181da14cebeSEric Cheng cv_init(&mcip->mci_tx_cv, NULL, CV_DRIVER, NULL); 182da14cebeSEric Cheng 183da14cebeSEric Cheng return (0); 184da14cebeSEric Cheng } 185da14cebeSEric Cheng 186da14cebeSEric Cheng /* ARGSUSED */ 187da14cebeSEric Cheng static void 188da14cebeSEric Cheng i_mac_client_impl_dtor(void *buf, void *arg) 189da14cebeSEric Cheng { 190da14cebeSEric Cheng int i; 191da14cebeSEric Cheng mac_client_impl_t *mcip = buf; 192da14cebeSEric Cheng 193da14cebeSEric Cheng ASSERT(mcip->mci_promisc_list == NULL); 194da14cebeSEric Cheng ASSERT(mcip->mci_unicast_list == NULL); 195da14cebeSEric Cheng ASSERT(mcip->mci_state_flags == 0); 196da14cebeSEric Cheng ASSERT(mcip->mci_tx_flag == 0); 197da14cebeSEric Cheng 198da14cebeSEric Cheng mutex_destroy(&mcip->mci_tx_cb_lock); 199da14cebeSEric Cheng 200da14cebeSEric Cheng ASSERT(mac_tx_percpu_cnt >= 0); 201da14cebeSEric Cheng for (i = 0; i <= mac_tx_percpu_cnt; i++) { 202da14cebeSEric Cheng ASSERT(mcip->mci_tx_pcpu[i].pcpu_tx_refcnt == 0); 203da14cebeSEric Cheng mutex_destroy(&mcip->mci_tx_pcpu[i].pcpu_tx_lock); 204da14cebeSEric Cheng } 205da14cebeSEric Cheng cv_destroy(&mcip->mci_tx_cv); 206da14cebeSEric Cheng } 207da14cebeSEric Cheng 208da14cebeSEric Cheng /* ARGSUSED */ 209da14cebeSEric Cheng static int 210da14cebeSEric Cheng i_mac_promisc_impl_ctor(void *buf, void *arg, int kmflag) 211da14cebeSEric Cheng { 212da14cebeSEric Cheng mac_promisc_impl_t *mpip = buf; 213da14cebeSEric Cheng 214da14cebeSEric Cheng bzero(buf, sizeof (mac_promisc_impl_t)); 215da14cebeSEric Cheng mpip->mpi_mci_link.mcb_objp = buf; 216da14cebeSEric Cheng mpip->mpi_mci_link.mcb_objsize = sizeof (mac_promisc_impl_t); 217da14cebeSEric Cheng mpip->mpi_mi_link.mcb_objp = buf; 218da14cebeSEric Cheng mpip->mpi_mi_link.mcb_objsize = sizeof (mac_promisc_impl_t); 219da14cebeSEric Cheng return (0); 220da14cebeSEric Cheng } 221da14cebeSEric Cheng 222da14cebeSEric Cheng /* ARGSUSED */ 223da14cebeSEric Cheng static void 224da14cebeSEric Cheng i_mac_promisc_impl_dtor(void *buf, void *arg) 225da14cebeSEric Cheng { 226da14cebeSEric Cheng mac_promisc_impl_t *mpip = buf; 227da14cebeSEric Cheng 228da14cebeSEric Cheng ASSERT(mpip->mpi_mci_link.mcb_objp != NULL); 229da14cebeSEric Cheng ASSERT(mpip->mpi_mci_link.mcb_objsize == sizeof (mac_promisc_impl_t)); 230da14cebeSEric Cheng ASSERT(mpip->mpi_mi_link.mcb_objp == mpip->mpi_mci_link.mcb_objp); 231da14cebeSEric Cheng ASSERT(mpip->mpi_mi_link.mcb_objsize == sizeof (mac_promisc_impl_t)); 232da14cebeSEric Cheng 233da14cebeSEric Cheng mpip->mpi_mci_link.mcb_objp = NULL; 234da14cebeSEric Cheng mpip->mpi_mci_link.mcb_objsize = 0; 235da14cebeSEric Cheng mpip->mpi_mi_link.mcb_objp = NULL; 236da14cebeSEric Cheng mpip->mpi_mi_link.mcb_objsize = 0; 237da14cebeSEric Cheng 238da14cebeSEric Cheng ASSERT(mpip->mpi_mci_link.mcb_flags == 0); 239da14cebeSEric Cheng mpip->mpi_mci_link.mcb_objsize = 0; 240da14cebeSEric Cheng } 241da14cebeSEric Cheng 242da14cebeSEric Cheng void 243da14cebeSEric Cheng mac_client_init(void) 244da14cebeSEric Cheng { 245da14cebeSEric Cheng ASSERT(mac_tx_percpu_cnt >= 0); 246da14cebeSEric Cheng 247da14cebeSEric Cheng mac_client_impl_cache = kmem_cache_create("mac_client_impl_cache", 248da14cebeSEric Cheng MAC_CLIENT_IMPL_SIZE, 0, i_mac_client_impl_ctor, 249da14cebeSEric Cheng i_mac_client_impl_dtor, NULL, NULL, NULL, 0); 250da14cebeSEric Cheng ASSERT(mac_client_impl_cache != NULL); 251da14cebeSEric Cheng 252da14cebeSEric Cheng mac_promisc_impl_cache = kmem_cache_create("mac_promisc_impl_cache", 253da14cebeSEric Cheng sizeof (mac_promisc_impl_t), 0, i_mac_promisc_impl_ctor, 254da14cebeSEric Cheng i_mac_promisc_impl_dtor, NULL, NULL, NULL, 0); 255da14cebeSEric Cheng ASSERT(mac_promisc_impl_cache != NULL); 256da14cebeSEric Cheng } 257da14cebeSEric Cheng 258da14cebeSEric Cheng void 259da14cebeSEric Cheng mac_client_fini(void) 260da14cebeSEric Cheng { 261da14cebeSEric Cheng kmem_cache_destroy(mac_client_impl_cache); 262da14cebeSEric Cheng kmem_cache_destroy(mac_promisc_impl_cache); 263da14cebeSEric Cheng } 264da14cebeSEric Cheng 265da14cebeSEric Cheng /* 266da14cebeSEric Cheng * Return the lower MAC client handle from the VNIC driver for the 267da14cebeSEric Cheng * specified VNIC MAC instance. 268da14cebeSEric Cheng */ 269da14cebeSEric Cheng mac_client_impl_t * 270da14cebeSEric Cheng mac_vnic_lower(mac_impl_t *mip) 271da14cebeSEric Cheng { 272da14cebeSEric Cheng mac_capab_vnic_t cap; 273da14cebeSEric Cheng mac_client_impl_t *mcip; 274da14cebeSEric Cheng 275da14cebeSEric Cheng VERIFY(i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_VNIC, &cap)); 276da14cebeSEric Cheng mcip = cap.mcv_mac_client_handle(cap.mcv_arg); 277da14cebeSEric Cheng 278da14cebeSEric Cheng return (mcip); 279da14cebeSEric Cheng } 280da14cebeSEric Cheng 281da14cebeSEric Cheng /* 2821a41ca23SJerry Jelinek * Update the secondary macs 2831a41ca23SJerry Jelinek */ 2841a41ca23SJerry Jelinek void 2851a41ca23SJerry Jelinek mac_vnic_secondary_update(mac_impl_t *mip) 2861a41ca23SJerry Jelinek { 2871a41ca23SJerry Jelinek mac_capab_vnic_t cap; 2881a41ca23SJerry Jelinek 2891a41ca23SJerry Jelinek VERIFY(i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_VNIC, &cap)); 2901a41ca23SJerry Jelinek cap.mcv_mac_secondary_update(cap.mcv_arg); 2911a41ca23SJerry Jelinek } 2921a41ca23SJerry Jelinek 2931a41ca23SJerry Jelinek /* 294da14cebeSEric Cheng * Return the MAC client handle of the primary MAC client for the 295da14cebeSEric Cheng * specified MAC instance, or NULL otherwise. 296da14cebeSEric Cheng */ 297da14cebeSEric Cheng mac_client_impl_t * 298da14cebeSEric Cheng mac_primary_client_handle(mac_impl_t *mip) 299da14cebeSEric Cheng { 300da14cebeSEric Cheng mac_client_impl_t *mcip; 301da14cebeSEric Cheng 302da14cebeSEric Cheng if (mip->mi_state_flags & MIS_IS_VNIC) 303da14cebeSEric Cheng return (mac_vnic_lower(mip)); 304da14cebeSEric Cheng 305da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 306da14cebeSEric Cheng 307da14cebeSEric Cheng for (mcip = mip->mi_clients_list; mcip != NULL; 308da14cebeSEric Cheng mcip = mcip->mci_client_next) { 309da14cebeSEric Cheng if (MCIP_DATAPATH_SETUP(mcip) && mac_is_primary_client(mcip)) 310da14cebeSEric Cheng return (mcip); 311da14cebeSEric Cheng } 312da14cebeSEric Cheng return (NULL); 313da14cebeSEric Cheng } 314da14cebeSEric Cheng 315da14cebeSEric Cheng /* 316da14cebeSEric Cheng * Open a MAC specified by its MAC name. 317da14cebeSEric Cheng */ 318da14cebeSEric Cheng int 319da14cebeSEric Cheng mac_open(const char *macname, mac_handle_t *mhp) 320da14cebeSEric Cheng { 321da14cebeSEric Cheng mac_impl_t *mip; 322da14cebeSEric Cheng int err; 323da14cebeSEric Cheng 324da14cebeSEric Cheng /* 325da14cebeSEric Cheng * Look up its entry in the global hash table. 326da14cebeSEric Cheng */ 327da14cebeSEric Cheng if ((err = mac_hold(macname, &mip)) != 0) 328da14cebeSEric Cheng return (err); 329da14cebeSEric Cheng 330da14cebeSEric Cheng /* 331da14cebeSEric Cheng * Hold the dip associated to the MAC to prevent it from being 332da14cebeSEric Cheng * detached. For a softmac, its underlying dip is held by the 333da14cebeSEric Cheng * mi_open() callback. 334da14cebeSEric Cheng * 335da14cebeSEric Cheng * This is done to be more tolerant with some defective drivers, 336da14cebeSEric Cheng * which incorrectly handle mac_unregister() failure in their 337da14cebeSEric Cheng * xxx_detach() routine. For example, some drivers ignore the 338da14cebeSEric Cheng * failure of mac_unregister() and free all resources that 339da14cebeSEric Cheng * that are needed for data transmition. 340da14cebeSEric Cheng */ 341da14cebeSEric Cheng e_ddi_hold_devi(mip->mi_dip); 342da14cebeSEric Cheng 343da14cebeSEric Cheng if (!(mip->mi_callbacks->mc_callbacks & MC_OPEN)) { 344da14cebeSEric Cheng *mhp = (mac_handle_t)mip; 345da14cebeSEric Cheng return (0); 346da14cebeSEric Cheng } 347da14cebeSEric Cheng 348da14cebeSEric Cheng /* 349da14cebeSEric Cheng * The mac perimeter is used in both mac_open and mac_close by the 350da14cebeSEric Cheng * framework to single thread the MC_OPEN/MC_CLOSE of drivers. 351da14cebeSEric Cheng */ 352da14cebeSEric Cheng i_mac_perim_enter(mip); 353da14cebeSEric Cheng mip->mi_oref++; 354da14cebeSEric Cheng if (mip->mi_oref != 1 || ((err = mip->mi_open(mip->mi_driver)) == 0)) { 355da14cebeSEric Cheng *mhp = (mac_handle_t)mip; 356da14cebeSEric Cheng i_mac_perim_exit(mip); 357da14cebeSEric Cheng return (0); 358da14cebeSEric Cheng } 359da14cebeSEric Cheng mip->mi_oref--; 360da14cebeSEric Cheng ddi_release_devi(mip->mi_dip); 361da14cebeSEric Cheng mac_rele(mip); 362da14cebeSEric Cheng i_mac_perim_exit(mip); 363da14cebeSEric Cheng return (err); 364da14cebeSEric Cheng } 365da14cebeSEric Cheng 366da14cebeSEric Cheng /* 367da14cebeSEric Cheng * Open a MAC specified by its linkid. 368da14cebeSEric Cheng */ 369da14cebeSEric Cheng int 370da14cebeSEric Cheng mac_open_by_linkid(datalink_id_t linkid, mac_handle_t *mhp) 371da14cebeSEric Cheng { 372da14cebeSEric Cheng dls_dl_handle_t dlh; 373da14cebeSEric Cheng int err; 374da14cebeSEric Cheng 375da14cebeSEric Cheng if ((err = dls_devnet_hold_tmp(linkid, &dlh)) != 0) 376da14cebeSEric Cheng return (err); 377da14cebeSEric Cheng 378da14cebeSEric Cheng dls_devnet_prop_task_wait(dlh); 379da14cebeSEric Cheng 380da14cebeSEric Cheng err = mac_open(dls_devnet_mac(dlh), mhp); 381da14cebeSEric Cheng 382da14cebeSEric Cheng dls_devnet_rele_tmp(dlh); 383da14cebeSEric Cheng return (err); 384da14cebeSEric Cheng } 385da14cebeSEric Cheng 386da14cebeSEric Cheng /* 387da14cebeSEric Cheng * Open a MAC specified by its link name. 388da14cebeSEric Cheng */ 389da14cebeSEric Cheng int 390da14cebeSEric Cheng mac_open_by_linkname(const char *link, mac_handle_t *mhp) 391da14cebeSEric Cheng { 392da14cebeSEric Cheng datalink_id_t linkid; 393da14cebeSEric Cheng int err; 394da14cebeSEric Cheng 395da14cebeSEric Cheng if ((err = dls_mgmt_get_linkid(link, &linkid)) != 0) 396da14cebeSEric Cheng return (err); 397da14cebeSEric Cheng return (mac_open_by_linkid(linkid, mhp)); 398da14cebeSEric Cheng } 399da14cebeSEric Cheng 400da14cebeSEric Cheng /* 401da14cebeSEric Cheng * Close the specified MAC. 402da14cebeSEric Cheng */ 403da14cebeSEric Cheng void 404da14cebeSEric Cheng mac_close(mac_handle_t mh) 405da14cebeSEric Cheng { 406da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 407da14cebeSEric Cheng 408da14cebeSEric Cheng i_mac_perim_enter(mip); 409da14cebeSEric Cheng /* 410da14cebeSEric Cheng * The mac perimeter is used in both mac_open and mac_close by the 411da14cebeSEric Cheng * framework to single thread the MC_OPEN/MC_CLOSE of drivers. 412da14cebeSEric Cheng */ 413da14cebeSEric Cheng if (mip->mi_callbacks->mc_callbacks & MC_OPEN) { 414da14cebeSEric Cheng ASSERT(mip->mi_oref != 0); 415da14cebeSEric Cheng if (--mip->mi_oref == 0) { 416da14cebeSEric Cheng if ((mip->mi_callbacks->mc_callbacks & MC_CLOSE)) 417da14cebeSEric Cheng mip->mi_close(mip->mi_driver); 418da14cebeSEric Cheng } 419da14cebeSEric Cheng } 420da14cebeSEric Cheng i_mac_perim_exit(mip); 421da14cebeSEric Cheng ddi_release_devi(mip->mi_dip); 422da14cebeSEric Cheng mac_rele(mip); 423da14cebeSEric Cheng } 424da14cebeSEric Cheng 425da14cebeSEric Cheng /* 426da14cebeSEric Cheng * Misc utility functions to retrieve various information about a MAC 427da14cebeSEric Cheng * instance or a MAC client. 428da14cebeSEric Cheng */ 429da14cebeSEric Cheng 430da14cebeSEric Cheng const mac_info_t * 431da14cebeSEric Cheng mac_info(mac_handle_t mh) 432da14cebeSEric Cheng { 433da14cebeSEric Cheng return (&((mac_impl_t *)mh)->mi_info); 434da14cebeSEric Cheng } 435da14cebeSEric Cheng 436da14cebeSEric Cheng dev_info_t * 437da14cebeSEric Cheng mac_devinfo_get(mac_handle_t mh) 438da14cebeSEric Cheng { 439da14cebeSEric Cheng return (((mac_impl_t *)mh)->mi_dip); 440da14cebeSEric Cheng } 441da14cebeSEric Cheng 4425d460eafSCathy Zhou void * 4435d460eafSCathy Zhou mac_driver(mac_handle_t mh) 4445d460eafSCathy Zhou { 4455d460eafSCathy Zhou return (((mac_impl_t *)mh)->mi_driver); 4465d460eafSCathy Zhou } 4475d460eafSCathy Zhou 448da14cebeSEric Cheng const char * 449da14cebeSEric Cheng mac_name(mac_handle_t mh) 450da14cebeSEric Cheng { 451da14cebeSEric Cheng return (((mac_impl_t *)mh)->mi_name); 452da14cebeSEric Cheng } 453da14cebeSEric Cheng 4540a0e9771SDarren Reed int 4550a0e9771SDarren Reed mac_type(mac_handle_t mh) 4560a0e9771SDarren Reed { 4570a0e9771SDarren Reed return (((mac_impl_t *)mh)->mi_type->mt_type); 4580a0e9771SDarren Reed } 4590a0e9771SDarren Reed 460f195a053SDarren Reed int 461f195a053SDarren Reed mac_nativetype(mac_handle_t mh) 462f195a053SDarren Reed { 463f195a053SDarren Reed return (((mac_impl_t *)mh)->mi_type->mt_nativetype); 464f195a053SDarren Reed } 465f195a053SDarren Reed 466da14cebeSEric Cheng char * 467da14cebeSEric Cheng mac_client_name(mac_client_handle_t mch) 468da14cebeSEric Cheng { 469da14cebeSEric Cheng return (((mac_client_impl_t *)mch)->mci_name); 470da14cebeSEric Cheng } 471da14cebeSEric Cheng 472da14cebeSEric Cheng minor_t 473da14cebeSEric Cheng mac_minor(mac_handle_t mh) 474da14cebeSEric Cheng { 475da14cebeSEric Cheng return (((mac_impl_t *)mh)->mi_minor); 476da14cebeSEric Cheng } 477da14cebeSEric Cheng 478da14cebeSEric Cheng /* 479da14cebeSEric Cheng * Return the VID associated with a MAC client. This function should 480da14cebeSEric Cheng * be called for clients which are associated with only one VID. 481da14cebeSEric Cheng */ 482da14cebeSEric Cheng uint16_t 483da14cebeSEric Cheng mac_client_vid(mac_client_handle_t mch) 484da14cebeSEric Cheng { 485da14cebeSEric Cheng uint16_t vid = VLAN_ID_NONE; 486da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 487da14cebeSEric Cheng flow_desc_t flow_desc; 488da14cebeSEric Cheng 489da14cebeSEric Cheng if (mcip->mci_nflents == 0) 490da14cebeSEric Cheng return (vid); 491da14cebeSEric Cheng 492da14cebeSEric Cheng ASSERT(MCIP_DATAPATH_SETUP(mcip) && mac_client_single_rcvr(mcip)); 493da14cebeSEric Cheng 494da14cebeSEric Cheng mac_flow_get_desc(mcip->mci_flent, &flow_desc); 495da14cebeSEric Cheng if ((flow_desc.fd_mask & FLOW_LINK_VID) != 0) 496da14cebeSEric Cheng vid = flow_desc.fd_vid; 497da14cebeSEric Cheng 498da14cebeSEric Cheng return (vid); 499da14cebeSEric Cheng } 500da14cebeSEric Cheng 501da14cebeSEric Cheng /* 50272782355SNicolas Droux * Return whether the specified MAC client corresponds to a VLAN VNIC. 50372782355SNicolas Droux */ 50472782355SNicolas Droux boolean_t 50572782355SNicolas Droux mac_client_is_vlan_vnic(mac_client_handle_t mch) 50672782355SNicolas Droux { 50772782355SNicolas Droux mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 50872782355SNicolas Droux 50972782355SNicolas Droux return (((mcip->mci_state_flags & MCIS_IS_VNIC) != 0) && 51072782355SNicolas Droux ((mcip->mci_flent->fe_type & FLOW_PRIMARY_MAC) != 0)); 51172782355SNicolas Droux } 51272782355SNicolas Droux 51372782355SNicolas Droux /* 514da14cebeSEric Cheng * Return the link speed associated with the specified MAC client. 515da14cebeSEric Cheng * 516da14cebeSEric Cheng * The link speed of a MAC client is equal to the smallest value of 517da14cebeSEric Cheng * 1) the current link speed of the underlying NIC, or 518da14cebeSEric Cheng * 2) the bandwidth limit set for the MAC client. 519da14cebeSEric Cheng * 520da14cebeSEric Cheng * Note that the bandwidth limit can be higher than the speed 521da14cebeSEric Cheng * of the underlying NIC. This is allowed to avoid spurious 522da14cebeSEric Cheng * administration action failures or artifically lowering the 523da14cebeSEric Cheng * bandwidth limit of a link that may have temporarily lowered 524da14cebeSEric Cheng * its link speed due to hardware problem or administrator action. 525da14cebeSEric Cheng */ 526da14cebeSEric Cheng static uint64_t 527da14cebeSEric Cheng mac_client_ifspeed(mac_client_impl_t *mcip) 528da14cebeSEric Cheng { 529da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip; 530da14cebeSEric Cheng uint64_t nic_speed; 531da14cebeSEric Cheng 532da14cebeSEric Cheng nic_speed = mac_stat_get((mac_handle_t)mip, MAC_STAT_IFSPEED); 533da14cebeSEric Cheng 534da14cebeSEric Cheng if (nic_speed == 0) { 535da14cebeSEric Cheng return (0); 536da14cebeSEric Cheng } else { 537da14cebeSEric Cheng uint64_t policy_limit = (uint64_t)-1; 538da14cebeSEric Cheng 539da14cebeSEric Cheng if (MCIP_RESOURCE_PROPS_MASK(mcip) & MRP_MAXBW) 540da14cebeSEric Cheng policy_limit = MCIP_RESOURCE_PROPS_MAXBW(mcip); 541da14cebeSEric Cheng 542da14cebeSEric Cheng return (MIN(policy_limit, nic_speed)); 543da14cebeSEric Cheng } 544da14cebeSEric Cheng } 545da14cebeSEric Cheng 546da14cebeSEric Cheng /* 547da14cebeSEric Cheng * Return the link state of the specified client. If here are more 548da14cebeSEric Cheng * than one clients of the underying mac_impl_t, the link state 549da14cebeSEric Cheng * will always be UP regardless of the link state of the underlying 550da14cebeSEric Cheng * mac_impl_t. This is needed to allow the MAC clients to continue 551da14cebeSEric Cheng * to communicate with each other even when the physical link of 552da14cebeSEric Cheng * their mac_impl_t is down. 553da14cebeSEric Cheng */ 554da14cebeSEric Cheng static uint64_t 555da14cebeSEric Cheng mac_client_link_state(mac_client_impl_t *mcip) 556da14cebeSEric Cheng { 557da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip; 558da14cebeSEric Cheng uint16_t vid; 559da14cebeSEric Cheng mac_client_impl_t *mci_list; 560da14cebeSEric Cheng mac_unicast_impl_t *mui_list, *oth_mui_list; 561da14cebeSEric Cheng 562da14cebeSEric Cheng /* 563da14cebeSEric Cheng * Returns LINK_STATE_UP if there are other MAC clients defined on 564da14cebeSEric Cheng * mac_impl_t which share same VLAN ID as that of mcip. Note that 565da14cebeSEric Cheng * if 'mcip' has more than one VID's then we match ANY one of the 566da14cebeSEric Cheng * VID's with other MAC client's VID's and return LINK_STATE_UP. 567da14cebeSEric Cheng */ 568da14cebeSEric Cheng rw_enter(&mcip->mci_rw_lock, RW_READER); 569da14cebeSEric Cheng for (mui_list = mcip->mci_unicast_list; mui_list != NULL; 570da14cebeSEric Cheng mui_list = mui_list->mui_next) { 571da14cebeSEric Cheng vid = mui_list->mui_vid; 572da14cebeSEric Cheng for (mci_list = mip->mi_clients_list; mci_list != NULL; 573da14cebeSEric Cheng mci_list = mci_list->mci_client_next) { 574da14cebeSEric Cheng if (mci_list == mcip) 575da14cebeSEric Cheng continue; 576da14cebeSEric Cheng for (oth_mui_list = mci_list->mci_unicast_list; 577da14cebeSEric Cheng oth_mui_list != NULL; oth_mui_list = oth_mui_list-> 578da14cebeSEric Cheng mui_next) { 579da14cebeSEric Cheng if (vid == oth_mui_list->mui_vid) { 580da14cebeSEric Cheng rw_exit(&mcip->mci_rw_lock); 581da14cebeSEric Cheng return (LINK_STATE_UP); 582da14cebeSEric Cheng } 583da14cebeSEric Cheng } 584da14cebeSEric Cheng } 585da14cebeSEric Cheng } 586da14cebeSEric Cheng rw_exit(&mcip->mci_rw_lock); 587da14cebeSEric Cheng 588da14cebeSEric Cheng return (mac_stat_get((mac_handle_t)mip, MAC_STAT_LINK_STATE)); 589da14cebeSEric Cheng } 590da14cebeSEric Cheng 591da14cebeSEric Cheng /* 5920dc2366fSVenugopal Iyer * These statistics are consumed by dladm show-link -s <vnic>, 5930dc2366fSVenugopal Iyer * dladm show-vnic -s and netstat. With the introduction of dlstat, 5940dc2366fSVenugopal Iyer * dladm show-link -s and dladm show-vnic -s witll be EOL'ed while 5950dc2366fSVenugopal Iyer * netstat will consume from kstats introduced for dlstat. This code 5960dc2366fSVenugopal Iyer * will be removed at that time. 5970dc2366fSVenugopal Iyer */ 5980dc2366fSVenugopal Iyer 5990dc2366fSVenugopal Iyer /* 600da14cebeSEric Cheng * Return the statistics of a MAC client. These statistics are different 601da14cebeSEric Cheng * then the statistics of the underlying MAC which are returned by 602da14cebeSEric Cheng * mac_stat_get(). 603d47ced1fSRobert Mustacchi * 604d47ced1fSRobert Mustacchi * Note that for things based on the tx and rx stats, mac will end up clobbering 605d47ced1fSRobert Mustacchi * those stats when the underlying set of rings in the srs changes. As such, we 606d47ced1fSRobert Mustacchi * need to source not only the current set, but also the historical set when 607d47ced1fSRobert Mustacchi * returning to the client, lest our counters appear to go backwards. 608da14cebeSEric Cheng */ 609da14cebeSEric Cheng uint64_t 610da14cebeSEric Cheng mac_client_stat_get(mac_client_handle_t mch, uint_t stat) 611da14cebeSEric Cheng { 612da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 613da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip; 6140dc2366fSVenugopal Iyer flow_entry_t *flent = mcip->mci_flent; 6150dc2366fSVenugopal Iyer mac_soft_ring_set_t *mac_srs; 616d47ced1fSRobert Mustacchi mac_rx_stats_t *mac_rx_stat, *old_rx_stat; 617d47ced1fSRobert Mustacchi mac_tx_stats_t *mac_tx_stat, *old_tx_stat; 6180dc2366fSVenugopal Iyer int i; 6190dc2366fSVenugopal Iyer uint64_t val = 0; 6200dc2366fSVenugopal Iyer 6210dc2366fSVenugopal Iyer mac_srs = (mac_soft_ring_set_t *)(flent->fe_tx_srs); 6220dc2366fSVenugopal Iyer mac_tx_stat = &mac_srs->srs_tx.st_stat; 623d47ced1fSRobert Mustacchi old_rx_stat = &mcip->mci_misc_stat.mms_defunctrxlanestats; 624d47ced1fSRobert Mustacchi old_tx_stat = &mcip->mci_misc_stat.mms_defuncttxlanestats; 625da14cebeSEric Cheng 626da14cebeSEric Cheng switch (stat) { 627da14cebeSEric Cheng case MAC_STAT_LINK_STATE: 628da14cebeSEric Cheng val = mac_client_link_state(mcip); 629da14cebeSEric Cheng break; 630da14cebeSEric Cheng case MAC_STAT_LINK_UP: 631da14cebeSEric Cheng val = (mac_client_link_state(mcip) == LINK_STATE_UP); 632da14cebeSEric Cheng break; 633da14cebeSEric Cheng case MAC_STAT_PROMISC: 634da14cebeSEric Cheng val = mac_stat_get((mac_handle_t)mip, MAC_STAT_PROMISC); 635da14cebeSEric Cheng break; 6364eaa4710SRishi Srivatsavai case MAC_STAT_LOWLINK_STATE: 6374eaa4710SRishi Srivatsavai val = mac_stat_get((mac_handle_t)mip, MAC_STAT_LOWLINK_STATE); 6384eaa4710SRishi Srivatsavai break; 639da14cebeSEric Cheng case MAC_STAT_IFSPEED: 640da14cebeSEric Cheng val = mac_client_ifspeed(mcip); 641da14cebeSEric Cheng break; 642da14cebeSEric Cheng case MAC_STAT_MULTIRCV: 6430dc2366fSVenugopal Iyer val = mcip->mci_misc_stat.mms_multircv; 644da14cebeSEric Cheng break; 645da14cebeSEric Cheng case MAC_STAT_BRDCSTRCV: 6460dc2366fSVenugopal Iyer val = mcip->mci_misc_stat.mms_brdcstrcv; 647da14cebeSEric Cheng break; 648da14cebeSEric Cheng case MAC_STAT_MULTIXMT: 6490dc2366fSVenugopal Iyer val = mcip->mci_misc_stat.mms_multixmt; 650da14cebeSEric Cheng break; 651da14cebeSEric Cheng case MAC_STAT_BRDCSTXMT: 6520dc2366fSVenugopal Iyer val = mcip->mci_misc_stat.mms_brdcstxmt; 653da14cebeSEric Cheng break; 654da14cebeSEric Cheng case MAC_STAT_OBYTES: 6550dc2366fSVenugopal Iyer val = mac_tx_stat->mts_obytes; 656d47ced1fSRobert Mustacchi val += old_tx_stat->mts_obytes; 657da14cebeSEric Cheng break; 658da14cebeSEric Cheng case MAC_STAT_OPACKETS: 6590dc2366fSVenugopal Iyer val = mac_tx_stat->mts_opackets; 660d47ced1fSRobert Mustacchi val += old_tx_stat->mts_opackets; 661da14cebeSEric Cheng break; 662da14cebeSEric Cheng case MAC_STAT_OERRORS: 6630dc2366fSVenugopal Iyer val = mac_tx_stat->mts_oerrors; 664d47ced1fSRobert Mustacchi val += old_tx_stat->mts_oerrors; 665da14cebeSEric Cheng break; 666da14cebeSEric Cheng case MAC_STAT_IPACKETS: 6670dc2366fSVenugopal Iyer for (i = 0; i < flent->fe_rx_srs_cnt; i++) { 6680dc2366fSVenugopal Iyer mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i]; 6690dc2366fSVenugopal Iyer mac_rx_stat = &mac_srs->srs_rx.sr_stat; 6700dc2366fSVenugopal Iyer val += mac_rx_stat->mrs_intrcnt + 6710dc2366fSVenugopal Iyer mac_rx_stat->mrs_pollcnt + mac_rx_stat->mrs_lclcnt; 6720dc2366fSVenugopal Iyer } 673d47ced1fSRobert Mustacchi val += old_rx_stat->mrs_intrcnt + old_rx_stat->mrs_pollcnt + 674d47ced1fSRobert Mustacchi old_rx_stat->mrs_lclcnt; 675da14cebeSEric Cheng break; 676da14cebeSEric Cheng case MAC_STAT_RBYTES: 6770dc2366fSVenugopal Iyer for (i = 0; i < flent->fe_rx_srs_cnt; i++) { 6780dc2366fSVenugopal Iyer mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i]; 6790dc2366fSVenugopal Iyer mac_rx_stat = &mac_srs->srs_rx.sr_stat; 6800dc2366fSVenugopal Iyer val += mac_rx_stat->mrs_intrbytes + 6810dc2366fSVenugopal Iyer mac_rx_stat->mrs_pollbytes + 6820dc2366fSVenugopal Iyer mac_rx_stat->mrs_lclbytes; 6830dc2366fSVenugopal Iyer } 684d47ced1fSRobert Mustacchi val += old_rx_stat->mrs_intrbytes + old_rx_stat->mrs_pollbytes + 685d47ced1fSRobert Mustacchi old_rx_stat->mrs_lclbytes; 686da14cebeSEric Cheng break; 687da14cebeSEric Cheng case MAC_STAT_IERRORS: 6880dc2366fSVenugopal Iyer for (i = 0; i < flent->fe_rx_srs_cnt; i++) { 6890dc2366fSVenugopal Iyer mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i]; 6900dc2366fSVenugopal Iyer mac_rx_stat = &mac_srs->srs_rx.sr_stat; 6910dc2366fSVenugopal Iyer val += mac_rx_stat->mrs_ierrors; 6920dc2366fSVenugopal Iyer } 693d47ced1fSRobert Mustacchi val += old_rx_stat->mrs_ierrors; 694da14cebeSEric Cheng break; 695da14cebeSEric Cheng default: 6960dc2366fSVenugopal Iyer val = mac_driver_stat_default(mip, stat); 697da14cebeSEric Cheng break; 698da14cebeSEric Cheng } 699da14cebeSEric Cheng 700da14cebeSEric Cheng return (val); 701da14cebeSEric Cheng } 702da14cebeSEric Cheng 703da14cebeSEric Cheng /* 704da14cebeSEric Cheng * Return the statistics of the specified MAC instance. 705da14cebeSEric Cheng */ 706da14cebeSEric Cheng uint64_t 707da14cebeSEric Cheng mac_stat_get(mac_handle_t mh, uint_t stat) 708da14cebeSEric Cheng { 709da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 710da14cebeSEric Cheng uint64_t val; 711da14cebeSEric Cheng int ret; 712da14cebeSEric Cheng 713da14cebeSEric Cheng /* 714da14cebeSEric Cheng * The range of stat determines where it is maintained. Stat 715da14cebeSEric Cheng * values from 0 up to (but not including) MAC_STAT_MIN are 716da14cebeSEric Cheng * mainteined by the mac module itself. Everything else is 717da14cebeSEric Cheng * maintained by the driver. 718da14cebeSEric Cheng * 719da14cebeSEric Cheng * If the mac_impl_t being queried corresponds to a VNIC, 720da14cebeSEric Cheng * the stats need to be queried from the lower MAC client 721da14cebeSEric Cheng * corresponding to the VNIC. (The mac_link_update() 722da14cebeSEric Cheng * invoked by the driver to the lower MAC causes the *lower 723da14cebeSEric Cheng * MAC* to update its mi_linkstate, and send a notification 724da14cebeSEric Cheng * to its MAC clients. Due to the VNIC passthrough, 725da14cebeSEric Cheng * these notifications are sent to the upper MAC clients 726da14cebeSEric Cheng * of the VNIC directly, and the upper mac_impl_t of the VNIC 727da14cebeSEric Cheng * does not have a valid mi_linkstate. 728da14cebeSEric Cheng */ 729da14cebeSEric Cheng if (stat < MAC_STAT_MIN && !(mip->mi_state_flags & MIS_IS_VNIC)) { 730da14cebeSEric Cheng /* these stats are maintained by the mac module itself */ 731da14cebeSEric Cheng switch (stat) { 732da14cebeSEric Cheng case MAC_STAT_LINK_STATE: 733da14cebeSEric Cheng return (mip->mi_linkstate); 734da14cebeSEric Cheng case MAC_STAT_LINK_UP: 735da14cebeSEric Cheng return (mip->mi_linkstate == LINK_STATE_UP); 736da14cebeSEric Cheng case MAC_STAT_PROMISC: 737da14cebeSEric Cheng return (mip->mi_devpromisc != 0); 7384eaa4710SRishi Srivatsavai case MAC_STAT_LOWLINK_STATE: 7394eaa4710SRishi Srivatsavai return (mip->mi_lowlinkstate); 740da14cebeSEric Cheng default: 741da14cebeSEric Cheng ASSERT(B_FALSE); 742da14cebeSEric Cheng } 743da14cebeSEric Cheng } 744da14cebeSEric Cheng 745da14cebeSEric Cheng /* 746da14cebeSEric Cheng * Call the driver to get the given statistic. 747da14cebeSEric Cheng */ 748da14cebeSEric Cheng ret = mip->mi_getstat(mip->mi_driver, stat, &val); 749da14cebeSEric Cheng if (ret != 0) { 750da14cebeSEric Cheng /* 751da14cebeSEric Cheng * The driver doesn't support this statistic. Get the 752da14cebeSEric Cheng * statistic's default value. 753da14cebeSEric Cheng */ 7540dc2366fSVenugopal Iyer val = mac_driver_stat_default(mip, stat); 755da14cebeSEric Cheng } 756da14cebeSEric Cheng return (val); 757da14cebeSEric Cheng } 758da14cebeSEric Cheng 759da14cebeSEric Cheng /* 7600dc2366fSVenugopal Iyer * Query hardware rx ring corresponding to the pseudo ring. 7610dc2366fSVenugopal Iyer */ 7620dc2366fSVenugopal Iyer uint64_t 7630dc2366fSVenugopal Iyer mac_pseudo_rx_ring_stat_get(mac_ring_handle_t handle, uint_t stat) 7640dc2366fSVenugopal Iyer { 7650dc2366fSVenugopal Iyer return (mac_rx_ring_stat_get(handle, stat)); 7660dc2366fSVenugopal Iyer } 7670dc2366fSVenugopal Iyer 7680dc2366fSVenugopal Iyer /* 7690dc2366fSVenugopal Iyer * Query hardware tx ring corresponding to the pseudo ring. 7700dc2366fSVenugopal Iyer */ 7710dc2366fSVenugopal Iyer uint64_t 7720dc2366fSVenugopal Iyer mac_pseudo_tx_ring_stat_get(mac_ring_handle_t handle, uint_t stat) 7730dc2366fSVenugopal Iyer { 7740dc2366fSVenugopal Iyer return (mac_tx_ring_stat_get(handle, stat)); 7750dc2366fSVenugopal Iyer } 7760dc2366fSVenugopal Iyer 7770dc2366fSVenugopal Iyer /* 778da14cebeSEric Cheng * Utility function which returns the VID associated with a flow entry. 779da14cebeSEric Cheng */ 780da14cebeSEric Cheng uint16_t 781da14cebeSEric Cheng i_mac_flow_vid(flow_entry_t *flent) 782da14cebeSEric Cheng { 783da14cebeSEric Cheng flow_desc_t flow_desc; 784da14cebeSEric Cheng 785da14cebeSEric Cheng mac_flow_get_desc(flent, &flow_desc); 786da14cebeSEric Cheng 787da14cebeSEric Cheng if ((flow_desc.fd_mask & FLOW_LINK_VID) != 0) 788da14cebeSEric Cheng return (flow_desc.fd_vid); 789da14cebeSEric Cheng return (VLAN_ID_NONE); 790da14cebeSEric Cheng } 791da14cebeSEric Cheng 792da14cebeSEric Cheng /* 793da14cebeSEric Cheng * Verify the validity of the specified unicast MAC address. Returns B_TRUE 794da14cebeSEric Cheng * if the address is valid, B_FALSE otherwise (multicast address, or incorrect 795da14cebeSEric Cheng * length. 796da14cebeSEric Cheng */ 797da14cebeSEric Cheng boolean_t 798da14cebeSEric Cheng mac_unicst_verify(mac_handle_t mh, const uint8_t *addr, uint_t len) 799da14cebeSEric Cheng { 800da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 801da14cebeSEric Cheng 802da14cebeSEric Cheng /* 803da14cebeSEric Cheng * Verify the address. No lock is needed since mi_type and plugin 804da14cebeSEric Cheng * details don't change after mac_register(). 805da14cebeSEric Cheng */ 806da14cebeSEric Cheng if ((len != mip->mi_type->mt_addr_length) || 807da14cebeSEric Cheng (mip->mi_type->mt_ops.mtops_unicst_verify(addr, 808da14cebeSEric Cheng mip->mi_pdata)) != 0) { 809da14cebeSEric Cheng return (B_FALSE); 810da14cebeSEric Cheng } else { 811da14cebeSEric Cheng return (B_TRUE); 812da14cebeSEric Cheng } 813da14cebeSEric Cheng } 814da14cebeSEric Cheng 815da14cebeSEric Cheng void 816da14cebeSEric Cheng mac_sdu_get(mac_handle_t mh, uint_t *min_sdu, uint_t *max_sdu) 817da14cebeSEric Cheng { 818da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 819da14cebeSEric Cheng 820da14cebeSEric Cheng if (min_sdu != NULL) 821da14cebeSEric Cheng *min_sdu = mip->mi_sdu_min; 822da14cebeSEric Cheng if (max_sdu != NULL) 823da14cebeSEric Cheng *max_sdu = mip->mi_sdu_max; 824da14cebeSEric Cheng } 825da14cebeSEric Cheng 8261eee170aSErik Nordmark void 8271eee170aSErik Nordmark mac_sdu_get2(mac_handle_t mh, uint_t *min_sdu, uint_t *max_sdu, 8281eee170aSErik Nordmark uint_t *multicast_sdu) 8291eee170aSErik Nordmark { 8301eee170aSErik Nordmark mac_impl_t *mip = (mac_impl_t *)mh; 8311eee170aSErik Nordmark 8321eee170aSErik Nordmark if (min_sdu != NULL) 8331eee170aSErik Nordmark *min_sdu = mip->mi_sdu_min; 8341eee170aSErik Nordmark if (max_sdu != NULL) 8351eee170aSErik Nordmark *max_sdu = mip->mi_sdu_max; 8361eee170aSErik Nordmark if (multicast_sdu != NULL) 8371eee170aSErik Nordmark *multicast_sdu = mip->mi_sdu_multicast; 8381eee170aSErik Nordmark } 8391eee170aSErik Nordmark 840da14cebeSEric Cheng /* 841da14cebeSEric Cheng * Update the MAC unicast address of the specified client's flows. Currently 842da14cebeSEric Cheng * only one unicast MAC unicast address is allowed per client. 843da14cebeSEric Cheng */ 844da14cebeSEric Cheng static void 845da14cebeSEric Cheng mac_unicast_update_client_flow(mac_client_impl_t *mcip) 846da14cebeSEric Cheng { 847da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip; 848da14cebeSEric Cheng flow_entry_t *flent = mcip->mci_flent; 849da14cebeSEric Cheng mac_address_t *map = mcip->mci_unicast; 850da14cebeSEric Cheng flow_desc_t flow_desc; 851da14cebeSEric Cheng 852da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 853da14cebeSEric Cheng ASSERT(flent != NULL); 854da14cebeSEric Cheng 855da14cebeSEric Cheng mac_flow_get_desc(flent, &flow_desc); 856da14cebeSEric Cheng ASSERT(flow_desc.fd_mask & FLOW_LINK_DST); 857da14cebeSEric Cheng 858da14cebeSEric Cheng bcopy(map->ma_addr, flow_desc.fd_dst_mac, map->ma_len); 859da14cebeSEric Cheng mac_flow_set_desc(flent, &flow_desc); 860da14cebeSEric Cheng 861da14cebeSEric Cheng /* 8624e6f6c83SCody Peter Mello * The v6 local and SLAAC addrs (used by mac protection) need to be 8630dc2366fSVenugopal Iyer * regenerated because our mac address has changed. 8640dc2366fSVenugopal Iyer */ 8654e6f6c83SCody Peter Mello mac_protect_update_mac_token(mcip); 8660dc2366fSVenugopal Iyer 8670dc2366fSVenugopal Iyer /* 868da14cebeSEric Cheng * A MAC client could have one MAC address but multiple 869da14cebeSEric Cheng * VLANs. In that case update the flow entries corresponding 870da14cebeSEric Cheng * to all VLANs of the MAC client. 871da14cebeSEric Cheng */ 872da14cebeSEric Cheng for (flent = mcip->mci_flent_list; flent != NULL; 873da14cebeSEric Cheng flent = flent->fe_client_next) { 874da14cebeSEric Cheng mac_flow_get_desc(flent, &flow_desc); 875da14cebeSEric Cheng if (!(flent->fe_type & FLOW_PRIMARY_MAC || 876da14cebeSEric Cheng flent->fe_type & FLOW_VNIC_MAC)) 877da14cebeSEric Cheng continue; 878da14cebeSEric Cheng 879da14cebeSEric Cheng bcopy(map->ma_addr, flow_desc.fd_dst_mac, map->ma_len); 880da14cebeSEric Cheng mac_flow_set_desc(flent, &flow_desc); 881da14cebeSEric Cheng } 882da14cebeSEric Cheng } 883da14cebeSEric Cheng 884da14cebeSEric Cheng /* 885da14cebeSEric Cheng * Update all clients that share the same unicast address. 886da14cebeSEric Cheng */ 887da14cebeSEric Cheng void 888da14cebeSEric Cheng mac_unicast_update_clients(mac_impl_t *mip, mac_address_t *map) 889da14cebeSEric Cheng { 890da14cebeSEric Cheng mac_client_impl_t *mcip; 891da14cebeSEric Cheng 892da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 893da14cebeSEric Cheng 894da14cebeSEric Cheng /* 895da14cebeSEric Cheng * Find all clients that share the same unicast MAC address and update 896da14cebeSEric Cheng * them appropriately. 897da14cebeSEric Cheng */ 898da14cebeSEric Cheng for (mcip = mip->mi_clients_list; mcip != NULL; 899da14cebeSEric Cheng mcip = mcip->mci_client_next) { 900da14cebeSEric Cheng /* 901da14cebeSEric Cheng * Ignore clients that don't share this MAC address. 902da14cebeSEric Cheng */ 903da14cebeSEric Cheng if (map != mcip->mci_unicast) 904da14cebeSEric Cheng continue; 905da14cebeSEric Cheng 906da14cebeSEric Cheng /* 907da14cebeSEric Cheng * Update those clients with same old unicast MAC address. 908da14cebeSEric Cheng */ 909da14cebeSEric Cheng mac_unicast_update_client_flow(mcip); 910da14cebeSEric Cheng } 911da14cebeSEric Cheng } 912da14cebeSEric Cheng 913da14cebeSEric Cheng /* 914da14cebeSEric Cheng * Update the unicast MAC address of the specified VNIC MAC client. 915da14cebeSEric Cheng * 916da14cebeSEric Cheng * Check whether the operation is valid. Any of following cases should fail: 917da14cebeSEric Cheng * 918da14cebeSEric Cheng * 1. It's a VLAN type of VNIC. 919da14cebeSEric Cheng * 2. The new value is current "primary" MAC address. 920da14cebeSEric Cheng * 3. The current MAC address is shared with other clients. 921da14cebeSEric Cheng * 4. The new MAC address has been used. This case will be valid when 922da14cebeSEric Cheng * client migration is fully supported. 923da14cebeSEric Cheng */ 924da14cebeSEric Cheng int 925da14cebeSEric Cheng mac_vnic_unicast_set(mac_client_handle_t mch, const uint8_t *addr) 926da14cebeSEric Cheng { 927da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 928da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip; 929da14cebeSEric Cheng mac_address_t *map = mcip->mci_unicast; 930da14cebeSEric Cheng int err; 931da14cebeSEric Cheng 932da14cebeSEric Cheng ASSERT(!(mip->mi_state_flags & MIS_IS_VNIC)); 933da14cebeSEric Cheng ASSERT(mcip->mci_state_flags & MCIS_IS_VNIC); 934da14cebeSEric Cheng ASSERT(mcip->mci_flags != MAC_CLIENT_FLAGS_PRIMARY); 935da14cebeSEric Cheng 936da14cebeSEric Cheng i_mac_perim_enter(mip); 937da14cebeSEric Cheng 938da14cebeSEric Cheng /* 939da14cebeSEric Cheng * If this is a VLAN type of VNIC, it's using "primary" MAC address 940da14cebeSEric Cheng * of the underlying interface. Must fail here. Refer to case 1 above. 941da14cebeSEric Cheng */ 942da14cebeSEric Cheng if (bcmp(map->ma_addr, mip->mi_addr, map->ma_len) == 0) { 943da14cebeSEric Cheng i_mac_perim_exit(mip); 944da14cebeSEric Cheng return (ENOTSUP); 945da14cebeSEric Cheng } 946da14cebeSEric Cheng 947da14cebeSEric Cheng /* 948da14cebeSEric Cheng * If the new address is the "primary" one, must fail. Refer to 949da14cebeSEric Cheng * case 2 above. 950da14cebeSEric Cheng */ 951da14cebeSEric Cheng if (bcmp(addr, mip->mi_addr, map->ma_len) == 0) { 952da14cebeSEric Cheng i_mac_perim_exit(mip); 953da14cebeSEric Cheng return (EACCES); 954da14cebeSEric Cheng } 955da14cebeSEric Cheng 956da14cebeSEric Cheng /* 957da14cebeSEric Cheng * If the address is shared by multiple clients, must fail. Refer 958da14cebeSEric Cheng * to case 3 above. 959da14cebeSEric Cheng */ 960da14cebeSEric Cheng if (mac_check_macaddr_shared(map)) { 961da14cebeSEric Cheng i_mac_perim_exit(mip); 962da14cebeSEric Cheng return (EBUSY); 963da14cebeSEric Cheng } 964da14cebeSEric Cheng 965da14cebeSEric Cheng /* 966da14cebeSEric Cheng * If the new address has been used, must fail for now. Refer to 967da14cebeSEric Cheng * case 4 above. 968da14cebeSEric Cheng */ 969da14cebeSEric Cheng if (mac_find_macaddr(mip, (uint8_t *)addr) != NULL) { 970da14cebeSEric Cheng i_mac_perim_exit(mip); 971da14cebeSEric Cheng return (ENOTSUP); 972da14cebeSEric Cheng } 973da14cebeSEric Cheng 974da14cebeSEric Cheng /* 975da14cebeSEric Cheng * Update the MAC address. 976da14cebeSEric Cheng */ 977da14cebeSEric Cheng err = mac_update_macaddr(map, (uint8_t *)addr); 978da14cebeSEric Cheng 979da14cebeSEric Cheng if (err != 0) { 980da14cebeSEric Cheng i_mac_perim_exit(mip); 981da14cebeSEric Cheng return (err); 982da14cebeSEric Cheng } 983da14cebeSEric Cheng 984da14cebeSEric Cheng /* 985da14cebeSEric Cheng * Update all flows of this MAC client. 986da14cebeSEric Cheng */ 987da14cebeSEric Cheng mac_unicast_update_client_flow(mcip); 988da14cebeSEric Cheng 989da14cebeSEric Cheng i_mac_perim_exit(mip); 990da14cebeSEric Cheng return (0); 991da14cebeSEric Cheng } 992da14cebeSEric Cheng 993da14cebeSEric Cheng /* 994da14cebeSEric Cheng * Program the new primary unicast address of the specified MAC. 995da14cebeSEric Cheng * 996da14cebeSEric Cheng * Function mac_update_macaddr() takes care different types of underlying 997da14cebeSEric Cheng * MAC. If the underlying MAC is VNIC, the VNIC driver must have registerd 998da14cebeSEric Cheng * mi_unicst() entry point, that indirectly calls mac_vnic_unicast_set() 999da14cebeSEric Cheng * which will take care of updating the MAC address of the corresponding 1000da14cebeSEric Cheng * MAC client. 1001da14cebeSEric Cheng * 1002da14cebeSEric Cheng * This is the only interface that allow the client to update the "primary" 1003da14cebeSEric Cheng * MAC address of the underlying MAC. The new value must have not been 1004da14cebeSEric Cheng * used by other clients. 1005da14cebeSEric Cheng */ 1006da14cebeSEric Cheng int 1007da14cebeSEric Cheng mac_unicast_primary_set(mac_handle_t mh, const uint8_t *addr) 1008da14cebeSEric Cheng { 1009da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 1010da14cebeSEric Cheng mac_address_t *map; 1011da14cebeSEric Cheng int err; 1012da14cebeSEric Cheng 1013da14cebeSEric Cheng /* verify the address validity */ 1014da14cebeSEric Cheng if (!mac_unicst_verify(mh, addr, mip->mi_type->mt_addr_length)) 1015da14cebeSEric Cheng return (EINVAL); 1016da14cebeSEric Cheng 1017da14cebeSEric Cheng i_mac_perim_enter(mip); 1018da14cebeSEric Cheng 1019da14cebeSEric Cheng /* 1020da14cebeSEric Cheng * If the new value is the same as the current primary address value, 1021da14cebeSEric Cheng * there's nothing to do. 1022da14cebeSEric Cheng */ 1023da14cebeSEric Cheng if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) { 1024da14cebeSEric Cheng i_mac_perim_exit(mip); 1025da14cebeSEric Cheng return (0); 1026da14cebeSEric Cheng } 1027da14cebeSEric Cheng 1028da14cebeSEric Cheng if (mac_find_macaddr(mip, (uint8_t *)addr) != 0) { 1029da14cebeSEric Cheng i_mac_perim_exit(mip); 1030da14cebeSEric Cheng return (EBUSY); 1031da14cebeSEric Cheng } 1032da14cebeSEric Cheng 1033da14cebeSEric Cheng map = mac_find_macaddr(mip, mip->mi_addr); 1034da14cebeSEric Cheng ASSERT(map != NULL); 1035da14cebeSEric Cheng 1036da14cebeSEric Cheng /* 1037da14cebeSEric Cheng * Update the MAC address. 1038da14cebeSEric Cheng */ 1039da14cebeSEric Cheng if (mip->mi_state_flags & MIS_IS_AGGR) { 1040da14cebeSEric Cheng mac_capab_aggr_t aggr_cap; 1041da14cebeSEric Cheng 1042da14cebeSEric Cheng /* 1043da14cebeSEric Cheng * If the mac is an aggregation, other than the unicast 1044da14cebeSEric Cheng * addresses programming, aggr must be informed about this 1045da14cebeSEric Cheng * primary unicst address change to change its mac address 1046da14cebeSEric Cheng * policy to be user-specified. 1047da14cebeSEric Cheng */ 1048da14cebeSEric Cheng ASSERT(map->ma_type == MAC_ADDRESS_TYPE_UNICAST_CLASSIFIED); 1049da14cebeSEric Cheng VERIFY(i_mac_capab_get(mh, MAC_CAPAB_AGGR, &aggr_cap)); 1050da14cebeSEric Cheng err = aggr_cap.mca_unicst(mip->mi_driver, addr); 1051da14cebeSEric Cheng if (err == 0) 1052da14cebeSEric Cheng bcopy(addr, map->ma_addr, map->ma_len); 1053da14cebeSEric Cheng } else { 1054da14cebeSEric Cheng err = mac_update_macaddr(map, (uint8_t *)addr); 1055da14cebeSEric Cheng } 1056da14cebeSEric Cheng 1057da14cebeSEric Cheng if (err != 0) { 1058da14cebeSEric Cheng i_mac_perim_exit(mip); 1059da14cebeSEric Cheng return (err); 1060da14cebeSEric Cheng } 1061da14cebeSEric Cheng 1062da14cebeSEric Cheng mac_unicast_update_clients(mip, map); 1063da14cebeSEric Cheng 1064da14cebeSEric Cheng /* 1065da14cebeSEric Cheng * Save the new primary MAC address in mac_impl_t. 1066da14cebeSEric Cheng */ 1067da14cebeSEric Cheng bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length); 1068da14cebeSEric Cheng 1069da14cebeSEric Cheng i_mac_perim_exit(mip); 1070da14cebeSEric Cheng 1071da14cebeSEric Cheng if (err == 0) 1072da14cebeSEric Cheng i_mac_notify(mip, MAC_NOTE_UNICST); 1073da14cebeSEric Cheng 1074da14cebeSEric Cheng return (err); 1075da14cebeSEric Cheng } 1076da14cebeSEric Cheng 1077da14cebeSEric Cheng /* 1078da14cebeSEric Cheng * Return the current primary MAC address of the specified MAC. 1079da14cebeSEric Cheng */ 1080da14cebeSEric Cheng void 1081da14cebeSEric Cheng mac_unicast_primary_get(mac_handle_t mh, uint8_t *addr) 1082da14cebeSEric Cheng { 1083da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 1084da14cebeSEric Cheng 1085da14cebeSEric Cheng rw_enter(&mip->mi_rw_lock, RW_READER); 1086da14cebeSEric Cheng bcopy(mip->mi_addr, addr, mip->mi_type->mt_addr_length); 1087da14cebeSEric Cheng rw_exit(&mip->mi_rw_lock); 1088da14cebeSEric Cheng } 1089da14cebeSEric Cheng 1090da14cebeSEric Cheng /* 10911a41ca23SJerry Jelinek * Return the secondary MAC address for the specified handle 10921a41ca23SJerry Jelinek */ 10931a41ca23SJerry Jelinek void 10941a41ca23SJerry Jelinek mac_unicast_secondary_get(mac_client_handle_t mh, uint8_t *addr) 10951a41ca23SJerry Jelinek { 10961a41ca23SJerry Jelinek mac_client_impl_t *mcip = (mac_client_impl_t *)mh; 10971a41ca23SJerry Jelinek 10981a41ca23SJerry Jelinek ASSERT(mcip->mci_unicast != NULL); 10991a41ca23SJerry Jelinek bcopy(mcip->mci_unicast->ma_addr, addr, mcip->mci_unicast->ma_len); 11001a41ca23SJerry Jelinek } 11011a41ca23SJerry Jelinek 11021a41ca23SJerry Jelinek /* 1103da14cebeSEric Cheng * Return information about the use of the primary MAC address of the 1104da14cebeSEric Cheng * specified MAC instance: 1105da14cebeSEric Cheng * 1106da14cebeSEric Cheng * - if client_name is non-NULL, it must point to a string of at 1107da14cebeSEric Cheng * least MAXNAMELEN bytes, and will be set to the name of the MAC 1108da14cebeSEric Cheng * client which uses the primary MAC address. 1109da14cebeSEric Cheng * 1110da14cebeSEric Cheng * - if in_use is non-NULL, used to return whether the primary MAC 1111da14cebeSEric Cheng * address is currently in use. 1112da14cebeSEric Cheng */ 1113da14cebeSEric Cheng void 1114da14cebeSEric Cheng mac_unicast_primary_info(mac_handle_t mh, char *client_name, boolean_t *in_use) 1115da14cebeSEric Cheng { 1116da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 1117da14cebeSEric Cheng mac_client_impl_t *cur_client; 1118da14cebeSEric Cheng 1119da14cebeSEric Cheng if (in_use != NULL) 1120da14cebeSEric Cheng *in_use = B_FALSE; 1121da14cebeSEric Cheng if (client_name != NULL) 1122da14cebeSEric Cheng bzero(client_name, MAXNAMELEN); 1123da14cebeSEric Cheng 1124da14cebeSEric Cheng /* 1125da14cebeSEric Cheng * The mi_rw_lock is used to protect threads that don't hold the 1126da14cebeSEric Cheng * mac perimeter to get a consistent view of the mi_clients_list. 1127da14cebeSEric Cheng * Threads that modify the list must hold both the mac perimeter and 1128da14cebeSEric Cheng * mi_rw_lock(RW_WRITER) 1129da14cebeSEric Cheng */ 1130da14cebeSEric Cheng rw_enter(&mip->mi_rw_lock, RW_READER); 1131da14cebeSEric Cheng for (cur_client = mip->mi_clients_list; cur_client != NULL; 1132da14cebeSEric Cheng cur_client = cur_client->mci_client_next) { 1133da14cebeSEric Cheng if (mac_is_primary_client(cur_client) || 1134da14cebeSEric Cheng (mip->mi_state_flags & MIS_IS_VNIC)) { 1135da14cebeSEric Cheng rw_exit(&mip->mi_rw_lock); 1136da14cebeSEric Cheng if (in_use != NULL) 1137da14cebeSEric Cheng *in_use = B_TRUE; 1138da14cebeSEric Cheng if (client_name != NULL) { 1139da14cebeSEric Cheng bcopy(cur_client->mci_name, client_name, 1140da14cebeSEric Cheng MAXNAMELEN); 1141da14cebeSEric Cheng } 1142da14cebeSEric Cheng return; 1143da14cebeSEric Cheng } 1144da14cebeSEric Cheng } 1145da14cebeSEric Cheng rw_exit(&mip->mi_rw_lock); 1146da14cebeSEric Cheng } 1147da14cebeSEric Cheng 1148da14cebeSEric Cheng /* 11492b24ab6bSSebastien Roy * Return the current destination MAC address of the specified MAC. 11502b24ab6bSSebastien Roy */ 11512b24ab6bSSebastien Roy boolean_t 11522b24ab6bSSebastien Roy mac_dst_get(mac_handle_t mh, uint8_t *addr) 11532b24ab6bSSebastien Roy { 11542b24ab6bSSebastien Roy mac_impl_t *mip = (mac_impl_t *)mh; 11552b24ab6bSSebastien Roy 11562b24ab6bSSebastien Roy rw_enter(&mip->mi_rw_lock, RW_READER); 11572b24ab6bSSebastien Roy if (mip->mi_dstaddr_set) 11582b24ab6bSSebastien Roy bcopy(mip->mi_dstaddr, addr, mip->mi_type->mt_addr_length); 11592b24ab6bSSebastien Roy rw_exit(&mip->mi_rw_lock); 11602b24ab6bSSebastien Roy return (mip->mi_dstaddr_set); 11612b24ab6bSSebastien Roy } 11622b24ab6bSSebastien Roy 11632b24ab6bSSebastien Roy /* 1164da14cebeSEric Cheng * Add the specified MAC client to the list of clients which opened 1165da14cebeSEric Cheng * the specified MAC. 1166da14cebeSEric Cheng */ 1167da14cebeSEric Cheng static void 1168da14cebeSEric Cheng mac_client_add(mac_client_impl_t *mcip) 1169da14cebeSEric Cheng { 1170da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip; 1171da14cebeSEric Cheng 1172da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 1173da14cebeSEric Cheng 1174da14cebeSEric Cheng /* add VNIC to the front of the list */ 1175da14cebeSEric Cheng rw_enter(&mip->mi_rw_lock, RW_WRITER); 1176da14cebeSEric Cheng mcip->mci_client_next = mip->mi_clients_list; 1177da14cebeSEric Cheng mip->mi_clients_list = mcip; 1178da14cebeSEric Cheng mip->mi_nclients++; 1179da14cebeSEric Cheng rw_exit(&mip->mi_rw_lock); 1180da14cebeSEric Cheng } 1181da14cebeSEric Cheng 1182da14cebeSEric Cheng /* 1183da14cebeSEric Cheng * Remove the specified MAC client from the list of clients which opened 1184da14cebeSEric Cheng * the specified MAC. 1185da14cebeSEric Cheng */ 1186da14cebeSEric Cheng static void 1187da14cebeSEric Cheng mac_client_remove(mac_client_impl_t *mcip) 1188da14cebeSEric Cheng { 1189da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip; 1190da14cebeSEric Cheng mac_client_impl_t **prev, *cclient; 1191da14cebeSEric Cheng 1192da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 1193da14cebeSEric Cheng 1194da14cebeSEric Cheng rw_enter(&mip->mi_rw_lock, RW_WRITER); 1195da14cebeSEric Cheng prev = &mip->mi_clients_list; 1196da14cebeSEric Cheng cclient = *prev; 1197da14cebeSEric Cheng while (cclient != NULL && cclient != mcip) { 1198da14cebeSEric Cheng prev = &cclient->mci_client_next; 1199da14cebeSEric Cheng cclient = *prev; 1200da14cebeSEric Cheng } 1201da14cebeSEric Cheng ASSERT(cclient != NULL); 1202da14cebeSEric Cheng *prev = cclient->mci_client_next; 1203da14cebeSEric Cheng mip->mi_nclients--; 1204da14cebeSEric Cheng rw_exit(&mip->mi_rw_lock); 1205da14cebeSEric Cheng } 1206da14cebeSEric Cheng 1207da14cebeSEric Cheng static mac_unicast_impl_t * 1208da14cebeSEric Cheng mac_client_find_vid(mac_client_impl_t *mcip, uint16_t vid) 1209da14cebeSEric Cheng { 1210da14cebeSEric Cheng mac_unicast_impl_t *muip = mcip->mci_unicast_list; 1211da14cebeSEric Cheng 1212da14cebeSEric Cheng while ((muip != NULL) && (muip->mui_vid != vid)) 1213da14cebeSEric Cheng muip = muip->mui_next; 1214da14cebeSEric Cheng 1215da14cebeSEric Cheng return (muip); 1216da14cebeSEric Cheng } 1217da14cebeSEric Cheng 1218da14cebeSEric Cheng /* 1219da14cebeSEric Cheng * Return whether the specified (MAC address, VID) tuple is already used by 1220da14cebeSEric Cheng * one of the MAC clients associated with the specified MAC. 1221da14cebeSEric Cheng */ 1222da14cebeSEric Cheng static boolean_t 1223da14cebeSEric Cheng mac_addr_in_use(mac_impl_t *mip, uint8_t *mac_addr, uint16_t vid) 1224da14cebeSEric Cheng { 1225da14cebeSEric Cheng mac_client_impl_t *client; 1226da14cebeSEric Cheng mac_address_t *map; 1227da14cebeSEric Cheng 1228da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 1229da14cebeSEric Cheng 1230da14cebeSEric Cheng for (client = mip->mi_clients_list; client != NULL; 1231da14cebeSEric Cheng client = client->mci_client_next) { 1232da14cebeSEric Cheng 1233da14cebeSEric Cheng /* 1234da14cebeSEric Cheng * Ignore clients that don't have unicast address. 1235da14cebeSEric Cheng */ 1236da14cebeSEric Cheng if (client->mci_unicast_list == NULL) 1237da14cebeSEric Cheng continue; 1238da14cebeSEric Cheng 1239da14cebeSEric Cheng map = client->mci_unicast; 1240da14cebeSEric Cheng 1241da14cebeSEric Cheng if ((bcmp(mac_addr, map->ma_addr, map->ma_len) == 0) && 1242da14cebeSEric Cheng (mac_client_find_vid(client, vid) != NULL)) { 1243da14cebeSEric Cheng return (B_TRUE); 1244da14cebeSEric Cheng } 1245da14cebeSEric Cheng } 1246da14cebeSEric Cheng 1247da14cebeSEric Cheng return (B_FALSE); 1248da14cebeSEric Cheng } 1249da14cebeSEric Cheng 1250da14cebeSEric Cheng /* 1251da14cebeSEric Cheng * Generate a random MAC address. The MAC address prefix is 1252da14cebeSEric Cheng * stored in the array pointed to by mac_addr, and its length, in bytes, 1253da14cebeSEric Cheng * is specified by prefix_len. The least significant bits 1254da14cebeSEric Cheng * after prefix_len bytes are generated, and stored after the prefix 1255da14cebeSEric Cheng * in the mac_addr array. 1256da14cebeSEric Cheng */ 1257da14cebeSEric Cheng int 1258da14cebeSEric Cheng mac_addr_random(mac_client_handle_t mch, uint_t prefix_len, 1259da14cebeSEric Cheng uint8_t *mac_addr, mac_diag_t *diag) 1260da14cebeSEric Cheng { 1261da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 1262da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip; 1263da14cebeSEric Cheng size_t addr_len = mip->mi_type->mt_addr_length; 1264da14cebeSEric Cheng 1265da14cebeSEric Cheng if (prefix_len >= addr_len) { 1266da14cebeSEric Cheng *diag = MAC_DIAG_MACPREFIXLEN_INVALID; 1267da14cebeSEric Cheng return (EINVAL); 1268da14cebeSEric Cheng } 1269da14cebeSEric Cheng 1270da14cebeSEric Cheng /* check the prefix value */ 1271da14cebeSEric Cheng if (prefix_len > 0) { 1272da14cebeSEric Cheng bzero(mac_addr + prefix_len, addr_len - prefix_len); 1273da14cebeSEric Cheng if (!mac_unicst_verify((mac_handle_t)mip, mac_addr, 1274da14cebeSEric Cheng addr_len)) { 1275da14cebeSEric Cheng *diag = MAC_DIAG_MACPREFIX_INVALID; 1276da14cebeSEric Cheng return (EINVAL); 1277da14cebeSEric Cheng } 1278da14cebeSEric Cheng } 1279da14cebeSEric Cheng 1280da14cebeSEric Cheng /* generate the MAC address */ 1281da14cebeSEric Cheng if (prefix_len < addr_len) { 1282da14cebeSEric Cheng (void) random_get_pseudo_bytes(mac_addr + 1283da14cebeSEric Cheng prefix_len, addr_len - prefix_len); 1284da14cebeSEric Cheng } 1285da14cebeSEric Cheng 1286da14cebeSEric Cheng *diag = 0; 1287da14cebeSEric Cheng return (0); 1288da14cebeSEric Cheng } 1289da14cebeSEric Cheng 1290da14cebeSEric Cheng /* 1291da14cebeSEric Cheng * Set the priority range for this MAC client. This will be used to 1292da14cebeSEric Cheng * determine the absolute priority for the threads created for this 1293da14cebeSEric Cheng * MAC client using the specified "low", "medium" and "high" level. 1294da14cebeSEric Cheng * This will also be used for any subflows on this MAC client. 1295da14cebeSEric Cheng */ 1296da14cebeSEric Cheng #define MAC_CLIENT_SET_PRIORITY_RANGE(mcip, pri) { \ 1297da14cebeSEric Cheng (mcip)->mci_min_pri = FLOW_MIN_PRIORITY(MINCLSYSPRI, \ 1298da14cebeSEric Cheng MAXCLSYSPRI, (pri)); \ 1299da14cebeSEric Cheng (mcip)->mci_max_pri = FLOW_MAX_PRIORITY(MINCLSYSPRI, \ 1300da14cebeSEric Cheng MAXCLSYSPRI, (mcip)->mci_min_pri); \ 1301da14cebeSEric Cheng } 1302da14cebeSEric Cheng 1303da14cebeSEric Cheng /* 1304da14cebeSEric Cheng * MAC client open entry point. Return a new MAC client handle. Each 1305da14cebeSEric Cheng * MAC client is associated with a name, specified through the 'name' 1306da14cebeSEric Cheng * argument. 1307da14cebeSEric Cheng */ 1308da14cebeSEric Cheng int 1309da14cebeSEric Cheng mac_client_open(mac_handle_t mh, mac_client_handle_t *mchp, char *name, 1310da14cebeSEric Cheng uint16_t flags) 1311da14cebeSEric Cheng { 1312da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 1313da14cebeSEric Cheng mac_client_impl_t *mcip; 1314da14cebeSEric Cheng int err = 0; 13150dc2366fSVenugopal Iyer boolean_t share_desired; 1316da14cebeSEric Cheng flow_entry_t *flent = NULL; 1317da14cebeSEric Cheng 13180dc2366fSVenugopal Iyer share_desired = (flags & MAC_OPEN_FLAGS_SHARES_DESIRED) != 0; 1319da14cebeSEric Cheng *mchp = NULL; 1320da14cebeSEric Cheng 1321da14cebeSEric Cheng i_mac_perim_enter(mip); 1322da14cebeSEric Cheng 1323da14cebeSEric Cheng if (mip->mi_state_flags & MIS_IS_VNIC) { 1324da14cebeSEric Cheng /* 1325da14cebeSEric Cheng * The underlying MAC is a VNIC. Return the MAC client 1326da14cebeSEric Cheng * handle of the lower MAC which was obtained by 1327da14cebeSEric Cheng * the VNIC driver when it did its mac_client_open(). 1328da14cebeSEric Cheng */ 1329da14cebeSEric Cheng 1330da14cebeSEric Cheng mcip = mac_vnic_lower(mip); 1331da14cebeSEric Cheng 1332da14cebeSEric Cheng /* 1333da14cebeSEric Cheng * Note that multiple mac clients share the same mcip in 1334da14cebeSEric Cheng * this case. 1335da14cebeSEric Cheng */ 1336da14cebeSEric Cheng if (flags & MAC_OPEN_FLAGS_EXCLUSIVE) 1337da14cebeSEric Cheng mcip->mci_state_flags |= MCIS_EXCLUSIVE; 1338da14cebeSEric Cheng 1339fc4e975dSVenugopal Iyer if (flags & MAC_OPEN_FLAGS_MULTI_PRIMARY) 1340fc4e975dSVenugopal Iyer mcip->mci_flags |= MAC_CLIENT_FLAGS_MULTI_PRIMARY; 1341fc4e975dSVenugopal Iyer 1342da14cebeSEric Cheng mip->mi_clients_list = mcip; 1343da14cebeSEric Cheng i_mac_perim_exit(mip); 1344da14cebeSEric Cheng *mchp = (mac_client_handle_t)mcip; 13451a41ca23SJerry Jelinek 13461a41ca23SJerry Jelinek DTRACE_PROBE2(mac__client__open__nonallocated, mac_impl_t *, 13471a41ca23SJerry Jelinek mcip->mci_mip, mac_client_impl_t *, mcip); 13481a41ca23SJerry Jelinek 1349da14cebeSEric Cheng return (err); 1350da14cebeSEric Cheng } 1351da14cebeSEric Cheng 1352da14cebeSEric Cheng mcip = kmem_cache_alloc(mac_client_impl_cache, KM_SLEEP); 1353da14cebeSEric Cheng 1354da14cebeSEric Cheng mcip->mci_mip = mip; 1355da14cebeSEric Cheng mcip->mci_upper_mip = NULL; 1356da14cebeSEric Cheng mcip->mci_rx_fn = mac_pkt_drop; 1357da14cebeSEric Cheng mcip->mci_rx_arg = NULL; 1358fc4e975dSVenugopal Iyer mcip->mci_rx_p_fn = NULL; 1359fc4e975dSVenugopal Iyer mcip->mci_rx_p_arg = NULL; 1360fc4e975dSVenugopal Iyer mcip->mci_p_unicast_list = NULL; 1361da14cebeSEric Cheng mcip->mci_direct_rx_fn = NULL; 1362da14cebeSEric Cheng mcip->mci_direct_rx_arg = NULL; 13633bb0cb70SBryan Cantrill mcip->mci_vidcache = MCIP_VIDCACHE_INVALID; 1364da14cebeSEric Cheng 1365fc4e975dSVenugopal Iyer mcip->mci_unicast_list = NULL; 1366fc4e975dSVenugopal Iyer 1367da14cebeSEric Cheng if ((flags & MAC_OPEN_FLAGS_IS_VNIC) != 0) 1368da14cebeSEric Cheng mcip->mci_state_flags |= MCIS_IS_VNIC; 1369da14cebeSEric Cheng 1370da14cebeSEric Cheng if ((flags & MAC_OPEN_FLAGS_EXCLUSIVE) != 0) 1371da14cebeSEric Cheng mcip->mci_state_flags |= MCIS_EXCLUSIVE; 1372da14cebeSEric Cheng 1373da14cebeSEric Cheng if ((flags & MAC_OPEN_FLAGS_IS_AGGR_PORT) != 0) 1374da14cebeSEric Cheng mcip->mci_state_flags |= MCIS_IS_AGGR_PORT; 1375da14cebeSEric Cheng 13760dc2366fSVenugopal Iyer if (mip->mi_state_flags & MIS_IS_AGGR) 13770dc2366fSVenugopal Iyer mcip->mci_state_flags |= MCIS_IS_AGGR; 13780dc2366fSVenugopal Iyer 1379da14cebeSEric Cheng if ((flags & MAC_OPEN_FLAGS_USE_DATALINK_NAME) != 0) { 1380da14cebeSEric Cheng datalink_id_t linkid; 1381da14cebeSEric Cheng 1382da14cebeSEric Cheng ASSERT(name == NULL); 1383da14cebeSEric Cheng if ((err = dls_devnet_macname2linkid(mip->mi_name, 1384da14cebeSEric Cheng &linkid)) != 0) { 1385da14cebeSEric Cheng goto done; 1386da14cebeSEric Cheng } 1387da14cebeSEric Cheng if ((err = dls_mgmt_get_linkinfo(linkid, mcip->mci_name, NULL, 1388da14cebeSEric Cheng NULL, NULL)) != 0) { 1389da14cebeSEric Cheng /* 1390da14cebeSEric Cheng * Use mac name if dlmgmtd is not available. 1391da14cebeSEric Cheng */ 1392da14cebeSEric Cheng if (err == EBADF) { 1393da14cebeSEric Cheng (void) strlcpy(mcip->mci_name, mip->mi_name, 1394da14cebeSEric Cheng sizeof (mcip->mci_name)); 1395da14cebeSEric Cheng err = 0; 1396da14cebeSEric Cheng } else { 1397da14cebeSEric Cheng goto done; 1398da14cebeSEric Cheng } 1399da14cebeSEric Cheng } 1400da14cebeSEric Cheng mcip->mci_state_flags |= MCIS_USE_DATALINK_NAME; 1401da14cebeSEric Cheng } else { 1402da14cebeSEric Cheng ASSERT(name != NULL); 1403da14cebeSEric Cheng if (strlen(name) > MAXNAMELEN) { 1404da14cebeSEric Cheng err = EINVAL; 1405da14cebeSEric Cheng goto done; 1406da14cebeSEric Cheng } 1407da14cebeSEric Cheng (void) strlcpy(mcip->mci_name, name, sizeof (mcip->mci_name)); 1408da14cebeSEric Cheng } 1409fc4e975dSVenugopal Iyer 1410fc4e975dSVenugopal Iyer if (flags & MAC_OPEN_FLAGS_MULTI_PRIMARY) 1411fc4e975dSVenugopal Iyer mcip->mci_flags |= MAC_CLIENT_FLAGS_MULTI_PRIMARY; 1412fc4e975dSVenugopal Iyer 14130dc2366fSVenugopal Iyer if (flags & MAC_OPEN_FLAGS_NO_UNICAST_ADDR) 14140dc2366fSVenugopal Iyer mcip->mci_state_flags |= MCIS_NO_UNICAST_ADDR; 14150dc2366fSVenugopal Iyer 14160dc2366fSVenugopal Iyer mac_protect_init(mcip); 14170dc2366fSVenugopal Iyer 1418da14cebeSEric Cheng /* the subflow table will be created dynamically */ 1419da14cebeSEric Cheng mcip->mci_subflow_tab = NULL; 1420da14cebeSEric Cheng 14210dc2366fSVenugopal Iyer mcip->mci_misc_stat.mms_multircv = 0; 14220dc2366fSVenugopal Iyer mcip->mci_misc_stat.mms_brdcstrcv = 0; 14230dc2366fSVenugopal Iyer mcip->mci_misc_stat.mms_multixmt = 0; 14240dc2366fSVenugopal Iyer mcip->mci_misc_stat.mms_brdcstxmt = 0; 1425da14cebeSEric Cheng 1426da14cebeSEric Cheng /* Create an initial flow */ 1427da14cebeSEric Cheng 1428da14cebeSEric Cheng err = mac_flow_create(NULL, NULL, mcip->mci_name, NULL, 1429da14cebeSEric Cheng mcip->mci_state_flags & MCIS_IS_VNIC ? FLOW_VNIC_MAC : 1430da14cebeSEric Cheng FLOW_PRIMARY_MAC, &flent); 1431da14cebeSEric Cheng if (err != 0) 1432da14cebeSEric Cheng goto done; 1433da14cebeSEric Cheng mcip->mci_flent = flent; 1434da14cebeSEric Cheng FLOW_MARK(flent, FE_MC_NO_DATAPATH); 1435da14cebeSEric Cheng flent->fe_mcip = mcip; 1436da14cebeSEric Cheng /* 1437da14cebeSEric Cheng * Place initial creation reference on the flow. This reference 1438da14cebeSEric Cheng * is released in the corresponding delete action viz. 1439da14cebeSEric Cheng * mac_unicast_remove after waiting for all transient refs to 1440da14cebeSEric Cheng * to go away. The wait happens in mac_flow_wait. 1441da14cebeSEric Cheng */ 1442da14cebeSEric Cheng FLOW_REFHOLD(flent); 1443da14cebeSEric Cheng 1444da14cebeSEric Cheng /* 1445da14cebeSEric Cheng * Do this ahead of the mac_bcast_add() below so that the mi_nclients 1446da14cebeSEric Cheng * will have the right value for mac_rx_srs_setup(). 1447da14cebeSEric Cheng */ 1448da14cebeSEric Cheng mac_client_add(mcip); 1449da14cebeSEric Cheng 1450da14cebeSEric Cheng mcip->mci_share = NULL; 14510dc2366fSVenugopal Iyer if (share_desired) 1452da14cebeSEric Cheng i_mac_share_alloc(mcip); 1453da14cebeSEric Cheng 14540dc2366fSVenugopal Iyer /* 14550dc2366fSVenugopal Iyer * We will do mimimal datapath setup to allow a MAC client to 14560dc2366fSVenugopal Iyer * transmit or receive non-unicast packets without waiting 14570dc2366fSVenugopal Iyer * for mac_unicast_add. 14580dc2366fSVenugopal Iyer */ 14590dc2366fSVenugopal Iyer if (mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR) { 14600dc2366fSVenugopal Iyer if ((err = mac_client_datapath_setup(mcip, VLAN_ID_NONE, 14610dc2366fSVenugopal Iyer NULL, NULL, B_TRUE, NULL)) != 0) { 14620dc2366fSVenugopal Iyer goto done; 14630dc2366fSVenugopal Iyer } 14640dc2366fSVenugopal Iyer } 14651a41ca23SJerry Jelinek 14661a41ca23SJerry Jelinek DTRACE_PROBE2(mac__client__open__allocated, mac_impl_t *, 14671a41ca23SJerry Jelinek mcip->mci_mip, mac_client_impl_t *, mcip); 14681a41ca23SJerry Jelinek 14691a41ca23SJerry Jelinek *mchp = (mac_client_handle_t)mcip; 1470da14cebeSEric Cheng i_mac_perim_exit(mip); 1471da14cebeSEric Cheng return (0); 1472da14cebeSEric Cheng 1473da14cebeSEric Cheng done: 1474da14cebeSEric Cheng i_mac_perim_exit(mip); 1475da14cebeSEric Cheng mcip->mci_state_flags = 0; 1476da14cebeSEric Cheng mcip->mci_tx_flag = 0; 1477da14cebeSEric Cheng kmem_cache_free(mac_client_impl_cache, mcip); 1478da14cebeSEric Cheng return (err); 1479da14cebeSEric Cheng } 1480da14cebeSEric Cheng 1481da14cebeSEric Cheng /* 1482da14cebeSEric Cheng * Close the specified MAC client handle. 1483da14cebeSEric Cheng */ 1484da14cebeSEric Cheng void 1485da14cebeSEric Cheng mac_client_close(mac_client_handle_t mch, uint16_t flags) 1486da14cebeSEric Cheng { 1487da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 1488da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip; 1489da14cebeSEric Cheng flow_entry_t *flent; 1490da14cebeSEric Cheng 1491da14cebeSEric Cheng i_mac_perim_enter(mip); 1492da14cebeSEric Cheng 1493da14cebeSEric Cheng if (flags & MAC_CLOSE_FLAGS_EXCLUSIVE) 1494da14cebeSEric Cheng mcip->mci_state_flags &= ~MCIS_EXCLUSIVE; 1495da14cebeSEric Cheng 1496da14cebeSEric Cheng if ((mcip->mci_state_flags & MCIS_IS_VNIC) && 1497da14cebeSEric Cheng !(flags & MAC_CLOSE_FLAGS_IS_VNIC)) { 1498da14cebeSEric Cheng /* 1499da14cebeSEric Cheng * This is an upper VNIC client initiated operation. 1500da14cebeSEric Cheng * The lower MAC client will be closed by the VNIC driver 1501da14cebeSEric Cheng * when the VNIC is deleted. 1502da14cebeSEric Cheng */ 1503da14cebeSEric Cheng 1504da14cebeSEric Cheng i_mac_perim_exit(mip); 1505da14cebeSEric Cheng return; 1506da14cebeSEric Cheng } 1507da14cebeSEric Cheng 15080dc2366fSVenugopal Iyer /* If we have only setup up minimal datapth setup, tear it down */ 15090dc2366fSVenugopal Iyer if (mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR) { 15100dc2366fSVenugopal Iyer mac_client_datapath_teardown((mac_client_handle_t)mcip, NULL, 15110dc2366fSVenugopal Iyer mcip->mci_flent); 15120dc2366fSVenugopal Iyer mcip->mci_state_flags &= ~MCIS_NO_UNICAST_ADDR; 15130dc2366fSVenugopal Iyer } 15140dc2366fSVenugopal Iyer 1515da14cebeSEric Cheng /* 1516da14cebeSEric Cheng * Remove the flent associated with the MAC client 1517da14cebeSEric Cheng */ 1518da14cebeSEric Cheng flent = mcip->mci_flent; 1519da14cebeSEric Cheng mcip->mci_flent = NULL; 1520da14cebeSEric Cheng FLOW_FINAL_REFRELE(flent); 1521da14cebeSEric Cheng 1522da14cebeSEric Cheng /* 1523da14cebeSEric Cheng * MAC clients must remove the unicast addresses and promisc callbacks 1524da14cebeSEric Cheng * they added before issuing a mac_client_close(). 1525da14cebeSEric Cheng */ 1526da14cebeSEric Cheng ASSERT(mcip->mci_unicast_list == NULL); 1527da14cebeSEric Cheng ASSERT(mcip->mci_promisc_list == NULL); 1528da14cebeSEric Cheng ASSERT(mcip->mci_tx_notify_cb_list == NULL); 1529da14cebeSEric Cheng 1530da14cebeSEric Cheng i_mac_share_free(mcip); 15310dc2366fSVenugopal Iyer mac_protect_fini(mcip); 1532da14cebeSEric Cheng mac_client_remove(mcip); 1533da14cebeSEric Cheng 1534da14cebeSEric Cheng i_mac_perim_exit(mip); 1535da14cebeSEric Cheng mcip->mci_subflow_tab = NULL; 1536da14cebeSEric Cheng mcip->mci_state_flags = 0; 1537da14cebeSEric Cheng mcip->mci_tx_flag = 0; 1538da14cebeSEric Cheng kmem_cache_free(mac_client_impl_cache, mch); 1539da14cebeSEric Cheng } 1540da14cebeSEric Cheng 1541da14cebeSEric Cheng /* 15428d4cf8d8S * Set the rx bypass receive callback. 1543da14cebeSEric Cheng */ 1544da14cebeSEric Cheng boolean_t 1545da14cebeSEric Cheng mac_rx_bypass_set(mac_client_handle_t mch, mac_direct_rx_t rx_fn, void *arg1) 1546da14cebeSEric Cheng { 1547da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 1548da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip; 1549da14cebeSEric Cheng 1550da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 1551da14cebeSEric Cheng 1552da14cebeSEric Cheng /* 1553ae6aa22aSVenugopal Iyer * If the mac_client is a VLAN, we should not do DLS bypass and 1554ae6aa22aSVenugopal Iyer * instead let the packets come up via mac_rx_deliver so the vlan 1555ae6aa22aSVenugopal Iyer * header can be stripped. 1556da14cebeSEric Cheng */ 1557ae6aa22aSVenugopal Iyer if (mcip->mci_nvids > 0) 1558da14cebeSEric Cheng return (B_FALSE); 1559da14cebeSEric Cheng 1560da14cebeSEric Cheng /* 1561da14cebeSEric Cheng * These are not accessed directly in the data path, and hence 1562da14cebeSEric Cheng * don't need any protection 1563da14cebeSEric Cheng */ 1564da14cebeSEric Cheng mcip->mci_direct_rx_fn = rx_fn; 1565da14cebeSEric Cheng mcip->mci_direct_rx_arg = arg1; 1566da14cebeSEric Cheng return (B_TRUE); 1567da14cebeSEric Cheng } 1568da14cebeSEric Cheng 1569da14cebeSEric Cheng /* 15708d4cf8d8S * Enable/Disable rx bypass. By default, bypass is assumed to be enabled. 15718d4cf8d8S */ 15728d4cf8d8S void 15738d4cf8d8S mac_rx_bypass_enable(mac_client_handle_t mch) 15748d4cf8d8S { 15758d4cf8d8S ((mac_client_impl_t *)mch)->mci_state_flags &= ~MCIS_RX_BYPASS_DISABLE; 15768d4cf8d8S } 15778d4cf8d8S 15788d4cf8d8S void 15798d4cf8d8S mac_rx_bypass_disable(mac_client_handle_t mch) 15808d4cf8d8S { 15818d4cf8d8S ((mac_client_impl_t *)mch)->mci_state_flags |= MCIS_RX_BYPASS_DISABLE; 15828d4cf8d8S } 15838d4cf8d8S 15848d4cf8d8S /* 1585da14cebeSEric Cheng * Set the receive callback for the specified MAC client. There can be 1586da14cebeSEric Cheng * at most one such callback per MAC client. 1587da14cebeSEric Cheng */ 1588da14cebeSEric Cheng void 1589da14cebeSEric Cheng mac_rx_set(mac_client_handle_t mch, mac_rx_t rx_fn, void *arg) 1590da14cebeSEric Cheng { 1591da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 1592da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip; 15931a41ca23SJerry Jelinek mac_impl_t *umip = mcip->mci_upper_mip; 1594da14cebeSEric Cheng 1595da14cebeSEric Cheng /* 1596da14cebeSEric Cheng * Instead of adding an extra set of locks and refcnts in 1597da14cebeSEric Cheng * the datapath at the mac client boundary, we temporarily quiesce 1598da14cebeSEric Cheng * the SRS and related entities. We then change the receive function 1599da14cebeSEric Cheng * without interference from any receive data thread and then reenable 1600da14cebeSEric Cheng * the data flow subsequently. 1601da14cebeSEric Cheng */ 1602da14cebeSEric Cheng i_mac_perim_enter(mip); 1603da14cebeSEric Cheng mac_rx_client_quiesce(mch); 1604da14cebeSEric Cheng 1605da14cebeSEric Cheng mcip->mci_rx_fn = rx_fn; 1606da14cebeSEric Cheng mcip->mci_rx_arg = arg; 1607da14cebeSEric Cheng mac_rx_client_restart(mch); 1608da14cebeSEric Cheng i_mac_perim_exit(mip); 16091a41ca23SJerry Jelinek 16101a41ca23SJerry Jelinek /* 16111a41ca23SJerry Jelinek * If we're changing the rx function on the primary mac of a vnic, 16121a41ca23SJerry Jelinek * make sure any secondary macs on the vnic are updated as well. 16131a41ca23SJerry Jelinek */ 16141a41ca23SJerry Jelinek if (umip != NULL) { 16151a41ca23SJerry Jelinek ASSERT((umip->mi_state_flags & MIS_IS_VNIC) != 0); 16161a41ca23SJerry Jelinek mac_vnic_secondary_update(umip); 16171a41ca23SJerry Jelinek } 1618da14cebeSEric Cheng } 1619da14cebeSEric Cheng 1620da14cebeSEric Cheng /* 1621da14cebeSEric Cheng * Reset the receive callback for the specified MAC client. 1622da14cebeSEric Cheng */ 1623da14cebeSEric Cheng void 1624da14cebeSEric Cheng mac_rx_clear(mac_client_handle_t mch) 1625da14cebeSEric Cheng { 1626da14cebeSEric Cheng mac_rx_set(mch, mac_pkt_drop, NULL); 1627da14cebeSEric Cheng } 1628da14cebeSEric Cheng 16291a41ca23SJerry Jelinek void 16301a41ca23SJerry Jelinek mac_secondary_dup(mac_client_handle_t smch, mac_client_handle_t dmch) 16311a41ca23SJerry Jelinek { 16321a41ca23SJerry Jelinek mac_client_impl_t *smcip = (mac_client_impl_t *)smch; 16331a41ca23SJerry Jelinek mac_client_impl_t *dmcip = (mac_client_impl_t *)dmch; 16341a41ca23SJerry Jelinek flow_entry_t *flent = dmcip->mci_flent; 16351a41ca23SJerry Jelinek 16361a41ca23SJerry Jelinek /* This should only be called to setup secondary macs */ 16371a41ca23SJerry Jelinek ASSERT((flent->fe_type & FLOW_PRIMARY_MAC) == 0); 16381a41ca23SJerry Jelinek 16391a41ca23SJerry Jelinek mac_rx_set(dmch, smcip->mci_rx_fn, smcip->mci_rx_arg); 16401a41ca23SJerry Jelinek dmcip->mci_promisc_list = smcip->mci_promisc_list; 16411a41ca23SJerry Jelinek 16421a41ca23SJerry Jelinek /* 16431a41ca23SJerry Jelinek * Duplicate the primary mac resources to the secondary. 16441a41ca23SJerry Jelinek * Since we already validated the resource controls when setting 16451a41ca23SJerry Jelinek * them on the primary, we can ignore errors here. 16461a41ca23SJerry Jelinek */ 16471a41ca23SJerry Jelinek (void) mac_resource_ctl_set(dmch, MCIP_RESOURCE_PROPS(smcip)); 16481a41ca23SJerry Jelinek } 16491a41ca23SJerry Jelinek 16501a41ca23SJerry Jelinek /* 16511a41ca23SJerry Jelinek * Called when removing a secondary MAC. Currently only clears the promisc_list 16521a41ca23SJerry Jelinek * since we share the primary mac's promisc_list. 16531a41ca23SJerry Jelinek */ 16541a41ca23SJerry Jelinek void 16551a41ca23SJerry Jelinek mac_secondary_cleanup(mac_client_handle_t mch) 16561a41ca23SJerry Jelinek { 16571a41ca23SJerry Jelinek mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 16581a41ca23SJerry Jelinek flow_entry_t *flent = mcip->mci_flent; 16591a41ca23SJerry Jelinek 16601a41ca23SJerry Jelinek /* This should only be called for secondary macs */ 16611a41ca23SJerry Jelinek ASSERT((flent->fe_type & FLOW_PRIMARY_MAC) == 0); 16621a41ca23SJerry Jelinek mcip->mci_promisc_list = NULL; 16631a41ca23SJerry Jelinek } 16641a41ca23SJerry Jelinek 1665da14cebeSEric Cheng /* 1666da14cebeSEric Cheng * Walk the MAC client subflow table and updates their priority values. 1667da14cebeSEric Cheng */ 1668da14cebeSEric Cheng static int 1669da14cebeSEric Cheng mac_update_subflow_priority_cb(flow_entry_t *flent, void *arg) 1670da14cebeSEric Cheng { 1671da14cebeSEric Cheng mac_flow_update_priority(arg, flent); 1672da14cebeSEric Cheng return (0); 1673da14cebeSEric Cheng } 1674da14cebeSEric Cheng 1675da14cebeSEric Cheng void 1676da14cebeSEric Cheng mac_update_subflow_priority(mac_client_impl_t *mcip) 1677da14cebeSEric Cheng { 1678da14cebeSEric Cheng (void) mac_flow_walk(mcip->mci_subflow_tab, 1679da14cebeSEric Cheng mac_update_subflow_priority_cb, mcip); 1680da14cebeSEric Cheng } 1681da14cebeSEric Cheng 1682da14cebeSEric Cheng /* 16830dc2366fSVenugopal Iyer * Modify the TX or RX ring properties. We could either just move around 16840dc2366fSVenugopal Iyer * rings, i.e add/remove rings given to a client. Or this might cause the 16850dc2366fSVenugopal Iyer * client to move from hardware based to software or the other way around. 16860dc2366fSVenugopal Iyer * If we want to reset this property, then we clear the mask, additionally 16870dc2366fSVenugopal Iyer * if the client was given a non-default group we remove all rings except 16880dc2366fSVenugopal Iyer * for 1 and give it back to the default group. 16890dc2366fSVenugopal Iyer */ 16900dc2366fSVenugopal Iyer int 16910dc2366fSVenugopal Iyer mac_client_set_rings_prop(mac_client_impl_t *mcip, mac_resource_props_t *mrp, 16920dc2366fSVenugopal Iyer mac_resource_props_t *tmrp) 16930dc2366fSVenugopal Iyer { 16940dc2366fSVenugopal Iyer mac_impl_t *mip = mcip->mci_mip; 16950dc2366fSVenugopal Iyer flow_entry_t *flent = mcip->mci_flent; 16960dc2366fSVenugopal Iyer uint8_t *mac_addr; 16970dc2366fSVenugopal Iyer int err = 0; 16980dc2366fSVenugopal Iyer mac_group_t *defgrp; 16990dc2366fSVenugopal Iyer mac_group_t *group; 17000dc2366fSVenugopal Iyer mac_group_t *ngrp; 17010dc2366fSVenugopal Iyer mac_resource_props_t *cmrp = MCIP_RESOURCE_PROPS(mcip); 17020dc2366fSVenugopal Iyer uint_t ringcnt; 17030dc2366fSVenugopal Iyer boolean_t unspec; 17040dc2366fSVenugopal Iyer 17050dc2366fSVenugopal Iyer if (mcip->mci_share != NULL) 17060dc2366fSVenugopal Iyer return (EINVAL); 17070dc2366fSVenugopal Iyer 17080dc2366fSVenugopal Iyer if (mrp->mrp_mask & MRP_RX_RINGS) { 17090dc2366fSVenugopal Iyer unspec = mrp->mrp_mask & MRP_RXRINGS_UNSPEC; 17100dc2366fSVenugopal Iyer group = flent->fe_rx_ring_group; 17110dc2366fSVenugopal Iyer defgrp = MAC_DEFAULT_RX_GROUP(mip); 17120dc2366fSVenugopal Iyer mac_addr = flent->fe_flow_desc.fd_dst_mac; 17130dc2366fSVenugopal Iyer 17140dc2366fSVenugopal Iyer /* 17150dc2366fSVenugopal Iyer * No resulting change. If we are resetting on a client on 17160dc2366fSVenugopal Iyer * which there was no rx rings property. For dynamic group 17170dc2366fSVenugopal Iyer * if we are setting the same number of rings already set. 17180dc2366fSVenugopal Iyer * For static group if we are requesting a group again. 17190dc2366fSVenugopal Iyer */ 17200dc2366fSVenugopal Iyer if (mrp->mrp_mask & MRP_RINGS_RESET) { 17210dc2366fSVenugopal Iyer if (!(tmrp->mrp_mask & MRP_RX_RINGS)) 17220dc2366fSVenugopal Iyer return (0); 17230dc2366fSVenugopal Iyer } else { 17240dc2366fSVenugopal Iyer if (unspec) { 17250dc2366fSVenugopal Iyer if (tmrp->mrp_mask & MRP_RXRINGS_UNSPEC) 17260dc2366fSVenugopal Iyer return (0); 17270dc2366fSVenugopal Iyer } else if (mip->mi_rx_group_type == 17280dc2366fSVenugopal Iyer MAC_GROUP_TYPE_DYNAMIC) { 17290dc2366fSVenugopal Iyer if ((tmrp->mrp_mask & MRP_RX_RINGS) && 17300dc2366fSVenugopal Iyer !(tmrp->mrp_mask & MRP_RXRINGS_UNSPEC) && 17310dc2366fSVenugopal Iyer mrp->mrp_nrxrings == tmrp->mrp_nrxrings) { 17320dc2366fSVenugopal Iyer return (0); 17330dc2366fSVenugopal Iyer } 17340dc2366fSVenugopal Iyer } 17350dc2366fSVenugopal Iyer } 17360dc2366fSVenugopal Iyer /* Resetting the prop */ 17370dc2366fSVenugopal Iyer if (mrp->mrp_mask & MRP_RINGS_RESET) { 17380dc2366fSVenugopal Iyer /* 17390dc2366fSVenugopal Iyer * We will just keep one ring and give others back if 17400dc2366fSVenugopal Iyer * we are not the primary. For the primary we give 17410dc2366fSVenugopal Iyer * all the rings in the default group except the 17420dc2366fSVenugopal Iyer * default ring. If it is a static group, then 17430dc2366fSVenugopal Iyer * we don't do anything, but clear the MRP_RX_RINGS 17440dc2366fSVenugopal Iyer * flag. 17450dc2366fSVenugopal Iyer */ 17460dc2366fSVenugopal Iyer if (group != defgrp) { 17470dc2366fSVenugopal Iyer if (mip->mi_rx_group_type == 17480dc2366fSVenugopal Iyer MAC_GROUP_TYPE_DYNAMIC) { 17490dc2366fSVenugopal Iyer /* 17500dc2366fSVenugopal Iyer * This group has reserved rings 17510dc2366fSVenugopal Iyer * that need to be released now, 17520dc2366fSVenugopal Iyer * so does the group. 17530dc2366fSVenugopal Iyer */ 17540dc2366fSVenugopal Iyer MAC_RX_RING_RELEASED(mip, 17550dc2366fSVenugopal Iyer group->mrg_cur_count); 17560dc2366fSVenugopal Iyer MAC_RX_GRP_RELEASED(mip); 17570dc2366fSVenugopal Iyer if ((flent->fe_type & 17580dc2366fSVenugopal Iyer FLOW_PRIMARY_MAC) != 0) { 17590dc2366fSVenugopal Iyer if (mip->mi_nactiveclients == 17600dc2366fSVenugopal Iyer 1) { 17610dc2366fSVenugopal Iyer (void) 17620dc2366fSVenugopal Iyer mac_rx_switch_group( 17630dc2366fSVenugopal Iyer mcip, group, 17640dc2366fSVenugopal Iyer defgrp); 17650dc2366fSVenugopal Iyer return (0); 17660dc2366fSVenugopal Iyer } else { 17670dc2366fSVenugopal Iyer cmrp->mrp_nrxrings = 17680dc2366fSVenugopal Iyer group-> 17690dc2366fSVenugopal Iyer mrg_cur_count + 17700dc2366fSVenugopal Iyer defgrp-> 17710dc2366fSVenugopal Iyer mrg_cur_count - 1; 17720dc2366fSVenugopal Iyer } 17730dc2366fSVenugopal Iyer } else { 17740dc2366fSVenugopal Iyer cmrp->mrp_nrxrings = 1; 17750dc2366fSVenugopal Iyer } 17760dc2366fSVenugopal Iyer (void) mac_group_ring_modify(mcip, 17770dc2366fSVenugopal Iyer group, defgrp); 17780dc2366fSVenugopal Iyer } else { 17790dc2366fSVenugopal Iyer /* 17800dc2366fSVenugopal Iyer * If this is a static group, we 17810dc2366fSVenugopal Iyer * need to release the group. The 17820dc2366fSVenugopal Iyer * client will remain in the same 17830dc2366fSVenugopal Iyer * group till some other client 17840dc2366fSVenugopal Iyer * needs this group. 17850dc2366fSVenugopal Iyer */ 17860dc2366fSVenugopal Iyer MAC_RX_GRP_RELEASED(mip); 17870dc2366fSVenugopal Iyer } 17880dc2366fSVenugopal Iyer /* Let check if we can give this an excl group */ 17890dc2366fSVenugopal Iyer } else if (group == defgrp) { 17900dc2366fSVenugopal Iyer ngrp = mac_reserve_rx_group(mcip, mac_addr, 17910dc2366fSVenugopal Iyer B_TRUE); 17920dc2366fSVenugopal Iyer /* Couldn't give it a group, that's fine */ 17930dc2366fSVenugopal Iyer if (ngrp == NULL) 17940dc2366fSVenugopal Iyer return (0); 17950dc2366fSVenugopal Iyer /* Switch to H/W */ 17960dc2366fSVenugopal Iyer if (mac_rx_switch_group(mcip, defgrp, ngrp) != 17970dc2366fSVenugopal Iyer 0) { 17980dc2366fSVenugopal Iyer mac_stop_group(ngrp); 17990dc2366fSVenugopal Iyer return (0); 18000dc2366fSVenugopal Iyer } 18010dc2366fSVenugopal Iyer } 18020dc2366fSVenugopal Iyer /* 18030dc2366fSVenugopal Iyer * If the client is in the default group, we will 18040dc2366fSVenugopal Iyer * just clear the MRP_RX_RINGS and leave it as 18050dc2366fSVenugopal Iyer * it rather than look for an exclusive group 18060dc2366fSVenugopal Iyer * for it. 18070dc2366fSVenugopal Iyer */ 18080dc2366fSVenugopal Iyer return (0); 18090dc2366fSVenugopal Iyer } 18100dc2366fSVenugopal Iyer 18110dc2366fSVenugopal Iyer if (group == defgrp && ((mrp->mrp_nrxrings > 0) || unspec)) { 18120dc2366fSVenugopal Iyer ngrp = mac_reserve_rx_group(mcip, mac_addr, B_TRUE); 18130dc2366fSVenugopal Iyer if (ngrp == NULL) 18140dc2366fSVenugopal Iyer return (ENOSPC); 18150dc2366fSVenugopal Iyer 18160dc2366fSVenugopal Iyer /* Switch to H/W */ 18170dc2366fSVenugopal Iyer if (mac_rx_switch_group(mcip, defgrp, ngrp) != 0) { 18180dc2366fSVenugopal Iyer mac_release_rx_group(mcip, ngrp); 18190dc2366fSVenugopal Iyer return (ENOSPC); 18200dc2366fSVenugopal Iyer } 18210dc2366fSVenugopal Iyer MAC_RX_GRP_RESERVED(mip); 18220dc2366fSVenugopal Iyer if (mip->mi_rx_group_type == MAC_GROUP_TYPE_DYNAMIC) 18230dc2366fSVenugopal Iyer MAC_RX_RING_RESERVED(mip, ngrp->mrg_cur_count); 18240dc2366fSVenugopal Iyer } else if (group != defgrp && !unspec && 18250dc2366fSVenugopal Iyer mrp->mrp_nrxrings == 0) { 18260dc2366fSVenugopal Iyer /* Switch to S/W */ 18270dc2366fSVenugopal Iyer ringcnt = group->mrg_cur_count; 18280dc2366fSVenugopal Iyer if (mac_rx_switch_group(mcip, group, defgrp) != 0) 18290dc2366fSVenugopal Iyer return (ENOSPC); 18300dc2366fSVenugopal Iyer if (tmrp->mrp_mask & MRP_RX_RINGS) { 18310dc2366fSVenugopal Iyer MAC_RX_GRP_RELEASED(mip); 18320dc2366fSVenugopal Iyer if (mip->mi_rx_group_type == 18330dc2366fSVenugopal Iyer MAC_GROUP_TYPE_DYNAMIC) { 18340dc2366fSVenugopal Iyer MAC_RX_RING_RELEASED(mip, ringcnt); 18350dc2366fSVenugopal Iyer } 18360dc2366fSVenugopal Iyer } 18370dc2366fSVenugopal Iyer } else if (group != defgrp && mip->mi_rx_group_type == 18380dc2366fSVenugopal Iyer MAC_GROUP_TYPE_DYNAMIC) { 18390dc2366fSVenugopal Iyer ringcnt = group->mrg_cur_count; 18400dc2366fSVenugopal Iyer err = mac_group_ring_modify(mcip, group, defgrp); 18410dc2366fSVenugopal Iyer if (err != 0) 18420dc2366fSVenugopal Iyer return (err); 18430dc2366fSVenugopal Iyer /* 18440dc2366fSVenugopal Iyer * Update the accounting. If this group 18450dc2366fSVenugopal Iyer * already had explicitly reserved rings, 18460dc2366fSVenugopal Iyer * we need to update the rings based on 18470dc2366fSVenugopal Iyer * the new ring count. If this group 18480dc2366fSVenugopal Iyer * had not explicitly reserved rings, 18490dc2366fSVenugopal Iyer * then we just reserve the rings asked for 18500dc2366fSVenugopal Iyer * and reserve the group. 18510dc2366fSVenugopal Iyer */ 18520dc2366fSVenugopal Iyer if (tmrp->mrp_mask & MRP_RX_RINGS) { 18530dc2366fSVenugopal Iyer if (ringcnt > group->mrg_cur_count) { 18540dc2366fSVenugopal Iyer MAC_RX_RING_RELEASED(mip, 18550dc2366fSVenugopal Iyer ringcnt - group->mrg_cur_count); 18560dc2366fSVenugopal Iyer } else { 18570dc2366fSVenugopal Iyer MAC_RX_RING_RESERVED(mip, 18580dc2366fSVenugopal Iyer group->mrg_cur_count - ringcnt); 18590dc2366fSVenugopal Iyer } 18600dc2366fSVenugopal Iyer } else { 18610dc2366fSVenugopal Iyer MAC_RX_RING_RESERVED(mip, group->mrg_cur_count); 18620dc2366fSVenugopal Iyer MAC_RX_GRP_RESERVED(mip); 18630dc2366fSVenugopal Iyer } 18640dc2366fSVenugopal Iyer } 18650dc2366fSVenugopal Iyer } 18660dc2366fSVenugopal Iyer if (mrp->mrp_mask & MRP_TX_RINGS) { 18670dc2366fSVenugopal Iyer unspec = mrp->mrp_mask & MRP_TXRINGS_UNSPEC; 18680dc2366fSVenugopal Iyer group = flent->fe_tx_ring_group; 18690dc2366fSVenugopal Iyer defgrp = MAC_DEFAULT_TX_GROUP(mip); 18700dc2366fSVenugopal Iyer 18710dc2366fSVenugopal Iyer /* 18720dc2366fSVenugopal Iyer * For static groups we only allow rings=0 or resetting the 18730dc2366fSVenugopal Iyer * rings property. 18740dc2366fSVenugopal Iyer */ 18750dc2366fSVenugopal Iyer if (mrp->mrp_ntxrings > 0 && 18760dc2366fSVenugopal Iyer mip->mi_tx_group_type != MAC_GROUP_TYPE_DYNAMIC) { 18770dc2366fSVenugopal Iyer return (ENOTSUP); 18780dc2366fSVenugopal Iyer } 18790dc2366fSVenugopal Iyer if (mrp->mrp_mask & MRP_RINGS_RESET) { 18800dc2366fSVenugopal Iyer if (!(tmrp->mrp_mask & MRP_TX_RINGS)) 18810dc2366fSVenugopal Iyer return (0); 18820dc2366fSVenugopal Iyer } else { 18830dc2366fSVenugopal Iyer if (unspec) { 18840dc2366fSVenugopal Iyer if (tmrp->mrp_mask & MRP_TXRINGS_UNSPEC) 18850dc2366fSVenugopal Iyer return (0); 18860dc2366fSVenugopal Iyer } else if (mip->mi_tx_group_type == 18870dc2366fSVenugopal Iyer MAC_GROUP_TYPE_DYNAMIC) { 18880dc2366fSVenugopal Iyer if ((tmrp->mrp_mask & MRP_TX_RINGS) && 18890dc2366fSVenugopal Iyer !(tmrp->mrp_mask & MRP_TXRINGS_UNSPEC) && 18900dc2366fSVenugopal Iyer mrp->mrp_ntxrings == tmrp->mrp_ntxrings) { 18910dc2366fSVenugopal Iyer return (0); 18920dc2366fSVenugopal Iyer } 18930dc2366fSVenugopal Iyer } 18940dc2366fSVenugopal Iyer } 18950dc2366fSVenugopal Iyer /* Resetting the prop */ 18960dc2366fSVenugopal Iyer if (mrp->mrp_mask & MRP_RINGS_RESET) { 18970dc2366fSVenugopal Iyer if (group != defgrp) { 18980dc2366fSVenugopal Iyer if (mip->mi_tx_group_type == 18990dc2366fSVenugopal Iyer MAC_GROUP_TYPE_DYNAMIC) { 19000dc2366fSVenugopal Iyer ringcnt = group->mrg_cur_count; 19010dc2366fSVenugopal Iyer if ((flent->fe_type & 19020dc2366fSVenugopal Iyer FLOW_PRIMARY_MAC) != 0) { 19030dc2366fSVenugopal Iyer mac_tx_client_quiesce( 19040dc2366fSVenugopal Iyer (mac_client_handle_t) 19050dc2366fSVenugopal Iyer mcip); 19060dc2366fSVenugopal Iyer mac_tx_switch_group(mcip, 19070dc2366fSVenugopal Iyer group, defgrp); 19080dc2366fSVenugopal Iyer mac_tx_client_restart( 19090dc2366fSVenugopal Iyer (mac_client_handle_t) 19100dc2366fSVenugopal Iyer mcip); 19110dc2366fSVenugopal Iyer MAC_TX_GRP_RELEASED(mip); 19120dc2366fSVenugopal Iyer MAC_TX_RING_RELEASED(mip, 19130dc2366fSVenugopal Iyer ringcnt); 19140dc2366fSVenugopal Iyer return (0); 19150dc2366fSVenugopal Iyer } 19160dc2366fSVenugopal Iyer cmrp->mrp_ntxrings = 1; 19170dc2366fSVenugopal Iyer (void) mac_group_ring_modify(mcip, 19180dc2366fSVenugopal Iyer group, defgrp); 19190dc2366fSVenugopal Iyer /* 19200dc2366fSVenugopal Iyer * This group has reserved rings 19210dc2366fSVenugopal Iyer * that need to be released now. 19220dc2366fSVenugopal Iyer */ 19230dc2366fSVenugopal Iyer MAC_TX_RING_RELEASED(mip, ringcnt); 19240dc2366fSVenugopal Iyer } 19250dc2366fSVenugopal Iyer /* 19260dc2366fSVenugopal Iyer * If this is a static group, we 19270dc2366fSVenugopal Iyer * need to release the group. The 19280dc2366fSVenugopal Iyer * client will remain in the same 19290dc2366fSVenugopal Iyer * group till some other client 19300dc2366fSVenugopal Iyer * needs this group. 19310dc2366fSVenugopal Iyer */ 19320dc2366fSVenugopal Iyer MAC_TX_GRP_RELEASED(mip); 19330dc2366fSVenugopal Iyer } else if (group == defgrp && 19340dc2366fSVenugopal Iyer (flent->fe_type & FLOW_PRIMARY_MAC) == 0) { 19350dc2366fSVenugopal Iyer ngrp = mac_reserve_tx_group(mcip, B_TRUE); 19360dc2366fSVenugopal Iyer if (ngrp == NULL) 19370dc2366fSVenugopal Iyer return (0); 19380dc2366fSVenugopal Iyer mac_tx_client_quiesce( 19390dc2366fSVenugopal Iyer (mac_client_handle_t)mcip); 19400dc2366fSVenugopal Iyer mac_tx_switch_group(mcip, defgrp, ngrp); 19410dc2366fSVenugopal Iyer mac_tx_client_restart( 19420dc2366fSVenugopal Iyer (mac_client_handle_t)mcip); 19430dc2366fSVenugopal Iyer } 19440dc2366fSVenugopal Iyer /* 19450dc2366fSVenugopal Iyer * If the client is in the default group, we will 19460dc2366fSVenugopal Iyer * just clear the MRP_TX_RINGS and leave it as 19470dc2366fSVenugopal Iyer * it rather than look for an exclusive group 19480dc2366fSVenugopal Iyer * for it. 19490dc2366fSVenugopal Iyer */ 19500dc2366fSVenugopal Iyer return (0); 19510dc2366fSVenugopal Iyer } 19520dc2366fSVenugopal Iyer 19530dc2366fSVenugopal Iyer /* Switch to H/W */ 19540dc2366fSVenugopal Iyer if (group == defgrp && ((mrp->mrp_ntxrings > 0) || unspec)) { 19550dc2366fSVenugopal Iyer ngrp = mac_reserve_tx_group(mcip, B_TRUE); 19560dc2366fSVenugopal Iyer if (ngrp == NULL) 19570dc2366fSVenugopal Iyer return (ENOSPC); 19580dc2366fSVenugopal Iyer mac_tx_client_quiesce((mac_client_handle_t)mcip); 19590dc2366fSVenugopal Iyer mac_tx_switch_group(mcip, defgrp, ngrp); 19600dc2366fSVenugopal Iyer mac_tx_client_restart((mac_client_handle_t)mcip); 19610dc2366fSVenugopal Iyer MAC_TX_GRP_RESERVED(mip); 19620dc2366fSVenugopal Iyer if (mip->mi_tx_group_type == MAC_GROUP_TYPE_DYNAMIC) 19630dc2366fSVenugopal Iyer MAC_TX_RING_RESERVED(mip, ngrp->mrg_cur_count); 19640dc2366fSVenugopal Iyer /* Switch to S/W */ 19650dc2366fSVenugopal Iyer } else if (group != defgrp && !unspec && 19660dc2366fSVenugopal Iyer mrp->mrp_ntxrings == 0) { 19670dc2366fSVenugopal Iyer /* Switch to S/W */ 19680dc2366fSVenugopal Iyer ringcnt = group->mrg_cur_count; 19690dc2366fSVenugopal Iyer mac_tx_client_quiesce((mac_client_handle_t)mcip); 19700dc2366fSVenugopal Iyer mac_tx_switch_group(mcip, group, defgrp); 19710dc2366fSVenugopal Iyer mac_tx_client_restart((mac_client_handle_t)mcip); 19720dc2366fSVenugopal Iyer if (tmrp->mrp_mask & MRP_TX_RINGS) { 19730dc2366fSVenugopal Iyer MAC_TX_GRP_RELEASED(mip); 19740dc2366fSVenugopal Iyer if (mip->mi_tx_group_type == 19750dc2366fSVenugopal Iyer MAC_GROUP_TYPE_DYNAMIC) { 19760dc2366fSVenugopal Iyer MAC_TX_RING_RELEASED(mip, ringcnt); 19770dc2366fSVenugopal Iyer } 19780dc2366fSVenugopal Iyer } 19790dc2366fSVenugopal Iyer } else if (group != defgrp && mip->mi_tx_group_type == 19800dc2366fSVenugopal Iyer MAC_GROUP_TYPE_DYNAMIC) { 19810dc2366fSVenugopal Iyer ringcnt = group->mrg_cur_count; 19820dc2366fSVenugopal Iyer err = mac_group_ring_modify(mcip, group, defgrp); 19830dc2366fSVenugopal Iyer if (err != 0) 19840dc2366fSVenugopal Iyer return (err); 19850dc2366fSVenugopal Iyer /* 19860dc2366fSVenugopal Iyer * Update the accounting. If this group 19870dc2366fSVenugopal Iyer * already had explicitly reserved rings, 19880dc2366fSVenugopal Iyer * we need to update the rings based on 19890dc2366fSVenugopal Iyer * the new ring count. If this group 19900dc2366fSVenugopal Iyer * had not explicitly reserved rings, 19910dc2366fSVenugopal Iyer * then we just reserve the rings asked for 19920dc2366fSVenugopal Iyer * and reserve the group. 19930dc2366fSVenugopal Iyer */ 19940dc2366fSVenugopal Iyer if (tmrp->mrp_mask & MRP_TX_RINGS) { 19950dc2366fSVenugopal Iyer if (ringcnt > group->mrg_cur_count) { 19960dc2366fSVenugopal Iyer MAC_TX_RING_RELEASED(mip, 19970dc2366fSVenugopal Iyer ringcnt - group->mrg_cur_count); 19980dc2366fSVenugopal Iyer } else { 19990dc2366fSVenugopal Iyer MAC_TX_RING_RESERVED(mip, 20000dc2366fSVenugopal Iyer group->mrg_cur_count - ringcnt); 20010dc2366fSVenugopal Iyer } 20020dc2366fSVenugopal Iyer } else { 20030dc2366fSVenugopal Iyer MAC_TX_RING_RESERVED(mip, group->mrg_cur_count); 20040dc2366fSVenugopal Iyer MAC_TX_GRP_RESERVED(mip); 20050dc2366fSVenugopal Iyer } 20060dc2366fSVenugopal Iyer } 20070dc2366fSVenugopal Iyer } 20080dc2366fSVenugopal Iyer return (0); 20090dc2366fSVenugopal Iyer } 20100dc2366fSVenugopal Iyer 20110dc2366fSVenugopal Iyer /* 2012da14cebeSEric Cheng * When the MAC client is being brought up (i.e. we do a unicast_add) we need 2013da14cebeSEric Cheng * to initialize the cpu and resource control structure in the 2014da14cebeSEric Cheng * mac_client_impl_t from the mac_impl_t (i.e if there are any cached 2015da14cebeSEric Cheng * properties before the flow entry for the unicast address was created). 2016da14cebeSEric Cheng */ 20171a41ca23SJerry Jelinek static int 2018da14cebeSEric Cheng mac_resource_ctl_set(mac_client_handle_t mch, mac_resource_props_t *mrp) 2019da14cebeSEric Cheng { 2020da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2021da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mcip->mci_mip; 20221a41ca23SJerry Jelinek mac_impl_t *umip = mcip->mci_upper_mip; 2023da14cebeSEric Cheng int err = 0; 20240dc2366fSVenugopal Iyer flow_entry_t *flent = mcip->mci_flent; 20250dc2366fSVenugopal Iyer mac_resource_props_t *omrp, *nmrp = MCIP_RESOURCE_PROPS(mcip); 2026da14cebeSEric Cheng 2027da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 2028da14cebeSEric Cheng 20290dc2366fSVenugopal Iyer err = mac_validate_props(mcip->mci_state_flags & MCIS_IS_VNIC ? 20300dc2366fSVenugopal Iyer mcip->mci_upper_mip : mip, mrp); 2031da14cebeSEric Cheng if (err != 0) 2032da14cebeSEric Cheng return (err); 2033da14cebeSEric Cheng 20340dc2366fSVenugopal Iyer /* 20350dc2366fSVenugopal Iyer * Copy over the existing properties since mac_update_resources 20360dc2366fSVenugopal Iyer * will modify the client's mrp. Currently, the saved property 20370dc2366fSVenugopal Iyer * is used to determine the difference between existing and 20380dc2366fSVenugopal Iyer * modified rings property. 20390dc2366fSVenugopal Iyer */ 20400dc2366fSVenugopal Iyer omrp = kmem_zalloc(sizeof (*omrp), KM_SLEEP); 20410dc2366fSVenugopal Iyer bcopy(nmrp, omrp, sizeof (*omrp)); 2042da14cebeSEric Cheng mac_update_resources(mrp, MCIP_RESOURCE_PROPS(mcip), B_FALSE); 2043da14cebeSEric Cheng if (MCIP_DATAPATH_SETUP(mcip)) { 2044da14cebeSEric Cheng /* 20450dc2366fSVenugopal Iyer * We support rings only for primary client when there are 20460dc2366fSVenugopal Iyer * multiple clients sharing the same MAC address (e.g. VLAN). 20470dc2366fSVenugopal Iyer */ 20480dc2366fSVenugopal Iyer if (mrp->mrp_mask & MRP_RX_RINGS || 20490dc2366fSVenugopal Iyer mrp->mrp_mask & MRP_TX_RINGS) { 20500dc2366fSVenugopal Iyer 20510dc2366fSVenugopal Iyer if ((err = mac_client_set_rings_prop(mcip, mrp, 20520dc2366fSVenugopal Iyer omrp)) != 0) { 20530dc2366fSVenugopal Iyer if (omrp->mrp_mask & MRP_RX_RINGS) { 20540dc2366fSVenugopal Iyer nmrp->mrp_mask |= MRP_RX_RINGS; 20550dc2366fSVenugopal Iyer nmrp->mrp_nrxrings = omrp->mrp_nrxrings; 20560dc2366fSVenugopal Iyer } else { 20570dc2366fSVenugopal Iyer nmrp->mrp_mask &= ~MRP_RX_RINGS; 20580dc2366fSVenugopal Iyer nmrp->mrp_nrxrings = 0; 20590dc2366fSVenugopal Iyer } 20600dc2366fSVenugopal Iyer if (omrp->mrp_mask & MRP_TX_RINGS) { 20610dc2366fSVenugopal Iyer nmrp->mrp_mask |= MRP_TX_RINGS; 20620dc2366fSVenugopal Iyer nmrp->mrp_ntxrings = omrp->mrp_ntxrings; 20630dc2366fSVenugopal Iyer } else { 20640dc2366fSVenugopal Iyer nmrp->mrp_mask &= ~MRP_TX_RINGS; 20650dc2366fSVenugopal Iyer nmrp->mrp_ntxrings = 0; 20660dc2366fSVenugopal Iyer } 20670dc2366fSVenugopal Iyer if (omrp->mrp_mask & MRP_RXRINGS_UNSPEC) 20680dc2366fSVenugopal Iyer omrp->mrp_mask |= MRP_RXRINGS_UNSPEC; 20690dc2366fSVenugopal Iyer else 20700dc2366fSVenugopal Iyer omrp->mrp_mask &= ~MRP_RXRINGS_UNSPEC; 20710dc2366fSVenugopal Iyer 20720dc2366fSVenugopal Iyer if (omrp->mrp_mask & MRP_TXRINGS_UNSPEC) 20730dc2366fSVenugopal Iyer omrp->mrp_mask |= MRP_TXRINGS_UNSPEC; 20740dc2366fSVenugopal Iyer else 20750dc2366fSVenugopal Iyer omrp->mrp_mask &= ~MRP_TXRINGS_UNSPEC; 20760dc2366fSVenugopal Iyer kmem_free(omrp, sizeof (*omrp)); 20770dc2366fSVenugopal Iyer return (err); 20780dc2366fSVenugopal Iyer } 20790dc2366fSVenugopal Iyer 20800dc2366fSVenugopal Iyer /* 20810dc2366fSVenugopal Iyer * If we modified the rings property of the primary 20820dc2366fSVenugopal Iyer * we need to update the property fields of its 20830dc2366fSVenugopal Iyer * VLANs as they inherit the primary's properites. 20840dc2366fSVenugopal Iyer */ 20850dc2366fSVenugopal Iyer if (mac_is_primary_client(mcip)) { 20860dc2366fSVenugopal Iyer mac_set_prim_vlan_rings(mip, 20870dc2366fSVenugopal Iyer MCIP_RESOURCE_PROPS(mcip)); 20880dc2366fSVenugopal Iyer } 20890dc2366fSVenugopal Iyer } 20900dc2366fSVenugopal Iyer /* 2091da14cebeSEric Cheng * We have to set this prior to calling mac_flow_modify. 2092da14cebeSEric Cheng */ 2093da14cebeSEric Cheng if (mrp->mrp_mask & MRP_PRIORITY) { 2094da14cebeSEric Cheng if (mrp->mrp_priority == MPL_RESET) { 2095da14cebeSEric Cheng MAC_CLIENT_SET_PRIORITY_RANGE(mcip, 2096da14cebeSEric Cheng MPL_LINK_DEFAULT); 2097da14cebeSEric Cheng } else { 2098da14cebeSEric Cheng MAC_CLIENT_SET_PRIORITY_RANGE(mcip, 2099da14cebeSEric Cheng mrp->mrp_priority); 2100da14cebeSEric Cheng } 2101da14cebeSEric Cheng } 2102da14cebeSEric Cheng 21030dc2366fSVenugopal Iyer mac_flow_modify(mip->mi_flow_tab, flent, mrp); 2104da14cebeSEric Cheng if (mrp->mrp_mask & MRP_PRIORITY) 2105da14cebeSEric Cheng mac_update_subflow_priority(mcip); 21061a41ca23SJerry Jelinek 21071a41ca23SJerry Jelinek /* Apply these resource settings to any secondary macs */ 21081a41ca23SJerry Jelinek if (umip != NULL) { 21091a41ca23SJerry Jelinek ASSERT((umip->mi_state_flags & MIS_IS_VNIC) != 0); 21101a41ca23SJerry Jelinek mac_vnic_secondary_update(umip); 21111a41ca23SJerry Jelinek } 2112da14cebeSEric Cheng } 21130dc2366fSVenugopal Iyer kmem_free(omrp, sizeof (*omrp)); 2114da14cebeSEric Cheng return (0); 2115da14cebeSEric Cheng } 2116da14cebeSEric Cheng 2117da14cebeSEric Cheng static int 2118da14cebeSEric Cheng mac_unicast_flow_create(mac_client_impl_t *mcip, uint8_t *mac_addr, 2119da14cebeSEric Cheng uint16_t vid, boolean_t is_primary, boolean_t first_flow, 2120da14cebeSEric Cheng flow_entry_t **flent, mac_resource_props_t *mrp) 2121da14cebeSEric Cheng { 2122da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mcip->mci_mip; 2123da14cebeSEric Cheng flow_desc_t flow_desc; 2124da000602SGirish Moodalbail char flowname[MAXFLOWNAMELEN]; 2125da14cebeSEric Cheng int err; 2126da14cebeSEric Cheng uint_t flent_flags; 2127da14cebeSEric Cheng 2128da14cebeSEric Cheng /* 2129da14cebeSEric Cheng * First unicast address being added, create a new flow 2130da14cebeSEric Cheng * for that MAC client. 2131da14cebeSEric Cheng */ 2132da14cebeSEric Cheng bzero(&flow_desc, sizeof (flow_desc)); 2133da14cebeSEric Cheng 21340dc2366fSVenugopal Iyer ASSERT(mac_addr != NULL || 21350dc2366fSVenugopal Iyer (mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR)); 21360dc2366fSVenugopal Iyer if (mac_addr != NULL) { 2137da14cebeSEric Cheng flow_desc.fd_mac_len = mip->mi_type->mt_addr_length; 2138da14cebeSEric Cheng bcopy(mac_addr, flow_desc.fd_dst_mac, flow_desc.fd_mac_len); 21390dc2366fSVenugopal Iyer } 2140da14cebeSEric Cheng flow_desc.fd_mask = FLOW_LINK_DST; 2141da14cebeSEric Cheng if (vid != 0) { 2142da14cebeSEric Cheng flow_desc.fd_vid = vid; 2143da14cebeSEric Cheng flow_desc.fd_mask |= FLOW_LINK_VID; 2144da14cebeSEric Cheng } 2145da14cebeSEric Cheng 2146da14cebeSEric Cheng /* 2147da14cebeSEric Cheng * XXX-nicolas. For now I'm keeping the FLOW_PRIMARY_MAC 2148da14cebeSEric Cheng * and FLOW_VNIC. Even though they're a hack inherited 2149da14cebeSEric Cheng * from the SRS code, we'll keep them for now. They're currently 2150da14cebeSEric Cheng * consumed by mac_datapath_setup() to create the SRS. 2151da14cebeSEric Cheng * That code should be eventually moved out of 2152da14cebeSEric Cheng * mac_datapath_setup() and moved to a mac_srs_create() 2153da14cebeSEric Cheng * function of some sort to keep things clean. 2154da14cebeSEric Cheng * 2155da14cebeSEric Cheng * Also, there's no reason why the SRS for the primary MAC 2156da14cebeSEric Cheng * client should be different than any other MAC client. Until 2157da14cebeSEric Cheng * this is cleaned-up, we support only one MAC unicast address 2158da14cebeSEric Cheng * per client. 2159da14cebeSEric Cheng * 2160da14cebeSEric Cheng * We set FLOW_PRIMARY_MAC for the primary MAC address, 2161da14cebeSEric Cheng * FLOW_VNIC for everything else. 2162da14cebeSEric Cheng */ 2163da14cebeSEric Cheng if (is_primary) 2164da14cebeSEric Cheng flent_flags = FLOW_PRIMARY_MAC; 2165da14cebeSEric Cheng else 2166da14cebeSEric Cheng flent_flags = FLOW_VNIC_MAC; 2167da14cebeSEric Cheng 2168da14cebeSEric Cheng /* 2169da14cebeSEric Cheng * For the first flow we use the mac client's name - mci_name, for 2170da14cebeSEric Cheng * subsequent ones we just create a name with the vid. This is 2171da14cebeSEric Cheng * so that we can add these flows to the same flow table. This is 2172da14cebeSEric Cheng * fine as the flow name (except for the one with the mac client's 2173da14cebeSEric Cheng * name) is not visible. When the first flow is removed, we just replace 2174da14cebeSEric Cheng * its fdesc with another from the list, so we will still retain the 2175da14cebeSEric Cheng * flent with the MAC client's flow name. 2176da14cebeSEric Cheng */ 2177da14cebeSEric Cheng if (first_flow) { 2178da000602SGirish Moodalbail bcopy(mcip->mci_name, flowname, MAXFLOWNAMELEN); 2179da14cebeSEric Cheng } else { 2180da14cebeSEric Cheng (void) sprintf(flowname, "%s%u", mcip->mci_name, vid); 2181da14cebeSEric Cheng flent_flags = FLOW_NO_STATS; 2182da14cebeSEric Cheng } 2183da14cebeSEric Cheng 2184da14cebeSEric Cheng if ((err = mac_flow_create(&flow_desc, mrp, flowname, NULL, 2185da14cebeSEric Cheng flent_flags, flent)) != 0) 2186da14cebeSEric Cheng return (err); 2187da14cebeSEric Cheng 21880dc2366fSVenugopal Iyer mac_misc_stat_create(*flent); 2189da14cebeSEric Cheng FLOW_MARK(*flent, FE_INCIPIENT); 2190da14cebeSEric Cheng (*flent)->fe_mcip = mcip; 2191da14cebeSEric Cheng 2192da14cebeSEric Cheng /* 2193da14cebeSEric Cheng * Place initial creation reference on the flow. This reference 2194da14cebeSEric Cheng * is released in the corresponding delete action viz. 2195da14cebeSEric Cheng * mac_unicast_remove after waiting for all transient refs to 2196da14cebeSEric Cheng * to go away. The wait happens in mac_flow_wait. 2197da14cebeSEric Cheng * We have already held the reference in mac_client_open(). 2198da14cebeSEric Cheng */ 2199da14cebeSEric Cheng if (!first_flow) 2200da14cebeSEric Cheng FLOW_REFHOLD(*flent); 2201da14cebeSEric Cheng return (0); 2202da14cebeSEric Cheng } 2203da14cebeSEric Cheng 2204da14cebeSEric Cheng /* Refresh the multicast grouping for this VID. */ 2205da14cebeSEric Cheng int 2206da14cebeSEric Cheng mac_client_update_mcast(void *arg, boolean_t add, const uint8_t *addrp) 2207da14cebeSEric Cheng { 2208da14cebeSEric Cheng flow_entry_t *flent = arg; 2209da14cebeSEric Cheng mac_client_impl_t *mcip = flent->fe_mcip; 2210da14cebeSEric Cheng uint16_t vid; 2211da14cebeSEric Cheng flow_desc_t flow_desc; 2212da14cebeSEric Cheng 2213da14cebeSEric Cheng mac_flow_get_desc(flent, &flow_desc); 2214da14cebeSEric Cheng vid = (flow_desc.fd_mask & FLOW_LINK_VID) != 0 ? 2215da14cebeSEric Cheng flow_desc.fd_vid : VLAN_ID_NONE; 2216da14cebeSEric Cheng 2217da14cebeSEric Cheng /* 2218da14cebeSEric Cheng * We don't call mac_multicast_add()/mac_multicast_remove() as 2219da14cebeSEric Cheng * we want to add/remove for this specific vid. 2220da14cebeSEric Cheng */ 2221da14cebeSEric Cheng if (add) { 2222da14cebeSEric Cheng return (mac_bcast_add(mcip, addrp, vid, 2223da14cebeSEric Cheng MAC_ADDRTYPE_MULTICAST)); 2224da14cebeSEric Cheng } else { 2225da14cebeSEric Cheng mac_bcast_delete(mcip, addrp, vid); 2226da14cebeSEric Cheng return (0); 2227da14cebeSEric Cheng } 2228da14cebeSEric Cheng } 2229da14cebeSEric Cheng 2230ae6aa22aSVenugopal Iyer static void 2231ae6aa22aSVenugopal Iyer mac_update_single_active_client(mac_impl_t *mip) 2232ae6aa22aSVenugopal Iyer { 2233ae6aa22aSVenugopal Iyer mac_client_impl_t *client = NULL; 2234ae6aa22aSVenugopal Iyer 2235ae6aa22aSVenugopal Iyer ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 2236ae6aa22aSVenugopal Iyer 2237ae6aa22aSVenugopal Iyer rw_enter(&mip->mi_rw_lock, RW_WRITER); 2238ae6aa22aSVenugopal Iyer if (mip->mi_nactiveclients == 1) { 2239ae6aa22aSVenugopal Iyer /* 2240ae6aa22aSVenugopal Iyer * Find the one active MAC client from the list of MAC 2241ae6aa22aSVenugopal Iyer * clients. The active MAC client has at least one 2242ae6aa22aSVenugopal Iyer * unicast address. 2243ae6aa22aSVenugopal Iyer */ 2244ae6aa22aSVenugopal Iyer for (client = mip->mi_clients_list; client != NULL; 2245ae6aa22aSVenugopal Iyer client = client->mci_client_next) { 2246ae6aa22aSVenugopal Iyer if (client->mci_unicast_list != NULL) 2247ae6aa22aSVenugopal Iyer break; 2248ae6aa22aSVenugopal Iyer } 2249ae6aa22aSVenugopal Iyer ASSERT(client != NULL); 2250ae6aa22aSVenugopal Iyer } 2251ae6aa22aSVenugopal Iyer 2252ae6aa22aSVenugopal Iyer /* 2253ae6aa22aSVenugopal Iyer * mi_single_active_client is protected by the MAC impl's read/writer 2254ae6aa22aSVenugopal Iyer * lock, which allows mac_rx() to check the value of that pointer 2255ae6aa22aSVenugopal Iyer * as a reader. 2256ae6aa22aSVenugopal Iyer */ 2257ae6aa22aSVenugopal Iyer mip->mi_single_active_client = client; 2258ae6aa22aSVenugopal Iyer rw_exit(&mip->mi_rw_lock); 2259ae6aa22aSVenugopal Iyer } 2260ae6aa22aSVenugopal Iyer 2261da14cebeSEric Cheng /* 2262fc4e975dSVenugopal Iyer * Set up the data path. Called from i_mac_unicast_add after having 2263fc4e975dSVenugopal Iyer * done all the validations including making sure this is an active 2264fc4e975dSVenugopal Iyer * client (i.e that is ready to process packets.) 2265fc4e975dSVenugopal Iyer */ 2266fc4e975dSVenugopal Iyer static int 2267fc4e975dSVenugopal Iyer mac_client_datapath_setup(mac_client_impl_t *mcip, uint16_t vid, 2268fc4e975dSVenugopal Iyer uint8_t *mac_addr, mac_resource_props_t *mrp, boolean_t isprimary, 2269fc4e975dSVenugopal Iyer mac_unicast_impl_t *muip) 2270fc4e975dSVenugopal Iyer { 2271fc4e975dSVenugopal Iyer mac_impl_t *mip = mcip->mci_mip; 2272fc4e975dSVenugopal Iyer boolean_t mac_started = B_FALSE; 2273fc4e975dSVenugopal Iyer boolean_t bcast_added = B_FALSE; 2274fc4e975dSVenugopal Iyer boolean_t nactiveclients_added = B_FALSE; 2275fc4e975dSVenugopal Iyer flow_entry_t *flent; 2276fc4e975dSVenugopal Iyer int err = 0; 22770dc2366fSVenugopal Iyer boolean_t no_unicast; 22780dc2366fSVenugopal Iyer 22790dc2366fSVenugopal Iyer no_unicast = mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR; 2280fc4e975dSVenugopal Iyer 2281fc4e975dSVenugopal Iyer if ((err = mac_start((mac_handle_t)mip)) != 0) 2282fc4e975dSVenugopal Iyer goto bail; 2283fc4e975dSVenugopal Iyer 2284fc4e975dSVenugopal Iyer mac_started = B_TRUE; 2285fc4e975dSVenugopal Iyer 2286fc4e975dSVenugopal Iyer /* add the MAC client to the broadcast address group by default */ 2287fc4e975dSVenugopal Iyer if (mip->mi_type->mt_brdcst_addr != NULL) { 2288fc4e975dSVenugopal Iyer err = mac_bcast_add(mcip, mip->mi_type->mt_brdcst_addr, vid, 2289fc4e975dSVenugopal Iyer MAC_ADDRTYPE_BROADCAST); 2290fc4e975dSVenugopal Iyer if (err != 0) 2291fc4e975dSVenugopal Iyer goto bail; 2292fc4e975dSVenugopal Iyer bcast_added = B_TRUE; 2293fc4e975dSVenugopal Iyer } 2294fc4e975dSVenugopal Iyer 2295fc4e975dSVenugopal Iyer /* 2296fc4e975dSVenugopal Iyer * If this is the first unicast address addition for this 2297fc4e975dSVenugopal Iyer * client, reuse the pre-allocated larval flow entry associated with 2298fc4e975dSVenugopal Iyer * the MAC client. 2299fc4e975dSVenugopal Iyer */ 2300fc4e975dSVenugopal Iyer flent = (mcip->mci_nflents == 0) ? mcip->mci_flent : NULL; 2301fc4e975dSVenugopal Iyer 2302fc4e975dSVenugopal Iyer /* We are configuring the unicast flow now */ 2303fc4e975dSVenugopal Iyer if (!MCIP_DATAPATH_SETUP(mcip)) { 2304fc4e975dSVenugopal Iyer 23050dc2366fSVenugopal Iyer if (mrp != NULL) { 2306fc4e975dSVenugopal Iyer MAC_CLIENT_SET_PRIORITY_RANGE(mcip, 2307fc4e975dSVenugopal Iyer (mrp->mrp_mask & MRP_PRIORITY) ? mrp->mrp_priority : 2308fc4e975dSVenugopal Iyer MPL_LINK_DEFAULT); 23090dc2366fSVenugopal Iyer } 2310fc4e975dSVenugopal Iyer if ((err = mac_unicast_flow_create(mcip, mac_addr, vid, 2311fc4e975dSVenugopal Iyer isprimary, B_TRUE, &flent, mrp)) != 0) 2312fc4e975dSVenugopal Iyer goto bail; 2313fc4e975dSVenugopal Iyer 2314fc4e975dSVenugopal Iyer mip->mi_nactiveclients++; 2315fc4e975dSVenugopal Iyer nactiveclients_added = B_TRUE; 2316fc4e975dSVenugopal Iyer 2317fc4e975dSVenugopal Iyer /* 2318fc4e975dSVenugopal Iyer * This will allocate the RX ring group if possible for the 2319fc4e975dSVenugopal Iyer * flow and program the software classifier as needed. 2320fc4e975dSVenugopal Iyer */ 2321fc4e975dSVenugopal Iyer if ((err = mac_datapath_setup(mcip, flent, SRST_LINK)) != 0) 2322fc4e975dSVenugopal Iyer goto bail; 2323fc4e975dSVenugopal Iyer 23240dc2366fSVenugopal Iyer if (no_unicast) 23250dc2366fSVenugopal Iyer goto done_setup; 2326fc4e975dSVenugopal Iyer /* 2327fc4e975dSVenugopal Iyer * The unicast MAC address must have been added successfully. 2328fc4e975dSVenugopal Iyer */ 2329fc4e975dSVenugopal Iyer ASSERT(mcip->mci_unicast != NULL); 2330fc4e975dSVenugopal Iyer /* 2331fc4e975dSVenugopal Iyer * Push down the sub-flows that were defined on this link 2332fc4e975dSVenugopal Iyer * hitherto. The flows are added to the active flow table 2333fc4e975dSVenugopal Iyer * and SRS, softrings etc. are created as needed. 2334fc4e975dSVenugopal Iyer */ 2335fc4e975dSVenugopal Iyer mac_link_init_flows((mac_client_handle_t)mcip); 2336fc4e975dSVenugopal Iyer } else { 2337fc4e975dSVenugopal Iyer mac_address_t *map = mcip->mci_unicast; 2338fc4e975dSVenugopal Iyer 23390dc2366fSVenugopal Iyer ASSERT(!no_unicast); 2340fc4e975dSVenugopal Iyer /* 2341fc4e975dSVenugopal Iyer * A unicast flow already exists for that MAC client, 2342fc4e975dSVenugopal Iyer * this flow must be the same mac address but with 2343fc4e975dSVenugopal Iyer * different VID. It has been checked by mac_addr_in_use(). 2344fc4e975dSVenugopal Iyer * 2345fc4e975dSVenugopal Iyer * We will use the SRS etc. from the mci_flent. Note that 2346fc4e975dSVenugopal Iyer * We don't need to create kstat for this as except for 2347fc4e975dSVenugopal Iyer * the fdesc, everything will be used from in the 1st flent. 2348fc4e975dSVenugopal Iyer */ 2349fc4e975dSVenugopal Iyer 2350fc4e975dSVenugopal Iyer if (bcmp(mac_addr, map->ma_addr, map->ma_len) != 0) { 2351fc4e975dSVenugopal Iyer err = EINVAL; 2352fc4e975dSVenugopal Iyer goto bail; 2353fc4e975dSVenugopal Iyer } 2354fc4e975dSVenugopal Iyer 2355fc4e975dSVenugopal Iyer if ((err = mac_unicast_flow_create(mcip, mac_addr, vid, 2356fc4e975dSVenugopal Iyer isprimary, B_FALSE, &flent, NULL)) != 0) { 2357fc4e975dSVenugopal Iyer goto bail; 2358fc4e975dSVenugopal Iyer } 2359fc4e975dSVenugopal Iyer if ((err = mac_flow_add(mip->mi_flow_tab, flent)) != 0) { 2360fc4e975dSVenugopal Iyer FLOW_FINAL_REFRELE(flent); 2361fc4e975dSVenugopal Iyer goto bail; 2362fc4e975dSVenugopal Iyer } 2363fc4e975dSVenugopal Iyer 2364fc4e975dSVenugopal Iyer /* update the multicast group for this vid */ 2365fc4e975dSVenugopal Iyer mac_client_bcast_refresh(mcip, mac_client_update_mcast, 2366fc4e975dSVenugopal Iyer (void *)flent, B_TRUE); 2367fc4e975dSVenugopal Iyer 2368fc4e975dSVenugopal Iyer } 2369fc4e975dSVenugopal Iyer 2370fc4e975dSVenugopal Iyer /* populate the shared MAC address */ 2371fc4e975dSVenugopal Iyer muip->mui_map = mcip->mci_unicast; 2372fc4e975dSVenugopal Iyer 2373fc4e975dSVenugopal Iyer rw_enter(&mcip->mci_rw_lock, RW_WRITER); 2374fc4e975dSVenugopal Iyer muip->mui_next = mcip->mci_unicast_list; 2375fc4e975dSVenugopal Iyer mcip->mci_unicast_list = muip; 2376fc4e975dSVenugopal Iyer rw_exit(&mcip->mci_rw_lock); 2377fc4e975dSVenugopal Iyer 23780dc2366fSVenugopal Iyer done_setup: 2379fc4e975dSVenugopal Iyer /* 2380fc4e975dSVenugopal Iyer * First add the flent to the flow list of this mcip. Then set 2381fc4e975dSVenugopal Iyer * the mip's mi_single_active_client if needed. The Rx path assumes 2382fc4e975dSVenugopal Iyer * that mip->mi_single_active_client will always have an associated 2383fc4e975dSVenugopal Iyer * flent. 2384fc4e975dSVenugopal Iyer */ 2385fc4e975dSVenugopal Iyer mac_client_add_to_flow_list(mcip, flent); 2386fc4e975dSVenugopal Iyer if (nactiveclients_added) 2387fc4e975dSVenugopal Iyer mac_update_single_active_client(mip); 2388fc4e975dSVenugopal Iyer /* 2389fc4e975dSVenugopal Iyer * Trigger a renegotiation of the capabilities when the number of 2390fc4e975dSVenugopal Iyer * active clients changes from 1 to 2, since some of the capabilities 2391fc4e975dSVenugopal Iyer * might have to be disabled. Also send a MAC_NOTE_LINK notification 2392fc4e975dSVenugopal Iyer * to all the MAC clients whenever physical link is DOWN. 2393fc4e975dSVenugopal Iyer */ 2394fc4e975dSVenugopal Iyer if (mip->mi_nactiveclients == 2) { 2395fc4e975dSVenugopal Iyer mac_capab_update((mac_handle_t)mip); 2396fc4e975dSVenugopal Iyer mac_virtual_link_update(mip); 2397fc4e975dSVenugopal Iyer } 2398fc4e975dSVenugopal Iyer /* 2399fc4e975dSVenugopal Iyer * Now that the setup is complete, clear the INCIPIENT flag. 2400fc4e975dSVenugopal Iyer * The flag was set to avoid incoming packets seeing inconsistent 2401fc4e975dSVenugopal Iyer * structures while the setup was in progress. Clear the mci_tx_flag 2402fc4e975dSVenugopal Iyer * by calling mac_tx_client_block. It is possible that 2403fc4e975dSVenugopal Iyer * mac_unicast_remove was called prior to this mac_unicast_add which 2404fc4e975dSVenugopal Iyer * could have set the MCI_TX_QUIESCE flag. 2405fc4e975dSVenugopal Iyer */ 2406fc4e975dSVenugopal Iyer if (flent->fe_rx_ring_group != NULL) 2407fc4e975dSVenugopal Iyer mac_rx_group_unmark(flent->fe_rx_ring_group, MR_INCIPIENT); 2408fc4e975dSVenugopal Iyer FLOW_UNMARK(flent, FE_INCIPIENT); 2409fc4e975dSVenugopal Iyer FLOW_UNMARK(flent, FE_MC_NO_DATAPATH); 2410fc4e975dSVenugopal Iyer mac_tx_client_unblock(mcip); 2411fc4e975dSVenugopal Iyer return (0); 2412fc4e975dSVenugopal Iyer bail: 2413fc4e975dSVenugopal Iyer if (bcast_added) 2414fc4e975dSVenugopal Iyer mac_bcast_delete(mcip, mip->mi_type->mt_brdcst_addr, vid); 2415fc4e975dSVenugopal Iyer 2416fc4e975dSVenugopal Iyer if (nactiveclients_added) 2417fc4e975dSVenugopal Iyer mip->mi_nactiveclients--; 2418fc4e975dSVenugopal Iyer 24194559da71SNitin Hande if (mac_started) 24204559da71SNitin Hande mac_stop((mac_handle_t)mip); 24214559da71SNitin Hande 2422fc4e975dSVenugopal Iyer return (err); 2423fc4e975dSVenugopal Iyer } 2424fc4e975dSVenugopal Iyer 2425fc4e975dSVenugopal Iyer /* 2426fc4e975dSVenugopal Iyer * Return the passive primary MAC client, if present. The passive client is 2427fc4e975dSVenugopal Iyer * a stand-by client that has the same unicast address as another that is 2428fc4e975dSVenugopal Iyer * currenly active. Once the active client goes away, the passive client 2429fc4e975dSVenugopal Iyer * becomes active. 2430fc4e975dSVenugopal Iyer */ 2431fc4e975dSVenugopal Iyer static mac_client_impl_t * 2432fc4e975dSVenugopal Iyer mac_get_passive_primary_client(mac_impl_t *mip) 2433fc4e975dSVenugopal Iyer { 2434fc4e975dSVenugopal Iyer mac_client_impl_t *mcip; 2435fc4e975dSVenugopal Iyer 2436fc4e975dSVenugopal Iyer for (mcip = mip->mi_clients_list; mcip != NULL; 2437fc4e975dSVenugopal Iyer mcip = mcip->mci_client_next) { 2438fc4e975dSVenugopal Iyer if (mac_is_primary_client(mcip) && 2439fc4e975dSVenugopal Iyer (mcip->mci_flags & MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) { 2440fc4e975dSVenugopal Iyer return (mcip); 2441fc4e975dSVenugopal Iyer } 2442fc4e975dSVenugopal Iyer } 2443fc4e975dSVenugopal Iyer return (NULL); 2444fc4e975dSVenugopal Iyer } 2445fc4e975dSVenugopal Iyer 2446fc4e975dSVenugopal Iyer /* 2447da14cebeSEric Cheng * Add a new unicast address to the MAC client. 2448da14cebeSEric Cheng * 2449da14cebeSEric Cheng * The MAC address can be specified either by value, or the MAC client 2450da14cebeSEric Cheng * can specify that it wants to use the primary MAC address of the 2451da14cebeSEric Cheng * underlying MAC. See the introductory comments at the beginning 2452da14cebeSEric Cheng * of this file for more more information on primary MAC addresses. 2453da14cebeSEric Cheng * 2454da14cebeSEric Cheng * Note also the tuple (MAC address, VID) must be unique 2455da14cebeSEric Cheng * for the MAC clients defined on top of the same underlying MAC 2456da14cebeSEric Cheng * instance, unless the MAC_UNICAST_NODUPCHECK is specified. 24574eaa4710SRishi Srivatsavai * 24584eaa4710SRishi Srivatsavai * In no case can a client use the PVID for the MAC, if the MAC has one set. 2459da14cebeSEric Cheng */ 2460da14cebeSEric Cheng int 2461da14cebeSEric Cheng i_mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags, 2462da14cebeSEric Cheng mac_unicast_handle_t *mah, uint16_t vid, mac_diag_t *diag) 2463da14cebeSEric Cheng { 2464da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2465da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip; 2466da14cebeSEric Cheng int err; 2467da14cebeSEric Cheng uint_t mac_len = mip->mi_type->mt_addr_length; 2468da14cebeSEric Cheng boolean_t check_dups = !(flags & MAC_UNICAST_NODUPCHECK); 24695d460eafSCathy Zhou boolean_t fastpath_disabled = B_FALSE; 2470fc4e975dSVenugopal Iyer boolean_t is_primary = (flags & MAC_UNICAST_PRIMARY); 2471fc4e975dSVenugopal Iyer boolean_t is_unicast_hw = (flags & MAC_UNICAST_HW); 24720dc2366fSVenugopal Iyer mac_resource_props_t *mrp; 2473fc4e975dSVenugopal Iyer boolean_t passive_client = B_FALSE; 2474fc4e975dSVenugopal Iyer mac_unicast_impl_t *muip; 2475fc4e975dSVenugopal Iyer boolean_t is_vnic_primary = 2476fc4e975dSVenugopal Iyer (flags & MAC_UNICAST_VNIC_PRIMARY); 2477da14cebeSEric Cheng 2478da14cebeSEric Cheng /* when VID is non-zero, the underlying MAC can not be VNIC */ 2479da14cebeSEric Cheng ASSERT(!((mip->mi_state_flags & MIS_IS_VNIC) && (vid != 0))); 2480da14cebeSEric Cheng 2481da14cebeSEric Cheng /* 24820dc2366fSVenugopal Iyer * Can't unicast add if the client asked only for minimal datapath 24830dc2366fSVenugopal Iyer * setup. 24840dc2366fSVenugopal Iyer */ 24850dc2366fSVenugopal Iyer if (mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR) 24860dc2366fSVenugopal Iyer return (ENOTSUP); 24870dc2366fSVenugopal Iyer 24880dc2366fSVenugopal Iyer /* 24894eaa4710SRishi Srivatsavai * Check for an attempted use of the current Port VLAN ID, if enabled. 24904eaa4710SRishi Srivatsavai * No client may use it. 24914eaa4710SRishi Srivatsavai */ 24924eaa4710SRishi Srivatsavai if (mip->mi_pvid != 0 && vid == mip->mi_pvid) 24934eaa4710SRishi Srivatsavai return (EBUSY); 24944eaa4710SRishi Srivatsavai 24954eaa4710SRishi Srivatsavai /* 2496da14cebeSEric Cheng * Check whether it's the primary client and flag it. 2497da14cebeSEric Cheng */ 2498da14cebeSEric Cheng if (!(mcip->mci_state_flags & MCIS_IS_VNIC) && is_primary && vid == 0) 2499da14cebeSEric Cheng mcip->mci_flags |= MAC_CLIENT_FLAGS_PRIMARY; 2500da14cebeSEric Cheng 2501da14cebeSEric Cheng /* 2502da14cebeSEric Cheng * is_vnic_primary is true when we come here as a VLAN VNIC 2503da14cebeSEric Cheng * which uses the primary mac client's address but with a non-zero 2504da14cebeSEric Cheng * VID. In this case the MAC address is not specified by an upper 2505da14cebeSEric Cheng * MAC client. 2506da14cebeSEric Cheng */ 2507da14cebeSEric Cheng if ((mcip->mci_state_flags & MCIS_IS_VNIC) && is_primary && 2508da14cebeSEric Cheng !is_vnic_primary) { 2509da14cebeSEric Cheng /* 2510da14cebeSEric Cheng * The address is being set by the upper MAC client 2511da14cebeSEric Cheng * of a VNIC. The MAC address was already set by the 2512da14cebeSEric Cheng * VNIC driver during VNIC creation. 2513da14cebeSEric Cheng * 2514da14cebeSEric Cheng * Note: a VNIC has only one MAC address. We return 2515da14cebeSEric Cheng * the MAC unicast address handle of the lower MAC client 2516da14cebeSEric Cheng * corresponding to the VNIC. We allocate a new entry 2517da14cebeSEric Cheng * which is flagged appropriately, so that mac_unicast_remove() 2518da14cebeSEric Cheng * doesn't attempt to free the original entry that 2519da14cebeSEric Cheng * was allocated by the VNIC driver. 2520da14cebeSEric Cheng */ 2521da14cebeSEric Cheng ASSERT(mcip->mci_unicast != NULL); 2522da14cebeSEric Cheng 25234c91d6c6SVenugopal Iyer /* Check for VLAN flags, if present */ 25244c91d6c6SVenugopal Iyer if ((flags & MAC_UNICAST_TAG_DISABLE) != 0) 25254c91d6c6SVenugopal Iyer mcip->mci_state_flags |= MCIS_TAG_DISABLE; 25264c91d6c6SVenugopal Iyer 25274c91d6c6SVenugopal Iyer if ((flags & MAC_UNICAST_STRIP_DISABLE) != 0) 25284c91d6c6SVenugopal Iyer mcip->mci_state_flags |= MCIS_STRIP_DISABLE; 25294c91d6c6SVenugopal Iyer 25304c91d6c6SVenugopal Iyer if ((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) != 0) 25314c91d6c6SVenugopal Iyer mcip->mci_state_flags |= MCIS_DISABLE_TX_VID_CHECK; 25324c91d6c6SVenugopal Iyer 2533da14cebeSEric Cheng /* 2534da14cebeSEric Cheng * Ensure that the primary unicast address of the VNIC 2535fc4e975dSVenugopal Iyer * is added only once unless we have the 2536fc4e975dSVenugopal Iyer * MAC_CLIENT_FLAGS_MULTI_PRIMARY set (and this is not 2537fc4e975dSVenugopal Iyer * a passive MAC client). 2538da14cebeSEric Cheng */ 2539fc4e975dSVenugopal Iyer if ((mcip->mci_flags & MAC_CLIENT_FLAGS_VNIC_PRIMARY) != 0) { 2540fc4e975dSVenugopal Iyer if ((mcip->mci_flags & 2541fc4e975dSVenugopal Iyer MAC_CLIENT_FLAGS_MULTI_PRIMARY) == 0 || 2542fc4e975dSVenugopal Iyer (mcip->mci_flags & 2543fc4e975dSVenugopal Iyer MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) { 2544da14cebeSEric Cheng return (EBUSY); 2545fc4e975dSVenugopal Iyer } 2546fc4e975dSVenugopal Iyer mcip->mci_flags |= MAC_CLIENT_FLAGS_PASSIVE_PRIMARY; 2547fc4e975dSVenugopal Iyer passive_client = B_TRUE; 2548fc4e975dSVenugopal Iyer } 2549da14cebeSEric Cheng 2550da14cebeSEric Cheng mcip->mci_flags |= MAC_CLIENT_FLAGS_VNIC_PRIMARY; 2551da14cebeSEric Cheng 2552da14cebeSEric Cheng /* 2553da14cebeSEric Cheng * Create a handle for vid 0. 2554da14cebeSEric Cheng */ 2555da14cebeSEric Cheng ASSERT(vid == 0); 2556da14cebeSEric Cheng muip = kmem_zalloc(sizeof (mac_unicast_impl_t), KM_SLEEP); 2557da14cebeSEric Cheng muip->mui_vid = vid; 2558da14cebeSEric Cheng *mah = (mac_unicast_handle_t)muip; 2559fc4e975dSVenugopal Iyer /* 2560fc4e975dSVenugopal Iyer * This will be used by the caller to defer setting the 2561fc4e975dSVenugopal Iyer * rx functions. 2562fc4e975dSVenugopal Iyer */ 2563fc4e975dSVenugopal Iyer if (passive_client) 2564fc4e975dSVenugopal Iyer return (EAGAIN); 2565da14cebeSEric Cheng return (0); 2566da14cebeSEric Cheng } 2567da14cebeSEric Cheng 2568da14cebeSEric Cheng /* primary MAC clients cannot be opened on top of anchor VNICs */ 2569da14cebeSEric Cheng if ((is_vnic_primary || is_primary) && 2570da14cebeSEric Cheng i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_ANCHOR_VNIC, NULL)) { 2571da14cebeSEric Cheng return (ENXIO); 2572da14cebeSEric Cheng } 2573da14cebeSEric Cheng 2574da14cebeSEric Cheng /* 25755d460eafSCathy Zhou * If this is a VNIC/VLAN, disable softmac fast-path. 2576da14cebeSEric Cheng */ 25775d460eafSCathy Zhou if (mcip->mci_state_flags & MCIS_IS_VNIC) { 25785d460eafSCathy Zhou err = mac_fastpath_disable((mac_handle_t)mip); 25795d460eafSCathy Zhou if (err != 0) 25805d460eafSCathy Zhou return (err); 25815d460eafSCathy Zhou fastpath_disabled = B_TRUE; 25825d460eafSCathy Zhou } 25835d460eafSCathy Zhou 25845d460eafSCathy Zhou /* 25855d460eafSCathy Zhou * Return EBUSY if: 25865d460eafSCathy Zhou * - there is an exclusively active mac client exists. 25875d460eafSCathy Zhou * - this is an exclusive active mac client but 25885d460eafSCathy Zhou * a. there is already active mac clients exist, or 25895d460eafSCathy Zhou * b. fastpath streams are already plumbed on this legacy device 25904eaa4710SRishi Srivatsavai * - the mac creator has disallowed active mac clients. 25915d460eafSCathy Zhou */ 25924eaa4710SRishi Srivatsavai if (mip->mi_state_flags & (MIS_EXCLUSIVE|MIS_NO_ACTIVE)) { 25935d460eafSCathy Zhou if (fastpath_disabled) 25945d460eafSCathy Zhou mac_fastpath_enable((mac_handle_t)mip); 2595da14cebeSEric Cheng return (EBUSY); 2596da14cebeSEric Cheng } 2597da14cebeSEric Cheng 25985d460eafSCathy Zhou if (mcip->mci_state_flags & MCIS_EXCLUSIVE) { 25995d460eafSCathy Zhou ASSERT(!fastpath_disabled); 26005d460eafSCathy Zhou if (mip->mi_nactiveclients != 0) 26015d460eafSCathy Zhou return (EBUSY); 26025d460eafSCathy Zhou 26035d460eafSCathy Zhou if ((mip->mi_state_flags & MIS_LEGACY) && 26045d460eafSCathy Zhou !(mip->mi_capab_legacy.ml_active_set(mip->mi_driver))) { 26055d460eafSCathy Zhou return (EBUSY); 26065d460eafSCathy Zhou } 2607da14cebeSEric Cheng mip->mi_state_flags |= MIS_EXCLUSIVE; 26085d460eafSCathy Zhou } 2609da14cebeSEric Cheng 26100dc2366fSVenugopal Iyer mrp = kmem_zalloc(sizeof (*mrp), KM_SLEEP); 2611ae6aa22aSVenugopal Iyer if (is_primary && !(mcip->mci_state_flags & (MCIS_IS_VNIC | 2612ae6aa22aSVenugopal Iyer MCIS_IS_AGGR_PORT))) { 2613da14cebeSEric Cheng /* 2614da14cebeSEric Cheng * Apply the property cached in the mac_impl_t to the primary 2615ae6aa22aSVenugopal Iyer * mac client. If the mac client is a VNIC or an aggregation 2616ae6aa22aSVenugopal Iyer * port, its property should be set in the mcip when the 2617ae6aa22aSVenugopal Iyer * VNIC/aggr was created. 2618da14cebeSEric Cheng */ 26190dc2366fSVenugopal Iyer mac_get_resources((mac_handle_t)mip, mrp); 26200dc2366fSVenugopal Iyer (void) mac_client_set_resources(mch, mrp); 2621da14cebeSEric Cheng } else if (mcip->mci_state_flags & MCIS_IS_VNIC) { 26220dc2366fSVenugopal Iyer /* 26230dc2366fSVenugopal Iyer * This is a primary VLAN client, we don't support 26240dc2366fSVenugopal Iyer * specifying rings property for this as it inherits the 26250dc2366fSVenugopal Iyer * rings property from its MAC. 26260dc2366fSVenugopal Iyer */ 26270dc2366fSVenugopal Iyer if (is_vnic_primary) { 26280dc2366fSVenugopal Iyer mac_resource_props_t *vmrp; 26290dc2366fSVenugopal Iyer 26300dc2366fSVenugopal Iyer vmrp = MCIP_RESOURCE_PROPS(mcip); 26310dc2366fSVenugopal Iyer if (vmrp->mrp_mask & MRP_RX_RINGS || 26320dc2366fSVenugopal Iyer vmrp->mrp_mask & MRP_TX_RINGS) { 26330dc2366fSVenugopal Iyer if (fastpath_disabled) 26340dc2366fSVenugopal Iyer mac_fastpath_enable((mac_handle_t)mip); 26350dc2366fSVenugopal Iyer kmem_free(mrp, sizeof (*mrp)); 26360dc2366fSVenugopal Iyer return (ENOTSUP); 26370dc2366fSVenugopal Iyer } 26380dc2366fSVenugopal Iyer /* 26390dc2366fSVenugopal Iyer * Additionally we also need to inherit any 26400dc2366fSVenugopal Iyer * rings property from the MAC. 26410dc2366fSVenugopal Iyer */ 26420dc2366fSVenugopal Iyer mac_get_resources((mac_handle_t)mip, mrp); 26430dc2366fSVenugopal Iyer if (mrp->mrp_mask & MRP_RX_RINGS) { 26440dc2366fSVenugopal Iyer vmrp->mrp_mask |= MRP_RX_RINGS; 26450dc2366fSVenugopal Iyer vmrp->mrp_nrxrings = mrp->mrp_nrxrings; 26460dc2366fSVenugopal Iyer } 26470dc2366fSVenugopal Iyer if (mrp->mrp_mask & MRP_TX_RINGS) { 26480dc2366fSVenugopal Iyer vmrp->mrp_mask |= MRP_TX_RINGS; 26490dc2366fSVenugopal Iyer vmrp->mrp_ntxrings = mrp->mrp_ntxrings; 26500dc2366fSVenugopal Iyer } 26510dc2366fSVenugopal Iyer } 26520dc2366fSVenugopal Iyer bcopy(MCIP_RESOURCE_PROPS(mcip), mrp, sizeof (*mrp)); 2653da14cebeSEric Cheng } 2654da14cebeSEric Cheng 2655da14cebeSEric Cheng muip = kmem_zalloc(sizeof (mac_unicast_impl_t), KM_SLEEP); 2656da14cebeSEric Cheng muip->mui_vid = vid; 2657da14cebeSEric Cheng 2658da14cebeSEric Cheng if (is_primary || is_vnic_primary) { 2659da14cebeSEric Cheng mac_addr = mip->mi_addr; 2660da14cebeSEric Cheng } else { 2661da14cebeSEric Cheng 2662da14cebeSEric Cheng /* 2663da14cebeSEric Cheng * Verify the validity of the specified MAC addresses value. 2664da14cebeSEric Cheng */ 2665da14cebeSEric Cheng if (!mac_unicst_verify((mac_handle_t)mip, mac_addr, mac_len)) { 2666da14cebeSEric Cheng *diag = MAC_DIAG_MACADDR_INVALID; 2667da14cebeSEric Cheng err = EINVAL; 2668fc4e975dSVenugopal Iyer goto bail_out; 2669da14cebeSEric Cheng } 2670da14cebeSEric Cheng 2671da14cebeSEric Cheng /* 2672da14cebeSEric Cheng * Make sure that the specified MAC address is different 2673da14cebeSEric Cheng * than the unicast MAC address of the underlying NIC. 2674da14cebeSEric Cheng */ 2675da14cebeSEric Cheng if (check_dups && bcmp(mip->mi_addr, mac_addr, mac_len) == 0) { 2676da14cebeSEric Cheng *diag = MAC_DIAG_MACADDR_NIC; 2677da14cebeSEric Cheng err = EINVAL; 2678fc4e975dSVenugopal Iyer goto bail_out; 2679da14cebeSEric Cheng } 2680da14cebeSEric Cheng } 2681da14cebeSEric Cheng 2682da14cebeSEric Cheng /* 2683fc4e975dSVenugopal Iyer * Set the flags here so that if this is a passive client, we 2684fc4e975dSVenugopal Iyer * can return and set it when we call mac_client_datapath_setup 2685fc4e975dSVenugopal Iyer * when this becomes the active client. If we defer to using these 2686fc4e975dSVenugopal Iyer * flags to mac_client_datapath_setup, then for a passive client, 2687fc4e975dSVenugopal Iyer * we'd have to store the flags somewhere (probably fe_flags) 2688fc4e975dSVenugopal Iyer * and then use it. 2689da14cebeSEric Cheng */ 2690da14cebeSEric Cheng if (!MCIP_DATAPATH_SETUP(mcip)) { 269108ac1c49SNicolas Droux if (is_unicast_hw) { 269208ac1c49SNicolas Droux /* 269308ac1c49SNicolas Droux * The client requires a hardware MAC address slot 269408ac1c49SNicolas Droux * for that unicast address. Since we support only 269508ac1c49SNicolas Droux * one unicast MAC address per client, flag the 269608ac1c49SNicolas Droux * MAC client itself. 269708ac1c49SNicolas Droux */ 269808ac1c49SNicolas Droux mcip->mci_state_flags |= MCIS_UNICAST_HW; 269908ac1c49SNicolas Droux } 2700da14cebeSEric Cheng 27014c91d6c6SVenugopal Iyer /* Check for VLAN flags, if present */ 27024c91d6c6SVenugopal Iyer if ((flags & MAC_UNICAST_TAG_DISABLE) != 0) 27034c91d6c6SVenugopal Iyer mcip->mci_state_flags |= MCIS_TAG_DISABLE; 27044c91d6c6SVenugopal Iyer 27054c91d6c6SVenugopal Iyer if ((flags & MAC_UNICAST_STRIP_DISABLE) != 0) 27064c91d6c6SVenugopal Iyer mcip->mci_state_flags |= MCIS_STRIP_DISABLE; 27074c91d6c6SVenugopal Iyer 27084c91d6c6SVenugopal Iyer if ((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) != 0) 27094c91d6c6SVenugopal Iyer mcip->mci_state_flags |= MCIS_DISABLE_TX_VID_CHECK; 2710da14cebeSEric Cheng } else { 27114c91d6c6SVenugopal Iyer /* 27124c91d6c6SVenugopal Iyer * Assert that the specified flags are consistent with the 27134c91d6c6SVenugopal Iyer * flags specified by previous calls to mac_unicast_add(). 27144c91d6c6SVenugopal Iyer */ 27154c91d6c6SVenugopal Iyer ASSERT(((flags & MAC_UNICAST_TAG_DISABLE) != 0 && 27164c91d6c6SVenugopal Iyer (mcip->mci_state_flags & MCIS_TAG_DISABLE) != 0) || 27174c91d6c6SVenugopal Iyer ((flags & MAC_UNICAST_TAG_DISABLE) == 0 && 27184c91d6c6SVenugopal Iyer (mcip->mci_state_flags & MCIS_TAG_DISABLE) == 0)); 27194c91d6c6SVenugopal Iyer 27204c91d6c6SVenugopal Iyer ASSERT(((flags & MAC_UNICAST_STRIP_DISABLE) != 0 && 27214c91d6c6SVenugopal Iyer (mcip->mci_state_flags & MCIS_STRIP_DISABLE) != 0) || 27224c91d6c6SVenugopal Iyer ((flags & MAC_UNICAST_STRIP_DISABLE) == 0 && 27234c91d6c6SVenugopal Iyer (mcip->mci_state_flags & MCIS_STRIP_DISABLE) == 0)); 27244c91d6c6SVenugopal Iyer 27254c91d6c6SVenugopal Iyer ASSERT(((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) != 0 && 27264c91d6c6SVenugopal Iyer (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) != 0) || 27274c91d6c6SVenugopal Iyer ((flags & MAC_UNICAST_DISABLE_TX_VID_CHECK) == 0 && 27284c91d6c6SVenugopal Iyer (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) == 0)); 27294c91d6c6SVenugopal Iyer 273008ac1c49SNicolas Droux /* 273108ac1c49SNicolas Droux * Make sure the client is consistent about its requests 273208ac1c49SNicolas Droux * for MAC addresses. I.e. all requests from the clients 273308ac1c49SNicolas Droux * must have the MAC_UNICAST_HW flag set or clear. 273408ac1c49SNicolas Droux */ 2735*74d6c910SAndrew Stormont if (((mcip->mci_state_flags & MCIS_UNICAST_HW) != 0 && 2736*74d6c910SAndrew Stormont !is_unicast_hw) || 2737*74d6c910SAndrew Stormont ((mcip->mci_state_flags & MCIS_UNICAST_HW) == 0 && 2738*74d6c910SAndrew Stormont is_unicast_hw)) { 273908ac1c49SNicolas Droux err = EINVAL; 2740fc4e975dSVenugopal Iyer goto bail_out; 274108ac1c49SNicolas Droux } 2742da14cebeSEric Cheng } 2743fc4e975dSVenugopal Iyer /* 2744fc4e975dSVenugopal Iyer * Make sure the MAC address is not already used by 2745fc4e975dSVenugopal Iyer * another MAC client defined on top of the same 2746fc4e975dSVenugopal Iyer * underlying NIC. Unless we have MAC_CLIENT_FLAGS_MULTI_PRIMARY 2747fc4e975dSVenugopal Iyer * set when we allow a passive client to be present which will 2748fc4e975dSVenugopal Iyer * be activated when the currently active client goes away - this 2749fc4e975dSVenugopal Iyer * works only with primary addresses. 2750fc4e975dSVenugopal Iyer */ 2751fc4e975dSVenugopal Iyer if ((check_dups || is_primary || is_vnic_primary) && 2752fc4e975dSVenugopal Iyer mac_addr_in_use(mip, mac_addr, vid)) { 2753fc4e975dSVenugopal Iyer /* 2754fc4e975dSVenugopal Iyer * Must have set the multiple primary address flag when 2755fc4e975dSVenugopal Iyer * we did a mac_client_open AND this should be a primary 2756fc4e975dSVenugopal Iyer * MAC client AND there should not already be a passive 2757fc4e975dSVenugopal Iyer * primary. If all is true then we let this succeed 2758fc4e975dSVenugopal Iyer * even if the address is a dup. 2759fc4e975dSVenugopal Iyer */ 2760fc4e975dSVenugopal Iyer if ((mcip->mci_flags & MAC_CLIENT_FLAGS_MULTI_PRIMARY) == 0 || 2761fc4e975dSVenugopal Iyer (mcip->mci_flags & MAC_CLIENT_FLAGS_PRIMARY) == 0 || 2762fc4e975dSVenugopal Iyer mac_get_passive_primary_client(mip) != NULL) { 2763fc4e975dSVenugopal Iyer *diag = MAC_DIAG_MACADDR_INUSE; 2764fc4e975dSVenugopal Iyer err = EEXIST; 2765fc4e975dSVenugopal Iyer goto bail_out; 2766da14cebeSEric Cheng } 2767fc4e975dSVenugopal Iyer ASSERT((mcip->mci_flags & 2768fc4e975dSVenugopal Iyer MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) == 0); 2769fc4e975dSVenugopal Iyer mcip->mci_flags |= MAC_CLIENT_FLAGS_PASSIVE_PRIMARY; 27700dc2366fSVenugopal Iyer kmem_free(mrp, sizeof (*mrp)); 2771da14cebeSEric Cheng 2772fc4e975dSVenugopal Iyer /* 2773fc4e975dSVenugopal Iyer * Stash the unicast address handle, we will use it when 2774fc4e975dSVenugopal Iyer * we set up the passive client. 2775fc4e975dSVenugopal Iyer */ 2776fc4e975dSVenugopal Iyer mcip->mci_p_unicast_list = muip; 2777da14cebeSEric Cheng *mah = (mac_unicast_handle_t)muip; 2778da14cebeSEric Cheng return (0); 27795d460eafSCathy Zhou } 27805d460eafSCathy Zhou 27810dc2366fSVenugopal Iyer err = mac_client_datapath_setup(mcip, vid, mac_addr, mrp, 2782fc4e975dSVenugopal Iyer is_primary || is_vnic_primary, muip); 2783fc4e975dSVenugopal Iyer if (err != 0) 2784fc4e975dSVenugopal Iyer goto bail_out; 27850dc2366fSVenugopal Iyer 27860dc2366fSVenugopal Iyer kmem_free(mrp, sizeof (*mrp)); 2787fc4e975dSVenugopal Iyer *mah = (mac_unicast_handle_t)muip; 2788fc4e975dSVenugopal Iyer return (0); 2789fc4e975dSVenugopal Iyer 2790fc4e975dSVenugopal Iyer bail_out: 27915d460eafSCathy Zhou if (fastpath_disabled) 27925d460eafSCathy Zhou mac_fastpath_enable((mac_handle_t)mip); 2793fc4e975dSVenugopal Iyer if (mcip->mci_state_flags & MCIS_EXCLUSIVE) { 2794fc4e975dSVenugopal Iyer mip->mi_state_flags &= ~MIS_EXCLUSIVE; 2795fc4e975dSVenugopal Iyer if (mip->mi_state_flags & MIS_LEGACY) { 2796fc4e975dSVenugopal Iyer mip->mi_capab_legacy.ml_active_clear( 2797fc4e975dSVenugopal Iyer mip->mi_driver); 2798fc4e975dSVenugopal Iyer } 2799fc4e975dSVenugopal Iyer } 28000dc2366fSVenugopal Iyer kmem_free(mrp, sizeof (*mrp)); 2801da14cebeSEric Cheng kmem_free(muip, sizeof (mac_unicast_impl_t)); 2802da14cebeSEric Cheng return (err); 2803da14cebeSEric Cheng } 2804da14cebeSEric Cheng 2805fc4e975dSVenugopal Iyer /* 2806fc4e975dSVenugopal Iyer * Wrapper function to mac_unicast_add when we want to have the same mac 2807fc4e975dSVenugopal Iyer * client open for two instances, one that is currently active and another 2808fc4e975dSVenugopal Iyer * that will become active when the current one is removed. In this case 2809fc4e975dSVenugopal Iyer * mac_unicast_add will return EGAIN and we will save the rx function and 2810fc4e975dSVenugopal Iyer * arg which will be used when we activate the passive client in 2811fc4e975dSVenugopal Iyer * mac_unicast_remove. 2812fc4e975dSVenugopal Iyer */ 2813fc4e975dSVenugopal Iyer int 2814fc4e975dSVenugopal Iyer mac_unicast_add_set_rx(mac_client_handle_t mch, uint8_t *mac_addr, 2815fc4e975dSVenugopal Iyer uint16_t flags, mac_unicast_handle_t *mah, uint16_t vid, mac_diag_t *diag, 2816fc4e975dSVenugopal Iyer mac_rx_t rx_fn, void *arg) 2817fc4e975dSVenugopal Iyer { 2818fc4e975dSVenugopal Iyer mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2819fc4e975dSVenugopal Iyer uint_t err; 2820fc4e975dSVenugopal Iyer 2821fc4e975dSVenugopal Iyer err = mac_unicast_add(mch, mac_addr, flags, mah, vid, diag); 2822fc4e975dSVenugopal Iyer if (err != 0 && err != EAGAIN) 2823fc4e975dSVenugopal Iyer return (err); 2824fc4e975dSVenugopal Iyer if (err == EAGAIN) { 2825fc4e975dSVenugopal Iyer if (rx_fn != NULL) { 2826fc4e975dSVenugopal Iyer mcip->mci_rx_p_fn = rx_fn; 2827fc4e975dSVenugopal Iyer mcip->mci_rx_p_arg = arg; 2828fc4e975dSVenugopal Iyer } 2829fc4e975dSVenugopal Iyer return (0); 2830fc4e975dSVenugopal Iyer } 2831fc4e975dSVenugopal Iyer if (rx_fn != NULL) 2832fc4e975dSVenugopal Iyer mac_rx_set(mch, rx_fn, arg); 2833fc4e975dSVenugopal Iyer return (err); 2834fc4e975dSVenugopal Iyer } 2835fc4e975dSVenugopal Iyer 2836da14cebeSEric Cheng int 2837da14cebeSEric Cheng mac_unicast_add(mac_client_handle_t mch, uint8_t *mac_addr, uint16_t flags, 2838da14cebeSEric Cheng mac_unicast_handle_t *mah, uint16_t vid, mac_diag_t *diag) 2839da14cebeSEric Cheng { 2840da14cebeSEric Cheng mac_impl_t *mip = ((mac_client_impl_t *)mch)->mci_mip; 2841da14cebeSEric Cheng uint_t err; 2842da14cebeSEric Cheng 2843da14cebeSEric Cheng i_mac_perim_enter(mip); 2844da14cebeSEric Cheng err = i_mac_unicast_add(mch, mac_addr, flags, mah, vid, diag); 2845da14cebeSEric Cheng i_mac_perim_exit(mip); 2846da14cebeSEric Cheng 2847da14cebeSEric Cheng return (err); 2848da14cebeSEric Cheng } 2849da14cebeSEric Cheng 28500dc2366fSVenugopal Iyer static void 2851fc4e975dSVenugopal Iyer mac_client_datapath_teardown(mac_client_handle_t mch, mac_unicast_impl_t *muip, 2852fc4e975dSVenugopal Iyer flow_entry_t *flent) 2853da14cebeSEric Cheng { 2854da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2855da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip; 28560dc2366fSVenugopal Iyer boolean_t no_unicast; 2857da14cebeSEric Cheng 2858ae6aa22aSVenugopal Iyer /* 28590dc2366fSVenugopal Iyer * If we have not added a unicast address for this MAC client, just 28600dc2366fSVenugopal Iyer * teardown the datapath. 28610dc2366fSVenugopal Iyer */ 28620dc2366fSVenugopal Iyer no_unicast = mcip->mci_state_flags & MCIS_NO_UNICAST_ADDR; 28630dc2366fSVenugopal Iyer 28640dc2366fSVenugopal Iyer if (!no_unicast) { 28650dc2366fSVenugopal Iyer /* 28660dc2366fSVenugopal Iyer * We would have initialized subflows etc. only if we brought 28670dc2366fSVenugopal Iyer * up the primary client and set the unicast unicast address 28680dc2366fSVenugopal Iyer * etc. Deactivate the flows. The flow entry will be removed 28690dc2366fSVenugopal Iyer * from the active flow tables, and the associated SRS, 28700dc2366fSVenugopal Iyer * softrings etc will be deleted. But the flow entry itself 28710dc2366fSVenugopal Iyer * won't be destroyed, instead it will continue to be archived 28720dc2366fSVenugopal Iyer * off the the global flow hash list, for a possible future 28730dc2366fSVenugopal Iyer * activation when say IP is plumbed again. 2874ae6aa22aSVenugopal Iyer */ 2875ae6aa22aSVenugopal Iyer mac_link_release_flows(mch); 28760dc2366fSVenugopal Iyer } 2877da14cebeSEric Cheng mip->mi_nactiveclients--; 2878ae6aa22aSVenugopal Iyer mac_update_single_active_client(mip); 2879da14cebeSEric Cheng 2880fc4e975dSVenugopal Iyer /* Tear down the data path */ 2881da14cebeSEric Cheng mac_datapath_teardown(mcip, mcip->mci_flent, SRST_LINK); 2882da14cebeSEric Cheng 2883da14cebeSEric Cheng /* 2884da14cebeSEric Cheng * Prevent any future access to the flow entry through the mci_flent 2885da14cebeSEric Cheng * pointer by setting the mci_flent to NULL. Access to mci_flent in 2886da14cebeSEric Cheng * mac_bcast_send is also under mi_rw_lock. 2887da14cebeSEric Cheng */ 2888da14cebeSEric Cheng rw_enter(&mip->mi_rw_lock, RW_WRITER); 2889da14cebeSEric Cheng flent = mcip->mci_flent; 2890da14cebeSEric Cheng mac_client_remove_flow_from_list(mcip, flent); 2891da14cebeSEric Cheng 2892da14cebeSEric Cheng if (mcip->mci_state_flags & MCIS_DESC_LOGGED) 2893da14cebeSEric Cheng mcip->mci_state_flags &= ~MCIS_DESC_LOGGED; 2894da14cebeSEric Cheng 2895da14cebeSEric Cheng /* 2896da14cebeSEric Cheng * This is the last unicast address being removed and there shouldn't 2897da14cebeSEric Cheng * be any outbound data threads at this point coming down from mac 2898da14cebeSEric Cheng * clients. We have waited for the data threads to finish before 2899da14cebeSEric Cheng * starting dld_str_detach. Non-data threads must access TX SRS 2900da14cebeSEric Cheng * under mi_rw_lock. 2901da14cebeSEric Cheng */ 2902da14cebeSEric Cheng rw_exit(&mip->mi_rw_lock); 2903da14cebeSEric Cheng 2904da14cebeSEric Cheng /* 2905da14cebeSEric Cheng * Don't use FLOW_MARK with FE_MC_NO_DATAPATH, as the flow might 2906da14cebeSEric Cheng * contain other flags, such as FE_CONDEMNED, which we need to 2907da14cebeSEric Cheng * cleared. We don't call mac_flow_cleanup() for this unicast 2908da14cebeSEric Cheng * flow as we have a already cleaned up SRSs etc. (via the teadown 2909da14cebeSEric Cheng * path). We just clear the stats and reset the initial callback 2910da14cebeSEric Cheng * function, the rest will be set when we call mac_flow_create, 2911da14cebeSEric Cheng * if at all. 2912da14cebeSEric Cheng */ 2913da14cebeSEric Cheng mutex_enter(&flent->fe_lock); 2914da14cebeSEric Cheng ASSERT(flent->fe_refcnt == 1 && flent->fe_mbg == NULL && 2915da14cebeSEric Cheng flent->fe_tx_srs == NULL && flent->fe_rx_srs_cnt == 0); 2916da14cebeSEric Cheng flent->fe_flags = FE_MC_NO_DATAPATH; 2917da14cebeSEric Cheng flow_stat_destroy(flent); 29180dc2366fSVenugopal Iyer mac_misc_stat_delete(flent); 2919da14cebeSEric Cheng 2920da14cebeSEric Cheng /* Initialize the receiver function to a safe routine */ 2921da14cebeSEric Cheng flent->fe_cb_fn = (flow_fn_t)mac_pkt_drop; 2922da14cebeSEric Cheng flent->fe_cb_arg1 = NULL; 2923da14cebeSEric Cheng flent->fe_cb_arg2 = NULL; 2924da14cebeSEric Cheng 2925da14cebeSEric Cheng flent->fe_index = -1; 2926da14cebeSEric Cheng mutex_exit(&flent->fe_lock); 2927da14cebeSEric Cheng 2928da14cebeSEric Cheng if (mip->mi_type->mt_brdcst_addr != NULL) { 29290dc2366fSVenugopal Iyer ASSERT(muip != NULL || no_unicast); 2930da14cebeSEric Cheng mac_bcast_delete(mcip, mip->mi_type->mt_brdcst_addr, 29310dc2366fSVenugopal Iyer muip != NULL ? muip->mui_vid : VLAN_ID_NONE); 2932da14cebeSEric Cheng } 2933da14cebeSEric Cheng 2934da14cebeSEric Cheng if (mip->mi_nactiveclients == 1) { 2935da14cebeSEric Cheng mac_capab_update((mac_handle_t)mip); 2936da14cebeSEric Cheng mac_virtual_link_update(mip); 2937da14cebeSEric Cheng } 29385d460eafSCathy Zhou 29395d460eafSCathy Zhou if (mcip->mci_state_flags & MCIS_EXCLUSIVE) { 2940da14cebeSEric Cheng mip->mi_state_flags &= ~MIS_EXCLUSIVE; 29415d460eafSCathy Zhou 29425d460eafSCathy Zhou if (mip->mi_state_flags & MIS_LEGACY) 29435d460eafSCathy Zhou mip->mi_capab_legacy.ml_active_clear(mip->mi_driver); 29445d460eafSCathy Zhou } 29455d460eafSCathy Zhou 294608ac1c49SNicolas Droux mcip->mci_state_flags &= ~MCIS_UNICAST_HW; 2947da14cebeSEric Cheng 29484c91d6c6SVenugopal Iyer if (mcip->mci_state_flags & MCIS_TAG_DISABLE) 29494c91d6c6SVenugopal Iyer mcip->mci_state_flags &= ~MCIS_TAG_DISABLE; 29504c91d6c6SVenugopal Iyer 29514c91d6c6SVenugopal Iyer if (mcip->mci_state_flags & MCIS_STRIP_DISABLE) 29524c91d6c6SVenugopal Iyer mcip->mci_state_flags &= ~MCIS_STRIP_DISABLE; 29534c91d6c6SVenugopal Iyer 29544c91d6c6SVenugopal Iyer if (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) 29554c91d6c6SVenugopal Iyer mcip->mci_state_flags &= ~MCIS_DISABLE_TX_VID_CHECK; 29564c91d6c6SVenugopal Iyer 29570dc2366fSVenugopal Iyer if (muip != NULL) 2958da14cebeSEric Cheng kmem_free(muip, sizeof (mac_unicast_impl_t)); 29590dc2366fSVenugopal Iyer mac_protect_cancel_timer(mcip); 29604e6f6c83SCody Peter Mello mac_protect_flush_dynamic(mcip); 29615d460eafSCathy Zhou 29620dc2366fSVenugopal Iyer bzero(&mcip->mci_misc_stat, sizeof (mcip->mci_misc_stat)); 29635d460eafSCathy Zhou /* 29645d460eafSCathy Zhou * Disable fastpath if this is a VNIC or a VLAN. 29655d460eafSCathy Zhou */ 29665d460eafSCathy Zhou if (mcip->mci_state_flags & MCIS_IS_VNIC) 29675d460eafSCathy Zhou mac_fastpath_enable((mac_handle_t)mip); 29685d460eafSCathy Zhou mac_stop((mac_handle_t)mip); 2969fc4e975dSVenugopal Iyer } 2970fc4e975dSVenugopal Iyer 2971fc4e975dSVenugopal Iyer /* 2972fc4e975dSVenugopal Iyer * Remove a MAC address which was previously added by mac_unicast_add(). 2973fc4e975dSVenugopal Iyer */ 2974fc4e975dSVenugopal Iyer int 2975fc4e975dSVenugopal Iyer mac_unicast_remove(mac_client_handle_t mch, mac_unicast_handle_t mah) 2976fc4e975dSVenugopal Iyer { 2977fc4e975dSVenugopal Iyer mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 2978fc4e975dSVenugopal Iyer mac_unicast_impl_t *muip = (mac_unicast_impl_t *)mah; 2979fc4e975dSVenugopal Iyer mac_unicast_impl_t *pre; 2980fc4e975dSVenugopal Iyer mac_impl_t *mip = mcip->mci_mip; 2981fc4e975dSVenugopal Iyer flow_entry_t *flent; 29820dc2366fSVenugopal Iyer uint16_t mui_vid; 2983fc4e975dSVenugopal Iyer 2984fc4e975dSVenugopal Iyer i_mac_perim_enter(mip); 2985fc4e975dSVenugopal Iyer if (mcip->mci_flags & MAC_CLIENT_FLAGS_VNIC_PRIMARY) { 2986fc4e975dSVenugopal Iyer /* 2987fc4e975dSVenugopal Iyer * Called made by the upper MAC client of a VNIC. 2988fc4e975dSVenugopal Iyer * There's nothing much to do, the unicast address will 2989fc4e975dSVenugopal Iyer * be removed by the VNIC driver when the VNIC is deleted, 2990fc4e975dSVenugopal Iyer * but let's ensure that all our transmit is done before 2991fc4e975dSVenugopal Iyer * the client does a mac_client_stop lest it trigger an 2992fc4e975dSVenugopal Iyer * assert in the driver. 2993fc4e975dSVenugopal Iyer */ 2994fc4e975dSVenugopal Iyer ASSERT(muip->mui_vid == 0); 2995fc4e975dSVenugopal Iyer 2996fc4e975dSVenugopal Iyer mac_tx_client_flush(mcip); 2997fc4e975dSVenugopal Iyer 2998fc4e975dSVenugopal Iyer if ((mcip->mci_flags & MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) { 2999fc4e975dSVenugopal Iyer mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PASSIVE_PRIMARY; 3000fc4e975dSVenugopal Iyer if (mcip->mci_rx_p_fn != NULL) { 3001fc4e975dSVenugopal Iyer mac_rx_set(mch, mcip->mci_rx_p_fn, 3002fc4e975dSVenugopal Iyer mcip->mci_rx_p_arg); 3003fc4e975dSVenugopal Iyer mcip->mci_rx_p_fn = NULL; 3004fc4e975dSVenugopal Iyer mcip->mci_rx_p_arg = NULL; 3005fc4e975dSVenugopal Iyer } 3006fc4e975dSVenugopal Iyer kmem_free(muip, sizeof (mac_unicast_impl_t)); 3007fc4e975dSVenugopal Iyer i_mac_perim_exit(mip); 3008fc4e975dSVenugopal Iyer return (0); 3009fc4e975dSVenugopal Iyer } 3010fc4e975dSVenugopal Iyer mcip->mci_flags &= ~MAC_CLIENT_FLAGS_VNIC_PRIMARY; 3011fc4e975dSVenugopal Iyer 3012fc4e975dSVenugopal Iyer if (mcip->mci_state_flags & MCIS_TAG_DISABLE) 3013fc4e975dSVenugopal Iyer mcip->mci_state_flags &= ~MCIS_TAG_DISABLE; 3014fc4e975dSVenugopal Iyer 3015fc4e975dSVenugopal Iyer if (mcip->mci_state_flags & MCIS_STRIP_DISABLE) 3016fc4e975dSVenugopal Iyer mcip->mci_state_flags &= ~MCIS_STRIP_DISABLE; 3017fc4e975dSVenugopal Iyer 3018fc4e975dSVenugopal Iyer if (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) 3019fc4e975dSVenugopal Iyer mcip->mci_state_flags &= ~MCIS_DISABLE_TX_VID_CHECK; 3020fc4e975dSVenugopal Iyer 3021fc4e975dSVenugopal Iyer kmem_free(muip, sizeof (mac_unicast_impl_t)); 3022fc4e975dSVenugopal Iyer i_mac_perim_exit(mip); 3023fc4e975dSVenugopal Iyer return (0); 3024fc4e975dSVenugopal Iyer } 3025fc4e975dSVenugopal Iyer 3026fc4e975dSVenugopal Iyer ASSERT(muip != NULL); 3027fc4e975dSVenugopal Iyer 3028fc4e975dSVenugopal Iyer /* 3029fc4e975dSVenugopal Iyer * We are removing a passive client, we haven't setup the datapath 3030fc4e975dSVenugopal Iyer * for this yet, so nothing much to do. 3031fc4e975dSVenugopal Iyer */ 3032b460a6edSVenugopal Iyer if ((mcip->mci_flags & MAC_CLIENT_FLAGS_PASSIVE_PRIMARY) != 0) { 3033fc4e975dSVenugopal Iyer 3034fc4e975dSVenugopal Iyer ASSERT((mcip->mci_flent->fe_flags & FE_MC_NO_DATAPATH) != 0); 3035fc4e975dSVenugopal Iyer ASSERT(mcip->mci_p_unicast_list == muip); 3036fc4e975dSVenugopal Iyer 3037b460a6edSVenugopal Iyer mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PASSIVE_PRIMARY; 3038b460a6edSVenugopal Iyer 3039fc4e975dSVenugopal Iyer mcip->mci_p_unicast_list = NULL; 3040fc4e975dSVenugopal Iyer mcip->mci_rx_p_fn = NULL; 3041fc4e975dSVenugopal Iyer mcip->mci_rx_p_arg = NULL; 3042fc4e975dSVenugopal Iyer 3043fc4e975dSVenugopal Iyer mcip->mci_state_flags &= ~MCIS_UNICAST_HW; 3044fc4e975dSVenugopal Iyer 3045fc4e975dSVenugopal Iyer if (mcip->mci_state_flags & MCIS_TAG_DISABLE) 3046fc4e975dSVenugopal Iyer mcip->mci_state_flags &= ~MCIS_TAG_DISABLE; 3047fc4e975dSVenugopal Iyer 3048fc4e975dSVenugopal Iyer if (mcip->mci_state_flags & MCIS_STRIP_DISABLE) 3049fc4e975dSVenugopal Iyer mcip->mci_state_flags &= ~MCIS_STRIP_DISABLE; 3050fc4e975dSVenugopal Iyer 3051fc4e975dSVenugopal Iyer if (mcip->mci_state_flags & MCIS_DISABLE_TX_VID_CHECK) 3052fc4e975dSVenugopal Iyer mcip->mci_state_flags &= ~MCIS_DISABLE_TX_VID_CHECK; 3053fc4e975dSVenugopal Iyer 3054fc4e975dSVenugopal Iyer kmem_free(muip, sizeof (mac_unicast_impl_t)); 3055fc4e975dSVenugopal Iyer i_mac_perim_exit(mip); 3056fc4e975dSVenugopal Iyer return (0); 3057fc4e975dSVenugopal Iyer } 3058fc4e975dSVenugopal Iyer /* 3059fc4e975dSVenugopal Iyer * Remove the VID from the list of client's VIDs. 3060fc4e975dSVenugopal Iyer */ 3061fc4e975dSVenugopal Iyer pre = mcip->mci_unicast_list; 3062fc4e975dSVenugopal Iyer if (muip == pre) { 3063fc4e975dSVenugopal Iyer mcip->mci_unicast_list = muip->mui_next; 3064fc4e975dSVenugopal Iyer } else { 3065fc4e975dSVenugopal Iyer while ((pre->mui_next != NULL) && (pre->mui_next != muip)) 3066fc4e975dSVenugopal Iyer pre = pre->mui_next; 3067fc4e975dSVenugopal Iyer ASSERT(pre->mui_next == muip); 3068fc4e975dSVenugopal Iyer rw_enter(&mcip->mci_rw_lock, RW_WRITER); 3069fc4e975dSVenugopal Iyer pre->mui_next = muip->mui_next; 3070fc4e975dSVenugopal Iyer rw_exit(&mcip->mci_rw_lock); 3071fc4e975dSVenugopal Iyer } 3072fc4e975dSVenugopal Iyer 3073fc4e975dSVenugopal Iyer if (!mac_client_single_rcvr(mcip)) { 3074fc4e975dSVenugopal Iyer /* 3075fc4e975dSVenugopal Iyer * This MAC client is shared by more than one unicast 3076fc4e975dSVenugopal Iyer * addresses, so we will just remove the flent 3077fc4e975dSVenugopal Iyer * corresponding to the address being removed. We don't invoke 3078fc4e975dSVenugopal Iyer * mac_rx_classify_flow_rem() since the additional flow is 3079fc4e975dSVenugopal Iyer * not associated with its own separate set of SRS and rings, 3080fc4e975dSVenugopal Iyer * and these constructs are still needed for the remaining 3081fc4e975dSVenugopal Iyer * flows. 3082fc4e975dSVenugopal Iyer */ 3083fc4e975dSVenugopal Iyer flent = mac_client_get_flow(mcip, muip); 3084fc4e975dSVenugopal Iyer ASSERT(flent != NULL); 3085fc4e975dSVenugopal Iyer 3086fc4e975dSVenugopal Iyer /* 3087fc4e975dSVenugopal Iyer * The first one is disappearing, need to make sure 3088fc4e975dSVenugopal Iyer * we replace it with another from the list of 3089fc4e975dSVenugopal Iyer * shared clients. 3090fc4e975dSVenugopal Iyer */ 3091fc4e975dSVenugopal Iyer if (flent == mcip->mci_flent) 3092fc4e975dSVenugopal Iyer flent = mac_client_swap_mciflent(mcip); 3093fc4e975dSVenugopal Iyer mac_client_remove_flow_from_list(mcip, flent); 3094fc4e975dSVenugopal Iyer mac_flow_remove(mip->mi_flow_tab, flent, B_FALSE); 3095fc4e975dSVenugopal Iyer mac_flow_wait(flent, FLOW_DRIVER_UPCALL); 3096fc4e975dSVenugopal Iyer 3097fc4e975dSVenugopal Iyer /* 3098fc4e975dSVenugopal Iyer * The multicast groups that were added by the client so 3099fc4e975dSVenugopal Iyer * far must be removed from the brodcast domain corresponding 3100fc4e975dSVenugopal Iyer * to the VID being removed. 3101fc4e975dSVenugopal Iyer */ 3102fc4e975dSVenugopal Iyer mac_client_bcast_refresh(mcip, mac_client_update_mcast, 3103fc4e975dSVenugopal Iyer (void *)flent, B_FALSE); 3104fc4e975dSVenugopal Iyer 3105fc4e975dSVenugopal Iyer if (mip->mi_type->mt_brdcst_addr != NULL) { 3106fc4e975dSVenugopal Iyer mac_bcast_delete(mcip, mip->mi_type->mt_brdcst_addr, 3107fc4e975dSVenugopal Iyer muip->mui_vid); 3108fc4e975dSVenugopal Iyer } 3109fc4e975dSVenugopal Iyer 3110fc4e975dSVenugopal Iyer FLOW_FINAL_REFRELE(flent); 3111fc4e975dSVenugopal Iyer ASSERT(!(mcip->mci_state_flags & MCIS_EXCLUSIVE)); 3112fc4e975dSVenugopal Iyer /* 3113fc4e975dSVenugopal Iyer * Enable fastpath if this is a VNIC or a VLAN. 3114fc4e975dSVenugopal Iyer */ 3115fc4e975dSVenugopal Iyer if (mcip->mci_state_flags & MCIS_IS_VNIC) 3116fc4e975dSVenugopal Iyer mac_fastpath_enable((mac_handle_t)mip); 3117fc4e975dSVenugopal Iyer mac_stop((mac_handle_t)mip); 3118fc4e975dSVenugopal Iyer i_mac_perim_exit(mip); 3119fc4e975dSVenugopal Iyer return (0); 3120fc4e975dSVenugopal Iyer } 3121fc4e975dSVenugopal Iyer 31220dc2366fSVenugopal Iyer mui_vid = muip->mui_vid; 3123fc4e975dSVenugopal Iyer mac_client_datapath_teardown(mch, muip, flent); 3124fc4e975dSVenugopal Iyer 31250dc2366fSVenugopal Iyer if ((mcip->mci_flags & MAC_CLIENT_FLAGS_PRIMARY) && mui_vid == 0) { 31260dc2366fSVenugopal Iyer mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PRIMARY; 31270dc2366fSVenugopal Iyer } else { 31280dc2366fSVenugopal Iyer i_mac_perim_exit(mip); 31290dc2366fSVenugopal Iyer return (0); 31300dc2366fSVenugopal Iyer } 31310dc2366fSVenugopal Iyer 3132fc4e975dSVenugopal Iyer /* 3133fc4e975dSVenugopal Iyer * If we are removing the primary, check if we have a passive primary 3134fc4e975dSVenugopal Iyer * client that we need to activate now. 3135fc4e975dSVenugopal Iyer */ 3136fc4e975dSVenugopal Iyer mcip = mac_get_passive_primary_client(mip); 3137fc4e975dSVenugopal Iyer if (mcip != NULL) { 31380dc2366fSVenugopal Iyer mac_resource_props_t *mrp; 3139fc4e975dSVenugopal Iyer mac_unicast_impl_t *muip; 3140fc4e975dSVenugopal Iyer 3141fc4e975dSVenugopal Iyer mcip->mci_flags &= ~MAC_CLIENT_FLAGS_PASSIVE_PRIMARY; 31420dc2366fSVenugopal Iyer mrp = kmem_zalloc(sizeof (*mrp), KM_SLEEP); 31430dc2366fSVenugopal Iyer 3144fc4e975dSVenugopal Iyer /* 3145fc4e975dSVenugopal Iyer * Apply the property cached in the mac_impl_t to the 3146fc4e975dSVenugopal Iyer * primary mac client. 3147fc4e975dSVenugopal Iyer */ 31480dc2366fSVenugopal Iyer mac_get_resources((mac_handle_t)mip, mrp); 31490dc2366fSVenugopal Iyer (void) mac_client_set_resources(mch, mrp); 3150fc4e975dSVenugopal Iyer ASSERT(mcip->mci_p_unicast_list != NULL); 3151fc4e975dSVenugopal Iyer muip = mcip->mci_p_unicast_list; 3152fc4e975dSVenugopal Iyer mcip->mci_p_unicast_list = NULL; 3153fc4e975dSVenugopal Iyer if (mac_client_datapath_setup(mcip, VLAN_ID_NONE, 31540dc2366fSVenugopal Iyer mip->mi_addr, mrp, B_TRUE, muip) == 0) { 3155fc4e975dSVenugopal Iyer if (mcip->mci_rx_p_fn != NULL) { 3156fc4e975dSVenugopal Iyer mac_rx_set(mch, mcip->mci_rx_p_fn, 3157fc4e975dSVenugopal Iyer mcip->mci_rx_p_arg); 3158fc4e975dSVenugopal Iyer mcip->mci_rx_p_fn = NULL; 3159fc4e975dSVenugopal Iyer mcip->mci_rx_p_arg = NULL; 3160fc4e975dSVenugopal Iyer } 3161c9c211bcSVenugopal Iyer } else { 3162c9c211bcSVenugopal Iyer kmem_free(muip, sizeof (mac_unicast_impl_t)); 3163fc4e975dSVenugopal Iyer } 31640dc2366fSVenugopal Iyer kmem_free(mrp, sizeof (*mrp)); 3165fc4e975dSVenugopal Iyer } 31665d460eafSCathy Zhou i_mac_perim_exit(mip); 3167da14cebeSEric Cheng return (0); 3168da14cebeSEric Cheng } 3169da14cebeSEric Cheng 3170da14cebeSEric Cheng /* 3171da14cebeSEric Cheng * Multicast add function invoked by MAC clients. 3172da14cebeSEric Cheng */ 3173da14cebeSEric Cheng int 3174da14cebeSEric Cheng mac_multicast_add(mac_client_handle_t mch, const uint8_t *addr) 3175da14cebeSEric Cheng { 3176da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3177da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip; 3178da14cebeSEric Cheng flow_entry_t *flent = mcip->mci_flent_list; 3179da14cebeSEric Cheng flow_entry_t *prev_fe = NULL; 3180da14cebeSEric Cheng uint16_t vid; 3181da14cebeSEric Cheng int err = 0; 3182da14cebeSEric Cheng 3183da14cebeSEric Cheng /* Verify the address is a valid multicast address */ 3184da14cebeSEric Cheng if ((err = mip->mi_type->mt_ops.mtops_multicst_verify(addr, 3185da14cebeSEric Cheng mip->mi_pdata)) != 0) 3186da14cebeSEric Cheng return (err); 3187da14cebeSEric Cheng 3188da14cebeSEric Cheng i_mac_perim_enter(mip); 3189da14cebeSEric Cheng while (flent != NULL) { 3190da14cebeSEric Cheng vid = i_mac_flow_vid(flent); 3191da14cebeSEric Cheng 3192da14cebeSEric Cheng err = mac_bcast_add((mac_client_impl_t *)mch, addr, vid, 3193da14cebeSEric Cheng MAC_ADDRTYPE_MULTICAST); 3194da14cebeSEric Cheng if (err != 0) 3195da14cebeSEric Cheng break; 3196da14cebeSEric Cheng prev_fe = flent; 3197da14cebeSEric Cheng flent = flent->fe_client_next; 3198da14cebeSEric Cheng } 3199da14cebeSEric Cheng 3200da14cebeSEric Cheng /* 3201da14cebeSEric Cheng * If we failed adding, then undo all, rather than partial 3202da14cebeSEric Cheng * success. 3203da14cebeSEric Cheng */ 3204da14cebeSEric Cheng if (flent != NULL && prev_fe != NULL) { 3205da14cebeSEric Cheng flent = mcip->mci_flent_list; 3206da14cebeSEric Cheng while (flent != prev_fe->fe_client_next) { 3207da14cebeSEric Cheng vid = i_mac_flow_vid(flent); 3208da14cebeSEric Cheng mac_bcast_delete((mac_client_impl_t *)mch, addr, vid); 3209da14cebeSEric Cheng flent = flent->fe_client_next; 3210da14cebeSEric Cheng } 3211da14cebeSEric Cheng } 3212da14cebeSEric Cheng i_mac_perim_exit(mip); 3213da14cebeSEric Cheng return (err); 3214da14cebeSEric Cheng } 3215da14cebeSEric Cheng 3216da14cebeSEric Cheng /* 3217da14cebeSEric Cheng * Multicast delete function invoked by MAC clients. 3218da14cebeSEric Cheng */ 3219da14cebeSEric Cheng void 3220da14cebeSEric Cheng mac_multicast_remove(mac_client_handle_t mch, const uint8_t *addr) 3221da14cebeSEric Cheng { 3222da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3223da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip; 3224da14cebeSEric Cheng flow_entry_t *flent; 3225da14cebeSEric Cheng uint16_t vid; 3226da14cebeSEric Cheng 3227da14cebeSEric Cheng i_mac_perim_enter(mip); 3228da14cebeSEric Cheng for (flent = mcip->mci_flent_list; flent != NULL; 3229da14cebeSEric Cheng flent = flent->fe_client_next) { 3230da14cebeSEric Cheng vid = i_mac_flow_vid(flent); 3231da14cebeSEric Cheng mac_bcast_delete((mac_client_impl_t *)mch, addr, vid); 3232da14cebeSEric Cheng } 3233da14cebeSEric Cheng i_mac_perim_exit(mip); 3234da14cebeSEric Cheng } 3235da14cebeSEric Cheng 3236da14cebeSEric Cheng /* 3237da14cebeSEric Cheng * When a MAC client desires to capture packets on an interface, 3238da14cebeSEric Cheng * it registers a promiscuous call back with mac_promisc_add(). 3239da14cebeSEric Cheng * There are three types of promiscuous callbacks: 3240da14cebeSEric Cheng * 3241da14cebeSEric Cheng * * MAC_CLIENT_PROMISC_ALL 3242da14cebeSEric Cheng * Captures all packets sent and received by the MAC client, 3243da14cebeSEric Cheng * the physical interface, as well as all other MAC clients 3244da14cebeSEric Cheng * defined on top of the same MAC. 3245da14cebeSEric Cheng * 3246da14cebeSEric Cheng * * MAC_CLIENT_PROMISC_FILTERED 3247da14cebeSEric Cheng * Captures all packets sent and received by the MAC client, 3248da14cebeSEric Cheng * plus all multicast traffic sent and received by the phyisical 3249da14cebeSEric Cheng * interface and the other MAC clients. 3250da14cebeSEric Cheng * 3251da14cebeSEric Cheng * * MAC_CLIENT_PROMISC_MULTI 3252da14cebeSEric Cheng * Captures all broadcast and multicast packets sent and 3253da14cebeSEric Cheng * received by the MAC clients as well as the physical interface. 3254da14cebeSEric Cheng * 3255da14cebeSEric Cheng * In all cases, the underlying MAC is put in promiscuous mode. 3256da14cebeSEric Cheng */ 3257da14cebeSEric Cheng int 3258da14cebeSEric Cheng mac_promisc_add(mac_client_handle_t mch, mac_client_promisc_type_t type, 3259da14cebeSEric Cheng mac_rx_t fn, void *arg, mac_promisc_handle_t *mphp, uint16_t flags) 3260da14cebeSEric Cheng { 3261da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3262da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip; 3263da14cebeSEric Cheng mac_promisc_impl_t *mpip; 3264da14cebeSEric Cheng mac_cb_info_t *mcbi; 3265da14cebeSEric Cheng int rc; 3266da14cebeSEric Cheng 3267da14cebeSEric Cheng i_mac_perim_enter(mip); 3268da14cebeSEric Cheng 32693bdd2dd4SMichael Lim if ((rc = mac_start((mac_handle_t)mip)) != 0) { 3270da14cebeSEric Cheng i_mac_perim_exit(mip); 3271da14cebeSEric Cheng return (rc); 3272da14cebeSEric Cheng } 3273da14cebeSEric Cheng 3274da14cebeSEric Cheng if ((mcip->mci_state_flags & MCIS_IS_VNIC) && 3275098d2c75SRobert Mustacchi type == MAC_CLIENT_PROMISC_ALL && 3276098d2c75SRobert Mustacchi (mcip->mci_protect_flags & MPT_FLAG_PROMISC_FILTERED)) { 3277da14cebeSEric Cheng /* 3278da14cebeSEric Cheng * The function is being invoked by the upper MAC client 3279da14cebeSEric Cheng * of a VNIC. The VNIC should only see the traffic 3280da14cebeSEric Cheng * it is entitled to. 3281da14cebeSEric Cheng */ 3282da14cebeSEric Cheng type = MAC_CLIENT_PROMISC_FILTERED; 3283da14cebeSEric Cheng } 3284da14cebeSEric Cheng 3285da14cebeSEric Cheng 3286da14cebeSEric Cheng /* 3287da14cebeSEric Cheng * Turn on promiscuous mode for the underlying NIC. 3288da14cebeSEric Cheng * This is needed even for filtered callbacks which 3289da14cebeSEric Cheng * expect to receive all multicast traffic on the wire. 3290da14cebeSEric Cheng * 3291da14cebeSEric Cheng * Physical promiscuous mode should not be turned on if 3292da14cebeSEric Cheng * MAC_PROMISC_FLAGS_NO_PHYS is set. 3293da14cebeSEric Cheng */ 3294da14cebeSEric Cheng if ((flags & MAC_PROMISC_FLAGS_NO_PHYS) == 0) { 3295d91a22bfSGirish Moodalbail if ((rc = i_mac_promisc_set(mip, B_TRUE)) != 0) { 32963bdd2dd4SMichael Lim mac_stop((mac_handle_t)mip); 3297da14cebeSEric Cheng i_mac_perim_exit(mip); 3298da14cebeSEric Cheng return (rc); 3299da14cebeSEric Cheng } 3300da14cebeSEric Cheng } 3301da14cebeSEric Cheng 3302da14cebeSEric Cheng mpip = kmem_cache_alloc(mac_promisc_impl_cache, KM_SLEEP); 3303da14cebeSEric Cheng 3304da14cebeSEric Cheng mpip->mpi_type = type; 3305da14cebeSEric Cheng mpip->mpi_fn = fn; 3306da14cebeSEric Cheng mpip->mpi_arg = arg; 3307da14cebeSEric Cheng mpip->mpi_mcip = mcip; 3308da14cebeSEric Cheng mpip->mpi_no_tx_loop = ((flags & MAC_PROMISC_FLAGS_NO_TX_LOOP) != 0); 3309da14cebeSEric Cheng mpip->mpi_no_phys = ((flags & MAC_PROMISC_FLAGS_NO_PHYS) != 0); 3310ae6aa22aSVenugopal Iyer mpip->mpi_strip_vlan_tag = 3311ae6aa22aSVenugopal Iyer ((flags & MAC_PROMISC_FLAGS_VLAN_TAG_STRIP) != 0); 33120a0e9771SDarren Reed mpip->mpi_no_copy = ((flags & MAC_PROMISC_FLAGS_NO_COPY) != 0); 3313da14cebeSEric Cheng 3314da14cebeSEric Cheng mcbi = &mip->mi_promisc_cb_info; 3315da14cebeSEric Cheng mutex_enter(mcbi->mcbi_lockp); 3316da14cebeSEric Cheng 3317da14cebeSEric Cheng mac_callback_add(&mip->mi_promisc_cb_info, &mcip->mci_promisc_list, 3318da14cebeSEric Cheng &mpip->mpi_mci_link); 3319da14cebeSEric Cheng mac_callback_add(&mip->mi_promisc_cb_info, &mip->mi_promisc_list, 3320da14cebeSEric Cheng &mpip->mpi_mi_link); 3321da14cebeSEric Cheng 3322da14cebeSEric Cheng mutex_exit(mcbi->mcbi_lockp); 3323da14cebeSEric Cheng 3324da14cebeSEric Cheng *mphp = (mac_promisc_handle_t)mpip; 33251a41ca23SJerry Jelinek 33261a41ca23SJerry Jelinek if (mcip->mci_state_flags & MCIS_IS_VNIC) { 33271a41ca23SJerry Jelinek mac_impl_t *umip = mcip->mci_upper_mip; 33281a41ca23SJerry Jelinek 33291a41ca23SJerry Jelinek ASSERT(umip != NULL); 33301a41ca23SJerry Jelinek mac_vnic_secondary_update(umip); 33311a41ca23SJerry Jelinek } 33321a41ca23SJerry Jelinek 3333da14cebeSEric Cheng i_mac_perim_exit(mip); 33341a41ca23SJerry Jelinek 3335da14cebeSEric Cheng return (0); 3336da14cebeSEric Cheng } 3337da14cebeSEric Cheng 3338da14cebeSEric Cheng /* 3339da14cebeSEric Cheng * Remove a multicast address previously aded through mac_promisc_add(). 3340da14cebeSEric Cheng */ 33415ecc58b1SGirish Moodalbail void 3342da14cebeSEric Cheng mac_promisc_remove(mac_promisc_handle_t mph) 3343da14cebeSEric Cheng { 3344da14cebeSEric Cheng mac_promisc_impl_t *mpip = (mac_promisc_impl_t *)mph; 3345da14cebeSEric Cheng mac_client_impl_t *mcip = mpip->mpi_mcip; 3346da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip; 3347da14cebeSEric Cheng mac_cb_info_t *mcbi; 3348d91a22bfSGirish Moodalbail int rv; 3349da14cebeSEric Cheng 3350da14cebeSEric Cheng i_mac_perim_enter(mip); 3351da14cebeSEric Cheng 3352da14cebeSEric Cheng /* 3353da14cebeSEric Cheng * Even if the device can't be reset into normal mode, we still 3354da14cebeSEric Cheng * need to clear the client promisc callbacks. The client may want 3355da14cebeSEric Cheng * to close the mac end point and we can't have stale callbacks. 3356da14cebeSEric Cheng */ 3357da14cebeSEric Cheng if (!(mpip->mpi_no_phys)) { 3358d91a22bfSGirish Moodalbail if ((rv = i_mac_promisc_set(mip, B_FALSE)) != 0) { 3359d91a22bfSGirish Moodalbail cmn_err(CE_WARN, "%s: failed to switch OFF promiscuous" 3360d91a22bfSGirish Moodalbail " mode because of error 0x%x", mip->mi_name, rv); 3361d91a22bfSGirish Moodalbail } 3362da14cebeSEric Cheng } 3363da14cebeSEric Cheng mcbi = &mip->mi_promisc_cb_info; 3364da14cebeSEric Cheng mutex_enter(mcbi->mcbi_lockp); 3365da14cebeSEric Cheng if (mac_callback_remove(mcbi, &mip->mi_promisc_list, 3366da14cebeSEric Cheng &mpip->mpi_mi_link)) { 3367da14cebeSEric Cheng VERIFY(mac_callback_remove(&mip->mi_promisc_cb_info, 3368da14cebeSEric Cheng &mcip->mci_promisc_list, &mpip->mpi_mci_link)); 3369da14cebeSEric Cheng kmem_cache_free(mac_promisc_impl_cache, mpip); 3370da14cebeSEric Cheng } else { 3371da14cebeSEric Cheng mac_callback_remove_wait(&mip->mi_promisc_cb_info); 3372da14cebeSEric Cheng } 33731a41ca23SJerry Jelinek 33741a41ca23SJerry Jelinek if (mcip->mci_state_flags & MCIS_IS_VNIC) { 33751a41ca23SJerry Jelinek mac_impl_t *umip = mcip->mci_upper_mip; 33761a41ca23SJerry Jelinek 33771a41ca23SJerry Jelinek ASSERT(umip != NULL); 33781a41ca23SJerry Jelinek mac_vnic_secondary_update(umip); 33791a41ca23SJerry Jelinek } 33801a41ca23SJerry Jelinek 3381da14cebeSEric Cheng mutex_exit(mcbi->mcbi_lockp); 33823bdd2dd4SMichael Lim mac_stop((mac_handle_t)mip); 3383da14cebeSEric Cheng 3384da14cebeSEric Cheng i_mac_perim_exit(mip); 3385da14cebeSEric Cheng } 3386da14cebeSEric Cheng 3387da14cebeSEric Cheng /* 3388da14cebeSEric Cheng * Reference count the number of active Tx threads. MCI_TX_QUIESCE indicates 3389da14cebeSEric Cheng * that a control operation wants to quiesce the Tx data flow in which case 3390da14cebeSEric Cheng * we return an error. Holding any of the per cpu locks ensures that the 3391da14cebeSEric Cheng * mci_tx_flag won't change. 3392da14cebeSEric Cheng * 3393da14cebeSEric Cheng * 'CPU' must be accessed just once and used to compute the index into the 3394da14cebeSEric Cheng * percpu array, and that index must be used for the entire duration of the 3395da14cebeSEric Cheng * packet send operation. Note that the thread may be preempted and run on 3396da14cebeSEric Cheng * another cpu any time and so we can't use 'CPU' more than once for the 3397da14cebeSEric Cheng * operation. 3398da14cebeSEric Cheng */ 3399da14cebeSEric Cheng #define MAC_TX_TRY_HOLD(mcip, mytx, error) \ 3400da14cebeSEric Cheng { \ 3401da14cebeSEric Cheng (error) = 0; \ 3402da14cebeSEric Cheng (mytx) = &(mcip)->mci_tx_pcpu[CPU->cpu_seqid & mac_tx_percpu_cnt]; \ 3403da14cebeSEric Cheng mutex_enter(&(mytx)->pcpu_tx_lock); \ 3404da14cebeSEric Cheng if (!((mcip)->mci_tx_flag & MCI_TX_QUIESCE)) { \ 3405da14cebeSEric Cheng (mytx)->pcpu_tx_refcnt++; \ 3406da14cebeSEric Cheng } else { \ 3407da14cebeSEric Cheng (error) = -1; \ 3408da14cebeSEric Cheng } \ 3409da14cebeSEric Cheng mutex_exit(&(mytx)->pcpu_tx_lock); \ 3410da14cebeSEric Cheng } 3411da14cebeSEric Cheng 3412da14cebeSEric Cheng /* 3413da14cebeSEric Cheng * Release the reference. If needed, signal any control operation waiting 3414da14cebeSEric Cheng * for Tx quiescence. The wait and signal are always done using the 3415da14cebeSEric Cheng * mci_tx_pcpu[0]'s lock 3416da14cebeSEric Cheng */ 3417da14cebeSEric Cheng #define MAC_TX_RELE(mcip, mytx) { \ 3418da14cebeSEric Cheng mutex_enter(&(mytx)->pcpu_tx_lock); \ 3419da14cebeSEric Cheng if (--(mytx)->pcpu_tx_refcnt == 0 && \ 3420da14cebeSEric Cheng (mcip)->mci_tx_flag & MCI_TX_QUIESCE) { \ 3421da14cebeSEric Cheng mutex_exit(&(mytx)->pcpu_tx_lock); \ 3422da14cebeSEric Cheng mutex_enter(&(mcip)->mci_tx_pcpu[0].pcpu_tx_lock); \ 3423da14cebeSEric Cheng cv_signal(&(mcip)->mci_tx_cv); \ 3424da14cebeSEric Cheng mutex_exit(&(mcip)->mci_tx_pcpu[0].pcpu_tx_lock); \ 3425da14cebeSEric Cheng } else { \ 3426da14cebeSEric Cheng mutex_exit(&(mytx)->pcpu_tx_lock); \ 3427da14cebeSEric Cheng } \ 3428da14cebeSEric Cheng } 3429da14cebeSEric Cheng 3430da14cebeSEric Cheng /* 3431da14cebeSEric Cheng * Send function invoked by MAC clients. 3432da14cebeSEric Cheng */ 3433da14cebeSEric Cheng mac_tx_cookie_t 3434da14cebeSEric Cheng mac_tx(mac_client_handle_t mch, mblk_t *mp_chain, uintptr_t hint, 3435da14cebeSEric Cheng uint16_t flag, mblk_t **ret_mp) 3436da14cebeSEric Cheng { 343725ec3e3dSEric Cheng mac_tx_cookie_t cookie = NULL; 3438da14cebeSEric Cheng int error; 3439da14cebeSEric Cheng mac_tx_percpu_t *mytx; 3440da14cebeSEric Cheng mac_soft_ring_set_t *srs; 3441da14cebeSEric Cheng flow_entry_t *flent; 3442da14cebeSEric Cheng boolean_t is_subflow = B_FALSE; 3443da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3444da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip; 3445da14cebeSEric Cheng mac_srs_tx_t *srs_tx; 3446da14cebeSEric Cheng 3447da14cebeSEric Cheng /* 3448da14cebeSEric Cheng * Check whether the active Tx threads count is bumped already. 3449da14cebeSEric Cheng */ 3450da14cebeSEric Cheng if (!(flag & MAC_TX_NO_HOLD)) { 3451da14cebeSEric Cheng MAC_TX_TRY_HOLD(mcip, mytx, error); 3452da14cebeSEric Cheng if (error != 0) { 3453da14cebeSEric Cheng freemsgchain(mp_chain); 3454da14cebeSEric Cheng return (NULL); 3455da14cebeSEric Cheng } 3456da14cebeSEric Cheng } 3457da14cebeSEric Cheng 345825ec3e3dSEric Cheng /* 345925ec3e3dSEric Cheng * If mac protection is enabled, only the permissible packets will be 346025ec3e3dSEric Cheng * returned by mac_protect_check(). 346125ec3e3dSEric Cheng */ 346225ec3e3dSEric Cheng if ((mcip->mci_flent-> 346325ec3e3dSEric Cheng fe_resource_props.mrp_mask & MRP_PROTECT) != 0 && 346425ec3e3dSEric Cheng (mp_chain = mac_protect_check(mch, mp_chain)) == NULL) 346525ec3e3dSEric Cheng goto done; 346625ec3e3dSEric Cheng 3467da14cebeSEric Cheng if (mcip->mci_subflow_tab != NULL && 3468da14cebeSEric Cheng mcip->mci_subflow_tab->ft_flow_count > 0 && 3469da14cebeSEric Cheng mac_flow_lookup(mcip->mci_subflow_tab, mp_chain, 3470da14cebeSEric Cheng FLOW_OUTBOUND, &flent) == 0) { 3471da14cebeSEric Cheng /* 3472da14cebeSEric Cheng * The main assumption here is that if in the event 3473da14cebeSEric Cheng * we get a chain, all the packets will be classified 3474da14cebeSEric Cheng * to the same Flow/SRS. If this changes for any 3475da14cebeSEric Cheng * reason, the following logic should change as well. 3476da14cebeSEric Cheng * I suppose the fanout_hint also assumes this . 3477da14cebeSEric Cheng */ 3478da14cebeSEric Cheng ASSERT(flent != NULL); 3479da14cebeSEric Cheng is_subflow = B_TRUE; 3480da14cebeSEric Cheng } else { 3481da14cebeSEric Cheng flent = mcip->mci_flent; 3482da14cebeSEric Cheng } 3483da14cebeSEric Cheng 3484da14cebeSEric Cheng srs = flent->fe_tx_srs; 34850a0e9771SDarren Reed /* 34860a0e9771SDarren Reed * This is to avoid panics with PF_PACKET that can call mac_tx() 34870a0e9771SDarren Reed * against an interface that is not capable of sending. A rewrite 34880a0e9771SDarren Reed * of the mac datapath is required to remove this limitation. 34890a0e9771SDarren Reed */ 34900a0e9771SDarren Reed if (srs == NULL) { 34910a0e9771SDarren Reed freemsgchain(mp_chain); 349225ec3e3dSEric Cheng goto done; 34930a0e9771SDarren Reed } 349425ec3e3dSEric Cheng 3495da14cebeSEric Cheng srs_tx = &srs->srs_tx; 3496da14cebeSEric Cheng if (srs_tx->st_mode == SRS_TX_DEFAULT && 3497da14cebeSEric Cheng (srs->srs_state & SRS_ENQUEUED) == 0 && 34980dc2366fSVenugopal Iyer mip->mi_nactiveclients == 1 && mp_chain->b_next == NULL) { 3499da14cebeSEric Cheng uint64_t obytes; 3500da14cebeSEric Cheng 3501da14cebeSEric Cheng /* 3502da14cebeSEric Cheng * Since dls always opens the underlying MAC, nclients equals 3503da14cebeSEric Cheng * to 1 means that the only active client is dls itself acting 3504da14cebeSEric Cheng * as a primary client of the MAC instance. Since dls will not 3505da14cebeSEric Cheng * send tagged packets in that case, and dls is trusted to send 3506da14cebeSEric Cheng * packets for its allowed VLAN(s), the VLAN tag insertion and 3507da14cebeSEric Cheng * check is required only if nclients is greater than 1. 3508da14cebeSEric Cheng */ 3509da14cebeSEric Cheng if (mip->mi_nclients > 1) { 3510da14cebeSEric Cheng if (MAC_VID_CHECK_NEEDED(mcip)) { 3511da14cebeSEric Cheng int err = 0; 3512da14cebeSEric Cheng 3513da14cebeSEric Cheng MAC_VID_CHECK(mcip, mp_chain, err); 3514da14cebeSEric Cheng if (err != 0) { 3515da14cebeSEric Cheng freemsg(mp_chain); 35160dc2366fSVenugopal Iyer mcip->mci_misc_stat.mms_txerrors++; 3517da14cebeSEric Cheng goto done; 3518da14cebeSEric Cheng } 3519da14cebeSEric Cheng } 3520da14cebeSEric Cheng if (MAC_TAG_NEEDED(mcip)) { 3521da14cebeSEric Cheng mp_chain = mac_add_vlan_tag(mp_chain, 0, 3522da14cebeSEric Cheng mac_client_vid(mch)); 3523da14cebeSEric Cheng if (mp_chain == NULL) { 35240dc2366fSVenugopal Iyer mcip->mci_misc_stat.mms_txerrors++; 3525da14cebeSEric Cheng goto done; 3526da14cebeSEric Cheng } 3527da14cebeSEric Cheng } 3528da14cebeSEric Cheng } 3529da14cebeSEric Cheng 3530da14cebeSEric Cheng obytes = (mp_chain->b_cont == NULL ? MBLKL(mp_chain) : 3531da14cebeSEric Cheng msgdsize(mp_chain)); 3532da14cebeSEric Cheng 35330dc2366fSVenugopal Iyer MAC_TX(mip, srs_tx->st_arg2, mp_chain, mcip); 3534da14cebeSEric Cheng if (mp_chain == NULL) { 3535da14cebeSEric Cheng cookie = NULL; 35360dc2366fSVenugopal Iyer SRS_TX_STAT_UPDATE(srs, opackets, 1); 35370dc2366fSVenugopal Iyer SRS_TX_STAT_UPDATE(srs, obytes, obytes); 3538da14cebeSEric Cheng } else { 3539da14cebeSEric Cheng mutex_enter(&srs->srs_lock); 3540da14cebeSEric Cheng cookie = mac_tx_srs_no_desc(srs, mp_chain, 3541da14cebeSEric Cheng flag, ret_mp); 3542da14cebeSEric Cheng mutex_exit(&srs->srs_lock); 3543da14cebeSEric Cheng } 3544da14cebeSEric Cheng } else { 3545da14cebeSEric Cheng cookie = srs_tx->st_func(srs, mp_chain, hint, flag, ret_mp); 3546da14cebeSEric Cheng } 3547da14cebeSEric Cheng 3548da14cebeSEric Cheng done: 3549da14cebeSEric Cheng if (is_subflow) 3550da14cebeSEric Cheng FLOW_REFRELE(flent); 3551da14cebeSEric Cheng 3552da14cebeSEric Cheng if (!(flag & MAC_TX_NO_HOLD)) 3553da14cebeSEric Cheng MAC_TX_RELE(mcip, mytx); 3554da14cebeSEric Cheng 3555da14cebeSEric Cheng return (cookie); 3556da14cebeSEric Cheng } 3557da14cebeSEric Cheng 3558da14cebeSEric Cheng /* 3559da14cebeSEric Cheng * mac_tx_is_blocked 3560da14cebeSEric Cheng * 3561da14cebeSEric Cheng * Given a cookie, it returns if the ring identified by the cookie is 3562ae6aa22aSVenugopal Iyer * flow-controlled or not. If NULL is passed in place of a cookie, 3563ae6aa22aSVenugopal Iyer * then it finds out if any of the underlying rings belonging to the 3564ae6aa22aSVenugopal Iyer * SRS is flow controlled or not and returns that status. 3565da14cebeSEric Cheng */ 3566da14cebeSEric Cheng /* ARGSUSED */ 3567da14cebeSEric Cheng boolean_t 3568da14cebeSEric Cheng mac_tx_is_flow_blocked(mac_client_handle_t mch, mac_tx_cookie_t cookie) 3569da14cebeSEric Cheng { 3570da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3571ae6aa22aSVenugopal Iyer mac_soft_ring_set_t *mac_srs; 3572da14cebeSEric Cheng mac_soft_ring_t *sringp; 3573da14cebeSEric Cheng boolean_t blocked = B_FALSE; 3574ae6aa22aSVenugopal Iyer mac_tx_percpu_t *mytx; 3575ae6aa22aSVenugopal Iyer int err; 3576da14cebeSEric Cheng int i; 3577da14cebeSEric Cheng 3578da14cebeSEric Cheng /* 3579ae6aa22aSVenugopal Iyer * Bump the reference count so that mac_srs won't be deleted. 3580ae6aa22aSVenugopal Iyer * If the client is currently quiesced and we failed to bump 3581ae6aa22aSVenugopal Iyer * the reference, return B_TRUE so that flow control stays 3582ae6aa22aSVenugopal Iyer * as enabled. 3583ae6aa22aSVenugopal Iyer * 3584ae6aa22aSVenugopal Iyer * Flow control will then be disabled once the client is no 3585ae6aa22aSVenugopal Iyer * longer quiesced. 3586da14cebeSEric Cheng */ 3587ae6aa22aSVenugopal Iyer MAC_TX_TRY_HOLD(mcip, mytx, err); 3588ae6aa22aSVenugopal Iyer if (err != 0) 3589ae6aa22aSVenugopal Iyer return (B_TRUE); 3590ae6aa22aSVenugopal Iyer 3591ae6aa22aSVenugopal Iyer if ((mac_srs = MCIP_TX_SRS(mcip)) == NULL) { 3592ae6aa22aSVenugopal Iyer MAC_TX_RELE(mcip, mytx); 3593da14cebeSEric Cheng return (B_FALSE); 3594ae6aa22aSVenugopal Iyer } 3595da14cebeSEric Cheng 3596da14cebeSEric Cheng mutex_enter(&mac_srs->srs_lock); 35970dc2366fSVenugopal Iyer /* 35980dc2366fSVenugopal Iyer * Only in the case of TX_FANOUT and TX_AGGR, the underlying 35990dc2366fSVenugopal Iyer * softring (s_ring_state) will have the HIWAT set. This is 36000dc2366fSVenugopal Iyer * the multiple Tx ring flow control case. For all other 36010dc2366fSVenugopal Iyer * case, SRS (srs_state) will store the condition. 36020dc2366fSVenugopal Iyer */ 36030dc2366fSVenugopal Iyer if (mac_srs->srs_tx.st_mode == SRS_TX_FANOUT || 36040dc2366fSVenugopal Iyer mac_srs->srs_tx.st_mode == SRS_TX_AGGR) { 3605ae6aa22aSVenugopal Iyer if (cookie != NULL) { 3606ae6aa22aSVenugopal Iyer sringp = (mac_soft_ring_t *)cookie; 3607ae6aa22aSVenugopal Iyer mutex_enter(&sringp->s_ring_lock); 3608ae6aa22aSVenugopal Iyer if (sringp->s_ring_state & S_RING_TX_HIWAT) 3609ae6aa22aSVenugopal Iyer blocked = B_TRUE; 3610ae6aa22aSVenugopal Iyer mutex_exit(&sringp->s_ring_lock); 3611ae6aa22aSVenugopal Iyer } else { 36120dc2366fSVenugopal Iyer for (i = 0; i < mac_srs->srs_tx_ring_count; i++) { 36130dc2366fSVenugopal Iyer sringp = mac_srs->srs_tx_soft_rings[i]; 3614da14cebeSEric Cheng mutex_enter(&sringp->s_ring_lock); 3615da14cebeSEric Cheng if (sringp->s_ring_state & S_RING_TX_HIWAT) { 3616da14cebeSEric Cheng blocked = B_TRUE; 3617da14cebeSEric Cheng mutex_exit(&sringp->s_ring_lock); 3618da14cebeSEric Cheng break; 3619da14cebeSEric Cheng } 3620da14cebeSEric Cheng mutex_exit(&sringp->s_ring_lock); 3621da14cebeSEric Cheng } 3622ae6aa22aSVenugopal Iyer } 3623da14cebeSEric Cheng } else { 3624da14cebeSEric Cheng blocked = (mac_srs->srs_state & SRS_TX_HIWAT); 3625da14cebeSEric Cheng } 3626da14cebeSEric Cheng mutex_exit(&mac_srs->srs_lock); 3627ae6aa22aSVenugopal Iyer MAC_TX_RELE(mcip, mytx); 3628da14cebeSEric Cheng return (blocked); 3629da14cebeSEric Cheng } 3630da14cebeSEric Cheng 3631da14cebeSEric Cheng /* 3632da14cebeSEric Cheng * Check if the MAC client is the primary MAC client. 3633da14cebeSEric Cheng */ 3634da14cebeSEric Cheng boolean_t 3635da14cebeSEric Cheng mac_is_primary_client(mac_client_impl_t *mcip) 3636da14cebeSEric Cheng { 3637da14cebeSEric Cheng return (mcip->mci_flags & MAC_CLIENT_FLAGS_PRIMARY); 3638da14cebeSEric Cheng } 3639da14cebeSEric Cheng 3640da14cebeSEric Cheng void 3641da14cebeSEric Cheng mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp) 3642da14cebeSEric Cheng { 3643da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 3644da14cebeSEric Cheng int cmd = ((struct iocblk *)bp->b_rptr)->ioc_cmd; 3645da14cebeSEric Cheng 3646da14cebeSEric Cheng if ((cmd == ND_GET && (mip->mi_callbacks->mc_callbacks & MC_GETPROP)) || 3647da14cebeSEric Cheng (cmd == ND_SET && (mip->mi_callbacks->mc_callbacks & MC_SETPROP))) { 3648da14cebeSEric Cheng /* 3649da14cebeSEric Cheng * If ndd props were registered, call them. 3650da14cebeSEric Cheng * Note that ndd ioctls are Obsolete 3651da14cebeSEric Cheng */ 3652da14cebeSEric Cheng mac_ndd_ioctl(mip, wq, bp); 3653da14cebeSEric Cheng return; 3654da14cebeSEric Cheng } 3655da14cebeSEric Cheng 3656da14cebeSEric Cheng /* 3657da14cebeSEric Cheng * Call the driver to handle the ioctl. The driver may not support 3658da14cebeSEric Cheng * any ioctls, in which case we reply with a NAK on its behalf. 3659da14cebeSEric Cheng */ 3660da14cebeSEric Cheng if (mip->mi_callbacks->mc_callbacks & MC_IOCTL) 3661da14cebeSEric Cheng mip->mi_ioctl(mip->mi_driver, wq, bp); 3662da14cebeSEric Cheng else 3663da14cebeSEric Cheng miocnak(wq, bp, 0, EINVAL); 3664da14cebeSEric Cheng } 3665da14cebeSEric Cheng 3666da14cebeSEric Cheng /* 3667da14cebeSEric Cheng * Return the link state of the specified MAC instance. 3668da14cebeSEric Cheng */ 3669da14cebeSEric Cheng link_state_t 3670da14cebeSEric Cheng mac_link_get(mac_handle_t mh) 3671da14cebeSEric Cheng { 3672da14cebeSEric Cheng return (((mac_impl_t *)mh)->mi_linkstate); 3673da14cebeSEric Cheng } 3674da14cebeSEric Cheng 3675da14cebeSEric Cheng /* 3676da14cebeSEric Cheng * Add a mac client specified notification callback. Please see the comments 3677da14cebeSEric Cheng * above mac_callback_add() for general information about mac callback 3678da14cebeSEric Cheng * addition/deletion in the presence of mac callback list walkers 3679da14cebeSEric Cheng */ 3680da14cebeSEric Cheng mac_notify_handle_t 3681da14cebeSEric Cheng mac_notify_add(mac_handle_t mh, mac_notify_t notify_fn, void *arg) 3682da14cebeSEric Cheng { 3683da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 3684da14cebeSEric Cheng mac_notify_cb_t *mncb; 3685da14cebeSEric Cheng mac_cb_info_t *mcbi; 3686da14cebeSEric Cheng 3687da14cebeSEric Cheng /* 3688da14cebeSEric Cheng * Allocate a notify callback structure, fill in the details and 3689da14cebeSEric Cheng * use the mac callback list manipulation functions to chain into 3690da14cebeSEric Cheng * the list of callbacks. 3691da14cebeSEric Cheng */ 3692da14cebeSEric Cheng mncb = kmem_zalloc(sizeof (mac_notify_cb_t), KM_SLEEP); 3693da14cebeSEric Cheng mncb->mncb_fn = notify_fn; 3694da14cebeSEric Cheng mncb->mncb_arg = arg; 3695da14cebeSEric Cheng mncb->mncb_mip = mip; 3696da14cebeSEric Cheng mncb->mncb_link.mcb_objp = mncb; 3697da14cebeSEric Cheng mncb->mncb_link.mcb_objsize = sizeof (mac_notify_cb_t); 3698da14cebeSEric Cheng mncb->mncb_link.mcb_flags = MCB_NOTIFY_CB_T; 3699da14cebeSEric Cheng 3700da14cebeSEric Cheng mcbi = &mip->mi_notify_cb_info; 3701da14cebeSEric Cheng 3702da14cebeSEric Cheng i_mac_perim_enter(mip); 3703da14cebeSEric Cheng mutex_enter(mcbi->mcbi_lockp); 3704da14cebeSEric Cheng 3705da14cebeSEric Cheng mac_callback_add(&mip->mi_notify_cb_info, &mip->mi_notify_cb_list, 3706da14cebeSEric Cheng &mncb->mncb_link); 3707da14cebeSEric Cheng 3708da14cebeSEric Cheng mutex_exit(mcbi->mcbi_lockp); 3709da14cebeSEric Cheng i_mac_perim_exit(mip); 3710da14cebeSEric Cheng return ((mac_notify_handle_t)mncb); 3711da14cebeSEric Cheng } 3712da14cebeSEric Cheng 3713da14cebeSEric Cheng void 3714da14cebeSEric Cheng mac_notify_remove_wait(mac_handle_t mh) 3715da14cebeSEric Cheng { 3716da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 3717da14cebeSEric Cheng mac_cb_info_t *mcbi = &mip->mi_notify_cb_info; 3718da14cebeSEric Cheng 3719da14cebeSEric Cheng mutex_enter(mcbi->mcbi_lockp); 3720da14cebeSEric Cheng mac_callback_remove_wait(&mip->mi_notify_cb_info); 3721da14cebeSEric Cheng mutex_exit(mcbi->mcbi_lockp); 3722da14cebeSEric Cheng } 3723da14cebeSEric Cheng 3724da14cebeSEric Cheng /* 3725da14cebeSEric Cheng * Remove a mac client specified notification callback 3726da14cebeSEric Cheng */ 3727da14cebeSEric Cheng int 3728da14cebeSEric Cheng mac_notify_remove(mac_notify_handle_t mnh, boolean_t wait) 3729da14cebeSEric Cheng { 3730da14cebeSEric Cheng mac_notify_cb_t *mncb = (mac_notify_cb_t *)mnh; 3731da14cebeSEric Cheng mac_impl_t *mip = mncb->mncb_mip; 3732da14cebeSEric Cheng mac_cb_info_t *mcbi; 3733da14cebeSEric Cheng int err = 0; 3734da14cebeSEric Cheng 3735da14cebeSEric Cheng mcbi = &mip->mi_notify_cb_info; 3736da14cebeSEric Cheng 3737da14cebeSEric Cheng i_mac_perim_enter(mip); 3738da14cebeSEric Cheng mutex_enter(mcbi->mcbi_lockp); 3739da14cebeSEric Cheng 3740da14cebeSEric Cheng ASSERT(mncb->mncb_link.mcb_objp == mncb); 3741da14cebeSEric Cheng /* 3742da14cebeSEric Cheng * If there aren't any list walkers, the remove would succeed 3743da14cebeSEric Cheng * inline, else we wait for the deferred remove to complete 3744da14cebeSEric Cheng */ 3745da14cebeSEric Cheng if (mac_callback_remove(&mip->mi_notify_cb_info, 3746da14cebeSEric Cheng &mip->mi_notify_cb_list, &mncb->mncb_link)) { 3747da14cebeSEric Cheng kmem_free(mncb, sizeof (mac_notify_cb_t)); 3748da14cebeSEric Cheng } else { 3749da14cebeSEric Cheng err = EBUSY; 3750da14cebeSEric Cheng } 3751da14cebeSEric Cheng 3752da14cebeSEric Cheng mutex_exit(mcbi->mcbi_lockp); 3753da14cebeSEric Cheng i_mac_perim_exit(mip); 3754da14cebeSEric Cheng 3755da14cebeSEric Cheng /* 3756da14cebeSEric Cheng * If we failed to remove the notification callback and "wait" is set 3757da14cebeSEric Cheng * to be B_TRUE, wait for the callback to finish after we exit the 3758da14cebeSEric Cheng * mac perimeter. 3759da14cebeSEric Cheng */ 3760da14cebeSEric Cheng if (err != 0 && wait) { 3761da14cebeSEric Cheng mac_notify_remove_wait((mac_handle_t)mip); 3762da14cebeSEric Cheng return (0); 3763da14cebeSEric Cheng } 3764da14cebeSEric Cheng 3765da14cebeSEric Cheng return (err); 3766da14cebeSEric Cheng } 3767da14cebeSEric Cheng 3768da14cebeSEric Cheng /* 3769da14cebeSEric Cheng * Associate resource management callbacks with the specified MAC 3770da14cebeSEric Cheng * clients. 3771da14cebeSEric Cheng */ 3772da14cebeSEric Cheng 3773da14cebeSEric Cheng void 3774da14cebeSEric Cheng mac_resource_set_common(mac_client_handle_t mch, mac_resource_add_t add, 3775da14cebeSEric Cheng mac_resource_remove_t remove, mac_resource_quiesce_t quiesce, 3776da14cebeSEric Cheng mac_resource_restart_t restart, mac_resource_bind_t bind, 3777da14cebeSEric Cheng void *arg) 3778da14cebeSEric Cheng { 3779da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3780da14cebeSEric Cheng 3781da14cebeSEric Cheng mcip->mci_resource_add = add; 3782da14cebeSEric Cheng mcip->mci_resource_remove = remove; 3783da14cebeSEric Cheng mcip->mci_resource_quiesce = quiesce; 3784da14cebeSEric Cheng mcip->mci_resource_restart = restart; 3785da14cebeSEric Cheng mcip->mci_resource_bind = bind; 3786da14cebeSEric Cheng mcip->mci_resource_arg = arg; 3787da14cebeSEric Cheng } 3788da14cebeSEric Cheng 3789da14cebeSEric Cheng void 3790da14cebeSEric Cheng mac_resource_set(mac_client_handle_t mch, mac_resource_add_t add, void *arg) 3791da14cebeSEric Cheng { 3792da14cebeSEric Cheng /* update the 'resource_add' callback */ 3793da14cebeSEric Cheng mac_resource_set_common(mch, add, NULL, NULL, NULL, NULL, arg); 3794da14cebeSEric Cheng } 3795da14cebeSEric Cheng 3796da14cebeSEric Cheng /* 3797da14cebeSEric Cheng * Sets up the client resources and enable the polling interface over all the 3798da14cebeSEric Cheng * SRS's and the soft rings of the client 3799da14cebeSEric Cheng */ 3800da14cebeSEric Cheng void 3801da14cebeSEric Cheng mac_client_poll_enable(mac_client_handle_t mch) 3802da14cebeSEric Cheng { 3803da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3804da14cebeSEric Cheng mac_soft_ring_set_t *mac_srs; 3805da14cebeSEric Cheng flow_entry_t *flent; 3806da14cebeSEric Cheng int i; 3807da14cebeSEric Cheng 3808da14cebeSEric Cheng flent = mcip->mci_flent; 3809da14cebeSEric Cheng ASSERT(flent != NULL); 3810da14cebeSEric Cheng 38118d4cf8d8S mcip->mci_state_flags |= MCIS_CLIENT_POLL_CAPABLE; 3812da14cebeSEric Cheng for (i = 0; i < flent->fe_rx_srs_cnt; i++) { 3813da14cebeSEric Cheng mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i]; 3814da14cebeSEric Cheng ASSERT(mac_srs->srs_mcip == mcip); 3815da14cebeSEric Cheng mac_srs_client_poll_enable(mcip, mac_srs); 3816da14cebeSEric Cheng } 3817da14cebeSEric Cheng } 3818da14cebeSEric Cheng 3819da14cebeSEric Cheng /* 3820da14cebeSEric Cheng * Tears down the client resources and disable the polling interface over all 3821da14cebeSEric Cheng * the SRS's and the soft rings of the client 3822da14cebeSEric Cheng */ 3823da14cebeSEric Cheng void 3824da14cebeSEric Cheng mac_client_poll_disable(mac_client_handle_t mch) 3825da14cebeSEric Cheng { 3826da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3827da14cebeSEric Cheng mac_soft_ring_set_t *mac_srs; 3828da14cebeSEric Cheng flow_entry_t *flent; 3829da14cebeSEric Cheng int i; 3830da14cebeSEric Cheng 3831da14cebeSEric Cheng flent = mcip->mci_flent; 3832da14cebeSEric Cheng ASSERT(flent != NULL); 3833da14cebeSEric Cheng 38348d4cf8d8S mcip->mci_state_flags &= ~MCIS_CLIENT_POLL_CAPABLE; 3835da14cebeSEric Cheng for (i = 0; i < flent->fe_rx_srs_cnt; i++) { 3836da14cebeSEric Cheng mac_srs = (mac_soft_ring_set_t *)flent->fe_rx_srs[i]; 3837da14cebeSEric Cheng ASSERT(mac_srs->srs_mcip == mcip); 3838da14cebeSEric Cheng mac_srs_client_poll_disable(mcip, mac_srs); 3839da14cebeSEric Cheng } 3840da14cebeSEric Cheng } 3841da14cebeSEric Cheng 3842da14cebeSEric Cheng /* 3843da14cebeSEric Cheng * Associate the CPUs specified by the given property with a MAC client. 3844da14cebeSEric Cheng */ 3845da14cebeSEric Cheng int 3846da14cebeSEric Cheng mac_cpu_set(mac_client_handle_t mch, mac_resource_props_t *mrp) 3847da14cebeSEric Cheng { 3848da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3849da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip; 3850da14cebeSEric Cheng int err = 0; 3851da14cebeSEric Cheng 3852da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 3853da14cebeSEric Cheng 38540dc2366fSVenugopal Iyer if ((err = mac_validate_props(mcip->mci_state_flags & MCIS_IS_VNIC ? 38550dc2366fSVenugopal Iyer mcip->mci_upper_mip : mip, mrp)) != 0) { 3856da14cebeSEric Cheng return (err); 38570dc2366fSVenugopal Iyer } 3858da14cebeSEric Cheng if (MCIP_DATAPATH_SETUP(mcip)) 3859da14cebeSEric Cheng mac_flow_modify(mip->mi_flow_tab, mcip->mci_flent, mrp); 3860da14cebeSEric Cheng 3861da14cebeSEric Cheng mac_update_resources(mrp, MCIP_RESOURCE_PROPS(mcip), B_FALSE); 3862da14cebeSEric Cheng return (0); 3863da14cebeSEric Cheng } 3864da14cebeSEric Cheng 3865da14cebeSEric Cheng /* 3866da14cebeSEric Cheng * Apply the specified properties to the specified MAC client. 3867da14cebeSEric Cheng */ 3868da14cebeSEric Cheng int 3869da14cebeSEric Cheng mac_client_set_resources(mac_client_handle_t mch, mac_resource_props_t *mrp) 3870da14cebeSEric Cheng { 3871da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3872da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip; 3873da14cebeSEric Cheng int err = 0; 3874da14cebeSEric Cheng 3875da14cebeSEric Cheng i_mac_perim_enter(mip); 3876da14cebeSEric Cheng 3877da14cebeSEric Cheng if ((mrp->mrp_mask & MRP_MAXBW) || (mrp->mrp_mask & MRP_PRIORITY)) { 3878da14cebeSEric Cheng err = mac_resource_ctl_set(mch, mrp); 387925ec3e3dSEric Cheng if (err != 0) 388025ec3e3dSEric Cheng goto done; 3881da14cebeSEric Cheng } 3882da14cebeSEric Cheng 38830dc2366fSVenugopal Iyer if (mrp->mrp_mask & (MRP_CPUS|MRP_POOL)) { 3884da14cebeSEric Cheng err = mac_cpu_set(mch, mrp); 388525ec3e3dSEric Cheng if (err != 0) 388625ec3e3dSEric Cheng goto done; 388725ec3e3dSEric Cheng } 3888da14cebeSEric Cheng 38890dc2366fSVenugopal Iyer if (mrp->mrp_mask & MRP_PROTECT) { 389025ec3e3dSEric Cheng err = mac_protect_set(mch, mrp); 38910dc2366fSVenugopal Iyer if (err != 0) 38920dc2366fSVenugopal Iyer goto done; 38930dc2366fSVenugopal Iyer } 38940dc2366fSVenugopal Iyer 38950dc2366fSVenugopal Iyer if ((mrp->mrp_mask & MRP_RX_RINGS) || (mrp->mrp_mask & MRP_TX_RINGS)) 38960dc2366fSVenugopal Iyer err = mac_resource_ctl_set(mch, mrp); 389725ec3e3dSEric Cheng 389825ec3e3dSEric Cheng done: 3899da14cebeSEric Cheng i_mac_perim_exit(mip); 3900da14cebeSEric Cheng return (err); 3901da14cebeSEric Cheng } 3902da14cebeSEric Cheng 3903da14cebeSEric Cheng /* 3904da14cebeSEric Cheng * Return the properties currently associated with the specified MAC client. 3905da14cebeSEric Cheng */ 3906da14cebeSEric Cheng void 3907da14cebeSEric Cheng mac_client_get_resources(mac_client_handle_t mch, mac_resource_props_t *mrp) 3908da14cebeSEric Cheng { 3909da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 3910da14cebeSEric Cheng mac_resource_props_t *mcip_mrp = MCIP_RESOURCE_PROPS(mcip); 3911da14cebeSEric Cheng 3912da14cebeSEric Cheng bcopy(mcip_mrp, mrp, sizeof (mac_resource_props_t)); 3913da14cebeSEric Cheng } 3914da14cebeSEric Cheng 3915da14cebeSEric Cheng /* 39160dc2366fSVenugopal Iyer * Return the effective properties currently associated with the specified 39170dc2366fSVenugopal Iyer * MAC client. 39180dc2366fSVenugopal Iyer */ 39190dc2366fSVenugopal Iyer void 39200dc2366fSVenugopal Iyer mac_client_get_effective_resources(mac_client_handle_t mch, 39210dc2366fSVenugopal Iyer mac_resource_props_t *mrp) 39220dc2366fSVenugopal Iyer { 39230dc2366fSVenugopal Iyer mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 39240dc2366fSVenugopal Iyer mac_resource_props_t *mcip_mrp = MCIP_EFFECTIVE_PROPS(mcip); 39250dc2366fSVenugopal Iyer 39260dc2366fSVenugopal Iyer bcopy(mcip_mrp, mrp, sizeof (mac_resource_props_t)); 39270dc2366fSVenugopal Iyer } 39280dc2366fSVenugopal Iyer 39290dc2366fSVenugopal Iyer /* 3930da14cebeSEric Cheng * Pass a copy of the specified packet to the promiscuous callbacks 3931da14cebeSEric Cheng * of the specified MAC. 3932da14cebeSEric Cheng * 3933da14cebeSEric Cheng * If sender is NULL, the function is being invoked for a packet chain 3934da14cebeSEric Cheng * received from the wire. If sender is non-NULL, it points to 3935da14cebeSEric Cheng * the MAC client from which the packet is being sent. 3936da14cebeSEric Cheng * 3937da14cebeSEric Cheng * The packets are distributed to the promiscuous callbacks as follows: 3938da14cebeSEric Cheng * 3939da14cebeSEric Cheng * - all packets are sent to the MAC_CLIENT_PROMISC_ALL callbacks 3940da14cebeSEric Cheng * - all broadcast and multicast packets are sent to the 3941da14cebeSEric Cheng * MAC_CLIENT_PROMISC_FILTER and MAC_CLIENT_PROMISC_MULTI. 3942da14cebeSEric Cheng * 3943da14cebeSEric Cheng * The unicast packets of MAC_CLIENT_PROMISC_FILTER callbacks are dispatched 3944da14cebeSEric Cheng * after classification by mac_rx_deliver(). 3945da14cebeSEric Cheng */ 3946da14cebeSEric Cheng 3947da14cebeSEric Cheng static void 3948da14cebeSEric Cheng mac_promisc_dispatch_one(mac_promisc_impl_t *mpip, mblk_t *mp, 3949da14cebeSEric Cheng boolean_t loopback) 3950da14cebeSEric Cheng { 39510a0e9771SDarren Reed mblk_t *mp_copy, *mp_next; 3952da14cebeSEric Cheng 39530a0e9771SDarren Reed if (!mpip->mpi_no_copy || mpip->mpi_strip_vlan_tag) { 3954da14cebeSEric Cheng mp_copy = copymsg(mp); 3955da14cebeSEric Cheng if (mp_copy == NULL) 3956da14cebeSEric Cheng return; 3957da14cebeSEric Cheng 3958ae6aa22aSVenugopal Iyer if (mpip->mpi_strip_vlan_tag) { 39590a0e9771SDarren Reed mp_copy = mac_strip_vlan_tag_chain(mp_copy); 39600a0e9771SDarren Reed if (mp_copy == NULL) 3961ae6aa22aSVenugopal Iyer return; 3962ae6aa22aSVenugopal Iyer } 39630a0e9771SDarren Reed mp_next = NULL; 39640a0e9771SDarren Reed } else { 39650a0e9771SDarren Reed mp_copy = mp; 39660a0e9771SDarren Reed mp_next = mp->b_next; 39670a0e9771SDarren Reed } 39680a0e9771SDarren Reed mp_copy->b_next = NULL; 39690a0e9771SDarren Reed 3970da14cebeSEric Cheng mpip->mpi_fn(mpip->mpi_arg, NULL, mp_copy, loopback); 39710a0e9771SDarren Reed if (mp_copy == mp) 39720a0e9771SDarren Reed mp->b_next = mp_next; 3973da14cebeSEric Cheng } 3974da14cebeSEric Cheng 3975da14cebeSEric Cheng /* 3976da14cebeSEric Cheng * Return the VID of a packet. Zero if the packet is not tagged. 3977da14cebeSEric Cheng */ 3978da14cebeSEric Cheng static uint16_t 3979da14cebeSEric Cheng mac_ether_vid(mblk_t *mp) 3980da14cebeSEric Cheng { 3981da14cebeSEric Cheng struct ether_header *eth = (struct ether_header *)mp->b_rptr; 3982da14cebeSEric Cheng 3983da14cebeSEric Cheng if (ntohs(eth->ether_type) == ETHERTYPE_VLAN) { 3984da14cebeSEric Cheng struct ether_vlan_header *t_evhp = 3985da14cebeSEric Cheng (struct ether_vlan_header *)mp->b_rptr; 3986da14cebeSEric Cheng return (VLAN_ID(ntohs(t_evhp->ether_tci))); 3987da14cebeSEric Cheng } 3988da14cebeSEric Cheng 3989da14cebeSEric Cheng return (0); 3990da14cebeSEric Cheng } 3991da14cebeSEric Cheng 3992da14cebeSEric Cheng /* 3993da14cebeSEric Cheng * Return whether the specified packet contains a multicast or broadcast 3994da14cebeSEric Cheng * destination MAC address. 3995da14cebeSEric Cheng */ 3996da14cebeSEric Cheng static boolean_t 3997da14cebeSEric Cheng mac_is_mcast(mac_impl_t *mip, mblk_t *mp) 3998da14cebeSEric Cheng { 3999da14cebeSEric Cheng mac_header_info_t hdr_info; 4000da14cebeSEric Cheng 4001da14cebeSEric Cheng if (mac_header_info((mac_handle_t)mip, mp, &hdr_info) != 0) 4002da14cebeSEric Cheng return (B_FALSE); 4003da14cebeSEric Cheng return ((hdr_info.mhi_dsttype == MAC_ADDRTYPE_BROADCAST) || 4004da14cebeSEric Cheng (hdr_info.mhi_dsttype == MAC_ADDRTYPE_MULTICAST)); 4005da14cebeSEric Cheng } 4006da14cebeSEric Cheng 4007da14cebeSEric Cheng /* 4008da14cebeSEric Cheng * Send a copy of an mblk chain to the MAC clients of the specified MAC. 4009da14cebeSEric Cheng * "sender" points to the sender MAC client for outbound packets, and 4010da14cebeSEric Cheng * is set to NULL for inbound packets. 4011da14cebeSEric Cheng */ 4012da14cebeSEric Cheng void 4013da14cebeSEric Cheng mac_promisc_dispatch(mac_impl_t *mip, mblk_t *mp_chain, 4014da14cebeSEric Cheng mac_client_impl_t *sender) 4015da14cebeSEric Cheng { 4016da14cebeSEric Cheng mac_promisc_impl_t *mpip; 4017da14cebeSEric Cheng mac_cb_t *mcb; 4018da14cebeSEric Cheng mblk_t *mp; 4019da14cebeSEric Cheng boolean_t is_mcast, is_sender; 4020da14cebeSEric Cheng 4021da14cebeSEric Cheng MAC_PROMISC_WALKER_INC(mip); 4022da14cebeSEric Cheng for (mp = mp_chain; mp != NULL; mp = mp->b_next) { 4023da14cebeSEric Cheng is_mcast = mac_is_mcast(mip, mp); 4024da14cebeSEric Cheng /* send packet to interested callbacks */ 4025da14cebeSEric Cheng for (mcb = mip->mi_promisc_list; mcb != NULL; 4026da14cebeSEric Cheng mcb = mcb->mcb_nextp) { 4027da14cebeSEric Cheng mpip = (mac_promisc_impl_t *)mcb->mcb_objp; 4028da14cebeSEric Cheng is_sender = (mpip->mpi_mcip == sender); 4029da14cebeSEric Cheng 4030da14cebeSEric Cheng if (is_sender && mpip->mpi_no_tx_loop) 4031da14cebeSEric Cheng /* 4032da14cebeSEric Cheng * The sender doesn't want to receive 4033da14cebeSEric Cheng * copies of the packets it sends. 4034da14cebeSEric Cheng */ 4035da14cebeSEric Cheng continue; 4036da14cebeSEric Cheng 40374eaa4710SRishi Srivatsavai /* this client doesn't need any packets (bridge) */ 40384eaa4710SRishi Srivatsavai if (mpip->mpi_fn == NULL) 40394eaa4710SRishi Srivatsavai continue; 40404eaa4710SRishi Srivatsavai 4041da14cebeSEric Cheng /* 4042da14cebeSEric Cheng * For an ethernet MAC, don't displatch a multicast 4043da14cebeSEric Cheng * packet to a non-PROMISC_ALL callbacks unless the VID 4044da14cebeSEric Cheng * of the packet matches the VID of the client. 4045da14cebeSEric Cheng */ 4046da14cebeSEric Cheng if (is_mcast && 4047da14cebeSEric Cheng mpip->mpi_type != MAC_CLIENT_PROMISC_ALL && 4048da14cebeSEric Cheng !mac_client_check_flow_vid(mpip->mpi_mcip, 4049da14cebeSEric Cheng mac_ether_vid(mp))) 4050da14cebeSEric Cheng continue; 4051da14cebeSEric Cheng 4052da14cebeSEric Cheng if (is_sender || 4053da14cebeSEric Cheng mpip->mpi_type == MAC_CLIENT_PROMISC_ALL || 4054da14cebeSEric Cheng is_mcast) 4055da14cebeSEric Cheng mac_promisc_dispatch_one(mpip, mp, is_sender); 4056da14cebeSEric Cheng } 4057da14cebeSEric Cheng } 4058da14cebeSEric Cheng MAC_PROMISC_WALKER_DCR(mip); 4059da14cebeSEric Cheng } 4060da14cebeSEric Cheng 4061da14cebeSEric Cheng void 4062da14cebeSEric Cheng mac_promisc_client_dispatch(mac_client_impl_t *mcip, mblk_t *mp_chain) 4063da14cebeSEric Cheng { 4064da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip; 4065da14cebeSEric Cheng mac_promisc_impl_t *mpip; 4066da14cebeSEric Cheng boolean_t is_mcast; 4067da14cebeSEric Cheng mblk_t *mp; 4068da14cebeSEric Cheng mac_cb_t *mcb; 4069da14cebeSEric Cheng 4070da14cebeSEric Cheng /* 4071da14cebeSEric Cheng * The unicast packets for the MAC client still 4072da14cebeSEric Cheng * need to be delivered to the MAC_CLIENT_PROMISC_FILTERED 4073da14cebeSEric Cheng * promiscuous callbacks. The broadcast and multicast 4074da14cebeSEric Cheng * packets were delivered from mac_rx(). 4075da14cebeSEric Cheng */ 4076da14cebeSEric Cheng MAC_PROMISC_WALKER_INC(mip); 4077da14cebeSEric Cheng for (mp = mp_chain; mp != NULL; mp = mp->b_next) { 4078da14cebeSEric Cheng is_mcast = mac_is_mcast(mip, mp); 4079da14cebeSEric Cheng for (mcb = mcip->mci_promisc_list; mcb != NULL; 4080da14cebeSEric Cheng mcb = mcb->mcb_nextp) { 4081da14cebeSEric Cheng mpip = (mac_promisc_impl_t *)mcb->mcb_objp; 4082da14cebeSEric Cheng if (mpip->mpi_type == MAC_CLIENT_PROMISC_FILTERED && 4083da14cebeSEric Cheng !is_mcast) { 4084da14cebeSEric Cheng mac_promisc_dispatch_one(mpip, mp, B_FALSE); 4085da14cebeSEric Cheng } 4086da14cebeSEric Cheng } 4087da14cebeSEric Cheng } 4088da14cebeSEric Cheng MAC_PROMISC_WALKER_DCR(mip); 4089da14cebeSEric Cheng } 4090da14cebeSEric Cheng 4091da14cebeSEric Cheng /* 4092da14cebeSEric Cheng * Return the margin value currently assigned to the specified MAC instance. 4093da14cebeSEric Cheng */ 4094da14cebeSEric Cheng void 4095da14cebeSEric Cheng mac_margin_get(mac_handle_t mh, uint32_t *marginp) 4096da14cebeSEric Cheng { 4097da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 4098da14cebeSEric Cheng 4099da14cebeSEric Cheng rw_enter(&(mip->mi_rw_lock), RW_READER); 4100da14cebeSEric Cheng *marginp = mip->mi_margin; 4101da14cebeSEric Cheng rw_exit(&(mip->mi_rw_lock)); 4102da14cebeSEric Cheng } 4103da14cebeSEric Cheng 4104da14cebeSEric Cheng /* 4105da14cebeSEric Cheng * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is 4106da14cebeSEric Cheng * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find 4107da14cebeSEric Cheng * the first mac_impl_t with a matching driver name; then we copy its mac_info_t 4108da14cebeSEric Cheng * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t 4109da14cebeSEric Cheng * cannot disappear while we are accessing it. 4110da14cebeSEric Cheng */ 4111da14cebeSEric Cheng typedef struct i_mac_info_state_s { 4112da14cebeSEric Cheng const char *mi_name; 4113da14cebeSEric Cheng mac_info_t *mi_infop; 4114da14cebeSEric Cheng } i_mac_info_state_t; 4115da14cebeSEric Cheng 4116da14cebeSEric Cheng /*ARGSUSED*/ 4117da14cebeSEric Cheng static uint_t 4118da14cebeSEric Cheng i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 4119da14cebeSEric Cheng { 4120da14cebeSEric Cheng i_mac_info_state_t *statep = arg; 4121da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)val; 4122da14cebeSEric Cheng 4123da14cebeSEric Cheng if (mip->mi_state_flags & MIS_DISABLED) 4124da14cebeSEric Cheng return (MH_WALK_CONTINUE); 4125da14cebeSEric Cheng 4126da14cebeSEric Cheng if (strcmp(statep->mi_name, 4127da14cebeSEric Cheng ddi_driver_name(mip->mi_dip)) != 0) 4128da14cebeSEric Cheng return (MH_WALK_CONTINUE); 4129da14cebeSEric Cheng 4130da14cebeSEric Cheng statep->mi_infop = &mip->mi_info; 4131da14cebeSEric Cheng return (MH_WALK_TERMINATE); 4132da14cebeSEric Cheng } 4133da14cebeSEric Cheng 4134da14cebeSEric Cheng boolean_t 4135da14cebeSEric Cheng mac_info_get(const char *name, mac_info_t *minfop) 4136da14cebeSEric Cheng { 4137da14cebeSEric Cheng i_mac_info_state_t state; 4138da14cebeSEric Cheng 4139da14cebeSEric Cheng rw_enter(&i_mac_impl_lock, RW_READER); 4140da14cebeSEric Cheng state.mi_name = name; 4141da14cebeSEric Cheng state.mi_infop = NULL; 4142da14cebeSEric Cheng mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state); 4143da14cebeSEric Cheng if (state.mi_infop == NULL) { 4144da14cebeSEric Cheng rw_exit(&i_mac_impl_lock); 4145da14cebeSEric Cheng return (B_FALSE); 4146da14cebeSEric Cheng } 4147da14cebeSEric Cheng *minfop = *state.mi_infop; 4148da14cebeSEric Cheng rw_exit(&i_mac_impl_lock); 4149da14cebeSEric Cheng return (B_TRUE); 4150da14cebeSEric Cheng } 4151da14cebeSEric Cheng 4152da14cebeSEric Cheng /* 4153da14cebeSEric Cheng * To get the capabilities that MAC layer cares about, such as rings, factory 41544eaa4710SRishi Srivatsavai * mac address, vnic or not, it should directly invoke this function. If the 41554eaa4710SRishi Srivatsavai * link is part of a bridge, then the only "capability" it has is the inability 41564eaa4710SRishi Srivatsavai * to do zero copy. 4157da14cebeSEric Cheng */ 4158da14cebeSEric Cheng boolean_t 4159da14cebeSEric Cheng i_mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data) 4160da14cebeSEric Cheng { 4161da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 4162da14cebeSEric Cheng 41634eaa4710SRishi Srivatsavai if (mip->mi_bridge_link != NULL) 41644eaa4710SRishi Srivatsavai return (cap == MAC_CAPAB_NO_ZCOPY); 41654eaa4710SRishi Srivatsavai else if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB) 4166da14cebeSEric Cheng return (mip->mi_getcapab(mip->mi_driver, cap, cap_data)); 4167da14cebeSEric Cheng else 4168da14cebeSEric Cheng return (B_FALSE); 4169da14cebeSEric Cheng } 4170da14cebeSEric Cheng 4171da14cebeSEric Cheng /* 4172da14cebeSEric Cheng * Capability query function. If number of active mac clients is greater than 4173da14cebeSEric Cheng * 1, only limited capabilities can be advertised to the caller no matter the 4174da14cebeSEric Cheng * driver has certain capability or not. Else, we query the driver to get the 4175da14cebeSEric Cheng * capability. 4176da14cebeSEric Cheng */ 4177da14cebeSEric Cheng boolean_t 4178da14cebeSEric Cheng mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data) 4179da14cebeSEric Cheng { 4180da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 4181da14cebeSEric Cheng 4182da14cebeSEric Cheng /* 41835d460eafSCathy Zhou * if mi_nactiveclients > 1, only MAC_CAPAB_LEGACY, MAC_CAPAB_HCKSUM, 41845d460eafSCathy Zhou * MAC_CAPAB_NO_NATIVEVLAN and MAC_CAPAB_NO_ZCOPY can be advertised. 4185da14cebeSEric Cheng */ 4186da14cebeSEric Cheng if (mip->mi_nactiveclients > 1) { 4187da14cebeSEric Cheng switch (cap) { 4188da14cebeSEric Cheng case MAC_CAPAB_NO_ZCOPY: 4189da14cebeSEric Cheng return (B_TRUE); 41905d460eafSCathy Zhou case MAC_CAPAB_LEGACY: 41915d460eafSCathy Zhou case MAC_CAPAB_HCKSUM: 41929056fcebSCathy Zhou case MAC_CAPAB_NO_NATIVEVLAN: 41935d460eafSCathy Zhou break; 4194da14cebeSEric Cheng default: 4195da14cebeSEric Cheng return (B_FALSE); 4196da14cebeSEric Cheng } 4197da14cebeSEric Cheng } 4198da14cebeSEric Cheng 4199da14cebeSEric Cheng /* else get capab from driver */ 4200da14cebeSEric Cheng return (i_mac_capab_get(mh, cap, cap_data)); 4201da14cebeSEric Cheng } 4202da14cebeSEric Cheng 4203da14cebeSEric Cheng boolean_t 4204da14cebeSEric Cheng mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap) 4205da14cebeSEric Cheng { 4206da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 4207da14cebeSEric Cheng 4208da14cebeSEric Cheng return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap, 4209da14cebeSEric Cheng mip->mi_pdata)); 4210da14cebeSEric Cheng } 4211da14cebeSEric Cheng 4212da14cebeSEric Cheng mblk_t * 4213da14cebeSEric Cheng mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload, 4214da14cebeSEric Cheng size_t extra_len) 4215da14cebeSEric Cheng { 4216da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 42172b24ab6bSSebastien Roy const uint8_t *hdr_daddr; 4218da14cebeSEric Cheng 42192b24ab6bSSebastien Roy /* 42202b24ab6bSSebastien Roy * If the MAC is point-to-point with a fixed destination address, then 42212b24ab6bSSebastien Roy * we must always use that destination in the MAC header. 42222b24ab6bSSebastien Roy */ 42232b24ab6bSSebastien Roy hdr_daddr = (mip->mi_dstaddr_set ? mip->mi_dstaddr : daddr); 42242b24ab6bSSebastien Roy return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, hdr_daddr, sap, 4225da14cebeSEric Cheng mip->mi_pdata, payload, extra_len)); 4226da14cebeSEric Cheng } 4227da14cebeSEric Cheng 4228da14cebeSEric Cheng int 4229da14cebeSEric Cheng mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip) 4230da14cebeSEric Cheng { 4231da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 4232da14cebeSEric Cheng 4233da14cebeSEric Cheng return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata, 4234da14cebeSEric Cheng mhip)); 4235da14cebeSEric Cheng } 4236da14cebeSEric Cheng 423725ec3e3dSEric Cheng int 423825ec3e3dSEric Cheng mac_vlan_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip) 423925ec3e3dSEric Cheng { 424025ec3e3dSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 424125ec3e3dSEric Cheng boolean_t is_ethernet = (mip->mi_info.mi_media == DL_ETHER); 424225ec3e3dSEric Cheng int err = 0; 424325ec3e3dSEric Cheng 424425ec3e3dSEric Cheng /* 424525ec3e3dSEric Cheng * Packets should always be at least 16 bit aligned. 424625ec3e3dSEric Cheng */ 424725ec3e3dSEric Cheng ASSERT(IS_P2ALIGNED(mp->b_rptr, sizeof (uint16_t))); 424825ec3e3dSEric Cheng 424925ec3e3dSEric Cheng if ((err = mac_header_info(mh, mp, mhip)) != 0) 425025ec3e3dSEric Cheng return (err); 425125ec3e3dSEric Cheng 425225ec3e3dSEric Cheng /* 425325ec3e3dSEric Cheng * If this is a VLAN-tagged Ethernet packet, then the SAP in the 425425ec3e3dSEric Cheng * mac_header_info_t as returned by mac_header_info() is 425525ec3e3dSEric Cheng * ETHERTYPE_VLAN. We need to grab the ethertype from the VLAN header. 425625ec3e3dSEric Cheng */ 425725ec3e3dSEric Cheng if (is_ethernet && (mhip->mhi_bindsap == ETHERTYPE_VLAN)) { 425825ec3e3dSEric Cheng struct ether_vlan_header *evhp; 425925ec3e3dSEric Cheng uint16_t sap; 426025ec3e3dSEric Cheng mblk_t *tmp = NULL; 426125ec3e3dSEric Cheng size_t size; 426225ec3e3dSEric Cheng 426325ec3e3dSEric Cheng size = sizeof (struct ether_vlan_header); 426425ec3e3dSEric Cheng if (MBLKL(mp) < size) { 426525ec3e3dSEric Cheng /* 426625ec3e3dSEric Cheng * Pullup the message in order to get the MAC header 426725ec3e3dSEric Cheng * infomation. Note that this is a read-only function, 426825ec3e3dSEric Cheng * we keep the input packet intact. 426925ec3e3dSEric Cheng */ 427025ec3e3dSEric Cheng if ((tmp = msgpullup(mp, size)) == NULL) 427125ec3e3dSEric Cheng return (EINVAL); 427225ec3e3dSEric Cheng 427325ec3e3dSEric Cheng mp = tmp; 427425ec3e3dSEric Cheng } 427525ec3e3dSEric Cheng evhp = (struct ether_vlan_header *)mp->b_rptr; 427625ec3e3dSEric Cheng sap = ntohs(evhp->ether_type); 427725ec3e3dSEric Cheng (void) mac_sap_verify(mh, sap, &mhip->mhi_bindsap); 427825ec3e3dSEric Cheng mhip->mhi_hdrsize = sizeof (struct ether_vlan_header); 427925ec3e3dSEric Cheng mhip->mhi_tci = ntohs(evhp->ether_tci); 428025ec3e3dSEric Cheng mhip->mhi_istagged = B_TRUE; 428125ec3e3dSEric Cheng freemsg(tmp); 428225ec3e3dSEric Cheng 428325ec3e3dSEric Cheng if (VLAN_CFI(mhip->mhi_tci) != ETHER_CFI) 428425ec3e3dSEric Cheng return (EINVAL); 428525ec3e3dSEric Cheng } else { 428625ec3e3dSEric Cheng mhip->mhi_istagged = B_FALSE; 428725ec3e3dSEric Cheng mhip->mhi_tci = 0; 428825ec3e3dSEric Cheng } 428925ec3e3dSEric Cheng 429025ec3e3dSEric Cheng return (0); 429125ec3e3dSEric Cheng } 429225ec3e3dSEric Cheng 4293da14cebeSEric Cheng mblk_t * 4294da14cebeSEric Cheng mac_header_cook(mac_handle_t mh, mblk_t *mp) 4295da14cebeSEric Cheng { 4296da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 4297da14cebeSEric Cheng 4298da14cebeSEric Cheng if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) { 4299da14cebeSEric Cheng if (DB_REF(mp) > 1) { 4300da14cebeSEric Cheng mblk_t *newmp = copymsg(mp); 4301da14cebeSEric Cheng if (newmp == NULL) 4302da14cebeSEric Cheng return (NULL); 4303da14cebeSEric Cheng freemsg(mp); 4304da14cebeSEric Cheng mp = newmp; 4305da14cebeSEric Cheng } 4306da14cebeSEric Cheng return (mip->mi_type->mt_ops.mtops_header_cook(mp, 4307da14cebeSEric Cheng mip->mi_pdata)); 4308da14cebeSEric Cheng } 4309da14cebeSEric Cheng return (mp); 4310da14cebeSEric Cheng } 4311da14cebeSEric Cheng 4312da14cebeSEric Cheng mblk_t * 4313da14cebeSEric Cheng mac_header_uncook(mac_handle_t mh, mblk_t *mp) 4314da14cebeSEric Cheng { 4315da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 4316da14cebeSEric Cheng 4317da14cebeSEric Cheng if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) { 4318da14cebeSEric Cheng if (DB_REF(mp) > 1) { 4319da14cebeSEric Cheng mblk_t *newmp = copymsg(mp); 4320da14cebeSEric Cheng if (newmp == NULL) 4321da14cebeSEric Cheng return (NULL); 4322da14cebeSEric Cheng freemsg(mp); 4323da14cebeSEric Cheng mp = newmp; 4324da14cebeSEric Cheng } 4325da14cebeSEric Cheng return (mip->mi_type->mt_ops.mtops_header_uncook(mp, 4326da14cebeSEric Cheng mip->mi_pdata)); 4327da14cebeSEric Cheng } 4328da14cebeSEric Cheng return (mp); 4329da14cebeSEric Cheng } 4330da14cebeSEric Cheng 4331da14cebeSEric Cheng uint_t 4332da14cebeSEric Cheng mac_addr_len(mac_handle_t mh) 4333da14cebeSEric Cheng { 4334da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 4335da14cebeSEric Cheng 4336da14cebeSEric Cheng return (mip->mi_type->mt_addr_length); 4337da14cebeSEric Cheng } 4338da14cebeSEric Cheng 4339da14cebeSEric Cheng /* True if a MAC is a VNIC */ 4340da14cebeSEric Cheng boolean_t 4341da14cebeSEric Cheng mac_is_vnic(mac_handle_t mh) 4342da14cebeSEric Cheng { 4343da14cebeSEric Cheng return (((mac_impl_t *)mh)->mi_state_flags & MIS_IS_VNIC); 4344da14cebeSEric Cheng } 4345da14cebeSEric Cheng 4346da14cebeSEric Cheng mac_handle_t 4347da14cebeSEric Cheng mac_get_lower_mac_handle(mac_handle_t mh) 4348da14cebeSEric Cheng { 4349da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 4350da14cebeSEric Cheng 4351da14cebeSEric Cheng ASSERT(mac_is_vnic(mh)); 4352da14cebeSEric Cheng return (((vnic_t *)mip->mi_driver)->vn_lower_mh); 4353da14cebeSEric Cheng } 4354da14cebeSEric Cheng 43550dc2366fSVenugopal Iyer boolean_t 43560dc2366fSVenugopal Iyer mac_is_vnic_primary(mac_handle_t mh) 43570dc2366fSVenugopal Iyer { 43580dc2366fSVenugopal Iyer mac_impl_t *mip = (mac_impl_t *)mh; 43590dc2366fSVenugopal Iyer 43600dc2366fSVenugopal Iyer ASSERT(mac_is_vnic(mh)); 43610dc2366fSVenugopal Iyer return (((vnic_t *)mip->mi_driver)->vn_addr_type == 43620dc2366fSVenugopal Iyer VNIC_MAC_ADDR_TYPE_PRIMARY); 43630dc2366fSVenugopal Iyer } 43640dc2366fSVenugopal Iyer 4365da14cebeSEric Cheng void 4366da14cebeSEric Cheng mac_update_resources(mac_resource_props_t *nmrp, mac_resource_props_t *cmrp, 4367da14cebeSEric Cheng boolean_t is_user_flow) 4368da14cebeSEric Cheng { 4369da14cebeSEric Cheng if (nmrp != NULL && cmrp != NULL) { 4370da14cebeSEric Cheng if (nmrp->mrp_mask & MRP_PRIORITY) { 4371da14cebeSEric Cheng if (nmrp->mrp_priority == MPL_RESET) { 4372da14cebeSEric Cheng cmrp->mrp_mask &= ~MRP_PRIORITY; 4373da14cebeSEric Cheng if (is_user_flow) { 4374da14cebeSEric Cheng cmrp->mrp_priority = 4375da14cebeSEric Cheng MPL_SUBFLOW_DEFAULT; 4376da14cebeSEric Cheng } else { 4377da14cebeSEric Cheng cmrp->mrp_priority = MPL_LINK_DEFAULT; 4378da14cebeSEric Cheng } 4379da14cebeSEric Cheng } else { 4380da14cebeSEric Cheng cmrp->mrp_mask |= MRP_PRIORITY; 4381da14cebeSEric Cheng cmrp->mrp_priority = nmrp->mrp_priority; 4382da14cebeSEric Cheng } 4383da14cebeSEric Cheng } 4384da14cebeSEric Cheng if (nmrp->mrp_mask & MRP_MAXBW) { 43850dc2366fSVenugopal Iyer if (nmrp->mrp_maxbw == MRP_MAXBW_RESETVAL) { 4386da14cebeSEric Cheng cmrp->mrp_mask &= ~MRP_MAXBW; 43870dc2366fSVenugopal Iyer cmrp->mrp_maxbw = 0; 43880dc2366fSVenugopal Iyer } else { 4389da14cebeSEric Cheng cmrp->mrp_mask |= MRP_MAXBW; 43900dc2366fSVenugopal Iyer cmrp->mrp_maxbw = nmrp->mrp_maxbw; 43910dc2366fSVenugopal Iyer } 4392da14cebeSEric Cheng } 4393da14cebeSEric Cheng if (nmrp->mrp_mask & MRP_CPUS) 4394da14cebeSEric Cheng MAC_COPY_CPUS(nmrp, cmrp); 439525ec3e3dSEric Cheng 43960dc2366fSVenugopal Iyer if (nmrp->mrp_mask & MRP_POOL) { 43970dc2366fSVenugopal Iyer if (strlen(nmrp->mrp_pool) == 0) { 43980dc2366fSVenugopal Iyer cmrp->mrp_mask &= ~MRP_POOL; 43990dc2366fSVenugopal Iyer bzero(cmrp->mrp_pool, sizeof (cmrp->mrp_pool)); 44000dc2366fSVenugopal Iyer } else { 44010dc2366fSVenugopal Iyer cmrp->mrp_mask |= MRP_POOL; 44020dc2366fSVenugopal Iyer (void) strncpy(cmrp->mrp_pool, nmrp->mrp_pool, 44030dc2366fSVenugopal Iyer sizeof (cmrp->mrp_pool)); 44040dc2366fSVenugopal Iyer } 44050dc2366fSVenugopal Iyer 44060dc2366fSVenugopal Iyer } 44070dc2366fSVenugopal Iyer 440825ec3e3dSEric Cheng if (nmrp->mrp_mask & MRP_PROTECT) 440925ec3e3dSEric Cheng mac_protect_update(nmrp, cmrp); 44100dc2366fSVenugopal Iyer 44110dc2366fSVenugopal Iyer /* 44120dc2366fSVenugopal Iyer * Update the rings specified. 44130dc2366fSVenugopal Iyer */ 44140dc2366fSVenugopal Iyer if (nmrp->mrp_mask & MRP_RX_RINGS) { 44150dc2366fSVenugopal Iyer if (nmrp->mrp_mask & MRP_RINGS_RESET) { 44160dc2366fSVenugopal Iyer cmrp->mrp_mask &= ~MRP_RX_RINGS; 44170dc2366fSVenugopal Iyer if (cmrp->mrp_mask & MRP_RXRINGS_UNSPEC) 44180dc2366fSVenugopal Iyer cmrp->mrp_mask &= ~MRP_RXRINGS_UNSPEC; 44190dc2366fSVenugopal Iyer cmrp->mrp_nrxrings = 0; 44200dc2366fSVenugopal Iyer } else { 44210dc2366fSVenugopal Iyer cmrp->mrp_mask |= MRP_RX_RINGS; 44220dc2366fSVenugopal Iyer cmrp->mrp_nrxrings = nmrp->mrp_nrxrings; 44230dc2366fSVenugopal Iyer } 44240dc2366fSVenugopal Iyer } 44250dc2366fSVenugopal Iyer if (nmrp->mrp_mask & MRP_TX_RINGS) { 44260dc2366fSVenugopal Iyer if (nmrp->mrp_mask & MRP_RINGS_RESET) { 44270dc2366fSVenugopal Iyer cmrp->mrp_mask &= ~MRP_TX_RINGS; 44280dc2366fSVenugopal Iyer if (cmrp->mrp_mask & MRP_TXRINGS_UNSPEC) 44290dc2366fSVenugopal Iyer cmrp->mrp_mask &= ~MRP_TXRINGS_UNSPEC; 44300dc2366fSVenugopal Iyer cmrp->mrp_ntxrings = 0; 44310dc2366fSVenugopal Iyer } else { 44320dc2366fSVenugopal Iyer cmrp->mrp_mask |= MRP_TX_RINGS; 44330dc2366fSVenugopal Iyer cmrp->mrp_ntxrings = nmrp->mrp_ntxrings; 44340dc2366fSVenugopal Iyer } 44350dc2366fSVenugopal Iyer } 44360dc2366fSVenugopal Iyer if (nmrp->mrp_mask & MRP_RXRINGS_UNSPEC) 44370dc2366fSVenugopal Iyer cmrp->mrp_mask |= MRP_RXRINGS_UNSPEC; 44380dc2366fSVenugopal Iyer else if (cmrp->mrp_mask & MRP_RXRINGS_UNSPEC) 44390dc2366fSVenugopal Iyer cmrp->mrp_mask &= ~MRP_RXRINGS_UNSPEC; 44400dc2366fSVenugopal Iyer 44410dc2366fSVenugopal Iyer if (nmrp->mrp_mask & MRP_TXRINGS_UNSPEC) 44420dc2366fSVenugopal Iyer cmrp->mrp_mask |= MRP_TXRINGS_UNSPEC; 44430dc2366fSVenugopal Iyer else if (cmrp->mrp_mask & MRP_TXRINGS_UNSPEC) 44440dc2366fSVenugopal Iyer cmrp->mrp_mask &= ~MRP_TXRINGS_UNSPEC; 4445da14cebeSEric Cheng } 4446da14cebeSEric Cheng } 4447da14cebeSEric Cheng 4448da14cebeSEric Cheng /* 4449da14cebeSEric Cheng * i_mac_set_resources: 4450da14cebeSEric Cheng * 4451da14cebeSEric Cheng * This routine associates properties with the primary MAC client of 4452da14cebeSEric Cheng * the specified MAC instance. 4453da14cebeSEric Cheng * - Cache the properties in mac_impl_t 4454da14cebeSEric Cheng * - Apply the properties to the primary MAC client if exists 4455da14cebeSEric Cheng */ 4456da14cebeSEric Cheng int 4457da14cebeSEric Cheng i_mac_set_resources(mac_handle_t mh, mac_resource_props_t *mrp) 4458da14cebeSEric Cheng { 4459da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 4460da14cebeSEric Cheng mac_client_impl_t *mcip; 4461da14cebeSEric Cheng int err = 0; 44625d460eafSCathy Zhou uint32_t resmask, newresmask; 44630dc2366fSVenugopal Iyer mac_resource_props_t *tmrp, *umrp; 4464da14cebeSEric Cheng 4465da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 4466da14cebeSEric Cheng 44670dc2366fSVenugopal Iyer err = mac_validate_props(mip, mrp); 4468da14cebeSEric Cheng if (err != 0) 4469da14cebeSEric Cheng return (err); 4470da14cebeSEric Cheng 44710dc2366fSVenugopal Iyer umrp = kmem_zalloc(sizeof (*umrp), KM_SLEEP); 44720dc2366fSVenugopal Iyer bcopy(&mip->mi_resource_props, umrp, sizeof (*umrp)); 44730dc2366fSVenugopal Iyer resmask = umrp->mrp_mask; 44740dc2366fSVenugopal Iyer mac_update_resources(mrp, umrp, B_FALSE); 44750dc2366fSVenugopal Iyer newresmask = umrp->mrp_mask; 44765d460eafSCathy Zhou 44775d460eafSCathy Zhou if (resmask == 0 && newresmask != 0) { 44785d460eafSCathy Zhou /* 44790dc2366fSVenugopal Iyer * Bandwidth, priority, cpu or pool link properties configured, 44805d460eafSCathy Zhou * must disable fastpath. 44815d460eafSCathy Zhou */ 44820dc2366fSVenugopal Iyer if ((err = mac_fastpath_disable((mac_handle_t)mip)) != 0) { 44830dc2366fSVenugopal Iyer kmem_free(umrp, sizeof (*umrp)); 44845d460eafSCathy Zhou return (err); 44855d460eafSCathy Zhou } 44860dc2366fSVenugopal Iyer } 44875d460eafSCathy Zhou 4488da14cebeSEric Cheng /* 4489da14cebeSEric Cheng * Since bind_cpu may be modified by mac_client_set_resources() 4490da14cebeSEric Cheng * we use a copy of bind_cpu and finally cache bind_cpu in mip. 4491da14cebeSEric Cheng * This allows us to cache only user edits in mip. 4492da14cebeSEric Cheng */ 44930dc2366fSVenugopal Iyer tmrp = kmem_zalloc(sizeof (*tmrp), KM_SLEEP); 44940dc2366fSVenugopal Iyer bcopy(mrp, tmrp, sizeof (*tmrp)); 4495da14cebeSEric Cheng mcip = mac_primary_client_handle(mip); 4496ae6aa22aSVenugopal Iyer if (mcip != NULL && (mcip->mci_state_flags & MCIS_IS_AGGR_PORT) == 0) { 44970dc2366fSVenugopal Iyer err = mac_client_set_resources((mac_client_handle_t)mcip, tmrp); 44980dc2366fSVenugopal Iyer } else if ((mrp->mrp_mask & MRP_RX_RINGS || 44990dc2366fSVenugopal Iyer mrp->mrp_mask & MRP_TX_RINGS)) { 45000dc2366fSVenugopal Iyer mac_client_impl_t *vmcip; 45010dc2366fSVenugopal Iyer 45020dc2366fSVenugopal Iyer /* 45030dc2366fSVenugopal Iyer * If the primary is not up, we need to check if there 45040dc2366fSVenugopal Iyer * are any VLANs on this primary. If there are then 45050dc2366fSVenugopal Iyer * we need to set this property on the VLANs since 45060dc2366fSVenugopal Iyer * VLANs follow the primary they are based on. Just 45070dc2366fSVenugopal Iyer * look for the first VLAN and change its properties, 45080dc2366fSVenugopal Iyer * all the other VLANs should be in the same group. 45090dc2366fSVenugopal Iyer */ 45100dc2366fSVenugopal Iyer for (vmcip = mip->mi_clients_list; vmcip != NULL; 45110dc2366fSVenugopal Iyer vmcip = vmcip->mci_client_next) { 45120dc2366fSVenugopal Iyer if ((vmcip->mci_flent->fe_type & FLOW_PRIMARY_MAC) && 45130dc2366fSVenugopal Iyer mac_client_vid((mac_client_handle_t)vmcip) != 45140dc2366fSVenugopal Iyer VLAN_ID_NONE) { 45150dc2366fSVenugopal Iyer break; 45160dc2366fSVenugopal Iyer } 45170dc2366fSVenugopal Iyer } 45180dc2366fSVenugopal Iyer if (vmcip != NULL) { 45190dc2366fSVenugopal Iyer mac_resource_props_t *omrp; 45200dc2366fSVenugopal Iyer mac_resource_props_t *vmrp; 45210dc2366fSVenugopal Iyer 45220dc2366fSVenugopal Iyer omrp = kmem_zalloc(sizeof (*omrp), KM_SLEEP); 45230dc2366fSVenugopal Iyer bcopy(MCIP_RESOURCE_PROPS(vmcip), omrp, sizeof (*omrp)); 45240dc2366fSVenugopal Iyer /* 45250dc2366fSVenugopal Iyer * We dont' call mac_update_resources since we 45260dc2366fSVenugopal Iyer * want to take only the ring properties and 45270dc2366fSVenugopal Iyer * not all the properties that may have changed. 45280dc2366fSVenugopal Iyer */ 45290dc2366fSVenugopal Iyer vmrp = MCIP_RESOURCE_PROPS(vmcip); 45300dc2366fSVenugopal Iyer if (mrp->mrp_mask & MRP_RX_RINGS) { 45310dc2366fSVenugopal Iyer if (mrp->mrp_mask & MRP_RINGS_RESET) { 45320dc2366fSVenugopal Iyer vmrp->mrp_mask &= ~MRP_RX_RINGS; 45330dc2366fSVenugopal Iyer if (vmrp->mrp_mask & 45340dc2366fSVenugopal Iyer MRP_RXRINGS_UNSPEC) { 45350dc2366fSVenugopal Iyer vmrp->mrp_mask &= 45360dc2366fSVenugopal Iyer ~MRP_RXRINGS_UNSPEC; 45370dc2366fSVenugopal Iyer } 45380dc2366fSVenugopal Iyer vmrp->mrp_nrxrings = 0; 45390dc2366fSVenugopal Iyer } else { 45400dc2366fSVenugopal Iyer vmrp->mrp_mask |= MRP_RX_RINGS; 45410dc2366fSVenugopal Iyer vmrp->mrp_nrxrings = mrp->mrp_nrxrings; 45420dc2366fSVenugopal Iyer } 45430dc2366fSVenugopal Iyer } 45440dc2366fSVenugopal Iyer if (mrp->mrp_mask & MRP_TX_RINGS) { 45450dc2366fSVenugopal Iyer if (mrp->mrp_mask & MRP_RINGS_RESET) { 45460dc2366fSVenugopal Iyer vmrp->mrp_mask &= ~MRP_TX_RINGS; 45470dc2366fSVenugopal Iyer if (vmrp->mrp_mask & 45480dc2366fSVenugopal Iyer MRP_TXRINGS_UNSPEC) { 45490dc2366fSVenugopal Iyer vmrp->mrp_mask &= 45500dc2366fSVenugopal Iyer ~MRP_TXRINGS_UNSPEC; 45510dc2366fSVenugopal Iyer } 45520dc2366fSVenugopal Iyer vmrp->mrp_ntxrings = 0; 45530dc2366fSVenugopal Iyer } else { 45540dc2366fSVenugopal Iyer vmrp->mrp_mask |= MRP_TX_RINGS; 45550dc2366fSVenugopal Iyer vmrp->mrp_ntxrings = mrp->mrp_ntxrings; 45560dc2366fSVenugopal Iyer } 45570dc2366fSVenugopal Iyer } 45580dc2366fSVenugopal Iyer if (mrp->mrp_mask & MRP_RXRINGS_UNSPEC) 45590dc2366fSVenugopal Iyer vmrp->mrp_mask |= MRP_RXRINGS_UNSPEC; 45600dc2366fSVenugopal Iyer 45610dc2366fSVenugopal Iyer if (mrp->mrp_mask & MRP_TXRINGS_UNSPEC) 45620dc2366fSVenugopal Iyer vmrp->mrp_mask |= MRP_TXRINGS_UNSPEC; 45630dc2366fSVenugopal Iyer 45640dc2366fSVenugopal Iyer if ((err = mac_client_set_rings_prop(vmcip, mrp, 45650dc2366fSVenugopal Iyer omrp)) != 0) { 45660dc2366fSVenugopal Iyer bcopy(omrp, MCIP_RESOURCE_PROPS(vmcip), 45670dc2366fSVenugopal Iyer sizeof (*omrp)); 45680dc2366fSVenugopal Iyer } else { 45690dc2366fSVenugopal Iyer mac_set_prim_vlan_rings(mip, vmrp); 45700dc2366fSVenugopal Iyer } 45710dc2366fSVenugopal Iyer kmem_free(omrp, sizeof (*omrp)); 45720dc2366fSVenugopal Iyer } 4573da14cebeSEric Cheng } 45745d460eafSCathy Zhou 45755d460eafSCathy Zhou /* Only update the values if mac_client_set_resources succeeded */ 45765d460eafSCathy Zhou if (err == 0) { 45770dc2366fSVenugopal Iyer bcopy(umrp, &mip->mi_resource_props, sizeof (*umrp)); 45785d460eafSCathy Zhou /* 45790dc2366fSVenugopal Iyer * If bandwidth, priority or cpu link properties cleared, 45805d460eafSCathy Zhou * renable fastpath. 45815d460eafSCathy Zhou */ 45825d460eafSCathy Zhou if (resmask != 0 && newresmask == 0) 45835d460eafSCathy Zhou mac_fastpath_enable((mac_handle_t)mip); 45845d460eafSCathy Zhou } else if (resmask == 0 && newresmask != 0) { 45855d460eafSCathy Zhou mac_fastpath_enable((mac_handle_t)mip); 45865d460eafSCathy Zhou } 45870dc2366fSVenugopal Iyer kmem_free(tmrp, sizeof (*tmrp)); 45880dc2366fSVenugopal Iyer kmem_free(umrp, sizeof (*umrp)); 4589da14cebeSEric Cheng return (err); 4590da14cebeSEric Cheng } 4591da14cebeSEric Cheng 4592da14cebeSEric Cheng int 4593da14cebeSEric Cheng mac_set_resources(mac_handle_t mh, mac_resource_props_t *mrp) 4594da14cebeSEric Cheng { 4595da14cebeSEric Cheng int err; 4596da14cebeSEric Cheng 4597da14cebeSEric Cheng i_mac_perim_enter((mac_impl_t *)mh); 4598da14cebeSEric Cheng err = i_mac_set_resources(mh, mrp); 4599da14cebeSEric Cheng i_mac_perim_exit((mac_impl_t *)mh); 4600da14cebeSEric Cheng return (err); 4601da14cebeSEric Cheng } 4602da14cebeSEric Cheng 4603da14cebeSEric Cheng /* 4604da14cebeSEric Cheng * Get the properties cached for the specified MAC instance. 4605da14cebeSEric Cheng */ 4606da14cebeSEric Cheng void 4607da14cebeSEric Cheng mac_get_resources(mac_handle_t mh, mac_resource_props_t *mrp) 4608da14cebeSEric Cheng { 4609da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 4610da14cebeSEric Cheng mac_client_impl_t *mcip; 4611da14cebeSEric Cheng 4612da14cebeSEric Cheng mcip = mac_primary_client_handle(mip); 4613da14cebeSEric Cheng if (mcip != NULL) { 46140dc2366fSVenugopal Iyer mac_client_get_resources((mac_client_handle_t)mcip, mrp); 46150dc2366fSVenugopal Iyer return; 46160dc2366fSVenugopal Iyer } 46170dc2366fSVenugopal Iyer bcopy(&mip->mi_resource_props, mrp, sizeof (mac_resource_props_t)); 46180dc2366fSVenugopal Iyer } 46190dc2366fSVenugopal Iyer 46200dc2366fSVenugopal Iyer /* 46210dc2366fSVenugopal Iyer * Get the effective properties from the primary client of the 46220dc2366fSVenugopal Iyer * specified MAC instance. 46230dc2366fSVenugopal Iyer */ 46240dc2366fSVenugopal Iyer void 46250dc2366fSVenugopal Iyer mac_get_effective_resources(mac_handle_t mh, mac_resource_props_t *mrp) 46260dc2366fSVenugopal Iyer { 46270dc2366fSVenugopal Iyer mac_impl_t *mip = (mac_impl_t *)mh; 46280dc2366fSVenugopal Iyer mac_client_impl_t *mcip; 46290dc2366fSVenugopal Iyer 46300dc2366fSVenugopal Iyer mcip = mac_primary_client_handle(mip); 46310dc2366fSVenugopal Iyer if (mcip != NULL) { 46320dc2366fSVenugopal Iyer mac_client_get_effective_resources((mac_client_handle_t)mcip, 4633da14cebeSEric Cheng mrp); 4634da14cebeSEric Cheng return; 4635da14cebeSEric Cheng } 46360dc2366fSVenugopal Iyer bzero(mrp, sizeof (mac_resource_props_t)); 4637da14cebeSEric Cheng } 4638da14cebeSEric Cheng 46394eaa4710SRishi Srivatsavai int 46404eaa4710SRishi Srivatsavai mac_set_pvid(mac_handle_t mh, uint16_t pvid) 46414eaa4710SRishi Srivatsavai { 46424eaa4710SRishi Srivatsavai mac_impl_t *mip = (mac_impl_t *)mh; 46434eaa4710SRishi Srivatsavai mac_client_impl_t *mcip; 46444eaa4710SRishi Srivatsavai mac_unicast_impl_t *muip; 46454eaa4710SRishi Srivatsavai 46464eaa4710SRishi Srivatsavai i_mac_perim_enter(mip); 46474eaa4710SRishi Srivatsavai if (pvid != 0) { 46484eaa4710SRishi Srivatsavai for (mcip = mip->mi_clients_list; mcip != NULL; 46494eaa4710SRishi Srivatsavai mcip = mcip->mci_client_next) { 46504eaa4710SRishi Srivatsavai for (muip = mcip->mci_unicast_list; muip != NULL; 46514eaa4710SRishi Srivatsavai muip = muip->mui_next) { 46524eaa4710SRishi Srivatsavai if (muip->mui_vid == pvid) { 46534eaa4710SRishi Srivatsavai i_mac_perim_exit(mip); 46544eaa4710SRishi Srivatsavai return (EBUSY); 46554eaa4710SRishi Srivatsavai } 46564eaa4710SRishi Srivatsavai } 46574eaa4710SRishi Srivatsavai } 46584eaa4710SRishi Srivatsavai } 46594eaa4710SRishi Srivatsavai mip->mi_pvid = pvid; 46604eaa4710SRishi Srivatsavai i_mac_perim_exit(mip); 46614eaa4710SRishi Srivatsavai return (0); 46624eaa4710SRishi Srivatsavai } 46634eaa4710SRishi Srivatsavai 46644eaa4710SRishi Srivatsavai uint16_t 46654eaa4710SRishi Srivatsavai mac_get_pvid(mac_handle_t mh) 46664eaa4710SRishi Srivatsavai { 46674eaa4710SRishi Srivatsavai mac_impl_t *mip = (mac_impl_t *)mh; 46684eaa4710SRishi Srivatsavai 46694eaa4710SRishi Srivatsavai return (mip->mi_pvid); 46704eaa4710SRishi Srivatsavai } 46714eaa4710SRishi Srivatsavai 46724eaa4710SRishi Srivatsavai uint32_t 46734eaa4710SRishi Srivatsavai mac_get_llimit(mac_handle_t mh) 46744eaa4710SRishi Srivatsavai { 46754eaa4710SRishi Srivatsavai mac_impl_t *mip = (mac_impl_t *)mh; 46764eaa4710SRishi Srivatsavai 46774eaa4710SRishi Srivatsavai return (mip->mi_llimit); 46784eaa4710SRishi Srivatsavai } 46794eaa4710SRishi Srivatsavai 46804eaa4710SRishi Srivatsavai uint32_t 46814eaa4710SRishi Srivatsavai mac_get_ldecay(mac_handle_t mh) 46824eaa4710SRishi Srivatsavai { 46834eaa4710SRishi Srivatsavai mac_impl_t *mip = (mac_impl_t *)mh; 46844eaa4710SRishi Srivatsavai 46854eaa4710SRishi Srivatsavai return (mip->mi_ldecay); 46864eaa4710SRishi Srivatsavai } 46874eaa4710SRishi Srivatsavai 4688da14cebeSEric Cheng /* 4689da14cebeSEric Cheng * Rename a mac client, its flow, and the kstat. 4690da14cebeSEric Cheng */ 4691da14cebeSEric Cheng int 4692da14cebeSEric Cheng mac_rename_primary(mac_handle_t mh, const char *new_name) 4693da14cebeSEric Cheng { 4694da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 4695da14cebeSEric Cheng mac_client_impl_t *cur_clnt = NULL; 4696da14cebeSEric Cheng flow_entry_t *fep; 4697da14cebeSEric Cheng 4698da14cebeSEric Cheng i_mac_perim_enter(mip); 4699da14cebeSEric Cheng 4700da14cebeSEric Cheng /* 4701da14cebeSEric Cheng * VNICs: we need to change the sys flow name and 4702da14cebeSEric Cheng * the associated flow kstat. 4703da14cebeSEric Cheng */ 4704da14cebeSEric Cheng if (mip->mi_state_flags & MIS_IS_VNIC) { 47050dc2366fSVenugopal Iyer mac_client_impl_t *mcip = mac_vnic_lower(mip); 4706da14cebeSEric Cheng ASSERT(new_name != NULL); 47070dc2366fSVenugopal Iyer mac_rename_flow_names(mcip, new_name); 47080dc2366fSVenugopal Iyer mac_stat_rename(mcip); 4709da14cebeSEric Cheng goto done; 4710da14cebeSEric Cheng } 4711da14cebeSEric Cheng /* 4712da14cebeSEric Cheng * This mac may itself be an aggr link, or it may have some client 4713da14cebeSEric Cheng * which is an aggr port. For both cases, we need to change the 4714da14cebeSEric Cheng * aggr port's mac client name, its flow name and the associated flow 4715da14cebeSEric Cheng * kstat. 4716da14cebeSEric Cheng */ 4717da14cebeSEric Cheng if (mip->mi_state_flags & MIS_IS_AGGR) { 4718da14cebeSEric Cheng mac_capab_aggr_t aggr_cap; 4719da14cebeSEric Cheng mac_rename_fn_t rename_fn; 4720da14cebeSEric Cheng boolean_t ret; 4721da14cebeSEric Cheng 4722da14cebeSEric Cheng ASSERT(new_name != NULL); 4723da14cebeSEric Cheng ret = i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_AGGR, 4724da14cebeSEric Cheng (void *)(&aggr_cap)); 4725da14cebeSEric Cheng ASSERT(ret == B_TRUE); 4726da14cebeSEric Cheng rename_fn = aggr_cap.mca_rename_fn; 4727da14cebeSEric Cheng rename_fn(new_name, mip->mi_driver); 4728da14cebeSEric Cheng /* 4729da14cebeSEric Cheng * The aggr's client name and kstat flow name will be 4730da14cebeSEric Cheng * updated below, i.e. via mac_rename_flow_names. 4731da14cebeSEric Cheng */ 4732da14cebeSEric Cheng } 4733da14cebeSEric Cheng 4734da14cebeSEric Cheng for (cur_clnt = mip->mi_clients_list; cur_clnt != NULL; 4735da14cebeSEric Cheng cur_clnt = cur_clnt->mci_client_next) { 4736da14cebeSEric Cheng if (cur_clnt->mci_state_flags & MCIS_IS_AGGR_PORT) { 4737da14cebeSEric Cheng if (new_name != NULL) { 4738da14cebeSEric Cheng char *str_st = cur_clnt->mci_name; 4739da14cebeSEric Cheng char *str_del = strchr(str_st, '-'); 4740da14cebeSEric Cheng 4741da14cebeSEric Cheng ASSERT(str_del != NULL); 4742da14cebeSEric Cheng bzero(str_del + 1, MAXNAMELEN - 4743da14cebeSEric Cheng (str_del - str_st + 1)); 4744da14cebeSEric Cheng bcopy(new_name, str_del + 1, 4745da14cebeSEric Cheng strlen(new_name)); 4746da14cebeSEric Cheng } 4747da14cebeSEric Cheng fep = cur_clnt->mci_flent; 4748da14cebeSEric Cheng mac_rename_flow(fep, cur_clnt->mci_name); 4749da14cebeSEric Cheng break; 4750da14cebeSEric Cheng } else if (new_name != NULL && 4751da14cebeSEric Cheng cur_clnt->mci_state_flags & MCIS_USE_DATALINK_NAME) { 4752da14cebeSEric Cheng mac_rename_flow_names(cur_clnt, new_name); 4753da14cebeSEric Cheng break; 4754da14cebeSEric Cheng } 4755da14cebeSEric Cheng } 4756da14cebeSEric Cheng 47570dc2366fSVenugopal Iyer /* Recreate kstats associated with aggr pseudo rings */ 47580dc2366fSVenugopal Iyer if (mip->mi_state_flags & MIS_IS_AGGR) 47590dc2366fSVenugopal Iyer mac_pseudo_ring_stat_rename(mip); 47600dc2366fSVenugopal Iyer 4761da14cebeSEric Cheng done: 4762da14cebeSEric Cheng i_mac_perim_exit(mip); 4763da14cebeSEric Cheng return (0); 4764da14cebeSEric Cheng } 4765da14cebeSEric Cheng 4766da14cebeSEric Cheng /* 4767da14cebeSEric Cheng * Rename the MAC client's flow names 4768da14cebeSEric Cheng */ 4769da14cebeSEric Cheng static void 4770da14cebeSEric Cheng mac_rename_flow_names(mac_client_impl_t *mcip, const char *new_name) 4771da14cebeSEric Cheng { 4772da14cebeSEric Cheng flow_entry_t *flent; 4773da14cebeSEric Cheng uint16_t vid; 4774da000602SGirish Moodalbail char flowname[MAXFLOWNAMELEN]; 4775da14cebeSEric Cheng mac_impl_t *mip = mcip->mci_mip; 4776da14cebeSEric Cheng 4777da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip)); 4778da14cebeSEric Cheng 4779da14cebeSEric Cheng /* 4780da14cebeSEric Cheng * Use mi_rw_lock to ensure that threads not in the mac perimeter 4781da14cebeSEric Cheng * see a self-consistent value for mci_name 4782da14cebeSEric Cheng */ 4783da14cebeSEric Cheng rw_enter(&mip->mi_rw_lock, RW_WRITER); 4784da14cebeSEric Cheng (void) strlcpy(mcip->mci_name, new_name, sizeof (mcip->mci_name)); 4785da14cebeSEric Cheng rw_exit(&mip->mi_rw_lock); 4786da14cebeSEric Cheng 4787da14cebeSEric Cheng mac_rename_flow(mcip->mci_flent, new_name); 4788da14cebeSEric Cheng 4789da14cebeSEric Cheng if (mcip->mci_nflents == 1) 4790da14cebeSEric Cheng return; 4791da14cebeSEric Cheng 4792da14cebeSEric Cheng /* 4793da14cebeSEric Cheng * We have to rename all the others too, no stats to destroy for 4794da14cebeSEric Cheng * these. 4795da14cebeSEric Cheng */ 4796da14cebeSEric Cheng for (flent = mcip->mci_flent_list; flent != NULL; 4797da14cebeSEric Cheng flent = flent->fe_client_next) { 4798da14cebeSEric Cheng if (flent != mcip->mci_flent) { 4799da14cebeSEric Cheng vid = i_mac_flow_vid(flent); 4800da14cebeSEric Cheng (void) sprintf(flowname, "%s%u", new_name, vid); 4801da14cebeSEric Cheng mac_flow_set_name(flent, flowname); 4802da14cebeSEric Cheng } 4803da14cebeSEric Cheng } 4804da14cebeSEric Cheng } 4805da14cebeSEric Cheng 4806da14cebeSEric Cheng 4807da14cebeSEric Cheng /* 4808da14cebeSEric Cheng * Add a flow to the MAC client's flow list - i.e list of MAC/VID tuples 4809da14cebeSEric Cheng * defined for the specified MAC client. 4810da14cebeSEric Cheng */ 4811da14cebeSEric Cheng static void 4812da14cebeSEric Cheng mac_client_add_to_flow_list(mac_client_impl_t *mcip, flow_entry_t *flent) 4813da14cebeSEric Cheng { 4814da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip)); 4815da14cebeSEric Cheng /* 4816da14cebeSEric Cheng * The promisc Rx data path walks the mci_flent_list. Protect by 4817da14cebeSEric Cheng * using mi_rw_lock 4818da14cebeSEric Cheng */ 4819da14cebeSEric Cheng rw_enter(&mcip->mci_rw_lock, RW_WRITER); 4820da14cebeSEric Cheng 48213bb0cb70SBryan Cantrill mcip->mci_vidcache = MCIP_VIDCACHE_INVALID; 48223bb0cb70SBryan Cantrill 4823da14cebeSEric Cheng /* Add it to the head */ 4824da14cebeSEric Cheng flent->fe_client_next = mcip->mci_flent_list; 4825da14cebeSEric Cheng mcip->mci_flent_list = flent; 4826da14cebeSEric Cheng mcip->mci_nflents++; 4827da14cebeSEric Cheng 4828da14cebeSEric Cheng /* 4829da14cebeSEric Cheng * Keep track of the number of non-zero VIDs addresses per MAC 4830da14cebeSEric Cheng * client to avoid figuring it out in the data-path. 4831da14cebeSEric Cheng */ 4832da14cebeSEric Cheng if (i_mac_flow_vid(flent) != VLAN_ID_NONE) 4833da14cebeSEric Cheng mcip->mci_nvids++; 4834da14cebeSEric Cheng 4835da14cebeSEric Cheng rw_exit(&mcip->mci_rw_lock); 4836da14cebeSEric Cheng } 4837da14cebeSEric Cheng 4838da14cebeSEric Cheng /* 4839da14cebeSEric Cheng * Remove a flow entry from the MAC client's list. 4840da14cebeSEric Cheng */ 4841da14cebeSEric Cheng static void 4842da14cebeSEric Cheng mac_client_remove_flow_from_list(mac_client_impl_t *mcip, flow_entry_t *flent) 4843da14cebeSEric Cheng { 4844da14cebeSEric Cheng flow_entry_t *fe = mcip->mci_flent_list; 4845da14cebeSEric Cheng flow_entry_t *prev_fe = NULL; 4846da14cebeSEric Cheng 4847da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip)); 4848da14cebeSEric Cheng /* 4849da14cebeSEric Cheng * The promisc Rx data path walks the mci_flent_list. Protect by 4850da14cebeSEric Cheng * using mci_rw_lock 4851da14cebeSEric Cheng */ 4852da14cebeSEric Cheng rw_enter(&mcip->mci_rw_lock, RW_WRITER); 48533bb0cb70SBryan Cantrill mcip->mci_vidcache = MCIP_VIDCACHE_INVALID; 48543bb0cb70SBryan Cantrill 4855da14cebeSEric Cheng while ((fe != NULL) && (fe != flent)) { 4856da14cebeSEric Cheng prev_fe = fe; 4857da14cebeSEric Cheng fe = fe->fe_client_next; 4858da14cebeSEric Cheng } 4859da14cebeSEric Cheng 4860da000602SGirish Moodalbail ASSERT(fe != NULL); 4861da14cebeSEric Cheng if (prev_fe == NULL) { 4862da14cebeSEric Cheng /* Deleting the first node */ 4863da14cebeSEric Cheng mcip->mci_flent_list = fe->fe_client_next; 4864da14cebeSEric Cheng } else { 4865da14cebeSEric Cheng prev_fe->fe_client_next = fe->fe_client_next; 4866da14cebeSEric Cheng } 4867da14cebeSEric Cheng mcip->mci_nflents--; 4868da14cebeSEric Cheng 4869da14cebeSEric Cheng if (i_mac_flow_vid(flent) != VLAN_ID_NONE) 4870da14cebeSEric Cheng mcip->mci_nvids--; 4871da000602SGirish Moodalbail 4872da14cebeSEric Cheng rw_exit(&mcip->mci_rw_lock); 4873da14cebeSEric Cheng } 4874da14cebeSEric Cheng 4875da14cebeSEric Cheng /* 4876da14cebeSEric Cheng * Check if the given VID belongs to this MAC client. 4877da14cebeSEric Cheng */ 4878da14cebeSEric Cheng boolean_t 4879da14cebeSEric Cheng mac_client_check_flow_vid(mac_client_impl_t *mcip, uint16_t vid) 4880da14cebeSEric Cheng { 4881da14cebeSEric Cheng flow_entry_t *flent; 4882da14cebeSEric Cheng uint16_t mci_vid; 48833bb0cb70SBryan Cantrill uint32_t cache = mcip->mci_vidcache; 48843bb0cb70SBryan Cantrill 48853bb0cb70SBryan Cantrill /* 48863bb0cb70SBryan Cantrill * In hopes of not having to touch the mci_rw_lock, check to see if 48873bb0cb70SBryan Cantrill * this vid matches our cached result. 48883bb0cb70SBryan Cantrill */ 48893bb0cb70SBryan Cantrill if (MCIP_VIDCACHE_ISVALID(cache) && MCIP_VIDCACHE_VID(cache) == vid) 48903bb0cb70SBryan Cantrill return (MCIP_VIDCACHE_BOOL(cache) ? B_TRUE : B_FALSE); 4891da14cebeSEric Cheng 4892da14cebeSEric Cheng /* The mci_flent_list is protected by mci_rw_lock */ 4893da14cebeSEric Cheng rw_enter(&mcip->mci_rw_lock, RW_WRITER); 4894da14cebeSEric Cheng for (flent = mcip->mci_flent_list; flent != NULL; 4895da14cebeSEric Cheng flent = flent->fe_client_next) { 4896da14cebeSEric Cheng mci_vid = i_mac_flow_vid(flent); 4897da14cebeSEric Cheng if (vid == mci_vid) { 48983bb0cb70SBryan Cantrill mcip->mci_vidcache = MCIP_VIDCACHE_CACHE(vid, B_TRUE); 4899da14cebeSEric Cheng rw_exit(&mcip->mci_rw_lock); 4900da14cebeSEric Cheng return (B_TRUE); 4901da14cebeSEric Cheng } 4902da14cebeSEric Cheng } 49033bb0cb70SBryan Cantrill 49043bb0cb70SBryan Cantrill mcip->mci_vidcache = MCIP_VIDCACHE_CACHE(vid, B_FALSE); 4905da14cebeSEric Cheng rw_exit(&mcip->mci_rw_lock); 4906da14cebeSEric Cheng return (B_FALSE); 4907da14cebeSEric Cheng } 4908da14cebeSEric Cheng 4909da14cebeSEric Cheng /* 4910da14cebeSEric Cheng * Get the flow entry for the specified <MAC addr, VID> tuple. 4911da14cebeSEric Cheng */ 4912da14cebeSEric Cheng static flow_entry_t * 4913da14cebeSEric Cheng mac_client_get_flow(mac_client_impl_t *mcip, mac_unicast_impl_t *muip) 4914da14cebeSEric Cheng { 4915da14cebeSEric Cheng mac_address_t *map = mcip->mci_unicast; 4916da14cebeSEric Cheng flow_entry_t *flent; 4917da14cebeSEric Cheng uint16_t vid; 4918da14cebeSEric Cheng flow_desc_t flow_desc; 4919da14cebeSEric Cheng 4920da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip)); 4921da14cebeSEric Cheng 4922da14cebeSEric Cheng mac_flow_get_desc(mcip->mci_flent, &flow_desc); 4923da14cebeSEric Cheng if (bcmp(flow_desc.fd_dst_mac, map->ma_addr, map->ma_len) != 0) 4924da14cebeSEric Cheng return (NULL); 4925da14cebeSEric Cheng 4926da14cebeSEric Cheng for (flent = mcip->mci_flent_list; flent != NULL; 4927da14cebeSEric Cheng flent = flent->fe_client_next) { 4928da14cebeSEric Cheng vid = i_mac_flow_vid(flent); 4929da14cebeSEric Cheng if (vid == muip->mui_vid) { 4930da14cebeSEric Cheng return (flent); 4931da14cebeSEric Cheng } 4932da14cebeSEric Cheng } 4933da14cebeSEric Cheng 4934da14cebeSEric Cheng return (NULL); 4935da14cebeSEric Cheng } 4936da14cebeSEric Cheng 4937da14cebeSEric Cheng /* 4938da14cebeSEric Cheng * Since mci_flent has the SRSs, when we want to remove it, we replace 4939da14cebeSEric Cheng * the flow_desc_t in mci_flent with that of an existing flent and then 4940da14cebeSEric Cheng * remove that flent instead of mci_flent. 4941da14cebeSEric Cheng */ 4942da14cebeSEric Cheng static flow_entry_t * 4943da14cebeSEric Cheng mac_client_swap_mciflent(mac_client_impl_t *mcip) 4944da14cebeSEric Cheng { 4945da14cebeSEric Cheng flow_entry_t *flent = mcip->mci_flent; 4946da14cebeSEric Cheng flow_tab_t *ft = flent->fe_flow_tab; 4947da14cebeSEric Cheng flow_entry_t *flent1; 4948da14cebeSEric Cheng flow_desc_t fl_desc; 4949da000602SGirish Moodalbail char fl_name[MAXFLOWNAMELEN]; 4950da14cebeSEric Cheng int err; 4951da14cebeSEric Cheng 4952da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip)); 4953da14cebeSEric Cheng ASSERT(mcip->mci_nflents > 1); 4954da14cebeSEric Cheng 4955da14cebeSEric Cheng /* get the next flent following the primary flent */ 4956da14cebeSEric Cheng flent1 = mcip->mci_flent_list->fe_client_next; 4957da14cebeSEric Cheng ASSERT(flent1 != NULL && flent1->fe_flow_tab == ft); 4958da14cebeSEric Cheng 4959da14cebeSEric Cheng /* 4960da14cebeSEric Cheng * Remove the flent from the flow table before updating the 4961da14cebeSEric Cheng * flow descriptor as the hash depends on the flow descriptor. 4962da14cebeSEric Cheng * This also helps incoming packet classification avoid having 4963da14cebeSEric Cheng * to grab fe_lock. Access to fe_flow_desc of a flent not in the 4964da14cebeSEric Cheng * flow table is done under the fe_lock so that log or stat functions 4965da14cebeSEric Cheng * see a self-consistent fe_flow_desc. The name and desc are specific 4966da14cebeSEric Cheng * to a flow, the rest are shared by all the clients, including 4967da14cebeSEric Cheng * resource control etc. 4968da14cebeSEric Cheng */ 4969da14cebeSEric Cheng mac_flow_remove(ft, flent, B_TRUE); 4970da14cebeSEric Cheng mac_flow_remove(ft, flent1, B_TRUE); 4971da14cebeSEric Cheng 4972da14cebeSEric Cheng bcopy(&flent->fe_flow_desc, &fl_desc, sizeof (flow_desc_t)); 4973da000602SGirish Moodalbail bcopy(flent->fe_flow_name, fl_name, MAXFLOWNAMELEN); 4974da14cebeSEric Cheng 4975da14cebeSEric Cheng /* update the primary flow entry */ 4976da14cebeSEric Cheng mutex_enter(&flent->fe_lock); 4977da14cebeSEric Cheng bcopy(&flent1->fe_flow_desc, &flent->fe_flow_desc, 4978da14cebeSEric Cheng sizeof (flow_desc_t)); 4979da000602SGirish Moodalbail bcopy(&flent1->fe_flow_name, &flent->fe_flow_name, MAXFLOWNAMELEN); 4980da14cebeSEric Cheng mutex_exit(&flent->fe_lock); 4981da14cebeSEric Cheng 4982da14cebeSEric Cheng /* update the flow entry that is to be freed */ 4983da14cebeSEric Cheng mutex_enter(&flent1->fe_lock); 4984da14cebeSEric Cheng bcopy(&fl_desc, &flent1->fe_flow_desc, sizeof (flow_desc_t)); 4985da000602SGirish Moodalbail bcopy(fl_name, &flent1->fe_flow_name, MAXFLOWNAMELEN); 4986da14cebeSEric Cheng mutex_exit(&flent1->fe_lock); 4987da14cebeSEric Cheng 4988da14cebeSEric Cheng /* now reinsert the flow entries in the table */ 4989da14cebeSEric Cheng err = mac_flow_add(ft, flent); 4990da14cebeSEric Cheng ASSERT(err == 0); 4991da14cebeSEric Cheng 4992da14cebeSEric Cheng err = mac_flow_add(ft, flent1); 4993da14cebeSEric Cheng ASSERT(err == 0); 4994da14cebeSEric Cheng 4995da14cebeSEric Cheng return (flent1); 4996da14cebeSEric Cheng } 4997da14cebeSEric Cheng 4998da14cebeSEric Cheng /* 4999da14cebeSEric Cheng * Return whether there is only one flow entry associated with this 5000da14cebeSEric Cheng * MAC client. 5001da14cebeSEric Cheng */ 5002da14cebeSEric Cheng static boolean_t 5003da14cebeSEric Cheng mac_client_single_rcvr(mac_client_impl_t *mcip) 5004da14cebeSEric Cheng { 5005da14cebeSEric Cheng return (mcip->mci_nflents == 1); 5006da14cebeSEric Cheng } 5007da14cebeSEric Cheng 5008da14cebeSEric Cheng int 50090dc2366fSVenugopal Iyer mac_validate_props(mac_impl_t *mip, mac_resource_props_t *mrp) 5010da14cebeSEric Cheng { 50110dc2366fSVenugopal Iyer boolean_t reset; 50120dc2366fSVenugopal Iyer uint32_t rings_needed; 50130dc2366fSVenugopal Iyer uint32_t rings_avail; 50140dc2366fSVenugopal Iyer mac_group_type_t gtype; 50150dc2366fSVenugopal Iyer mac_resource_props_t *mip_mrp; 50160dc2366fSVenugopal Iyer 5017da14cebeSEric Cheng if (mrp == NULL) 5018da14cebeSEric Cheng return (0); 5019da14cebeSEric Cheng 5020da14cebeSEric Cheng if (mrp->mrp_mask & MRP_PRIORITY) { 5021da14cebeSEric Cheng mac_priority_level_t pri = mrp->mrp_priority; 5022da14cebeSEric Cheng 5023da14cebeSEric Cheng if (pri < MPL_LOW || pri > MPL_RESET) 5024da14cebeSEric Cheng return (EINVAL); 5025da14cebeSEric Cheng } 5026da14cebeSEric Cheng 5027da14cebeSEric Cheng if (mrp->mrp_mask & MRP_MAXBW) { 5028da14cebeSEric Cheng uint64_t maxbw = mrp->mrp_maxbw; 5029da14cebeSEric Cheng 5030da14cebeSEric Cheng if (maxbw < MRP_MAXBW_MINVAL && maxbw != 0) 5031da14cebeSEric Cheng return (EINVAL); 5032da14cebeSEric Cheng } 5033da14cebeSEric Cheng if (mrp->mrp_mask & MRP_CPUS) { 5034b6b50fcfSNitin Hande int i, j; 5035da14cebeSEric Cheng mac_cpu_mode_t fanout; 5036da14cebeSEric Cheng 50375adf34bdSRajagopal Kunhappan if (mrp->mrp_ncpus > ncpus) 5038da14cebeSEric Cheng return (EINVAL); 5039da14cebeSEric Cheng 5040da14cebeSEric Cheng for (i = 0; i < mrp->mrp_ncpus; i++) { 5041b6b50fcfSNitin Hande for (j = 0; j < mrp->mrp_ncpus; j++) { 5042b6b50fcfSNitin Hande if (i != j && 5043b6b50fcfSNitin Hande mrp->mrp_cpu[i] == mrp->mrp_cpu[j]) { 5044b6b50fcfSNitin Hande return (EINVAL); 5045b6b50fcfSNitin Hande } 5046b6b50fcfSNitin Hande } 5047b6b50fcfSNitin Hande } 5048b6b50fcfSNitin Hande 5049b6b50fcfSNitin Hande for (i = 0; i < mrp->mrp_ncpus; i++) { 5050da14cebeSEric Cheng cpu_t *cp; 5051da14cebeSEric Cheng int rv; 5052da14cebeSEric Cheng 5053da14cebeSEric Cheng mutex_enter(&cpu_lock); 5054da14cebeSEric Cheng cp = cpu_get(mrp->mrp_cpu[i]); 5055da14cebeSEric Cheng if (cp != NULL) 5056da14cebeSEric Cheng rv = cpu_is_online(cp); 5057da14cebeSEric Cheng else 5058da14cebeSEric Cheng rv = 0; 5059da14cebeSEric Cheng mutex_exit(&cpu_lock); 5060da14cebeSEric Cheng if (rv == 0) 5061da14cebeSEric Cheng return (EINVAL); 5062da14cebeSEric Cheng } 5063da14cebeSEric Cheng 5064da14cebeSEric Cheng fanout = mrp->mrp_fanout_mode; 5065da14cebeSEric Cheng if (fanout < 0 || fanout > MCM_CPUS) 5066da14cebeSEric Cheng return (EINVAL); 5067da14cebeSEric Cheng } 506825ec3e3dSEric Cheng 506925ec3e3dSEric Cheng if (mrp->mrp_mask & MRP_PROTECT) { 507025ec3e3dSEric Cheng int err = mac_protect_validate(mrp); 507125ec3e3dSEric Cheng if (err != 0) 507225ec3e3dSEric Cheng return (err); 507325ec3e3dSEric Cheng } 50740dc2366fSVenugopal Iyer 50750dc2366fSVenugopal Iyer if (!(mrp->mrp_mask & MRP_RX_RINGS) && 50760dc2366fSVenugopal Iyer !(mrp->mrp_mask & MRP_TX_RINGS)) { 50770dc2366fSVenugopal Iyer return (0); 50780dc2366fSVenugopal Iyer } 50790dc2366fSVenugopal Iyer 50800dc2366fSVenugopal Iyer /* 50810dc2366fSVenugopal Iyer * mip will be null when we come from mac_flow_create or 50820dc2366fSVenugopal Iyer * mac_link_flow_modify. In the latter case it is a user flow, 50830dc2366fSVenugopal Iyer * for which we don't support rings. In the former we would 50840dc2366fSVenugopal Iyer * have validated the props beforehand (i_mac_unicast_add -> 50850dc2366fSVenugopal Iyer * mac_client_set_resources -> validate for the primary and 50860dc2366fSVenugopal Iyer * vnic_dev_create -> mac_client_set_resources -> validate for 50870dc2366fSVenugopal Iyer * a vnic. 50880dc2366fSVenugopal Iyer */ 50890dc2366fSVenugopal Iyer if (mip == NULL) 50900dc2366fSVenugopal Iyer return (0); 50910dc2366fSVenugopal Iyer 50920dc2366fSVenugopal Iyer /* 50930dc2366fSVenugopal Iyer * We don't support setting rings property for a VNIC that is using a 50940dc2366fSVenugopal Iyer * primary address (VLAN) 50950dc2366fSVenugopal Iyer */ 50960dc2366fSVenugopal Iyer if ((mip->mi_state_flags & MIS_IS_VNIC) && 50970dc2366fSVenugopal Iyer mac_is_vnic_primary((mac_handle_t)mip)) { 50980dc2366fSVenugopal Iyer return (ENOTSUP); 50990dc2366fSVenugopal Iyer } 51000dc2366fSVenugopal Iyer 51010dc2366fSVenugopal Iyer mip_mrp = &mip->mi_resource_props; 51020dc2366fSVenugopal Iyer /* 51030dc2366fSVenugopal Iyer * The rings property should be validated against the NICs 51040dc2366fSVenugopal Iyer * resources 51050dc2366fSVenugopal Iyer */ 51060dc2366fSVenugopal Iyer if (mip->mi_state_flags & MIS_IS_VNIC) 51070dc2366fSVenugopal Iyer mip = (mac_impl_t *)mac_get_lower_mac_handle((mac_handle_t)mip); 51080dc2366fSVenugopal Iyer 51090dc2366fSVenugopal Iyer reset = mrp->mrp_mask & MRP_RINGS_RESET; 51100dc2366fSVenugopal Iyer /* 51110dc2366fSVenugopal Iyer * If groups are not supported, return error. 51120dc2366fSVenugopal Iyer */ 51130dc2366fSVenugopal Iyer if (((mrp->mrp_mask & MRP_RX_RINGS) && mip->mi_rx_groups == NULL) || 51140dc2366fSVenugopal Iyer ((mrp->mrp_mask & MRP_TX_RINGS) && mip->mi_tx_groups == NULL)) { 51150dc2366fSVenugopal Iyer return (EINVAL); 51160dc2366fSVenugopal Iyer } 51170dc2366fSVenugopal Iyer /* 51180dc2366fSVenugopal Iyer * If we are just resetting, there is no validation needed. 51190dc2366fSVenugopal Iyer */ 51200dc2366fSVenugopal Iyer if (reset) 51210dc2366fSVenugopal Iyer return (0); 51220dc2366fSVenugopal Iyer 51230dc2366fSVenugopal Iyer if (mrp->mrp_mask & MRP_RX_RINGS) { 51240dc2366fSVenugopal Iyer rings_needed = mrp->mrp_nrxrings; 51250dc2366fSVenugopal Iyer /* 51260dc2366fSVenugopal Iyer * We just want to check if the number of additional 51270dc2366fSVenugopal Iyer * rings requested is available. 51280dc2366fSVenugopal Iyer */ 51290dc2366fSVenugopal Iyer if (mip_mrp->mrp_mask & MRP_RX_RINGS) { 51300dc2366fSVenugopal Iyer if (mrp->mrp_nrxrings > mip_mrp->mrp_nrxrings) 51310dc2366fSVenugopal Iyer /* Just check for the additional rings */ 51320dc2366fSVenugopal Iyer rings_needed -= mip_mrp->mrp_nrxrings; 51330dc2366fSVenugopal Iyer else 51340dc2366fSVenugopal Iyer /* We are not asking for additional rings */ 51350dc2366fSVenugopal Iyer rings_needed = 0; 51360dc2366fSVenugopal Iyer } 51370dc2366fSVenugopal Iyer rings_avail = mip->mi_rxrings_avail; 51380dc2366fSVenugopal Iyer gtype = mip->mi_rx_group_type; 51390dc2366fSVenugopal Iyer } else { 51400dc2366fSVenugopal Iyer rings_needed = mrp->mrp_ntxrings; 51410dc2366fSVenugopal Iyer /* Similarly for the TX rings */ 51420dc2366fSVenugopal Iyer if (mip_mrp->mrp_mask & MRP_TX_RINGS) { 51430dc2366fSVenugopal Iyer if (mrp->mrp_ntxrings > mip_mrp->mrp_ntxrings) 51440dc2366fSVenugopal Iyer /* Just check for the additional rings */ 51450dc2366fSVenugopal Iyer rings_needed -= mip_mrp->mrp_ntxrings; 51460dc2366fSVenugopal Iyer else 51470dc2366fSVenugopal Iyer /* We are not asking for additional rings */ 51480dc2366fSVenugopal Iyer rings_needed = 0; 51490dc2366fSVenugopal Iyer } 51500dc2366fSVenugopal Iyer rings_avail = mip->mi_txrings_avail; 51510dc2366fSVenugopal Iyer gtype = mip->mi_tx_group_type; 51520dc2366fSVenugopal Iyer } 51530dc2366fSVenugopal Iyer 51540dc2366fSVenugopal Iyer /* Error if the group is dynamic .. */ 51550dc2366fSVenugopal Iyer if (gtype == MAC_GROUP_TYPE_DYNAMIC) { 51560dc2366fSVenugopal Iyer /* 51570dc2366fSVenugopal Iyer * .. and rings specified are more than available. 51580dc2366fSVenugopal Iyer */ 51590dc2366fSVenugopal Iyer if (rings_needed > rings_avail) 51600dc2366fSVenugopal Iyer return (EINVAL); 51610dc2366fSVenugopal Iyer } else { 51620dc2366fSVenugopal Iyer /* 51630dc2366fSVenugopal Iyer * OR group is static and we have specified some rings. 51640dc2366fSVenugopal Iyer */ 51650dc2366fSVenugopal Iyer if (rings_needed > 0) 51660dc2366fSVenugopal Iyer return (EINVAL); 51670dc2366fSVenugopal Iyer } 5168da14cebeSEric Cheng return (0); 5169da14cebeSEric Cheng } 5170da14cebeSEric Cheng 5171da14cebeSEric Cheng /* 5172da14cebeSEric Cheng * Send a MAC_NOTE_LINK notification to all the MAC clients whenever the 5173da14cebeSEric Cheng * underlying physical link is down. This is to allow MAC clients to 5174da14cebeSEric Cheng * communicate with other clients. 5175da14cebeSEric Cheng */ 5176da14cebeSEric Cheng void 5177da14cebeSEric Cheng mac_virtual_link_update(mac_impl_t *mip) 5178da14cebeSEric Cheng { 5179da14cebeSEric Cheng if (mip->mi_linkstate != LINK_STATE_UP) 5180da14cebeSEric Cheng i_mac_notify(mip, MAC_NOTE_LINK); 5181da14cebeSEric Cheng } 5182da14cebeSEric Cheng 5183da14cebeSEric Cheng /* 5184da14cebeSEric Cheng * For clients that have a pass-thru MAC, e.g. VNIC, we set the VNIC's 5185da14cebeSEric Cheng * mac handle in the client. 5186da14cebeSEric Cheng */ 5187da14cebeSEric Cheng void 51880dc2366fSVenugopal Iyer mac_set_upper_mac(mac_client_handle_t mch, mac_handle_t mh, 51890dc2366fSVenugopal Iyer mac_resource_props_t *mrp) 5190da14cebeSEric Cheng { 5191da14cebeSEric Cheng mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 51920dc2366fSVenugopal Iyer mac_impl_t *mip = (mac_impl_t *)mh; 5193da14cebeSEric Cheng 51940dc2366fSVenugopal Iyer mcip->mci_upper_mip = mip; 51950dc2366fSVenugopal Iyer /* If there are any properties, copy it over too */ 51960dc2366fSVenugopal Iyer if (mrp != NULL) { 51970dc2366fSVenugopal Iyer bcopy(mrp, &mip->mi_resource_props, 51980dc2366fSVenugopal Iyer sizeof (mac_resource_props_t)); 51990dc2366fSVenugopal Iyer } 5200da14cebeSEric Cheng } 5201da14cebeSEric Cheng 5202da14cebeSEric Cheng /* 5203da14cebeSEric Cheng * Mark the mac as being used exclusively by the single mac client that is 5204da14cebeSEric Cheng * doing some control operation on this mac. No further opens of this mac 5205da14cebeSEric Cheng * will be allowed until this client calls mac_unmark_exclusive. The mac 5206da14cebeSEric Cheng * client calling this function must already be in the mac perimeter 5207da14cebeSEric Cheng */ 5208da14cebeSEric Cheng int 5209da14cebeSEric Cheng mac_mark_exclusive(mac_handle_t mh) 5210da14cebeSEric Cheng { 5211da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 5212da14cebeSEric Cheng 5213da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD(mh)); 5214da14cebeSEric Cheng /* 5215da14cebeSEric Cheng * Look up its entry in the global hash table. 5216da14cebeSEric Cheng */ 5217da14cebeSEric Cheng rw_enter(&i_mac_impl_lock, RW_WRITER); 5218da14cebeSEric Cheng if (mip->mi_state_flags & MIS_DISABLED) { 5219da14cebeSEric Cheng rw_exit(&i_mac_impl_lock); 5220da14cebeSEric Cheng return (ENOENT); 5221da14cebeSEric Cheng } 5222da14cebeSEric Cheng 5223da14cebeSEric Cheng /* 5224da14cebeSEric Cheng * A reference to mac is held even if the link is not plumbed. 5225da14cebeSEric Cheng * In i_dls_link_create() we open the MAC interface and hold the 5226da14cebeSEric Cheng * reference. There is an additional reference for the mac_open 5227da14cebeSEric Cheng * done in acquiring the mac perimeter 5228da14cebeSEric Cheng */ 5229da14cebeSEric Cheng if (mip->mi_ref != 2) { 5230da14cebeSEric Cheng rw_exit(&i_mac_impl_lock); 5231da14cebeSEric Cheng return (EBUSY); 5232da14cebeSEric Cheng } 5233da14cebeSEric Cheng 5234da14cebeSEric Cheng ASSERT(!(mip->mi_state_flags & MIS_EXCLUSIVE_HELD)); 5235da14cebeSEric Cheng mip->mi_state_flags |= MIS_EXCLUSIVE_HELD; 5236da14cebeSEric Cheng rw_exit(&i_mac_impl_lock); 5237da14cebeSEric Cheng return (0); 5238da14cebeSEric Cheng } 5239da14cebeSEric Cheng 5240da14cebeSEric Cheng void 5241da14cebeSEric Cheng mac_unmark_exclusive(mac_handle_t mh) 5242da14cebeSEric Cheng { 5243da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 5244da14cebeSEric Cheng 5245da14cebeSEric Cheng ASSERT(MAC_PERIM_HELD(mh)); 5246da14cebeSEric Cheng 5247da14cebeSEric Cheng rw_enter(&i_mac_impl_lock, RW_WRITER); 5248da14cebeSEric Cheng /* 1 for the creation and another for the perimeter */ 5249da14cebeSEric Cheng ASSERT(mip->mi_ref == 2 && (mip->mi_state_flags & MIS_EXCLUSIVE_HELD)); 5250da14cebeSEric Cheng mip->mi_state_flags &= ~MIS_EXCLUSIVE_HELD; 5251da14cebeSEric Cheng rw_exit(&i_mac_impl_lock); 5252da14cebeSEric Cheng } 5253da14cebeSEric Cheng 5254da14cebeSEric Cheng /* 52550dc2366fSVenugopal Iyer * Set the MTU for the specified MAC. 5256da14cebeSEric Cheng */ 5257da14cebeSEric Cheng int 5258da14cebeSEric Cheng mac_set_mtu(mac_handle_t mh, uint_t new_mtu, uint_t *old_mtu_arg) 5259da14cebeSEric Cheng { 5260da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 5261da14cebeSEric Cheng uint_t old_mtu; 5262e3321b89SSebastien Roy int rv = 0; 5263da14cebeSEric Cheng 5264da14cebeSEric Cheng i_mac_perim_enter(mip); 5265da14cebeSEric Cheng 52662b24ab6bSSebastien Roy if (!(mip->mi_callbacks->mc_callbacks & (MC_SETPROP|MC_GETPROP))) { 5267da14cebeSEric Cheng rv = ENOTSUP; 5268da14cebeSEric Cheng goto bail; 5269da14cebeSEric Cheng } 5270da14cebeSEric Cheng 52712b24ab6bSSebastien Roy old_mtu = mip->mi_sdu_max; 5272da14cebeSEric Cheng 52730dc2366fSVenugopal Iyer if (new_mtu == 0 || new_mtu < mip->mi_sdu_min) { 52740dc2366fSVenugopal Iyer rv = EINVAL; 52750dc2366fSVenugopal Iyer goto bail; 52760dc2366fSVenugopal Iyer } 52770dc2366fSVenugopal Iyer 5278a776d98eSRobert Mustacchi rw_enter(&mip->mi_rw_lock, RW_READER); 5279a776d98eSRobert Mustacchi if (mip->mi_mtrp != NULL && new_mtu < mip->mi_mtrp->mtr_mtu) { 5280a776d98eSRobert Mustacchi rv = EBUSY; 5281a776d98eSRobert Mustacchi rw_exit(&mip->mi_rw_lock); 5282a776d98eSRobert Mustacchi goto bail; 5283a776d98eSRobert Mustacchi } 5284a776d98eSRobert Mustacchi rw_exit(&mip->mi_rw_lock); 5285a776d98eSRobert Mustacchi 5286da14cebeSEric Cheng if (old_mtu != new_mtu) { 5287da14cebeSEric Cheng rv = mip->mi_callbacks->mc_setprop(mip->mi_driver, 5288da14cebeSEric Cheng "mtu", MAC_PROP_MTU, sizeof (uint_t), &new_mtu); 52890dc2366fSVenugopal Iyer if (rv != 0) 52900dc2366fSVenugopal Iyer goto bail; 52910dc2366fSVenugopal Iyer rv = mac_maxsdu_update(mh, new_mtu); 52920dc2366fSVenugopal Iyer ASSERT(rv == 0); 5293da14cebeSEric Cheng } 5294da14cebeSEric Cheng 5295da14cebeSEric Cheng bail: 5296da14cebeSEric Cheng i_mac_perim_exit(mip); 5297da14cebeSEric Cheng 5298da14cebeSEric Cheng if (rv == 0 && old_mtu_arg != NULL) 5299da14cebeSEric Cheng *old_mtu_arg = old_mtu; 5300da14cebeSEric Cheng return (rv); 5301da14cebeSEric Cheng } 5302da14cebeSEric Cheng 53030dc2366fSVenugopal Iyer /* 53040dc2366fSVenugopal Iyer * Return the RX h/w information for the group indexed by grp_num. 53050dc2366fSVenugopal Iyer */ 5306da14cebeSEric Cheng void 53070dc2366fSVenugopal Iyer mac_get_hwrxgrp_info(mac_handle_t mh, int grp_index, uint_t *grp_num, 53080dc2366fSVenugopal Iyer uint_t *n_rings, uint_t *rings, uint_t *type, uint_t *n_clnts, 53090dc2366fSVenugopal Iyer char *clnts_name) 5310da14cebeSEric Cheng { 5311da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 5312da14cebeSEric Cheng mac_grp_client_t *mcip; 5313da14cebeSEric Cheng uint_t i = 0, index = 0; 53140dc2366fSVenugopal Iyer mac_ring_t *ring; 5315da14cebeSEric Cheng 5316da14cebeSEric Cheng /* Revisit when we implement fully dynamic group allocation */ 5317da14cebeSEric Cheng ASSERT(grp_index >= 0 && grp_index < mip->mi_rx_group_count); 5318da14cebeSEric Cheng 5319da14cebeSEric Cheng rw_enter(&mip->mi_rw_lock, RW_READER); 5320da14cebeSEric Cheng *grp_num = mip->mi_rx_groups[grp_index].mrg_index; 5321da14cebeSEric Cheng *type = mip->mi_rx_groups[grp_index].mrg_type; 5322da14cebeSEric Cheng *n_rings = mip->mi_rx_groups[grp_index].mrg_cur_count; 53230dc2366fSVenugopal Iyer ring = mip->mi_rx_groups[grp_index].mrg_rings; 53240dc2366fSVenugopal Iyer for (index = 0; index < mip->mi_rx_groups[grp_index].mrg_cur_count; 53250dc2366fSVenugopal Iyer index++) { 53260dc2366fSVenugopal Iyer rings[index] = ring->mr_index; 53270dc2366fSVenugopal Iyer ring = ring->mr_next; 53280dc2366fSVenugopal Iyer } 53290dc2366fSVenugopal Iyer /* Assuming the 1st is the default group */ 53300dc2366fSVenugopal Iyer index = 0; 53310dc2366fSVenugopal Iyer if (grp_index == 0) { 53320dc2366fSVenugopal Iyer (void) strlcpy(clnts_name, "<default,mcast>,", 53330dc2366fSVenugopal Iyer MAXCLIENTNAMELEN); 53340dc2366fSVenugopal Iyer index += strlen("<default,mcast>,"); 53350dc2366fSVenugopal Iyer } 5336da14cebeSEric Cheng for (mcip = mip->mi_rx_groups[grp_index].mrg_clients; mcip != NULL; 5337da14cebeSEric Cheng mcip = mcip->mgc_next) { 5338da14cebeSEric Cheng int name_len = strlen(mcip->mgc_client->mci_name); 5339da14cebeSEric Cheng 5340da14cebeSEric Cheng /* 5341da14cebeSEric Cheng * MAXCLIENTNAMELEN is the buffer size reserved for client 5342da14cebeSEric Cheng * names. 5343da14cebeSEric Cheng * XXXX Formating the client name string needs to be moved 5344da14cebeSEric Cheng * to user land when fixing the size of dhi_clnts in 5345da14cebeSEric Cheng * dld_hwgrpinfo_t. We should use n_clients * client_name for 5346da14cebeSEric Cheng * dhi_clntsin instead of MAXCLIENTNAMELEN 5347da14cebeSEric Cheng */ 5348da14cebeSEric Cheng if (index + name_len >= MAXCLIENTNAMELEN) { 5349da14cebeSEric Cheng index = MAXCLIENTNAMELEN; 5350da14cebeSEric Cheng break; 5351da14cebeSEric Cheng } 5352da14cebeSEric Cheng bcopy(mcip->mgc_client->mci_name, &(clnts_name[index]), 5353da14cebeSEric Cheng name_len); 5354da14cebeSEric Cheng index += name_len; 5355da14cebeSEric Cheng clnts_name[index++] = ','; 5356da14cebeSEric Cheng i++; 5357da14cebeSEric Cheng } 5358da14cebeSEric Cheng 5359da14cebeSEric Cheng /* Get rid of the last , */ 5360da14cebeSEric Cheng if (index > 0) 5361da14cebeSEric Cheng clnts_name[index - 1] = '\0'; 5362da14cebeSEric Cheng *n_clnts = i; 5363da14cebeSEric Cheng rw_exit(&mip->mi_rw_lock); 5364da14cebeSEric Cheng } 5365da14cebeSEric Cheng 53660dc2366fSVenugopal Iyer /* 53670dc2366fSVenugopal Iyer * Return the TX h/w information for the group indexed by grp_num. 53680dc2366fSVenugopal Iyer */ 53690dc2366fSVenugopal Iyer void 53700dc2366fSVenugopal Iyer mac_get_hwtxgrp_info(mac_handle_t mh, int grp_index, uint_t *grp_num, 53710dc2366fSVenugopal Iyer uint_t *n_rings, uint_t *rings, uint_t *type, uint_t *n_clnts, 53720dc2366fSVenugopal Iyer char *clnts_name) 53730dc2366fSVenugopal Iyer { 53740dc2366fSVenugopal Iyer mac_impl_t *mip = (mac_impl_t *)mh; 53750dc2366fSVenugopal Iyer mac_grp_client_t *mcip; 53760dc2366fSVenugopal Iyer uint_t i = 0, index = 0; 53770dc2366fSVenugopal Iyer mac_ring_t *ring; 53780dc2366fSVenugopal Iyer 53790dc2366fSVenugopal Iyer /* Revisit when we implement fully dynamic group allocation */ 53800dc2366fSVenugopal Iyer ASSERT(grp_index >= 0 && grp_index <= mip->mi_tx_group_count); 53810dc2366fSVenugopal Iyer 53820dc2366fSVenugopal Iyer rw_enter(&mip->mi_rw_lock, RW_READER); 53830dc2366fSVenugopal Iyer *grp_num = mip->mi_tx_groups[grp_index].mrg_index > 0 ? 53840dc2366fSVenugopal Iyer mip->mi_tx_groups[grp_index].mrg_index : grp_index; 53850dc2366fSVenugopal Iyer *type = mip->mi_tx_groups[grp_index].mrg_type; 53860dc2366fSVenugopal Iyer *n_rings = mip->mi_tx_groups[grp_index].mrg_cur_count; 53870dc2366fSVenugopal Iyer ring = mip->mi_tx_groups[grp_index].mrg_rings; 53880dc2366fSVenugopal Iyer for (index = 0; index < mip->mi_tx_groups[grp_index].mrg_cur_count; 53890dc2366fSVenugopal Iyer index++) { 53900dc2366fSVenugopal Iyer rings[index] = ring->mr_index; 53910dc2366fSVenugopal Iyer ring = ring->mr_next; 53920dc2366fSVenugopal Iyer } 53930dc2366fSVenugopal Iyer index = 0; 53940dc2366fSVenugopal Iyer /* Default group has an index of -1 */ 53950dc2366fSVenugopal Iyer if (mip->mi_tx_groups[grp_index].mrg_index < 0) { 53960dc2366fSVenugopal Iyer (void) strlcpy(clnts_name, "<default>,", 53970dc2366fSVenugopal Iyer MAXCLIENTNAMELEN); 53980dc2366fSVenugopal Iyer index += strlen("<default>,"); 53990dc2366fSVenugopal Iyer } 54000dc2366fSVenugopal Iyer for (mcip = mip->mi_tx_groups[grp_index].mrg_clients; mcip != NULL; 54010dc2366fSVenugopal Iyer mcip = mcip->mgc_next) { 54020dc2366fSVenugopal Iyer int name_len = strlen(mcip->mgc_client->mci_name); 54030dc2366fSVenugopal Iyer 54040dc2366fSVenugopal Iyer /* 54050dc2366fSVenugopal Iyer * MAXCLIENTNAMELEN is the buffer size reserved for client 54060dc2366fSVenugopal Iyer * names. 54070dc2366fSVenugopal Iyer * XXXX Formating the client name string needs to be moved 54080dc2366fSVenugopal Iyer * to user land when fixing the size of dhi_clnts in 54090dc2366fSVenugopal Iyer * dld_hwgrpinfo_t. We should use n_clients * client_name for 54100dc2366fSVenugopal Iyer * dhi_clntsin instead of MAXCLIENTNAMELEN 54110dc2366fSVenugopal Iyer */ 54120dc2366fSVenugopal Iyer if (index + name_len >= MAXCLIENTNAMELEN) { 54130dc2366fSVenugopal Iyer index = MAXCLIENTNAMELEN; 54140dc2366fSVenugopal Iyer break; 54150dc2366fSVenugopal Iyer } 54160dc2366fSVenugopal Iyer bcopy(mcip->mgc_client->mci_name, &(clnts_name[index]), 54170dc2366fSVenugopal Iyer name_len); 54180dc2366fSVenugopal Iyer index += name_len; 54190dc2366fSVenugopal Iyer clnts_name[index++] = ','; 54200dc2366fSVenugopal Iyer i++; 54210dc2366fSVenugopal Iyer } 54220dc2366fSVenugopal Iyer 54230dc2366fSVenugopal Iyer /* Get rid of the last , */ 54240dc2366fSVenugopal Iyer if (index > 0) 54250dc2366fSVenugopal Iyer clnts_name[index - 1] = '\0'; 54260dc2366fSVenugopal Iyer *n_clnts = i; 54270dc2366fSVenugopal Iyer rw_exit(&mip->mi_rw_lock); 54280dc2366fSVenugopal Iyer } 54290dc2366fSVenugopal Iyer 54300dc2366fSVenugopal Iyer /* 54310dc2366fSVenugopal Iyer * Return the group count for RX or TX. 54320dc2366fSVenugopal Iyer */ 5433da14cebeSEric Cheng uint_t 54340dc2366fSVenugopal Iyer mac_hwgrp_num(mac_handle_t mh, int type) 5435da14cebeSEric Cheng { 5436da14cebeSEric Cheng mac_impl_t *mip = (mac_impl_t *)mh; 5437da14cebeSEric Cheng 54380dc2366fSVenugopal Iyer /* 54390dc2366fSVenugopal Iyer * Return the Rx and Tx group count; for the Tx we need to 54400dc2366fSVenugopal Iyer * include the default too. 54410dc2366fSVenugopal Iyer */ 54420dc2366fSVenugopal Iyer return (type == MAC_RING_TYPE_RX ? mip->mi_rx_group_count : 54430dc2366fSVenugopal Iyer mip->mi_tx_groups != NULL ? mip->mi_tx_group_count + 1 : 0); 54440dc2366fSVenugopal Iyer } 54450dc2366fSVenugopal Iyer 54460dc2366fSVenugopal Iyer /* 54470dc2366fSVenugopal Iyer * The total number of free TX rings for this MAC. 54480dc2366fSVenugopal Iyer */ 54490dc2366fSVenugopal Iyer uint_t 54500dc2366fSVenugopal Iyer mac_txavail_get(mac_handle_t mh) 54510dc2366fSVenugopal Iyer { 54520dc2366fSVenugopal Iyer mac_impl_t *mip = (mac_impl_t *)mh; 54530dc2366fSVenugopal Iyer 54540dc2366fSVenugopal Iyer return (mip->mi_txrings_avail); 54550dc2366fSVenugopal Iyer } 54560dc2366fSVenugopal Iyer 54570dc2366fSVenugopal Iyer /* 54580dc2366fSVenugopal Iyer * The total number of free RX rings for this MAC. 54590dc2366fSVenugopal Iyer */ 54600dc2366fSVenugopal Iyer uint_t 54610dc2366fSVenugopal Iyer mac_rxavail_get(mac_handle_t mh) 54620dc2366fSVenugopal Iyer { 54630dc2366fSVenugopal Iyer mac_impl_t *mip = (mac_impl_t *)mh; 54640dc2366fSVenugopal Iyer 54650dc2366fSVenugopal Iyer return (mip->mi_rxrings_avail); 54660dc2366fSVenugopal Iyer } 54670dc2366fSVenugopal Iyer 54680dc2366fSVenugopal Iyer /* 54690dc2366fSVenugopal Iyer * The total number of reserved RX rings on this MAC. 54700dc2366fSVenugopal Iyer */ 54710dc2366fSVenugopal Iyer uint_t 54720dc2366fSVenugopal Iyer mac_rxrsvd_get(mac_handle_t mh) 54730dc2366fSVenugopal Iyer { 54740dc2366fSVenugopal Iyer mac_impl_t *mip = (mac_impl_t *)mh; 54750dc2366fSVenugopal Iyer 54760dc2366fSVenugopal Iyer return (mip->mi_rxrings_rsvd); 54770dc2366fSVenugopal Iyer } 54780dc2366fSVenugopal Iyer 54790dc2366fSVenugopal Iyer /* 54800dc2366fSVenugopal Iyer * The total number of reserved TX rings on this MAC. 54810dc2366fSVenugopal Iyer */ 54820dc2366fSVenugopal Iyer uint_t 54830dc2366fSVenugopal Iyer mac_txrsvd_get(mac_handle_t mh) 54840dc2366fSVenugopal Iyer { 54850dc2366fSVenugopal Iyer mac_impl_t *mip = (mac_impl_t *)mh; 54860dc2366fSVenugopal Iyer 54870dc2366fSVenugopal Iyer return (mip->mi_txrings_rsvd); 54880dc2366fSVenugopal Iyer } 54890dc2366fSVenugopal Iyer 54900dc2366fSVenugopal Iyer /* 54910dc2366fSVenugopal Iyer * Total number of free RX groups on this MAC. 54920dc2366fSVenugopal Iyer */ 54930dc2366fSVenugopal Iyer uint_t 54940dc2366fSVenugopal Iyer mac_rxhwlnksavail_get(mac_handle_t mh) 54950dc2366fSVenugopal Iyer { 54960dc2366fSVenugopal Iyer mac_impl_t *mip = (mac_impl_t *)mh; 54970dc2366fSVenugopal Iyer 54980dc2366fSVenugopal Iyer return (mip->mi_rxhwclnt_avail); 54990dc2366fSVenugopal Iyer } 55000dc2366fSVenugopal Iyer 55010dc2366fSVenugopal Iyer /* 55020dc2366fSVenugopal Iyer * Total number of RX groups reserved on this MAC. 55030dc2366fSVenugopal Iyer */ 55040dc2366fSVenugopal Iyer uint_t 55050dc2366fSVenugopal Iyer mac_rxhwlnksrsvd_get(mac_handle_t mh) 55060dc2366fSVenugopal Iyer { 55070dc2366fSVenugopal Iyer mac_impl_t *mip = (mac_impl_t *)mh; 55080dc2366fSVenugopal Iyer 55090dc2366fSVenugopal Iyer return (mip->mi_rxhwclnt_used); 55100dc2366fSVenugopal Iyer } 55110dc2366fSVenugopal Iyer 55120dc2366fSVenugopal Iyer /* 55130dc2366fSVenugopal Iyer * Total number of free TX groups on this MAC. 55140dc2366fSVenugopal Iyer */ 55150dc2366fSVenugopal Iyer uint_t 55160dc2366fSVenugopal Iyer mac_txhwlnksavail_get(mac_handle_t mh) 55170dc2366fSVenugopal Iyer { 55180dc2366fSVenugopal Iyer mac_impl_t *mip = (mac_impl_t *)mh; 55190dc2366fSVenugopal Iyer 55200dc2366fSVenugopal Iyer return (mip->mi_txhwclnt_avail); 55210dc2366fSVenugopal Iyer } 55220dc2366fSVenugopal Iyer 55230dc2366fSVenugopal Iyer /* 55240dc2366fSVenugopal Iyer * Total number of TX groups reserved on this MAC. 55250dc2366fSVenugopal Iyer */ 55260dc2366fSVenugopal Iyer uint_t 55270dc2366fSVenugopal Iyer mac_txhwlnksrsvd_get(mac_handle_t mh) 55280dc2366fSVenugopal Iyer { 55290dc2366fSVenugopal Iyer mac_impl_t *mip = (mac_impl_t *)mh; 55300dc2366fSVenugopal Iyer 55310dc2366fSVenugopal Iyer return (mip->mi_txhwclnt_used); 55320dc2366fSVenugopal Iyer } 55330dc2366fSVenugopal Iyer 55340dc2366fSVenugopal Iyer /* 55350dc2366fSVenugopal Iyer * Initialize the rings property for a mac client. A non-0 value for 55360dc2366fSVenugopal Iyer * rxring or txring specifies the number of rings required, a value 55370dc2366fSVenugopal Iyer * of MAC_RXRINGS_NONE/MAC_TXRINGS_NONE specifies that it doesn't need 55380dc2366fSVenugopal Iyer * any RX/TX rings and a value of MAC_RXRINGS_DONTCARE/MAC_TXRINGS_DONTCARE 55390dc2366fSVenugopal Iyer * means the system can decide whether it can give any rings or not. 55400dc2366fSVenugopal Iyer */ 55410dc2366fSVenugopal Iyer void 55420dc2366fSVenugopal Iyer mac_client_set_rings(mac_client_handle_t mch, int rxrings, int txrings) 55430dc2366fSVenugopal Iyer { 55440dc2366fSVenugopal Iyer mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 55450dc2366fSVenugopal Iyer mac_resource_props_t *mrp = MCIP_RESOURCE_PROPS(mcip); 55460dc2366fSVenugopal Iyer 55470dc2366fSVenugopal Iyer if (rxrings != MAC_RXRINGS_DONTCARE) { 55480dc2366fSVenugopal Iyer mrp->mrp_mask |= MRP_RX_RINGS; 55490dc2366fSVenugopal Iyer mrp->mrp_nrxrings = rxrings; 55500dc2366fSVenugopal Iyer } 55510dc2366fSVenugopal Iyer 55520dc2366fSVenugopal Iyer if (txrings != MAC_TXRINGS_DONTCARE) { 55530dc2366fSVenugopal Iyer mrp->mrp_mask |= MRP_TX_RINGS; 55540dc2366fSVenugopal Iyer mrp->mrp_ntxrings = txrings; 55550dc2366fSVenugopal Iyer } 5556da14cebeSEric Cheng } 5557098d2c75SRobert Mustacchi 5558098d2c75SRobert Mustacchi boolean_t 5559098d2c75SRobert Mustacchi mac_get_promisc_filtered(mac_client_handle_t mch) 5560098d2c75SRobert Mustacchi { 5561098d2c75SRobert Mustacchi mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 5562098d2c75SRobert Mustacchi 5563098d2c75SRobert Mustacchi return (mcip->mci_protect_flags & MPT_FLAG_PROMISC_FILTERED); 5564098d2c75SRobert Mustacchi } 5565098d2c75SRobert Mustacchi 5566098d2c75SRobert Mustacchi void 5567098d2c75SRobert Mustacchi mac_set_promisc_filtered(mac_client_handle_t mch, boolean_t enable) 5568098d2c75SRobert Mustacchi { 5569098d2c75SRobert Mustacchi mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 5570098d2c75SRobert Mustacchi 5571098d2c75SRobert Mustacchi ASSERT(MAC_PERIM_HELD((mac_handle_t)mcip->mci_mip)); 5572098d2c75SRobert Mustacchi if (enable) 5573098d2c75SRobert Mustacchi mcip->mci_protect_flags |= MPT_FLAG_PROMISC_FILTERED; 5574098d2c75SRobert Mustacchi else 5575098d2c75SRobert Mustacchi mcip->mci_protect_flags &= ~MPT_FLAG_PROMISC_FILTERED; 5576098d2c75SRobert Mustacchi } 5577