VirtualBox

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

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

Devices/Network: Call pfnBeginXmit and pfnEndXmit.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 52.7 KB
Line 
1/* $Id: DrvIntNet.cpp 28275 2010-04-13 19:40:10Z 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/err.h>
34
35#include <VBox/param.h>
36#include <VBox/log.h>
37#include <iprt/asm.h>
38#include <iprt/assert.h>
39#include <iprt/ctype.h>
40#include <iprt/memcache.h>
41#include <iprt/net.h>
42#include <iprt/semaphore.h>
43#include <iprt/string.h>
44#include <iprt/time.h>
45#include <iprt/thread.h>
46#include <iprt/uuid.h>
47
48#include "../Builtins.h"
49
50
51/*******************************************************************************
52* Structures and Typedefs *
53*******************************************************************************/
54/**
55 * The state of the asynchronous thread.
56 */
57typedef enum ASYNCSTATE
58{
59 /** The thread is suspended. */
60 ASYNCSTATE_SUSPENDED = 1,
61 /** The thread is running. */
62 ASYNCSTATE_RUNNING,
63 /** The thread must (/has) terminate. */
64 ASYNCSTATE_TERMINATE,
65 /** The usual 32-bit type blowup. */
66 ASYNCSTATE_32BIT_HACK = 0x7fffffff
67} ASYNCSTATE;
68
69/**
70 * Internal networking driver instance data.
71 *
72 * @implements PDMINETWORKUP
73 */
74typedef struct DRVINTNET
75{
76 /** The network interface. */
77 PDMINETWORKUP INetworkUpR3;
78 /** The network interface. */
79 R3PTRTYPE(PPDMINETWORKDOWN) pIAboveNet;
80 /** The network config interface.
81 * Can (in theory at least) be NULL. */
82 R3PTRTYPE(PPDMINETWORKCONFIG) pIAboveConfigR3;
83 /** Pointer to the driver instance. */
84 PPDMDRVINSR3 pDrvInsR3;
85 /** Pointer to the communication buffer. */
86 R3PTRTYPE(PINTNETBUF) pBufR3;
87 /** Interface handle. */
88 INTNETIFHANDLE hIf;
89
90 /** The thread state. */
91 ASYNCSTATE volatile enmState;
92 /** Reader thread. */
93 RTTHREAD Thread;
94 /** Event semaphore the Thread waits on while the VM is suspended. */
95 RTSEMEVENT hEvtSuspended;
96 /** Scatter/gather descriptor cache. */
97 RTMEMCACHE hSgCache;
98 /** Set if the link is down.
99 * When the link is down all incoming packets will be dropped. */
100 bool volatile fLinkDown;
101 /** Set if data transmission should start immediately and deactivate
102 * as late as possible. */
103 bool fActivateEarlyDeactivateLate;
104 /** Padding. */
105 bool afReserved[2];
106 /** The network name. */
107 char szNetwork[INTNET_MAX_NETWORK_NAME];
108
109 /** Base interface for ring-0. */
110 PDMIBASER0 IBaseR0;
111 /** Base interface for ring-0. */
112 PDMIBASERC IBaseRC;
113
114 /** The transmit lock. */
115 PDMCRITSECT XmitLock;
116
117#ifdef LOG_ENABLED
118 /** The nano ts of the last transfer. */
119 uint64_t u64LastTransferTS;
120 /** The nano ts of the last receive. */
121 uint64_t u64LastReceiveTS;
122#endif
123#ifdef VBOX_WITH_STATISTICS
124 /** Profiling packet transmit runs. */
125 STAMPROFILE StatTransmit;
126 /** Profiling packet receive runs. */
127 STAMPROFILEADV StatReceive;
128#endif /* VBOX_WITH_STATISTICS */
129 /** Number of GSO packets sent. */
130 STAMCOUNTER StatSentGso;
131 /** Number of GSO packets recevied. */
132 STAMCOUNTER StatReceivedGso;
133} DRVINTNET;
134/** Pointer to instance data of the internal networking driver. */
135typedef DRVINTNET *PDRVINTNET;
136
137
138#ifdef IN_RING3
139
140
141/**
142 * Updates the MAC address on the kernel side.
143 *
144 * @returns VBox status code.
145 * @param pThis The driver instance.
146 */
147static int drvR3IntNetUpdateMacAddress(PDRVINTNET pThis)
148{
149 if (!pThis->pIAboveConfigR3)
150 return VINF_SUCCESS;
151
152 INTNETIFSETMACADDRESSREQ SetMacAddressReq;
153 SetMacAddressReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
154 SetMacAddressReq.Hdr.cbReq = sizeof(SetMacAddressReq);
155 SetMacAddressReq.pSession = NIL_RTR0PTR;
156 SetMacAddressReq.hIf = pThis->hIf;
157 int rc = pThis->pIAboveConfigR3->pfnGetMac(pThis->pIAboveConfigR3, &SetMacAddressReq.Mac);
158 if (RT_SUCCESS(rc))
159 rc = PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SET_MAC_ADDRESS,
160 &SetMacAddressReq, sizeof(SetMacAddressReq));
161
162 Log(("drvR3IntNetUpdateMacAddress: %.*Rhxs rc=%Rrc\n", sizeof(SetMacAddressReq.Mac), &SetMacAddressReq.Mac, rc));
163 return rc;
164}
165
166
167/**
168 * Sets the kernel interface active or inactive.
169 *
170 * Worker for poweron, poweroff, suspend and resume.
171 *
172 * @returns VBox status code.
173 * @param pThis The driver instance.
174 * @param fActive The new state.
175 */
176static int drvR3IntNetSetActive(PDRVINTNET pThis, bool fActive)
177{
178 if (!pThis->pIAboveConfigR3)
179 return VINF_SUCCESS;
180
181 INTNETIFSETACTIVEREQ SetActiveReq;
182 SetActiveReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
183 SetActiveReq.Hdr.cbReq = sizeof(SetActiveReq);
184 SetActiveReq.pSession = NIL_RTR0PTR;
185 SetActiveReq.hIf = pThis->hIf;
186 SetActiveReq.fActive = fActive;
187 int rc = PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SET_ACTIVE,
188 &SetActiveReq, sizeof(SetActiveReq));
189
190 Log(("drvR3IntNetSetActive: fActive=%d rc=%Rrc\n", fActive, rc));
191 AssertRC(rc);
192 return rc;
193}
194
195
196
197/* -=-=-=-=- PDMINETWORKUP -=-=-=-=- */
198
199/**
200 * @interface_method_impl{PDMINETWORKUP,pfnBeginXmit}
201 */
202static DECLCALLBACK(int) drvR3IntNetUp_BeginXmit(PPDMINETWORKUP pInterface, bool fOnWorkerThread)
203{
204 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, INetworkUpR3);
205 int rc = PDMCritSectTryEnter(&pThis->XmitLock);
206 if (RT_UNLIKELY(rc == VERR_SEM_BUSY))
207 rc = VERR_TRY_AGAIN;
208 return rc;
209}
210
211
212/**
213 * @interface_method_impl{PDMINETWORKUP,pfnAllocBuf}
214 */
215static DECLCALLBACK(int) drvR3IntNetUp_AllocBuf(PPDMINETWORKUP pInterface, size_t cbMin,
216 PCPDMNETWORKGSO pGso, PPPDMSCATTERGATHER ppSgBuf)
217{
218 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, INetworkUpR3);
219 int rc = VINF_SUCCESS;
220 Assert(cbMin < UINT32_MAX / 2);
221 Assert(PDMCritSectIsOwner(&pThis->XmitLock));
222
223 /*
224 * Allocate a S/G buffer.
225 */
226 PPDMSCATTERGATHER pSgBuf = (PPDMSCATTERGATHER)RTMemCacheAlloc(pThis->hSgCache);
227 if (pSgBuf)
228 {
229 PINTNETHDR pHdr;
230 if (pGso)
231 rc = INTNETRingAllocateGsoFrame(&pThis->pBufR3->Send, (uint32_t)cbMin, pGso,
232 &pHdr, &pSgBuf->aSegs[0].pvSeg);
233 else
234 rc = INTNETRingAllocateFrame(&pThis->pBufR3->Send, (uint32_t)cbMin,
235 &pHdr, &pSgBuf->aSegs[0].pvSeg);
236
237#if 1 /** @todo implement VERR_TRY_AGAIN once this moves to EMT. */
238 if ( RT_FAILURE(rc)
239 && pThis->pBufR3->cbSend >= cbMin * 2 + sizeof(INTNETHDR))
240 {
241 INTNETIFSENDREQ SendReq;
242 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
243 SendReq.Hdr.cbReq = sizeof(SendReq);
244 SendReq.pSession = NIL_RTR0PTR;
245 SendReq.hIf = pThis->hIf;
246 PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SEND, &SendReq, sizeof(SendReq));
247
248 if (pGso)
249 rc = INTNETRingAllocateGsoFrame(&pThis->pBufR3->Send, (uint32_t)cbMin, pGso,
250 &pHdr, &pSgBuf->aSegs[0].pvSeg);
251 else
252 rc = INTNETRingAllocateFrame(&pThis->pBufR3->Send, (uint32_t)cbMin,
253 &pHdr, &pSgBuf->aSegs[0].pvSeg);
254 }
255#endif
256 if (RT_SUCCESS(rc))
257 {
258 pSgBuf->fFlags = PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1;
259 pSgBuf->cbUsed = 0;
260 pSgBuf->cbAvailable = cbMin;
261 pSgBuf->pvAllocator = pHdr;
262 pSgBuf->pvUser = pGso ? (PPDMNETWORKGSO)pSgBuf->aSegs[0].pvSeg - 1 : NULL;
263 pSgBuf->cSegs = 1;
264 pSgBuf->aSegs[0].cbSeg = cbMin;
265
266 *ppSgBuf = pSgBuf;
267 return VINF_SUCCESS;
268 }
269
270 /*
271 * Arm the try again stuff.
272 */
273/** @todo if (pThis->pBufR3->cbSend >= cbMin * 2 + sizeof(INTNETHDR))
274 rc = VERR_TRY_AGAIN;
275 else */
276 rc = VERR_NO_MEMORY;
277
278 RTMemCacheFree(pThis->hSgCache, pSgBuf);
279 }
280 else
281 rc = VERR_NO_MEMORY;
282 /** @todo implement VERR_TRY_AGAIN */
283 return rc;
284}
285
286
287/**
288 * @interface_method_impl{PDMINETWORKUP,pfnFreeBuf}
289 */
290static DECLCALLBACK(int) drvR3IntNetUp_FreeBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf)
291{
292 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, INetworkUpR3);
293 PINTNETHDR pHdr = (PINTNETHDR)pSgBuf->pvAllocator;
294 Assert(pSgBuf->fFlags == (PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1));
295 Assert(pSgBuf->cbUsed <= pSgBuf->cbAvailable);
296 Assert( pHdr->u16Type == INTNETHDR_TYPE_FRAME
297 || pHdr->u16Type == INTNETHDR_TYPE_GSO);
298 Assert(PDMCritSectIsOwner(&pThis->XmitLock));
299
300 /** @todo LATER: try unalloc the frame. */
301 pHdr->u16Type = INTNETHDR_TYPE_PADDING;
302 INTNETRingCommitFrame(&pThis->pBufR3->Send, pHdr);
303
304 RTMemCacheFree(pThis->hSgCache, pSgBuf);
305 return VINF_SUCCESS;
306}
307
308
309/**
310 * @interface_method_impl{PDMINETWORKUP,pfnSendBuf}
311 */
312static DECLCALLBACK(int) drvR3IntNetUp_SendBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)
313{
314 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, INetworkUpR3);
315 STAM_PROFILE_START(&pThis->StatTransmit, a);
316
317 AssertPtr(pSgBuf);
318 Assert(pSgBuf->fFlags == (PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1));
319 Assert(pSgBuf->cbUsed <= pSgBuf->cbAvailable);
320 Assert(PDMCritSectIsOwner(&pThis->XmitLock));
321
322 if (pSgBuf->pvUser)
323 STAM_COUNTER_INC(&pThis->StatSentGso);
324
325 /*
326 * Commit the frame and push it thru the switch.
327 */
328 PINTNETHDR pHdr = (PINTNETHDR)pSgBuf->pvAllocator;
329 INTNETRingCommitFrameEx(&pThis->pBufR3->Send, pHdr, pSgBuf->cbUsed);
330
331 INTNETIFSENDREQ SendReq;
332 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
333 SendReq.Hdr.cbReq = sizeof(SendReq);
334 SendReq.pSession = NIL_RTR0PTR;
335 SendReq.hIf = pThis->hIf;
336 PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SEND, &SendReq, sizeof(SendReq));
337
338 RTMemCacheFree(pThis->hSgCache, pSgBuf);
339
340 STAM_PROFILE_STOP(&pThis->StatTransmit, a);
341 return VINF_SUCCESS;
342}
343
344
345/**
346 * @interface_method_impl{PDMINETWORKUP,pfnEndXmit}
347 */
348static DECLCALLBACK(void) drvR3IntNetUp_EndXmit(PPDMINETWORKUP pInterface)
349{
350 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, INetworkUpR3);
351 PDMCritSectLeave(&pThis->XmitLock);
352}
353
354
355/**
356 * @interface_method_impl{PDMINETWORKUP,pfnSetPromiscuousMode}
357 */
358static DECLCALLBACK(void) drvR3IntNetUp_SetPromiscuousMode(PPDMINETWORKUP pInterface, bool fPromiscuous)
359{
360 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, INetworkUpR3);
361 INTNETIFSETPROMISCUOUSMODEREQ Req;
362 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
363 Req.Hdr.cbReq = sizeof(Req);
364 Req.pSession = NIL_RTR0PTR;
365 Req.hIf = pThis->hIf;
366 Req.fPromiscuous = fPromiscuous;
367 int rc = PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE, &Req, sizeof(Req));
368 LogFlow(("drvR3IntNetUp_SetPromiscuousMode: fPromiscuous=%RTbool\n", fPromiscuous));
369 AssertRC(rc);
370}
371
372
373/**
374 * @interface_method_impl{PDMINETWORKUP,pfnNotifyLinkChanged}
375 */
376static DECLCALLBACK(void) drvR3IntNetUp_NotifyLinkChanged(PPDMINETWORKUP pInterface, PDMNETWORKLINKSTATE enmLinkState)
377{
378 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, INetworkUpR3);
379 bool fLinkDown;
380 switch (enmLinkState)
381 {
382 case PDMNETWORKLINKSTATE_DOWN:
383 case PDMNETWORKLINKSTATE_DOWN_RESUME:
384 fLinkDown = true;
385 break;
386 default:
387 AssertMsgFailed(("enmLinkState=%d\n", enmLinkState));
388 case PDMNETWORKLINKSTATE_UP:
389 fLinkDown = false;
390 break;
391 }
392 LogFlow(("drvR3IntNetUp_NotifyLinkChanged: enmLinkState=%d %d->%d\n", enmLinkState, pThis->fLinkDown, fLinkDown));
393 ASMAtomicXchgSize(&pThis->fLinkDown, fLinkDown);
394}
395
396
397/**
398 * Wait for space to become available up the driver/device chain.
399 *
400 * @returns VINF_SUCCESS if space is available.
401 * @returns VERR_STATE_CHANGED if the state changed.
402 * @returns VBox status code on other errors.
403 * @param pThis Pointer to the instance data.
404 */
405static int drvR3IntNetAsyncIoWaitForSpace(PDRVINTNET pThis)
406{
407 LogFlow(("drvR3IntNetAsyncIoWaitForSpace:\n"));
408 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
409 int rc = pThis->pIAboveNet->pfnWaitReceiveAvail(pThis->pIAboveNet, RT_INDEFINITE_WAIT);
410 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
411 LogFlow(("drvR3IntNetAsyncIoWaitForSpace: returns %Rrc\n", rc));
412 return rc;
413}
414
415
416/**
417 * Executes async I/O (RUNNING mode).
418 *
419 * @returns VERR_STATE_CHANGED if the state changed.
420 * @returns Appropriate VBox status code (error) on fatal error.
421 * @param pThis The driver instance data.
422 */
423static int drvR3IntNetAsyncIoRun(PDRVINTNET pThis)
424{
425 PPDMDRVINS pDrvIns = pThis->pDrvInsR3;
426 LogFlow(("drvR3IntNetAsyncIoRun: pThis=%p\n", pThis));
427
428 /*
429 * The running loop - processing received data and waiting for more to arrive.
430 */
431 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
432 PINTNETBUF pBuf = pThis->pBufR3;
433 PINTNETRINGBUF pRingBuf = &pBuf->Recv;
434 for (;;)
435 {
436 /*
437 * Process the receive buffer.
438 */
439 PINTNETHDR pHdr;
440 while ((pHdr = INTNETRingGetNextFrameToRead(pRingBuf)) != NULL)
441 {
442 /*
443 * Check the state and then inspect the packet.
444 */
445 if (pThis->enmState != ASYNCSTATE_RUNNING)
446 {
447 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
448 LogFlow(("drvR3IntNetAsyncIoRun: returns VERR_STATE_CHANGED (state changed - #0)\n"));
449 return VERR_STATE_CHANGED;
450 }
451
452 Log2(("pHdr=%p offRead=%#x: %.8Rhxs\n", pHdr, pRingBuf->offReadX, pHdr));
453 uint16_t u16Type = pHdr->u16Type;
454 if ( ( u16Type == INTNETHDR_TYPE_FRAME
455 || u16Type == INTNETHDR_TYPE_GSO)
456 && !pThis->fLinkDown)
457 {
458 /*
459 * Check if there is room for the frame and pass it up.
460 */
461 size_t cbFrame = pHdr->cbFrame;
462 int rc = pThis->pIAboveNet->pfnWaitReceiveAvail(pThis->pIAboveNet, 0);
463 if (rc == VINF_SUCCESS)
464 {
465 if (u16Type == INTNETHDR_TYPE_FRAME)
466 {
467 /*
468 * Normal frame.
469 */
470#ifdef LOG_ENABLED
471 if (LogIsEnabled())
472 {
473 uint64_t u64Now = RTTimeProgramNanoTS();
474 LogFlow(("drvR3IntNetAsyncIoRun: %-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
475 cbFrame, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS));
476 pThis->u64LastReceiveTS = u64Now;
477 Log2(("drvR3IntNetAsyncIoRun: cbFrame=%#x\n"
478 "%.*Rhxd\n",
479 cbFrame, cbFrame, INTNETHdrGetFramePtr(pHdr, pBuf)));
480 }
481#endif
482 rc = pThis->pIAboveNet->pfnReceive(pThis->pIAboveNet, INTNETHdrGetFramePtr(pHdr, pBuf), cbFrame);
483 AssertRC(rc);
484
485 /* skip to the next frame. */
486 INTNETRingSkipFrame(pRingBuf);
487 }
488 else
489 {
490 /*
491 * Generic segment offload frame (INTNETHDR_TYPE_GSO).
492 *
493 * This is where we do the offloading since we don't
494 * emulate any NICs with large receive offload (LRO).
495 */
496 STAM_COUNTER_INC(&pThis->StatReceivedGso);
497 PCPDMNETWORKGSO pGso = INTNETHdrGetGsoContext(pHdr, pBuf);
498 if (PDMNetGsoIsValid(pGso, cbFrame, cbFrame - sizeof(PDMNETWORKGSO)))
499 {
500 cbFrame -= sizeof(PDMNETWORKGSO);
501
502 uint8_t abHdrScratch[256];
503 uint32_t const cSegs = PDMNetGsoCalcSegmentCount(pGso, cbFrame);
504#ifdef LOG_ENABLED
505 if (LogIsEnabled())
506 {
507 uint64_t u64Now = RTTimeProgramNanoTS();
508 LogFlow(("drvR3IntNetAsyncIoRun: %-4d bytes at %llu ns deltas: r=%llu t=%llu; GSO - %u segs\n",
509 cbFrame, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS, cSegs));
510 pThis->u64LastReceiveTS = u64Now;
511 Log2(("drvR3IntNetAsyncIoRun: cbFrame=%#x type=%d cbHdrs=%#x Hdr1=%#x Hdr2=%#x MMS=%#x\n"
512 "%.*Rhxd\n",
513 cbFrame, pGso->u8Type, pGso->cbHdrs, pGso->offHdr1, pGso->offHdr2, pGso->cbMaxSeg,
514 cbFrame - sizeof(*pGso), pGso + 1));
515 }
516#endif
517 for (size_t iSeg = 0; iSeg < cSegs; iSeg++)
518 {
519 uint32_t cbSegFrame;
520 void *pvSegFrame = PDMNetGsoCarveSegmentQD(pGso, (uint8_t *)(pGso + 1), cbFrame, abHdrScratch,
521 iSeg, cSegs, &cbSegFrame);
522 rc = drvR3IntNetAsyncIoWaitForSpace(pThis);
523 if (RT_FAILURE(rc))
524 {
525 Log(("drvR3IntNetAsyncIoRun: drvR3IntNetAsyncIoWaitForSpace -> %Rrc; iSeg=%u cSegs=%u\n", iSeg, cSegs));
526 break; /* we drop the rest. */
527 }
528 rc = pThis->pIAboveNet->pfnReceive(pThis->pIAboveNet, pvSegFrame, cbSegFrame);
529 AssertRC(rc);
530 }
531 }
532 else
533 {
534 AssertMsgFailed(("cbFrame=%#x type=%d cbHdrs=%#x Hdr1=%#x Hdr2=%#x MMS=%#x\n",
535 cbFrame, pGso->u8Type, pGso->cbHdrs, pGso->offHdr1, pGso->offHdr2, pGso->cbMaxSeg));
536 STAM_REL_COUNTER_INC(&pBuf->cStatBadFrames);
537 }
538
539 INTNETRingSkipFrame(pRingBuf);
540 }
541 }
542 else
543 {
544 /*
545 * Wait for sufficient space to become available and then retry.
546 */
547 rc = drvR3IntNetAsyncIoWaitForSpace(pThis);
548 if (RT_FAILURE(rc))
549 {
550 if (rc == VERR_INTERRUPTED)
551 {
552 /*
553 * NIC is going down, likely because the VM is being reset. Skip the frame.
554 */
555 AssertMsg(INETNETIsValidFrameType(pHdr->u16Type), ("Unknown frame type %RX16! offRead=%#x\n", pHdr->u16Type, pRingBuf->offReadX));
556 INTNETRingSkipFrame(pRingBuf);
557 }
558 else
559 {
560 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
561 LogFlow(("drvR3IntNetAsyncIoRun: returns %Rrc (wait-for-space)\n", rc));
562 return rc;
563 }
564 }
565 }
566 }
567 else
568 {
569 /*
570 * Link down or unknown frame - skip to the next frame.
571 */
572 AssertMsg(INETNETIsValidFrameType(pHdr->u16Type), ("Unknown frame type %RX16! offRead=%#x\n", pHdr->u16Type, pRingBuf->offReadX));
573 INTNETRingSkipFrame(pRingBuf);
574 STAM_REL_COUNTER_INC(&pBuf->cStatBadFrames);
575 }
576 } /* while more received data */
577
578 /*
579 * Wait for data, checking the state before we block.
580 */
581 if (pThis->enmState != ASYNCSTATE_RUNNING)
582 {
583 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
584 LogFlow(("drvR3IntNetAsyncIoRun: returns VINF_SUCCESS (state changed - #1)\n"));
585 return VERR_STATE_CHANGED;
586 }
587 INTNETIFWAITREQ WaitReq;
588 WaitReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
589 WaitReq.Hdr.cbReq = sizeof(WaitReq);
590 WaitReq.pSession = NIL_RTR0PTR;
591 WaitReq.hIf = pThis->hIf;
592 WaitReq.cMillies = 30000; /* 30s - don't wait forever, timeout now and then. */
593 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
594 int rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_WAIT, &WaitReq, sizeof(WaitReq));
595 if ( RT_FAILURE(rc)
596 && rc != VERR_TIMEOUT
597 && rc != VERR_INTERRUPTED)
598 {
599 LogFlow(("drvR3IntNetAsyncIoRun: returns %Rrc\n", rc));
600 return rc;
601 }
602 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
603 }
604}
605
606
607/**
608 * Asynchronous I/O thread for handling receive.
609 *
610 * @returns VINF_SUCCESS (ignored).
611 * @param ThreadSelf Thread handle.
612 * @param pvUser Pointer to a DRVINTNET structure.
613 */
614static DECLCALLBACK(int) drvR3IntNetAsyncIoThread(RTTHREAD ThreadSelf, void *pvUser)
615{
616 PDRVINTNET pThis = (PDRVINTNET)pvUser;
617 LogFlow(("drvR3IntNetAsyncIoThread: pThis=%p\n", pThis));
618 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
619
620 /*
621 * The main loop - acting on state.
622 */
623 for (;;)
624 {
625 ASYNCSTATE enmState = pThis->enmState;
626 switch (enmState)
627 {
628 case ASYNCSTATE_SUSPENDED:
629 {
630 int rc = RTSemEventWait(pThis->hEvtSuspended, 30000);
631 if ( RT_FAILURE(rc)
632 && rc != VERR_TIMEOUT)
633 {
634 LogFlow(("drvR3IntNetAsyncIoThread: returns %Rrc\n", rc));
635 return rc;
636 }
637 break;
638 }
639
640 case ASYNCSTATE_RUNNING:
641 {
642 int rc = drvR3IntNetAsyncIoRun(pThis);
643 if ( rc != VERR_STATE_CHANGED
644 && RT_FAILURE(rc))
645 {
646 LogFlow(("drvR3IntNetAsyncIoThread: returns %Rrc\n", rc));
647 return rc;
648 }
649 break;
650 }
651
652 default:
653 AssertMsgFailed(("Invalid state %d\n", enmState));
654 case ASYNCSTATE_TERMINATE:
655 LogFlow(("drvR3IntNetAsyncIoThread: returns VINF_SUCCESS\n"));
656 return VINF_SUCCESS;
657 }
658 }
659}
660
661/* -=-=-=-=- PDMIBASERC -=-=-=-=- */
662
663/**
664 * @interface_method_impl{PDMIBASERC,pfnQueryInterface}
665 */
666static DECLCALLBACK(RTRCPTR) drvR3IntNetIBaseRC_QueryInterface(PPDMIBASERC pInterface, const char *pszIID)
667{
668 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, IBaseRC);
669
670 PDMIBASERC_RETURN_INTERFACE(pThis->pDrvInsR3, pszIID, PDMIBASERC, &pThis->IBaseRC);
671 return NIL_RTRCPTR;
672}
673
674/* -=-=-=-=- PDMIBASER0 -=-=-=-=- */
675
676/**
677 * @interface_method_impl{PDMIBASER0,pfnQueryInterface}
678 */
679static DECLCALLBACK(RTR0PTR) drvR3IntNetIBaseR0_QueryInterface(PPDMIBASER0 pInterface, const char *pszIID)
680{
681 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, IBaseR0);
682
683 PDMIBASER0_RETURN_INTERFACE(pThis->pDrvInsR3, pszIID, PDMIBASER0, &pThis->IBaseR0);
684 return NIL_RTR0PTR;
685}
686
687/* -=-=-=-=- PDMIBASE -=-=-=-=- */
688
689/**
690 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
691 */
692static DECLCALLBACK(void *) drvR3IntNetIBase_QueryInterface(PPDMIBASE pInterface, const char *pszIID)
693{
694 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
695 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
696
697 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
698 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASER0, &pThis->IBaseR0);
699 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASERC, &pThis->IBaseRC);
700 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKUP, &pThis->INetworkUpR3);
701 return NULL;
702}
703
704/* -=-=-=-=- PDMDRVREG -=-=-=-=- */
705
706/**
707 * Power Off notification.
708 *
709 * @param pDrvIns The driver instance.
710 */
711static DECLCALLBACK(void) drvR3IntNetPowerOff(PPDMDRVINS pDrvIns)
712{
713 LogFlow(("drvR3IntNetPowerOff\n"));
714 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
715 if (!pThis->fActivateEarlyDeactivateLate)
716 {
717 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_SUSPENDED);
718 drvR3IntNetSetActive(pThis, false /* fActive */);
719 }
720}
721
722
723/**
724 * drvR3IntNetResume helper.
725 */
726static int drvR3IntNetResumeSend(PDRVINTNET pThis, const void *pvBuf, size_t cb)
727{
728 /*
729 * Add the frame to the send buffer and push it onto the network.
730 */
731 int rc = INTNETRingWriteFrame(&pThis->pBufR3->Send, pvBuf, (uint32_t)cb);
732 if ( rc == VERR_BUFFER_OVERFLOW
733 && pThis->pBufR3->cbSend < cb)
734 {
735 INTNETIFSENDREQ SendReq;
736 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
737 SendReq.Hdr.cbReq = sizeof(SendReq);
738 SendReq.pSession = NIL_RTR0PTR;
739 SendReq.hIf = pThis->hIf;
740 PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SEND, &SendReq, sizeof(SendReq));
741
742 rc = INTNETRingWriteFrame(&pThis->pBufR3->Send, pvBuf, (uint32_t)cb);
743 }
744
745 if (RT_SUCCESS(rc))
746 {
747 INTNETIFSENDREQ SendReq;
748 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
749 SendReq.Hdr.cbReq = sizeof(SendReq);
750 SendReq.pSession = NIL_RTR0PTR;
751 SendReq.hIf = pThis->hIf;
752 rc = PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SEND, &SendReq, sizeof(SendReq));
753 }
754
755 AssertRC(rc);
756 return rc;
757}
758
759
760/**
761 * Resume notification.
762 *
763 * @param pDrvIns The driver instance.
764 */
765static DECLCALLBACK(void) drvR3IntNetResume(PPDMDRVINS pDrvIns)
766{
767 LogFlow(("drvR3IntNetPowerResume\n"));
768 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
769 if (!pThis->fActivateEarlyDeactivateLate)
770 {
771 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
772 RTSemEventSignal(pThis->hEvtSuspended);
773 drvR3IntNetUpdateMacAddress(pThis); /* (could be a state restore) */
774 drvR3IntNetSetActive(pThis, true /* fActive */);
775 }
776 if ( PDMDrvHlpVMTeleportedAndNotFullyResumedYet(pDrvIns)
777 && pThis->pIAboveConfigR3)
778 {
779 /*
780 * We've just been teleported and need to drop a hint to the switch
781 * since we're likely to have changed to a different port. We just
782 * push out some ethernet frame that doesn't mean anything to anyone.
783 * For this purpose ethertype 0x801e was chosen since it was registered
784 * to Sun (dunno what it is/was used for though).
785 */
786 union
787 {
788 RTNETETHERHDR Hdr;
789 uint8_t ab[128];
790 } Frame;
791 RT_ZERO(Frame);
792 Frame.Hdr.DstMac.au16[0] = 0xffff;
793 Frame.Hdr.DstMac.au16[1] = 0xffff;
794 Frame.Hdr.DstMac.au16[2] = 0xffff;
795 Frame.Hdr.EtherType = RT_H2BE_U16_C(0x801e);
796 int rc = pThis->pIAboveConfigR3->pfnGetMac(pThis->pIAboveConfigR3, &Frame.Hdr.SrcMac);
797 if (RT_SUCCESS(rc))
798 rc = drvR3IntNetResumeSend(pThis, &Frame, sizeof(Frame));
799 if (RT_FAILURE(rc))
800 LogRel(("IntNet#%u: Sending dummy frame failed: %Rrc\n", pDrvIns->iInstance, rc));
801 }
802}
803
804
805/**
806 * Suspend notification.
807 *
808 * @param pDrvIns The driver instance.
809 */
810static DECLCALLBACK(void) drvR3IntNetSuspend(PPDMDRVINS pDrvIns)
811{
812 LogFlow(("drvR3IntNetPowerSuspend\n"));
813 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
814 if (!pThis->fActivateEarlyDeactivateLate)
815 {
816 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_SUSPENDED);
817 drvR3IntNetSetActive(pThis, false /* fActive */);
818 }
819}
820
821
822/**
823 * Power On notification.
824 *
825 * @param pDrvIns The driver instance.
826 */
827static DECLCALLBACK(void) drvR3IntNetPowerOn(PPDMDRVINS pDrvIns)
828{
829 LogFlow(("drvR3IntNetPowerOn\n"));
830 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
831 if (!pThis->fActivateEarlyDeactivateLate)
832 {
833 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
834 RTSemEventSignal(pThis->hEvtSuspended);
835 drvR3IntNetUpdateMacAddress(pThis);
836 drvR3IntNetSetActive(pThis, true /* fActive */);
837 }
838}
839
840
841/**
842 * @interface_method_impl{PDMDRVREG,pfnRelocate}
843 */
844static DECLCALLBACK(void) drvR3IntNetRelocate(PPDMDRVINS pDrvIns, RTGCINTPTR offDelta)
845{
846 /* nothing to do here yet */
847}
848
849
850/**
851 * Destruct a driver instance.
852 *
853 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
854 * resources can be freed correctly.
855 *
856 * @param pDrvIns The driver instance data.
857 */
858static DECLCALLBACK(void) drvR3IntNetDestruct(PPDMDRVINS pDrvIns)
859{
860 LogFlow(("drvR3IntNetDestruct\n"));
861 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
862 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
863
864 /*
865 * Indicate to the thread that it's time to quit.
866 */
867 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_TERMINATE);
868 ASMAtomicXchgSize(&pThis->fLinkDown, true);
869 RTSEMEVENT hEvtSuspended = pThis->hEvtSuspended;
870 pThis->hEvtSuspended = NIL_RTSEMEVENT;
871
872 /*
873 * Close the interface
874 */
875 if (pThis->hIf != INTNET_HANDLE_INVALID)
876 {
877 INTNETIFCLOSEREQ CloseReq;
878 CloseReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
879 CloseReq.Hdr.cbReq = sizeof(CloseReq);
880 CloseReq.pSession = NIL_RTR0PTR;
881 CloseReq.hIf = pThis->hIf;
882 pThis->hIf = INTNET_HANDLE_INVALID;
883 int rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_CLOSE, &CloseReq, sizeof(CloseReq));
884 AssertRC(rc);
885 }
886
887 /*
888 * Wait for the thread to terminate.
889 */
890 if (pThis->Thread != NIL_RTTHREAD)
891 {
892 if (hEvtSuspended != NIL_RTSEMEVENT)
893 RTSemEventSignal(hEvtSuspended);
894 int rc = RTThreadWait(pThis->Thread, 5000, NULL);
895 AssertRC(rc);
896 pThis->Thread = NIL_RTTHREAD;
897 }
898
899 /*
900 * Destroy the semaphore, S/G cache and xmit lock.
901 */
902 if (hEvtSuspended != NIL_RTSEMEVENT)
903 RTSemEventDestroy(hEvtSuspended);
904
905 RTMemCacheDestroy(pThis->hSgCache);
906 pThis->hSgCache = NIL_RTMEMCACHE;
907
908 if (PDMCritSectIsInitialized(&pThis->XmitLock))
909 PDMR3CritSectDelete(&pThis->XmitLock);
910
911 if (pThis->pBufR3)
912 {
913 /*
914 * Deregister statistics in case we're being detached.
915 */
916 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->Recv.cStatFrames);
917 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->Recv.cbStatWritten);
918 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->Recv.cOverflows);
919 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->Send.cStatFrames);
920 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->Send.cbStatWritten);
921 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->Send.cOverflows);
922 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->cStatYieldsOk);
923 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->cStatYieldsNok);
924 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->cStatLost);
925 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->cStatBadFrames);
926 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReceivedGso);
927 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatSentGso);
928#ifdef VBOX_WITH_STATISTICS
929 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReceive);
930 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatTransmit);
931#endif
932 }
933}
934
935
936/**
937 * Construct a TAP network transport driver instance.
938 *
939 * @copydoc FNPDMDRVCONSTRUCT
940 */
941static DECLCALLBACK(int) drvR3IntNetConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
942{
943 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
944 bool f;
945 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
946
947 /*
948 * Init the static parts.
949 */
950 pThis->pDrvInsR3 = pDrvIns;
951 pThis->hIf = INTNET_HANDLE_INVALID;
952 pThis->Thread = NIL_RTTHREAD;
953 pThis->hEvtSuspended = NIL_RTSEMEVENT;
954 pThis->hSgCache = NIL_RTMEMCACHE;
955 pThis->enmState = ASYNCSTATE_SUSPENDED;
956 pThis->fActivateEarlyDeactivateLate = false;
957 /* IBase* */
958 pDrvIns->IBase.pfnQueryInterface = drvR3IntNetIBase_QueryInterface;
959 pThis->IBaseR0.pfnQueryInterface = drvR3IntNetIBaseR0_QueryInterface;
960 pThis->IBaseRC.pfnQueryInterface = drvR3IntNetIBaseRC_QueryInterface;
961 /* INetworkUp */
962 pThis->INetworkUpR3.pfnBeginXmit = drvR3IntNetUp_BeginXmit;
963 pThis->INetworkUpR3.pfnAllocBuf = drvR3IntNetUp_AllocBuf;
964 pThis->INetworkUpR3.pfnFreeBuf = drvR3IntNetUp_FreeBuf;
965 pThis->INetworkUpR3.pfnSendBuf = drvR3IntNetUp_SendBuf;
966 pThis->INetworkUpR3.pfnEndXmit = drvR3IntNetUp_EndXmit;
967 pThis->INetworkUpR3.pfnSetPromiscuousMode = drvR3IntNetUp_SetPromiscuousMode;
968 pThis->INetworkUpR3.pfnNotifyLinkChanged = drvR3IntNetUp_NotifyLinkChanged;
969
970 /*
971 * Validate the config.
972 */
973 if (!CFGMR3AreValuesValid(pCfg,
974 "Network\0"
975 "Trunk\0"
976 "TrunkType\0"
977 "ReceiveBufferSize\0"
978 "SendBufferSize\0"
979 "RestrictAccess\0"
980 "SharedMacOnWire\0"
981 "IgnoreAllPromisc\0"
982 "QuietlyIgnoreAllPromisc\0"
983 "IgnoreClientPromisc\0"
984 "QuietlyIgnoreClientPromisc\0"
985 "IgnoreTrunkWirePromisc\0"
986 "QuietlyIgnoreTrunkWirePromisc\0"
987 "IgnoreTrunkHostPromisc\0"
988 "QuietlyIgnoreTrunkHostPromisc\0"
989 "IsService\0"))
990 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
991
992 /*
993 * Check that no-one is attached to us.
994 */
995 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
996 ("Configuration error: Not possible to attach anything to this driver!\n"),
997 VERR_PDM_DRVINS_NO_ATTACH);
998
999 /*
1000 * Query the network port interface.
1001 */
1002 pThis->pIAboveNet = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKDOWN);
1003 if (!pThis->pIAboveNet)
1004 {
1005 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network port interface!\n"));
1006 return VERR_PDM_MISSING_INTERFACE_ABOVE;
1007 }
1008 pThis->pIAboveConfigR3 = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKCONFIG);
1009
1010 /*
1011 * Read the configuration.
1012 */
1013 INTNETOPENREQ OpenReq;
1014 memset(&OpenReq, 0, sizeof(OpenReq));
1015 OpenReq.Hdr.cbReq = sizeof(OpenReq);
1016 OpenReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
1017 OpenReq.pSession = NIL_RTR0PTR;
1018
1019 /** @cfgm{Network, string}
1020 * The name of the internal network to connect to.
1021 */
1022 int rc = CFGMR3QueryString(pCfg, "Network", OpenReq.szNetwork, sizeof(OpenReq.szNetwork));
1023 if (RT_FAILURE(rc))
1024 return PDMDRV_SET_ERROR(pDrvIns, rc,
1025 N_("Configuration error: Failed to get the \"Network\" value"));
1026 strcpy(pThis->szNetwork, OpenReq.szNetwork);
1027
1028 /** @cfgm{TrunkType, uint32_t, kIntNetTrunkType_None}
1029 * The trunk connection type see INTNETTRUNKTYPE.
1030 */
1031 uint32_t u32TrunkType;
1032 rc = CFGMR3QueryU32(pCfg, "TrunkType", &u32TrunkType);
1033 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1034 u32TrunkType = kIntNetTrunkType_None;
1035 else if (RT_FAILURE(rc))
1036 return PDMDRV_SET_ERROR(pDrvIns, rc,
1037 N_("Configuration error: Failed to get the \"TrunkType\" value"));
1038 OpenReq.enmTrunkType = (INTNETTRUNKTYPE)u32TrunkType;
1039
1040 /** @cfgm{Trunk, string, ""}
1041 * The name of the trunk connection.
1042 */
1043 rc = CFGMR3QueryString(pCfg, "Trunk", OpenReq.szTrunk, sizeof(OpenReq.szTrunk));
1044 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1045 OpenReq.szTrunk[0] = '\0';
1046 else if (RT_FAILURE(rc))
1047 return PDMDRV_SET_ERROR(pDrvIns, rc,
1048 N_("Configuration error: Failed to get the \"Trunk\" value"));
1049
1050 /** @cfgm{RestrictAccess, boolean, true}
1051 * Whether to restrict the access to the network or if it should be public. Everyone on
1052 * the computer can connect to a public network. Don't change this.
1053 */
1054 bool fRestrictAccess;
1055 rc = CFGMR3QueryBool(pCfg, "RestrictAccess", &fRestrictAccess);
1056 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1057 fRestrictAccess = true;
1058 else if (RT_FAILURE(rc))
1059 return PDMDRV_SET_ERROR(pDrvIns, rc,
1060 N_("Configuration error: Failed to get the \"RestrictAccess\" value"));
1061 OpenReq.fFlags = fRestrictAccess ? 0 : INTNET_OPEN_FLAGS_PUBLIC;
1062
1063 /** @cfgm{IgnoreAllPromisc, boolean, false}
1064 * When set all request for operating any interface or trunk in promiscuous
1065 * mode will be ignored. */
1066 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreAllPromisc", &f, false);
1067 if (RT_FAILURE(rc))
1068 return PDMDRV_SET_ERROR(pDrvIns, rc,
1069 N_("Configuration error: Failed to get the \"IgnoreAllPromisc\" value"));
1070 if (f)
1071 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC;
1072
1073 /** @cfgm{QuietlyIgnoreAllPromisc, boolean, false}
1074 * When set all request for operating any interface or trunk in promiscuous
1075 * mode will be ignored. This differs from IgnoreAllPromisc in that clients
1076 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
1077 rc = CFGMR3QueryBoolDef(pCfg, "QuietlyIgnoreAllPromisc", &f, false);
1078 if (RT_FAILURE(rc))
1079 return PDMDRV_SET_ERROR(pDrvIns, rc,
1080 N_("Configuration error: Failed to get the \"QuietlyIgnoreAllPromisc\" value"));
1081 if (f)
1082 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC;
1083
1084 /** @cfgm{IgnoreClientPromisc, boolean, false}
1085 * When set all request for operating any non-trunk interface in promiscuous
1086 * mode will be ignored. */
1087 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreClientPromisc", &f, false);
1088 if (RT_FAILURE(rc))
1089 return PDMDRV_SET_ERROR(pDrvIns, rc,
1090 N_("Configuration error: Failed to get the \"IgnoreClientPromisc\" value"));
1091 if (f)
1092 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC; /** @todo add special flag for this. */
1093
1094 /** @cfgm{QuietlyIgnoreClientPromisc, boolean, false}
1095 * When set all request for operating any non-trunk interface promiscuous mode
1096 * will be ignored. This differs from IgnoreClientPromisc in that clients won't
1097 * get VERR_INTNET_INCOMPATIBLE_FLAGS. */
1098 rc = CFGMR3QueryBoolDef(pCfg, "QuietlyIgnoreClientPromisc", &f, false);
1099 if (RT_FAILURE(rc))
1100 return PDMDRV_SET_ERROR(pDrvIns, rc,
1101 N_("Configuration error: Failed to get the \"QuietlyIgnoreClientPromisc\" value"));
1102 if (f)
1103 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC; /** @todo add special flag for this. */
1104
1105 /** @cfgm{IgnoreTrunkWirePromisc, boolean, false}
1106 * When set all request for operating the trunk-wire connection in promiscuous
1107 * mode will be ignored. */
1108 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreTrunkWirePromisc", &f, false);
1109 if (RT_FAILURE(rc))
1110 return PDMDRV_SET_ERROR(pDrvIns, rc,
1111 N_("Configuration error: Failed to get the \"IgnoreTrunkWirePromisc\" value"));
1112 if (f)
1113 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_WIRE;
1114
1115 /** @cfgm{QuietlyIgnoreTrunkWirePromisc, boolean, false}
1116 * When set all request for operating any trunk-wire connection promiscuous mode
1117 * will be ignored. This differs from IgnoreTrunkWirePromisc in that clients
1118 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
1119 rc = CFGMR3QueryBoolDef(pCfg, "QuietlyIgnoreTrunkWirePromisc", &f, false);
1120 if (RT_FAILURE(rc))
1121 return PDMDRV_SET_ERROR(pDrvIns, rc,
1122 N_("Configuration error: Failed to get the \"QuietlyIgnoreTrunkWirePromisc\" value"));
1123 if (f)
1124 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_WIRE;
1125
1126 /** @cfgm{IgnoreTrunkHostPromisc, boolean, false}
1127 * When set all request for operating the trunk-host connection in promiscuous
1128 * mode will be ignored. */
1129 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreTrunkHostPromisc", &f, false);
1130 if (RT_FAILURE(rc))
1131 return PDMDRV_SET_ERROR(pDrvIns, rc,
1132 N_("Configuration error: Failed to get the \"IgnoreTrunkHostPromisc\" value"));
1133 if (f)
1134 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_HOST;
1135
1136 /** @cfgm{QuietlyIgnoreTrunkHostPromisc, boolean, false}
1137 * When set all request for operating any trunk-host connection promiscuous mode
1138 * will be ignored. This differs from IgnoreTrunkHostPromisc in that clients
1139 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
1140 rc = CFGMR3QueryBoolDef(pCfg, "QuietlyIgnoreTrunkHostPromisc", &f, false);
1141 if (RT_FAILURE(rc))
1142 return PDMDRV_SET_ERROR(pDrvIns, rc,
1143 N_("Configuration error: Failed to get the \"QuietlyIgnoreTrunkHostPromisc\" value"));
1144 if (f)
1145 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_HOST;
1146
1147 /** @todo flags for not sending to the host and for setting the trunk-wire
1148 * connection in promiscuous mode. */
1149
1150
1151 /** @cfgm{SharedMacOnWire, boolean, false}
1152 * Whether to shared the MAC address of the host interface when using the wire. When
1153 * attaching to a wireless NIC this option is usally a requirement.
1154 */
1155 bool fSharedMacOnWire;
1156 rc = CFGMR3QueryBoolDef(pCfg, "SharedMacOnWire", &fSharedMacOnWire, false);
1157 if (RT_FAILURE(rc))
1158 return PDMDRV_SET_ERROR(pDrvIns, rc,
1159 N_("Configuration error: Failed to get the \"SharedMacOnWire\" value"));
1160 if (fSharedMacOnWire)
1161 OpenReq.fFlags |= INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE;
1162
1163 /** @cfgm{ReceiveBufferSize, uint32_t, 318 KB}
1164 * The size of the receive buffer.
1165 */
1166 rc = CFGMR3QueryU32(pCfg, "ReceiveBufferSize", &OpenReq.cbRecv);
1167 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1168 OpenReq.cbRecv = 318 * _1K ;
1169 else if (RT_FAILURE(rc))
1170 return PDMDRV_SET_ERROR(pDrvIns, rc,
1171 N_("Configuration error: Failed to get the \"ReceiveBufferSize\" value"));
1172
1173 /** @cfgm{SendBufferSize, uint32_t, 196 KB}
1174 * The size of the send (transmit) buffer.
1175 * This should be more than twice the size of the larges frame size because
1176 * the ring buffer is very simple and doesn't support splitting up frames
1177 * nor inserting padding. So, if this is too close to the frame size the
1178 * header will fragment the buffer such that the frame won't fit on either
1179 * side of it and the code will get very upset about it all.
1180 */
1181 rc = CFGMR3QueryU32(pCfg, "SendBufferSize", &OpenReq.cbSend);
1182 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1183 OpenReq.cbSend = RT_ALIGN_Z(VBOX_MAX_GSO_SIZE * 3, _1K);
1184 else if (RT_FAILURE(rc))
1185 return PDMDRV_SET_ERROR(pDrvIns, rc,
1186 N_("Configuration error: Failed to get the \"SendBufferSize\" value"));
1187 if (OpenReq.cbSend < 128)
1188 return PDMDRV_SET_ERROR(pDrvIns, rc,
1189 N_("Configuration error: The \"SendBufferSize\" value is too small"));
1190 if (OpenReq.cbSend < VBOX_MAX_GSO_SIZE * 4)
1191 LogRel(("DrvIntNet: Warning! SendBufferSize=%u, Recommended minimum size %u butes.\n", OpenReq.cbSend, VBOX_MAX_GSO_SIZE * 4));
1192
1193 /** @cfgm{IsService, boolean, true}
1194 * This alterns the way the thread is suspended and resumed. When it's being used by
1195 * a service such as LWIP/iSCSI it shouldn't suspend immediately like for a NIC.
1196 */
1197 rc = CFGMR3QueryBool(pCfg, "IsService", &pThis->fActivateEarlyDeactivateLate);
1198 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1199 pThis->fActivateEarlyDeactivateLate = false;
1200 else if (RT_FAILURE(rc))
1201 return PDMDRV_SET_ERROR(pDrvIns, rc,
1202 N_("Configuration error: Failed to get the \"IsService\" value"));
1203
1204 LogRel(("IntNet#%u: szNetwork={%s} enmTrunkType=%d szTrunk={%s} fFlags=%#x cbRecv=%u cbSend=%u\n",
1205 pDrvIns->iInstance, OpenReq.szNetwork, OpenReq.enmTrunkType, OpenReq.szTrunk, OpenReq.fFlags,
1206 OpenReq.cbRecv, OpenReq.cbSend));
1207
1208#ifdef RT_OS_DARWIN
1209 /* Temporary hack: attach to a network with the name 'if=en0' and you're hitting the wire. */
1210 if ( !OpenReq.szTrunk[0]
1211 && OpenReq.enmTrunkType == kIntNetTrunkType_None
1212 && !strncmp(pThis->szNetwork, "if=en", sizeof("if=en") - 1)
1213 && RT_C_IS_DIGIT(pThis->szNetwork[sizeof("if=en") - 1])
1214 && !pThis->szNetwork[sizeof("if=en")])
1215 {
1216 OpenReq.enmTrunkType = kIntNetTrunkType_NetFlt;
1217 strcpy(OpenReq.szTrunk, &pThis->szNetwork[sizeof("if=") - 1]);
1218 }
1219 /* Temporary hack: attach to a network with the name 'wif=en0' and you're on the air. */
1220 if ( !OpenReq.szTrunk[0]
1221 && OpenReq.enmTrunkType == kIntNetTrunkType_None
1222 && !strncmp(pThis->szNetwork, "wif=en", sizeof("wif=en") - 1)
1223 && RT_C_IS_DIGIT(pThis->szNetwork[sizeof("wif=en") - 1])
1224 && !pThis->szNetwork[sizeof("wif=en")])
1225 {
1226 OpenReq.enmTrunkType = kIntNetTrunkType_NetFlt;
1227 OpenReq.fFlags |= INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE;
1228 strcpy(OpenReq.szTrunk, &pThis->szNetwork[sizeof("wif=") - 1]);
1229 }
1230#endif /* DARWIN */
1231
1232 /*
1233 * Create the event semaphore, S/G cache and xmit critsect.
1234 */
1235 rc = RTSemEventCreate(&pThis->hEvtSuspended);
1236 if (RT_FAILURE(rc))
1237 return rc;
1238 rc = RTMemCacheCreate(&pThis->hSgCache, sizeof(PDMSCATTERGATHER), 0, UINT32_MAX, NULL, NULL, pThis, 0);
1239 if (RT_FAILURE(rc))
1240 return rc;
1241 rc = PDMDrvHlpCritSectInit(pDrvIns, &pThis->XmitLock, RT_SRC_POS, "IntNetXmit");
1242 if (RT_FAILURE(rc))
1243 return rc;
1244
1245
1246 /*
1247 * Create the interface.
1248 */
1249 OpenReq.hIf = INTNET_HANDLE_INVALID;
1250 rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_OPEN, &OpenReq, sizeof(OpenReq));
1251 if (RT_FAILURE(rc))
1252 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1253 N_("Failed to open/create the internal network '%s'"), pThis->szNetwork);
1254 AssertRelease(OpenReq.hIf != INTNET_HANDLE_INVALID);
1255 pThis->hIf = OpenReq.hIf;
1256 Log(("IntNet%d: hIf=%RX32 '%s'\n", pDrvIns->iInstance, pThis->hIf, pThis->szNetwork));
1257
1258 /*
1259 * Get default buffer.
1260 */
1261 INTNETIFGETRING3BUFFERREQ GetRing3BufferReq;
1262 GetRing3BufferReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
1263 GetRing3BufferReq.Hdr.cbReq = sizeof(GetRing3BufferReq);
1264 GetRing3BufferReq.pSession = NIL_RTR0PTR;
1265 GetRing3BufferReq.hIf = pThis->hIf;
1266 GetRing3BufferReq.pRing3Buf = NULL;
1267 rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_GET_RING3_BUFFER, &GetRing3BufferReq, sizeof(GetRing3BufferReq));
1268 if (RT_FAILURE(rc))
1269 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1270 N_("Failed to get ring-3 buffer for the newly created interface to '%s'"), pThis->szNetwork);
1271 AssertRelease(VALID_PTR(GetRing3BufferReq.pRing3Buf));
1272 pThis->pBufR3 = GetRing3BufferReq.pRing3Buf;
1273
1274 /*
1275 * Create the async I/O thread.
1276 * Note! Using a PDM thread here doesn't fit with the IsService=true operation.
1277 */
1278 rc = RTThreadCreate(&pThis->Thread, drvR3IntNetAsyncIoThread, pThis, _128K, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "INTNET");
1279 if (RT_FAILURE(rc))
1280 {
1281 AssertRC(rc);
1282 return rc;
1283 }
1284 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->Recv.cbStatWritten, "Bytes/Received", STAMUNIT_BYTES, "Number of received bytes.");
1285 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->Send.cbStatWritten, "Bytes/Sent", STAMUNIT_BYTES, "Number of sent bytes.");
1286 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->Recv.cOverflows, "Overflows/Recv", STAMUNIT_COUNT, "Number overflows.");
1287 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->Send.cOverflows, "Overflows/Sent", STAMUNIT_COUNT, "Number overflows.");
1288 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->Recv.cStatFrames, "Packets/Received", STAMUNIT_COUNT, "Number of received packets.");
1289 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->Send.cStatFrames, "Packets/Sent", STAMUNIT_COUNT, "Number of sent packets.");
1290 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->StatReceivedGso, "Packets/Received-Gso", STAMUNIT_COUNT, "The GSO portion of the received packets.");
1291 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->StatSentGso, "Packets/Sent-Gso", STAMUNIT_COUNT, "The GSO portion of the sent packets.");
1292
1293 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->cStatLost, "Packets/Lost", STAMUNIT_COUNT, "Number of lost packets.");
1294 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->cStatYieldsNok, "YieldOk", STAMUNIT_COUNT, "Number of times yielding helped fix an overflow.");
1295 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->cStatYieldsOk, "YieldNok", STAMUNIT_COUNT, "Number of times yielding didn't help fix an overflow.");
1296 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->cStatBadFrames, "BadFrames", STAMUNIT_COUNT, "Number of bad frames seed by the consumers.");
1297#ifdef VBOX_WITH_STATISTICS
1298 PDMDrvHlpSTAMRegProfileAdv(pDrvIns, &pThis->StatReceive, "Receive", STAMUNIT_TICKS_PER_CALL, "Profiling packet receive runs.");
1299 PDMDrvHlpSTAMRegProfile(pDrvIns, &pThis->StatTransmit, "Transmit", STAMUNIT_TICKS_PER_CALL, "Profiling packet transmit runs.");
1300#endif
1301
1302 /*
1303 * Activate data transmission as early as possible
1304 */
1305 if (pThis->fActivateEarlyDeactivateLate)
1306 {
1307 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
1308 RTSemEventSignal(pThis->hEvtSuspended);
1309 drvR3IntNetUpdateMacAddress(pThis);
1310 drvR3IntNetSetActive(pThis, true /* fActive */);
1311 }
1312
1313 return rc;
1314}
1315
1316
1317/**
1318 * Internal networking transport driver registration record.
1319 */
1320const PDMDRVREG g_DrvIntNet =
1321{
1322 /* u32Version */
1323 PDM_DRVREG_VERSION,
1324 /* szName */
1325 "IntNet",
1326 /* szRCMod */
1327 "VBoxDDRC",
1328 /* szR0Mod */
1329 "VBoxDDR0",
1330 /* pszDescription */
1331 "Internal Networking Transport Driver",
1332 /* fFlags */
1333#ifdef VBOX_WITH_R0_AND_RC_DRIVERS
1334 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DRVREG_FLAGS_R0 | PDM_DRVREG_FLAGS_RC,
1335#else
1336 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1337#endif
1338 /* fClass. */
1339 PDM_DRVREG_CLASS_NETWORK,
1340 /* cMaxInstances */
1341 ~0,
1342 /* cbInstance */
1343 sizeof(DRVINTNET),
1344 /* pfnConstruct */
1345 drvR3IntNetConstruct,
1346 /* pfnDestruct */
1347 drvR3IntNetDestruct,
1348 /* pfnRelocate */
1349 drvR3IntNetRelocate,
1350 /* pfnIOCtl */
1351 NULL,
1352 /* pfnPowerOn */
1353 drvR3IntNetPowerOn,
1354 /* pfnReset */
1355 NULL,
1356 /* pfnSuspend */
1357 drvR3IntNetSuspend,
1358 /* pfnResume */
1359 drvR3IntNetResume,
1360 /* pfnAttach */
1361 NULL,
1362 /* pfnDetach */
1363 NULL,
1364 /* pfnPowerOff */
1365 drvR3IntNetPowerOff,
1366 /* pfnSoftReset */
1367 NULL,
1368 /* u32EndVersion */
1369 PDM_DRVREG_VERSION
1370};
1371
1372#endif /* IN_RING3 */
1373
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette