DevVirtioNet.cpp revision e204adaca3d185da35ecbb638f81535c7e95b47d
/* $Id$ */
/** @file
* DevVirtioNet - Virtio Network Device
*/
/*
* Copyright (C) 2009 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
#define LOG_GROUP LOG_GROUP_DEV_VIRTIO_NET
#define VNET_GC_SUPPORT
#include <VBox/pdmnetifs.h>
#include <iprt/semaphore.h>
#ifdef IN_RING3
#endif /* IN_RING3 */
#include "../Builtins.h"
#ifndef VBOX_DEVICE_STRUCT_TESTCASE
#ifdef IN_RING3
#define VNET_PCI_CLASS 0x0200
#define VNET_N_QUEUES 3
#define VNET_NAME_FMT "VNet%d"
#if 0
/* Virtio Block Device */
#define VNET_PCI_CLASS 0x0180
#define VNET_N_QUEUES 2
#define VNET_NAME_FMT "VBlk%d"
#endif
#endif /* IN_RING3 */
/* Forward declarations ******************************************************/
PDMBOTHCBDECL(int) vnetIOPortIn (PPDMDEVINS pDevIns, void *pvUser, RTIOPORT port, uint32_t *pu32, unsigned cb);
PDMBOTHCBDECL(int) vnetIOPortOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT port, uint32_t u32, unsigned cb);
#endif /* VBOX_DEVICE_STRUCT_TESTCASE */
#define VNET_MAC_FILTER_LEN 32
/* Virtio net features */
#define VNET_S_LINK_UP 1
#ifdef _MSC_VER
struct VNetPCIConfig
#else /* !_MSC_VER */
#endif /* !_MSC_VER */
{
};
/**
* Device state structure. Holds the current state of device.
*
* @extends VPCISTATE
* @implements PDMINETWORKPORT
* @implements PDMINETWORKCONFIG
*/
struct VNetState_st
{
/* VPCISTATE must be the first member! */
// PDMCRITSECT csRx; /**< Protects RX queue. */
#if HC_ARCH_BITS == 64
#endif
/** transmit buffer */
/**< Link Up(/Restore) Timer. */
#ifdef VNET_TX_DELAY
/**< Transmit Delay Timer - R3. */
/**< Transmit Delay Timer - R0. */
/**< Transmit Delay Timer - GC. */
#if HC_ARCH_BITS == 64
#endif
#endif /* VNET_TX_DELAY */
/** Indicates transmission in progress -- only one thread is allowed. */
/** PCI config area holding MAC address as well as TBD. */
struct VNetPCIConfig config;
/** MAC address obtained from the configuration. */
/** True if physical cable is attached in configuration. */
bool fCableConnected;
/** N/A: */
bool volatile fMaybeOutOfSpace;
/** Promiscuous mode -- RX filter accepts all packets. */
bool fPromiscuous;
/** AllMulti mode -- RX filter accepts all multicast packets. */
bool fAllMulti;
/** The number of actually used slots in aMacTable. */
/** Array of MAC addresses accepted by RX filter. */
/** Bit array of VLAN filter, one bit per VLAN ID. */
#if HC_ARCH_BITS != 64
#endif
/* Receive-blocking-related fields ***************************************/
/** EMT: Gets signalled when more RX descriptors become available. */
/* Statistic fields ******************************************************/
#if defined(VBOX_WITH_STATISTICS)
#endif /* VBOX_WITH_STATISTICS */
};
typedef struct VNetState_st VNETSTATE;
typedef VNETSTATE *PVNETSTATE;
#ifndef VBOX_DEVICE_STRUCT_TESTCASE
#define VNETHDR_GSO_NONE 0
struct VNetHdr
{
};
#define VNET_OK 0
#define VNET_ERROR 1
typedef uint8_t VNETCTLACK;
#define VNET_CTRL_CLS_RX_MODE 0
#define VNET_CTRL_CMD_RX_MODE_PROMISC 0
#define VNET_CTRL_CMD_RX_MODE_ALLMULTI 1
#define VNET_CTRL_CLS_MAC 1
#define VNET_CTRL_CMD_MAC_TABLE_SET 0
#define VNET_CTRL_CLS_VLAN 2
#define VNET_CTRL_CMD_VLAN_ADD 0
#define VNET_CTRL_CMD_VLAN_DEL 1
struct VNetCtlHdr
{
};
typedef struct VNetCtlHdr VNETCTLHDR;
typedef VNETCTLHDR *PVNETCTLHDR;
{
}
{
}
{
// STAM_PROFILE_START(&pState->CTXSUFF(StatCsRx), a);
// int rc = PDMCritSectEnter(&pState->csRx, rcBusy);
// STAM_PROFILE_STOP(&pState->CTXSUFF(StatCsRx), a);
// return rc;
return VINF_SUCCESS;
}
{
// PDMCritSectLeave(&pState->csRx);
}
/**
* Dump a packet to debug log.
*
* @param pState The device state structure.
* @param cpPacket The packet.
* @param cb The size of the packet.
* @param cszText A string denoting direction of packet transfer.
*/
DECLINLINE(void) vnetPacketDump(PVNETSTATE pState, const uint8_t *cpPacket, size_t cb, const char *cszText)
{
#ifdef DEBUG
Log(("%s %s packet #%d (%d bytes):\n",
//Log3(("%.*Rhxd\n", cb, cpPacket));
#endif
}
{
/* We support:
* - Host-provided MAC address
* - Link status reporting in config space
* - Control queue
* - RX mode setting
* - MAC filter table
* - VLAN filter
*/
return VNET_F_MAC
}
{
return VNET_F_MAC;
}
{
// TODO: Nothing to do here yet
}
{
{
Log(("%s vnetGetConfig: Read beyond the config structure is attempted (port=%RTiop cb=%x).\n", INSTANCE(pState), port, cb));
return VERR_IOM_IOPORT_UNUSED;
}
return VINF_SUCCESS;
}
{
{
Log(("%s vnetGetConfig: Write beyond the config structure is attempted (port=%RTiop cb=%x).\n", INSTANCE(pState), port, cb));
if (port < sizeof(struct VNetPCIConfig))
sizeof(struct VNetPCIConfig) - port);
return VINF_SUCCESS;
}
return VINF_SUCCESS;
}
/**
* Hardware reset. Revert all registers to initial values.
*
* @param pState The device state structure.
*/
{
{
LogRel(("vnetReset failed to enter RX critical section!\n"));
return;
}
// TODO: Implement reset
if (pState->fCableConnected)
else
STATUS = 0;
/*
* By default we pass all packets up since the older guests cannot control
* virtio mode.
*/
pState->fPromiscuous = true;
pState->nMacFilterEntries = 0;
pState->uIsTransmitting = 0;
}
#ifdef IN_RING3
/**
* Wakeup the RX thread.
*/
{
if ( pState->fMaybeOutOfSpace
{
}
}
/**
* Link Up Timer handler.
*
* @param pDevIns Pointer to device instance structure.
* @param pTimer Pointer to the timer.
* @param pvUser NULL.
* @thread EMT
*/
{
return;
STATUS |= VNET_S_LINK_UP;
}
/**
* Handler for the wakeup signaller queue.
*/
{
return true;
}
#endif /* IN_RING3 */
/**
* This function is called when the driver becomes ready.
*
* @param pState The device state structure.
*/
{
#ifdef IN_RING3
#else
if (pItem)
#endif
}
/**
* Port I/O Handler for IN operations.
*
* @returns VBox status code.
*
* @param pDevIns The device instance.
* @param pvUser Pointer to the device state structure.
* @param port Port number used for the IN operation.
* @param pu32 Where to store the result.
* @param cb Number of bytes read.
* @thread EMT
*/
{
}
/**
* Port I/O Handler for OUT operations.
*
* @returns VBox status code.
*
* @param pDevIns The device instance.
* @param pvUser User argument.
* @param Port Port number used for the IN operation.
* @param u32 The value to output.
* @param cb The value size in bytes.
* @thread EMT
*/
{
}
#ifdef IN_RING3
/**
* Check if the device can receive data now.
* This must be called before the pfnRecieve() method is called.
*
* @remarks As a side effect this function enables queue notification
* if it cannot receive because the queue is empty.
* It disables notification if it can receive.
*
* @returns VERR_NET_NO_BUFFER_SPACE if it cannot.
* @param pInterface Pointer to the interface structure containing the called function pointer.
* @thread RX
*/
{
{
}
else
{
rc = VINF_SUCCESS;
}
return rc;
}
{
if (RT_SUCCESS(rc))
return VINF_SUCCESS;
if (RT_UNLIKELY(cMillies == 0))
return VERR_NET_NO_BUFFER_SPACE;
while (RT_LIKELY( (enmVMState = PDMDevHlpVMState(pState->VPCI.CTX_SUFF(pDevIns))) == VMSTATE_RUNNING
|| enmVMState == VMSTATE_RUNNING_LS))
{
if (RT_SUCCESS(rc2))
{
rc = VINF_SUCCESS;
break;
}
Log(("%s vnetWaitReceiveAvail: waiting cMillies=%u...\n",
}
return rc;
}
/**
* @interface_method_impl{PDMIBASE,pfnQueryInterface}
*/
{
}
/**
* Returns true if it is a broadcast packet.
*
* @returns true if destination address indicates broadcast.
* @param pvBuf The ethernet packet.
*/
{
}
/**
* Returns true if it is a multicast packet.
*
* @remarks returns true for broadcast packets as well.
* @returns true if destination address indicates multicast.
* @param pvBuf The ethernet packet.
*/
{
return (*(char*)pvBuf) & 1;
}
/**
* Determines if the packet is to be delivered to upper layer.
*
* @returns true if packet is intended for this node.
* @param pState Pointer to the state structure.
* @param pvBuf The ethernet packet.
* @param cb Number of bytes available in the packet.
*/
{
if (pState->fPromiscuous)
return true;
/* Ignore everything outside of our VLANs */
/* Compare TPID with VLAN Ether Type */
return false;
if (vnetIsBroadcast(pvBuf))
return true;
return true;
return true;
for (unsigned i = 0; i < pState->nMacFilterEntries; i++)
return true;
return false;
}
/**
* Pad and store received packet.
*
* @remarks Make sure that the packet appears to upper layer as one coming
* from real Ethernet: pad it and insert FCS.
*
* @returns VBox status code.
* @param pState The device state structure.
* @param pvBuf The available data.
* @param cb Number of bytes available in the buffer.
* @thread RX
*/
{
unsigned int uOffset = 0;
{
{
return VERR_INTERNAL_ERROR;
}
{
return VERR_INTERNAL_ERROR;
}
if (nElem == 0)
{
/* The very first segment of the very first element gets the header. */
{
Log(("%s vnetHandleRxPacket: The first descriptor does match the header size!\n", INSTANCE(pState)));
return VERR_INTERNAL_ERROR;
}
}
{
}
}
return VINF_SUCCESS;
}
/**
* Receive data from the network.
*
* @returns VBox status code.
* @param pInterface Pointer to the interface structure containing the called function pointer.
* @param pvBuf The available data.
* @param cb Number of bytes available in the buffer.
* @thread RX
*/
{
if (RT_FAILURE(rc))
return rc;
/* Drop packets if VM is not running or cable is disconnected. */
if (( enmVMState != VMSTATE_RUNNING
&& enmVMState != VMSTATE_RUNNING_LS)
|| !(STATUS & VNET_S_LINK_UP))
return VINF_SUCCESS;
{
if (RT_SUCCESS(rc))
{
}
}
return rc;
}
/**
* Gets the current Media Access Control (MAC) address.
*
* @returns VBox status code.
* @param pInterface Pointer to the interface structure containing the called function pointer.
* @param pMac Where to store the MAC address.
* @thread EMT
*/
{
return VINF_SUCCESS;
}
/**
* Gets the new link state.
*
* @returns The current link state.
* @param pInterface Pointer to the interface structure containing the called function pointer.
* @thread EMT
*/
{
if (STATUS & VNET_S_LINK_UP)
return PDMNETWORKLINKSTATE_UP;
return PDMNETWORKLINKSTATE_DOWN;
}
/**
* Sets the new link state.
*
* @returns VBox status code.
* @param pInterface Pointer to the interface structure containing the called function pointer.
* @param enmState The new link state
*/
static DECLCALLBACK(int) vnetSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
{
{
if (fNewUp)
{
STATUS |= VNET_S_LINK_UP;
}
else
{
STATUS &= ~VNET_S_LINK_UP;
}
}
return VINF_SUCCESS;
}
{
}
{
/*
* Only one thread is allowed to transmit at a time, others should skip
* transmission as the packets will be picked up by the transmitting
* thread.
*/
return;
{
Log(("%s Ignoring transmit requests from non-existent driver (status=0x%x).\n",
return;
}
{
unsigned int uOffset = 0;
{
Log(("%s vnetQueueTransmit: The first segment is not the header! (%u < 2 || %u != %u).\n",
break; /* For now we simply ignore the header, but it must be there anyway! */
}
else
{
/* Assemble a complete frame. */
{
{
}
}
{
}
}
}
}
#ifdef VNET_TX_DELAY
{
{
Log3(("%s vnetQueueTransmit: Got kicked with notification disabled, "
LogRel(("vnetQueueTransmit: Failed to enter critical section!/n"));
else
{
}
}
else
{
LogRel(("vnetQueueTransmit: Failed to enter critical section!/n"));
else
{
}
}
}
/**
* Transmit Delay Timer handler.
*
* @remarks We only get here when the timer expires.
*
* @param pDevIns Pointer to device instance structure.
* @param pTimer Pointer to the timer.
* @param pvUser NULL.
* @thread EMT
*/
{
Log3(("vnetTxTimer: Expired, diff %9d usec, avg %9d usec, min %9d usec, max %9d usec\n",
// Log3(("%s vnetTxTimer: Expired\n", INSTANCE(pState)));
{
LogRel(("vnetTxTimer: Failed to enter critical section!/n"));
return;
}
}
#else /* !VNET_TX_DELAY */
{
}
#endif /* !VNET_TX_DELAY */
{
{
break;
break;
default:
u8Ack = VNET_ERROR;
}
return u8Ack;
}
{
{
Log(("%s vnetControlMac: Segment layout is wrong "
return VNET_ERROR;
}
/* Load unicast addresses */
{
Log(("%s vnetControlMac: The unicast mac segment is too small "
return VNET_ERROR;
}
if (nMacs > VNET_MAC_FILTER_LEN)
{
Log(("%s vnetControlMac: MAC table is too big, have to use promiscuous"
pState->fPromiscuous = true;
}
else
{
if (nMacs)
#ifdef DEBUG
for(unsigned i = 0; i < nMacs; i++)
#endif /* DEBUG */
}
/* Load multicast addresses */
{
Log(("%s vnetControlMac: The multicast mac segment is too small "
return VNET_ERROR;
}
{
Log(("%s vnetControlMac: MAC table is too big, have to use allmulti"
}
else
{
if (nMacs)
#ifdef DEBUG
for(unsigned i = 0; i < nMacs; i++)
Log((" %RTmac\n",
#endif /* DEBUG */
}
return VNET_OK;
}
{
{
Log(("%s vnetControlVlan: Segment layout is wrong "
return VNET_ERROR;
}
if (u16Vid >= VNET_MAX_VID)
{
Log(("%s vnetControlVlan: VLAN ID is out of range "
return VNET_ERROR;
}
{
case VNET_CTRL_CMD_VLAN_ADD:
break;
case VNET_CTRL_CMD_VLAN_DEL:
break;
default:
u8Ack = VNET_ERROR;
}
return u8Ack;
}
{
{
unsigned int uOffset = 0;
{
Log(("%s vnetQueueControl: The first 'out' segment is not the "
break; /* Skip the element and hope the next one is good. */
}
{
Log(("%s vnetQueueControl: The last 'in' segment is too small "
"to hold the acknowledge! (%u < 1 || %u < %u).\n",
sizeof(VNETCTLACK)));
break; /* Skip the element and hope the next one is good. */
}
else
{
{
case VNET_CTRL_CLS_RX_MODE:
break;
case VNET_CTRL_CLS_MAC:
break;
case VNET_CTRL_CLS_VLAN:
break;
default:
u8Ack = VNET_ERROR;
}
}
}
}
/**
* Saves the configuration.
*
* @param pState The VNET state.
* @param pSSM The handle to the saved state.
*/
{
}
/**
* Live save - save basic configuration.
*
* @returns VBox status code.
* @param pDevIns The device instance.
* @param pSSM The handle to the saved state.
* @param uPass
*/
{
return VINF_SSM_DONT_CALL_AGAIN;
}
/**
* Prepares for state saving.
*
* @returns VBox status code.
* @param pDevIns The device instance.
* @param pSSM The handle to the saved state.
*/
{
return rc;
return VINF_SUCCESS;
}
/**
* Saves the state of device.
*
* @returns VBox status code.
* @param pDevIns The device instance.
* @param pSSM The handle to the saved state.
*/
{
/* Save config first */
/* Save the common part */
/* Save device-specific part */
return VINF_SUCCESS;
}
/**
* Serializes the receive thread, it may be working inside the critsect.
*
* @returns VBox status code.
* @param pDevIns The device instance.
* @param pSSM The handle to the saved state.
*/
{
return rc;
return VINF_SUCCESS;
}
/* Takes down the link temporarily if it's current status is up.
*
* This is used during restore and when replumbing the network link.
*
* The temporary link outage is supposed to indicate to the OS that all network
* connections have been lost and that it for instance is appropriate to
* renegotiate any DHCP lease.
*
* @param pThis The PCNet instance data.
*/
{
if (STATUS & VNET_S_LINK_UP)
{
STATUS &= ~VNET_S_LINK_UP;
/* Restore the link back in 5 seconds. */
}
}
/**
* Restore previously saved state of device.
*
* @returns VBox status code.
* @param pDevIns The device instance.
* @param pSSM The handle to the saved state.
* @param uVersion The data unit version number.
* @param uPass The data pass.
*/
static DECLCALLBACK(int) vnetLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
{
int rc;
/* config checks */
LogRel(("%s: The mac address differs: config=%RTmac saved=%RTmac\n", INSTANCE(pState), &pState->macConfigured, &macConfigured));
if (uPass == SSM_PASS_FINAL)
{
{
/* Clear the rest. */
0,
* sizeof(RTMAC));
sizeof(pState->aVlanFilter));
}
else
{
pState->fPromiscuous = true;
pState->nMacFilterEntries = 0;
}
}
return rc;
}
/**
* Link status adjustments after loading.
*
* @returns VBox status code.
* @param pDevIns The device instance.
* @param pSSM The handle to the saved state.
*/
{
/*
* Indicate link down to the guest OS that all network connections have
* been lost, unless we've been teleported here.
*/
return VINF_SUCCESS;
}
/**
* Map PCI I/O region.
*
* @return VBox status code.
* @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
* @param iRegion The region number.
* @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
* I/O port, else it's a physical address.
* This address is *NOT* relative to pci_mem_base like earlier!
* @param cb Region size.
* @param enmType One of the PCI_ADDRESS_SPACE_* values.
* @thread EMT
*/
{
int rc;
if (enmType != PCI_ADDRESS_SPACE_IO)
{
/* We should never get here */
AssertMsgFailed(("Invalid PCI address space param in map callback"));
return VERR_INTERNAL_ERROR;
}
#ifdef VNET_GC_SUPPORT
#endif
return rc;
}
/* -=-=-=-=- PDMDEVREG -=-=-=-=- */
#ifdef VBOX_DYNAMIC_NET_ATTACH
/**
* Detach notification.
*
* One port on the network card has been disconnected from the network.
*
* @param pDevIns The device instance.
* @param iLUN The logical unit which is being detached.
* @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
*/
{
AssertLogRelReturnVoid(iLUN == 0);
if (RT_FAILURE(rc))
{
LogRel(("vnetDetach failed to enter critical section!\n"));
return;
}
/*
* Zero some important members.
*/
}
/**
* Attach the Network attachment.
*
* One port on the network card has been connected to a network.
*
* @returns VBox status code.
* @param pDevIns The device instance.
* @param iLUN The logical unit which is being attached.
* @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
*
* @remarks This code path is not used during construction.
*/
{
if (RT_FAILURE(rc))
{
LogRel(("vnetAttach failed to enter critical section!\n"));
return rc;
}
/*
* Attach the driver.
*/
if (RT_SUCCESS(rc))
{
if (rc == VINF_NAT_DNS)
{
#ifdef RT_OS_LINUX
N_("A Domain Name Server (DNS) for NAT networking could not be determined. Please check your /etc/resolv.conf for <tt>nameserver</tt> entries. Either add one manually (<i>man resolv.conf</i>) or ensure that your host is correctly connected to an ISP. If you ignore this warning the guest will not be able to perform nameserver lookups and it will probably observe delays if trying so"));
#else
N_("A Domain Name Server (DNS) for NAT networking could not be determined. Ensure that your host is correctly connected to an ISP. If you ignore this warning the guest will not be able to perform nameserver lookups and it will probably observe delays if trying so"));
#endif
}
}
else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
/*
* Temporary set the link down if it was up so that the guest
* will know that we have change the configuration of the
* network card
*/
if (RT_SUCCESS(rc))
return rc;
}
#endif /* VBOX_DYNAMIC_NET_ATTACH */
/**
* @copydoc FNPDMDEVSUSPEND
*/
{
/* Poke thread waiting for buffer space. */
}
/**
* @copydoc FNPDMDEVPOWEROFF
*/
{
/* Poke thread waiting for buffer space. */
}
/**
* Device relocation callback.
*
* When this callback is called the device instance data, and if the
* have been changed. The device must use the chance to perform the
* necessary pointer relocations and data updates.
*
* Before the GC code is executed the first time, this function will be
* called with a 0 delta so GC pointer calculations can be one in one place.
*
* @param pDevIns Pointer to the device instance.
* @param offDelta The relocation delta relative to the old location.
*
* @remark A relocation CANNOT fail.
*/
{
#ifdef VNET_TX_DELAY
#endif /* VNET_TX_DELAY */
// TBD
}
/**
* Destruct a device instance.
*
* We need to free non-VM resources only.
*
* @returns VBox status.
* @param pDevIns The device instance data.
* @thread EMT
*/
{
{
}
{
}
// if (PDMCritSectIsInitialized(&pState->csRx))
// PDMR3CritSectDelete(&pState->csRx);
}
/**
* @interface_method_impl{PDMDEVREG,pfnConstruct}
*/
{
int rc;
/* Initialize PCI part first. */
/*
* Validate configuration.
*/
N_("Invalid configuration for VirtioNet device"));
/* Get config params */
sizeof(pState->macConfigured));
if (RT_FAILURE(rc))
N_("Configuration error: Failed to get MAC address"));
if (RT_FAILURE(rc))
N_("Configuration error: Failed to get the value of 'CableConnected'"));
/* Initialize PCI config space */
/* Initialize state structure */
/* Interfaces */
("Cannot allocate TX buffer for virtio-net device\n"), VERR_NO_MEMORY);
/* Initialize critical section. */
// char szTmp[sizeof(pState->VPCI.szInstance) + 2];
// RTStrPrintf(szTmp, sizeof(szTmp), "%sRX", pState->VPCI.szInstance);
// rc = PDMDevHlpCritSectInit(pDevIns, &pState->csRx, szTmp);
// if (RT_FAILURE(rc))
// return rc;
/* Map our ports to IO space. */
VPCI_CONFIG + sizeof(VNetPCIConfig),
if (RT_FAILURE(rc))
return rc;
if (RT_FAILURE(rc))
return rc;
/* Create the RX notifier signaller. */
if (RT_FAILURE(rc))
return rc;
/* Create Link Up Timer */
TMTIMER_FLAGS_DEFAULT_CRIT_SECT, /** @todo check locking here. */
if (RT_FAILURE(rc))
return rc;
#ifdef VNET_TX_DELAY
/* Create Transmit Delay Timer */
TMTIMER_FLAGS_DEFAULT_CRIT_SECT, /** @todo check locking here. */
if (RT_FAILURE(rc))
return rc;
pState->u32MinDiff = ~0;
#endif /* VNET_TX_DELAY */
if (RT_SUCCESS(rc))
{
if (rc == VINF_NAT_DNS)
{
N_("A Domain Name Server (DNS) for NAT networking could not be determined. Ensure that your host is correctly connected to an ISP. If you ignore this warning the guest will not be able to perform nameserver lookups and it will probably observe delays if trying so"));
}
}
else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
{
}
else
if (RT_FAILURE(rc))
return rc;
PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceiveBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data received", "/Devices/VNet%d/ReceiveBytes", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data transmitted", "/Devices/VNet%d/TransmitBytes", iInstance);
#if defined(VBOX_WITH_STATISTICS)
PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive", "/Devices/VNet%d/Receive/Total", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceiveStore, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive storing", "/Devices/VNet%d/Receive/Store", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatRxOverflow, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, "Profiling RX overflows", "/Devices/VNet%d/RxOverflow", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatRxOverflowWakeup, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of RX overflow wakeups", "/Devices/VNet%d/RxOverflowWakeup", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling transmits in HC", "/Devices/VNet%d/Transmit/Total", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitSend, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling send transmit in HC", "/Devices/VNet%d/Transmit/Send", iInstance);
#endif /* VBOX_WITH_STATISTICS */
return VINF_SUCCESS;
}
/**
* The device registration structure.
*/
const PDMDEVREG g_DeviceVirtioNet =
{
/* Structure version. PDM_DEVREG_VERSION defines the current version. */
/* Device name. */
"virtio-net",
/* Name of guest context module (no path).
* Only evalutated if PDM_DEVREG_FLAGS_RC is set. */
"VBoxDDGC.gc",
/* Name of ring-0 module (no path).
* Only evalutated if PDM_DEVREG_FLAGS_RC is set. */
"VBoxDDR0.r0",
/* The description of the device. The UTF-8 string pointed to shall, like this structure,
* remain unchanged from registration till VM destruction. */
"Virtio Ethernet.\n",
/* Flags, combination of the PDM_DEVREG_FLAGS_* \#defines. */
#ifdef VNET_GC_SUPPORT
#else
#endif
/* Device class(es), combination of the PDM_DEVREG_CLASS_* \#defines. */
/* Maximum number of instances (per VM). */
8,
/* Size of the instance data. */
sizeof(VNETSTATE),
/* Construct instance - required. */
/* Destruct instance - optional. */
/* Relocation command - optional. */
/* I/O Control interface - optional. */
NULL,
/* Power on notification - optional. */
NULL,
/* Reset notification - optional. */
NULL,
/* Suspend notification - optional. */
/* Resume notification - optional. */
NULL,
#ifdef VBOX_DYNAMIC_NET_ATTACH
/* Attach command - optional. */
/* Detach notification - optional. */
#else /* !VBOX_DYNAMIC_NET_ATTACH */
/* Attach command - optional. */
NULL,
/* Detach notification - optional. */
NULL,
#endif /* !VBOX_DYNAMIC_NET_ATTACH */
/* Query a LUN base interface - optional. */
NULL,
/* Init complete notification - optional. */
NULL,
/* Power off notification - optional. */
/* pfnSoftReset */
NULL,
/* u32VersionEnd */
};
#endif /* IN_RING3 */
#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */