VirtualBox

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

Last change on this file since 44582 was 44528, checked in by vboxsync, 12 years ago

header (C) fixes

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