vnet.c revision e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061
/*
* 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 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/ethernet.h>
#include <sys/mac_ether.h>
/*
* Function prototypes.
*/
/* DDI entrypoints */
/* MAC entrypoints */
static int vnet_m_start(void *);
static void vnet_m_stop(void *);
static int vnet_m_promisc(void *, boolean_t);
static int vnet_m_unicst(void *, const uint8_t *);
/* vnet internal functions */
static int vnet_mac_register(vnet_t *);
/* exported functions */
void vnet_del_def_rte(void *arg);
void vnet_tx_update(void *arg);
/* externs */
extern int vgen_uninit(void *arg);
static mac_callbacks_t vnet_m_callbacks = {
0,
NULL,
NULL,
};
/*
* Linked list of "vnet_t" structures - one per instance.
*/
/* Tunables */
/*
* Property names
*/
static char macaddr_propname[] = "local-mac-address";
/*
* This is the string displayed by modinfo(1m).
*/
static char vnet_ident[] = "vnet driver v%I%";
extern struct mod_ops mod_driverops;
static struct cb_ops cb_vnetops = {
nulldev, /* cb_open */
nulldev, /* cb_close */
nodev, /* cb_strategy */
nodev, /* cb_print */
nodev, /* cb_dump */
nodev, /* cb_read */
nodev, /* cb_write */
nodev, /* cb_ioctl */
nodev, /* cb_devmap */
nodev, /* cb_mmap */
nodev, /* cb_segmap */
nochpoll, /* cb_chpoll */
ddi_prop_op, /* cb_prop_op */
NULL, /* cb_stream */
(int)(D_MP) /* cb_flag */
};
DEVO_REV, /* devo_rev */
0, /* devo_refcnt */
NULL, /* devo_getinfo */
nulldev, /* devo_identify */
nulldev, /* devo_probe */
vnetattach, /* devo_attach */
vnetdetach, /* devo_detach */
nodev, /* devo_reset */
&cb_vnetops, /* devo_cb_ops */
};
&mod_driverops, /* Type of module. This one is a driver */
vnet_ident, /* ID string */
&vnetops /* driver specific ops */
};
static struct modlinkage modlinkage = {
};
/*
* Print debug messages - set to 0xf to enable all msgs
*/
int _vnet_dbglevel = 0x8;
void
{
char buf[512];
else
}
#ifdef DEBUG
/*
* XXX: any changes to the definitions below need corresponding changes in
*/
/*
* debug levels:
* DBG_LEVEL2: Info messages
* DBG_LEVEL3: Warning messages
* DBG_LEVEL4: Error messages
*/
DBG_LEVEL4 = 0x08 };
if ((_vnet_dbglevel & DBG_LEVEL1) != 0) { \
} \
if ((_vnet_dbglevel & DBG_LEVEL2) != 0) { \
} \
if ((_vnet_dbglevel & DBG_LEVEL3) != 0) { \
} \
if ((_vnet_dbglevel & DBG_LEVEL4) != 0) { \
} \
#else
#endif
/* _init(9E): initialize the loadable module */
int
_init(void)
{
int status;
if (status != 0) {
}
return (status);
}
/* _fini(9E): prepare the module for unloading. */
int
_fini(void)
{
int status;
if (status != 0)
return (status);
return (status);
}
/* _info(9E): return information about the loadable module */
int
{
}
/*
* attach(9E): attach a device to the system.
* called once for each instance of the device on the system.
*/
static int
{
int instance;
int status;
AST_fdbh_alloc = 0x20 }
switch (cmd) {
case DDI_ATTACH:
break;
case DDI_RESUME:
case DDI_PM_RESUME:
default:
goto vnet_attach_fail;
}
/* allocate vnet_t and mac_t structures */
/* setup links to vnet_t from both devinfo and mac_t */
/* read the mac address */
if (status != DDI_SUCCESS) {
goto vnet_attach_fail;
}
/*
* Initialize the generic vnet proxy transport. This is the first
* and default transport used by vnet. The generic transport
* is provided by using sun4v LDC (logical domain channel). On success,
* vgen_init() provides a pointer to mac_t of generic transport.
* Currently, this generic layer provides network connectivity to other
* vnets within ldoms and also to remote hosts oustide ldoms through
* the virtual switch (vsw) device on domain0. In the future, when
* physical adapters that are able to share their resources (such as
* dma channels) with guest domains become available, the vnet device
* will use hardware specific driver to communicate directly over the
* physical device to reach remote hosts without going through vswitch.
*/
&vgenmacp);
if (status != DDI_SUCCESS) {
goto vnet_attach_fail;
}
/* add generic transport to the list of vnet proxy transports */
}
else
/* allocate fdb hash table, with an extra slot for default route */
/* register with MAC layer */
if (status != DDI_SUCCESS) {
goto vnet_attach_fail;
}
/* add to the list of vnet devices */
vnet_headp = vnetp;
return (DDI_SUCCESS);
if (attach_state & AST_fdbh_alloc) {
}
if (attach_state & AST_vptl_alloc) {
}
if (attach_state & AST_vgen_init) {
}
if (attach_state & AST_vnet_alloc) {
}
return (DDI_FAILURE);
}
/*
* detach(9E): detach a device from the system.
*/
static int
{
int instance;
int rv;
goto vnet_detach_fail;
}
switch (cmd) {
case DDI_DETACH:
break;
case DDI_SUSPEND:
case DDI_PM_SUSPEND:
default:
goto vnet_detach_fail;
}
/* uninit and free vnet proxy transports */
/* uninitialize generic transport */
if (rv != DDI_SUCCESS) {
goto vnet_detach_fail;
}
}
}
/*
* Unregister from the MAC subsystem. This can fail, in
* particular if there are DLPI style-2 streams still open -
* in which case we just return failure.
*/
goto vnet_detach_fail;
/* unlink from instance(vnet_t) list */
break;
}
}
return (DDI_SUCCESS);
return (DDI_FAILURE);
}
static int
vnet_m_start(void *arg)
{
/*
* XXX
* Currently, we only have generic transport. m_start() invokes
* initiates handshake with peer vnets and vsw. In the future when we
* have support for hardware specific transports, this information
* needs to be propagted back to vnet from vgen and we need to revisit
* this code (see comments in vnet_attach()).
*
*/
}
return (VNET_SUCCESS);
}
static void
vnet_m_stop(void *arg)
{
}
}
/* set the unicast mac address of the device */
static int
{
/*
* XXX: setting mac address dynamically is not supported.
*/
return (VNET_FAILURE);
}
static int
{
int rv = VNET_SUCCESS;
break;
}
}
return (rv);
}
/* set or clear promiscuous mode on the device */
static int
{
/*
* XXX: setting promiscuous mode is not supported, just return success.
*/
return (VNET_SUCCESS);
}
/*
* Transmit a chain of packets. This function provides switching functionality
* based on the destination mac address to reach other guests (within ldoms) or
* external hosts.
*/
mblk_t *
{
struct ether_header *ehp;
/* get the destination mac address in the eth header */
/* Calculate hash value and fdb fanout */
if (fdbp) {
/*
* If the destination is in FDB, the destination is
* a vnet device within ldoms and directly reachable,
* invoke the tx function in the fdb entry.
*/
/* m_tx failed */
break;
}
} else {
/* destination is not in FDB */
/*
* or an unknown unicast address, forward the
* packet to vsw, using the last slot in fdb which is
* reserved for default route.
*/
if (fdbp) {
/* m_tx failed */
break;
}
} else {
/* drop the packet */
}
}
}
return (mp);
}
/* get statistics from the device */
int
{
/*
* get the specified statistic from each transport and return the
* aggregate val. This obviously only works for counters.
*/
return (ENOTSUP);
}
}
return (0);
}
/* wrapper function for mac_register() */
static int
{
int err;
return (DDI_FAILURE);
/*
* Finally, we're ready to register ourselves with the MAC layer
* interface; if this succeeds, we're all ready to start()
*/
}
/* add vp_tl to the list */
static void
{
} else {
}
}
/* remove vp_tl from the list */
static void
{
while (ttlp) {
break;
}
}
if (found) {
}
}
/* get vp_tl corresponding to the given name */
static vp_tl_t *
{
while (tlp) {
return (tlp);
}
}
"vnet_get_vptl: can't find vp_tl with name (%s)\n", name));
return (NULL);
}
/* read the mac address of the device */
static int
{
int rv;
"vnet_read_mac_address: prop_lookup failed (%s) err (%d)\n",
macaddr_propname, rv));
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* entries in forwarding database. See comments in vgen_port_init(vnet_gen.c).
*/
/* add an entry into the forwarding database */
void
{
/* Calculate hash value and fdb fanout */
return;
}
}
/* delete an entry from the forwarding database */
void
{
/* Calculate hash value and fdb fanout */
/* Unlink it from the list */
break;
}
}
}
/* modify an existing entry in the forwarding database */
void
{
/* Calculate hash value and fdb fanout */
/* change the entry to have new tx params */
break;
}
}
}
/* look up an fdb entry based on the mac address, caller holds lock */
static fdb_t *
{
break;
}
}
return (fdbp);
}
/* add default route entry into the forwarding database */
void
{
/*
* The last hash list is reserved for default route entry,
* and for now, we have only one entry in this list.
*/
"vnet_add_def_rte: default rte already exists\n"));
return;
}
return;
}
}
/* delete default route entry from the forwarding database */
void
vnet_del_def_rte(void *arg)
{
/*
* The last hash list is reserved for default route entry,
* and for now, we have only one entry in this list.
*/
return;
}
}
void
{
}
void
vnet_tx_update(void *arg)
{
}