da14cebe459d3275048785f25bd869cb09b5307fEric Cheng/*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * CDDL HEADER START
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng *
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * The contents of this file are subject to the terms of the
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Common Development and Distribution License (the "License").
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * You may not use this file except in compliance with the License.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng *
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * or http://www.opensolaris.org/os/licensing.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * See the License for the specific language governing permissions
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * and limitations under the License.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng *
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * When distributing Covered Code, include this CDDL HEADER in each
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * If applicable, add the following below this CDDL HEADER, with the
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * fields enclosed by brackets "[]" replaced with your own identifying
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * information: Portions Copyright [yyyy] [name of copyright owner]
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng *
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * CDDL HEADER END
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng/*
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Use is subject to license terms.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include <sys/types.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include <sys/sysmacros.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include <sys/conf.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include <sys/cmn_err.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include <sys/list.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include <sys/kmem.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include <sys/stream.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include <sys/modctl.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include <sys/ddi.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include <sys/sunddi.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include <sys/atomic.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include <sys/stat.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include <sys/modhash.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include <sys/strsubr.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include <sys/strsun.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include <sys/sdt.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include <sys/mac.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include <sys/mac_impl.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include <sys/mac_client_impl.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include <sys/mac_client_priv.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng#include <sys/mac_flow_impl.h>
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng/*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Broadcast and multicast traffic must be distributed to the MAC clients
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * that are defined on top of the same MAC. The set of
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * destinations to which a multicast packet must be sent is a subset
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * of all MAC clients defined on top of the MAC. A MAC client can be member
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * of more than one such subset.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng *
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * To accomodate these requirements, we introduce broadcast groups.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * A broadcast group is associated with a broadcast or multicast
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * address. The members of a broadcast group consist of the MAC clients
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * that should received copies of packets sent to the address
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * associated with the group, and are defined on top of the
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * same MAC.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng *
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * The broadcast groups defined on top of a MAC are chained,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * hanging off the mac_impl_t. The broadcast group id's are
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * unique globally (tracked by mac_bcast_id).
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng/*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * The same MAC client may be added for different <addr,vid> tuple,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * we maintain a ref count for the number of times it has been added
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * to account for deleting the MAC client from the group.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Chengtypedef struct mac_bcast_grp_mcip_s {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_client_impl_t *mgb_client;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng int mgb_client_ref;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng} mac_bcast_grp_mcip_t;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengtypedef struct mac_bcast_grp_s { /* Protected by */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng struct mac_bcast_grp_s *mbg_next; /* SL */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng void *mbg_addr; /* SL */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng uint16_t mbg_vid; /* SL */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_impl_t *mbg_mac_impl; /* WO */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_addrtype_t mbg_addrtype; /* WO */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng flow_entry_t *mbg_flow_ent; /* WO */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_bcast_grp_mcip_t *mbg_clients; /* mi_rw_lock */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng uint_t mbg_nclients; /* mi_rw_lock */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng uint_t mbg_nclients_alloc; /* SL */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng uint64_t mbg_clients_gen; /* mi_rw_lock */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng uint32_t mbg_id; /* atomic */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng} mac_bcast_grp_t;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic kmem_cache_t *mac_bcast_grp_cache;
da14cebe459d3275048785f25bd869cb09b5307fEric Chengstatic uint32_t mac_bcast_id = 0;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengvoid
da14cebe459d3275048785f25bd869cb09b5307fEric Chengmac_bcast_init(void)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_bcast_grp_cache = kmem_cache_create("mac_bcast_grp_cache",
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng sizeof (mac_bcast_grp_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengvoid
da14cebe459d3275048785f25bd869cb09b5307fEric Chengmac_bcast_fini(void)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng kmem_cache_destroy(mac_bcast_grp_cache);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Chengmac_impl_t *
da14cebe459d3275048785f25bd869cb09b5307fEric Chengmac_bcast_grp_mip(void *grp)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_bcast_grp_t *bcast_grp = grp;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return (bcast_grp->mbg_mac_impl);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng/*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Free the specific broadcast group. Invoked when the last reference
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * to the group is released.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Chengvoid
da14cebe459d3275048785f25bd869cb09b5307fEric Chengmac_bcast_grp_free(void *bcast_grp)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_bcast_grp_t *grp = bcast_grp;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_impl_t *mip = grp->mbg_mac_impl;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ASSERT(grp->mbg_addr != NULL);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng kmem_free(grp->mbg_addr, mip->mi_type->mt_addr_length);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng kmem_free(grp->mbg_clients,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp->mbg_nclients_alloc * sizeof (mac_bcast_grp_mcip_t));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mip->mi_bcast_ngrps--;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng kmem_cache_free(mac_bcast_grp_cache, grp);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng/*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * arg1: broadcast group
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * arg2: sender MAC client if it is being sent by a MAC client,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * NULL if it was received from the wire.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Chengvoid
da14cebe459d3275048785f25bd869cb09b5307fEric Chengmac_bcast_send(void *arg1, void *arg2, mblk_t *mp_chain, boolean_t is_loopback)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_bcast_grp_t *grp = arg1;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_client_impl_t *src_mcip = arg2, *dst_mcip;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_impl_t *mip = grp->mbg_mac_impl;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng uint64_t gen;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng uint_t i;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mblk_t *mp_chain1;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng flow_entry_t *flent;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng int err;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng rw_enter(&mip->mi_rw_lock, RW_READER);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Pass a copy of the mp chain to every MAC client except the sender
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * MAC client, if the packet was not received from the underlying NIC.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng *
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * The broadcast group lock should not be held across calls to
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * the flow's callback function, since the same group could
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * potentially be accessed from the same context. When the lock
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * is reacquired, changes to the broadcast group while the lock
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * was released are caught using a generation counter incremented
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * each time the list of MAC clients associated with the broadcast
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * group is changed.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng for (i = 0; i < grp->mbg_nclients_alloc; i++) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng dst_mcip = grp->mbg_clients[i].mgb_client;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (dst_mcip == NULL)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng continue;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng flent = dst_mcip->mci_flent;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (flent == NULL || dst_mcip == src_mcip) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Don't send a copy of the packet back to
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * its sender.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng continue;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * It is important to hold a reference on the
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * flow_ent here.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if ((mp_chain1 = mac_copymsgchain_cksum(mp_chain)) == NULL)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng break;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Fix the checksum for packets originating
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * from the local machine.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if ((src_mcip != NULL) &&
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng (mp_chain1 = mac_fix_cksum(mp_chain1)) == NULL)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng break;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng FLOW_TRY_REFHOLD(flent, err);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (err != 0) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng freemsgchain(mp_chain1);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng continue;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng gen = grp->mbg_clients_gen;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng rw_exit(&mip->mi_rw_lock);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng DTRACE_PROBE4(mac__bcast__send__to, mac_client_impl_t *,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng src_mcip, flow_fn_t, dst_mcip->mci_flent->fe_cb_fn,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng void *, dst_mcip->mci_flent->fe_cb_arg1,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng void *, dst_mcip->mci_flent->fe_cb_arg2);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng (dst_mcip->mci_flent->fe_cb_fn)(dst_mcip->mci_flent->fe_cb_arg1,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng dst_mcip->mci_flent->fe_cb_arg2, mp_chain1, is_loopback);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng FLOW_REFRELE(flent);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng rw_enter(&mip->mi_rw_lock, RW_READER);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* update stats */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer if (grp->mbg_addrtype == MAC_ADDRTYPE_MULTICAST) {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer MCIP_STAT_UPDATE(dst_mcip, multircv, 1);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer MCIP_STAT_UPDATE(dst_mcip, multircvbytes,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer msgdsize(mp_chain));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer } else {
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer MCIP_STAT_UPDATE(dst_mcip, brdcstrcv, 1);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer MCIP_STAT_UPDATE(dst_mcip, brdcstrcvbytes,
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer msgdsize(mp_chain));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (grp->mbg_clients_gen != gen) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * The list of MAC clients associated with the group
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * was changed while the lock was released.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Give up on the current packet.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng rw_exit(&mip->mi_rw_lock);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng freemsgchain(mp_chain);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng rw_exit(&mip->mi_rw_lock);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (src_mcip != NULL) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * The packet was sent from one of the MAC clients,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * so we need to send a copy of the packet to the
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * underlying NIC so that it can be sent on the wire.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer MCIP_STAT_UPDATE(src_mcip, multixmt, 1);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer MCIP_STAT_UPDATE(src_mcip, multixmtbytes, msgdsize(mp_chain));
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer MCIP_STAT_UPDATE(src_mcip, brdcstxmt, 1);
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer MCIP_STAT_UPDATE(src_mcip, brdcstxmtbytes, msgdsize(mp_chain));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
0dc2366f7b9f9f36e10909b1e95edbf2a261c2acVenugopal Iyer MAC_TX(mip, mip->mi_default_tx_ring, mp_chain, src_mcip);
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai if (mp_chain != NULL)
4eaa471005973e11a6110b69fe990530b3b95a38Rishi Srivatsavai freemsgchain(mp_chain);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng } else {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng freemsgchain(mp_chain);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng/*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Add the specified MAC client to the group corresponding to the specified
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * broadcast or multicast address.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Return 0 on success, or an errno value on failure.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Chengint
da14cebe459d3275048785f25bd869cb09b5307fEric Chengmac_bcast_add(mac_client_impl_t *mcip, const uint8_t *addr, uint16_t vid,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_addrtype_t addrtype)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_impl_t *mip = mcip->mci_mip;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_bcast_grp_t *grp = NULL, **last_grp;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng size_t addr_len = mip->mi_type->mt_addr_length;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng int rc = 0;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng int i, index = -1;
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer mac_mcast_addrs_t **prev_mi_addr = NULL;
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer mac_mcast_addrs_t **prev_mci_addr = NULL;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ASSERT(addrtype == MAC_ADDRTYPE_MULTICAST ||
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng addrtype == MAC_ADDRTYPE_BROADCAST);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer /*
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer * Add the MAC client to the list of MAC clients associated
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer * with the group.
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer */
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer if (addrtype == MAC_ADDRTYPE_MULTICAST) {
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer mac_mcast_addrs_t *maddr;
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer /*
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer * In case of a driver (say aggr), we need this information
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer * on a per MAC instance basis.
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer */
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer prev_mi_addr = &mip->mi_mcast_addrs;
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer for (maddr = *prev_mi_addr; maddr != NULL;
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer prev_mi_addr = &maddr->mma_next, maddr = maddr->mma_next) {
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer if (bcmp(maddr->mma_addr, addr, addr_len) == 0)
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer break;
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer }
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer if (maddr == NULL) {
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer /*
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer * For multicast addresses, have the underlying MAC
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer * join the corresponding multicast group.
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer */
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer rc = mip->mi_multicst(mip->mi_driver, B_TRUE, addr);
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer if (rc != 0)
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer return (rc);
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer maddr = kmem_zalloc(sizeof (mac_mcast_addrs_t),
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer KM_SLEEP);
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer bcopy(addr, maddr->mma_addr, addr_len);
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer *prev_mi_addr = maddr;
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer } else {
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer prev_mi_addr = NULL;
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer }
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer maddr->mma_ref++;
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer /*
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer * We maintain a separate list for each MAC client. Get
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer * the entry or add, if it is not present.
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer */
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer prev_mci_addr = &mcip->mci_mcast_addrs;
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer for (maddr = *prev_mci_addr; maddr != NULL;
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer prev_mci_addr = &maddr->mma_next, maddr = maddr->mma_next) {
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer if (bcmp(maddr->mma_addr, addr, addr_len) == 0)
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer break;
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer }
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer if (maddr == NULL) {
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer maddr = kmem_zalloc(sizeof (mac_mcast_addrs_t),
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer KM_SLEEP);
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer bcopy(addr, maddr->mma_addr, addr_len);
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer *prev_mci_addr = maddr;
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer } else {
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer prev_mci_addr = NULL;
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer }
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer maddr->mma_ref++;
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer }
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* The list is protected by the perimeter */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng last_grp = &mip->mi_bcast_grp;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng for (grp = *last_grp; grp != NULL;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng last_grp = &grp->mbg_next, grp = grp->mbg_next) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (bcmp(grp->mbg_addr, addr, addr_len) == 0 &&
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp->mbg_vid == vid)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng break;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (grp == NULL) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * The group does not yet exist, create it.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng flow_desc_t flow_desc;
da0006029e69465355313f503741ac6ebe0d513bGirish Moodalbail char flow_name[MAXFLOWNAMELEN];
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp = kmem_cache_alloc(mac_bcast_grp_cache, KM_SLEEP);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng bzero(grp, sizeof (mac_bcast_grp_t));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp->mbg_next = NULL;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp->mbg_mac_impl = mip;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng DTRACE_PROBE1(mac__bcast__add__new__group, mac_bcast_grp_t *,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp->mbg_addr = kmem_zalloc(addr_len, KM_SLEEP);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng bcopy(addr, grp->mbg_addr, addr_len);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp->mbg_addrtype = addrtype;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp->mbg_vid = vid;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Add a new flow to the underlying MAC.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng bzero(&flow_desc, sizeof (flow_desc));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng bcopy(addr, &flow_desc.fd_dst_mac, addr_len);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng flow_desc.fd_mac_len = (uint32_t)addr_len;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng flow_desc.fd_mask = FLOW_LINK_DST;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (vid != 0) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng flow_desc.fd_vid = vid;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng flow_desc.fd_mask |= FLOW_LINK_VID;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
1a5e258f5471356ca102c7176637cdce45bac147Josef 'Jeff' Sipek grp->mbg_id = atomic_inc_32_nv(&mac_bcast_id);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng (void) sprintf(flow_name,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng "mac/%s/mcast%d", mip->mi_name, grp->mbg_id);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng rc = mac_flow_create(&flow_desc, NULL, flow_name,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp, FLOW_MCAST, &grp->mbg_flow_ent);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (rc != 0) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng kmem_free(grp->mbg_addr, addr_len);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng kmem_cache_free(mac_bcast_grp_cache, grp);
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer goto fail;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp->mbg_flow_ent->fe_mbg = grp;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mip->mi_bcast_ngrps++;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Initial creation reference on the flow. This is released
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * in the corresponding delete action i_mac_bcast_delete()
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng FLOW_REFHOLD(grp->mbg_flow_ent);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * When the multicast and broadcast packet is received
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * by the underlying NIC, mac_rx_classify() will invoke
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * mac_bcast_send() with arg2=NULL, which will cause
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * mac_bcast_send() to send a copy of the packet(s)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * to every MAC client opened on top of the underlying MAC.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng *
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * When the mac_bcast_send() function is invoked from
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * the transmit path of a MAC client, it will specify the
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * transmitting MAC client as the arg2 value, which will
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * allow mac_bcast_send() to skip that MAC client and not
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * send it a copy of the packet.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng *
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * We program the classifier to dispatch matching broadcast
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * packets to mac_bcast_send().
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp->mbg_flow_ent->fe_cb_fn = mac_bcast_send;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp->mbg_flow_ent->fe_cb_arg1 = grp;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp->mbg_flow_ent->fe_cb_arg2 = NULL;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng rc = mac_flow_add(mip->mi_flow_tab, grp->mbg_flow_ent);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (rc != 0) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng FLOW_FINAL_REFRELE(grp->mbg_flow_ent);
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer goto fail;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng *last_grp = grp;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ASSERT(grp->mbg_addrtype == addrtype);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Add the MAC client to the list of MAC clients associated
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * with the group.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng rw_enter(&mip->mi_rw_lock, RW_WRITER);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng for (i = 0; i < grp->mbg_nclients_alloc; i++) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * The MAC client was already added, say when we have
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * different unicast addresses with the same vid.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Just increment the ref and we are done.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (grp->mbg_clients[i].mgb_client == mcip) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp->mbg_clients[i].mgb_client_ref++;
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer rw_exit(&mip->mi_rw_lock);
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer return (0);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng } else if (grp->mbg_clients[i].mgb_client == NULL &&
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng index == -1) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng index = i;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (grp->mbg_nclients_alloc == grp->mbg_nclients) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_bcast_grp_mcip_t *new_clients;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng uint_t new_size = grp->mbg_nclients+1;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng new_clients = kmem_zalloc(new_size *
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng sizeof (mac_bcast_grp_mcip_t), KM_SLEEP);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (grp->mbg_nclients > 0) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ASSERT(grp->mbg_clients != NULL);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng bcopy(grp->mbg_clients, new_clients, grp->mbg_nclients *
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng sizeof (mac_bcast_grp_mcip_t));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng kmem_free(grp->mbg_clients, grp->mbg_nclients *
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng sizeof (mac_bcast_grp_mcip_t));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp->mbg_clients = new_clients;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp->mbg_nclients_alloc = new_size;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng index = new_size - 1;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ASSERT(index != -1);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp->mbg_clients[index].mgb_client = mcip;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp->mbg_clients[index].mgb_client_ref = 1;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp->mbg_nclients++;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Since we're adding to the list of MAC clients using that group,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * kick the generation count, which will allow mac_bcast_send()
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * to detect that condition after re-acquiring the lock.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp->mbg_clients_gen++;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng rw_exit(&mip->mi_rw_lock);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng return (0);
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyerfail:
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer if (prev_mi_addr != NULL) {
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer kmem_free(*prev_mi_addr, sizeof (mac_mcast_addrs_t));
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer *prev_mi_addr = NULL;
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer (void) mip->mi_multicst(mip->mi_driver, B_FALSE, addr);
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer }
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer if (prev_mci_addr != NULL) {
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer kmem_free(*prev_mci_addr, sizeof (mac_mcast_addrs_t));
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer *prev_mci_addr = NULL;
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer }
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer return (rc);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng/*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Remove the specified MAC client from the group corresponding to
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * the specific broadcast or multicast address.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng *
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Note: mac_bcast_delete() calls mac_remove_flow() which
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * will call cv_wait for fe_refcnt to drop to 0. So this function
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * should not be called from interrupt or STREAMS context.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Chengvoid
da14cebe459d3275048785f25bd869cb09b5307fEric Chengmac_bcast_delete(mac_client_impl_t *mcip, const uint8_t *addr, uint16_t vid)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_impl_t *mip = mcip->mci_mip;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_bcast_grp_t *grp = NULL, **prev;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng size_t addr_len = mip->mi_type->mt_addr_length;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng flow_entry_t *flent;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng uint_t i;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_mcast_addrs_t *maddr = NULL;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_mcast_addrs_t **mprev;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /* find the broadcast group. The list is protected by the perimeter */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng prev = &mip->mi_bcast_grp;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng for (grp = mip->mi_bcast_grp; grp != NULL; prev = &grp->mbg_next,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp = grp->mbg_next) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (bcmp(grp->mbg_addr, addr, addr_len) == 0 &&
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp->mbg_vid == vid)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng break;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ASSERT(grp != NULL);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Remove the MAC client from the list of MAC clients associated
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * with that broadcast group.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng *
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * We mark the mbg_clients[] location corresponding to the removed MAC
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * client NULL and reuse that location when we add a new MAC client.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng rw_enter(&mip->mi_rw_lock, RW_WRITER);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng for (i = 0; i < grp->mbg_nclients_alloc; i++) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (grp->mbg_clients[i].mgb_client == mcip)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng break;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ASSERT(i < grp->mbg_nclients_alloc);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * If there are more references to this MAC client, then we let
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * it remain till it goes to 0.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (--grp->mbg_clients[i].mgb_client_ref > 0)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng goto update_maddr;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp->mbg_clients[i].mgb_client = NULL;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp->mbg_clients[i].mgb_client_ref = 0;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Since we're removing from the list of MAC clients using that group,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * kick the generation count, which will allow mac_bcast_send()
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * to detect that condition.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng grp->mbg_clients_gen++;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (--grp->mbg_nclients == 0) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * The last MAC client of the group was just removed.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Unlink the current group from the list of groups
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * defined on top of the underlying NIC. The group
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * structure will stay around until the last reference
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * is dropped.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng *prev = grp->mbg_next;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Chengupdate_maddr:
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer rw_exit(&mip->mi_rw_lock);
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (grp->mbg_addrtype == MAC_ADDRTYPE_MULTICAST) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mprev = &mcip->mci_mcast_addrs;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng for (maddr = mcip->mci_mcast_addrs; maddr != NULL;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mprev = &maddr->mma_next, maddr = maddr->mma_next) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (bcmp(grp->mbg_addr, maddr->mma_addr,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mip->mi_type->mt_addr_length) == 0)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng break;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ASSERT(maddr != NULL);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (--maddr->mma_ref == 0) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng *mprev = maddr->mma_next;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng maddr->mma_next = NULL;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng kmem_free(maddr, sizeof (mac_mcast_addrs_t));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mprev = &mip->mi_mcast_addrs;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng for (maddr = mip->mi_mcast_addrs; maddr != NULL;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mprev = &maddr->mma_next, maddr = maddr->mma_next) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (bcmp(grp->mbg_addr, maddr->mma_addr,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mip->mi_type->mt_addr_length) == 0)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng break;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ASSERT(maddr != NULL);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (--maddr->mma_ref == 0) {
ae6aa22afeb444ae208c287e7227a4a7c877f17aVenugopal Iyer (void) mip->mi_multicst(mip->mi_driver, B_FALSE, addr);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng *mprev = maddr->mma_next;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng maddr->mma_next = NULL;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng kmem_free(maddr, sizeof (mac_mcast_addrs_t));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * If the group itself is being removed, remove the
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * corresponding flow from the underlying NIC.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng flent = grp->mbg_flow_ent;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng if (grp->mbg_nclients == 0) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_flow_remove(mip->mi_flow_tab, flent, B_FALSE);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_flow_wait(flent, FLOW_DRIVER_UPCALL);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng FLOW_FINAL_REFRELE(flent);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng/*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * This will be called by a driver, such as aggr, when a port is added/removed
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * to add/remove the port to/from all the multcast addresses for that aggr.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Chengvoid
da14cebe459d3275048785f25bd869cb09b5307fEric Chengmac_bcast_refresh(mac_impl_t *mip, mac_multicst_t refresh_fn, void *arg,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng boolean_t add)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_mcast_addrs_t *grp, *next;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ASSERT(refresh_fn != NULL);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Walk the multicast address list and call the refresh function for
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * each address.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng for (grp = mip->mi_mcast_addrs; grp != NULL; grp = next) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Save the next pointer just in case the refresh
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * function's action causes the group entry to be
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * freed.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * We won't be adding to this list as part of the
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * refresh.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng next = grp->mma_next;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng refresh_fn(arg, add, grp->mma_addr);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng/*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Walk the MAC client's multicast address list and add/remove the addr/vid
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * ('arg' is 'flent') to all the addresses.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Chengvoid
da14cebe459d3275048785f25bd869cb09b5307fEric Chengmac_client_bcast_refresh(mac_client_impl_t *mcip, mac_multicst_t refresh_fn,
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng void *arg, boolean_t add)
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng{
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_mcast_addrs_t *grp, *next;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng mac_impl_t *mip = mcip->mci_mip;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ASSERT(refresh_fn != NULL);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Walk the multicast address list and call the refresh function for
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * each address.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Broadcast addresses are not added or removed through the multicast
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * entry points, so don't include them as part of the refresh.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng for (grp = mcip->mci_mcast_addrs; grp != NULL; grp = next) {
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng /*
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * Save the next pointer just in case the refresh
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * function's action causes the group entry to be
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * freed.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * We won't be adding to this list as part of the
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng * refresh.
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng */
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng next = grp->mma_next;
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng refresh_fn(arg, add, grp->mma_addr);
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng }
da14cebe459d3275048785f25bd869cb09b5307fEric Cheng}