DevVirtioNet.cpp revision abc1c143c7e4b1c81651e524ebf8ee3ccd794cdd
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * DevVirtioNet - Virtio Network Device
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * Copyright (C) 2009 Sun Microsystems, Inc.
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * available from http://www.virtualbox.org. This file is free software;
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * you can redistribute it and/or modify it under the terms of the GNU
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * General Public License (GPL) as published by the Free Software
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * additional information or have any questions.
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync#endif /* IN_RING3 */
9b0ba1d4360299b4e6ee23c946feb5a4f16c6d00vboxsync ((VNETSTATE *)((char*)pIface - RT_OFFSETOF(VNETSTATE, ifaceName)))
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync/* Virtio Block Device */
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync#endif /* IN_RING3 */
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync/* Forward declarations ******************************************************/
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsyncPDMBOTHCBDECL(int) vnetIOPortIn (PPDMDEVINS pDevIns, void *pvUser, RTIOPORT port, uint32_t *pu32, unsigned cb);
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsyncPDMBOTHCBDECL(int) vnetIOPortOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT port, uint32_t u32, unsigned cb);
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync#endif /* VBOX_DEVICE_STRUCT_TESTCASE */
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync#define VNET_MAX_FRAME_SIZE 65536 // TODO: Is it the right limit?
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync/* Virtio net features */
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync#define VNET_F_CSUM 0x00000001 /* Host handles pkts w/ partial csum */
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync#define VNET_F_GUEST_CSUM 0x00000002 /* Guest handles pkts w/ partial csum */
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync#define VNET_F_MAC 0x00000020 /* Host has given MAC address. */
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync#define VNET_F_GSO 0x00000040 /* Host handles pkts w/ any GSO type */
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync#define VNET_F_GUEST_TSO4 0x00000080 /* Guest can handle TSOv4 in. */
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync#define VNET_F_GUEST_TSO6 0x00000100 /* Guest can handle TSOv6 in. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync#define VNET_F_GUEST_ECN 0x00000200 /* Guest can handle TSO[6] w/ ECN in. */
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync#define VNET_F_GUEST_UFO 0x00000400 /* Guest can handle UFO in. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync#define VNET_F_HOST_TSO4 0x00000800 /* Host can handle TSOv4 in. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync#define VNET_F_HOST_TSO6 0x00001000 /* Host can handle TSOv6 in. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync#define VNET_F_HOST_ECN 0x00002000 /* Host can handle TSO[6] w/ ECN in. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync#define VNET_F_HOST_UFO 0x00004000 /* Host can handle UFO in. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync#define VNET_F_MRG_RXBUF 0x00008000 /* Host can merge receive buffers. */
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync#define VNET_F_STATUS 0x00010000 /* virtio_net_config.status available */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync#define VNET_F_CTRL_VQ 0x00020000 /* Control channel available */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync#define VNET_F_CTRL_RX 0x00040000 /* Control channel RX mode support */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync#define VNET_F_CTRL_VLAN 0x00080000 /* Control channel VLAN filtering */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync#else /* !_MSC_VER */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync#endif /* !_MSC_VER */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsyncAssertCompileMemberOffset(struct VNetPCIConfig, uStatus, 6);
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync * Device state structure. Holds the current state of device.
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync /* VPCISTATE must be the first member! */
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync// PDMCRITSECT csRx; /**< Protects RX queue. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync R3PTRTYPE(PPDMIBASE) pDrvBase; /**< Attached network driver. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync R3PTRTYPE(PPDMINETWORKCONNECTOR) pDrv; /**< Connector of attached network driver. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync R3PTRTYPE(PPDMQUEUE) pCanRxQueueR3; /**< Rx wakeup signaller - R3. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync R0PTRTYPE(PPDMQUEUE) pCanRxQueueR0; /**< Rx wakeup signaller - R0. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync RCPTRTYPE(PPDMQUEUE) pCanRxQueueRC; /**< Rx wakeup signaller - RC. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync /** transmit buffer */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync /**< Link Up(/Restore) Timer. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync /**< Transmit Delay Timer - R3. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync /**< Transmit Delay Timer - R0. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync /**< Transmit Delay Timer - GC. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync#endif /* VNET_TX_DELAY */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync /** PCI config area holding MAC address as well as TBD. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync /** MAC address obtained from the configuration. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync /** True if physical cable is attached in configuration. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync /** Number of packet being sent/received to show in debug log. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync /** N/A: */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync bool volatile fMaybeOutOfSpace;
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync /** Promiscuous mode -- RX filter accepts all packets. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync /** AllMulti mode -- RX filter accepts all multicast packets. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync /** The number of actually used slots in aMacTable. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync /** Array of MAC addresses accepted by RX filter. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync /** Bit array of VLAN filter, one bit per VLAN ID. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync uint8_t aVlanFilter[VNET_MAX_VID / sizeof(uint8_t)];
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync /* Receive-blocking-related fields ***************************************/
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync /** EMT: Gets signalled when more RX descriptors become available. */
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync /* Statistic fields ******************************************************/
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync#endif /* VBOX_WITH_STATISTICS */
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsyncDECLINLINE(int) vnetCsEnter(PVNETSTATE pState, int rcBusy)
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsyncDECLINLINE(int) vnetCsRxEnter(PVNETSTATE pState, int rcBusy)
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync // STAM_PROFILE_START(&pState->CTXSUFF(StatCsRx), a);
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync // int rc = PDMCritSectEnter(&pState->csRx, rcBusy);
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync // STAM_PROFILE_STOP(&pState->CTXSUFF(StatCsRx), a);
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync // return rc;
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync // PDMCritSectLeave(&pState->csRx);
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsyncPDMBOTHCBDECL(uint32_t) vnetGetHostFeatures(void *pvState)
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync /* We support:
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * - Host-provided MAC address
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * - Link status reporting in config space
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * - Control queue
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * - RX mode setting
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * - MAC filter table
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * - VLAN filter
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsyncPDMBOTHCBDECL(uint32_t) vnetGetHostMinimalFeatures(void *pvState)
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsyncPDMBOTHCBDECL(void) vnetSetHostFeatures(void *pvState, uint32_t uFeatures)
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync // TODO: Nothing to do here yet
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync LogFlow(("%s vnetSetHostFeatures: uFeatures=%x\n", INSTANCE(pState), uFeatures));
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsyncPDMBOTHCBDECL(int) vnetGetConfig(void *pvState, uint32_t port, uint32_t cb, void *data)
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync Log(("%s vnetGetConfig: Read beyond the config structure is attempted (port=%RTiop cb=%x).\n", INSTANCE(pState), port, cb));
f46e7db81f80ea09725c6cc048fa0cad86573dc2vboxsync memcpy(data, ((uint8_t*)&pState->config) + port, cb);
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsyncPDMBOTHCBDECL(int) vnetSetConfig(void *pvState, uint32_t port, uint32_t cb, void *data)
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync Log(("%s vnetGetConfig: Write beyond the config structure is attempted (port=%RTiop cb=%x).\n", INSTANCE(pState), port, cb));
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync memcpy(((uint8_t*)&pState->config) + port, data, cb);
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * Hardware reset. Revert all registers to initial values.
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * @param pState The device state structure.
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync LogRel(("vnetReset failed to enter RX critical section!\n"));
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync // TODO: Implement reset
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * By default we pass all packets up since the older guests cannot control
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * virtio mode.
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync memset(pState->aMacFilter, 0, VNET_MAC_FILTER_LEN * sizeof(RTMAC));
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync memset(pState->aVlanFilter, 0, sizeof(pState->aVlanFilter));
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * Wakeup the RX thread.
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE *);
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync && pState->hEventMoreRxDescAvail != NIL_RTSEMEVENT)
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync Log(("%s Waking up Out-of-RX-space semaphore\n", INSTANCE(pState)));
b6517c5cc3b7a38889416706905a3cf2fd010785vboxsync * Link Up Timer handler.
#ifdef IN_RING3
if (pItem)
#ifdef IN_RING3
return rc;
return VINF_SUCCESS;
return VERR_NET_NO_BUFFER_SPACE;
while (RT_LIKELY( (enmVMState = PDMDevHlpVMState(pState->VPCI.CTX_SUFF(pDevIns))) == VMSTATE_RUNNING
return rc;
static DECLCALLBACK(void *) vnetQueryInterface(struct PDMIBASE *pInterface, PDMINTERFACE enmInterface)
switch (enmInterface)
unsigned int uOffset = 0;
return VERR_INTERNAL_ERROR;
return VERR_INTERNAL_ERROR;
if (nElem == 0)
Log(("%s vnetHandleRxPacket: The first descriptor does match the header size!\n", INSTANCE(pState)));
return VERR_INTERNAL_ERROR;
return VINF_SUCCESS;
return rc;
return VINF_SUCCESS;
return rc;
return VINF_SUCCESS;
return PDMNETWORKLINKSTATE_UP;
return PDMNETWORKLINKSTATE_DOWN;
static DECLCALLBACK(int) vnetSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
if (fNewUp)
return VINF_SUCCESS;
unsigned int uOffset = 0;
#ifdef VNET_TX_DELAY
return u8Ack;
return VNET_ERROR;
return VNET_ERROR;
if (nMacs)
#ifdef DEBUG
for(unsigned i = 0; i < nMacs; i++)
return VNET_ERROR;
if (nMacs)
#ifdef DEBUG
for(unsigned i = 0; i < nMacs; i++)
return VNET_OK;
return VNET_ERROR;
return VNET_ERROR;
case VNET_CTRL_CMD_VLAN_ADD:
case VNET_CTRL_CMD_VLAN_DEL:
return u8Ack;
unsigned int uOffset = 0;
sizeof(VNETCTLACK)));
case VNET_CTRL_CLS_RX_MODE:
case VNET_CTRL_CLS_MAC:
case VNET_CTRL_CLS_VLAN:
return VINF_SSM_DONT_CALL_AGAIN;
return rc;
return VINF_SUCCESS;
return VINF_SUCCESS;
return rc;
return VINF_SUCCESS;
static DECLCALLBACK(int) vnetLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
int rc;
LogRel(("%s: The mac address differs: config=%RTmac saved=%RTmac\n", INSTANCE(pState), &pState->macConfigured, &macConfigured));
* sizeof(RTMAC));
return rc;
return VINF_SUCCESS;
int rc;
return VERR_INTERNAL_ERROR;
#ifdef VNET_GC_SUPPORT
return rc;
int rc;
// char szTmp[sizeof(pState->VPCI.szInstance) + 2];
// RTStrPrintf(szTmp, sizeof(szTmp), "%sRX", pState->VPCI.szInstance);
return rc;
return rc;
return rc;
return rc;
#ifdef VNET_TX_DELAY
return rc;
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"));
return VERR_PDM_MISSING_INTERFACE_BELOW;
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);
return VINF_SUCCESS;
#ifdef VNET_TX_DELAY
#ifdef VBOX_DYNAMIC_NET_ATTACH
return rc;
#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"));
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"));
pState->pDrv = (PPDMINETWORKCONNECTOR)pState->pDrvBase->pfnQueryInterface(pState->pDrvBase, PDMINTERFACE_NETWORK_CONNECTOR);
return rc;
#ifdef VNET_GC_SUPPORT
sizeof(VNETSTATE),
NULL,
NULL,
NULL,
NULL,
#ifdef VBOX_DYNAMIC_NET_ATTACH
NULL,
NULL,
NULL,
NULL,
NULL,