VirtualBox

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

Last change on this file since 91942 was 91897, checked in by vboxsync, 3 years ago

VMM,Devices: Add callbacks to required MMR3* APIs to the helper callbacks tables and convert devices and drivers to make use of those, bugref:10074

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.5 KB
Line 
1/* $Id: DrvVDE.cpp 91897 2021-10-20 13:42:39Z 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-2020 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 int rc;
220 if (!pSgBuf->pvUser)
221 {
222#ifdef LOG_ENABLED
223 uint64_t u64Now = RTTimeProgramNanoTS();
224 LogFlow(("drvVDESend: %-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
225 pSgBuf->cbUsed, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS));
226 pThis->u64LastTransferTS = u64Now;
227#endif
228 Log2(("drvVDESend: pSgBuf->aSegs[0].pvSeg=%p pSgBuf->cbUsed=%#x\n"
229 "%.*Rhxd\n",
230 pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed, pSgBuf->cbUsed, pSgBuf->aSegs[0].pvSeg));
231
232 ssize_t cbSent;
233 cbSent = vde_send(pThis->pVdeConn, pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed, 0);
234 rc = cbSent < 0 ? RTErrConvertFromErrno(-cbSent) : VINF_SUCCESS;
235 }
236 else
237 {
238 uint8_t abHdrScratch[256];
239 uint8_t const *pbFrame = (uint8_t const *)pSgBuf->aSegs[0].pvSeg;
240 PCPDMNETWORKGSO pGso = (PCPDMNETWORKGSO)pSgBuf->pvUser;
241 uint32_t const cSegs = PDMNetGsoCalcSegmentCount(pGso, pSgBuf->cbUsed); Assert(cSegs > 1);
242 rc = 0;
243 for (size_t iSeg = 0; iSeg < cSegs; iSeg++)
244 {
245 uint32_t cbSegFrame;
246 void *pvSegFrame = PDMNetGsoCarveSegmentQD(pGso, (uint8_t *)pbFrame, pSgBuf->cbUsed, abHdrScratch,
247 iSeg, cSegs, &cbSegFrame);
248 ssize_t cbSent;
249 cbSent = vde_send(pThis->pVdeConn, pvSegFrame, cbSegFrame, 0);
250 rc = cbSent < 0 ? RTErrConvertFromErrno(-cbSent) : VINF_SUCCESS;
251 if (RT_FAILURE(rc))
252 break;
253 }
254 }
255
256 pSgBuf->fFlags = 0;
257 RTMemFree(pSgBuf);
258
259 STAM_PROFILE_STOP(&pThis->StatTransmit, a);
260 AssertRC(rc);
261 if (RT_FAILURE(rc))
262 rc = rc == VERR_NO_MEMORY ? VERR_NET_NO_BUFFER_SPACE : VERR_NET_DOWN;
263 return rc;
264}
265
266
267/**
268 * @interface_method_impl{PDMINETWORKUP,pfnEndXmit}
269 */
270static DECLCALLBACK(void) drvVDENetworkUp_EndXmit(PPDMINETWORKUP pInterface)
271{
272 PDRVVDE pThis = PDMINETWORKUP_2_DRVVDE(pInterface);
273 RTCritSectLeave(&pThis->XmitLock);
274}
275
276
277/**
278 * @interface_method_impl{PDMINETWORKUP,pfnSetPromiscuousMode}
279 */
280static DECLCALLBACK(void) drvVDENetworkUp_SetPromiscuousMode(PPDMINETWORKUP pInterface, bool fPromiscuous)
281{
282 RT_NOREF(pInterface, fPromiscuous);
283 LogFlow(("drvVDESetPromiscuousMode: fPromiscuous=%d\n", fPromiscuous));
284 /* nothing to do */
285}
286
287
288/**
289 * Notification on link status changes.
290 *
291 * @param pInterface Pointer to the interface structure containing the called function pointer.
292 * @param enmLinkState The new link state.
293 * @thread EMT
294 */
295static DECLCALLBACK(void) drvVDENetworkUp_NotifyLinkChanged(PPDMINETWORKUP pInterface, PDMNETWORKLINKSTATE enmLinkState)
296{
297 RT_NOREF(pInterface, enmLinkState);
298 LogFlow(("drvNATNetworkUp_NotifyLinkChanged: enmLinkState=%d\n", enmLinkState));
299 /** @todo take action on link down and up. Stop the polling and such like. */
300}
301
302
303/**
304 * Asynchronous I/O thread for handling receive.
305 *
306 * @returns VINF_SUCCESS (ignored).
307 * @param Thread Thread handle.
308 * @param pvUser Pointer to a DRVVDE structure.
309 */
310static DECLCALLBACK(int) drvVDEAsyncIoThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
311{
312 PDRVVDE pThis = PDMINS_2_DATA(pDrvIns, PDRVVDE);
313 LogFlow(("drvVDEAsyncIoThread: pThis=%p\n", pThis));
314
315 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
316 return VINF_SUCCESS;
317
318 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
319
320 /*
321 * Polling loop.
322 */
323 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
324 {
325 /*
326 * Wait for something to become available.
327 */
328 struct pollfd aFDs[2];
329 aFDs[0].fd = vde_datafd(pThis->pVdeConn);
330 aFDs[0].events = POLLIN | POLLPRI;
331 aFDs[0].revents = 0;
332 aFDs[1].fd = RTPipeToNative(pThis->hPipeRead);
333 aFDs[1].events = POLLIN | POLLPRI | POLLERR | POLLHUP;
334 aFDs[1].revents = 0;
335 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
336 errno=0;
337 int rc = poll(&aFDs[0], RT_ELEMENTS(aFDs), -1 /* infinite */);
338
339 /* this might have changed in the meantime */
340 if (pThread->enmState != PDMTHREADSTATE_RUNNING)
341 break;
342
343 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
344 if ( rc > 0
345 && (aFDs[0].revents & (POLLIN | POLLPRI))
346 && !aFDs[1].revents)
347 {
348 /*
349 * Read the frame.
350 */
351 char achBuf[16384];
352 ssize_t cbRead = 0;
353 cbRead = vde_recv(pThis->pVdeConn, achBuf, sizeof(achBuf), 0);
354 rc = cbRead < 0 ? RTErrConvertFromErrno(-cbRead) : VINF_SUCCESS;
355 if (RT_SUCCESS(rc))
356 {
357 /*
358 * Wait for the device to have space for this frame.
359 * Most guests use frame-sized receive buffers, hence non-zero cbMax
360 * automatically means there is enough room for entire frame. Some
361 * guests (eg. Solaris) use large chains of small receive buffers
362 * (each 128 or so bytes large). We will still start receiving as soon
363 * as cbMax is non-zero because:
364 * - it would be quite expensive for pfnCanReceive to accurately
365 * determine free receive buffer space
366 * - if we were waiting for enough free buffers, there is a risk
367 * of deadlocking because the guest could be waiting for a receive
368 * overflow error to allocate more receive buffers
369 */
370 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
371 int rc1 = pThis->pIAboveNet->pfnWaitReceiveAvail(pThis->pIAboveNet, RT_INDEFINITE_WAIT);
372 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
373
374 /*
375 * A return code != VINF_SUCCESS means that we were woken up during a VM
376 * state transition. Drop the packet and wait for the next one.
377 */
378 if (RT_FAILURE(rc1))
379 continue;
380
381 /*
382 * Pass the data up.
383 */
384#ifdef LOG_ENABLED
385 uint64_t u64Now = RTTimeProgramNanoTS();
386 LogFlow(("drvVDEAsyncIoThread: %-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
387 cbRead, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS));
388 pThis->u64LastReceiveTS = u64Now;
389#endif
390 Log2(("drvVDEAsyncIoThread: cbRead=%#x\n" "%.*Rhxd\n", cbRead, cbRead, achBuf));
391 STAM_COUNTER_INC(&pThis->StatPktRecv);
392 STAM_COUNTER_ADD(&pThis->StatPktRecvBytes, cbRead);
393 rc1 = pThis->pIAboveNet->pfnReceive(pThis->pIAboveNet, achBuf, cbRead);
394 AssertRC(rc1);
395 }
396 else
397 {
398 LogFlow(("drvVDEAsyncIoThread: RTFileRead -> %Rrc\n", rc));
399 if (rc == VERR_INVALID_HANDLE)
400 break;
401 RTThreadYield();
402 }
403 }
404 else if ( rc > 0
405 && aFDs[1].revents)
406 {
407 LogFlow(("drvVDEAsyncIoThread: Control message: enmState=%d revents=%#x\n", pThread->enmState, aFDs[1].revents));
408 if (aFDs[1].revents & (POLLHUP | POLLERR | POLLNVAL))
409 break;
410
411 /* drain the pipe */
412 char ch;
413 size_t cbRead;
414 RTPipeRead(pThis->hPipeRead, &ch, 1, &cbRead);
415 }
416 else
417 {
418 /*
419 * poll() failed for some reason. Yield to avoid eating too much CPU.
420 *
421 * EINTR errors have been seen frequently. They should be harmless, even
422 * if they are not supposed to occur in our setup.
423 */
424 if (errno == EINTR)
425 Log(("rc=%d revents=%#x,%#x errno=%p %s\n", rc, aFDs[0].revents, aFDs[1].revents, errno, strerror(errno)));
426 else
427 AssertMsgFailed(("rc=%d revents=%#x,%#x errno=%p %s\n", rc, aFDs[0].revents, aFDs[1].revents, errno, strerror(errno)));
428 RTThreadYield();
429 }
430 }
431
432
433 LogFlow(("drvVDEAsyncIoThread: returns %Rrc\n", VINF_SUCCESS));
434 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
435 return VINF_SUCCESS;
436}
437
438
439/**
440 * Unblock the send thread so it can respond to a state change.
441 *
442 * @returns VBox status code.
443 * @param pDevIns The pcnet device instance.
444 * @param pThread The send thread.
445 */
446static DECLCALLBACK(int) drvVDEAsyncIoWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
447{
448 RT_NOREF(pThread);
449 PDRVVDE pThis = PDMINS_2_DATA(pDrvIns, PDRVVDE);
450
451 size_t cbIgnored;
452 int rc = RTPipeWrite(pThis->hPipeWrite, "", 1, &cbIgnored);
453 AssertRC(rc);
454
455 return VINF_SUCCESS;
456}
457
458
459/* -=-=-=-=- PDMIBASE -=-=-=-=- */
460
461/**
462 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
463 */
464static DECLCALLBACK(void *) drvVDEQueryInterface(PPDMIBASE pInterface, const char *pszIID)
465{
466 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
467 PDRVVDE pThis = PDMINS_2_DATA(pDrvIns, PDRVVDE);
468
469 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
470 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKUP, &pThis->INetworkUp);
471 return NULL;
472}
473
474/* -=-=-=-=- PDMDRVREG -=-=-=-=- */
475
476/**
477 * Destruct a driver instance.
478 *
479 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
480 * resources can be freed correctly.
481 *
482 * @param pDrvIns The driver instance data.
483 */
484static DECLCALLBACK(void) drvVDEDestruct(PPDMDRVINS pDrvIns)
485{
486 LogFlow(("drvVDEDestruct\n"));
487 PDRVVDE pThis = PDMINS_2_DATA(pDrvIns, PDRVVDE);
488 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
489
490 /*
491 * Terminate the control pipe.
492 */
493 if (pThis->hPipeWrite != NIL_RTPIPE)
494 {
495 RTPipeClose(pThis->hPipeWrite);
496 pThis->hPipeWrite = NIL_RTPIPE;
497 }
498 if (pThis->hPipeRead != NIL_RTPIPE)
499 {
500 RTPipeClose(pThis->hPipeRead);
501 pThis->hPipeRead = NIL_RTPIPE;
502 }
503
504 PDMDrvHlpMMHeapFree(pDrvIns, pThis->pszDeviceName);
505 pThis->pszDeviceName = NULL;
506
507 /*
508 * Kill the xmit lock.
509 */
510 if (RTCritSectIsInitialized(&pThis->XmitLock))
511 RTCritSectDelete(&pThis->XmitLock);
512
513 if (pThis->pVdeConn)
514 {
515 vde_close(pThis->pVdeConn);
516 pThis->pVdeConn = NULL;
517 }
518
519#ifdef VBOX_WITH_STATISTICS
520 /*
521 * Deregister statistics.
522 */
523 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatPktSent);
524 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatPktSentBytes);
525 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatPktRecv);
526 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatPktRecvBytes);
527 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatTransmit);
528 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReceive);
529#endif /* VBOX_WITH_STATISTICS */
530}
531
532
533/**
534 * Construct a VDE network transport driver instance.
535 *
536 * @copydoc FNPDMDRVCONSTRUCT
537 */
538static DECLCALLBACK(int) drvVDEConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
539{
540 RT_NOREF(fFlags);
541 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
542 PDRVVDE pThis = PDMINS_2_DATA(pDrvIns, PDRVVDE);
543 PCPDMDRVHLPR3 pHlp = pDrvIns->pHlpR3;
544
545 /*
546 * Init the static parts.
547 */
548 pThis->pDrvIns = pDrvIns;
549 pThis->pszDeviceName = NULL;
550 pThis->hPipeRead = NIL_RTPIPE;
551 pThis->hPipeWrite = NIL_RTPIPE;
552
553 /* IBase */
554 pDrvIns->IBase.pfnQueryInterface = drvVDEQueryInterface;
555 /* INetwork */
556 pThis->INetworkUp.pfnBeginXmit = drvVDENetworkUp_BeginXmit;
557 pThis->INetworkUp.pfnAllocBuf = drvVDENetworkUp_AllocBuf;
558 pThis->INetworkUp.pfnFreeBuf = drvVDENetworkUp_FreeBuf;
559 pThis->INetworkUp.pfnSendBuf = drvVDENetworkUp_SendBuf;
560 pThis->INetworkUp.pfnEndXmit = drvVDENetworkUp_EndXmit;
561 pThis->INetworkUp.pfnSetPromiscuousMode = drvVDENetworkUp_SetPromiscuousMode;
562 pThis->INetworkUp.pfnNotifyLinkChanged = drvVDENetworkUp_NotifyLinkChanged;
563
564#ifdef VBOX_WITH_STATISTICS
565 /*
566 * Statistics.
567 */
568 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktSent, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of sent packets.", "/Drivers/VDE%d/Packets/Sent", pDrvIns->iInstance);
569 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktSentBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of sent bytes.", "/Drivers/VDE%d/Bytes/Sent", pDrvIns->iInstance);
570 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktRecv, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of received packets.", "/Drivers/VDE%d/Packets/Received", pDrvIns->iInstance);
571 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktRecvBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of received bytes.", "/Drivers/VDE%d/Bytes/Received", pDrvIns->iInstance);
572 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet transmit runs.", "/Drivers/VDE%d/Transmit", pDrvIns->iInstance);
573 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet receive runs.", "/Drivers/VDE%d/Receive", pDrvIns->iInstance);
574#endif /* VBOX_WITH_STATISTICS */
575
576 /*
577 * Validate the config.
578 */
579 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "network", "");
580
581 /*
582 * Check that no-one is attached to us.
583 */
584 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
585 ("Configuration error: Not possible to attach anything to this driver!\n"),
586 VERR_PDM_DRVINS_NO_ATTACH);
587
588 /*
589 * Query the network port interface.
590 */
591 pThis->pIAboveNet = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKDOWN);
592 if (!pThis->pIAboveNet)
593 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE,
594 N_("Configuration error: The above device/driver didn't export the network port interface"));
595
596 /*
597 * Read the configuration.
598 */
599 int rc;
600 char szNetwork[RTPATH_MAX];
601 rc = pHlp->pfnCFGMQueryString(pCfg, "network", szNetwork, sizeof(szNetwork));
602 if (RT_FAILURE(rc))
603 *szNetwork=0;
604
605 if (RT_FAILURE(DrvVDELoadVDEPlug()))
606 return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_HIF_OPEN_FAILED, RT_SRC_POS,
607 N_("VDEplug library: not found"));
608 pThis->pVdeConn = vde_open(szNetwork, "VirtualBOX", NULL);
609 if (pThis->pVdeConn == NULL)
610 return PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_PDM_HIF_OPEN_FAILED, RT_SRC_POS,
611 N_("Failed to connect to the VDE SWITCH"));
612
613 /*
614 * Create the transmit lock.
615 */
616 rc = RTCritSectInit(&pThis->XmitLock);
617 AssertRCReturn(rc, rc);
618
619 /*
620 * Create the control pipe.
621 */
622 rc = RTPipeCreate(&pThis->hPipeRead, &pThis->hPipeWrite, 0 /*fFlags*/);
623 AssertRCReturn(rc, rc);
624
625 /*
626 * Create the async I/O thread.
627 */
628 rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pThread, pThis, drvVDEAsyncIoThread, drvVDEAsyncIoWakeup, 128 * _1K, RTTHREADTYPE_IO, "VDE");
629 AssertRCReturn(rc, rc);
630
631 return rc;
632}
633
634
635/**
636 * VDE network transport driver registration record.
637 */
638const PDMDRVREG g_DrvVDE =
639{
640 /* u32Version */
641 PDM_DRVREG_VERSION,
642 /* szName */
643 "VDE",
644 /* szRCMod */
645 "",
646 /* szR0Mod */
647 "",
648 /* pszDescription */
649 "VDE Network Transport Driver",
650 /* fFlags */
651 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
652 /* fClass. */
653 PDM_DRVREG_CLASS_NETWORK,
654 /* cMaxInstances */
655 ~0U,
656 /* cbInstance */
657 sizeof(DRVVDE),
658 /* pfnConstruct */
659 drvVDEConstruct,
660 /* pfnDestruct */
661 drvVDEDestruct,
662 /* pfnRelocate */
663 NULL,
664 /* pfnIOCtl */
665 NULL,
666 /* pfnPowerOn */
667 NULL,
668 /* pfnReset */
669 NULL,
670 /* pfnSuspend */
671 NULL, /** @todo Do power on, suspend and resume handlers! */
672 /* pfnResume */
673 NULL,
674 /* pfnAttach */
675 NULL,
676 /* pfnDetach */
677 NULL,
678 /* pfnPowerOff */
679 NULL,
680 /* pfnSoftReset */
681 NULL,
682 /* u32EndVersion */
683 PDM_DRVREG_VERSION
684};
685
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