/*
* 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 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* IEEE 802.3ad Link Aggregation - Link Aggregation MAC ports.
*
* Implements the functions needed to manage the MAC ports that are
* part of Link Aggregation groups.
*/
#include <sys/sysmacros.h>
#include <sys/id_space.h>
#include <sys/aggr_impl.h>
static void aggr_port_notify_cb(void *, mac_notify_type_t);
/*ARGSUSED*/
static int
{
return (0);
}
/*ARGSUSED*/
static void
{
}
void
aggr_port_init(void)
{
sizeof (aggr_port_t), 0, aggr_port_constructor,
/*
* Allocate a id space to manage port identification. The range of
* the arena will be from 1 to UINT16_MAX, because the LACP protocol
* specifies 16-bit unique identification.
*/
}
void
aggr_port_fini(void)
{
/*
* This function is called only after all groups have been
* freed. This ensures that there are no remaining allocated
* ports when this function is invoked.
*/
}
/* ARGSUSED */
void
{
/* add the port's receive callback */
/*
* Hold a reference of the grp and the port and this reference will
* be released when the thread exits.
*
* The reference on the port is used for aggr_port_delete() to
* continue without waiting for the thread to exit; the reference
* on the grp is used for aggr_grp_delete() to wait for the thread
* to exit before calling mac_unregister().
*
* Note that these references will be released either in
* aggr_port_delete() when mac_notify_remove() succeeds, or in
* the aggr_port_notify_cb() callback when the port is deleted
* (lp_closing is set).
*/
}
/* ARGSUSED */
int
aggr_port_t **pp)
{
int err;
uint_t i;
return (err);
goto fail;
}
/*
* If the underlying MAC does not support link update notification, it
* can only be aggregated if `force' is set. This is because aggr
* depends on link notifications to attach ports whose link is up.
*/
if (!force) {
/*
* We borrow this error code to indicate that link
* notification is not supported.
*/
goto fail;
}
}
goto fail;
}
MAC_OPEN_FLAGS_IS_AGGR_PORT | MAC_OPEN_FLAGS_EXCLUSIVE)) != 0) {
goto fail;
}
goto fail;
}
/*
* As the underlying mac's current margin size is used to determine
* the margin size of the aggregation itself, request the underlying
* mac not to change to a smaller size.
*/
goto fail;
}
goto fail;
}
/* get the port's original MAC address */
/* initialize state */
port->lp_ifspeed = 0;
/*
* Save the current statistics of the port. They will be used
* later by aggr_m_stats() when aggregating the statistics of
* the constituent ports.
*/
for (i = 0; i < MAC_NSTAT; i++) {
}
for (i = 0; i < ETHER_NSTAT; i++) {
port->lp_ether_stat[i] =
}
/* LACP related state */
return (0);
fail:
return (err);
}
void
{
/*
* If the notification callback is already in process and waiting for
* the aggr grp's mac perimeter, don't wait (otherwise there would be
* deadlock). Otherwise, if mac_notify_remove() succeeds, we can
* release the reference held when mac_notify_add() is called.
*/
}
/*
* Inform the the port lacp timer thread to exit. Note that waiting
* for the thread to exit may cause deadlock since that thread may
* need to enter into the mac perimeter which we are currently in.
* It is fine to continue without waiting though since that thread
* is holding a reference of the port.
*/
/*
* Restore the port MAC address. Note it is called after the
* port's notification callback being removed. This prevent
* port's MAC_NOTE_UNICST notify callback function being called.
*/
}
void
{
}
/*
* Invoked upon receiving a MAC_NOTE_LINK notification for
* one of the constituent ports.
*/
{
/*
* link state change? For links that do not support link state
* notification, always assume the link is up.
*/
if (link_state == LINK_STATE_UP)
else
}
/* link duplex change? */
if (link_duplex == LINK_DUPLEX_FULL)
else
}
/* link speed changes? */
else
}
if (do_attach) {
/* attempt to attach the port to the aggregation */
} else if (do_detach) {
/* detach the port from the aggregation */
}
return (link_state_changed);
}
/*
* Invoked upon receiving a MAC_NOTE_UNICST for one of the constituent
* ports of a group.
*/
static void
{
/*
* If it is called when setting the MAC address to the
* aggregation group MAC address, do nothing.
*/
goto done;
}
/* save the new port MAC address */
/*
* If this port was used to determine the MAC address of
* the group, update the MAC address of the constituent
* ports.
*/
done:
}
/*
* Notification callback invoked by the MAC service module for
* a particular MAC port.
*/
static void
{
if (port->lp_closing) {
/*
* Release the reference so it is safe for aggr to call
* mac_unregister() now.
*/
return;
}
switch (type) {
case MAC_NOTE_TX:
break;
case MAC_NOTE_LINK:
break;
case MAC_NOTE_UNICST:
if (mac_addr_changed)
if (link_state_changed)
break;
default:
break;
}
}
int
{
if (port->lp_started)
return (0);
return (0);
}
void
{
if (!port->lp_started)
return;
/* update the port state */
}
int
{
int rc;
/* already in desired promiscous mode */
return (0);
if (on) {
if (rc != 0) {
return (rc);
}
} else {
}
return (0);
}
/*
* Set the MAC address of a port.
*/
int
{
}
/*
*/
int
{
if (add) {
} else {
return (0);
}
}
{
}
/*
* Add a non-primary unicast address to the underlying port. If the port
* supports HW Rx group, try to add the address into the HW Rx group of
* the port first. If that fails, or if the port does not support HW Rx
* group, enable the port's promiscous mode.
*/
int
{
int err;
/*
* If the underlying port support HW Rx group, add the mac to its
* RX group directly.
*/
return (0);
}
/*
* If that fails, or if the port does not support HW Rx group, enable
* the port's promiscous mode. (Note that we turn on the promiscous
* mode only if the port is already started.
*/
if (port->lp_started &&
return (err);
}
/*
* Walk through the unicast addresses that requires promiscous mode
* enabled on this port, and add this address to the end of the list.
*/
}
return (0);
}
/*
* Remove a non-primary unicast address from the underlying port. This address
* must has been added by aggr_port_addmac(). As a result, we probably need to
* remove the address from the port's HW Rx group, or to disable the port's
* promiscous mode.
*/
void
{
/*
* See whether this address is in the list of addresses that requires
* the port being promiscous mode.
*/
break;
}
/*
* This unicast address put the port into the promiscous mode,
* delete this address from the lp_prom_addr list. If this is
* the last address in that list, disable the promiscous mode
* if the aggregation is not in promiscous mode.
*/
} else {
}
}