DrvUDPTunnel.cpp revision 1e1273b11e17928ec3c3a8fff45121aa7a169413
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh * DrvUDPTunnel - UDP tunnel network transport driver
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh * Based on code contributed by Christophe Devriese
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh * Copyright (C) 2009-2012 Oracle Corporation
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh * This file is part of VirtualBox Open Source Edition (OSE), as
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh * available from http://www.virtualbox.org. This file is free software;
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh * you can redistribute it and/or modify it under the terms of the GNU
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh * General Public License (GPL) as published by the Free Software
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh * Foundation, in version 2 as it comes in the "COPYING" file of the
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh/*******************************************************************************
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh* Header Files *
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh*******************************************************************************/
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh/*******************************************************************************
50c9d542e8bf641412debaa82a4dcf67ddb72258Lukas Slebodnik* Structures and Typedefs *
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik*******************************************************************************/
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh * UDP tunnel driver instance data.
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik * @implements PDMINETWORKUP
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh /** The network interface. */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik /** The network interface. */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik /** Pointer to the driver instance. */
25255e4d0e1517a5d443e8fee22e91862e255702Abhishek Singh /** UDP tunnel source port. */
25255e4d0e1517a5d443e8fee22e91862e255702Abhishek Singh /** UDP tunnel destination port. */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik /** UDP tunnel destination IP address. */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik /** UDP tunnel instance string. */
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh /** UDP destination address. */
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh /** Transmit lock used by drvUDPTunnelUp_BeginXmit. */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik /** Server data structure for UDP communication. */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik /** Flag whether the link is down. */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik bool volatile fLinkDown;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik /** Number of sent packets. */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik /** Number of sent bytes. */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik /** Number of received packets. */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik /** Number of received bytes. */
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek /** Profiling packet transmit runs. */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik /** Profiling packet receive runs. */
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh#endif /* VBOX_WITH_STATISTICS */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik /** The nano ts of the last transfer. */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik /** The nano ts of the last receive. */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik/** Converts a pointer to UDPTUNNEL::INetworkUp to a PRDVUDPTUNNEL. */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik#define PDMINETWORKUP_2_DRVUDPTUNNEL(pInterface) ( (PDRVUDPTUNNEL)((uintptr_t)pInterface - RT_OFFSETOF(DRVUDPTUNNEL, INetworkUp)) )
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik/*******************************************************************************
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik* Internal Functions *
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik*******************************************************************************/
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik * @interface_method_impl{PDMINETWORKUP,pfnBeginXmit}
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnikstatic DECLCALLBACK(int) drvUDPTunnelUp_BeginXmit(PPDMINETWORKUP pInterface, bool fOnWorkerThread)
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik PDRVUDPTUNNEL pThis = PDMINETWORKUP_2_DRVUDPTUNNEL(pInterface);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik int rc = RTCritSectTryEnter(&pThis->XmitLock);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik /** @todo XMIT thread */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik * @interface_method_impl{PDMINETWORKUP,pfnAllocBuf}
25255e4d0e1517a5d443e8fee22e91862e255702Abhishek Singhstatic DECLCALLBACK(int) drvUDPTunnelUp_AllocBuf(PPDMINETWORKUP pInterface, size_t cbMin,
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik PCPDMNETWORKGSO pGso, PPPDMSCATTERGATHER ppSgBuf)
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik PDRVUDPTUNNEL pThis = PDMINETWORKUP_2_DRVUDPTUNNEL(pInterface);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik Assert(RTCritSectIsOwner(&pThis->XmitLock));
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik * Allocate a scatter / gather buffer descriptor that is immediately
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik * followed by the buffer space of its single segment. The GSO context
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik * comes after that again.
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik PPDMSCATTERGATHER pSgBuf = (PPDMSCATTERGATHER)RTMemAlloc( RT_ALIGN_Z(sizeof(*pSgBuf), 16)
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik + (pGso ? RT_ALIGN_Z(sizeof(*pGso), 16) : 0));
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek * Initialize the S/G buffer and return.
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh pSgBuf->fFlags = PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik pSgBuf->pvUser = (uint8_t *)(pSgBuf + 1) + pSgBuf->cbAvailable;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik pSgBuf->aSegs[0].cbSeg = pSgBuf->cbAvailable;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik#if 0 /* poison */
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik memset(pSgBuf->aSegs[0].pvSeg, 'F', pSgBuf->aSegs[0].cbSeg);
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh * @interface_method_impl{PDMINETWORKUP,pfnFreeBuf}
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singhstatic DECLCALLBACK(int) drvUDPTunnelUp_FreeBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf)
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh PDRVUDPTUNNEL pThis = PDMINETWORKUP_2_DRVUDPTUNNEL(pInterface);
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik Assert(RTCritSectIsOwner(&pThis->XmitLock));
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh Assert((pSgBuf->fFlags & PDMSCATTERGATHER_FLAGS_MAGIC_MASK) == PDMSCATTERGATHER_FLAGS_MAGIC);
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh * @interface_method_impl{PDMINETWORKUP,pfnSendBuf}
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singhstatic DECLCALLBACK(int) drvUDPTunnelUp_SendBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh PDRVUDPTUNNEL pThis = PDMINETWORKUP_2_DRVUDPTUNNEL(pInterface);
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh STAM_COUNTER_ADD(&pThis->StatPktSentBytes, pSgBuf->cbUsed);
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh Assert((pSgBuf->fFlags & PDMSCATTERGATHER_FLAGS_MAGIC_MASK) == PDMSCATTERGATHER_FLAGS_MAGIC);
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh /* Set an FTM checkpoint as this operation changes the state permanently. */
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh PDMDrvHlpFTSetCheckpoint(pThis->pDrvIns, FTMCHECKPOINTTYPE_NETWORK);
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh LogFunc(("%-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh pSgBuf->cbUsed, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS));
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh Log2(("pSgBuf->aSegs[0].pvSeg=%p pSgBuf->cbUsed=%#x\n%.*Rhxd\n",
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed, pSgBuf->cbUsed, pSgBuf->aSegs[0].pvSeg));
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh rc = RTUdpWrite(pThis->pServer, pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed, &pThis->DestAddress);
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh uint8_t const *pbFrame = (uint8_t const *)pSgBuf->aSegs[0].pvSeg;
f333ca01311000475db0fbd059243d05f9a90e96Lukas Slebodnik PCPDMNETWORKGSO pGso = (PCPDMNETWORKGSO)pSgBuf->pvUser;
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh uint32_t const cSegs = PDMNetGsoCalcSegmentCount(pGso, pSgBuf->cbUsed); Assert(cSegs > 1);
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh void *pvSegFrame = PDMNetGsoCarveSegmentQD(pGso, (uint8_t *)pbFrame, pSgBuf->cbUsed, abHdrScratch,
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh rc = RTUdpWrite(pThis->pServer, pvSegFrame, cbSegFrame, &pThis->DestAddress);
return rc;
static DECLCALLBACK(void) drvUDPTunnelUp_SetPromiscuousMode(PPDMINETWORKUP pInterface, bool fPromiscuous)
static DECLCALLBACK(void) drvUDPTunnelUp_NotifyLinkChanged(PPDMINETWORKUP pInterface, PDMNETWORKLINKSTATE enmLinkState)
bool fLinkDown;
switch (enmLinkState)
case PDMNETWORKLINKSTATE_DOWN:
fLinkDown = true;
case PDMNETWORKLINKSTATE_UP:
fLinkDown = false;
return VINF_SUCCESS;
#ifdef LOG_ENABLED
return VERR_UDP_SERVER_STOP;
return VINF_SUCCESS;
return NULL;
#ifdef VBOX_WITH_STATISTICS
#ifdef VBOX_WITH_STATISTICS
PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktSent, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of sent packets.", "/Drivers/UDPTunnel%d/Packets/Sent", pDrvIns->iInstance);
PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktSentBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of sent bytes.", "/Drivers/UDPTunnel%d/Bytes/Sent", pDrvIns->iInstance);
PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktRecv, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of received packets.", "/Drivers/UDPTunnel%d/Packets/Received", pDrvIns->iInstance);
PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktRecvBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of received bytes.", "/Drivers/UDPTunnel%d/Bytes/Received", pDrvIns->iInstance);
PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet transmit runs.", "/Drivers/UDPTunnel%d/Transmit", pDrvIns->iInstance);
PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet receive runs.", "/Drivers/UDPTunnel%d/Receive", pDrvIns->iInstance);
int rc;
LogRel(("UDPTunnel#%d: sport=%d;dest=%s;dport=%d\n", pDrvIns->iInstance, pThis->uSrcPort, pThis->pszDestIP, pThis->uDestPort));
return rc;
sizeof(DRVUDPTUNNEL),
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,