/*
* 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.
*/
#include <sys/sysmacros.h>
#include <sys/ethernet.h>
#include <sys/machsystm.h>
#include <sys/mac_client.h>
#include <sys/mac_provider.h>
#include <sys/mac_client_priv.h>
#include <sys/mac_ether.h>
#include <sys/mach_descrip.h>
#include <sys/mac_flow.h>
/* MAC Ring table functions. */
/* MAC layer routines */
int nvids);
/* Support functions */
void vsw_reconfig_hw(vsw_t *);
int type);
/*
* Functions imported from other files.
*/
extern uint32_t vsw_publish_macaddr_count;
/*
* Tunables used in this file.
*/
extern int vsw_mac_open_retries;
/*
* Locking strategy in this file is explained as follows:
* - A global lock(vswp->mac_lock) is used to protect the
* MAC calls that deal with entire device. That is, the
* operations that deal with mac_handle which include
* mac_open()/close() and mac_client_open().
*
* the operations that deal with the MAC client.
*
* When both mac_lock and maccl_rwlock need to be held, the
* mac_lock need be acquired first and then maccl_rwlock. That is,
* mac_lock---->maccl_rwlock
*
* The 'mca_lock' that protects the mcast list is also acquired
* within the context of maccl_rwlock. The hierarchy for this
* one is as below:
* maccl_rwlock---->mca_lock
*/
/*
* Program unicast and multicast addresses of vsw interface and the ports
* into the network device.
*/
void
{
int rv;
/* Open a mac client and program addresses */
if (rv != 0) {
"!vsw%d: failed to program interface "
}
/*
* Notify the MAC layer of the changed address.
*/
if (rv == 0) {
}
}
/* program unicast address of ports in the network device */
continue;
/* Open a mac client and program addresses */
if (rv != 0) {
"!vsw%d: failed to program port(%d) "
port->p_instance);
}
}
/* announce macaddr of vnets to the physical switch */
if (vsw_publish_macaddr_count != 0) { /* enabled */
}
}
}
/*
* Remove unicast, multicast addresses and close mac clients
* for the vsw interface and all ports.
*/
void
{
/* Cleanup and close the mac client for the interface */
}
/* Cleanup and close the mac clients for all ports */
}
/*
* Open the underlying network 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 mac_open() failed and the error indicates that either
* the dlmgmtd door or the device is not available yet, we
* return EAGAIN to indicate that mac_open() needs to be
* retried. For example, this may happen during boot up, if
* the required link aggregation groups(devices) have not
* been created yet.
*/
return (EAGAIN);
} else {
return (EIO);
}
}
vswp->mac_open_retries = 0;
if (rv != 0) {
}
return (0);
}
/*
* Close the underlying physical device.
*/
void
{
(void) vsw_notify_rem(vswp);
}
}
}
}
/*
* Add multicast addr.
*/
int
int type)
{
int ret = 0;
if (ret != 0) {
"program multicast address(%s) err=%d",
return (ret);
}
}
return (ret);
}
/*
* Remove multicast addr.
*/
void
int type)
{
}
}
/*
* Add all multicast addresses of the port.
*/
static void
{
int rv;
if (type == VSW_LOCALDEV) {
} else {
}
return;
continue;
if (rv == 0) {
} else {
}
}
}
/*
* Remove all multicast addresses of the port.
*/
static void
{
if (type == VSW_LOCALDEV) {
} else {
}
return;
continue;
}
}
void
{
}
/*
* Open a mac client and program uncast and multicast addresses
* for a port or the interface.
* Returns:
* 0 on success
* non-zero for failure.
*/
int
{
int rv;
/* Release mac_lock now */
if (rv == 0) {
}
return (rv);
}
/*
* Open a MAC client for a port or an interface.
* The flags and their purpose as below:
*
* MAC_OPEN_FLAGS_SHARES_DESIRED -- This flag is used to indicate
* that a port desires a Share. This will be the case with the
* the ports that have hybrid mode enabled. This will only cause
* MAC layer to allocate a share and corresponding resources
* ahead of time. Ports that are not HybridIO enabled are
* associated with default group & resources.
*
* MAC_UNICAST_TAG_DISABLE -- This flag is used for VLAN
* support. It will cause MAC to not add any tags, but expect
* vsw to tag the packets.
*
* MAC_UNICAST_STRIP_DISABLE -- This flag is used for VLAN
* support. It will case the MAC layer to not strip the tags.
* Vsw may have to strip the tag for pvid case.
*/
static int
{
int rv = 0;
int instance;
const char *dev_name;
/*
* In case net-dev is changed (either set to nothing or
* using aggregation device), return success here as the
* timeout mechanism will handle it.
*/
return (0);
}
/* already open */
return (0);
}
if (type == VSW_VNETPORT) {
if (port->p_hio_enabled)
} else {
}
if (rv != 0) {
}
return (rv);
}
/*
* Clean up by removing uncast, multicast addresses and
* closing the MAC client for a port or the interface.
*/
void
{
}
/*
* Close a MAC client for a port or an interface.
*/
static void
{
mac_client_close(*mchp, 0);
}
}
/*
* Cleanup MAC client related stuff for all ports.
*/
void
{
}
}
/*
* 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 mode, open a mac client and program the mac-address
* and vlan-ids. The MAC layer will take care of programming
* the address into h/w or set the h/w into promiscuous mode.
*
* Returns 0 success, 1 on failure.
*/
int
{
return (0);
if (type == VSW_VNETPORT) {
} else {
}
return (err);
}
/*
* 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.
*/
void
{
return;
if (type == VSW_VNETPORT) {
} else {
}
}
/*
* Program the macaddress and vlans of a port.
*
* Returns 0 on sucess, 1 on failure.
*/
static int
{
int rv;
return (0);
/*
* If the port has a specific 'pvid', then
* register with that vlan-id, otherwise register
* with VLAN_ID_NONE.
*/
}
}
if (rv != 0) {
"macaddr,vid(%s, %d) err=%d",
return (rv);
}
}
/* Add vlans to the MAC layer */
/* Configure bandwidth to the MAC layer */
return (rv);
}
/*
* Program the macaddress and vlans of a port.
*
* Returns 0 on sucess, 1 on failure.
*/
static int
{
int rv;
return (0);
/* check if it is the primary macaddr of the card. */
}
/*
* If the interface has a specific 'pvid', then
* register with that vlan-id, otherwise register
* with VLAN_ID_NONE.
*/
}
}
if (rv != 0) {
"macaddr,vid(%s, %d) err=%d",
return (rv);
}
}
return (rv);
}
/*
* Remove a unicast mac address which has previously been programmed
* into HW.
*
* Returns 0 on sucess, 1 on failure.
*/
static void
{
int nvids;
if (type == VSW_VNETPORT) {
} else {
}
/* First clear the callback */
if (type == VSW_LOCALDEV) {
} else if (type == VSW_VNETPORT) {
}
return;
}
/* Remove vlans */
}
}
/*
* receive callback routine for vsw interface. Invoked by MAC layer when there
* are pkts being passed up from physical device for this vsw interface.
*/
/* ARGSUSED */
static void
{
int count;
if (count != 0) {
}
} else {
}
}
/*
* receive callback routine for port. Invoked by MAC layer when there
* are pkts being passed up from physical device for this port.
*/
/* ARGSUSED */
static void
{
/*
* Send the packets to the peer directly.
*/
}
/*
* Send a message out over the physical device
* via the MAC layer.
*
* Returns any mblks that it was unable to transmit.
*/
mblk_t *
{
return (mp);
}
/* packets are sent or dropped */
return (NULL);
}
/*
* vsw_port_mac_reconfig -- Cleanup and close the MAC client
* and reopen and re-configure the MAC client with new flags etc.
* This function is useful for two different purposes:
* 1) To update the MAC client with new vlan-ids. This is done
* by freeing the existing vlan-ids and reopen with the new
* vlan-ids.
*
* 2) If the Hybrid mode status of a port changes, then the
* MAC client need to be closed and re-opened, otherwise,
* Share related resources may not be freed(hybird mode disabled)
* or assigned(hybrid mode enabled). To accomplish this,
* this function simply closes and reopens the MAC client.
* The reopen will result in using the flags based on the
* new hybrid mode of the port.
*/
void
{
int rv;
/*
* Remove the multi-cast addresses, unicast address
* and close the mac-client.
*/
if (update_vlans == B_TRUE) {
}
}
/*
* Now re-open the mac-client and
* configure unicast addr and multicast addrs.
*/
if (rv != 0) {
goto recret;
}
goto recret;
}
}
/*
* vsw_if_mac_reconfig -- Reconfigure the vsw interfaace's mac-client
* by closing and re-opening it. This function is used handle the
* following two cases:
*
* 1) Handle the MAC address change for the interface.
* 2) Handle vlan update.
*/
void
{
int rv;
/*
* Remove the multi-cast addresses, unicast address
* and close the mac-client.
*/
if (update_vlans == B_TRUE) {
}
}
/*
* Now re-open the mac-client and
* configure unicast addr and multicast addrs.
*/
if (rv != 0) {
goto ifrecret;
}
goto ifrecret;
}
}
/*
* vsw_mac_port_reconfig_vlans -- Reconfigure a port to handle
* vlan configuration update. As the removal of the last unicast-address,vid
* from the MAC client results in releasing all resources, it expects
* no Shares to be associated with such MAC client.
*
* To handle vlan configuration update for a port that already has
* a Share bound, then we need to free that share prior to reconfiguration.
* Initiate the hybrdIO setup again after the completion of reconfiguration.
*/
void
{
/*
* As the reconfiguration involves the close of
* mac client, cleanup HybridIO and later restart
* HybridIO setup again.
*/
}
/* reset to setup the HybridIO again. */
}
}
/* Add vlans to MAC client */
static void
{
int rv;
int i;
/* Add vlans to the MAC layer */
for (i = 0; i < nvids; i++) {
continue;
}
if (rv != 0) {
"macaddr,vid(%s, %d) err=%d",
} else {
"into device %s", __func__,
ether_sprintf((void *)macaddr),
}
}
}
/* Remove vlans from the MAC client */
static void
{
int i;
for (i = 0; i < nvids; i++) {
continue;
}
}
}
/*
* Send a gratuitous RARP packet to notify the physical switch to update its
* Layer2 forwarding table for the given mac address. This is done to allow the
* switch to quickly learn the macaddr-port association when a guest is live
* migrated or when vsw's physical device is changed dynamically. Any protocol
* packet would serve this purpose, but we choose RARP, as it allows us to
* accomplish this within L2 (ie, no need to specify IP addr etc in the packet)
* The macaddr of vnet is retained across migration. Hence, we don't need to
* update the arp cache of other hosts within the broadcast domain. Note that
* it is harmless to send these RARP packets during normal port attach of a
* client vnet. This can can be turned off if needed, by setting
*/
void
{
int count = 0;
return;
}
/* Initialize eth header */
/* Initialize arp packet */
cp += ARH_FIXED_LEN;
/* Sender's hardware address and protocol address */
cp += ETHERADDRL;
/* Target hardware address and protocol address */
cp += ETHERADDRL;
continue;
}
/* transmit the packet */
}
}
}
static void
{
int rv;
if (rv != 0) {
"!vsw%d: Unable to set the mtu:%d, in the "
"physical device:%s\n",
return;
}
/* save the original mtu of physdev to reset it back later if needed */
}
/*
* Register a callback with underlying mac layer for notifications.
* We are currently interested in only link-state events.
*/
static int
{
/*
* Check if the underlying MAC supports link update notification.
*/
} else {
}
/*
* Read the current link state of the device and cache it.
*/
/*
* Add notify callback function, if link update is supported.
*/
return (0);
}
if (mnh == 0) {
/* failed */
return (1);
}
return (0);
}
/*
* Remove notify callback.
*/
static int
{
int rv;
return (rv);
}
/*
* Notification callback invoked by the MAC service
* module. Note that we process only link state updates.
*/
static void
{
switch (type) {
case MAC_NOTE_LINK:
break;
default:
break;
}
}
/*
* Invoked upon receiving a MAC_NOTE_LINK
* notification for the underlying physical device.
*/
static void
{
/* link state change notification */
}
}
/*
* Configure the bandwidth limit on the vsw or vnet devices via the MAC layer.
* Note that bandwidth limit is not supported on a HybridIO enabled
* vnet, as the HybridIO assigns a specific unit of hardware resource
* that cannot be changed to limit bandwidth.
*/
static void
{
int rv = 0;
if (type == VSW_VNETPORT) {
} else {
}
return;
}
if (maxbw == 0) {
} else {
}
if (rv != 0) {
if (type == VSW_VNETPORT) {
"bandwidth limit to (%ld), error(%d)\n",
} else {
"bandwidth limit to (%ld), error(%d)\n",
}
} else {
/*
* update with successfully configured bandwidth.
*/
}
}
}