VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DrvVDE.cpp@ 76882

Last change on this file since 76882 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.6 KB
Line 
1/* $Id: DrvVDE.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * VDE network transport driver.
4 */
5
6/*
7 * Contributed by Renzo Davoli. VirtualSquare. University of Bologna, 2010
8 *
9 * Copyright (C) 2006-2019 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20
21/*********************************************************************************************************************************
22* Header Files *
23*********************************************************************************************************************************/
24#define LOG_GROUP LOG_GROUP_DRV_TUN
25#include <VBox/log.h>
26#include <VBox/vmm/pdmdrv.h>
27#include <VBox/vmm/pdmnetifs.h>
28#include <VBox/vmm/pdmnetinline.h>
29#include <VBox/VDEPlug.h>
30
31#include <iprt/asm.h>
32#include <iprt/assert.h>
33#include <iprt/ctype.h>
34#include <iprt/file.h>
35#include <iprt/mem.h>
36#include <iprt/param.h>
37#include <iprt/path.h>
38#include <iprt/pipe.h>
39#include <iprt/semaphore.h>
40#include <iprt/string.h>
41#include <iprt/thread.h>
42#include <iprt/uuid.h>
43
44#include <sys/ioctl.h>
45#include <sys/poll.h>
46#include <sys/fcntl.h>
47#include <errno.h>
48#include <unistd.h>
49
50#include "VBoxDD.h"
51
52
53/*********************************************************************************************************************************
54* Structures and Typedefs *
55*********************************************************************************************************************************/
56/**
57 * VDE driver instance data.
58 *
59 * @implements PDMINETWORKUP
60 */
61typedef struct DRVVDE
62{
63 /** The network interface. */
64 PDMINETWORKUP INetworkUp;
65 /** The network interface. */
66 PPDMINETWORKDOWN pIAboveNet;
67 /** Pointer to the driver instance. */
68 PPDMDRVINS pDrvIns;
69 /** The configured VDE device name. */
70 char *pszDeviceName;
71 /** The write end of the control pipe. */
72 RTPIPE hPipeWrite;
73 /** The read end of the control pipe. */
74 RTPIPE hPipeRead;
75 /** Reader thread. */
76 PPDMTHREAD pThread;
77 /** The connection to the VDE switch */
78 VDECONN *pVdeConn;
79
80 /** @todo The transmit thread. */
81 /** Transmit lock used by drvTAPNetworkUp_BeginXmit. */
82 RTCRITSECT XmitLock;
83
84#ifdef VBOX_WITH_STATISTICS
85 /** Number of sent packets. */
86 STAMCOUNTER StatPktSent;
87 /** Number of sent bytes. */
88 STAMCOUNTER StatPktSentBytes;
89 /** Number of received packets. */
90 STAMCOUNTER StatPktRecv;
91 /** Number of received bytes. */
92 STAMCOUNTER StatPktRecvBytes;
93 /** Profiling packet transmit runs. */
94 STAMPROFILE StatTransmit;
95 /** Profiling packet receive runs. */
96 STAMPROFILEADV StatReceive;
97#endif /* VBOX_WITH_STATISTICS */
98
99#ifdef LOG_ENABLED
100 /** The nano ts of the last transfer. */
101 uint64_t u64LastTransferTS;
102 /** The nano ts of the last receive. */
103 uint64_t u64LastReceiveTS;
104#endif
105} DRVVDE, *PDRVVDE;
106
107
108/** Converts a pointer to VDE::INetworkUp to a PRDVVDE. */
109#define PDMINETWORKUP_2_DRVVDE(pInterface) ( (PDRVVDE)((uintptr_t)pInterface - RT_UOFFSETOF(DRVVDE, INetworkUp)) )
110
111
112/*********************************************************************************************************************************
113* Internal Functions *
114*********************************************************************************************************************************/
115
116
117
118/**
119 * @interface_method_impl{PDMINETWORKUP,pfnBeginXmit}
120 */
121static DECLCALLBACK(int) drvVDENetworkUp_BeginXmit(PPDMINETWORKUP pInterface, bool fOnWorkerThread)
122{
123 RT_NOREF(fOnWorkerThread);
124 PDRVVDE pThis = PDMINETWORKUP_2_DRVVDE(pInterface);
125 int rc = RTCritSectTryEnter(&pThis->XmitLock);
126 if (RT_FAILURE(rc))
127 {
128 /** @todo XMIT thread */
129 rc = VERR_TRY_AGAIN;
130 }
131 return rc;
132}
133
134
135/**
136 * @interface_method_impl{PDMINETWORKUP,pfnAllocBuf}
137 */
138static DECLCALLBACK(int) drvVDENetworkUp_AllocBuf(PPDMINETWORKUP pInterface, size_t cbMin,
139 PCPDMNETWORKGSO pGso, PPPDMSCATTERGATHER ppSgBuf)
140{
141 RT_NOREF(pInterface);
142#ifdef VBOX_STRICT
143 PDRVVDE pThis = PDMINETWORKUP_2_DRVVDE(pInterface);
144 Assert(RTCritSectIsOwner(&pThis->XmitLock));
145#endif
146
147 /*
148 * Allocate a scatter / gather buffer descriptor that is immediately
149 * followed by the buffer space of its single segment. The GSO context
150 * comes after that again.
151 */
152 PPDMSCATTERGATHER pSgBuf = (PPDMSCATTERGATHER)RTMemAlloc( RT_ALIGN_Z(sizeof(*pSgBuf), 16)
153 + RT_ALIGN_Z(cbMin, 16)
154 + (pGso ? RT_ALIGN_Z(sizeof(*pGso), 16) : 0));
155 if (!pSgBuf)
156 return VERR_NO_MEMORY;
157
158 /*
159 * Initialize the S/G buffer and return.
160 */
161 pSgBuf->fFlags = PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1;
162 pSgBuf->cbUsed = 0;
163 pSgBuf->cbAvailable = RT_ALIGN_Z(cbMin, 16);
164 pSgBuf->pvAllocator = NULL;
165 if (!pGso)
166 pSgBuf->pvUser = NULL;
167 else
168 {
169 pSgBuf->pvUser = (uint8_t *)(pSgBuf + 1) + pSgBuf->cbAvailable;
170 *(PPDMNETWORKGSO)pSgBuf->pvUser = *pGso;
171 }
172 pSgBuf->cSegs = 1;
173 pSgBuf->aSegs[0].cbSeg = pSgBuf->cbAvailable;
174 pSgBuf->aSegs[0].pvSeg = pSgBuf + 1;
175
176#if 0 /* poison */
177 memset(pSgBuf->aSegs[0].pvSeg, 'F', pSgBuf->aSegs[0].cbSeg);
178#endif
179 *ppSgBuf = pSgBuf;
180 return VINF_SUCCESS;
181}
182
183
184/**
185 * @interface_method_impl{PDMINETWORKUP,pfnFreeBuf}
186 */
187static DECLCALLBACK(int) drvVDENetworkUp_FreeBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf)
188{
189 RT_NOREF(pInterface);
190#ifdef VBOX_STRICT
191 PDRVVDE pThis = PDMINETWORKUP_2_DRVVDE(pInterface);
192 Assert(RTCritSectIsOwner(&pThis->XmitLock));
193#endif
194 if (pSgBuf)
195 {
196 Assert((pSgBuf->fFlags & PDMSCATTERGATHER_FLAGS_MAGIC_MASK) == PDMSCATTERGATHER_FLAGS_MAGIC);
197 pSgBuf->fFlags = 0;
198 RTMemFree(pSgBuf);
199 }
200 return VINF_SUCCESS;
201}
202
203
204/**
205 * @interface_method_impl{PDMINETWORKUP,pfnSendBuf}
206 */
207static DECLCALLBACK(int) drvVDENetworkUp_SendBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)
208{
209 RT_NOREF(fOnWorkerThread);
210 PDRVVDE pThis = PDMINETWORKUP_2_DRVVDE(pInterface);
211 STAM_COUNTER_INC(&pThis->StatPktSent);
212 STAM_COUNTER_ADD(&pThis->StatPktSentBytes, pSgBuf->cbUsed);
213 STAM_PROFILE_START(&pThis->StatTransmit, a);
214
215 AssertPtr(pSgBuf);
216 Assert((pSgBuf->fFlags & PDMSCATTERGATHER_FLAGS_MAGIC_MASK) == PDMSCATTERGATHER_FLAGS_MAGIC);
217 Assert(RTCritSectIsOwner(&pThis->XmitLock));
218
219 /* Set an FTM checkpoint as this operation changes the state permanently. */
220 PDMDrvHlpFTSetCheckpoint(pThis->pDrvIns, FTMCHECKPOINTTYPE_NETWORK);
221
222 int rc;
223 if (!pSgBuf->pvUser)
224 {
225#ifdef LOG_ENABLED
226 uint64_t u64Now = RTTimeProgramNanoTS();
227 LogFlow(("drvVDESend: %-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
228 pSgBuf->cbUsed, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS));
229 pThis->u64LastTransferTS = u64Now;
230#endif
231 Log2(("drvVDESend: pSgBuf->aSegs[0].pvSeg=%p pSgBuf->cbUsed=%#x\n"
232 "%.*Rhxd\n",
233 pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed, pSgBuf->cbUsed, pSgBuf->aSegs[0].pvSeg));
234
235 ssize_t cbSent;
236 cbSent = vde_send(pThis->pVdeConn, pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed, 0);
237 rc = cbSent < 0 ? RTErrConvertFromErrno(-cbSent) : VINF_SUCCESS;
238 }
239 else
240 {
241 uint8_t abHdrScratch[256];
242 uint8_t const *pbFrame = (uint8_t const *)pSgBuf->aSegs[0].pvSeg;
243 PCPDMNETWORKGSO pGso = (PCPDMNETWORKGSO)pSgBuf->pvUser;
244 uint32_t const cSegs = PDMNetGsoCalcSegmentCount(pGso, pSgBuf->cbUsed); Assert(cSegs > 1);
245 rc = 0;
246 for (size_t iSeg = 0; iSeg < cSegs; iSeg++)
247 {
248 uint32_t cbSegFrame;
249 void *pvSegFrame = PDMNetGsoCarveSegmentQD(pGso, (uint8_t *)pbFrame, pSgBuf->cbUsed, abHdrScratch,
250 iSeg, cSegs, &cbSegFrame);
251 ssize_t cbSent;
252 cbSent = vde_send(pThis->pVdeConn, pvSegFrame, cbSegFrame, 0);
253 rc = cbSent < 0 ? RTErrConvertFromErrno(-cbSent) : VINF_SUCCESS;
254 if (RT_FAILURE(rc))
255 break;
256 }
257 }
258
259 pSgBuf->fFlags = 0;
260 RTMemFree(pSgBuf);
261
262 STAM_PROFILE_STOP(&pThis->StatTransmit, a);
263 AssertRC(rc);
264 if (RT_FAILURE(rc))
265 rc = rc == VERR_NO_MEMORY ? VERR_NET_NO_BUFFER_SPACE : VERR_NET_DOWN;
266 return rc;
267}
268
269
270/**
271 * @interface_method_impl{PDMINETWORKUP,pfnEndXmit}
272 */
273static DECLCALLBACK(void) drvVDENetworkUp_EndXmit(PPDMINETWORKUP pInterface)
274{
275 PDRVVDE pThis = PDMINETWORKUP_2_DRVVDE(pInterface);
276 RTCritSectLeave(&pThis->XmitLock);
277}
278
279
280/**
281 * @interface_method_impl{PDMINETWORKUP,pfnSetPromiscuousMode}
282 */
283static DECLCALLBACK(void) drvVDENetworkUp_SetPromiscuousMode(PPDMINETWORKUP pInterface, bool fPromiscuous)
284{
285 RT_NOREF(pInterface, fPromiscuous);
286 LogFlow(("drvVDESetPromiscuousMode: fPromiscuous=%d\n", fPromiscuous));
287 /* nothing to do */
288}
289
290
291/**
292 * Notification on link status changes.
293 *
294 * @param pInterface Pointer to the interface structure containing the called function pointer.
295 * @param enmLinkState The new link state.
296 * @thread EMT
297 */
298static DECLCALLBACK(void) drvVDENetworkUp_NotifyLinkChanged(PPDMINETWORKUP pInterface, PDMNETWORKLINKSTATE enmLinkState)
299{
300 RT_NOREF(pInterface, enmLinkState);
301 LogFlow(("drvNATNetworkUp_NotifyLinkChanged: enmLinkState=%d\n", enmLinkState));
302 /** @todo take action on link down and up. Stop the polling and such like. */
303}
304
305
306/**
307 * Asynchronous I/O thread for handling receive.
308 *
309 * @returns VINF_SUCCESS (ignored).
310 * @param Thread Thread handle.
311 * @param pvUser Pointer to a DRVVDE structure.
312 */
313static DECLCALLBACK(int) drvVDEAsyncIoThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
314{
315 PDRVVDE pThis = PDMINS_2_DATA(pDrvIns, PDRVVDE);
316 LogFlow(("drvVDEAsyncIoThread: pThis=%p\n", pThis));
317
318 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
319 return VINF_SUCCESS;
320
321 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
322
323 /*
324 * Polling loop.
325 */
326 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
327 {
328 /*
329 * Wait for something to become available.
330 */
331 struct pollfd aFDs[2];
332 aFDs[0].fd = vde_datafd(pThis->pVdeConn);
333 aFDs[0].events = POLLIN | POLLPRI;
334 aFDs[0].revents = 0;
335 aFDs[1].fd = RTPipeToNative(pThis->hPipeRead);
336 aFDs[1].events = POLLIN | POLLPRI | POLLERR | POLLHUP;
337 aFDs[1].revents = 0;
338 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
339 errno=0;
340 int rc = poll(&aFDs[0], RT_ELEMENTS(aFDs), -1 /* infinite */);
341
342 /* this might have changed in the meantime */
343 if (pThread->enmState != PDMTHREADSTATE_RUNNING)
344 break;
345
346 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
347 if ( rc > 0
348 && (aFDs[0].revents & (POLLIN | POLLPRI))
349 && !aFDs[1].revents)
350 {
351 /*
352 * Read the frame.
353 */
354 char achBuf[16384];
355 ssize_t cbRead = 0;
356 cbRead = vde_recv(pThis->pVdeConn, achBuf, sizeof(achBuf), 0);
357 rc = cbRead < 0 ? RTErrConvertFromErrno(-cbRead) : VINF_SUCCESS;
358 if (RT_SUCCESS(rc))
359 {
360 /*
361 * Wait for the device to have space for this frame.
362 * Most guests use frame-sized receive buffers, hence non-zero cbMax
363 * automatically means there is enough room for entire frame. Some
364 * guests (eg. Solaris) use large chains of small receive buffers
365 * (each 128 or so bytes large). We will still start receiving as soon
366 * as cbMax is non-zero because:
367 * - it would be quite expensive for pfnCanReceive to accurately
368 * determine free receive buffer space
369 * - if we were waiting for enough free buffers, there is a risk
370 * of deadlocking because the guest could be waiting for a receive
371 * overflow error to allocate more receive buffers
372 */
373 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
374 int rc1 = pThis->pIAboveNet->pfnWaitReceiveAvail(pThis->pIAboveNet, RT_INDEFINITE_WAIT);
375 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
376
377 /*
378 * A return code != VINF_SUCCESS means that we were woken up during a VM
379 * state transition. Drop the packet and wait for the next one.
380 */
381 if (RT_FAILURE(rc1))
382 continue;
383
384 /*
385 * Pass the data up.
386 */
387#ifdef LOG_ENABLED
388 uint64_t u64Now = RTTimeProgramNanoTS();
389 LogFlow(("drvVDEAsyncIoThread: %-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
390 cbRead, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS));
391 pThis->u64LastReceiveTS = u64Now;
392#endif
393 Log2(("drvVDEAsyncIoThread: cbRead=%#x\n" "%.*Rhxd\n", cbRead, cbRead, achBuf));
394 STAM_COUNTER_INC(&pThis->StatPktRecv);
395 STAM_COUNTER_ADD(&pThis->StatPktRecvBytes, cbRead);
396 rc1 = pThis->pIAboveNet->pfnReceive(pThis->pIAboveNet, achBuf, cbRead);
397 AssertRC(rc1);
398 }
399 else
400 {
401 LogFlow(("drvVDEAsyncIoThread: RTFileRead -> %Rrc\n", rc));
402 if (rc == VERR_INVALID_HANDLE)
403 break;
404 RTThreadYield();
405 }
406 }
407 else if ( rc > 0
408 && aFDs[1].revents)
409 {
410 LogFlow(("drvVDEAsyncIoThread: Control message: enmState=%d revents=%#x\n", pThread->enmState, aFDs[1].revents));
411 if (aFDs[1].revents & (POLLHUP | POLLERR | POLLNVAL))
412 break;
413
414 /* drain the pipe */
415 char ch;
416 size_t cbRead;
417 RTPipeRead(pThis->hPipeRead, &ch, 1, &cbRead);
418 }
419 else
420 {
421 /*
422 * poll() failed for some reason. Yield to avoid eating too much CPU.
423 *
424 * EINTR errors have been seen frequently. They should be harmless, even
425 * if they are not supposed to occur in our setup.
426 */
427 if (errno == EINTR)
428 Log(("rc=%d revents=%#x,%#x errno=%p %s\n", rc, aFDs[0].revents, aFDs[1].revents, errno, strerror(errno)));
429 else
430 AssertMsgFailed(("rc=%d revents=%#x,%#x errno=%p %s\n", rc, aFDs[0].revents, aFDs[1].revents, errno, strerror(errno)));
431 RTThreadYield();
432 }
433 }
434
435
436 LogFlow(("drvVDEAsyncIoThread: returns %Rrc\n", VINF_SUCCESS));
437 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
438 return VINF_SUCCESS;
439}
440
441
442/**
443 * Unblock the send thread so it can respond to a state change.
444 *
445 * @returns VBox status code.
446 * @param pDevIns The pcnet device instance.
447 * @param pThread The send thread.
448 */
449static DECLCALLBACK(int) drvVDEAsyncIoWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
450{
451 RT_NOREF(pThread);
452 PDRVVDE pThis = PDMINS_2_DATA(pDrvIns, PDRVVDE);
453
454 size_t cbIgnored;
455 int rc = RTPipeWrite(pThis->hPipeWrite, "", 1, &cbIgnored);
456 AssertRC(rc);
457
458 return VINF_SUCCESS;
459}
460
461
462/* -=-=-=-=- PDMIBASE -=-=-=-=- */
463
464/**
465 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
466 */
467static DECLCALLBACK(void *) drvVDEQueryInterface(PPDMIBASE pInterface, const char *pszIID)
468{
469 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
470 PDRVVDE pThis = PDMINS_2_DATA(pDrvIns, PDRVVDE);
471
472 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
473 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKUP, &pThis->INetworkUp);
474 return NULL;
475}
476
477/* -=-=-=-=- PDMDRVREG -=-=-=-=- */
478
479/**
480 * Destruct a driver instance.
481 *
482 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
483 * resources can be freed correctly.
484 *
485 * @param pDrvIns The driver instance data.
486 */
487static DECLCALLBACK(void) drvVDEDestruct(PPDMDRVINS pDrvIns)
488{
489 LogFlow(("drvVDEDestruct\n"));
490 PDRVVDE pThis = PDMINS_2_DATA(pDrvIns, PDRVVDE);
491 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
492
493 /*
494 * Terminate the control pipe.
495 */
496 if (pThis->hPipeWrite != NIL_RTPIPE)
497 {
498 RTPipeClose(pThis->hPipeWrite);
499 pThis->hPipeWrite = NIL_RTPIPE;
500 }
501 if (pThis->hPipeRead != NIL_RTPIPE)
502 {
503 RTPipeClose(pThis->hPipeRead);
504 pThis->hPipeRead = NIL_RTPIPE;
505 }
506
507 MMR3HeapFree(pThis->pszDeviceName);
508 pThis->pszDeviceName = NULL;
509
510 /*
511 * Kill the xmit lock.
512 */
513 if (RTCritSectIsInitialized(&pThis->XmitLock))
514 RTCritSectDelete(&pThis->XmitLock);
515
516 if (pThis->pVdeConn)
517 {
518 vde_close(pThis->pVdeConn);
519 pThis->pVdeConn = NULL;
520 }
521
522#ifdef VBOX_WITH_STATISTICS
523 /*
524 * Deregister statistics.
525 */
526 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatPktSent);
527 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatPktSentBytes);
528 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatPktRecv);
529 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatPktRecvBytes);
530 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatTransmit);
531 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReceive);
532#endif /* VBOX_WITH_STATISTICS */
533}
534
535
536/**
537 * Construct a VDE network transport driver instance.
538 *
539 * @copydoc FNPDMDRVCONSTRUCT
540 */
541static DECLCALLBACK(int) drvVDEConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
542{
543 RT_NOREF(fFlags);
544 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
545 PDRVVDE pThis = PDMINS_2_DATA(pDrvIns, PDRVVDE);
546
547 /*
548 * Init the static parts.
549 */
550 pThis->pDrvIns = pDrvIns;
551 pThis->pszDeviceName = NULL;
552 pThis->hPipeRead = NIL_RTPIPE;
553 pThis->hPipeWrite = NIL_RTPIPE;
554
555 /* IBase */
556 pDrvIns->IBase.pfnQueryInterface = drvVDEQueryInterface;
557 /* INetwork */
558 pThis->INetworkUp.pfnBeginXmit = drvVDENetworkUp_BeginXmit;
559 pThis->INetworkUp.pfnAllocBuf = drvVDENetworkUp_AllocBuf;
560 pThis->INetworkUp.pfnFreeBuf = drvVDENetworkUp_FreeBuf;
561 pThis->INetworkUp.pfnSendBuf = drvVDENetworkUp_SendBuf;
562 pThis->INetworkUp.pfnEndXmit = drvVDENetworkUp_EndXmit;
563 pThis->INetworkUp.pfnSetPromiscuousMode = drvVDENetworkUp_SetPromiscuousMode;
564 pThis->INetworkUp.pfnNotifyLinkChanged = drvVDENetworkUp_NotifyLinkChanged;
565
566#ifdef VBOX_WITH_STATISTICS
567 /*
568 * Statistics.
569 */
570 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktSent, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of sent packets.", "/Drivers/VDE%d/Packets/Sent", pDrvIns->iInstance);
571 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktSentBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of sent bytes.", "/Drivers/VDE%d/Bytes/Sent", pDrvIns->iInstance);
572 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktRecv, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of received packets.", "/Drivers/VDE%d/Packets/Received", pDrvIns->iInstance);
573 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktRecvBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of received bytes.", "/Drivers/VDE%d/Bytes/Received", pDrvIns->iInstance);
574 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet transmit runs.", "/Drivers/VDE%d/Transmit", pDrvIns->iInstance);
575 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet receive runs.", "/Drivers/VDE%d/Receive", pDrvIns->iInstance);
576#endif /* VBOX_WITH_STATISTICS */
577
578 /*
579 * Validate the config.
580 */
581 if (!CFGMR3AreValuesValid(pCfg, "network"))
582 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES, "");
583
584 /*
585 * Check that no-one is attached to us.
586 */
587 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
588 ("Configuration error: Not possible to attach anything to this driver!\n"),
589 VERR_PDM_DRVINS_NO_ATTACH);
590
591 /*
592 * Query the network port interface.
593 */
594 pThis->pIAboveNet = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKDOWN);
595 if (!pThis->pIAboveNet)
596 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE,
597 N_("Configuration error: The above device/driver didn't export the network port interface"));
598
599 /*
600 * Read the configuration.
601 */
602 int rc;
603 char szNetwork[RTPATH_MAX];
604 rc = CFGMR3QueryString(pCfg, "network", szNetwork, sizeof(szNetwork));
605 if (RT_FAILURE(rc))
606 *szNetwork=0;
607
608 if (RT_FAILURE(DrvVDELoadVDEPlug()))
609 return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_HIF_OPEN_FAILED, RT_SRC_POS,
610 N_("VDEplug library: not found"));
611 pThis->pVdeConn = vde_open(szNetwork, "VirtualBOX", NULL);
612 if (pThis->pVdeConn == NULL)
613 return PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_PDM_HIF_OPEN_FAILED, RT_SRC_POS,
614 N_("Failed to connect to the VDE SWITCH"));
615
616 /*
617 * Create the transmit lock.
618 */
619 rc = RTCritSectInit(&pThis->XmitLock);
620 AssertRCReturn(rc, rc);
621
622 /*
623 * Create the control pipe.
624 */
625 rc = RTPipeCreate(&pThis->hPipeRead, &pThis->hPipeWrite, 0 /*fFlags*/);
626 AssertRCReturn(rc, rc);
627
628 /*
629 * Create the async I/O thread.
630 */
631 rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pThread, pThis, drvVDEAsyncIoThread, drvVDEAsyncIoWakeup, 128 * _1K, RTTHREADTYPE_IO, "VDE");
632 AssertRCReturn(rc, rc);
633
634 return rc;
635}
636
637
638/**
639 * VDE network transport driver registration record.
640 */
641const PDMDRVREG g_DrvVDE =
642{
643 /* u32Version */
644 PDM_DRVREG_VERSION,
645 /* szName */
646 "VDE",
647 /* szRCMod */
648 "",
649 /* szR0Mod */
650 "",
651 /* pszDescription */
652 "VDE Network Transport Driver",
653 /* fFlags */
654 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
655 /* fClass. */
656 PDM_DRVREG_CLASS_NETWORK,
657 /* cMaxInstances */
658 ~0U,
659 /* cbInstance */
660 sizeof(DRVVDE),
661 /* pfnConstruct */
662 drvVDEConstruct,
663 /* pfnDestruct */
664 drvVDEDestruct,
665 /* pfnRelocate */
666 NULL,
667 /* pfnIOCtl */
668 NULL,
669 /* pfnPowerOn */
670 NULL,
671 /* pfnReset */
672 NULL,
673 /* pfnSuspend */
674 NULL, /** @todo Do power on, suspend and resume handlers! */
675 /* pfnResume */
676 NULL,
677 /* pfnAttach */
678 NULL,
679 /* pfnDetach */
680 NULL,
681 /* pfnPowerOff */
682 NULL,
683 /* pfnSoftReset */
684 NULL,
685 /* u32EndVersion */
686 PDM_DRVREG_VERSION
687};
688
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette