VirtualBox

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

Last change on this file since 1048 was 1005, checked in by vboxsync, 18 years ago

fixed log format specifier

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