vsw_phys.c revision ee03c681cedb48165922333190cdd8b230ffa073
/*
* 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 2008 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/ethernet.h>
#include <sys/machsystm.h>
#include <sys/mac_ether.h>
#include <sys/mach_descrip.h>
/* MAC Ring table functions. */
static vsw_queue_t *vsw_queue_create();
/* MAC layer routines */
static int vsw_unset_hw_addr(vsw_t *, int);
static int vsw_prog_if(vsw_t *);
/* Support functions */
static int vsw_prog_ports(vsw_t *);
void vsw_reconfig_hw(vsw_t *);
int vsw_get_hw_maddr(vsw_t *);
/*
* Tunables used in this file.
*/
extern int vsw_mac_open_retries;
extern boolean_t vsw_multi_ring_enable;
extern int vsw_mac_rx_rings;
/*
* Check to see if the card supports the setting of multiple unicst
* addresses.
*
* Returns 0 if card supports the programming of multiple unicast addresses,
* otherwise returns 1.
*/
int
{
return (1);
return (1);
}
return (0);
}
/*
* Program unicast and multicast addresses of vsw interface and the ports
* into the physical device.
*/
void
{
int rv;
/* program unicst addr of vsw interface in the physdev */
if (rv != 0) {
"!vsw%d: failed to program interface "
}
/*
* Notify the MAC layer of the changed address.
*/
}
/* program mcast addrs of vsw interface in the physdev */
continue;
if (rv == 0) {
} else {
}
}
}
/* program unicast address of ports in the physical device */
continue;
"!vsw%d: port:%d failed to set unicast address\n",
}
}
/* program multicast addresses of ports in the physdev */
continue;
if (rv == 0) {
} else {
}
}
}
}
/*
* Remove unicast and multicast addresses of vsw interface and the ports
* from the physical device.
*/
void
{
/*
* Remove unicast addr of vsw interfce
* from current physdev
*/
/*
* Remove mcast addrs of vsw interface
* from current physdev
*/
continue;
}
}
/*
* Remove unicast address of ports from the current physical device
*/
/* Remove address if was programmed into HW. */
continue;
}
/* Remove multicast addresses of ports from the current physdev */
continue;
}
}
}
/*
* Open the underlying physical device for access in layer2 mode.
* Returns:
* 0 on success
* EAGAIN if mac_open() fails due to the device being not available yet.
* EIO on any other failures.
*/
int
{
int rv;
/* already open */
return (0);
}
/* exceeded max retries */
return (EIO);
}
if (rv != 0) {
/*
* If mac_open() failed and the error indicates that the
* device is not available yet, then, we return EAGAIN to
* indicate that it needs to be retried.
* For example, this may happen during boot up, as the
* required link aggregation groups(devices) have not been
* created yet.
*/
return (EAGAIN);
} else {
return (EIO);
}
}
vswp->mac_open_retries = 0;
return (0);
}
/*
* Close the underlying physical device.
*/
void
{
}
}
/*
* Link into the MAC layer to gain access to the services provided by
* the underlying physical device driver (which should also have
* registered with the MAC layer).
*
* Only when in layer 2 mode.
*/
int
{
if (vsw_multi_ring_enable) {
/*
* Initialize the ring table.
*/
/*
* Register our rx callback function.
*/
vsw_rx_queue_cb, (void *)vswp);
/*
* Register our mac resource callback.
*/
/*
* Get the ring resources available to us from
* the mac below us.
*/
} else {
/*
* Just register our rx callback function
*/
}
/* Get the MAC tx fn */
/* start the interface */
goto mac_fail_exit;
}
return (0);
return (1);
}
void
{
if (vsw_multi_ring_enable) {
}
if (vswp->mresources)
}
}
/*
* Depending on the mode specified, the capabilites and capacity
* of the underlying device setup the physical device.
*
* If in layer 3 mode, then do nothing.
*
* If in layer 2 programmed mode attempt to program the unicast address
* associated with the port into the physical device. If this is not
* possible due to resource exhaustion or simply because the device does
* not support multiple unicast addresses then if required fallback onto
* putting the card into promisc mode.
*
* If in promisc mode then simply set the card into promisc mode.
*
* Returns 0 success, 1 on failure.
*/
int
{
int err;
return (0);
}
/*
* Attempt to program the unicast address into the HW.
*/
if (type == VSW_VNETPORT) {
} else {
}
/*
* Mark that attempt should be made to re-config sometime
* in future if a port is deleted.
*/
/*
* Only 1 mode specified, nothing more to do.
*/
return (err);
/*
* If promiscuous was next mode specified try to
* set the card into that mode.
*/
}
return (err);
}
if (err != 0)
return (err);
if (type == VSW_VNETPORT) {
} else {
}
return (0);
}
/*
* If in layer 3 mode do nothing.
*
* If in layer 2 switched mode remove the address from the physical
* device.
*
* If in layer 2 promiscuous mode disable promisc mode.
*
* Returns 0 on success.
*/
int
{
int rv;
return (0);
switch (type) {
case VSW_VNETPORT:
}
break;
case VSW_LOCALDEV:
}
break;
default:
/* should never happen */
ASSERT(0);
return (1);
}
return (rv);
}
/*
* Attempt to program a unicast address into HW.
*
* Returns 0 on sucess, 1 on failure.
*/
static int
{
void *mah;
return (rv);
if (rv == 0)
return (rv);
/*
* Its okay for the add to fail because we have exhausted
* all the resouces in the hardware device. Any other error
* we want to flag.
*/
"address %s into HW err (%d)",
}
return (rv);
}
/*
* Remove a unicast mac address which has previously been programmed
* into HW.
*
* Returns 0 on sucess, 1 on failure.
*/
static int
{
void *mah;
int rv;
return (1);
if (rv != 0) {
"from slot %d in device %s (err %d)",
return (1);
}
return (0);
}
/*
* Set network card into promisc mode.
*
* Returns 0 on success, 1 on failure.
*/
static int
{
return (1);
}
if (vswp->promisc_cnt++ == 0) {
vswp->promisc_cnt--;
return (1);
}
}
if (type == VSW_VNETPORT) {
} else {
}
return (0);
}
/*
* Turn off promiscuous mode on network card.
*
* Returns 0 on success, 1 on failure.
*/
static int
{
return (1);
}
if (--vswp->promisc_cnt == 0) {
vswp->promisc_cnt++;
return (1);
}
/*
* We are exiting promisc mode either because we were
* only in promisc mode because we had failed over from
* switched mode due to HW resource issues, or the user
* wanted the card in promisc mode for all the ports and
* the last port is now being deleted. Tweak the message
* accordingly.
*/
} else {
}
}
if (type == VSW_VNETPORT) {
} else {
}
return (0);
}
/*
* Determine whether or not we are operating in our prefered
* mode and if not whether the physical resources now allow us
* to operate in it.
*
* If a port is being removed should only be invoked after port has been
* removed from the port list.
*/
void
{
int s_idx;
return;
}
/*
* If we are in layer 2 (i.e. switched) or would like to be
* in layer 2 then check if any ports or the vswitch itself
* need to be programmed into the HW.
*
* This can happen in two cases - switched was specified as
* the prefered mode of operation but we exhausted the HW
* resources and so failed over to the next specifed mode,
* or switched was the only mode specified so after HW
* resources were exhausted there was nothing more we
* could do.
*/
else
return;
}
/*
* First, attempt to set the vswitch mac address into HW,
* if required.
*/
if (vsw_prog_if(vswp)) {
return;
}
/*
* Next, attempt to set any ports which have not yet been
* programmed into HW.
*/
if (vsw_prog_ports(vswp)) {
return;
}
/*
* By now we know that have programmed all desired ports etc
* into HW, so safe to mark reconfiguration as complete.
*/
}
/*
* Check to see if vsw itself is plumbed, and if so whether or not
* its mac address should be written into HW.
*
* Returns 0 if could set address, or didn't have to set it.
* Returns 1 if failed to set address.
*/
static int
{
return (1);
}
/*
* If previously when plumbed had had to place
* interface into promisc mode, now reverse that.
*
* Note that interface will only actually be set into
* programmed into HW.
*/
}
return (0);
}
/*
* Scan the port list for any ports which have not yet been set
* into HW. For those found attempt to program their mac addresses
* into the physical device.
*
* Returns 0 if able to program all required ports (can be 0) into HW.
* Returns 1 if failed to set at least one mac address.
*/
static int
{
vsw_port_t *tp;
int rv = 0;
rv = 1;
break;
}
/*
* If when this port had first attached we had
* had to place the interface into promisc mode,
* then now reverse that.
*
* Note that the interface will not actually
* change to non-promisc mode until all ports
* have been programmed.
*/
(void) vsw_unset_hw_promisc(vswp,
tp, VSW_VNETPORT);
}
}
return (rv);
}
static void
{
}
static void
{
int i;
vswp->mac_ring_tbl =
for (i = 0; i < vswp->mac_ring_tbl_sz; i++)
}
static void
{
int i;
for (i = 0; i < vswp->mac_ring_tbl_sz; i++) {
/*
* Destroy the queue.
*/
/*
* Re-initialize the structure.
*/
}
}
vswp->mac_ring_tbl_sz = 0;
}
/*
* Handle resource add callbacks from the driver below.
*/
static mac_resource_handle_t
{
int i;
/*
* Check to make sure we have the correct resource type.
*/
return (NULL);
/*
* Find a open entry in the ring table.
*/
for (i = 0; i < vswp->mac_ring_tbl_sz; i++) {
/*
* Check for an empty slot, if found, then setup queue
* and thread.
*/
/*
* Create the queue for this ring.
*/
vqp = vsw_queue_create();
/*
* Initialize the ring data structure.
*/
/*
* Create the worker thread.
*/
}
/*
* Make sure thread get's running state for
* this ring.
*/
}
/*
* If the thread is not running, cleanup.
*/
ringp);
}
}
return ((mac_resource_handle_t)ringp);
}
}
/*
* No slots in the ring table available.
*/
return (NULL);
}
static void
{
}
}
static vsw_queue_t *
{
return (vqp);
}
static void
{
}
static void
{
/*
* Set the state to running, since the thread is now active.
*/
/*
* Wait for work to do or the state has changed
* to not running.
*/
}
/*
* Process packets that we received from the interface.
*/
/* switch the chain of packets received */
}
}
/*
* We are drained and signal we are done.
*/
/*
* Exit lock and drain the remaining packets.
*/
/*
* Exit the thread
*/
thread_exit();
}
/*
* static void
* vsw_rx_queue_cb() - Receive callback routine when
* vsw_multi_ring_enable is non-zero. Queue the packets
* to a packet queue for a worker thread to process.
*/
static void
{
/*
* Find the last element in the mblk chain.
*/
do {
/* Get the queue for the packets */
/*
* Grab the lock such we can queue the packets.
*/
goto vsw_rx_queue_cb_exit;
}
/*
* Add the mblk chain to the queue. If there
* is some mblks in the queue, then add the new
* chain to the end.
*/
else
/*
* Signal the worker thread that there is work to
* do.
*/
/*
* Let go of the lock and exit.
*/
}
/*
* receive callback routine. Invoked by MAC layer when there
* are pkts being passed up from physical device.
*
* PERF: It may be more efficient when the card is in promisc
* mode to check the dest address of the pkts here (against
* the FDB) rather than checking later. Needs to be investigated.
*/
static void
{
/* switch the chain of packets received */
}
/*
* Send a message out over the physical device via the MAC layer.
*
* Returns any mblks that it was unable to transmit.
*/
mblk_t *
{
const mac_txinfo_t *mtp;
return (mp);
} else {
}
return (mp);
}