VirtualBox

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

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

intnet, VBoxNet*, network device & drivers: GSO preps.

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