VirtualBox

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

Last change on this file since 28721 was 28721, checked in by vboxsync, 15 years ago

DrvIntNet.cpp: Enable the ring-0 part of the driver.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 62.7 KB
Line 
1/* $Id: DrvIntNet.cpp 28721 2010-04-25 21:36:26Z vboxsync $ */
2/** @file
3 * DrvIntNet - Internal network transport driver.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Sun Microsystems, Inc.
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 (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#define LOG_GROUP LOG_GROUP_DRV_INTNET
26#include <VBox/pdmdrv.h>
27#include <VBox/pdmnetinline.h>
28#include <VBox/pdmnetifs.h>
29#include <VBox/cfgm.h>
30#include <VBox/intnet.h>
31#include <VBox/intnetinline.h>
32#include <VBox/vmm.h>
33#include <VBox/sup.h>
34#include <VBox/err.h>
35
36#include <VBox/param.h>
37#include <VBox/log.h>
38#include <iprt/asm.h>
39#include <iprt/assert.h>
40#include <iprt/ctype.h>
41#include <iprt/memcache.h>
42#include <iprt/net.h>
43#include <iprt/semaphore.h>
44#include <iprt/string.h>
45#include <iprt/time.h>
46#include <iprt/thread.h>
47#include <iprt/uuid.h>
48
49#include "../Builtins.h"
50
51
52/*******************************************************************************
53* Defined Constants And Macros *
54*******************************************************************************/
55/** Enables the ring-0 part. */
56#define VBOX_WITH_DRVINTNET_IN_R0
57
58
59/*******************************************************************************
60* Structures and Typedefs *
61*******************************************************************************/
62/**
63 * The state of the asynchronous thread.
64 */
65typedef enum RECVSTATE
66{
67 /** The thread is suspended. */
68 RECVSTATE_SUSPENDED = 1,
69 /** The thread is running. */
70 RECVSTATE_RUNNING,
71 /** The thread must (/has) terminate. */
72 RECVSTATE_TERMINATE,
73 /** The usual 32-bit type blowup. */
74 RECVSTATE_32BIT_HACK = 0x7fffffff
75} RECVSTATE;
76
77/**
78 * Internal networking driver instance data.
79 *
80 * @implements PDMINETWORKUP
81 */
82typedef struct DRVINTNET
83{
84 /** The network interface. */
85 PDMINETWORKUP INetworkUpR3;
86 /** The network interface. */
87 R3PTRTYPE(PPDMINETWORKDOWN) pIAboveNet;
88 /** The network config interface.
89 * Can (in theory at least) be NULL. */
90 R3PTRTYPE(PPDMINETWORKCONFIG) pIAboveConfigR3;
91 /** Pointer to the driver instance (ring-3). */
92 PPDMDRVINSR3 pDrvInsR3;
93 /** Pointer to the communication buffer (ring-3). */
94 R3PTRTYPE(PINTNETBUF) pBufR3;
95 /** Ring-3 base interface for the ring-0 context. */
96 PDMIBASER0 IBaseR0;
97 /** Ring-3 base interface for the raw-mode context. */
98 PDMIBASERC IBaseRC;
99 RTR3PTR R3PtrAlignment;
100
101 /** The network interface for the ring-0 context. */
102 PDMINETWORKUPR0 INetworkUpR0;
103 /** Pointer to the driver instance (ring-0). */
104 PPDMDRVINSR0 pDrvInsR0;
105 /** Pointer to the communication buffer (ring-0). */
106 R0PTRTYPE(PINTNETBUF) pBufR0;
107
108 /** The network interface for the raw-mode context. */
109 PDMINETWORKUPRC INetworkUpRC;
110 /** Pointer to the driver instance. */
111 PPDMDRVINSRC pDrvInsRC;
112 RTRCPTR RCPtrAlignment;
113
114 /** The transmit lock. */
115 PDMCRITSECT XmitLock;
116 /** Interface handle. */
117 INTNETIFHANDLE hIf;
118 /** The receive thread state. */
119 RECVSTATE volatile enmRecvState;
120 /** The receive thread. */
121 RTTHREAD hRecvThread;
122 /** The event semaphore that the receive thread waits on. */
123 RTSEMEVENT hRecvEvt;
124 /** The transmit thread. */
125 PPDMTHREAD pXmitThread;
126 /** The event semaphore that the transmit thread waits on. */
127 SUPSEMEVENT hXmitEvt;
128 /** The support driver session handle. */
129 PSUPDRVSESSION pSupDrvSession;
130 /** Scatter/gather descriptor cache. */
131 RTMEMCACHE hSgCache;
132 /** Set if the link is down.
133 * When the link is down all incoming packets will be dropped. */
134 bool volatile fLinkDown;
135 /** Set when the xmit thread has been signalled. (atomic) */
136 bool volatile fXmitSignalled;
137 /** Set if the transmit thread the one busy transmitting. */
138 bool volatile fXmitOnXmitThread;
139 /** The xmit thread should process the ring ASAP. */
140 bool fXmitProcessRing;
141 /** Set if data transmission should start immediately and deactivate
142 * as late as possible. */
143 bool fActivateEarlyDeactivateLate;
144 /** Padding. */
145 bool afReserved[HC_ARCH_BITS == 64 ? 3 : 3];
146 /** Scratch space for holding the ring-0 scatter / gather descriptor.
147 * The PDMSCATTERGATHER::fFlags member is used to indicate whether it is in
148 * use or not. Always accessed while owning the XmitLock. */
149 union
150 {
151 PDMSCATTERGATHER Sg;
152 uint8_t padding[8 * sizeof(RTUINTPTR)];
153 } u;
154 /** The network name. */
155 char szNetwork[INTNET_MAX_NETWORK_NAME];
156
157 /** Number of GSO packets sent. */
158 STAMCOUNTER StatSentGso;
159 /** Number of GSO packets recevied. */
160 STAMCOUNTER StatReceivedGso;
161 /** Number of packets send from ring-0. */
162 STAMCOUNTER StatSentR0;
163 /** The number of times we've had to wake up the xmit thread to contine the
164 * ring-0 job. */
165 STAMCOUNTER StatXmitWakeupR0;
166 /** The number of times we've had to wake up the xmit thread to contine the
167 * ring-3 job. */
168 STAMCOUNTER StatXmitWakeupR3;
169 /** The times the xmit thread has been told to process the ring. */
170 STAMCOUNTER StatXmitProcessRing;
171#ifdef VBOX_WITH_STATISTICS
172 /** Profiling packet transmit runs. */
173 STAMPROFILE StatTransmit;
174 /** Profiling packet receive runs. */
175 STAMPROFILEADV StatReceive;
176#endif /* VBOX_WITH_STATISTICS */
177#ifdef LOG_ENABLED
178 /** The nano ts of the last transfer. */
179 uint64_t u64LastTransferTS;
180 /** The nano ts of the last receive. */
181 uint64_t u64LastReceiveTS;
182#endif
183} DRVINTNET;
184AssertCompileMemberAlignment(DRVINTNET, XmitLock, 8);
185AssertCompileMemberAlignment(DRVINTNET, StatSentGso, 8);
186/** Pointer to instance data of the internal networking driver. */
187typedef DRVINTNET *PDRVINTNET;
188
189
190#ifdef IN_RING3
191
192
193/**
194 * Updates the MAC address on the kernel side.
195 *
196 * @returns VBox status code.
197 * @param pThis The driver instance.
198 */
199static int drvR3IntNetUpdateMacAddress(PDRVINTNET pThis)
200{
201 if (!pThis->pIAboveConfigR3)
202 return VINF_SUCCESS;
203
204 INTNETIFSETMACADDRESSREQ SetMacAddressReq;
205 SetMacAddressReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
206 SetMacAddressReq.Hdr.cbReq = sizeof(SetMacAddressReq);
207 SetMacAddressReq.pSession = NIL_RTR0PTR;
208 SetMacAddressReq.hIf = pThis->hIf;
209 int rc = pThis->pIAboveConfigR3->pfnGetMac(pThis->pIAboveConfigR3, &SetMacAddressReq.Mac);
210 if (RT_SUCCESS(rc))
211 rc = PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SET_MAC_ADDRESS,
212 &SetMacAddressReq, sizeof(SetMacAddressReq));
213
214 Log(("drvR3IntNetUpdateMacAddress: %.*Rhxs rc=%Rrc\n", sizeof(SetMacAddressReq.Mac), &SetMacAddressReq.Mac, rc));
215 return rc;
216}
217
218
219/**
220 * Sets the kernel interface active or inactive.
221 *
222 * Worker for poweron, poweroff, suspend and resume.
223 *
224 * @returns VBox status code.
225 * @param pThis The driver instance.
226 * @param fActive The new state.
227 */
228static int drvR3IntNetSetActive(PDRVINTNET pThis, bool fActive)
229{
230 if (!pThis->pIAboveConfigR3)
231 return VINF_SUCCESS;
232
233 INTNETIFSETACTIVEREQ SetActiveReq;
234 SetActiveReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
235 SetActiveReq.Hdr.cbReq = sizeof(SetActiveReq);
236 SetActiveReq.pSession = NIL_RTR0PTR;
237 SetActiveReq.hIf = pThis->hIf;
238 SetActiveReq.fActive = fActive;
239 int rc = PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SET_ACTIVE,
240 &SetActiveReq, sizeof(SetActiveReq));
241
242 Log(("drvR3IntNetSetActive: fActive=%d rc=%Rrc\n", fActive, rc));
243 AssertRC(rc);
244 return rc;
245}
246
247#endif /* IN_RING3 */
248
249/* -=-=-=-=- PDMINETWORKUP -=-=-=-=- */
250
251/**
252 * Helper for signalling the xmit thread.
253 *
254 * @returns VERR_TRY_AGAIN (convenience).
255 * @param pThis The instance data..
256 */
257DECLINLINE(int) drvIntNetSignalXmit(PDRVINTNET pThis)
258{
259 /// @todo if (!ASMAtomicXchgBool(&pThis->fXmitSignalled, true)) - needs careful optimizing.
260 {
261 int rc = SUPSemEventSignal(pThis->pSupDrvSession, pThis->hXmitEvt);
262 AssertRC(rc);
263 STAM_REL_COUNTER_INC(&pThis->CTX_SUFF(StatXmitWakeup));
264 }
265 return VERR_TRY_AGAIN;
266}
267
268
269/**
270 * Helper for processing the ring-0 consumer side of the xmit ring.
271 *
272 * The caller MUST own the xmit lock.
273 *
274 * @returns Status code from IntNetR0IfSend, except for VERR_TRY_AGAIN.
275 * @param pThis The instance data..
276 */
277DECLINLINE(int) drvIntNetProcessXmit(PDRVINTNET pThis)
278{
279 Assert(PDMCritSectIsOwner(&pThis->XmitLock));
280
281#ifdef IN_RING3
282 INTNETIFSENDREQ SendReq;
283 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
284 SendReq.Hdr.cbReq = sizeof(SendReq);
285 SendReq.pSession = NIL_RTR0PTR;
286 SendReq.hIf = pThis->hIf;
287 int rc = PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SEND, &SendReq, sizeof(SendReq));
288#else
289 int rc = IntNetR0IfSend(pThis->hIf, pThis->pSupDrvSession);
290 if (rc == VERR_TRY_AGAIN)
291 {
292 ASMAtomicUoWriteBool(&pThis->fXmitProcessRing, true);
293 drvIntNetSignalXmit(pThis);
294 rc = VINF_SUCCESS;
295 }
296#endif
297 return rc;
298}
299
300
301
302/**
303 * @interface_method_impl{PDMINETWORKUP,pfnBeginXmit}
304 */
305PDMBOTHCBDECL(int) drvIntNetUp_BeginXmit(PPDMINETWORKUP pInterface, bool fOnWorkerThread)
306{
307 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, CTX_SUFF(INetworkUp));
308#ifndef IN_RING3
309 Assert(!fOnWorkerThread);
310#endif
311
312 int rc = PDMCritSectTryEnter(&pThis->XmitLock);
313 if (RT_SUCCESS(rc))
314 {
315 if (fOnWorkerThread)
316 {
317 ASMAtomicUoWriteBool(&pThis->fXmitOnXmitThread, true);
318 ASMAtomicWriteBool(&pThis->fXmitSignalled, false);
319 }
320 }
321 else if (rc == VERR_SEM_BUSY)
322 {
323 /** @todo Does this actually make sense if the other dude is an EMT and so
324 * forth? I seriously think this is ring-0 only...
325 * We might end up waking up the xmit thread unnecessarily here, even when in
326 * ring-0... This needs some more thought and opitmizations when the ring-0 bits
327 * are working. */
328#ifdef IN_RING3
329 if ( !fOnWorkerThread
330 /*&& !ASMAtomicUoReadBool(&pThis->fXmitOnXmitThread)
331 && ASMAtomicCmpXchgBool(&pThis->fXmitSignalled, true, false)*/)
332 {
333 rc = SUPSemEventSignal(pThis->pSupDrvSession, pThis->hXmitEvt);
334 AssertRC(rc);
335 }
336 rc = VERR_TRY_AGAIN;
337#else /* IN_RING0 */
338 rc = drvIntNetSignalXmit(pThis);
339#endif /* IN_RING0 */
340 }
341 return rc;
342}
343
344
345/**
346 * @interface_method_impl{PDMINETWORKUP,pfnAllocBuf}
347 */
348PDMBOTHCBDECL(int) drvIntNetUp_AllocBuf(PPDMINETWORKUP pInterface, size_t cbMin,
349 PCPDMNETWORKGSO pGso, PPPDMSCATTERGATHER ppSgBuf)
350{
351 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, CTX_SUFF(INetworkUp));
352 int rc = VINF_SUCCESS;
353 Assert(cbMin < UINT32_MAX / 2);
354 Assert(PDMCritSectIsOwner(&pThis->XmitLock));
355
356 /*
357 * Allocate a S/G descriptor.
358 * This shouldn't normally fail as the NICs usually won't allocate more
359 * than one buffer at a time and the SG gets freed on sending.
360 */
361#ifdef IN_RING3
362 PPDMSCATTERGATHER pSgBuf = (PPDMSCATTERGATHER)RTMemCacheAlloc(pThis->hSgCache);
363 if (!pSgBuf)
364 return VERR_NO_MEMORY;
365#else
366 PPDMSCATTERGATHER pSgBuf = &pThis->u.Sg;
367 if (RT_UNLIKELY(pSgBuf->fFlags != 0))
368 return drvIntNetSignalXmit(pThis);
369#endif
370
371 /*
372 * Allocate room in the ring buffer.
373 *
374 * In ring-3 we may have to process the xmit ring before there is
375 * sufficient buffer space since we might've stacked up a few frames to the
376 * trunk while in ring-0. (There is not point of doing this in ring-0.)
377 */
378 PINTNETHDR pHdr = NULL; /* gcc silliness */
379 if (pGso)
380 rc = IntNetRingAllocateGsoFrame(&pThis->CTX_SUFF(pBuf)->Send, (uint32_t)cbMin, pGso,
381 &pHdr, &pSgBuf->aSegs[0].pvSeg);
382 else
383 rc = IntNetRingAllocateFrame(&pThis->CTX_SUFF(pBuf)->Send, (uint32_t)cbMin,
384 &pHdr, &pSgBuf->aSegs[0].pvSeg);
385#ifdef IN_RING3
386 if ( RT_FAILURE(rc)
387 && pThis->CTX_SUFF(pBuf)->cbSend >= cbMin * 2 + sizeof(INTNETHDR))
388 {
389 drvIntNetProcessXmit(pThis);
390 if (pGso)
391 rc = IntNetRingAllocateGsoFrame(&pThis->CTX_SUFF(pBuf)->Send, (uint32_t)cbMin, pGso,
392 &pHdr, &pSgBuf->aSegs[0].pvSeg);
393 else
394 rc = IntNetRingAllocateFrame(&pThis->CTX_SUFF(pBuf)->Send, (uint32_t)cbMin,
395 &pHdr, &pSgBuf->aSegs[0].pvSeg);
396 }
397#endif
398 if (RT_SUCCESS(rc))
399 {
400 /*
401 * Set up the S/G descriptor and return successfully.
402 */
403 pSgBuf->fFlags = PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1;
404 pSgBuf->cbUsed = 0;
405 pSgBuf->cbAvailable = cbMin;
406 pSgBuf->pvAllocator = pHdr;
407 pSgBuf->pvUser = pGso ? (PPDMNETWORKGSO)pSgBuf->aSegs[0].pvSeg - 1 : NULL;
408 pSgBuf->cSegs = 1;
409 pSgBuf->aSegs[0].cbSeg = cbMin;
410
411 *ppSgBuf = pSgBuf;
412 return VINF_SUCCESS;
413 }
414
415#ifdef IN_RING3
416 /*
417 * If the above fails, then we're really out of space. There are nobody
418 * competing with us here because of the xmit lock.
419 */
420 rc = VERR_NO_MEMORY;
421 RTMemCacheFree(pThis->hSgCache, pSgBuf);
422
423#else /* IN_RING0 */
424 /*
425 * If the request is reasonable, kick the xmit thread and tell it to
426 * process the xmit ring ASAP.
427 */
428 if (pThis->CTX_SUFF(pBuf)->cbSend >= cbMin * 2 + sizeof(INTNETHDR))
429 {
430 pThis->fXmitProcessRing = true;
431 rc = drvIntNetSignalXmit(pThis);
432 }
433 else
434 rc = VERR_NO_MEMORY;
435 pSgBuf->fFlags = 0;
436#endif /* IN_RING0 */
437 return rc;
438}
439
440
441/**
442 * @interface_method_impl{PDMINETWORKUP,pfnFreeBuf}
443 */
444PDMBOTHCBDECL(int) drvIntNetUp_FreeBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf)
445{
446 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, CTX_SUFF(INetworkUp));
447 PINTNETHDR pHdr = (PINTNETHDR)pSgBuf->pvAllocator;
448#ifdef IN_RING0
449 Assert(pSgBuf == &pThis->u.Sg);
450#endif
451 Assert(pSgBuf->fFlags == (PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1));
452 Assert(pSgBuf->cbUsed <= pSgBuf->cbAvailable);
453 Assert( pHdr->u16Type == INTNETHDR_TYPE_FRAME
454 || pHdr->u16Type == INTNETHDR_TYPE_GSO);
455 Assert(PDMCritSectIsOwner(&pThis->XmitLock));
456
457 /** @todo LATER: try unalloc the frame. */
458 pHdr->u16Type = INTNETHDR_TYPE_PADDING;
459 IntNetRingCommitFrame(&pThis->CTX_SUFF(pBuf)->Send, pHdr);
460
461#ifdef IN_RING3
462 RTMemCacheFree(pThis->hSgCache, pSgBuf);
463#else
464 pSgBuf->fFlags = 0;
465#endif
466 return VINF_SUCCESS;
467}
468
469
470/**
471 * @interface_method_impl{PDMINETWORKUP,pfnSendBuf}
472 */
473PDMBOTHCBDECL(int) drvIntNetUp_SendBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)
474{
475 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, CTX_SUFF(INetworkUp));
476 STAM_PROFILE_START(&pThis->StatTransmit, a);
477
478 AssertPtr(pSgBuf);
479 Assert(pSgBuf->fFlags == (PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1));
480 Assert(pSgBuf->cbUsed <= pSgBuf->cbAvailable);
481 Assert(PDMCritSectIsOwner(&pThis->XmitLock));
482
483 if (pSgBuf->pvUser)
484 STAM_COUNTER_INC(&pThis->StatSentGso);
485
486 /*
487 * Commit the frame and push it thru the switch.
488 */
489 PINTNETHDR pHdr = (PINTNETHDR)pSgBuf->pvAllocator;
490 IntNetRingCommitFrameEx(&pThis->CTX_SUFF(pBuf)->Send, pHdr, pSgBuf->cbUsed);
491 int rc = drvIntNetProcessXmit(pThis);
492 STAM_PROFILE_STOP(&pThis->StatTransmit, a);
493
494 /*
495 * Free the descriptor and return.
496 */
497#ifdef IN_RING3
498 RTMemCacheFree(pThis->hSgCache, pSgBuf);
499#else
500 STAM_REL_COUNTER_INC(&pThis->StatSentR0);
501 pSgBuf->fFlags = 0;
502#endif
503 return rc;
504}
505
506
507/**
508 * @interface_method_impl{PDMINETWORKUP,pfnEndXmit}
509 */
510PDMBOTHCBDECL(void) drvIntNetUp_EndXmit(PPDMINETWORKUP pInterface)
511{
512 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, CTX_SUFF(INetworkUp));
513 ASMAtomicUoWriteBool(&pThis->fXmitOnXmitThread, false);
514 PDMCritSectLeave(&pThis->XmitLock);
515}
516
517
518/**
519 * @interface_method_impl{PDMINETWORKUP,pfnSetPromiscuousMode}
520 */
521PDMBOTHCBDECL(void) drvIntNetUp_SetPromiscuousMode(PPDMINETWORKUP pInterface, bool fPromiscuous)
522{
523 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, CTX_SUFF(INetworkUp));
524
525#ifdef IN_RING3
526 INTNETIFSETPROMISCUOUSMODEREQ Req;
527 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
528 Req.Hdr.cbReq = sizeof(Req);
529 Req.pSession = NIL_RTR0PTR;
530 Req.hIf = pThis->hIf;
531 Req.fPromiscuous = fPromiscuous;
532 int rc = PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE, &Req, sizeof(Req));
533#else /* IN_RING0 */
534 int rc = IntNetR0IfSetPromiscuousMode(pThis->hIf, pThis->pSupDrvSession, fPromiscuous);
535#endif /* IN_RING0 */
536
537 LogFlow(("drvIntNetUp_SetPromiscuousMode: fPromiscuous=%RTbool\n", fPromiscuous));
538 AssertRC(rc);
539}
540
541#ifdef IN_RING3
542
543/**
544 * @interface_method_impl{PDMINETWORKUP,pfnNotifyLinkChanged}
545 */
546static DECLCALLBACK(void) drvR3IntNetUp_NotifyLinkChanged(PPDMINETWORKUP pInterface, PDMNETWORKLINKSTATE enmLinkState)
547{
548 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, CTX_SUFF(INetworkUp));
549 bool fLinkDown;
550 switch (enmLinkState)
551 {
552 case PDMNETWORKLINKSTATE_DOWN:
553 case PDMNETWORKLINKSTATE_DOWN_RESUME:
554 fLinkDown = true;
555 break;
556 default:
557 AssertMsgFailed(("enmLinkState=%d\n", enmLinkState));
558 case PDMNETWORKLINKSTATE_UP:
559 fLinkDown = false;
560 break;
561 }
562 LogFlow(("drvR3IntNetUp_NotifyLinkChanged: enmLinkState=%d %d->%d\n", enmLinkState, pThis->fLinkDown, fLinkDown));
563 ASMAtomicXchgSize(&pThis->fLinkDown, fLinkDown);
564}
565
566
567/* -=-=-=-=- Transmit Thread -=-=-=-=- */
568
569/**
570 * Async I/O thread for defered packet transmission.
571 *
572 * @returns VBox status code. Returning failure will naturally terminate the thread.
573 * @param pDrvIns The internal networking driver instance.
574 * @param pThread The thread.
575 */
576static DECLCALLBACK(int) drvR3IntNetXmitThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
577{
578 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
579
580 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
581 {
582 /*
583 * Transmit any pending packets.
584 */
585 /** @todo Optimize this. We shouldn't call pfnXmitPending unless asked for.
586 * Also there is no need to call drvIntNetProcessXmit if we also
587 * called pfnXmitPending and send one or more frames. */
588 if (ASMAtomicXchgBool(&pThis->fXmitProcessRing, false))
589 {
590 STAM_REL_COUNTER_INC(&pThis->StatXmitProcessRing);
591 PDMCritSectEnter(&pThis->XmitLock, VERR_IGNORED);
592 drvIntNetProcessXmit(pThis);
593 PDMCritSectLeave(&pThis->XmitLock);
594 }
595
596 pThis->pIAboveNet->pfnXmitPending(pThis->pIAboveNet);
597
598 if (ASMAtomicXchgBool(&pThis->fXmitProcessRing, false))
599 {
600 STAM_REL_COUNTER_INC(&pThis->StatXmitProcessRing);
601 PDMCritSectEnter(&pThis->XmitLock, VERR_IGNORED);
602 drvIntNetProcessXmit(pThis);
603 PDMCritSectLeave(&pThis->XmitLock);
604 }
605
606 /*
607 * Block until we've got something to send or is supposed
608 * to leave the running state.
609 */
610 int rc = SUPSemEventWaitNoResume(pThis->pSupDrvSession, pThis->hXmitEvt, RT_INDEFINITE_WAIT);
611 AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc);
612 if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
613 break;
614
615 }
616
617 /* The thread is being initialized, suspended or terminated. */
618 return VINF_SUCCESS;
619}
620
621
622/**
623 * @copydoc FNPDMTHREADWAKEUPDRV
624 */
625static DECLCALLBACK(int) drvR3IntNetXmitWakeUp(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
626{
627 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
628 return SUPSemEventSignal(pThis->pSupDrvSession, pThis->hXmitEvt);
629}
630
631
632/* -=-=-=-=- Receive Thread -=-=-=-=- */
633
634/**
635 * Wait for space to become available up the driver/device chain.
636 *
637 * @returns VINF_SUCCESS if space is available.
638 * @returns VERR_STATE_CHANGED if the state changed.
639 * @returns VBox status code on other errors.
640 * @param pThis Pointer to the instance data.
641 */
642static int drvR3IntNetRecvWaitForSpace(PDRVINTNET pThis)
643{
644 LogFlow(("drvR3IntNetRecvWaitForSpace:\n"));
645 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
646 int rc = pThis->pIAboveNet->pfnWaitReceiveAvail(pThis->pIAboveNet, RT_INDEFINITE_WAIT);
647 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
648 LogFlow(("drvR3IntNetRecvWaitForSpace: returns %Rrc\n", rc));
649 return rc;
650}
651
652
653/**
654 * Executes async I/O (RUNNING mode).
655 *
656 * @returns VERR_STATE_CHANGED if the state changed.
657 * @returns Appropriate VBox status code (error) on fatal error.
658 * @param pThis The driver instance data.
659 */
660static int drvR3IntNetRecvRun(PDRVINTNET pThis)
661{
662 PPDMDRVINS pDrvIns = pThis->pDrvInsR3;
663 LogFlow(("drvR3IntNetRecvRun: pThis=%p\n", pThis));
664
665 /*
666 * The running loop - processing received data and waiting for more to arrive.
667 */
668 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
669 PINTNETBUF pBuf = pThis->CTX_SUFF(pBuf);
670 PINTNETRINGBUF pRingBuf = &pBuf->Recv;
671 for (;;)
672 {
673 /*
674 * Process the receive buffer.
675 */
676 PINTNETHDR pHdr;
677 while ((pHdr = IntNetRingGetNextFrameToRead(pRingBuf)) != NULL)
678 {
679 /*
680 * Check the state and then inspect the packet.
681 */
682 if (pThis->enmRecvState != RECVSTATE_RUNNING)
683 {
684 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
685 LogFlow(("drvR3IntNetRecvRun: returns VERR_STATE_CHANGED (state changed - #0)\n"));
686 return VERR_STATE_CHANGED;
687 }
688
689 Log2(("pHdr=%p offRead=%#x: %.8Rhxs\n", pHdr, pRingBuf->offReadX, pHdr));
690 uint16_t u16Type = pHdr->u16Type;
691 if ( ( u16Type == INTNETHDR_TYPE_FRAME
692 || u16Type == INTNETHDR_TYPE_GSO)
693 && !pThis->fLinkDown)
694 {
695 /*
696 * Check if there is room for the frame and pass it up.
697 */
698 size_t cbFrame = pHdr->cbFrame;
699 int rc = pThis->pIAboveNet->pfnWaitReceiveAvail(pThis->pIAboveNet, 0);
700 if (rc == VINF_SUCCESS)
701 {
702 if (u16Type == INTNETHDR_TYPE_FRAME)
703 {
704 /*
705 * Normal frame.
706 */
707#ifdef LOG_ENABLED
708 if (LogIsEnabled())
709 {
710 uint64_t u64Now = RTTimeProgramNanoTS();
711 LogFlow(("drvR3IntNetRecvRun: %-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
712 cbFrame, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS));
713 pThis->u64LastReceiveTS = u64Now;
714 Log2(("drvR3IntNetRecvRun: cbFrame=%#x\n"
715 "%.*Rhxd\n",
716 cbFrame, cbFrame, IntNetHdrGetFramePtr(pHdr, pBuf)));
717 }
718#endif
719 rc = pThis->pIAboveNet->pfnReceive(pThis->pIAboveNet, IntNetHdrGetFramePtr(pHdr, pBuf), cbFrame);
720 AssertRC(rc);
721
722 /* skip to the next frame. */
723 IntNetRingSkipFrame(pRingBuf);
724 }
725 else
726 {
727 /*
728 * Generic segment offload frame (INTNETHDR_TYPE_GSO).
729 *
730 * This is where we do the offloading since we don't
731 * emulate any NICs with large receive offload (LRO).
732 */
733 STAM_COUNTER_INC(&pThis->StatReceivedGso);
734 PCPDMNETWORKGSO pGso = IntNetHdrGetGsoContext(pHdr, pBuf);
735 if (PDMNetGsoIsValid(pGso, cbFrame, cbFrame - sizeof(PDMNETWORKGSO)))
736 {
737 cbFrame -= sizeof(PDMNETWORKGSO);
738
739 uint8_t abHdrScratch[256];
740 uint32_t const cSegs = PDMNetGsoCalcSegmentCount(pGso, cbFrame);
741#ifdef LOG_ENABLED
742 if (LogIsEnabled())
743 {
744 uint64_t u64Now = RTTimeProgramNanoTS();
745 LogFlow(("drvR3IntNetRecvRun: %-4d bytes at %llu ns deltas: r=%llu t=%llu; GSO - %u segs\n",
746 cbFrame, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS, cSegs));
747 pThis->u64LastReceiveTS = u64Now;
748 Log2(("drvR3IntNetRecvRun: cbFrame=%#x type=%d cbHdrs=%#x Hdr1=%#x Hdr2=%#x MMS=%#x\n"
749 "%.*Rhxd\n",
750 cbFrame, pGso->u8Type, pGso->cbHdrs, pGso->offHdr1, pGso->offHdr2, pGso->cbMaxSeg,
751 cbFrame - sizeof(*pGso), pGso + 1));
752 }
753#endif
754 for (size_t iSeg = 0; iSeg < cSegs; iSeg++)
755 {
756 uint32_t cbSegFrame;
757 void *pvSegFrame = PDMNetGsoCarveSegmentQD(pGso, (uint8_t *)(pGso + 1), cbFrame, abHdrScratch,
758 iSeg, cSegs, &cbSegFrame);
759 rc = drvR3IntNetRecvWaitForSpace(pThis);
760 if (RT_FAILURE(rc))
761 {
762 Log(("drvR3IntNetRecvRun: drvR3IntNetRecvWaitForSpace -> %Rrc; iSeg=%u cSegs=%u\n", iSeg, cSegs));
763 break; /* we drop the rest. */
764 }
765 rc = pThis->pIAboveNet->pfnReceive(pThis->pIAboveNet, pvSegFrame, cbSegFrame);
766 AssertRC(rc);
767 }
768 }
769 else
770 {
771 AssertMsgFailed(("cbFrame=%#x type=%d cbHdrs=%#x Hdr1=%#x Hdr2=%#x MMS=%#x\n",
772 cbFrame, pGso->u8Type, pGso->cbHdrs, pGso->offHdr1, pGso->offHdr2, pGso->cbMaxSeg));
773 STAM_REL_COUNTER_INC(&pBuf->cStatBadFrames);
774 }
775
776 IntNetRingSkipFrame(pRingBuf);
777 }
778 }
779 else
780 {
781 /*
782 * Wait for sufficient space to become available and then retry.
783 */
784 rc = drvR3IntNetRecvWaitForSpace(pThis);
785 if (RT_FAILURE(rc))
786 {
787 if (rc == VERR_INTERRUPTED)
788 {
789 /*
790 * NIC is going down, likely because the VM is being reset. Skip the frame.
791 */
792 AssertMsg(IntNetIsValidFrameType(pHdr->u16Type), ("Unknown frame type %RX16! offRead=%#x\n", pHdr->u16Type, pRingBuf->offReadX));
793 IntNetRingSkipFrame(pRingBuf);
794 }
795 else
796 {
797 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
798 LogFlow(("drvR3IntNetRecvRun: returns %Rrc (wait-for-space)\n", rc));
799 return rc;
800 }
801 }
802 }
803 }
804 else
805 {
806 /*
807 * Link down or unknown frame - skip to the next frame.
808 */
809 AssertMsg(IntNetIsValidFrameType(pHdr->u16Type), ("Unknown frame type %RX16! offRead=%#x\n", pHdr->u16Type, pRingBuf->offReadX));
810 IntNetRingSkipFrame(pRingBuf);
811 STAM_REL_COUNTER_INC(&pBuf->cStatBadFrames);
812 }
813 } /* while more received data */
814
815 /*
816 * Wait for data, checking the state before we block.
817 */
818 if (pThis->enmRecvState != RECVSTATE_RUNNING)
819 {
820 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
821 LogFlow(("drvR3IntNetRecvRun: returns VINF_SUCCESS (state changed - #1)\n"));
822 return VERR_STATE_CHANGED;
823 }
824 INTNETIFWAITREQ WaitReq;
825 WaitReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
826 WaitReq.Hdr.cbReq = sizeof(WaitReq);
827 WaitReq.pSession = NIL_RTR0PTR;
828 WaitReq.hIf = pThis->hIf;
829 WaitReq.cMillies = 30000; /* 30s - don't wait forever, timeout now and then. */
830 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
831 int rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_WAIT, &WaitReq, sizeof(WaitReq));
832 if ( RT_FAILURE(rc)
833 && rc != VERR_TIMEOUT
834 && rc != VERR_INTERRUPTED)
835 {
836 LogFlow(("drvR3IntNetRecvRun: returns %Rrc\n", rc));
837 return rc;
838 }
839 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
840 }
841}
842
843
844/**
845 * Asynchronous I/O thread for handling receive.
846 *
847 * @returns VINF_SUCCESS (ignored).
848 * @param ThreadSelf Thread handle.
849 * @param pvUser Pointer to a DRVINTNET structure.
850 */
851static DECLCALLBACK(int) drvR3IntNetRecvThread(RTTHREAD ThreadSelf, void *pvUser)
852{
853 PDRVINTNET pThis = (PDRVINTNET)pvUser;
854 LogFlow(("drvR3IntNetRecvThread: pThis=%p\n", pThis));
855 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
856
857 /*
858 * The main loop - acting on state.
859 */
860 for (;;)
861 {
862 RECVSTATE enmRecvState = pThis->enmRecvState;
863 switch (enmRecvState)
864 {
865 case RECVSTATE_SUSPENDED:
866 {
867 int rc = RTSemEventWait(pThis->hRecvEvt, 30000);
868 if ( RT_FAILURE(rc)
869 && rc != VERR_TIMEOUT)
870 {
871 LogFlow(("drvR3IntNetRecvThread: returns %Rrc\n", rc));
872 return rc;
873 }
874 break;
875 }
876
877 case RECVSTATE_RUNNING:
878 {
879 int rc = drvR3IntNetRecvRun(pThis);
880 if ( rc != VERR_STATE_CHANGED
881 && RT_FAILURE(rc))
882 {
883 LogFlow(("drvR3IntNetRecvThread: returns %Rrc\n", rc));
884 return rc;
885 }
886 break;
887 }
888
889 default:
890 AssertMsgFailed(("Invalid state %d\n", enmRecvState));
891 case RECVSTATE_TERMINATE:
892 LogFlow(("drvR3IntNetRecvThread: returns VINF_SUCCESS\n"));
893 return VINF_SUCCESS;
894 }
895 }
896}
897
898
899/* -=-=-=-=- PDMIBASERC -=-=-=-=- */
900
901/**
902 * @interface_method_impl{PDMIBASERC,pfnQueryInterface}
903 */
904static DECLCALLBACK(RTRCPTR) drvR3IntNetIBaseRC_QueryInterface(PPDMIBASERC pInterface, const char *pszIID)
905{
906 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, IBaseRC);
907
908#if 0
909 PDMIBASERC_RETURN_INTERFACE(pThis->pDrvInsR3, pszIID, PDMINETWORKUP, &pThis->INetworkUpRC);
910#endif
911 return NIL_RTRCPTR;
912}
913
914
915/* -=-=-=-=- PDMIBASER0 -=-=-=-=- */
916
917/**
918 * @interface_method_impl{PDMIBASER0,pfnQueryInterface}
919 */
920static DECLCALLBACK(RTR0PTR) drvR3IntNetIBaseR0_QueryInterface(PPDMIBASER0 pInterface, const char *pszIID)
921{
922 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, IBaseR0);
923#ifdef VBOX_WITH_DRVINTNET_IN_R0
924 PDMIBASER0_RETURN_INTERFACE(pThis->pDrvInsR3, pszIID, PDMINETWORKUP, &pThis->INetworkUpR0);
925#endif
926 return NIL_RTR0PTR;
927}
928
929
930/* -=-=-=-=- PDMIBASE -=-=-=-=- */
931
932/**
933 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
934 */
935static DECLCALLBACK(void *) drvR3IntNetIBase_QueryInterface(PPDMIBASE pInterface, const char *pszIID)
936{
937 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
938 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
939
940 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
941 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASER0, &pThis->IBaseR0);
942 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASERC, &pThis->IBaseRC);
943 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKUP, &pThis->INetworkUpR3);
944 return NULL;
945}
946
947
948/* -=-=-=-=- PDMDRVREG -=-=-=-=- */
949
950/**
951 * Power Off notification.
952 *
953 * @param pDrvIns The driver instance.
954 */
955static DECLCALLBACK(void) drvR3IntNetPowerOff(PPDMDRVINS pDrvIns)
956{
957 LogFlow(("drvR3IntNetPowerOff\n"));
958 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
959 if (!pThis->fActivateEarlyDeactivateLate)
960 {
961 ASMAtomicXchgSize(&pThis->enmRecvState, RECVSTATE_SUSPENDED);
962 drvR3IntNetSetActive(pThis, false /* fActive */);
963 }
964}
965
966
967/**
968 * drvR3IntNetResume helper.
969 */
970static int drvR3IntNetResumeSend(PDRVINTNET pThis, const void *pvBuf, size_t cb)
971{
972 /*
973 * Add the frame to the send buffer and push it onto the network.
974 */
975 int rc = IntNetRingWriteFrame(&pThis->pBufR3->Send, pvBuf, (uint32_t)cb);
976 if ( rc == VERR_BUFFER_OVERFLOW
977 && pThis->pBufR3->cbSend < cb)
978 {
979 INTNETIFSENDREQ SendReq;
980 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
981 SendReq.Hdr.cbReq = sizeof(SendReq);
982 SendReq.pSession = NIL_RTR0PTR;
983 SendReq.hIf = pThis->hIf;
984 PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SEND, &SendReq, sizeof(SendReq));
985
986 rc = IntNetRingWriteFrame(&pThis->pBufR3->Send, pvBuf, (uint32_t)cb);
987 }
988
989 if (RT_SUCCESS(rc))
990 {
991 INTNETIFSENDREQ SendReq;
992 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
993 SendReq.Hdr.cbReq = sizeof(SendReq);
994 SendReq.pSession = NIL_RTR0PTR;
995 SendReq.hIf = pThis->hIf;
996 rc = PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SEND, &SendReq, sizeof(SendReq));
997 }
998
999 AssertRC(rc);
1000 return rc;
1001}
1002
1003
1004/**
1005 * Resume notification.
1006 *
1007 * @param pDrvIns The driver instance.
1008 */
1009static DECLCALLBACK(void) drvR3IntNetResume(PPDMDRVINS pDrvIns)
1010{
1011 LogFlow(("drvR3IntNetPowerResume\n"));
1012 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
1013 if (!pThis->fActivateEarlyDeactivateLate)
1014 {
1015 ASMAtomicXchgSize(&pThis->enmRecvState, RECVSTATE_RUNNING);
1016 RTSemEventSignal(pThis->hRecvEvt);
1017 drvR3IntNetUpdateMacAddress(pThis); /* (could be a state restore) */
1018 drvR3IntNetSetActive(pThis, true /* fActive */);
1019 }
1020 if ( PDMDrvHlpVMTeleportedAndNotFullyResumedYet(pDrvIns)
1021 && pThis->pIAboveConfigR3)
1022 {
1023 /*
1024 * We've just been teleported and need to drop a hint to the switch
1025 * since we're likely to have changed to a different port. We just
1026 * push out some ethernet frame that doesn't mean anything to anyone.
1027 * For this purpose ethertype 0x801e was chosen since it was registered
1028 * to Sun (dunno what it is/was used for though).
1029 */
1030 union
1031 {
1032 RTNETETHERHDR Hdr;
1033 uint8_t ab[128];
1034 } Frame;
1035 RT_ZERO(Frame);
1036 Frame.Hdr.DstMac.au16[0] = 0xffff;
1037 Frame.Hdr.DstMac.au16[1] = 0xffff;
1038 Frame.Hdr.DstMac.au16[2] = 0xffff;
1039 Frame.Hdr.EtherType = RT_H2BE_U16_C(0x801e);
1040 int rc = pThis->pIAboveConfigR3->pfnGetMac(pThis->pIAboveConfigR3, &Frame.Hdr.SrcMac);
1041 if (RT_SUCCESS(rc))
1042 rc = drvR3IntNetResumeSend(pThis, &Frame, sizeof(Frame));
1043 if (RT_FAILURE(rc))
1044 LogRel(("IntNet#%u: Sending dummy frame failed: %Rrc\n", pDrvIns->iInstance, rc));
1045 }
1046}
1047
1048
1049/**
1050 * Suspend notification.
1051 *
1052 * @param pDrvIns The driver instance.
1053 */
1054static DECLCALLBACK(void) drvR3IntNetSuspend(PPDMDRVINS pDrvIns)
1055{
1056 LogFlow(("drvR3IntNetPowerSuspend\n"));
1057 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
1058 if (!pThis->fActivateEarlyDeactivateLate)
1059 {
1060 ASMAtomicXchgSize(&pThis->enmRecvState, RECVSTATE_SUSPENDED);
1061 drvR3IntNetSetActive(pThis, false /* fActive */);
1062 }
1063}
1064
1065
1066/**
1067 * Power On notification.
1068 *
1069 * @param pDrvIns The driver instance.
1070 */
1071static DECLCALLBACK(void) drvR3IntNetPowerOn(PPDMDRVINS pDrvIns)
1072{
1073 LogFlow(("drvR3IntNetPowerOn\n"));
1074 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
1075 if (!pThis->fActivateEarlyDeactivateLate)
1076 {
1077 ASMAtomicXchgSize(&pThis->enmRecvState, RECVSTATE_RUNNING);
1078 RTSemEventSignal(pThis->hRecvEvt);
1079 drvR3IntNetUpdateMacAddress(pThis);
1080 drvR3IntNetSetActive(pThis, true /* fActive */);
1081 }
1082}
1083
1084
1085/**
1086 * @interface_method_impl{PDMDRVREG,pfnRelocate}
1087 */
1088static DECLCALLBACK(void) drvR3IntNetRelocate(PPDMDRVINS pDrvIns, RTGCINTPTR offDelta)
1089{
1090 /* nothing to do here yet */
1091}
1092
1093
1094/**
1095 * Destruct a driver instance.
1096 *
1097 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
1098 * resources can be freed correctly.
1099 *
1100 * @param pDrvIns The driver instance data.
1101 */
1102static DECLCALLBACK(void) drvR3IntNetDestruct(PPDMDRVINS pDrvIns)
1103{
1104 LogFlow(("drvR3IntNetDestruct\n"));
1105 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
1106 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
1107
1108 /*
1109 * Indicate to the thread that it's time to quit.
1110 */
1111 ASMAtomicXchgSize(&pThis->enmRecvState, RECVSTATE_TERMINATE);
1112 ASMAtomicXchgSize(&pThis->fLinkDown, true);
1113 RTSEMEVENT hRecvEvt = pThis->hRecvEvt;
1114 pThis->hRecvEvt = NIL_RTSEMEVENT;
1115
1116 /*
1117 * Close the interface
1118 */
1119 if (pThis->hIf != INTNET_HANDLE_INVALID)
1120 {
1121 INTNETIFCLOSEREQ CloseReq;
1122 CloseReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
1123 CloseReq.Hdr.cbReq = sizeof(CloseReq);
1124 CloseReq.pSession = NIL_RTR0PTR;
1125 CloseReq.hIf = pThis->hIf;
1126 pThis->hIf = INTNET_HANDLE_INVALID;
1127 int rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_CLOSE, &CloseReq, sizeof(CloseReq));
1128 AssertRC(rc);
1129 }
1130
1131 /*
1132 * Wait for the thread to terminate.
1133 */
1134 if (hRecvEvt != NIL_RTSEMEVENT)
1135 RTSemEventSignal(hRecvEvt);
1136
1137 if (pThis->pXmitThread)
1138 {
1139 int rc = PDMR3ThreadDestroy(pThis->pXmitThread, NULL);
1140 AssertRC(rc);
1141 pThis->pXmitThread = NULL;
1142 }
1143
1144 if (pThis->hRecvThread != NIL_RTTHREAD)
1145 {
1146 int rc = RTThreadWait(pThis->hRecvThread, 5000, NULL);
1147 AssertRC(rc);
1148 pThis->hRecvThread = NIL_RTTHREAD;
1149 }
1150
1151
1152 /*
1153 * Destroy the semaphores, S/G cache and xmit lock.
1154 */
1155 if (hRecvEvt != NIL_RTSEMEVENT)
1156 RTSemEventDestroy(hRecvEvt);
1157
1158 if (pThis->hXmitEvt != NIL_SUPSEMEVENT)
1159 {
1160 SUPSemEventClose(pThis->pSupDrvSession, pThis->hXmitEvt);
1161 pThis->hXmitEvt = NIL_SUPSEMEVENT;
1162 }
1163
1164 RTMemCacheDestroy(pThis->hSgCache);
1165 pThis->hSgCache = NIL_RTMEMCACHE;
1166
1167 if (PDMCritSectIsInitialized(&pThis->XmitLock))
1168 PDMR3CritSectDelete(&pThis->XmitLock);
1169
1170 if (pThis->pBufR3)
1171 {
1172 /*
1173 * Deregister statistics in case we're being detached.
1174 */
1175 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->Recv.cStatFrames);
1176 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->Recv.cbStatWritten);
1177 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->Recv.cOverflows);
1178 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->Send.cStatFrames);
1179 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->Send.cbStatWritten);
1180 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->Send.cOverflows);
1181 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->cStatYieldsOk);
1182 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->cStatYieldsNok);
1183 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->cStatLost);
1184 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->cStatBadFrames);
1185 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReceivedGso);
1186 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatSentGso);
1187#ifdef VBOX_WITH_STATISTICS
1188 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReceive);
1189 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatTransmit);
1190#endif
1191 }
1192}
1193
1194
1195/**
1196 * Construct a TAP network transport driver instance.
1197 *
1198 * @copydoc FNPDMDRVCONSTRUCT
1199 */
1200static DECLCALLBACK(int) drvR3IntNetConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
1201{
1202 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
1203 bool f;
1204 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1205
1206 /*
1207 * Init the static parts.
1208 */
1209 pThis->pDrvInsR3 = pDrvIns;
1210 pThis->hIf = INTNET_HANDLE_INVALID;
1211 pThis->hRecvThread = NIL_RTTHREAD;
1212 pThis->hRecvEvt = NIL_RTSEMEVENT;
1213 pThis->pXmitThread = NULL;
1214 pThis->hXmitEvt = NIL_SUPSEMEVENT;
1215 pThis->pSupDrvSession = PDMDrvHlpGetSupDrvSession(pDrvIns);
1216 pThis->hSgCache = NIL_RTMEMCACHE;
1217 pThis->enmRecvState = RECVSTATE_SUSPENDED;
1218 pThis->fActivateEarlyDeactivateLate = false;
1219 /* IBase* */
1220 pDrvIns->IBase.pfnQueryInterface = drvR3IntNetIBase_QueryInterface;
1221 pThis->IBaseR0.pfnQueryInterface = drvR3IntNetIBaseR0_QueryInterface;
1222 pThis->IBaseRC.pfnQueryInterface = drvR3IntNetIBaseRC_QueryInterface;
1223 /* INetworkUp */
1224 pThis->INetworkUpR3.pfnBeginXmit = drvIntNetUp_BeginXmit;
1225 pThis->INetworkUpR3.pfnAllocBuf = drvIntNetUp_AllocBuf;
1226 pThis->INetworkUpR3.pfnFreeBuf = drvIntNetUp_FreeBuf;
1227 pThis->INetworkUpR3.pfnSendBuf = drvIntNetUp_SendBuf;
1228 pThis->INetworkUpR3.pfnEndXmit = drvIntNetUp_EndXmit;
1229 pThis->INetworkUpR3.pfnSetPromiscuousMode = drvIntNetUp_SetPromiscuousMode;
1230 pThis->INetworkUpR3.pfnNotifyLinkChanged = drvR3IntNetUp_NotifyLinkChanged;
1231
1232 /*
1233 * Validate the config.
1234 */
1235 if (!CFGMR3AreValuesValid(pCfg,
1236 "Network\0"
1237 "Trunk\0"
1238 "TrunkType\0"
1239 "ReceiveBufferSize\0"
1240 "SendBufferSize\0"
1241 "RestrictAccess\0"
1242 "SharedMacOnWire\0"
1243 "IgnoreAllPromisc\0"
1244 "QuietlyIgnoreAllPromisc\0"
1245 "IgnoreClientPromisc\0"
1246 "QuietlyIgnoreClientPromisc\0"
1247 "IgnoreTrunkWirePromisc\0"
1248 "QuietlyIgnoreTrunkWirePromisc\0"
1249 "IgnoreTrunkHostPromisc\0"
1250 "QuietlyIgnoreTrunkHostPromisc\0"
1251 "IsService\0"))
1252 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
1253
1254 /*
1255 * Check that no-one is attached to us.
1256 */
1257 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
1258 ("Configuration error: Not possible to attach anything to this driver!\n"),
1259 VERR_PDM_DRVINS_NO_ATTACH);
1260
1261 /*
1262 * Query the network port interface.
1263 */
1264 pThis->pIAboveNet = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKDOWN);
1265 if (!pThis->pIAboveNet)
1266 {
1267 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network port interface!\n"));
1268 return VERR_PDM_MISSING_INTERFACE_ABOVE;
1269 }
1270 pThis->pIAboveConfigR3 = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKCONFIG);
1271
1272 /*
1273 * Read the configuration.
1274 */
1275 INTNETOPENREQ OpenReq;
1276 memset(&OpenReq, 0, sizeof(OpenReq));
1277 OpenReq.Hdr.cbReq = sizeof(OpenReq);
1278 OpenReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
1279 OpenReq.pSession = NIL_RTR0PTR;
1280
1281 /** @cfgm{Network, string}
1282 * The name of the internal network to connect to.
1283 */
1284 int rc = CFGMR3QueryString(pCfg, "Network", OpenReq.szNetwork, sizeof(OpenReq.szNetwork));
1285 if (RT_FAILURE(rc))
1286 return PDMDRV_SET_ERROR(pDrvIns, rc,
1287 N_("Configuration error: Failed to get the \"Network\" value"));
1288 strcpy(pThis->szNetwork, OpenReq.szNetwork);
1289
1290 /** @cfgm{TrunkType, uint32_t, kIntNetTrunkType_None}
1291 * The trunk connection type see INTNETTRUNKTYPE.
1292 */
1293 uint32_t u32TrunkType;
1294 rc = CFGMR3QueryU32(pCfg, "TrunkType", &u32TrunkType);
1295 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1296 u32TrunkType = kIntNetTrunkType_None;
1297 else if (RT_FAILURE(rc))
1298 return PDMDRV_SET_ERROR(pDrvIns, rc,
1299 N_("Configuration error: Failed to get the \"TrunkType\" value"));
1300 OpenReq.enmTrunkType = (INTNETTRUNKTYPE)u32TrunkType;
1301
1302 /** @cfgm{Trunk, string, ""}
1303 * The name of the trunk connection.
1304 */
1305 rc = CFGMR3QueryString(pCfg, "Trunk", OpenReq.szTrunk, sizeof(OpenReq.szTrunk));
1306 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1307 OpenReq.szTrunk[0] = '\0';
1308 else if (RT_FAILURE(rc))
1309 return PDMDRV_SET_ERROR(pDrvIns, rc,
1310 N_("Configuration error: Failed to get the \"Trunk\" value"));
1311
1312 /** @cfgm{RestrictAccess, boolean, true}
1313 * Whether to restrict the access to the network or if it should be public. Everyone on
1314 * the computer can connect to a public network. Don't change this.
1315 */
1316 bool fRestrictAccess;
1317 rc = CFGMR3QueryBool(pCfg, "RestrictAccess", &fRestrictAccess);
1318 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1319 fRestrictAccess = true;
1320 else if (RT_FAILURE(rc))
1321 return PDMDRV_SET_ERROR(pDrvIns, rc,
1322 N_("Configuration error: Failed to get the \"RestrictAccess\" value"));
1323 OpenReq.fFlags = fRestrictAccess ? 0 : INTNET_OPEN_FLAGS_PUBLIC;
1324
1325 /** @cfgm{IgnoreAllPromisc, boolean, false}
1326 * When set all request for operating any interface or trunk in promiscuous
1327 * mode will be ignored. */
1328 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreAllPromisc", &f, false);
1329 if (RT_FAILURE(rc))
1330 return PDMDRV_SET_ERROR(pDrvIns, rc,
1331 N_("Configuration error: Failed to get the \"IgnoreAllPromisc\" value"));
1332 if (f)
1333 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC;
1334
1335 /** @cfgm{QuietlyIgnoreAllPromisc, boolean, false}
1336 * When set all request for operating any interface or trunk in promiscuous
1337 * mode will be ignored. This differs from IgnoreAllPromisc in that clients
1338 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
1339 rc = CFGMR3QueryBoolDef(pCfg, "QuietlyIgnoreAllPromisc", &f, false);
1340 if (RT_FAILURE(rc))
1341 return PDMDRV_SET_ERROR(pDrvIns, rc,
1342 N_("Configuration error: Failed to get the \"QuietlyIgnoreAllPromisc\" value"));
1343 if (f)
1344 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC;
1345
1346 /** @cfgm{IgnoreClientPromisc, boolean, false}
1347 * When set all request for operating any non-trunk interface in promiscuous
1348 * mode will be ignored. */
1349 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreClientPromisc", &f, false);
1350 if (RT_FAILURE(rc))
1351 return PDMDRV_SET_ERROR(pDrvIns, rc,
1352 N_("Configuration error: Failed to get the \"IgnoreClientPromisc\" value"));
1353 if (f)
1354 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC; /** @todo add special flag for this. */
1355
1356 /** @cfgm{QuietlyIgnoreClientPromisc, boolean, false}
1357 * When set all request for operating any non-trunk interface promiscuous mode
1358 * will be ignored. This differs from IgnoreClientPromisc in that clients won't
1359 * get VERR_INTNET_INCOMPATIBLE_FLAGS. */
1360 rc = CFGMR3QueryBoolDef(pCfg, "QuietlyIgnoreClientPromisc", &f, false);
1361 if (RT_FAILURE(rc))
1362 return PDMDRV_SET_ERROR(pDrvIns, rc,
1363 N_("Configuration error: Failed to get the \"QuietlyIgnoreClientPromisc\" value"));
1364 if (f)
1365 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC; /** @todo add special flag for this. */
1366
1367 /** @cfgm{IgnoreTrunkWirePromisc, boolean, false}
1368 * When set all request for operating the trunk-wire connection in promiscuous
1369 * mode will be ignored. */
1370 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreTrunkWirePromisc", &f, false);
1371 if (RT_FAILURE(rc))
1372 return PDMDRV_SET_ERROR(pDrvIns, rc,
1373 N_("Configuration error: Failed to get the \"IgnoreTrunkWirePromisc\" value"));
1374 if (f)
1375 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_WIRE;
1376
1377 /** @cfgm{QuietlyIgnoreTrunkWirePromisc, boolean, false}
1378 * When set all request for operating any trunk-wire connection promiscuous mode
1379 * will be ignored. This differs from IgnoreTrunkWirePromisc in that clients
1380 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
1381 rc = CFGMR3QueryBoolDef(pCfg, "QuietlyIgnoreTrunkWirePromisc", &f, false);
1382 if (RT_FAILURE(rc))
1383 return PDMDRV_SET_ERROR(pDrvIns, rc,
1384 N_("Configuration error: Failed to get the \"QuietlyIgnoreTrunkWirePromisc\" value"));
1385 if (f)
1386 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_WIRE;
1387
1388 /** @cfgm{IgnoreTrunkHostPromisc, boolean, false}
1389 * When set all request for operating the trunk-host connection in promiscuous
1390 * mode will be ignored. */
1391 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreTrunkHostPromisc", &f, false);
1392 if (RT_FAILURE(rc))
1393 return PDMDRV_SET_ERROR(pDrvIns, rc,
1394 N_("Configuration error: Failed to get the \"IgnoreTrunkHostPromisc\" value"));
1395 if (f)
1396 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_HOST;
1397
1398 /** @cfgm{QuietlyIgnoreTrunkHostPromisc, boolean, false}
1399 * When set all request for operating any trunk-host connection promiscuous mode
1400 * will be ignored. This differs from IgnoreTrunkHostPromisc in that clients
1401 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
1402 rc = CFGMR3QueryBoolDef(pCfg, "QuietlyIgnoreTrunkHostPromisc", &f, false);
1403 if (RT_FAILURE(rc))
1404 return PDMDRV_SET_ERROR(pDrvIns, rc,
1405 N_("Configuration error: Failed to get the \"QuietlyIgnoreTrunkHostPromisc\" value"));
1406 if (f)
1407 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_HOST;
1408
1409 /** @todo flags for not sending to the host and for setting the trunk-wire
1410 * connection in promiscuous mode. */
1411
1412
1413 /** @cfgm{SharedMacOnWire, boolean, false}
1414 * Whether to shared the MAC address of the host interface when using the wire. When
1415 * attaching to a wireless NIC this option is usally a requirement.
1416 */
1417 bool fSharedMacOnWire;
1418 rc = CFGMR3QueryBoolDef(pCfg, "SharedMacOnWire", &fSharedMacOnWire, false);
1419 if (RT_FAILURE(rc))
1420 return PDMDRV_SET_ERROR(pDrvIns, rc,
1421 N_("Configuration error: Failed to get the \"SharedMacOnWire\" value"));
1422 if (fSharedMacOnWire)
1423 OpenReq.fFlags |= INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE;
1424
1425 /** @cfgm{ReceiveBufferSize, uint32_t, 318 KB}
1426 * The size of the receive buffer.
1427 */
1428 rc = CFGMR3QueryU32(pCfg, "ReceiveBufferSize", &OpenReq.cbRecv);
1429 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1430 OpenReq.cbRecv = 318 * _1K ;
1431 else if (RT_FAILURE(rc))
1432 return PDMDRV_SET_ERROR(pDrvIns, rc,
1433 N_("Configuration error: Failed to get the \"ReceiveBufferSize\" value"));
1434
1435 /** @cfgm{SendBufferSize, uint32_t, 196 KB}
1436 * The size of the send (transmit) buffer.
1437 * This should be more than twice the size of the larges frame size because
1438 * the ring buffer is very simple and doesn't support splitting up frames
1439 * nor inserting padding. So, if this is too close to the frame size the
1440 * header will fragment the buffer such that the frame won't fit on either
1441 * side of it and the code will get very upset about it all.
1442 */
1443 rc = CFGMR3QueryU32(pCfg, "SendBufferSize", &OpenReq.cbSend);
1444 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1445 OpenReq.cbSend = RT_ALIGN_Z(VBOX_MAX_GSO_SIZE * 3, _1K);
1446 else if (RT_FAILURE(rc))
1447 return PDMDRV_SET_ERROR(pDrvIns, rc,
1448 N_("Configuration error: Failed to get the \"SendBufferSize\" value"));
1449 if (OpenReq.cbSend < 128)
1450 return PDMDRV_SET_ERROR(pDrvIns, rc,
1451 N_("Configuration error: The \"SendBufferSize\" value is too small"));
1452 if (OpenReq.cbSend < VBOX_MAX_GSO_SIZE * 4)
1453 LogRel(("DrvIntNet: Warning! SendBufferSize=%u, Recommended minimum size %u butes.\n", OpenReq.cbSend, VBOX_MAX_GSO_SIZE * 4));
1454
1455 /** @cfgm{IsService, boolean, true}
1456 * This alterns the way the thread is suspended and resumed. When it's being used by
1457 * a service such as LWIP/iSCSI it shouldn't suspend immediately like for a NIC.
1458 */
1459 rc = CFGMR3QueryBool(pCfg, "IsService", &pThis->fActivateEarlyDeactivateLate);
1460 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1461 pThis->fActivateEarlyDeactivateLate = false;
1462 else if (RT_FAILURE(rc))
1463 return PDMDRV_SET_ERROR(pDrvIns, rc,
1464 N_("Configuration error: Failed to get the \"IsService\" value"));
1465
1466 LogRel(("IntNet#%u: szNetwork={%s} enmTrunkType=%d szTrunk={%s} fFlags=%#x cbRecv=%u cbSend=%u\n",
1467 pDrvIns->iInstance, OpenReq.szNetwork, OpenReq.enmTrunkType, OpenReq.szTrunk, OpenReq.fFlags,
1468 OpenReq.cbRecv, OpenReq.cbSend));
1469
1470#ifdef RT_OS_DARWIN
1471 /* Temporary hack: attach to a network with the name 'if=en0' and you're hitting the wire. */
1472 if ( !OpenReq.szTrunk[0]
1473 && OpenReq.enmTrunkType == kIntNetTrunkType_None
1474 && !strncmp(pThis->szNetwork, "if=en", sizeof("if=en") - 1)
1475 && RT_C_IS_DIGIT(pThis->szNetwork[sizeof("if=en") - 1])
1476 && !pThis->szNetwork[sizeof("if=en")])
1477 {
1478 OpenReq.enmTrunkType = kIntNetTrunkType_NetFlt;
1479 strcpy(OpenReq.szTrunk, &pThis->szNetwork[sizeof("if=") - 1]);
1480 }
1481 /* Temporary hack: attach to a network with the name 'wif=en0' and you're on the air. */
1482 if ( !OpenReq.szTrunk[0]
1483 && OpenReq.enmTrunkType == kIntNetTrunkType_None
1484 && !strncmp(pThis->szNetwork, "wif=en", sizeof("wif=en") - 1)
1485 && RT_C_IS_DIGIT(pThis->szNetwork[sizeof("wif=en") - 1])
1486 && !pThis->szNetwork[sizeof("wif=en")])
1487 {
1488 OpenReq.enmTrunkType = kIntNetTrunkType_NetFlt;
1489 OpenReq.fFlags |= INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE;
1490 strcpy(OpenReq.szTrunk, &pThis->szNetwork[sizeof("wif=") - 1]);
1491 }
1492#endif /* DARWIN */
1493
1494 /*
1495 * Create the event semaphore, S/G cache and xmit critsect.
1496 */
1497 rc = RTSemEventCreate(&pThis->hRecvEvt);
1498 if (RT_FAILURE(rc))
1499 return rc;
1500 rc = RTMemCacheCreate(&pThis->hSgCache, sizeof(PDMSCATTERGATHER), 0, UINT32_MAX, NULL, NULL, pThis, 0);
1501 if (RT_FAILURE(rc))
1502 return rc;
1503 rc = PDMDrvHlpCritSectInit(pDrvIns, &pThis->XmitLock, RT_SRC_POS, "IntNetXmit");
1504 if (RT_FAILURE(rc))
1505 return rc;
1506
1507 /*
1508 * Create the interface.
1509 */
1510 OpenReq.hIf = INTNET_HANDLE_INVALID;
1511 rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_OPEN, &OpenReq, sizeof(OpenReq));
1512 if (RT_FAILURE(rc))
1513 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1514 N_("Failed to open/create the internal network '%s'"), pThis->szNetwork);
1515 AssertRelease(OpenReq.hIf != INTNET_HANDLE_INVALID);
1516 pThis->hIf = OpenReq.hIf;
1517 Log(("IntNet%d: hIf=%RX32 '%s'\n", pDrvIns->iInstance, pThis->hIf, pThis->szNetwork));
1518
1519 /*
1520 * Get default buffer.
1521 */
1522 INTNETIFGETBUFFERPTRSREQ GetBufferPtrsReq;
1523 GetBufferPtrsReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
1524 GetBufferPtrsReq.Hdr.cbReq = sizeof(GetBufferPtrsReq);
1525 GetBufferPtrsReq.pSession = NIL_RTR0PTR;
1526 GetBufferPtrsReq.hIf = pThis->hIf;
1527 GetBufferPtrsReq.pRing3Buf = NULL;
1528 GetBufferPtrsReq.pRing0Buf = NULL;
1529 rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS, &GetBufferPtrsReq, sizeof(GetBufferPtrsReq));
1530 if (RT_FAILURE(rc))
1531 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1532 N_("Failed to get ring-3 buffer for the newly created interface to '%s'"), pThis->szNetwork);
1533 AssertRelease(VALID_PTR(GetBufferPtrsReq.pRing3Buf));
1534 pThis->pBufR3 = GetBufferPtrsReq.pRing3Buf;
1535 pThis->pBufR0 = GetBufferPtrsReq.pRing0Buf;
1536
1537 /*
1538 * Register statistics.
1539 */
1540 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->Recv.cbStatWritten, "Bytes/Received", STAMUNIT_BYTES, "Number of received bytes.");
1541 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->Send.cbStatWritten, "Bytes/Sent", STAMUNIT_BYTES, "Number of sent bytes.");
1542 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->Recv.cOverflows, "Overflows/Recv", STAMUNIT_COUNT, "Number overflows.");
1543 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->Send.cOverflows, "Overflows/Sent", STAMUNIT_COUNT, "Number overflows.");
1544 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->Recv.cStatFrames, "Packets/Received", STAMUNIT_COUNT, "Number of received packets.");
1545 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->Send.cStatFrames, "Packets/Sent", STAMUNIT_COUNT, "Number of sent packets.");
1546 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->StatReceivedGso, "Packets/Received-Gso", STAMUNIT_COUNT, "The GSO portion of the received packets.");
1547 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->StatSentGso, "Packets/Sent-Gso", STAMUNIT_COUNT, "The GSO portion of the sent packets.");
1548 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->StatSentR0, "Packets/Sent-R0", STAMUNIT_COUNT, "The ring-0 portion of the sent packets.");
1549
1550 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->cStatLost, "Packets/Lost", STAMUNIT_COUNT, "Number of lost packets.");
1551 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->cStatYieldsNok, "YieldOk", STAMUNIT_COUNT, "Number of times yielding helped fix an overflow.");
1552 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->cStatYieldsOk, "YieldNok", STAMUNIT_COUNT, "Number of times yielding didn't help fix an overflow.");
1553 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->cStatBadFrames, "BadFrames", STAMUNIT_COUNT, "Number of bad frames seed by the consumers.");
1554#ifdef VBOX_WITH_STATISTICS
1555 PDMDrvHlpSTAMRegProfileAdv(pDrvIns, &pThis->StatReceive, "Receive", STAMUNIT_TICKS_PER_CALL, "Profiling packet receive runs.");
1556 PDMDrvHlpSTAMRegProfile(pDrvIns, &pThis->StatTransmit, "Transmit", STAMUNIT_TICKS_PER_CALL, "Profiling packet transmit runs.");
1557#endif
1558 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->StatXmitWakeupR0, "XmitWakeup-R0", STAMUNIT_COUNT, "Xmit thread wakeups from ring-0.");
1559 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->StatXmitWakeupR3, "XmitWakeup-R3", STAMUNIT_COUNT, "Xmit thread wakeups from ring-3.");
1560 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->StatXmitProcessRing, "XmitProcessRing", STAMUNIT_COUNT, "Time xmit thread was told to process the ring.");
1561
1562 /*
1563 * Create the async I/O threads.
1564 * Note! Using a PDM thread here doesn't fit with the IsService=true operation.
1565 */
1566 rc = RTThreadCreate(&pThis->hRecvThread, drvR3IntNetRecvThread, pThis, 0,
1567 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "INTNET-RECV");
1568 if (RT_FAILURE(rc))
1569 {
1570 AssertRC(rc);
1571 return rc;
1572 }
1573
1574 rc = SUPSemEventCreate(pThis->pSupDrvSession, &pThis->hXmitEvt);
1575 AssertRCReturn(rc, rc);
1576
1577 rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pXmitThread, pThis,
1578 drvR3IntNetXmitThread, drvR3IntNetXmitWakeUp, 0, RTTHREADTYPE_IO, "INTNET-XMIT");
1579 AssertRCReturn(rc, rc);
1580
1581#ifdef VBOX_WITH_DRVINTNET_IN_R0
1582 /*
1583 * Resolve the ring-0 context interface addresses.
1584 */
1585 rc = pDrvIns->pHlpR3->pfnLdrGetR0InterfaceSymbols(pDrvIns, &pThis->INetworkUpR0, sizeof(pThis->INetworkUpR0),
1586 "drvIntNetUp_", PDMINETWORKUP_SYM_LIST);
1587 AssertLogRelRCReturn(rc, rc);
1588#endif
1589
1590 /*
1591 * Activate data transmission as early as possible
1592 */
1593 if (pThis->fActivateEarlyDeactivateLate)
1594 {
1595 ASMAtomicXchgSize(&pThis->enmRecvState, RECVSTATE_RUNNING);
1596 RTSemEventSignal(pThis->hRecvEvt);
1597
1598 drvR3IntNetUpdateMacAddress(pThis);
1599 drvR3IntNetSetActive(pThis, true /* fActive */);
1600 }
1601
1602 return rc;
1603}
1604
1605
1606
1607/**
1608 * Internal networking transport driver registration record.
1609 */
1610const PDMDRVREG g_DrvIntNet =
1611{
1612 /* u32Version */
1613 PDM_DRVREG_VERSION,
1614 /* szName */
1615 "IntNet",
1616 /* szRCMod */
1617 "VBoxDDGC.rc",
1618 /* szR0Mod */
1619 "VBoxDDR0.r0",
1620 /* pszDescription */
1621 "Internal Networking Transport Driver",
1622 /* fFlags */
1623#ifdef VBOX_WITH_DRVINTNET_IN_R0
1624 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DRVREG_FLAGS_R0,
1625#else
1626 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1627#endif
1628 /* fClass. */
1629 PDM_DRVREG_CLASS_NETWORK,
1630 /* cMaxInstances */
1631 ~0,
1632 /* cbInstance */
1633 sizeof(DRVINTNET),
1634 /* pfnConstruct */
1635 drvR3IntNetConstruct,
1636 /* pfnDestruct */
1637 drvR3IntNetDestruct,
1638 /* pfnRelocate */
1639 drvR3IntNetRelocate,
1640 /* pfnIOCtl */
1641 NULL,
1642 /* pfnPowerOn */
1643 drvR3IntNetPowerOn,
1644 /* pfnReset */
1645 NULL,
1646 /* pfnSuspend */
1647 drvR3IntNetSuspend,
1648 /* pfnResume */
1649 drvR3IntNetResume,
1650 /* pfnAttach */
1651 NULL,
1652 /* pfnDetach */
1653 NULL,
1654 /* pfnPowerOff */
1655 drvR3IntNetPowerOff,
1656 /* pfnSoftReset */
1657 NULL,
1658 /* u32EndVersion */
1659 PDM_DRVREG_VERSION
1660};
1661
1662#endif /* IN_RING3 */
1663
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