mac_bcast.c revision ae6aa22afeb444ae208c287e7227a4a7c877f17a
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/sysmacros.h>
#include <sys/mac_impl.h>
#include <sys/mac_client_impl.h>
#include <sys/mac_client_priv.h>
#include <sys/mac_flow_impl.h>
/*
* Broadcast and multicast traffic must be distributed to the MAC clients
* that are defined on top of the same MAC. The set of
* destinations to which a multicast packet must be sent is a subset
* of all MAC clients defined on top of the MAC. A MAC client can be member
* of more than one such subset.
*
* To accomodate these requirements, we introduce broadcast groups.
* A broadcast group is associated with a broadcast or multicast
* address. The members of a broadcast group consist of the MAC clients
* that should received copies of packets sent to the address
* associated with the group, and are defined on top of the
* same MAC.
*
* The broadcast groups defined on top of a MAC are chained,
* hanging off the mac_impl_t. The broadcast group id's are
* unique globally (tracked by mac_bcast_id).
*/
/*
* The same MAC client may be added for different <addr,vid> tuple,
* we maintain a ref count for the number of times it has been added
* to account for deleting the MAC client from the group.
*/
typedef struct mac_bcast_grp_mcip_s {
int mgb_client_ref;
typedef struct mac_bcast_grp_s { /* Protected by */
void *mbg_addr; /* SL */
static kmem_cache_t *mac_bcast_grp_cache;
static uint32_t mac_bcast_id = 0;
void
mac_bcast_init(void)
{
}
void
mac_bcast_fini(void)
{
}
mac_bcast_grp_mip(void *grp)
{
return (bcast_grp->mbg_mac_impl);
}
/*
* Free the specific broadcast group. Invoked when the last reference
* to the group is released.
*/
void
mac_bcast_grp_free(void *bcast_grp)
{
mip->mi_bcast_ngrps--;
}
/*
* arg1: broadcast group
* arg2: sender MAC client if it is being sent by a MAC client,
* NULL if it was received from the wire.
*/
void
{
uint_t i;
int err;
/*
* Pass a copy of the mp chain to every MAC client except the sender
* MAC client, if the packet was not received from the underlying NIC.
*
* The broadcast group lock should not be held across calls to
* the flow's callback function, since the same group could
* potentially be accessed from the same context. When the lock
* is reacquired, changes to the broadcast group while the lock
* was released are caught using a generation counter incremented
* each time the list of MAC clients associated with the broadcast
* group is changed.
*/
for (i = 0; i < grp->mbg_nclients_alloc; i++) {
continue;
/*
* Don't send a copy of the packet back to
* its sender.
*/
continue;
}
/*
* It is important to hold a reference on the
* flow_ent here.
*/
break;
/*
* Fix the checksum for packets originating
* from the local machine.
*/
break;
if (err != 0) {
continue;
}
/* update stats */
else
/*
* The list of MAC clients associated with the group
* was changed while the lock was released.
* Give up on the current packet.
*/
return;
}
}
/*
* The packet was sent from one of the MAC clients,
* so we need to send a copy of the packet to the
* underlying NIC so that it can be sent on the wire.
*/
} else {
}
}
/*
* Add the specified MAC client to the group corresponding to the specified
* broadcast or multicast address.
* Return 0 on success, or an errno value on failure.
*/
int
{
int rc = 0;
int i, index = -1;
/*
* Add the MAC client to the list of MAC clients associated
* with the group.
*/
if (addrtype == MAC_ADDRTYPE_MULTICAST) {
/*
* In case of a driver (say aggr), we need this information
* on a per MAC instance basis.
*/
break;
}
/*
* For multicast addresses, have the underlying MAC
* join the corresponding multicast group.
*/
if (rc != 0)
return (rc);
KM_SLEEP);
*prev_mi_addr = maddr;
} else {
prev_mi_addr = NULL;
}
/*
* We maintain a separate list for each MAC client. Get
* the entry or add, if it is not present.
*/
break;
}
KM_SLEEP);
*prev_mci_addr = maddr;
} else {
}
}
/* The list is protected by the perimeter */
break;
}
/*
* The group does not yet exist, create it.
*/
char flow_name[MAXFLOWNAMELEN];
grp);
/*
* Add a new flow to the underlying MAC.
*/
if (vid != 0) {
}
if (rc != 0) {
goto fail;
}
mip->mi_bcast_ngrps++;
/*
* Initial creation reference on the flow. This is released
* in the corresponding delete action i_mac_bcast_delete()
*/
/*
* When the multicast and broadcast packet is received
* by the underlying NIC, mac_rx_classify() will invoke
* mac_bcast_send() with arg2=NULL, which will cause
* mac_bcast_send() to send a copy of the packet(s)
* to every MAC client opened on top of the underlying MAC.
*
* When the mac_bcast_send() function is invoked from
* the transmit path of a MAC client, it will specify the
* transmitting MAC client as the arg2 value, which will
* allow mac_bcast_send() to skip that MAC client and not
* send it a copy of the packet.
*
* We program the classifier to dispatch matching broadcast
* packets to mac_bcast_send().
*/
if (rc != 0) {
goto fail;
}
}
/*
* Add the MAC client to the list of MAC clients associated
* with the group.
*/
for (i = 0; i < grp->mbg_nclients_alloc; i++) {
/*
* The MAC client was already added, say when we have
* different unicast addresses with the same vid.
* Just increment the ref and we are done.
*/
return (0);
index == -1) {
index = i;
}
}
sizeof (mac_bcast_grp_mcip_t), KM_SLEEP);
if (grp->mbg_nclients > 0) {
sizeof (mac_bcast_grp_mcip_t));
sizeof (mac_bcast_grp_mcip_t));
}
}
grp->mbg_nclients++;
/*
* Since we're adding to the list of MAC clients using that group,
* kick the generation count, which will allow mac_bcast_send()
* to detect that condition after re-acquiring the lock.
*/
grp->mbg_clients_gen++;
return (0);
fail:
if (prev_mi_addr != NULL) {
*prev_mi_addr = NULL;
}
if (prev_mci_addr != NULL) {
*prev_mci_addr = NULL;
}
return (rc);
}
/*
* Remove the specified MAC client from the group corresponding to
* the specific broadcast or multicast address.
*
* Note: mac_bcast_delete() calls mac_remove_flow() which
* will call cv_wait for fe_refcnt to drop to 0. So this function
* should not be called from interrupt or STREAMS context.
*/
void
{
uint_t i;
/* find the broadcast group. The list is protected by the perimeter */
break;
}
/*
* Remove the MAC client from the list of MAC clients associated
* with that broadcast group.
*
* We mark the mbg_clients[] location corresponding to the removed MAC
* client NULL and reuse that location when we add a new MAC client.
*/
for (i = 0; i < grp->mbg_nclients_alloc; i++) {
break;
}
/*
* If there are more references to this MAC client, then we let
* it remain till it goes to 0.
*/
goto update_maddr;
/*
* Since we're removing from the list of MAC clients using that group,
* kick the generation count, which will allow mac_bcast_send()
* to detect that condition.
*/
grp->mbg_clients_gen++;
if (--grp->mbg_nclients == 0) {
/*
* The last MAC client of the group was just removed.
* Unlink the current group from the list of groups
* defined on top of the underlying NIC. The group
* structure will stay around until the last reference
* is dropped.
*/
}
break;
}
}
break;
}
}
}
/*
* If the group itself is being removed, remove the
* corresponding flow from the underlying NIC.
*/
if (grp->mbg_nclients == 0) {
}
}
/*
*/
void
{
/*
* Walk the multicast address list and call the refresh function for
* each address.
*/
/*
* Save the next pointer just in case the refresh
* function's action causes the group entry to be
* freed.
* We won't be adding to this list as part of the
* refresh.
*/
}
}
/*
* ('arg' is 'flent') to all the addresses.
*/
void
{
/*
* Walk the multicast address list and call the refresh function for
* each address.
* Broadcast addresses are not added or removed through the multicast
* entry points, so don't include them as part of the refresh.
*/
/*
* Save the next pointer just in case the refresh
* function's action causes the group entry to be
* freed.
* We won't be adding to this list as part of the
* refresh.
*/
}
}