VirtualBox

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

Last change on this file since 3953 was 3931, checked in by vboxsync, 17 years ago

an L4 hack

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