VirtualBox

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

Last change on this file since 29354 was 29122, checked in by vboxsync, 15 years ago

FE/Qt, Devices: moved VDE plugin headers into include/VBox and enabled VDE in the GUI, but only if the plugin is found on the host (Linux and FreeBSD only)

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