VirtualBox

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

Last change on this file since 4624 was 4372, checked in by vboxsync, 17 years ago

Finally corrected the RTFileRead, RTFileReadAt, RTFileWrite and RTFileWriteAt APIs to size_t. This was long overdue.

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