VirtualBox

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

Last change on this file since 4849 was 4641, checked in by vboxsync, 17 years ago

a review todo

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