VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DrvIntNet.cpp@ 1910

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

added verbose text for internal network

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.0 KB
Line 
1/** @file
2 *
3 * VBox network devices:
4 * Internal network transport driver
5 */
6
7/*
8 * Copyright (C) 2006 InnoTek Systemberatung GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
21 */
22
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#define LOG_GROUP LOG_GROUP_DRV_INTNET
28#include <VBox/pdm.h>
29#include <VBox/cfgm.h>
30#include <VBox/intnet.h>
31#include <VBox/vmm.h>
32#include <VBox/err.h>
33
34#include <VBox/log.h>
35#include <iprt/asm.h>
36#include <iprt/assert.h>
37#include <iprt/thread.h>
38#include <iprt/semaphore.h>
39#include <iprt/string.h>
40#include <iprt/time.h>
41
42#include "Builtins.h"
43
44
45/*******************************************************************************
46* Structures and Typedefs *
47*******************************************************************************/
48/**
49 * The state of the asynchronous thread.
50 */
51typedef enum ASYNCSTATE
52{
53 /** The thread is suspended. */
54 ASYNCSTATE_SUSPENDED = 1,
55 /** The thread is running. */
56 ASYNCSTATE_RUNNING,
57 /** The thread must (/has) terminate. */
58 ASYNCSTATE_TERMINATE,
59 /** The usual 32-bit type blowup. */
60 ASYNCSTATE_32BIT_HACK = 0x7fffffff
61} ASYNCSTATE;
62
63/**
64 * Block driver instance data.
65 */
66typedef struct DRVINTNET
67{
68 /** The network interface. */
69 PDMINETWORKCONNECTOR INetworkConnector;
70 /** The network interface. */
71 PPDMINETWORKPORT pPort;
72 /** Pointer to the driver instance. */
73 PPDMDRVINS pDrvIns;
74 /** Interface handle. */
75 INTNETIFHANDLE hIf;
76 /** Pointer to the communication buffer. */
77 PINTNETBUF pBuf;
78 /** The thread state. */
79 ASYNCSTATE volatile enmState;
80 /** Reader thread. */
81 RTTHREAD Thread;
82 /** Event semaphore the Thread waits on while the VM is suspended. */
83 RTSEMEVENT EventSuspended;
84 /** Indicates that we're in waiting for recieve space to become available. */
85 bool volatile fOutOfSpace;
86 /** Event semaphore the Thread sleeps on while polling for more
87 * buffer space to become available.
88 * @todo We really need the network device to signal this! */
89 RTSEMEVENT EventOutOfSpace;
90 /** Set if the link is down.
91 * When the link is down all incoming packets will be dropped. */
92 bool volatile fLinkDown;
93
94#ifdef VBOX_WITH_STATISTICS
95 /** Profiling packet transmit runs. */
96 STAMPROFILE StatTransmit;
97 /** Profiling packet receive runs. */
98 STAMPROFILEADV StatReceive;
99 /** Number of receive overflows. */
100 STAMPROFILE StatRecvOverflows;
101#endif /* VBOX_WITH_STATISTICS */
102
103#ifdef LOG_ENABLED
104 /** The nano ts of the last transfer. */
105 uint64_t u64LastTransferTS;
106 /** The nano ts of the last receive. */
107 uint64_t u64LastReceiveTS;
108#endif
109 /** The network name. */
110 char szNetwork[INTNET_MAX_NETWORK_NAME];
111} DRVINTNET, *PDRVINTNET;
112
113
114/** Converts a pointer to DRVINTNET::INetworkConnector to a PDRVINTNET. */
115#define PDMINETWORKCONNECTOR_2_DRVINTNET(pInterface) ( (PDRVINTNET)((uintptr_t)pInterface - RT_OFFSETOF(DRVINTNET, INetworkConnector)) )
116
117
118/**
119 * Send data to the network.
120 *
121 * @returns VBox status code.
122 * @param pInterface Pointer to the interface structure containing the called function pointer.
123 * @param pvBuf Data to send.
124 * @param cb Number of bytes to send.
125 * @thread EMT
126 */
127static DECLCALLBACK(int) drvIntNetSend(PPDMINETWORKCONNECTOR pInterface, const void *pvBuf, size_t cb)
128{
129 PDRVINTNET pThis = PDMINETWORKCONNECTOR_2_DRVINTNET(pInterface);
130 STAM_PROFILE_START(&pThis->StatTransmit, a);
131
132#ifdef LOG_ENABLED
133 uint64_t u64Now = RTTimeProgramNanoTS();
134 LogFlow(("drvIntNetSend: %-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
135 cb, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS));
136 pThis->u64LastTransferTS = u64Now;
137 Log2(("drvIntNetSend: pvBuf=%p cb=%#x\n"
138 "%.*Vhxd\n",
139 pvBuf, cb, cb, pvBuf));
140#endif
141
142 /** @todo copy to send buffer, this is not safe. */
143 INTNETIFSENDARGS SendArgs;
144 SendArgs.hIf = pThis->hIf;
145 SendArgs.pvFrame = pvBuf;
146 SendArgs.cbFrame = cb;
147 int rc = pThis->pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pThis->pDrvIns, VMMR0_DO_INTNET_IF_SEND, &SendArgs, sizeof(SendArgs));
148
149 STAM_PROFILE_STOP(&pThis->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) drvIntNetSetPromiscuousMode(PPDMINETWORKCONNECTOR pInterface, bool fPromiscuous)
166{
167 PDRVINTNET pThis = PDMINETWORKCONNECTOR_2_DRVINTNET(pInterface);
168 INTNETIFSETPROMISCUOUSMODEARGS SetArgs = {0};
169 SetArgs.hIf = pThis->hIf;
170 SetArgs.fPromiscuous = fPromiscuous;
171 int rc = pThis->pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pThis->pDrvIns, VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE, &SetArgs, sizeof(SetArgs));
172 LogFlow(("drvIntNetSetPromiscuousMode: fPromiscuous=%d\n", fPromiscuous));
173 AssertRC(rc);
174}
175
176
177/**
178 * Notification on link status changes.
179 *
180 * @param pInterface Pointer to the interface structure containing the called function pointer.
181 * @param enmLinkState The new link state.
182 * @thread EMT
183 */
184static DECLCALLBACK(void) drvIntNetNotifyLinkChanged(PPDMINETWORKCONNECTOR pInterface, PDMNETWORKLINKSTATE enmLinkState)
185{
186 PDRVINTNET pThis = PDMINETWORKCONNECTOR_2_DRVINTNET(pInterface);
187 bool fLinkDown;
188 switch (enmLinkState)
189 {
190 case PDMNETWORKLINKSTATE_DOWN:
191 case PDMNETWORKLINKSTATE_DOWN_RESUME:
192 fLinkDown = true;
193 break;
194 default:
195 AssertMsgFailed(("enmLinkState=%d\n", enmLinkState));
196 case PDMNETWORKLINKSTATE_UP:
197 fLinkDown = false;
198 break;
199 }
200 LogFlow(("drvIntNetNotifyLinkChanged: enmLinkState=%d %d->%d\n", enmLinkState, pThis->fLinkDown, fLinkDown));
201 ASMAtomicXchgSize(&pThis->fLinkDown, fLinkDown);
202}
203
204
205/**
206 * More receive buffer has become available.
207 *
208 * This is called when the NIC frees up receive buffers.
209 *
210 * @param pInterface Pointer to the interface structure containing the called function pointer.
211 * @remark This function isn't called by pcnet nor yet.
212 * @thread EMT
213 */
214static DECLCALLBACK(void) drvIntNetNotifyCanReceive(PPDMINETWORKCONNECTOR pInterface)
215{
216 PDRVINTNET pThis = PDMINETWORKCONNECTOR_2_DRVINTNET(pInterface);
217 if (pThis->fOutOfSpace)
218 {
219 LogFlow(("drvIntNetNotifyCanReceive: signaling\n"));
220 RTSemEventSignal(pThis->EventOutOfSpace);
221 }
222}
223
224
225/**
226 * Wait for space to become available up the driver/device chain.
227 *
228 * @returns VINF_SUCCESS if space is available.
229 * @returns VERR_STATE_CHANGED if the state changed.
230 * @returns VBox status code on other errors.
231 * @param pThis Pointer to the instance data.
232 * @param cbFrame The frame size.
233 */
234static int drvIntNetAsyncIoWaitForSpace(PDRVINTNET pThis, size_t cbFrame)
235{
236 LogFlow(("drvIntNetAsyncIoWaitForSpace: cbFrame=%zu\n", cbFrame));
237 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
238 STAM_PROFILE_START(&pData->StatRecvOverflows, b);
239
240 ASMAtomicXchgSize(&pThis->fOutOfSpace, true);
241 int rc;
242 unsigned cYields = 0;
243 for (;;)
244 {
245 /* yield/sleep */
246 if ( !RTThreadYield()
247 || ++cYields % 100 == 0)
248 {
249 /** @todo we need a callback from the device which can wake us up here. */
250 rc = RTSemEventWait(pThis->EventOutOfSpace, 1);
251 if ( VBOX_FAILURE(rc)
252 && rc != VERR_TIMEOUT)
253 break;
254 }
255 if (pThis->enmState != ASYNCSTATE_RUNNING)
256 {
257 rc = VERR_STATE_CHANGED;
258 break;
259 }
260
261 /* retry */
262 size_t cbMax = pThis->pPort->pfnCanReceive(pThis->pPort);
263 if (cbMax >= cbFrame)
264 {
265 rc = VINF_SUCCESS;
266 break;
267 }
268 }
269 ASMAtomicXchgSize(&pThis->fOutOfSpace, false);
270
271 STAM_PROFILE_STOP(&pThis->StatRecvOverflows, b);
272 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
273 LogFlow(("drvIntNetAsyncIoWaitForSpace: returns %Vrc\n", rc));
274 return rc;
275}
276
277
278/**
279 * Executes async I/O (RUNNING mode).
280 *
281 * @returns VERR_STATE_CHANGED if the state changed.
282 * @returns Appropriate VBox status code (error) on fatal error.
283 * @param pThis The driver instance data.
284 */
285static int drvIntNetAsyncIoRun(PDRVINTNET pThis)
286{
287 PPDMDRVINS pDrvIns = pThis->pDrvIns;
288 LogFlow(("drvIntNetAsyncIoRun: pThis=%p\n", pThis));
289
290 /*
291 * The running loop - processing received data and waiting for more to arrive.
292 */
293 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
294 PINTNETBUF pBuf = pThis->pBuf;
295 PINTNETRINGBUF pRingBuf = &pThis->pBuf->Recv;
296 for (;;)
297 {
298 /*
299 * Process the receive buffer.
300 */
301 while (INTNETRingGetReadable(pRingBuf) > 0)
302 {
303 /*
304 * Check the state and then inspect the packet.
305 */
306 if (pThis->enmState != ASYNCSTATE_RUNNING)
307 {
308 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
309 LogFlow(("drvIntNetAsyncIoRun: returns VERR_STATE_CHANGED (state changed - #0)\n"));
310 return VERR_STATE_CHANGED;
311 }
312
313 PINTNETHDR pHdr = (PINTNETHDR)((uintptr_t)pBuf + pRingBuf->offRead);
314 Log2(("pHdr=%p offRead=%#x: %.8Rhxs\n", pHdr, pRingBuf->offRead, pHdr));
315 if ( pHdr->u16Type == INTNETHDR_TYPE_FRAME
316 && !pThis->fLinkDown)
317 {
318 /*
319 * Check if there is room for the frame and pass it up.
320 */
321 size_t cbFrame = pHdr->cbFrame;
322 size_t cbMax = pThis->pPort->pfnCanReceive(pThis->pPort);
323 if (cbMax >= cbFrame)
324 {
325#ifdef LOG_ENABLED
326 uint64_t u64Now = RTTimeProgramNanoTS();
327 LogFlow(("drvIntNetAsyncIoRun: %-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
328 cbFrame, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS));
329 pThis->u64LastReceiveTS = u64Now;
330 Log2(("drvIntNetAsyncIoRun: cbFrame=%#x\n"
331 "%.*Vhxd\n",
332 cbFrame, cbFrame, INTNETHdrGetFramePtr(pHdr, pBuf)));
333#endif
334 int rc = pThis->pPort->pfnReceive(pThis->pPort, INTNETHdrGetFramePtr(pHdr, pBuf), cbFrame);
335 AssertRC(rc);
336
337 /* skip to the next frame. */
338 INTNETRingSkipFrame(pBuf, pRingBuf);
339 }
340 else
341 {
342 /*
343 * Wait for sufficient space to become available and then retry.
344 */
345 int rc = drvIntNetAsyncIoWaitForSpace(pThis, cbFrame);
346 if (VBOX_FAILURE(rc))
347 {
348 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
349 LogFlow(("drvIntNetAsyncIoRun: returns %Vrc (wait-for-space)\n", rc));
350 return rc;
351 }
352 }
353 }
354 else
355 {
356 /*
357 * Link down or unknown frame - skip to the next frame.
358 */
359 AssertMsg(pHdr->u16Type == INTNETHDR_TYPE_FRAME, ("Unknown frame type %RX16! offRead=%#x\n",
360 pHdr->u16Type, pRingBuf->offRead));
361 INTNETRingSkipFrame(pBuf, pRingBuf);
362 }
363 } /* while more received data */
364
365 /*
366 * Wait for data, checking the state before we block.
367 */
368 if (pThis->enmState != ASYNCSTATE_RUNNING)
369 {
370 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
371 LogFlow(("drvIntNetAsyncIoRun: returns VINF_SUCCESS (state changed - #1)\n"));
372 return VERR_STATE_CHANGED;
373 }
374 INTNETIFWAITARGS WaitArgs;
375 WaitArgs.hIf = pThis->hIf;
376 WaitArgs.cMillies = 30000; /* don't wait forever, timeout now and then. */
377 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
378 int rc = pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_WAIT, &WaitArgs, sizeof(WaitArgs));
379 if ( VBOX_FAILURE(rc)
380 && rc != VERR_TIMEOUT
381 && rc != VERR_INTERRUPTED)
382 {
383 LogFlow(("drvIntNetAsyncIoRun: returns %Vrc\n", rc));
384 return rc;
385 }
386 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
387 }
388}
389
390
391/**
392 * Asynchronous I/O thread for handling receive.
393 *
394 * @returns VINF_SUCCESS (ignored).
395 * @param ThreadSelf Thread handle.
396 * @param pvUser Pointer to a DRVINTNET structure.
397 */
398static DECLCALLBACK(int) drvIntNetAsyncIoThread(RTTHREAD ThreadSelf, void *pvUser)
399{
400 PDRVINTNET pThis = (PDRVINTNET)pvUser;
401 LogFlow(("drvIntNetAsyncIoThread: pThis=%p\n", pThis));
402 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
403
404 /*
405 * The main loop - acting on state.
406 */
407 for (;;)
408 {
409 ASYNCSTATE enmState = pThis->enmState;
410 switch (enmState)
411 {
412 case ASYNCSTATE_SUSPENDED:
413 {
414 int rc = RTSemEventWait(pThis->EventSuspended, 30000);
415 if ( VBOX_FAILURE(rc)
416 && rc != VERR_TIMEOUT)
417 {
418 LogFlow(("drvIntNetAsyncIoThread: returns %Vrc\n", rc));
419 return rc;
420 }
421 break;
422 }
423
424 case ASYNCSTATE_RUNNING:
425 {
426 int rc = drvIntNetAsyncIoRun(pThis);
427 if ( rc != VERR_STATE_CHANGED
428 && VBOX_FAILURE(rc))
429 {
430 LogFlow(("drvIntNetAsyncIoThread: returns %Vrc\n", rc));
431 return rc;
432 }
433 break;
434 }
435
436 default:
437 AssertMsgFailed(("Invalid state %d\n", enmState));
438 case ASYNCSTATE_TERMINATE:
439 LogFlow(("drvIntNetAsyncIoThread: returns VINF_SUCCESS\n"));
440 return VINF_SUCCESS;
441 }
442 }
443}
444
445
446/**
447 * Queries an interface to the driver.
448 *
449 * @returns Pointer to interface.
450 * @returns NULL if the interface was not supported by the driver.
451 * @param pInterface Pointer to this interface structure.
452 * @param enmInterface The requested interface identification.
453 * @thread Any thread.
454 */
455static DECLCALLBACK(void *) drvIntNetQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
456{
457 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
458 PDRVINTNET pThis = PDMINS2DATA(pDrvIns, PDRVINTNET);
459 switch (enmInterface)
460 {
461 case PDMINTERFACE_BASE:
462 return &pDrvIns->IBase;
463 case PDMINTERFACE_NETWORK_CONNECTOR:
464 return &pThis->INetworkConnector;
465 default:
466 return NULL;
467 }
468}
469
470
471/**
472 * Power Off notification.
473 *
474 * @param pDrvIns The driver instance.
475 */
476static DECLCALLBACK(void) drvIntNetPowerOff(PPDMDRVINS pDrvIns)
477{
478 LogFlow(("drvIntNetPowerOff\n"));
479 PDRVINTNET pThis = PDMINS2DATA(pDrvIns, PDRVINTNET);
480 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_SUSPENDED);
481}
482
483
484/**
485 * Resume notification.
486 *
487 * @param pDrvIns The driver instance.
488 */
489static DECLCALLBACK(void) drvIntNetResume(PPDMDRVINS pDrvIns)
490{
491 LogFlow(("drvIntNetPowerResume\n"));
492 PDRVINTNET pThis = PDMINS2DATA(pDrvIns, PDRVINTNET);
493 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
494 RTSemEventSignal(pThis->EventSuspended);
495}
496
497
498/**
499 * Suspend notification.
500 *
501 * @param pDrvIns The driver instance.
502 */
503static DECLCALLBACK(void) drvIntNetSuspend(PPDMDRVINS pDrvIns)
504{
505 LogFlow(("drvIntNetPowerSuspend\n"));
506 PDRVINTNET pThis = PDMINS2DATA(pDrvIns, PDRVINTNET);
507 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_SUSPENDED);
508}
509
510
511/**
512 * Power On notification.
513 *
514 * @param pDrvIns The driver instance.
515 */
516static DECLCALLBACK(void) drvIntNetPowerOn(PPDMDRVINS pDrvIns)
517{
518 LogFlow(("drvIntNetPowerOn\n"));
519 PDRVINTNET pThis = PDMINS2DATA(pDrvIns, PDRVINTNET);
520 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
521 RTSemEventSignal(pThis->EventSuspended);
522}
523
524
525/**
526 * Destruct a driver instance.
527 *
528 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
529 * resources can be freed correctly.
530 *
531 * @param pDrvIns The driver instance data.
532 */
533static DECLCALLBACK(void) drvIntNetDestruct(PPDMDRVINS pDrvIns)
534{
535 LogFlow(("drvIntNetDestruct\n"));
536 PDRVINTNET pThis = PDMINS2DATA(pDrvIns, PDRVINTNET);
537
538 /*
539 * Indicate to the thread that it's time to quit.
540 */
541 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_TERMINATE);
542 ASMAtomicXchgSize(&pThis->fLinkDown, true);
543 RTSEMEVENT EventOutOfSpace = pThis->EventOutOfSpace;
544 pThis->EventOutOfSpace = NIL_RTSEMEVENT;
545 RTSEMEVENT EventSuspended = pThis->EventSuspended;
546 pThis->EventSuspended = NIL_RTSEMEVENT;
547
548 /*
549 * Close the interface
550 */
551 if (pThis->hIf != INTNET_HANDLE_INVALID)
552 {
553 INTNETIFCLOSEARGS CloseArgs = {0};
554 CloseArgs.hIf = pThis->hIf;
555 pThis->hIf = INTNET_HANDLE_INVALID;
556 int rc = pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_CLOSE, &CloseArgs, sizeof(CloseArgs));
557 AssertRC(rc);
558 }
559
560 /*
561 * Wait for the thread to terminate.
562 */
563 if (pThis->Thread != NIL_RTTHREAD)
564 {
565 if (EventOutOfSpace != NIL_RTSEMEVENT)
566 RTSemEventSignal(EventOutOfSpace);
567 if (EventSuspended != NIL_RTSEMEVENT)
568 RTSemEventSignal(EventSuspended);
569 int rc = RTThreadWait(pThis->Thread, 5000, NULL);
570 AssertRC(rc);
571 pThis->Thread = NIL_RTTHREAD;
572 }
573
574 /*
575 * Destroy the semaphores.
576 */
577 if (EventOutOfSpace != NIL_RTSEMEVENT)
578 RTSemEventDestroy(EventOutOfSpace);
579 if (EventSuspended != NIL_RTSEMEVENT)
580 RTSemEventDestroy(EventSuspended);
581}
582
583
584/**
585 * Construct a TAP network transport driver instance.
586 *
587 * @returns VBox status.
588 * @param pDrvIns The driver instance data.
589 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
590 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
591 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
592 * iInstance it's expected to be used a bit in this function.
593 */
594static DECLCALLBACK(int) drvIntNetConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
595{
596 PDRVINTNET pThis = PDMINS2DATA(pDrvIns, PDRVINTNET);
597
598 /*
599 * Init the static parts.
600 */
601 pThis->pDrvIns = pDrvIns;
602 pThis->hIf = INTNET_HANDLE_INVALID;
603 pThis->Thread = NIL_RTTHREAD;
604 pThis->EventSuspended = NIL_RTSEMEVENT;
605 pThis->EventOutOfSpace = NIL_RTSEMEVENT;
606 pThis->enmState = ASYNCSTATE_SUSPENDED;
607 /* IBase */
608 pDrvIns->IBase.pfnQueryInterface = drvIntNetQueryInterface;
609 /* INetwork */
610 pThis->INetworkConnector.pfnSend = drvIntNetSend;
611 pThis->INetworkConnector.pfnSetPromiscuousMode = drvIntNetSetPromiscuousMode;
612 pThis->INetworkConnector.pfnNotifyLinkChanged = drvIntNetNotifyLinkChanged;
613 pThis->INetworkConnector.pfnNotifyCanReceive = drvIntNetNotifyCanReceive;
614
615 /*
616 * Validate the config.
617 */
618 if (!CFGMR3AreValuesValid(pCfgHandle, "Network\0ReceiveBufferSize\0SendBufferSize\0RestrictAccess\0"))
619 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
620
621 /*
622 * Check that no-one is attached to us.
623 */
624 int rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, NULL);
625 if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
626 {
627 AssertMsgFailed(("Configuration error: Cannot attach drivers to the TAP driver!\n"));
628 return VERR_PDM_DRVINS_NO_ATTACH;
629 }
630
631 /*
632 * Query the network port interface.
633 */
634 pThis->pPort = (PPDMINETWORKPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_NETWORK_PORT);
635 if (!pThis->pPort)
636 {
637 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network port interface!\n"));
638 return VERR_PDM_MISSING_INTERFACE_ABOVE;
639 }
640
641 /*
642 * Read the configuration.
643 */
644 INTNETOPENARGS OpenArgs;
645 memset(&OpenArgs, 0, sizeof(OpenArgs));
646 rc = CFGMR3QueryString(pCfgHandle, "Network", OpenArgs.szNetwork, sizeof(OpenArgs.szNetwork));
647 if (VBOX_FAILURE(rc))
648 return PDMDRV_SET_ERROR(pDrvIns, rc,
649 N_("Configuration error: Failed to get the \"Network\" value"));
650 strcpy(pThis->szNetwork, OpenArgs.szNetwork);
651
652 rc = CFGMR3QueryU32(pCfgHandle, "ReceiveBufferSize", &OpenArgs.cbRecv);
653 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
654 OpenArgs.cbRecv = _256K;
655 else if (VBOX_FAILURE(rc))
656 return PDMDRV_SET_ERROR(pDrvIns, rc,
657 N_("Configuration error: Failed to get the \"ReceiveBufferSize\" value"));
658
659 rc = CFGMR3QueryU32(pCfgHandle, "SendBufferSize", &OpenArgs.cbSend);
660 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
661 OpenArgs.cbSend = _4K;
662 else if (VBOX_FAILURE(rc))
663 return PDMDRV_SET_ERROR(pDrvIns, rc,
664 N_("Configuration error: Failed to get the \"SendBufferSize\" value"));
665
666 rc = CFGMR3QueryBool(pCfgHandle, "RestrictAccess", &OpenArgs.fRestrictAccess);
667 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
668 OpenArgs.fRestrictAccess = true;
669 else if (VBOX_FAILURE(rc))
670 return PDMDRV_SET_ERROR(pDrvIns, rc,
671 N_("Configuration error: Failed to get the \"RestrictAccess\" value"));
672
673 /*
674 * Create the event semaphores
675 */
676 rc = RTSemEventCreate(&pThis->EventSuspended);
677 if (VBOX_FAILURE(rc))
678 return rc;
679 rc = RTSemEventCreate(&pThis->EventOutOfSpace);
680 if (VBOX_FAILURE(rc))
681 return rc;
682
683 /*
684 * Create the interface.
685 */
686 OpenArgs.hIf = INTNET_HANDLE_INVALID;
687 rc = pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_OPEN, &OpenArgs, sizeof(OpenArgs));
688 if (VBOX_FAILURE(rc))
689 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
690 N_("Failed to open/create the internal network '%s'"), pThis->szNetwork);
691 AssertRelease(OpenArgs.hIf != INTNET_HANDLE_INVALID);
692 pThis->hIf = OpenArgs.hIf;
693 Log(("IntNet%d: hIf=%RX32 '%s'\n", pDrvIns->iInstance, pThis->hIf, pThis->szNetwork));
694
695 /*
696 * Get default buffer.
697 */
698 INTNETIFGETRING3BUFFERARGS GetRing3BufferArgs = {0};
699 GetRing3BufferArgs.hIf = pThis->hIf;
700 GetRing3BufferArgs.pRing3Buf = NULL;
701 rc = pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_GET_RING3_BUFFER, &GetRing3BufferArgs, sizeof(GetRing3BufferArgs));
702 if (VBOX_FAILURE(rc))
703 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
704 N_("Failed to get ring-3 buffer for the newly created interface to '%s'"), pThis->szNetwork);
705 AssertRelease(VALID_PTR(GetRing3BufferArgs.pRing3Buf));
706 pThis->pBuf = GetRing3BufferArgs.pRing3Buf;
707
708 /*
709 * Create the async I/O thread.
710 */
711 rc = RTThreadCreate(&pThis->Thread, drvIntNetAsyncIoThread, pThis, _128K, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "INTNET");
712 if (VBOX_FAILURE(rc))
713 {
714 AssertRC(rc);
715 return rc;
716 }
717
718 char szStatName[64];
719 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/Bytes/Received", pDrvIns->iInstance);
720 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->pBuf->cbStatRecv, STAMTYPE_COUNTER, szStatName, STAMUNIT_BYTES, "Number of received bytes.");
721 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/Bytes/Sent", pDrvIns->iInstance);
722 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->pBuf->cbStatSend, STAMTYPE_COUNTER, szStatName, STAMUNIT_BYTES, "Number of sent bytes.");
723 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/Packets/Received", pDrvIns->iInstance);
724 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->pBuf->cStatRecvs, STAMTYPE_COUNTER, szStatName, STAMUNIT_OCCURENCES, "Number of received packets.");
725 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/Packets/Sent", pDrvIns->iInstance);
726 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->pBuf->cStatSends, STAMTYPE_COUNTER, szStatName, STAMUNIT_OCCURENCES, "Number of sent packets.");
727 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/Packets/Lost", pDrvIns->iInstance);
728 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->pBuf->cStatLost, STAMTYPE_COUNTER, szStatName, STAMUNIT_OCCURENCES, "Number of lost packets.");
729 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/YieldOk", pDrvIns->iInstance);
730 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->pBuf->cStatYieldsOk, STAMTYPE_COUNTER, szStatName, STAMUNIT_OCCURENCES, "Number of times yielding fixed an overflow.");
731 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/YieldNok", pDrvIns->iInstance);
732 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->pBuf->cStatYieldsNok, STAMTYPE_COUNTER, szStatName, STAMUNIT_OCCURENCES, "Number of times yielding didn't help fix an overflow.");
733
734#ifdef VBOX_WITH_STATISTICS
735 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/Receive", pDrvIns->iInstance);
736 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->StatReceive, STAMTYPE_PROFILE, szStatName, STAMUNIT_TICKS_PER_CALL, "Profiling packet receive runs.");
737 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/RecvOverflows", pDrvIns->iInstance);
738 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->StatRecvOverflows, STAMTYPE_PROFILE, szStatName, STAMUNIT_TICKS_PER_OCCURENCE, "Profiling packet receive overflows.");
739 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/Transmit", pDrvIns->iInstance);
740 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->StatTransmit, STAMTYPE_PROFILE, szStatName, STAMUNIT_TICKS_PER_CALL, "Profiling packet transmit runs.");
741#endif
742
743 LogRel(("IntNet#%u: cbRecv=%u cbSend=%u fRestrictAccess=%d\n", pDrvIns->iInstance, OpenArgs.cbRecv, OpenArgs.cbSend, OpenArgs.fRestrictAccess));
744
745 return rc;
746}
747
748
749/**
750 * Internal networking transport driver registration record.
751 */
752const PDMDRVREG g_DrvIntNet =
753{
754 /* u32Version */
755 PDM_DRVREG_VERSION,
756 /* szDriverName */
757 "IntNet",
758 /* pszDescription */
759 "Internal Networking Transport Driver",
760 /* fFlags */
761 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
762 /* fClass. */
763 PDM_DRVREG_CLASS_NETWORK,
764 /* cMaxInstances */
765 ~0,
766 /* cbInstance */
767 sizeof(DRVINTNET),
768 /* pfnConstruct */
769 drvIntNetConstruct,
770 /* pfnDestruct */
771 drvIntNetDestruct,
772 /* pfnIOCtl */
773 NULL,
774 /* pfnPowerOn */
775 drvIntNetPowerOn,
776 /* pfnReset */
777 NULL,
778 /* pfnSuspend */
779 drvIntNetSuspend,
780 /* pfnResume */
781 drvIntNetResume,
782 /* pfnDetach */
783 NULL,
784 /* pfnPowerOff */
785 drvIntNetPowerOff
786};
787
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