vnic_bcast.c revision 843e19887f64dde75055cf8842fc4db2171eff45
/*
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/sysmacros.h>
#include <sys/vnic_impl.h>
/*
* Broadcast and multicast traffic must be distributed to the VNICs
* that are defined on top of the same underlying NIC. The set of
* destinations to which a multicast packet must be sent is a subset
* of all VNICs defined on top of the same NIC. A VNIC 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 VNICs
* that should received copies of packets sent to the address
* associated with the group, and are defined on top of the
* same underlying NIC. The underlying NIC is always implicetely
* part of the group.
*
* The broadcast groups defined on top of a underlying NIC are chained,
* hanging off vnic_mac_t structures.
*/
typedef struct vnic_bcast_grp_s {
struct vnic_bcast_grp_s *vbg_next;
void *vbg_addr;
#define VNIC_BCAST_GRP_REFHOLD(grp) { \
}
#define VNIC_BCAST_GRP_REFRELE(grp) { \
membar_exit(); \
}
static kmem_cache_t *vnic_bcast_grp_cache;
void
vnic_bcast_init(void)
{
}
void
vnic_bcast_fini(void)
{
}
/*
* Free the specific broadcast group. Invoked when the last reference
* to the group is released.
*/
static void
{
/*
* The address is a multicast address, have the
* underlying NIC leave the multicast group.
*/
}
}
void
{
const vnic_flow_fn_info_t *fn_info;
uint_t i;
/*
* Pass a copy of the mp chain to every VNIC except the sender
* VNIC, if the packet was not received from the underlying NIC.
*
* The broadcast group lock 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 VNICs associated with the broadcast group
* is changed.
*/
for (i = 0; i < grp->vbg_nvnics; i++) {
if (vnic == sender_vnic)
continue;
/*
* If this consumer is in promiscuous mode then it
* will have already seen a copy of the packet.
*/
if (vnic->vn_promisc)
continue;
/*
* It is important to hold a reference on the
* flow_ent here. vnic_dev_delete() may be waiting
* to delete the vnic after removing it from grp.
*/
break;
/*
* Fix the checksum for packets originating
* from the local machine.
*/
if ((sender_vnic != NULL) &&
break;
/* update stats */
vnic->vn_stat_multircv++;
else
/*
* The list of VNICs associated with the group
* was changed while the lock was released.
* Give up on the current packet.
*/
goto bail;
}
}
if (sender_vnic != NULL) {
/*
* The packet was sent from one of the VNICs
* (vnic_active_tx()), or from the active MAC
* (vnic_active_tx()). In both cases, we need to send
* a copy of the packet to the underlying NIC so that
* it can be sent on the wire.
*/
}
}
/*
* Called while sending a packet from one of the VNICs.
* Make sure the active interface gets its copy.
*/
}
} else {
}
bail:
}
/*
* Add the specified VNIC 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;
/*
* Does a group with the specified broadcast address already
* exist for the underlying NIC?
*/
break;
}
/*
* The group does not yet exist, create it.
*/
/*
* Add a new flow for the broadcast address.
*/
goto bail;
}
/*
* When the multicast and broadcast packet is received
* by the underlying NIC, mac_rx_classify() will invoke
* vnic_bcast_send() with arg2=NULL, which will cause
* vnic_bcast_send() to send a copy of the packet(s)
* to every VNIC defined on top of the underlying MAC.
*
* When the vnic_bcast_send() function is invoked from
* the VNIC transmit path, it will specify the transmitting
* VNIC as the arg2 value, which will allow vnic_bcast_send()
* to skip that VNIC and not send it a copy of the packet.
*
* We program the classifier to dispatch matching broadcast
* packets to vnic_bcast_send().
* We need a ring allocated for this bcast flow, so that
* later snooping of the underlying MAC uses the same scheme
* of intercepting the ring's receiver to mac_rx_promisc().
* For the economy of hardware resources, we command the MAC
* classifier to use a soft ring for these broadcast and
* multicast flows.
*/
/*
* For multicast addresses, have the underlying MAC
* join the corresponsing multicast group.
*/
if ((addrtype == MAC_ADDRTYPE_MULTICAST) &&
grp->vbg_flow_ent);
goto bail;
}
}
/*
* Add the VNIC to the list of VNICs associated with the group.
*/
KM_SLEEP);
if (grp->vbg_nvnics) {
sizeof (vnic_t *));
sizeof (vnic_t *));
}
}
/*
* Since we're adding to the list of VNICs using that group,
* kick the generation count, which will allow vnic_bcast_send()
* to detect that condition.
*/
grp->vbg_vnics_gen++;
bail:
}
return (rc);
}
/*
* Remove the specified VNIC from the group corresponding to
* the specific broadcast or multicast address.
*
* Note: vnic_bcast_delete() calls net_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. The only
* callers are vnic_dev_delete() and vnic_m_multicst() (both of
* which are called from taskq thread context).
*/
void
{
uint_t i;
/* find the broadcast group */
break;
}
/*
* Remove the VNIC from the list of VNICs associated with that
* broadcast group.
*
* We keep the vbg_vnics[] always compact by repacing
* the removed vnic with the last non NULL element in that array.
*/
for (i = 0; i < grp->vbg_nvnics; i++) {
break;
}
} else {
}
/*
* Since we're removing from the list of VNICs using that group,
* kick the generation count, which will allow vnic_bcast_send()
* to detect that condition.
*/
grp->vbg_vnics_gen++;
if (--grp->vbg_nvnics == 0) {
/*
* 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.
*/
}
/*
* If the group itself is being removed, remove the
* corresponding flow from the underlying NIC.
*/
if (removing_grp) {
grp->vbg_flow_ent);
}
}