VirtualBox

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

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

solaris / beautify.

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