VirtualBox

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

Last change on this file since 48107 was 45061, checked in by vboxsync, 12 years ago

Review of PDM driver destructors making sure that variables they use are correctly initialized in the constructor. Found several RTFileClose(0) cases.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.9 KB
Line 
1/* $Id: DrvVDE.cpp 45061 2013-03-18 14:09:03Z 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 if (pThis->hPipeWrite != NIL_RTPIPE)
484 {
485 RTPipeClose(pThis->hPipeWrite);
486 pThis->hPipeWrite = NIL_RTPIPE;
487 }
488 if (pThis->hPipeRead != NIL_RTPIPE)
489 {
490 RTPipeClose(pThis->hPipeRead);
491 pThis->hPipeRead = NIL_RTPIPE;
492 }
493
494 MMR3HeapFree(pThis->pszDeviceName);
495 pThis->pszDeviceName = NULL;
496
497 /*
498 * Kill the xmit lock.
499 */
500 if (RTCritSectIsInitialized(&pThis->XmitLock))
501 RTCritSectDelete(&pThis->XmitLock);
502
503 if (pThis->pVdeConn)
504 {
505 vde_close(pThis->pVdeConn);
506 pThis->pVdeConn = NULL;
507 }
508
509#ifdef VBOX_WITH_STATISTICS
510 /*
511 * Deregister statistics.
512 */
513 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatPktSent);
514 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatPktSentBytes);
515 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatPktRecv);
516 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatPktRecvBytes);
517 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatTransmit);
518 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReceive);
519#endif /* VBOX_WITH_STATISTICS */
520}
521
522
523/**
524 * Construct a VDE network transport driver instance.
525 *
526 * @copydoc FNPDMDRVCONSTRUCT
527 */
528static DECLCALLBACK(int) drvVDEConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
529{
530 PDRVVDE pThis = PDMINS_2_DATA(pDrvIns, PDRVVDE);
531 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
532
533 /*
534 * Init the static parts.
535 */
536 pThis->pDrvIns = pDrvIns;
537 pThis->pszDeviceName = NULL;
538 pThis->hPipeRead = NIL_RTPIPE;
539 pThis->hPipeWrite = NIL_RTPIPE;
540
541 /* IBase */
542 pDrvIns->IBase.pfnQueryInterface = drvVDEQueryInterface;
543 /* INetwork */
544 pThis->INetworkUp.pfnBeginXmit = drvVDENetworkUp_BeginXmit;
545 pThis->INetworkUp.pfnAllocBuf = drvVDENetworkUp_AllocBuf;
546 pThis->INetworkUp.pfnFreeBuf = drvVDENetworkUp_FreeBuf;
547 pThis->INetworkUp.pfnSendBuf = drvVDENetworkUp_SendBuf;
548 pThis->INetworkUp.pfnEndXmit = drvVDENetworkUp_EndXmit;
549 pThis->INetworkUp.pfnSetPromiscuousMode = drvVDENetworkUp_SetPromiscuousMode;
550 pThis->INetworkUp.pfnNotifyLinkChanged = drvVDENetworkUp_NotifyLinkChanged;
551
552#ifdef VBOX_WITH_STATISTICS
553 /*
554 * Statistics.
555 */
556 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktSent, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of sent packets.", "/Drivers/VDE%d/Packets/Sent", pDrvIns->iInstance);
557 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktSentBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of sent bytes.", "/Drivers/VDE%d/Bytes/Sent", pDrvIns->iInstance);
558 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktRecv, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of received packets.", "/Drivers/VDE%d/Packets/Received", pDrvIns->iInstance);
559 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktRecvBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of received bytes.", "/Drivers/VDE%d/Bytes/Received", pDrvIns->iInstance);
560 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet transmit runs.", "/Drivers/VDE%d/Transmit", pDrvIns->iInstance);
561 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet receive runs.", "/Drivers/VDE%d/Receive", pDrvIns->iInstance);
562#endif /* VBOX_WITH_STATISTICS */
563
564 /*
565 * Validate the config.
566 */
567 if (!CFGMR3AreValuesValid(pCfg, "network"))
568 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES, "");
569
570 /*
571 * Check that no-one is attached to us.
572 */
573 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
574 ("Configuration error: Not possible to attach anything to this driver!\n"),
575 VERR_PDM_DRVINS_NO_ATTACH);
576
577 /*
578 * Query the network port interface.
579 */
580 pThis->pIAboveNet = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKDOWN);
581 if (!pThis->pIAboveNet)
582 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE,
583 N_("Configuration error: The above device/driver didn't export the network port interface"));
584
585 /*
586 * Read the configuration.
587 */
588 int rc;
589 char szNetwork[RTPATH_MAX];
590 rc = CFGMR3QueryString(pCfg, "network", szNetwork, sizeof(szNetwork));
591 if (RT_FAILURE(rc))
592 *szNetwork=0;
593
594 if (RT_FAILURE(DrvVDELoadVDEPlug()))
595 return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_HIF_OPEN_FAILED, RT_SRC_POS,
596 N_("VDEplug library: not found"));
597 pThis->pVdeConn = vde_open(szNetwork, "VirtualBOX", NULL);
598 if (pThis->pVdeConn == NULL)
599 return PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_PDM_HIF_OPEN_FAILED, RT_SRC_POS,
600 N_("Failed to connect to the VDE SWITCH"));
601
602 /*
603 * Create the transmit lock.
604 */
605 rc = RTCritSectInit(&pThis->XmitLock);
606 AssertRCReturn(rc, rc);
607
608 /*
609 * Create the control pipe.
610 */
611 rc = RTPipeCreate(&pThis->hPipeRead, &pThis->hPipeWrite, 0 /*fFlags*/);
612 AssertRCReturn(rc, rc);
613
614 /*
615 * Create the async I/O thread.
616 */
617 rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pThread, pThis, drvVDEAsyncIoThread, drvVDEAsyncIoWakeup, 128 * _1K, RTTHREADTYPE_IO, "VDE");
618 AssertRCReturn(rc, rc);
619
620 return rc;
621}
622
623
624/**
625 * VDE network transport driver registration record.
626 */
627const PDMDRVREG g_DrvVDE =
628{
629 /* u32Version */
630 PDM_DRVREG_VERSION,
631 /* szName */
632 "VDE",
633 /* szRCMod */
634 "",
635 /* szR0Mod */
636 "",
637 /* pszDescription */
638 "VDE Network Transport Driver",
639 /* fFlags */
640 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
641 /* fClass. */
642 PDM_DRVREG_CLASS_NETWORK,
643 /* cMaxInstances */
644 ~0U,
645 /* cbInstance */
646 sizeof(DRVVDE),
647 /* pfnConstruct */
648 drvVDEConstruct,
649 /* pfnDestruct */
650 drvVDEDestruct,
651 /* pfnRelocate */
652 NULL,
653 /* pfnIOCtl */
654 NULL,
655 /* pfnPowerOn */
656 NULL,
657 /* pfnReset */
658 NULL,
659 /* pfnSuspend */
660 NULL, /** @todo Do power on, suspend and resume handlers! */
661 /* pfnResume */
662 NULL,
663 /* pfnAttach */
664 NULL,
665 /* pfnDetach */
666 NULL,
667 /* pfnPowerOff */
668 NULL,
669 /* pfnSoftReset */
670 NULL,
671 /* u32EndVersion */
672 PDM_DRVREG_VERSION
673};
674
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