VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DrvTAP.cpp@ 559

Last change on this file since 559 was 559, checked in by vboxsync, 18 years ago

Added INetworkConnector callback for sending multiple packets

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.7 KB
Line 
1/** @file
2 *
3 * VBox network devices:
4 * Linux TAP network transport driver
5 */
6
7/*
8 *
9 * Copyright (C) 2006 InnoTek Systemberatung GmbH
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.215389.xyz. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License as published by the Free Software Foundation,
15 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
16 * distribution. VirtualBox OSE is distributed in the hope that it will
17 * be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * If you received this file as part of a commercial VirtualBox
20 * distribution, then only the terms of your commercial VirtualBox
21 * license agreement apply instead of the previous paragraph.
22 *
23 */
24
25#define ASYNC_NET
26
27/*******************************************************************************
28* Header Files *
29*******************************************************************************/
30#define LOG_GROUP LOG_GROUP_DRV_TUN
31#include <VBox/cfgm.h>
32#include <VBox/err.h>
33#include <VBox/log.h>
34#include <VBox/mm.h>
35#include <VBox/pdm.h>
36
37#include <iprt/assert.h>
38#include <iprt/file.h>
39#include <iprt/string.h>
40#ifdef ASYNC_NET
41#include <iprt/thread.h>
42#include <iprt/asm.h>
43#include <iprt/semaphore.h>
44#endif
45
46#include <sys/ioctl.h>
47#include <sys/poll.h>
48#include <sys/fcntl.h>
49#include <errno.h>
50#ifdef ASYNC_NET
51#include <unistd.h>
52#endif
53
54#include "Builtins.h"
55
56
57/*******************************************************************************
58* Structures and Typedefs *
59*******************************************************************************/
60typedef enum ASYNCSTATE
61{
62 //ASYNCSTATE_SUSPENDED = 1,
63 ASYNCSTATE_RUNNING,
64 ASYNCSTATE_TERMINATE
65} ASYNCSTATE;
66
67/**
68 * Block driver instance data.
69 */
70typedef struct DRVTAP
71{
72 /** The network interface. */
73 PDMINETWORKCONNECTOR INetworkConnector;
74 /** The network interface. */
75 PPDMINETWORKPORT pPort;
76 /** Pointer to the driver instance. */
77 PPDMDRVINS pDrvIns;
78 /** TAP device file handle. */
79 RTFILE FileDevice;
80#ifdef ASYNC_NET
81 /** The write end of the control pipe. */
82 RTFILE PipeWrite;
83 /** The read end of the control pipe. */
84 RTFILE PipeRead;
85 /** The thread state. */
86 ASYNCSTATE volatile enmState;
87 /** Reader thread. */
88 RTTHREAD Thread;
89 /** We are waiting for more receive buffers. */
90 uint32_t volatile fOutOfSpace;
91 /** Event semaphore for blocking on receive. */
92 RTSEMEVENT EventOutOfSpace;
93#endif
94
95#ifdef VBOX_WITH_STATISTICS
96 /** Number of sent packets. */
97 STAMCOUNTER StatPktSent;
98 /** Number of sent bytes. */
99 STAMCOUNTER StatPktSentBytes;
100 /** Number of received packets. */
101 STAMCOUNTER StatPktRecv;
102 /** Number of received bytes. */
103 STAMCOUNTER StatPktRecvBytes;
104 /** Profiling packet transmit runs. */
105 STAMPROFILE StatTransmit;
106 /** Profiling packet receive runs. */
107 STAMPROFILEADV StatReceive;
108#ifdef ASYNC_NET
109 STAMPROFILE StatRecvOverflows;
110#endif
111#endif /* VBOX_WITH_STATISTICS */
112
113#ifdef LOG_ENABLED
114 /** The nano ts of the last transfer. */
115 uint64_t u64LastTransferTS;
116 /** The nano ts of the last receive. */
117 uint64_t u64LastReceiveTS;
118#endif
119} DRVTAP, *PDRVTAP;
120
121
122/** Converts a pointer to TAP::INetworkConnector to a PRDVTAP. */
123#define PDMINETWORKCONNECTOR_2_DRVTAP(pInterface) ( (PDRVTAP)((uintptr_t)pInterface - RT_OFFSETOF(DRVTAP, INetworkConnector)) )
124
125
126/**
127 * Send data to the network.
128 *
129 * @returns VBox status code.
130 * @param pInterface Pointer to the interface structure containing the called function pointer.
131 * @param pvBuf Data to send.
132 * @param cb Number of bytes to send.
133 * @thread EMT
134 */
135static DECLCALLBACK(int) drvTAPSend(PPDMINETWORKCONNECTOR pInterface, const void *pvBuf, size_t cb)
136{
137 PDRVTAP pData = PDMINETWORKCONNECTOR_2_DRVTAP(pInterface);
138 STAM_COUNTER_INC(&pData->StatPktSent);
139 STAM_COUNTER_ADD(&pData->StatPktSentBytes, cb);
140 STAM_PROFILE_START(&pData->StatTransmit, a);
141
142#ifdef LOG_ENABLED
143 uint64_t u64Now = RTTimeProgramNanoTS();
144 LogFlow(("drvTAPSend: %-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
145 cb, u64Now, u64Now - pData->u64LastReceiveTS, u64Now - pData->u64LastTransferTS));
146 pData->u64LastTransferTS = u64Now;
147#endif
148 Log2(("drvTAPSend: pvBuf=%p cb=%#x\n"
149 "%.*Vhxd\n",
150 pvBuf, cb, cb, pvBuf));
151
152 int rc = RTFileWrite(pData->FileDevice, pvBuf, cb, NULL);
153
154 STAM_PROFILE_STOP(&pData->StatTransmit, a);
155 AssertRC(rc);
156 return rc;
157}
158
159/**
160 * Send multiple data packets to the network.
161 *
162 * @returns VBox status code.
163 * @param pInterface Pointer to the interface structure containing the called function pointer.
164 * @param cPackets Number of packets
165 * @param paPacket Packet description array
166 * @thread EMT
167 */
168static DECLCALLBACK(int) drvTAPSendEx(PPDMINETWORKCONNECTOR pInterface, uint32_t cPackets, PPDMINETWORKPACKET paPacket)
169{
170 int rc = VERR_INVALID_PARAMETER;
171
172 for (uint32_t i=0;i<cPackets;i++)
173 {
174 rc = drvTAPSend(pInterface, paPacket[i].pvBuf, paPacket[i].cb);
175 if (VBOX_FAILURE(rc))
176 break;
177 }
178 return rc;
179}
180
181/**
182 * Set promiscuous mode.
183 *
184 * This is called when the promiscuous mode is set. This means that there doesn't have
185 * to be a mode change when it's called.
186 *
187 * @param pInterface Pointer to the interface structure containing the called function pointer.
188 * @param fPromiscuous Set if the adaptor is now in promiscuous mode. Clear if it is not.
189 * @thread EMT
190 */
191static DECLCALLBACK(void) drvTAPSetPromiscuousMode(PPDMINETWORKCONNECTOR pInterface, bool fPromiscuous)
192{
193 LogFlow(("drvTAPSetPromiscuousMode: fPromiscuous=%d\n", fPromiscuous));
194 /* nothing to do */
195}
196
197
198/**
199 * Notification on link status changes.
200 *
201 * @param pInterface Pointer to the interface structure containing the called function pointer.
202 * @param enmLinkState The new link state.
203 * @thread EMT
204 */
205static DECLCALLBACK(void) drvTAPNotifyLinkChanged(PPDMINETWORKCONNECTOR pInterface, PDMNETWORKLINKSTATE enmLinkState)
206{
207 LogFlow(("drvNATNotifyLinkChanged: enmLinkState=%d\n", enmLinkState));
208 /** @todo take action on link down and up. Stop the polling and such like. */
209}
210
211
212/**
213 * More receive buffer has become available.
214 *
215 * This is called when the NIC frees up receive buffers.
216 *
217 * @param pInterface Pointer to the interface structure containing the called function pointer.
218 * @thread EMT
219 */
220static DECLCALLBACK(void) drvTAPNotifyCanReceive(PPDMINETWORKCONNECTOR pInterface)
221{
222 PDRVTAP pData = PDMINETWORKCONNECTOR_2_DRVTAP(pInterface);
223
224 LogFlow(("drvTAPNotifyCanReceive:\n"));
225 /* ensure we wake up only once */
226 if (ASMAtomicXchgU32(&pData->fOutOfSpace, false))
227 RTSemEventSignal(pData->EventOutOfSpace);
228}
229
230
231#ifdef ASYNC_NET
232/**
233 * Asynchronous I/O thread for handling receive.
234 *
235 * @returns VINF_SUCCESS (ignored).
236 * @param Thread Thread handle.
237 * @param pvUser Pointer to a DRVTAP structure.
238 */
239static DECLCALLBACK(int) drvTAPAsyncIoThread(RTTHREAD ThreadSelf, void *pvUser)
240{
241 PDRVTAP pData = (PDRVTAP)pvUser;
242 LogFlow(("drvTAPAsyncIoThread: pData=%p\n", pData));
243 STAM_PROFILE_ADV_START(&pData->StatReceive, a);
244
245 int rc = RTSemEventCreate(&pData->EventOutOfSpace);
246 AssertRC(rc);
247
248 /*
249 * Polling loop.
250 */
251 for (;;)
252 {
253 /*
254 * Wait for something to become available.
255 */
256 struct pollfd aFDs[2];
257 aFDs[0].fd = pData->FileDevice;
258 aFDs[0].events = POLLIN | POLLPRI;
259 aFDs[0].revents = 0;
260 aFDs[1].fd = pData->PipeRead;
261 aFDs[1].events = POLLIN | POLLPRI | POLLERR | POLLHUP;
262 aFDs[1].revents = 0;
263 STAM_PROFILE_ADV_STOP(&pData->StatReceive, a);
264 errno=0;
265 rc = poll(&aFDs[0], ELEMENTS(aFDs), -1 /* infinite */);
266 STAM_PROFILE_ADV_START(&pData->StatReceive, a);
267 if ( rc > 0
268 && (aFDs[0].revents & (POLLIN | POLLPRI))
269 && !aFDs[1].revents)
270 {
271 /*
272 * Read the frame.
273 */
274 char achBuf[4096];
275 unsigned cbRead = 0;
276 rc = RTFileRead(pData->FileDevice, achBuf, sizeof(achBuf), &cbRead);
277 if (VBOX_SUCCESS(rc))
278 {
279 AssertMsg(cbRead <= 1536, ("cbRead=%d\n", cbRead));
280
281 /*
282 * Wait for the device to have space for this frame.
283 */
284 size_t cbMax = pData->pPort->pfnCanReceive(pData->pPort);
285 if (cbMax < cbRead)
286 {
287 /** @todo receive overflow handling needs serious improving! */
288 STAM_PROFILE_ADV_STOP(&pData->StatReceive, a);
289 STAM_PROFILE_START(&pData->StatRecvOverflows, b);
290 while ( cbMax < cbRead
291 && pData->enmState != ASYNCSTATE_TERMINATE)
292 {
293 LogFlow(("drvTAPAsyncIoThread: cbMax=%d cbRead=%d waiting...\n", cbMax, cbRead));
294#if 1
295 /* We get signalled by the network driver. 50ms is just for sanity */
296 ASMAtomicXchgU32(&pData->fOutOfSpace, true);
297 RTSemEventWait(pData->EventOutOfSpace, 50);
298#else
299 RTThreadSleep(1);
300#endif
301 cbMax = pData->pPort->pfnCanReceive(pData->pPort);
302 }
303 ASMAtomicXchgU32(&pData->fOutOfSpace, false);
304 STAM_PROFILE_STOP(&pData->StatRecvOverflows, b);
305 STAM_PROFILE_ADV_START(&pData->StatReceive, a);
306 if (pData->enmState == ASYNCSTATE_TERMINATE)
307 break;
308 }
309
310 /*
311 * Pass the data up.
312 */
313#ifdef LOG_ENABLED
314 uint64_t u64Now = RTTimeProgramNanoTS();
315 LogFlow(("drvTAPAsyncIoThread: %-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
316 cbRead, u64Now, u64Now - pData->u64LastReceiveTS, u64Now - pData->u64LastTransferTS));
317 pData->u64LastReceiveTS = u64Now;
318#endif
319 Log2(("drvTAPAsyncIoThread: cbRead=%#x\n"
320 "%.*Vhxd\n",
321 cbRead, cbRead, achBuf));
322 STAM_COUNTER_INC(&pData->StatPktRecv);
323 STAM_COUNTER_ADD(&pData->StatPktRecvBytes, cbRead);
324 rc = pData->pPort->pfnReceive(pData->pPort, achBuf, cbRead);
325 AssertRC(rc);
326 }
327 else
328 {
329 LogFlow(("drvTAPAsyncIoThread: RTFileRead -> %Vrc\n", rc));
330 if (rc == VERR_INVALID_HANDLE)
331 break;
332 RTThreadYield();
333 }
334 }
335 else if ( rc > 0
336 && aFDs[1].revents)
337 {
338 LogFlow(("drvTAPAsyncIoThread: Control message: enmState=%d revents=%#x\n", pData->enmState, aFDs[1].revents));
339 if (pData->enmState == ASYNCSTATE_TERMINATE)
340 break;
341 if (aFDs[1].revents & (POLLHUP | POLLERR | POLLNVAL))
342 break;
343
344 /* drain the pipe */
345 char ch;
346 unsigned cbRead;
347 RTFileRead(pData->PipeRead, &ch, 1, &cbRead);
348 }
349 else
350 {
351 /*
352 * poll() failed for some reason. Yield to avoid eating too much CPU.
353 *
354 * EINTR errors have been seen frequently. They should be harmless, even
355 * if they are not supposed to occur in our setup.
356 */
357 if (errno == EINTR)
358 Log(("rc=%d revents=%#x,%#x errno=%p %s\n", rc, aFDs[0].revents, aFDs[1].revents, errno, strerror(errno)));
359 else
360 AssertMsgFailed(("rc=%d revents=%#x,%#x errno=%p %s\n", rc, aFDs[0].revents, aFDs[1].revents, errno, strerror(errno)));
361 RTThreadYield();
362 }
363 }
364
365 rc = RTSemEventDestroy(pData->EventOutOfSpace);
366 AssertRC(rc);
367
368 LogFlow(("drvTAPAsyncIoThread: returns %Vrc\n", VINF_SUCCESS));
369 STAM_PROFILE_ADV_STOP(&pData->StatReceive, a);
370 return VINF_SUCCESS;
371}
372
373#else
374/**
375 * Poller callback.
376 */
377static DECLCALLBACK(void) drvTAPPoller(PPDMDRVINS pDrvIns)
378{
379 /* check how much the device/driver can receive now. */
380 PDRVTAP pData = PDMINS2DATA(pDrvIns, PDRVTAP);
381 STAM_PROFILE_ADV_START(&pData->StatReceive, a);
382
383 size_t cbMax = pData->pPort->pfnCanReceive(pData->pPort);
384 while (cbMax > 0)
385 {
386 /* check for data to read */
387 struct pollfd aFDs[1];
388 aFDs[0].fd = pData->FileDevice;
389 aFDs[0].events = POLLIN | POLLPRI;
390 aFDs[0].revents = 0;
391 if (poll(&aFDs[0], 1, 0) > 0)
392 {
393 if (aFDs[0].revents & (POLLIN | POLLPRI))
394 {
395 /* data waiting, read it. */
396 char achBuf[4096];
397 unsigned cbRead = 0;
398 int rc = RTFileRead(pData->FileDevice, achBuf, RT_MIN(sizeof(achBuf), cbMax), &cbRead);
399 if (VBOX_SUCCESS(rc))
400 {
401 STAM_COUNTER_INC(&pData->StatPktRecv);
402 STAM_COUNTER_ADD(&pData->StatPktRecvBytes, cbRead);
403
404 /* push it up to guy over us. */
405 Log2(("drvTAPPoller: cbRead=%#x\n"
406 "%.*Vhxd\n",
407 cbRead, cbRead, achBuf));
408 rc = pData->pPort->pfnReceive(pData->pPort, achBuf, cbRead);
409 AssertRC(rc);
410 }
411 else
412 AssertRC(rc);
413 if (VBOX_FAILURE(rc) || !cbRead)
414 break;
415 }
416 else
417 break;
418 }
419 else
420 break;
421
422 cbMax = pData->pPort->pfnCanReceive(pData->pPort);
423 }
424
425 STAM_PROFILE_ADV_STOP(&pData->StatReceive, a);
426}
427#endif
428
429
430/**
431 * Queries an interface to the driver.
432 *
433 * @returns Pointer to interface.
434 * @returns NULL if the interface was not supported by the driver.
435 * @param pInterface Pointer to this interface structure.
436 * @param enmInterface The requested interface identification.
437 * @thread Any thread.
438 */
439static DECLCALLBACK(void *) drvTAPQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
440{
441 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
442 PDRVTAP pData = PDMINS2DATA(pDrvIns, PDRVTAP);
443 switch (enmInterface)
444 {
445 case PDMINTERFACE_BASE:
446 return &pDrvIns->IBase;
447 case PDMINTERFACE_NETWORK_CONNECTOR:
448 return &pData->INetworkConnector;
449 default:
450 return NULL;
451 }
452}
453
454
455/**
456 * Destruct a driver instance.
457 *
458 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
459 * resources can be freed correctly.
460 *
461 * @param pDrvIns The driver instance data.
462 */
463static DECLCALLBACK(void) drvTAPDestruct(PPDMDRVINS pDrvIns)
464{
465 LogFlow(("drvTAPDestruct\n"));
466#ifdef ASYNC_NET
467 PDRVTAP pData = PDMINS2DATA(pDrvIns, PDRVTAP);
468
469 /*
470 * Terminate the Async I/O Thread.
471 */
472 ASMAtomicXchgSize(&pData->enmState, ASYNCSTATE_TERMINATE);
473 if (pData->Thread != NIL_RTTHREAD)
474 {
475 /* Ensure that it does not spin in the CanReceive loop */
476 if (ASMAtomicXchgU32(&pData->fOutOfSpace, false))
477 RTSemEventSignal(pData->EventOutOfSpace);
478
479 int rc = RTFileWrite(pData->PipeWrite, "", 1, NULL);
480 AssertRC(rc);
481 rc = RTThreadWait(pData->Thread, 5000, NULL);
482 AssertRC(rc);
483 pData->Thread = NIL_RTTHREAD;
484 }
485
486 /*
487 * Terminate the control pipe.
488 */
489 if (pData->PipeWrite != NIL_RTFILE)
490 {
491 int rc = RTFileClose(pData->PipeWrite);
492 AssertRC(rc);
493 pData->PipeWrite = NIL_RTFILE;
494 }
495 if (pData->PipeRead != NIL_RTFILE)
496 {
497 int rc = RTFileClose(pData->PipeRead);
498 AssertRC(rc);
499 pData->PipeRead = NIL_RTFILE;
500 }
501#endif
502}
503
504
505/**
506 * Construct a TAP network transport driver instance.
507 *
508 * @returns VBox status.
509 * @param pDrvIns The driver instance data.
510 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
511 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
512 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
513 * iInstance it's expected to be used a bit in this function.
514 */
515static DECLCALLBACK(int) drvTAPConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
516{
517 PDRVTAP pData = PDMINS2DATA(pDrvIns, PDRVTAP);
518
519 /*
520 * Init the static parts.
521 */
522 pData->pDrvIns = pDrvIns;
523 pData->FileDevice = NIL_RTFILE;
524#ifdef ASYNC_NET
525 pData->Thread = NIL_RTTHREAD;
526 pData->enmState = ASYNCSTATE_RUNNING;
527#endif
528 /* IBase */
529 pDrvIns->IBase.pfnQueryInterface = drvTAPQueryInterface;
530 /* INetwork */
531 pData->INetworkConnector.pfnSend = drvTAPSend;
532 pData->INetworkConnector.pfnSendEx = drvTAPSendEx;
533 pData->INetworkConnector.pfnSetPromiscuousMode = drvTAPSetPromiscuousMode;
534 pData->INetworkConnector.pfnNotifyLinkChanged = drvTAPNotifyLinkChanged;
535 pData->INetworkConnector.pfnNotifyCanReceive = drvTAPNotifyCanReceive;
536
537 /*
538 * Validate the config.
539 */
540 if (!CFGMR3AreValuesValid(pCfgHandle, "Device\0InitProg\0TermProg\0FileHandle\0"))
541 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES, "");
542
543 /*
544 * Check that no-one is attached to us.
545 */
546 int rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, NULL);
547 if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
548 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRVINS_NO_ATTACH,
549 N_("Configuration error: Cannot attach drivers to the TAP driver!"));
550
551 /*
552 * Query the network port interface.
553 */
554 pData->pPort = (PPDMINETWORKPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_NETWORK_PORT);
555 if (!pData->pPort)
556 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE,
557 N_("Configuration error: The above device/driver didn't export the network port interface!"));
558
559 /*
560 * Read the configuration.
561 */
562 int32_t iFile;
563 rc = CFGMR3QueryS32(pCfgHandle, "FileHandle", &iFile);
564 if (VBOX_FAILURE(rc))
565 return PDMDRV_SET_ERROR(pDrvIns, rc,
566 N_("Configuration error: Query for \"FileHandle\" 32-bit signed integer failed!"));
567 pData->FileDevice = (RTFILE)iFile;
568 if (!RTFileIsValid(pData->FileDevice))
569 return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_HANDLE, RT_SRC_POS,
570 N_("The TAP file handle %RTfile is not valid!"), pData->FileDevice);
571
572 /*
573 * Make sure the descriptor is non-blocking and valid.
574 *
575 * We should actually query if it's a TAP device, but I haven't
576 * found any way to do that.
577 */
578 if (fcntl(pData->FileDevice, F_SETFL, O_NONBLOCK) == -1)
579 return PDMDrvHlpVMSetError(pDrvIns, VERR_HOSTIF_IOCTL, RT_SRC_POS,
580 N_("Configuration error: Failed to configure /dev/net/tun. errno=%d"), errno);
581 /** @todo determine device name. This can be done by reading the link /proc/<pid>/fd/<fd> */
582 Log(("drvTAPContruct: %d (from fd)\n", pData->FileDevice));
583 rc = VINF_SUCCESS;
584
585#ifdef ASYNC_NET
586 /*
587 * Create the control pipe.
588 */
589 int fds[2];
590 if (pipe(&fds[0]) != 0) /** @todo RTPipeCreate() or something... */
591 {
592 int rc = RTErrConvertFromErrno(errno);
593 AssertRC(rc);
594 return rc;
595 }
596 pData->PipeRead = fds[0];
597 pData->PipeWrite = fds[1];
598
599 /*
600 * Create the async I/O thread.
601 */
602 rc = RTThreadCreate(&pData->Thread, drvTAPAsyncIoThread, pData, 128*_1K, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "TAP");
603 AssertRCReturn(rc, rc);
604#else
605 /*
606 * Register poller
607 */
608 rc = pDrvIns->pDrvHlp->pfnPDMPollerRegister(pDrvIns, drvTAPPoller);
609 AssertRCReturn(rc, rc);
610#endif
611
612#ifdef VBOX_WITH_STATISTICS
613 /*
614 * Statistics.
615 */
616 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatPktSent, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of sent packets.", "/Drivers/TAP%d/Packets/Sent", pDrvIns->iInstance);
617 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatPktSentBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of sent bytes.", "/Drivers/TAP%d/Bytes/Sent", pDrvIns->iInstance);
618 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatPktRecv, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of received packets.", "/Drivers/TAP%d/Packets/Received", pDrvIns->iInstance);
619 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatPktRecvBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of received bytes.", "/Drivers/TAP%d/Bytes/Received", pDrvIns->iInstance);
620 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet transmit runs.", "/Drivers/TAP%d/Transmit", pDrvIns->iInstance);
621 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet receive runs.", "/Drivers/TAP%d/Receive", pDrvIns->iInstance);
622# ifdef ASYNC_NET
623 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatRecvOverflows, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, "Profiling packet receive overflows.", "/Drivers/TAP%d/RecvOverflows", pDrvIns->iInstance);
624# endif
625#endif /* VBOX_WITH_STATISTICS */
626
627 return rc;
628}
629
630
631/**
632 * TAP network transport driver registration record.
633 */
634const PDMDRVREG g_DrvHostInterface =
635{
636 /* u32Version */
637 PDM_DRVREG_VERSION,
638 /* szDriverName */
639 "HostInterface",
640 /* pszDescription */
641 "TAP Network Transport Driver",
642 /* fFlags */
643 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
644 /* fClass. */
645 PDM_DRVREG_CLASS_NETWORK,
646 /* cMaxInstances */
647 ~0,
648 /* cbInstance */
649 sizeof(DRVTAP),
650 /* pfnConstruct */
651 drvTAPConstruct,
652 /* pfnDestruct */
653 drvTAPDestruct,
654 /* pfnIOCtl */
655 NULL,
656 /* pfnPowerOn */
657 NULL,
658 /* pfnReset */
659 NULL,
660 /* pfnSuspend */
661 NULL, /** @todo Do power on, suspend and resume handlers! */
662 /* pfnResume */
663 NULL,
664 /* pfnDetach */
665 NULL,
666 /* pfnPowerOff */
667 NULL
668};
Note: See TracBrowser for help on using the repository browser.

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