DevVirtioNet.cpp revision 75cb12092223b74f2f415d7e9ba54f10854bc43b
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * DevVirtioNet - Virtio Network Device
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Copyright (C) 2009 Sun Microsystems, Inc.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * available from http://www.virtualbox.org. This file is free software;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * you can redistribute it and/or modify it under the terms of the GNU
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * General Public License (GPL) as published by the Free Software
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * additional information or have any questions.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#endif /* IN_RING3 */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync ((VNETSTATE *)((char*)pIface - RT_OFFSETOF(VNETSTATE, ifaceName)))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/* Virtio Block Device */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#endif /* IN_RING3 */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/* Forward declarations ******************************************************/
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncPDMBOTHCBDECL(int) vnetIOPortIn (PPDMDEVINS pDevIns, void *pvUser, RTIOPORT port, uint32_t *pu32, unsigned cb);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncPDMBOTHCBDECL(int) vnetIOPortOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT port, uint32_t u32, unsigned cb);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#endif /* VBOX_DEVICE_STRUCT_TESTCASE */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#define VNET_MAX_FRAME_SIZE 65536 // TODO: Is it the right limit?
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/* Virtio net features */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#define VNET_F_CSUM 0x00000001 /* Host handles pkts w/ partial csum */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#define VNET_F_GUEST_CSUM 0x00000002 /* Guest handles pkts w/ partial csum */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#define VNET_F_MAC 0x00000020 /* Host has given MAC address. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#define VNET_F_GSO 0x00000040 /* Host handles pkts w/ any GSO type */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#define VNET_F_GUEST_TSO4 0x00000080 /* Guest can handle TSOv4 in. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#define VNET_F_GUEST_TSO6 0x00000100 /* Guest can handle TSOv6 in. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#define VNET_F_GUEST_ECN 0x00000200 /* Guest can handle TSO[6] w/ ECN in. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#define VNET_F_GUEST_UFO 0x00000400 /* Guest can handle UFO in. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#define VNET_F_HOST_TSO4 0x00000800 /* Host can handle TSOv4 in. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#define VNET_F_HOST_TSO6 0x00001000 /* Host can handle TSOv6 in. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#define VNET_F_HOST_ECN 0x00002000 /* Host can handle TSO[6] w/ ECN in. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#define VNET_F_HOST_UFO 0x00004000 /* Host can handle UFO in. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#define VNET_F_MRG_RXBUF 0x00008000 /* Host can merge receive buffers. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#define VNET_F_STATUS 0x00010000 /* virtio_net_config.status available */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#define VNET_F_CTRL_VQ 0x00020000 /* Control channel available */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#define VNET_F_CTRL_RX 0x00040000 /* Control channel RX mode support */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#define VNET_F_CTRL_VLAN 0x00080000 /* Control channel VLAN filtering */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#else /* !_MSC_VER */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#endif /* !_MSC_VER */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncAssertCompileMemberOffset(struct VNetPCIConfig, uStatus, 6);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Device state structure. Holds the current state of device.
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync /* VPCISTATE must be the first member! */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync// PDMCRITSECT csRx; /**< Protects RX queue. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync R3PTRTYPE(PPDMIBASE) pDrvBase; /**< Attached network driver. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync R3PTRTYPE(PPDMINETWORKCONNECTOR) pDrv; /**< Connector of attached network driver. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync R3PTRTYPE(PPDMQUEUE) pCanRxQueueR3; /**< Rx wakeup signaller - R3. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync R0PTRTYPE(PPDMQUEUE) pCanRxQueueR0; /**< Rx wakeup signaller - R0. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RCPTRTYPE(PPDMQUEUE) pCanRxQueueRC; /**< Rx wakeup signaller - RC. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** transmit buffer */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /**< Link Up(/Restore) Timer. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /**< Transmit Delay Timer - R3. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /**< Transmit Delay Timer - R0. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /**< Transmit Delay Timer - GC. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#endif /* VNET_TX_DELAY */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** Indicates transmission in progress -- only one thread is allowed. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** PCI config area holding MAC address as well as TBD. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** MAC address obtained from the configuration. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** True if physical cable is attached in configuration. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** Number of packet being sent/received to show in debug log. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** N/A: */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync bool volatile fMaybeOutOfSpace;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** Promiscuous mode -- RX filter accepts all packets. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** AllMulti mode -- RX filter accepts all multicast packets. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** The number of actually used slots in aMacTable. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** Array of MAC addresses accepted by RX filter. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** Bit array of VLAN filter, one bit per VLAN ID. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync uint8_t aVlanFilter[VNET_MAX_VID / sizeof(uint8_t)];
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* Receive-blocking-related fields ***************************************/
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** EMT: Gets signalled when more RX descriptors become available. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* Statistic fields ******************************************************/
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#endif /* VBOX_WITH_STATISTICS */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncDECLINLINE(int) vnetCsEnter(PVNETSTATE pState, int rcBusy)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncDECLINLINE(int) vnetCsRxEnter(PVNETSTATE pState, int rcBusy)
83dc9ca94cd3c31dabc33a35b945de124d43aaeavboxsync // STAM_PROFILE_START(&pState->CTXSUFF(StatCsRx), a);
83dc9ca94cd3c31dabc33a35b945de124d43aaeavboxsync // int rc = PDMCritSectEnter(&pState->csRx, rcBusy);
fb1975a6972d89de9e515bed0248db93f04ec9d8vboxsync // STAM_PROFILE_STOP(&pState->CTXSUFF(StatCsRx), a);
83dc9ca94cd3c31dabc33a35b945de124d43aaeavboxsync // return rc;
83dc9ca94cd3c31dabc33a35b945de124d43aaeavboxsync // PDMCritSectLeave(&pState->csRx);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Dump a packet to debug log.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pState The device state structure.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param cpPacket The packet.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param cb The size of the packet.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param cszText A string denoting direction of packet transfer.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncDECLINLINE(void) vnetPacketDump(PVNETSTATE pState, const uint8_t *cpPacket, size_t cb, const char *cszText)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync INSTANCE(pState), cszText, ++pState->u32PktNo, cb));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync //Log3(("%.*Rhxd\n", cb, cpPacket));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncPDMBOTHCBDECL(uint32_t) vnetGetHostFeatures(void *pvState)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* We support:
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * - Host-provided MAC address
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * - Link status reporting in config space
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * - Control queue
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * - RX mode setting
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * - MAC filter table
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * - VLAN filter
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncPDMBOTHCBDECL(uint32_t) vnetGetHostMinimalFeatures(void *pvState)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncPDMBOTHCBDECL(void) vnetSetHostFeatures(void *pvState, uint32_t uFeatures)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync // TODO: Nothing to do here yet
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync LogFlow(("%s vnetSetHostFeatures: uFeatures=%x\n", INSTANCE(pState), uFeatures));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncPDMBOTHCBDECL(int) vnetGetConfig(void *pvState, uint32_t port, uint32_t cb, void *data)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Log(("%s vnetGetConfig: Read beyond the config structure is attempted (port=%RTiop cb=%x).\n", INSTANCE(pState), port, cb));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync memcpy(data, ((uint8_t*)&pState->config) + port, cb);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncPDMBOTHCBDECL(int) vnetSetConfig(void *pvState, uint32_t port, uint32_t cb, void *data)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Log(("%s vnetGetConfig: Write beyond the config structure is attempted (port=%RTiop cb=%x).\n", INSTANCE(pState), port, cb));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync memcpy(((uint8_t*)&pState->config) + port, data, cb);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Hardware reset. Revert all registers to initial values.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pState The device state structure.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync LogRel(("vnetReset failed to enter RX critical section!\n"));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync // TODO: Implement reset
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * By default we pass all packets up since the older guests cannot control
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * virtio mode.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync memset(pState->aMacFilter, 0, VNET_MAC_FILTER_LEN * sizeof(RTMAC));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync memset(pState->aVlanFilter, 0, sizeof(pState->aVlanFilter));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Wakeup the RX thread.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE *);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync && pState->hEventMoreRxDescAvail != NIL_RTSEMEVENT)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Log(("%s Waking up Out-of-RX-space semaphore\n", INSTANCE(pState)));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Link Up Timer handler.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pDevIns Pointer to device instance structure.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pTimer Pointer to the timer.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pvUser NULL.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @thread EMT
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic DECLCALLBACK(void) vnetLinkUpTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Handler for the wakeup signaller queue.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic DECLCALLBACK(bool) vnetCanRxQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return true;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#endif /* IN_RING3 */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * This function is called when the driver becomes ready.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pState The device state structure.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Log(("%s Driver became ready, waking up RX thread...\n", INSTANCE(pState)));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(pState->CTX_SUFF(pCanRxQueue));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync PDMQueueInsert(pState->CTX_SUFF(pCanRxQueue), pItem);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Port I/O Handler for IN operations.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns VBox status code.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pDevIns The device instance.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pvUser Pointer to the device state structure.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param port Port number used for the IN operation.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pu32 Where to store the result.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param cb Number of bytes read.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @thread EMT
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncPDMBOTHCBDECL(int) vnetIOPortIn(PPDMDEVINS pDevIns, void *pvUser,
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return vpciIOPortIn(pDevIns, pvUser, port, pu32, cb,
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Port I/O Handler for OUT operations.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns VBox status code.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pDevIns The device instance.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pvUser User argument.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param Port Port number used for the IN operation.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param u32 The value to output.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param cb The value size in bytes.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @thread EMT
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncPDMBOTHCBDECL(int) vnetIOPortOut(PPDMDEVINS pDevIns, void *pvUser,
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return vpciIOPortOut(pDevIns, pvUser, port, u32, cb,
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Check if the device can receive data now.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * This must be called before the pfnRecieve() method is called.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @remarks As a side effect this function enables queue notification
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * if it cannot receive because the queue is empty.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * It disables notification if it can receive.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns VERR_NET_NO_BUFFER_SPACE if it cannot.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pInterface Pointer to the interface structure containing the called function pointer.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @thread RX
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync LogFlow(("%s vnetCanReceive\n", INSTANCE(pState)));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync else if (!vqueueIsReady(&pState->VPCI, pState->pRxQueue))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync else if (vqueueIsEmpty(&pState->VPCI, pState->pRxQueue))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync vringSetNotification(&pState->VPCI, &pState->pRxQueue->VRing, true);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync vringSetNotification(&pState->VPCI, &pState->pRxQueue->VRing, false);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync LogFlow(("%s vnetCanReceive -> %Vrc\n", INSTANCE(pState), rc));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic DECLCALLBACK(int) vnetWaitReceiveAvail(PPDMINETWORKPORT pInterface, RTMSINTERVAL cMillies)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkPort);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync LogFlow(("%s vnetWaitReceiveAvail(cMillies=%u)\n", INSTANCE(pState), cMillies));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync ASMAtomicXchgBool(&pState->fMaybeOutOfSpace, true);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync while (RT_LIKELY( (enmVMState = PDMDevHlpVMState(pState->VPCI.CTX_SUFF(pDevIns))) == VMSTATE_RUNNING
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Log(("%s vnetWaitReceiveAvail: waiting cMillies=%u...\n",
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTSemEventWait(pState->hEventMoreRxDescAvail, cMillies);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync ASMAtomicXchgBool(&pState->fMaybeOutOfSpace, false);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync LogFlow(("%s vnetWaitReceiveAvail -> %d\n", INSTANCE(pState), rc));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Provides interfaces to the driver.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns Pointer to interface. NULL if the interface is not supported.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pInterface Pointer to this interface structure.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param enmInterface The requested interface identification.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @thread EMT
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic DECLCALLBACK(void *) vnetQueryInterface(struct PDMIBASE *pInterface, PDMINTERFACE enmInterface)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync VNETSTATE *pState = IFACE_TO_STATE(pInterface, VPCI.IBase);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return vpciQueryInterface(pInterface, enmInterface);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Returns true if it is a broadcast packet.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns true if destination address indicates broadcast.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pvBuf The ethernet packet.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync static const uint8_t s_abBcastAddr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return memcmp(pvBuf, s_abBcastAddr, sizeof(s_abBcastAddr)) == 0;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Returns true if it is a multicast packet.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @remarks returns true for broadcast packets as well.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns true if destination address indicates multicast.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pvBuf The ethernet packet.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Determines if the packet is to be delivered to upper layer.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns true if packet is intended for this node.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pState Pointer to the state structure.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pvBuf The ethernet packet.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param cb Number of bytes available in the packet.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic bool vnetAddressFilter(PVNETSTATE pState, const void *pvBuf, size_t cb)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return true;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* Ignore everything outside of our VLANs */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* Compare TPID with VLAN Ether Type */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync && !ASMBitTest(pState->aVlanFilter, RT_BE2H_U16(u16Ptr[7]) & 0xFFF))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return false;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return true;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return true;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (!memcmp(pState->config.mac.au8, pvBuf, sizeof(RTMAC)))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return true;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync for (unsigned i = 0; i < pState->nMacFilterEntries; i++)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (!memcmp(&pState->aMacFilter[i], pvBuf, sizeof(RTMAC)))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return true;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync return false;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Pad and store received packet.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @remarks Make sure that the packet appears to upper layer as one coming
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * from real Ethernet: pad it and insert FCS.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns VBox status code.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pState The device state structure.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pvBuf The available data.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param cb Number of bytes available in the buffer.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @thread RX
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic int vnetHandleRxPacket(PVNETSTATE pState, const void *pvBuf, size_t cb)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync vnetPacketDump(pState, (const uint8_t*)pvBuf, cb, "<-- Incoming");
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync unsigned int uOffset = 0;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync for (unsigned int nElem = 0; uOffset < cb; nElem++)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (!vqueueGet(&pState->VPCI, pState->pRxQueue, &elem))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Log(("%s vnetHandleRxPacket: Suddenly there is no space in receive queue!\n", INSTANCE(pState)));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Log(("%s vnetHandleRxPacket: No writable descriptors in receive queue!\n", INSTANCE(pState)));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* The very first segment of the very first element gets the header. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Log(("%s vnetHandleRxPacket: The first descriptor does match the header size!\n", INSTANCE(pState)));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync unsigned int uSize = RT_MIN(elem.aSegsIn[nSeg].cb, cb - uOffset);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync elem.aSegsIn[nSeg++].pv = (uint8_t*)pvBuf + uOffset;
f313ed48a0cc2d9d12580dc9412291ae15773f02vboxsync vqueuePut(&pState->VPCI, pState->pRxQueue, &elem, uElemSize);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Receive data from the network.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns VBox status code.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pInterface Pointer to the interface structure containing the called function pointer.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pvBuf The available data.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param cb Number of bytes available in the buffer.
f313ed48a0cc2d9d12580dc9412291ae15773f02vboxsync * @thread RX
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic DECLCALLBACK(int) vnetReceive(PPDMINETWORKPORT pInterface, const void *pvBuf, size_t cb)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkPort);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Log2(("%s vnetReceive: pvBuf=%p cb=%u\n", INSTANCE(pState), pvBuf, cb));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* Drop packets if VM is not running or cable is disconnected. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync VMSTATE enmVMState = PDMDevHlpVMState(pState->VPCI.CTX_SUFF(pDevIns));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync STAM_REL_COUNTER_ADD(&pState->StatReceiveBytes, cb);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Gets the current Media Access Control (MAC) address.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns VBox status code.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pInterface Pointer to the interface structure containing the called function pointer.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pMac Where to store the MAC address.
230bd8589bba39933ac5ec21482d6186d675e604vboxsync * @thread EMT
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic DECLCALLBACK(int) vnetGetMac(PPDMINETWORKCONFIG pInterface, PRTMAC pMac)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkConfig);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync memcpy(pMac, pState->config.mac.au8, sizeof(RTMAC));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Gets the new link state.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns The current link state.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pInterface Pointer to the interface structure containing the called function pointer.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @thread EMT
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic DECLCALLBACK(PDMNETWORKLINKSTATE) vnetGetLinkState(PPDMINETWORKCONFIG pInterface)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkConfig);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Sets the new link state.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns VBox status code.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pInterface Pointer to the interface structure containing the called function pointer.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param enmState The new link state
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic DECLCALLBACK(int) vnetSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkConfig);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync pState->pDrv->pfnNotifyLinkChanged(pState->pDrv, enmState);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic DECLCALLBACK(void) vnetQueueReceive(void *pvState, PVQUEUE pQueue)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Log(("%s Receive buffers has been added, waking up receive thread.\n", INSTANCE(pState)));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncstatic DECLCALLBACK(void) vnetTransmitPendingPackets(PVNETSTATE pState, PVQUEUE pQueue)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Only one thread is allowed to transmit at a time, others should skip
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * transmission as the packets will be picked up by the transmitting
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (!ASMAtomicCmpXchgU32(&pState->uIsTransmitting, 1, 0))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if ((pState->VPCI.uStatus & VPCI_STATUS_DRV_OK) == 0)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Log(("%s Ignoring transmit requests from non-existent driver (status=0x%x).\n",
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Log3(("%s vnetTransmitPendingPackets: About to trasmit %d pending packets\n", INSTANCE(pState),
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync vringReadAvailIndex(&pState->VPCI, &pState->pTxQueue->VRing) - pState->pTxQueue->uNextAvailIndex));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync unsigned int uOffset = 0;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (elem.nOut < 2 || elem.aSegsOut[0].cb != sizeof(VNETHDR))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Log(("%s vnetQueueTransmit: The first segment is not the header! (%u < 2 || %u != %u).\n",
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync INSTANCE(pState), elem.nOut, elem.aSegsOut[0].cb, sizeof(VNETHDR)));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync break; /* For now we simply ignore the header, but it must be there anyway! */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* Assemble a complete frame. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync for (unsigned int i = 1; i < elem.nOut && uOffset < VNET_MAX_FRAME_SIZE; i++)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Log(("%s vnetQueueTransmit: Packet is too big (>64k), truncating...\n", INSTANCE(pState)));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns), elem.aSegsOut[i].addr,
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync vnetPacketDump(pState, pState->pTxBuf, uOffset, "--> Outgoing");
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync int rc = pState->pDrv->pfnSend(pState->pDrv, pState->pTxBuf, uOffset);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync STAM_REL_COUNTER_ADD(&pState->StatTransmitBytes, uOffset);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync vqueuePut(&pState->VPCI, pQueue, &elem, sizeof(VNETHDR) + uOffset);
#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,