VirtualBox

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

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

fixed internal networking after last network notification update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.8 KB
Line 
1/** @file
2 *
3 * VBox network devices:
4 * Internal network transport driver
5 */
6
7/*
8 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#define LOG_GROUP LOG_GROUP_DRV_INTNET
28#include <VBox/pdmdrv.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 /** Set if the link is down.
85 * When the link is down all incoming packets will be dropped. */
86 bool volatile fLinkDown;
87 /** Set if data transmission should start immediately. */
88 bool fActivateEarly;
89
90#ifdef VBOX_WITH_STATISTICS
91 /** Profiling packet transmit runs. */
92 STAMPROFILE StatTransmit;
93 /** Profiling packet receive runs. */
94 STAMPROFILEADV StatReceive;
95#endif /* VBOX_WITH_STATISTICS */
96
97#ifdef LOG_ENABLED
98 /** The nano ts of the last transfer. */
99 uint64_t u64LastTransferTS;
100 /** The nano ts of the last receive. */
101 uint64_t u64LastReceiveTS;
102#endif
103 /** The network name. */
104 char szNetwork[INTNET_MAX_NETWORK_NAME];
105} DRVINTNET, *PDRVINTNET;
106
107
108/** Converts a pointer to DRVINTNET::INetworkConnector to a PDRVINTNET. */
109#define PDMINETWORKCONNECTOR_2_DRVINTNET(pInterface) ( (PDRVINTNET)((uintptr_t)pInterface - RT_OFFSETOF(DRVINTNET, INetworkConnector)) )
110
111
112/**
113 * Writes a frame packet to the buffer.
114 *
115 * @returns VBox status code.
116 * @param pBuf The buffer.
117 * @param pRingBuf The ring buffer to read from.
118 * @param pvFrame The frame to write.
119 * @param cbFrame The size of the frame.
120 * @remark This is the same as INTNETRingWriteFrame
121 */
122static int drvIntNetRingWriteFrame(PINTNETBUF pBuf, PINTNETRINGBUF pRingBuf, const void *pvFrame, uint32_t cbFrame)
123{
124 /*
125 * Validate input.
126 */
127 Assert(pBuf);
128 Assert(pRingBuf);
129 Assert(pvFrame);
130 Assert(cbFrame >= sizeof(PDMMAC) * 2);
131 uint32_t offWrite = pRingBuf->offWrite;
132 Assert(offWrite == RT_ALIGN_32(offWrite, sizeof(INTNETHDR)));
133 uint32_t offRead = pRingBuf->offRead;
134 Assert(offRead == RT_ALIGN_32(offRead, sizeof(INTNETHDR)));
135
136 const uint32_t cb = RT_ALIGN_32(cbFrame, sizeof(INTNETHDR));
137 if (offRead <= offWrite)
138 {
139 /*
140 * Try fit it all before the end of the buffer.
141 */
142 if (pRingBuf->offEnd - offWrite >= cb + sizeof(INTNETHDR))
143 {
144 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
145 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
146 pHdr->cbFrame = cbFrame;
147 pHdr->offFrame = sizeof(INTNETHDR);
148
149 memcpy(pHdr + 1, pvFrame, cbFrame);
150
151 offWrite += cb + sizeof(INTNETHDR);
152 Assert(offWrite <= pRingBuf->offEnd && offWrite >= pRingBuf->offStart);
153 if (offWrite >= pRingBuf->offEnd)
154 offWrite = pRingBuf->offStart;
155 Log2(("WriteFrame: offWrite: %#x -> %#x (1)\n", pRingBuf->offWrite, offWrite));
156 ASMAtomicXchgU32(&pRingBuf->offWrite, offWrite);
157 return VINF_SUCCESS;
158 }
159
160 /*
161 * Try fit the frame at the start of the buffer.
162 * (The header fits before the end of the buffer because of alignment.)
163 */
164 AssertMsg(pRingBuf->offEnd - offWrite >= sizeof(INTNETHDR), ("offEnd=%x offWrite=%x\n", pRingBuf->offEnd, offWrite));
165 if (offRead - pRingBuf->offStart > cb) /* not >= ! */
166 {
167 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
168 void *pvFrameOut = (PINTNETHDR)((uint8_t *)pBuf + pRingBuf->offStart);
169 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
170 pHdr->cbFrame = cbFrame;
171 pHdr->offFrame = (intptr_t)pvFrameOut - (intptr_t)pHdr;
172
173 memcpy(pvFrameOut, pvFrame, cbFrame);
174
175 offWrite = pRingBuf->offStart + cb;
176 ASMAtomicXchgU32(&pRingBuf->offWrite, offWrite);
177 Log2(("WriteFrame: offWrite: %#x -> %#x (2)\n", pRingBuf->offWrite, offWrite));
178 return VINF_SUCCESS;
179 }
180 }
181 /*
182 * The reader is ahead of the writer, try fit it into that space.
183 */
184 else if (offRead - offWrite > cb + sizeof(INTNETHDR)) /* not >= ! */
185 {
186 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
187 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
188 pHdr->cbFrame = cbFrame;
189 pHdr->offFrame = sizeof(INTNETHDR);
190
191 memcpy(pHdr + 1, pvFrame, cbFrame);
192
193 offWrite += cb + sizeof(INTNETHDR);
194 ASMAtomicXchgU32(&pRingBuf->offWrite, offWrite);
195 Log2(("WriteFrame: offWrite: %#x -> %#x (3)\n", pRingBuf->offWrite, offWrite));
196 return VINF_SUCCESS;
197 }
198
199 /* (it didn't fit) */
200 /** @todo stats */
201 return VERR_BUFFER_OVERFLOW;
202}
203
204
205/**
206 * Send data to the network.
207 *
208 * @returns VBox status code.
209 * @param pInterface Pointer to the interface structure containing the called function pointer.
210 * @param pvBuf Data to send.
211 * @param cb Number of bytes to send.
212 * @thread EMT
213 */
214static DECLCALLBACK(int) drvIntNetSend(PPDMINETWORKCONNECTOR pInterface, const void *pvBuf, size_t cb)
215{
216 PDRVINTNET pThis = PDMINETWORKCONNECTOR_2_DRVINTNET(pInterface);
217 STAM_PROFILE_START(&pThis->StatTransmit, a);
218
219#ifdef LOG_ENABLED
220 uint64_t u64Now = RTTimeProgramNanoTS();
221 LogFlow(("drvIntNetSend: %-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
222 cb, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS));
223 pThis->u64LastTransferTS = u64Now;
224 Log2(("drvIntNetSend: pvBuf=%p cb=%#x\n"
225 "%.*Vhxd\n",
226 pvBuf, cb, cb, pvBuf));
227#endif
228
229 /*
230 * Add the frame to the send buffer and push it onto the network.
231 */
232 int rc = drvIntNetRingWriteFrame(pThis->pBuf, &pThis->pBuf->Send, pvBuf, cb);
233 if ( rc == VERR_BUFFER_OVERFLOW
234 && pThis->pBuf->cbSend < cb)
235 {
236 INTNETIFSENDREQ SendReq;
237 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
238 SendReq.Hdr.cbReq = sizeof(SendReq);
239 SendReq.hIf = pThis->hIf;
240 pThis->pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pThis->pDrvIns, VMMR0_DO_INTNET_IF_SEND, &SendReq, sizeof(SendReq));
241
242 rc = drvIntNetRingWriteFrame(pThis->pBuf, &pThis->pBuf->Send, pvBuf, cb);
243 }
244
245 if (RT_SUCCESS(rc))
246 {
247 INTNETIFSENDREQ SendReq;
248 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
249 SendReq.Hdr.cbReq = sizeof(SendReq);
250 SendReq.hIf = pThis->hIf;
251 rc = pThis->pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pThis->pDrvIns, VMMR0_DO_INTNET_IF_SEND, &SendReq, sizeof(SendReq));
252 }
253
254 STAM_PROFILE_STOP(&pThis->StatTransmit, a);
255 AssertRC(rc);
256 return rc;
257}
258
259
260/**
261 * Set promiscuous mode.
262 *
263 * This is called when the promiscuous mode is set. This means that there doesn't have
264 * to be a mode change when it's called.
265 *
266 * @param pInterface Pointer to the interface structure containing the called function pointer.
267 * @param fPromiscuous Set if the adaptor is now in promiscuous mode. Clear if it is not.
268 * @thread EMT
269 */
270static DECLCALLBACK(void) drvIntNetSetPromiscuousMode(PPDMINETWORKCONNECTOR pInterface, bool fPromiscuous)
271{
272 PDRVINTNET pThis = PDMINETWORKCONNECTOR_2_DRVINTNET(pInterface);
273 INTNETIFSETPROMISCUOUSMODEREQ Req;
274 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
275 Req.Hdr.cbReq = sizeof(Req);
276 Req.hIf = pThis->hIf;
277 Req.fPromiscuous = fPromiscuous;
278 int rc = pThis->pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pThis->pDrvIns, VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE, &Req, sizeof(Req));
279 LogFlow(("drvIntNetSetPromiscuousMode: fPromiscuous=%RTbool\n", fPromiscuous));
280 AssertRC(rc);
281}
282
283
284/**
285 * Notification on link status changes.
286 *
287 * @param pInterface Pointer to the interface structure containing the called function pointer.
288 * @param enmLinkState The new link state.
289 * @thread EMT
290 */
291static DECLCALLBACK(void) drvIntNetNotifyLinkChanged(PPDMINETWORKCONNECTOR pInterface, PDMNETWORKLINKSTATE enmLinkState)
292{
293 PDRVINTNET pThis = PDMINETWORKCONNECTOR_2_DRVINTNET(pInterface);
294 bool fLinkDown;
295 switch (enmLinkState)
296 {
297 case PDMNETWORKLINKSTATE_DOWN:
298 case PDMNETWORKLINKSTATE_DOWN_RESUME:
299 fLinkDown = true;
300 break;
301 default:
302 AssertMsgFailed(("enmLinkState=%d\n", enmLinkState));
303 case PDMNETWORKLINKSTATE_UP:
304 fLinkDown = false;
305 break;
306 }
307 LogFlow(("drvIntNetNotifyLinkChanged: enmLinkState=%d %d->%d\n", enmLinkState, pThis->fLinkDown, fLinkDown));
308 ASMAtomicXchgSize(&pThis->fLinkDown, fLinkDown);
309}
310
311
312/**
313 * Wait for space to become available up the driver/device chain.
314 *
315 * @returns VINF_SUCCESS if space is available.
316 * @returns VERR_STATE_CHANGED if the state changed.
317 * @returns VBox status code on other errors.
318 * @param pThis Pointer to the instance data.
319 */
320static int drvIntNetAsyncIoWaitForSpace(PDRVINTNET pThis)
321{
322 LogFlow(("drvIntNetAsyncIoWaitForSpace:\n"));
323 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
324 int rc = pThis->pPort->pfnWaitReceiveAvail(pThis->pPort, RT_INDEFINITE_WAIT);
325 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
326 LogFlow(("drvIntNetAsyncIoWaitForSpace: returns %Vrc\n", rc));
327 return rc;
328}
329
330
331/**
332 * Executes async I/O (RUNNING mode).
333 *
334 * @returns VERR_STATE_CHANGED if the state changed.
335 * @returns Appropriate VBox status code (error) on fatal error.
336 * @param pThis The driver instance data.
337 */
338static int drvIntNetAsyncIoRun(PDRVINTNET pThis)
339{
340 PPDMDRVINS pDrvIns = pThis->pDrvIns;
341 LogFlow(("drvIntNetAsyncIoRun: pThis=%p\n", pThis));
342
343 /*
344 * The running loop - processing received data and waiting for more to arrive.
345 */
346 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
347 PINTNETBUF pBuf = pThis->pBuf;
348 PINTNETRINGBUF pRingBuf = &pThis->pBuf->Recv;
349 for (;;)
350 {
351 /*
352 * Process the receive buffer.
353 */
354 while (INTNETRingGetReadable(pRingBuf) > 0)
355 {
356 /*
357 * Check the state and then inspect the packet.
358 */
359 if (pThis->enmState != ASYNCSTATE_RUNNING)
360 {
361 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
362 LogFlow(("drvIntNetAsyncIoRun: returns VERR_STATE_CHANGED (state changed - #0)\n"));
363 return VERR_STATE_CHANGED;
364 }
365
366 PINTNETHDR pHdr = (PINTNETHDR)((uintptr_t)pBuf + pRingBuf->offRead);
367 Log2(("pHdr=%p offRead=%#x: %.8Rhxs\n", pHdr, pRingBuf->offRead, pHdr));
368 if ( pHdr->u16Type == INTNETHDR_TYPE_FRAME
369 && !pThis->fLinkDown)
370 {
371 /*
372 * Check if there is room for the frame and pass it up.
373 */
374 size_t cbFrame = pHdr->cbFrame;
375 int rc = pThis->pPort->pfnWaitReceiveAvail(pThis->pPort, 0);
376 if (rc == VINF_SUCCESS)
377 {
378#ifdef LOG_ENABLED
379 uint64_t u64Now = RTTimeProgramNanoTS();
380 LogFlow(("drvIntNetAsyncIoRun: %-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
381 cbFrame, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS));
382 pThis->u64LastReceiveTS = u64Now;
383 Log2(("drvIntNetAsyncIoRun: cbFrame=%#x\n"
384 "%.*Vhxd\n",
385 cbFrame, cbFrame, INTNETHdrGetFramePtr(pHdr, pBuf)));
386#endif
387 int rc = pThis->pPort->pfnReceive(pThis->pPort, INTNETHdrGetFramePtr(pHdr, pBuf), cbFrame);
388 AssertRC(rc);
389
390 /* skip to the next frame. */
391 INTNETRingSkipFrame(pBuf, pRingBuf);
392 }
393 else
394 {
395 /*
396 * Wait for sufficient space to become available and then retry.
397 */
398 rc = drvIntNetAsyncIoWaitForSpace(pThis);
399 if (VBOX_FAILURE(rc))
400 {
401 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
402 LogFlow(("drvIntNetAsyncIoRun: returns %Vrc (wait-for-space)\n", rc));
403 return rc;
404 }
405 }
406 }
407 else
408 {
409 /*
410 * Link down or unknown frame - skip to the next frame.
411 */
412 AssertMsg(pHdr->u16Type == INTNETHDR_TYPE_FRAME, ("Unknown frame type %RX16! offRead=%#x\n",
413 pHdr->u16Type, pRingBuf->offRead));
414 INTNETRingSkipFrame(pBuf, pRingBuf);
415 }
416 } /* while more received data */
417
418 /*
419 * Wait for data, checking the state before we block.
420 */
421 if (pThis->enmState != ASYNCSTATE_RUNNING)
422 {
423 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
424 LogFlow(("drvIntNetAsyncIoRun: returns VINF_SUCCESS (state changed - #1)\n"));
425 return VERR_STATE_CHANGED;
426 }
427 INTNETIFWAITREQ WaitReq;
428 WaitReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
429 WaitReq.Hdr.cbReq = sizeof(WaitReq);
430 WaitReq.hIf = pThis->hIf;
431 WaitReq.cMillies = 30000; /* 30s - don't wait forever, timeout now and then. */
432 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
433 int rc = pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_WAIT, &WaitReq, sizeof(WaitReq));
434 if ( VBOX_FAILURE(rc)
435 && rc != VERR_TIMEOUT
436 && rc != VERR_INTERRUPTED)
437 {
438 LogFlow(("drvIntNetAsyncIoRun: returns %Vrc\n", rc));
439 return rc;
440 }
441 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
442 }
443}
444
445
446/**
447 * Asynchronous I/O thread for handling receive.
448 *
449 * @returns VINF_SUCCESS (ignored).
450 * @param ThreadSelf Thread handle.
451 * @param pvUser Pointer to a DRVINTNET structure.
452 */
453static DECLCALLBACK(int) drvIntNetAsyncIoThread(RTTHREAD ThreadSelf, void *pvUser)
454{
455 PDRVINTNET pThis = (PDRVINTNET)pvUser;
456 LogFlow(("drvIntNetAsyncIoThread: pThis=%p\n", pThis));
457 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
458
459 /*
460 * The main loop - acting on state.
461 */
462 for (;;)
463 {
464 ASYNCSTATE enmState = pThis->enmState;
465 switch (enmState)
466 {
467 case ASYNCSTATE_SUSPENDED:
468 {
469 int rc = RTSemEventWait(pThis->EventSuspended, 30000);
470 if ( VBOX_FAILURE(rc)
471 && rc != VERR_TIMEOUT)
472 {
473 LogFlow(("drvIntNetAsyncIoThread: returns %Vrc\n", rc));
474 return rc;
475 }
476 break;
477 }
478
479 case ASYNCSTATE_RUNNING:
480 {
481 int rc = drvIntNetAsyncIoRun(pThis);
482 if ( rc != VERR_STATE_CHANGED
483 && VBOX_FAILURE(rc))
484 {
485 LogFlow(("drvIntNetAsyncIoThread: returns %Vrc\n", rc));
486 return rc;
487 }
488 break;
489 }
490
491 default:
492 AssertMsgFailed(("Invalid state %d\n", enmState));
493 case ASYNCSTATE_TERMINATE:
494 LogFlow(("drvIntNetAsyncIoThread: returns VINF_SUCCESS\n"));
495 return VINF_SUCCESS;
496 }
497 }
498}
499
500
501/**
502 * Queries an interface to the driver.
503 *
504 * @returns Pointer to interface.
505 * @returns NULL if the interface was not supported by the driver.
506 * @param pInterface Pointer to this interface structure.
507 * @param enmInterface The requested interface identification.
508 * @thread Any thread.
509 */
510static DECLCALLBACK(void *) drvIntNetQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
511{
512 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
513 PDRVINTNET pThis = PDMINS2DATA(pDrvIns, PDRVINTNET);
514 switch (enmInterface)
515 {
516 case PDMINTERFACE_BASE:
517 return &pDrvIns->IBase;
518 case PDMINTERFACE_NETWORK_CONNECTOR:
519 return &pThis->INetworkConnector;
520 default:
521 return NULL;
522 }
523}
524
525
526/**
527 * Power Off notification.
528 *
529 * @param pDrvIns The driver instance.
530 */
531static DECLCALLBACK(void) drvIntNetPowerOff(PPDMDRVINS pDrvIns)
532{
533 LogFlow(("drvIntNetPowerOff\n"));
534 PDRVINTNET pThis = PDMINS2DATA(pDrvIns, PDRVINTNET);
535 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_SUSPENDED);
536}
537
538
539/**
540 * Resume notification.
541 *
542 * @param pDrvIns The driver instance.
543 */
544static DECLCALLBACK(void) drvIntNetResume(PPDMDRVINS pDrvIns)
545{
546 LogFlow(("drvIntNetPowerResume\n"));
547 PDRVINTNET pThis = PDMINS2DATA(pDrvIns, PDRVINTNET);
548 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
549 RTSemEventSignal(pThis->EventSuspended);
550}
551
552
553/**
554 * Suspend notification.
555 *
556 * @param pDrvIns The driver instance.
557 */
558static DECLCALLBACK(void) drvIntNetSuspend(PPDMDRVINS pDrvIns)
559{
560 LogFlow(("drvIntNetPowerSuspend\n"));
561 PDRVINTNET pThis = PDMINS2DATA(pDrvIns, PDRVINTNET);
562 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_SUSPENDED);
563}
564
565
566/**
567 * Power On notification.
568 *
569 * @param pDrvIns The driver instance.
570 */
571static DECLCALLBACK(void) drvIntNetPowerOn(PPDMDRVINS pDrvIns)
572{
573 LogFlow(("drvIntNetPowerOn\n"));
574 PDRVINTNET pThis = PDMINS2DATA(pDrvIns, PDRVINTNET);
575 if (!pThis->fActivateEarly)
576 {
577 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
578 RTSemEventSignal(pThis->EventSuspended);
579 }
580}
581
582
583/**
584 * Destruct a driver instance.
585 *
586 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
587 * resources can be freed correctly.
588 *
589 * @param pDrvIns The driver instance data.
590 */
591static DECLCALLBACK(void) drvIntNetDestruct(PPDMDRVINS pDrvIns)
592{
593 LogFlow(("drvIntNetDestruct\n"));
594 PDRVINTNET pThis = PDMINS2DATA(pDrvIns, PDRVINTNET);
595
596 /*
597 * Indicate to the thread that it's time to quit.
598 */
599 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_TERMINATE);
600 ASMAtomicXchgSize(&pThis->fLinkDown, true);
601 RTSEMEVENT EventSuspended = pThis->EventSuspended;
602 pThis->EventSuspended = NIL_RTSEMEVENT;
603
604 /*
605 * Close the interface
606 */
607 if (pThis->hIf != INTNET_HANDLE_INVALID)
608 {
609 INTNETIFCLOSEREQ CloseReq;
610 CloseReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
611 CloseReq.Hdr.cbReq = sizeof(CloseReq);
612 CloseReq.hIf = pThis->hIf;
613 pThis->hIf = INTNET_HANDLE_INVALID;
614 int rc = pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_CLOSE, &CloseReq, sizeof(CloseReq));
615 AssertRC(rc);
616 }
617
618 /*
619 * Wait for the thread to terminate.
620 */
621 if (pThis->Thread != NIL_RTTHREAD)
622 {
623 if (EventSuspended != NIL_RTSEMEVENT)
624 RTSemEventSignal(EventSuspended);
625 int rc = RTThreadWait(pThis->Thread, 5000, NULL);
626 AssertRC(rc);
627 pThis->Thread = NIL_RTTHREAD;
628 }
629
630 /*
631 * Destroy the semaphores.
632 */
633 if (EventSuspended != NIL_RTSEMEVENT)
634 RTSemEventDestroy(EventSuspended);
635}
636
637
638/**
639 * Construct a TAP network transport driver instance.
640 *
641 * @returns VBox status.
642 * @param pDrvIns The driver instance data.
643 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
644 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
645 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
646 * iInstance it's expected to be used a bit in this function.
647 */
648static DECLCALLBACK(int) drvIntNetConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
649{
650 PDRVINTNET pThis = PDMINS2DATA(pDrvIns, PDRVINTNET);
651
652 /*
653 * Init the static parts.
654 */
655 pThis->pDrvIns = pDrvIns;
656 pThis->hIf = INTNET_HANDLE_INVALID;
657 pThis->Thread = NIL_RTTHREAD;
658 pThis->EventSuspended = NIL_RTSEMEVENT;
659 pThis->enmState = ASYNCSTATE_SUSPENDED;
660 pThis->fActivateEarly = false;
661 /* IBase */
662 pDrvIns->IBase.pfnQueryInterface = drvIntNetQueryInterface;
663 /* INetwork */
664 pThis->INetworkConnector.pfnSend = drvIntNetSend;
665 pThis->INetworkConnector.pfnSetPromiscuousMode = drvIntNetSetPromiscuousMode;
666 pThis->INetworkConnector.pfnNotifyLinkChanged = drvIntNetNotifyLinkChanged;
667
668 /*
669 * Validate the config.
670 */
671 if (!CFGMR3AreValuesValid(pCfgHandle, "Network\0ReceiveBufferSize\0SendBufferSize\0RestrictAccess\0IsService\0"))
672 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
673
674 /*
675 * Check that no-one is attached to us.
676 */
677 int rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, NULL);
678 if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
679 {
680 AssertMsgFailed(("Configuration error: Cannot attach drivers to the TAP driver!\n"));
681 return VERR_PDM_DRVINS_NO_ATTACH;
682 }
683
684 /*
685 * Query the network port interface.
686 */
687 pThis->pPort = (PPDMINETWORKPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_NETWORK_PORT);
688 if (!pThis->pPort)
689 {
690 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network port interface!\n"));
691 return VERR_PDM_MISSING_INTERFACE_ABOVE;
692 }
693
694 /*
695 * Read the configuration.
696 */
697 INTNETOPENREQ OpenReq;
698 memset(&OpenReq, 0, sizeof(OpenReq));
699 OpenReq.Hdr.cbReq = sizeof(OpenReq);
700 OpenReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
701
702 rc = CFGMR3QueryString(pCfgHandle, "Network", OpenReq.szNetwork, sizeof(OpenReq.szNetwork));
703 if (VBOX_FAILURE(rc))
704 return PDMDRV_SET_ERROR(pDrvIns, rc,
705 N_("Configuration error: Failed to get the \"Network\" value"));
706 strcpy(pThis->szNetwork, OpenReq.szNetwork);
707
708 rc = CFGMR3QueryU32(pCfgHandle, "ReceiveBufferSize", &OpenReq.cbRecv);
709 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
710 OpenReq.cbRecv = _256K;
711 else if (VBOX_FAILURE(rc))
712 return PDMDRV_SET_ERROR(pDrvIns, rc,
713 N_("Configuration error: Failed to get the \"ReceiveBufferSize\" value"));
714
715 rc = CFGMR3QueryU32(pCfgHandle, "SendBufferSize", &OpenReq.cbSend);
716 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
717 OpenReq.cbSend = _4K;
718 else if (VBOX_FAILURE(rc))
719 return PDMDRV_SET_ERROR(pDrvIns, rc,
720 N_("Configuration error: Failed to get the \"SendBufferSize\" value"));
721 if (OpenReq.cbSend < 16)
722 return PDMDRV_SET_ERROR(pDrvIns, rc,
723 N_("Configuration error: The \"SendBufferSize\" value is too small"));
724 if (OpenReq.cbSend < 1536*2 + 4)
725 LogRel(("DrvIntNet: Warning! SendBufferSize=%u, Recommended minimum size %u butes.\n", OpenReq.cbSend, 1536*2 + 4));
726
727 rc = CFGMR3QueryBool(pCfgHandle, "RestrictAccess", &OpenReq.fRestrictAccess);
728 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
729 OpenReq.fRestrictAccess = true;
730 else if (VBOX_FAILURE(rc))
731 return PDMDRV_SET_ERROR(pDrvIns, rc,
732 N_("Configuration error: Failed to get the \"RestrictAccess\" value"));
733
734 rc = CFGMR3QueryBool(pCfgHandle, "IsService", &pThis->fActivateEarly);
735 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
736 pThis->fActivateEarly = false;
737 else if (VBOX_FAILURE(rc))
738 return PDMDRV_SET_ERROR(pDrvIns, rc,
739 N_("Configuration error: Failed to get the \"IsService\" value"));
740
741 /*
742 * Create the event semaphores
743 */
744 rc = RTSemEventCreate(&pThis->EventSuspended);
745 if (VBOX_FAILURE(rc))
746 return rc;
747
748 /*
749 * Create the interface.
750 */
751 OpenReq.hIf = INTNET_HANDLE_INVALID;
752 rc = pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_OPEN, &OpenReq, sizeof(OpenReq));
753 if (VBOX_FAILURE(rc))
754 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
755 N_("Failed to open/create the internal network '%s'"), pThis->szNetwork);
756 AssertRelease(OpenReq.hIf != INTNET_HANDLE_INVALID);
757 pThis->hIf = OpenReq.hIf;
758 Log(("IntNet%d: hIf=%RX32 '%s'\n", pDrvIns->iInstance, pThis->hIf, pThis->szNetwork));
759
760 /*
761 * Get default buffer.
762 */
763 INTNETIFGETRING3BUFFERREQ GetRing3BufferReq;
764 GetRing3BufferReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
765 GetRing3BufferReq.Hdr.cbReq = sizeof(GetRing3BufferReq);
766 GetRing3BufferReq.hIf = pThis->hIf;
767 GetRing3BufferReq.pRing3Buf = NULL;
768 rc = pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_GET_RING3_BUFFER, &GetRing3BufferReq, sizeof(GetRing3BufferReq));
769 if (VBOX_FAILURE(rc))
770 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
771 N_("Failed to get ring-3 buffer for the newly created interface to '%s'"), pThis->szNetwork);
772 AssertRelease(VALID_PTR(GetRing3BufferReq.pRing3Buf));
773 pThis->pBuf = GetRing3BufferReq.pRing3Buf;
774
775 /*
776 * Create the async I/O thread.
777 */
778 rc = RTThreadCreate(&pThis->Thread, drvIntNetAsyncIoThread, pThis, _128K, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "INTNET");
779 if (VBOX_FAILURE(rc))
780 {
781 AssertRC(rc);
782 return rc;
783 }
784
785 char szStatName[64];
786 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/Bytes/Received", pDrvIns->iInstance);
787 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->pBuf->cbStatRecv, STAMTYPE_COUNTER, szStatName, STAMUNIT_BYTES, "Number of received bytes.");
788 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/Bytes/Sent", pDrvIns->iInstance);
789 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->pBuf->cbStatSend, STAMTYPE_COUNTER, szStatName, STAMUNIT_BYTES, "Number of sent bytes.");
790 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/Packets/Received", pDrvIns->iInstance);
791 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->pBuf->cStatRecvs, STAMTYPE_COUNTER, szStatName, STAMUNIT_OCCURENCES, "Number of received packets.");
792 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/Packets/Sent", pDrvIns->iInstance);
793 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->pBuf->cStatSends, STAMTYPE_COUNTER, szStatName, STAMUNIT_OCCURENCES, "Number of sent packets.");
794 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/Packets/Lost", pDrvIns->iInstance);
795 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->pBuf->cStatLost, STAMTYPE_COUNTER, szStatName, STAMUNIT_OCCURENCES, "Number of lost packets.");
796 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/YieldOk", pDrvIns->iInstance);
797 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->pBuf->cStatYieldsOk, STAMTYPE_COUNTER, szStatName, STAMUNIT_OCCURENCES, "Number of times yielding fixed an overflow.");
798 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/YieldNok", pDrvIns->iInstance);
799 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->pBuf->cStatYieldsNok, STAMTYPE_COUNTER, szStatName, STAMUNIT_OCCURENCES, "Number of times yielding didn't help fix an overflow.");
800
801#ifdef VBOX_WITH_STATISTICS
802 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/Receive", pDrvIns->iInstance);
803 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->StatReceive, STAMTYPE_PROFILE, szStatName, STAMUNIT_TICKS_PER_CALL, "Profiling packet receive runs.");
804 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/Transmit", pDrvIns->iInstance);
805 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->StatTransmit, STAMTYPE_PROFILE, szStatName, STAMUNIT_TICKS_PER_CALL, "Profiling packet transmit runs.");
806#endif
807
808 /*
809 * Activate data transmission as early as possible
810 */
811 if (pThis->fActivateEarly)
812 {
813 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
814 RTSemEventSignal(pThis->EventSuspended);
815 }
816
817 LogRel(("IntNet#%u: cbRecv=%u cbSend=%u fRestrictAccess=%d\n", pDrvIns->iInstance, OpenReq.cbRecv, OpenReq.cbSend, OpenReq.fRestrictAccess));
818
819 return rc;
820}
821
822
823/**
824 * Internal networking transport driver registration record.
825 */
826const PDMDRVREG g_DrvIntNet =
827{
828 /* u32Version */
829 PDM_DRVREG_VERSION,
830 /* szDriverName */
831 "IntNet",
832 /* pszDescription */
833 "Internal Networking Transport Driver",
834 /* fFlags */
835 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
836 /* fClass. */
837 PDM_DRVREG_CLASS_NETWORK,
838 /* cMaxInstances */
839 ~0,
840 /* cbInstance */
841 sizeof(DRVINTNET),
842 /* pfnConstruct */
843 drvIntNetConstruct,
844 /* pfnDestruct */
845 drvIntNetDestruct,
846 /* pfnIOCtl */
847 NULL,
848 /* pfnPowerOn */
849 drvIntNetPowerOn,
850 /* pfnReset */
851 NULL,
852 /* pfnSuspend */
853 drvIntNetSuspend,
854 /* pfnResume */
855 drvIntNetResume,
856 /* pfnDetach */
857 NULL,
858 /* pfnPowerOff */
859 drvIntNetPowerOff
860};
861
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