VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DevVirtioNet.cpp@ 30351

Last change on this file since 30351 was 30219, checked in by vboxsync, 14 years ago

DevVirtioNet.cpp: warning.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 64.5 KB
Line 
1/* $Id: DevVirtioNet.cpp 30219 2010-06-16 01:47:40Z vboxsync $ */
2/** @file
3 * DevVirtioNet - Virtio Network Device
4 */
5
6/*
7 * Copyright (C) 2009-2010 Oracle Corporation
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
18
19#define LOG_GROUP LOG_GROUP_DEV_VIRTIO_NET
20#define VNET_GC_SUPPORT
21
22#include <VBox/pdmdev.h>
23#include <VBox/pdmnetifs.h>
24#include <iprt/asm.h>
25#include <iprt/semaphore.h>
26#ifdef IN_RING3
27# include <iprt/mem.h>
28# include <iprt/uuid.h>
29#endif /* IN_RING3 */
30#include "../Builtins.h"
31#include "../VirtIO/Virtio.h"
32
33
34#ifndef VBOX_DEVICE_STRUCT_TESTCASE
35
36#define INSTANCE(pState) pState->VPCI.szInstance
37#define STATUS pState->config.uStatus
38
39#ifdef IN_RING3
40
41#define VNET_PCI_SUBSYSTEM_ID 1 + VIRTIO_NET_ID
42#define VNET_PCI_CLASS 0x0200
43#define VNET_N_QUEUES 3
44#define VNET_NAME_FMT "VNet%d"
45
46#if 0
47/* Virtio Block Device */
48#define VNET_PCI_SUBSYSTEM_ID 1 + VIRTIO_BLK_ID
49#define VNET_PCI_CLASS 0x0180
50#define VNET_N_QUEUES 2
51#define VNET_NAME_FMT "VBlk%d"
52#endif
53
54#endif /* IN_RING3 */
55
56/* Forward declarations ******************************************************/
57RT_C_DECLS_BEGIN
58PDMBOTHCBDECL(int) vnetIOPortIn (PPDMDEVINS pDevIns, void *pvUser, RTIOPORT port, uint32_t *pu32, unsigned cb);
59PDMBOTHCBDECL(int) vnetIOPortOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT port, uint32_t u32, unsigned cb);
60RT_C_DECLS_END
61
62#endif /* VBOX_DEVICE_STRUCT_TESTCASE */
63
64
65#define VNET_TX_DELAY 150 /* 150 microseconds */
66#define VNET_MAX_FRAME_SIZE 65536 // TODO: Is it the right limit?
67#define VNET_MAC_FILTER_LEN 32
68#define VNET_MAX_VID (1 << 12)
69
70/* Virtio net features */
71#define VNET_F_CSUM 0x00000001 /* Host handles pkts w/ partial csum */
72#define VNET_F_GUEST_CSUM 0x00000002 /* Guest handles pkts w/ partial csum */
73#define VNET_F_MAC 0x00000020 /* Host has given MAC address. */
74#define VNET_F_GSO 0x00000040 /* Host handles pkts w/ any GSO type */
75#define VNET_F_GUEST_TSO4 0x00000080 /* Guest can handle TSOv4 in. */
76#define VNET_F_GUEST_TSO6 0x00000100 /* Guest can handle TSOv6 in. */
77#define VNET_F_GUEST_ECN 0x00000200 /* Guest can handle TSO[6] w/ ECN in. */
78#define VNET_F_GUEST_UFO 0x00000400 /* Guest can handle UFO in. */
79#define VNET_F_HOST_TSO4 0x00000800 /* Host can handle TSOv4 in. */
80#define VNET_F_HOST_TSO6 0x00001000 /* Host can handle TSOv6 in. */
81#define VNET_F_HOST_ECN 0x00002000 /* Host can handle TSO[6] w/ ECN in. */
82#define VNET_F_HOST_UFO 0x00004000 /* Host can handle UFO in. */
83#define VNET_F_MRG_RXBUF 0x00008000 /* Host can merge receive buffers. */
84#define VNET_F_STATUS 0x00010000 /* virtio_net_config.status available */
85#define VNET_F_CTRL_VQ 0x00020000 /* Control channel available */
86#define VNET_F_CTRL_RX 0x00040000 /* Control channel RX mode support */
87#define VNET_F_CTRL_VLAN 0x00080000 /* Control channel VLAN filtering */
88
89#define VNET_S_LINK_UP 1
90
91
92#ifdef _MSC_VER
93struct VNetPCIConfig
94#else /* !_MSC_VER */
95struct __attribute__ ((__packed__)) VNetPCIConfig
96#endif /* !_MSC_VER */
97{
98 RTMAC mac;
99 uint16_t uStatus;
100};
101AssertCompileMemberOffset(struct VNetPCIConfig, uStatus, 6);
102
103/**
104 * Device state structure. Holds the current state of device.
105 *
106 * @extends VPCISTATE
107 * @implements PDMINETWORKDOWN
108 * @implements PDMINETWORKCONFIG
109 */
110struct VNetState_st
111{
112 /* VPCISTATE must be the first member! */
113 VPCISTATE VPCI;
114
115// PDMCRITSECT csRx; /**< Protects RX queue. */
116
117 PDMINETWORKDOWN INetworkDown;
118 PDMINETWORKCONFIG INetworkConfig;
119 R3PTRTYPE(PPDMIBASE) pDrvBase; /**< Attached network driver. */
120 R3PTRTYPE(PPDMINETWORKUP) pDrv; /**< Connector of attached network driver. */
121
122 R3PTRTYPE(PPDMQUEUE) pCanRxQueueR3; /**< Rx wakeup signaller - R3. */
123 R0PTRTYPE(PPDMQUEUE) pCanRxQueueR0; /**< Rx wakeup signaller - R0. */
124 RCPTRTYPE(PPDMQUEUE) pCanRxQueueRC; /**< Rx wakeup signaller - RC. */
125
126#if HC_ARCH_BITS == 64
127 uint32_t padding;
128#endif
129
130 /** transmit buffer */
131 R3PTRTYPE(uint8_t*) pTxBuf;
132 /**< Link Up(/Restore) Timer. */
133 PTMTIMERR3 pLinkUpTimer;
134#ifdef VNET_TX_DELAY
135 /**< Transmit Delay Timer - R3. */
136 PTMTIMERR3 pTxTimerR3;
137 /**< Transmit Delay Timer - R0. */
138 PTMTIMERR0 pTxTimerR0;
139 /**< Transmit Delay Timer - GC. */
140 PTMTIMERRC pTxTimerRC;
141
142#if HC_ARCH_BITS == 64
143 uint32_t padding2;
144#endif
145
146 uint32_t u32i;
147 uint32_t u32AvgDiff;
148 uint32_t u32MinDiff;
149 uint32_t u32MaxDiff;
150 uint64_t u64NanoTS;
151
152#endif /* VNET_TX_DELAY */
153 /** Indicates transmission in progress -- only one thread is allowed. */
154 uint32_t uIsTransmitting;
155
156 /** PCI config area holding MAC address as well as TBD. */
157 struct VNetPCIConfig config;
158 /** MAC address obtained from the configuration. */
159 RTMAC macConfigured;
160 /** True if physical cable is attached in configuration. */
161 bool fCableConnected;
162
163 /** Number of packet being sent/received to show in debug log. */
164 uint32_t u32PktNo;
165
166 /** N/A: */
167 bool volatile fMaybeOutOfSpace;
168
169 /** Promiscuous mode -- RX filter accepts all packets. */
170 bool fPromiscuous;
171 /** AllMulti mode -- RX filter accepts all multicast packets. */
172 bool fAllMulti;
173 /** The number of actually used slots in aMacTable. */
174 uint32_t nMacFilterEntries;
175 /** Array of MAC addresses accepted by RX filter. */
176 RTMAC aMacFilter[VNET_MAC_FILTER_LEN];
177 /** Bit array of VLAN filter, one bit per VLAN ID. */
178 uint8_t aVlanFilter[VNET_MAX_VID / sizeof(uint8_t)];
179
180 R3PTRTYPE(PVQUEUE) pRxQueue;
181 R3PTRTYPE(PVQUEUE) pTxQueue;
182 R3PTRTYPE(PVQUEUE) pCtlQueue;
183 /* Receive-blocking-related fields ***************************************/
184
185 /** EMT: Gets signalled when more RX descriptors become available. */
186 RTSEMEVENT hEventMoreRxDescAvail;
187
188 /* Statistic fields ******************************************************/
189
190 STAMCOUNTER StatReceiveBytes;
191 STAMCOUNTER StatTransmitBytes;
192#if defined(VBOX_WITH_STATISTICS)
193 STAMPROFILE StatReceive;
194 STAMPROFILE StatReceiveStore;
195 STAMPROFILEADV StatTransmit;
196 STAMPROFILE StatTransmitSend;
197 STAMPROFILE StatRxOverflow;
198 STAMCOUNTER StatRxOverflowWakeup;
199#endif /* VBOX_WITH_STATISTICS */
200
201};
202typedef struct VNetState_st VNETSTATE;
203typedef VNETSTATE *PVNETSTATE;
204
205#ifndef VBOX_DEVICE_STRUCT_TESTCASE
206
207#define VNETHDR_GSO_NONE 0
208
209struct VNetHdr
210{
211 uint8_t u8Flags;
212 uint8_t u8GSOType;
213 uint16_t u16HdrLen;
214 uint16_t u16GSOSize;
215 uint16_t u16CSumStart;
216 uint16_t u16CSumOffset;
217};
218typedef struct VNetHdr VNETHDR;
219typedef VNETHDR *PVNETHDR;
220AssertCompileSize(VNETHDR, 10);
221
222AssertCompileMemberOffset(VNETSTATE, VPCI, 0);
223
224#define VNET_OK 0
225#define VNET_ERROR 1
226typedef uint8_t VNETCTLACK;
227
228#define VNET_CTRL_CLS_RX_MODE 0
229#define VNET_CTRL_CMD_RX_MODE_PROMISC 0
230#define VNET_CTRL_CMD_RX_MODE_ALLMULTI 1
231
232#define VNET_CTRL_CLS_MAC 1
233#define VNET_CTRL_CMD_MAC_TABLE_SET 0
234
235#define VNET_CTRL_CLS_VLAN 2
236#define VNET_CTRL_CMD_VLAN_ADD 0
237#define VNET_CTRL_CMD_VLAN_DEL 1
238
239
240struct VNetCtlHdr
241{
242 uint8_t u8Class;
243 uint8_t u8Command;
244};
245typedef struct VNetCtlHdr VNETCTLHDR;
246typedef VNETCTLHDR *PVNETCTLHDR;
247AssertCompileSize(VNETCTLHDR, 2);
248
249DECLINLINE(int) vnetCsEnter(PVNETSTATE pState, int rcBusy)
250{
251 return vpciCsEnter(&pState->VPCI, rcBusy);
252}
253
254DECLINLINE(void) vnetCsLeave(PVNETSTATE pState)
255{
256 vpciCsLeave(&pState->VPCI);
257}
258
259DECLINLINE(int) vnetCsRxEnter(PVNETSTATE pState, int rcBusy)
260{
261 // STAM_PROFILE_START(&pState->CTXSUFF(StatCsRx), a);
262 // int rc = PDMCritSectEnter(&pState->csRx, rcBusy);
263 // STAM_PROFILE_STOP(&pState->CTXSUFF(StatCsRx), a);
264 // return rc;
265 return VINF_SUCCESS;
266}
267
268DECLINLINE(void) vnetCsRxLeave(PVNETSTATE pState)
269{
270 // PDMCritSectLeave(&pState->csRx);
271}
272
273/**
274 * Dump a packet to debug log.
275 *
276 * @param pState The device state structure.
277 * @param cpPacket The packet.
278 * @param cb The size of the packet.
279 * @param cszText A string denoting direction of packet transfer.
280 */
281DECLINLINE(void) vnetPacketDump(PVNETSTATE pState, const uint8_t *cpPacket, size_t cb, const char *cszText)
282{
283#ifdef DEBUG
284 Log(("%s %s packet #%d (%d bytes):\n",
285 INSTANCE(pState), cszText, ++pState->u32PktNo, cb));
286 //Log3(("%.*Rhxd\n", cb, cpPacket));
287#endif
288}
289
290
291
292PDMBOTHCBDECL(uint32_t) vnetGetHostFeatures(void *pvState)
293{
294 /* We support:
295 * - Host-provided MAC address
296 * - Link status reporting in config space
297 * - Control queue
298 * - RX mode setting
299 * - MAC filter table
300 * - VLAN filter
301 */
302 return VNET_F_MAC
303 | VNET_F_STATUS
304 | VNET_F_CTRL_VQ
305 | VNET_F_CTRL_RX
306 | VNET_F_CTRL_VLAN;
307}
308
309PDMBOTHCBDECL(uint32_t) vnetGetHostMinimalFeatures(void *pvState)
310{
311 return VNET_F_MAC;
312}
313
314PDMBOTHCBDECL(void) vnetSetHostFeatures(void *pvState, uint32_t uFeatures)
315{
316 // TODO: Nothing to do here yet
317 VNETSTATE *pState = (VNETSTATE *)pvState;
318 LogFlow(("%s vnetSetHostFeatures: uFeatures=%x\n", INSTANCE(pState), uFeatures));
319}
320
321PDMBOTHCBDECL(int) vnetGetConfig(void *pvState, uint32_t port, uint32_t cb, void *data)
322{
323 VNETSTATE *pState = (VNETSTATE *)pvState;
324 if (port + cb > sizeof(struct VNetPCIConfig))
325 {
326 Log(("%s vnetGetConfig: Read beyond the config structure is attempted (port=%RTiop cb=%x).\n", INSTANCE(pState), port, cb));
327 return VERR_IOM_IOPORT_UNUSED;
328 }
329 memcpy(data, ((uint8_t*)&pState->config) + port, cb);
330 return VINF_SUCCESS;
331}
332
333PDMBOTHCBDECL(int) vnetSetConfig(void *pvState, uint32_t port, uint32_t cb, void *data)
334{
335 VNETSTATE *pState = (VNETSTATE *)pvState;
336 if (port + cb > sizeof(struct VNetPCIConfig))
337 {
338 Log(("%s vnetGetConfig: Write beyond the config structure is attempted (port=%RTiop cb=%x).\n", INSTANCE(pState), port, cb));
339 if (port < sizeof(struct VNetPCIConfig))
340 memcpy(((uint8_t*)&pState->config) + port, data,
341 sizeof(struct VNetPCIConfig) - port);
342 return VINF_SUCCESS;
343 }
344 memcpy(((uint8_t*)&pState->config) + port, data, cb);
345 return VINF_SUCCESS;
346}
347
348/**
349 * Hardware reset. Revert all registers to initial values.
350 *
351 * @param pState The device state structure.
352 */
353PDMBOTHCBDECL(int) vnetReset(void *pvState)
354{
355 VNETSTATE *pState = (VNETSTATE*)pvState;
356 Log(("%s Reset triggered\n", INSTANCE(pState)));
357
358 int rc = vnetCsRxEnter(pState, VERR_SEM_BUSY);
359 if (RT_UNLIKELY(rc != VINF_SUCCESS))
360 {
361 LogRel(("vnetReset failed to enter RX critical section!\n"));
362 return rc;
363 }
364 vpciReset(&pState->VPCI);
365 vnetCsRxLeave(pState);
366
367 // TODO: Implement reset
368 if (pState->fCableConnected)
369 STATUS = VNET_S_LINK_UP;
370 else
371 STATUS = 0;
372 /*
373 * By default we pass all packets up since the older guests cannot control
374 * virtio mode.
375 */
376 pState->fPromiscuous = true;
377 pState->fAllMulti = false;
378 pState->nMacFilterEntries = 0;
379 memset(pState->aMacFilter, 0, VNET_MAC_FILTER_LEN * sizeof(RTMAC));
380 memset(pState->aVlanFilter, 0, sizeof(pState->aVlanFilter));
381 pState->uIsTransmitting = 0;
382#ifndef IN_RING3
383 return VINF_IOM_HC_IOPORT_WRITE;
384#else
385 if (pState->pDrv)
386 pState->pDrv->pfnSetPromiscuousMode(pState->pDrv, true);
387 return VINF_SUCCESS;
388#endif
389}
390
391#ifdef IN_RING3
392
393/**
394 * Wakeup the RX thread.
395 */
396static void vnetWakeupReceive(PPDMDEVINS pDevIns)
397{
398 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE *);
399 if ( pState->fMaybeOutOfSpace
400 && pState->hEventMoreRxDescAvail != NIL_RTSEMEVENT)
401 {
402 STAM_COUNTER_INC(&pState->StatRxOverflowWakeup);
403 Log(("%s Waking up Out-of-RX-space semaphore\n", INSTANCE(pState)));
404 RTSemEventSignal(pState->hEventMoreRxDescAvail);
405 }
406}
407
408/**
409 * Link Up Timer handler.
410 *
411 * @param pDevIns Pointer to device instance structure.
412 * @param pTimer Pointer to the timer.
413 * @param pvUser NULL.
414 * @thread EMT
415 */
416static DECLCALLBACK(void) vnetLinkUpTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
417{
418 VNETSTATE *pState = (VNETSTATE *)pvUser;
419
420 int rc = vnetCsEnter(pState, VERR_SEM_BUSY);
421 if (RT_UNLIKELY(rc != VINF_SUCCESS))
422 return;
423 STATUS |= VNET_S_LINK_UP;
424 vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
425 vnetWakeupReceive(pDevIns);
426 vnetCsLeave(pState);
427}
428
429
430
431
432/**
433 * Handler for the wakeup signaller queue.
434 */
435static DECLCALLBACK(bool) vnetCanRxQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
436{
437 vnetWakeupReceive(pDevIns);
438 return true;
439}
440
441#endif /* IN_RING3 */
442
443/**
444 * This function is called when the driver becomes ready.
445 *
446 * @param pState The device state structure.
447 */
448PDMBOTHCBDECL(void) vnetReady(void *pvState)
449{
450 VNETSTATE *pState = (VNETSTATE*)pvState;
451 Log(("%s Driver became ready, waking up RX thread...\n", INSTANCE(pState)));
452#ifdef IN_RING3
453 vnetWakeupReceive(pState->VPCI.CTX_SUFF(pDevIns));
454#else
455 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(pState->CTX_SUFF(pCanRxQueue));
456 if (pItem)
457 PDMQueueInsert(pState->CTX_SUFF(pCanRxQueue), pItem);
458#endif
459}
460
461/**
462 * Port I/O Handler for IN operations.
463 *
464 * @returns VBox status code.
465 *
466 * @param pDevIns The device instance.
467 * @param pvUser Pointer to the device state structure.
468 * @param port Port number used for the IN operation.
469 * @param pu32 Where to store the result.
470 * @param cb Number of bytes read.
471 * @thread EMT
472 */
473PDMBOTHCBDECL(int) vnetIOPortIn(PPDMDEVINS pDevIns, void *pvUser,
474 RTIOPORT port, uint32_t *pu32, unsigned cb)
475{
476 return vpciIOPortIn(pDevIns, pvUser, port, pu32, cb,
477 vnetGetHostFeatures,
478 vnetGetConfig);
479}
480
481
482/**
483 * Port I/O Handler for OUT operations.
484 *
485 * @returns VBox status code.
486 *
487 * @param pDevIns The device instance.
488 * @param pvUser User argument.
489 * @param Port Port number used for the IN operation.
490 * @param u32 The value to output.
491 * @param cb The value size in bytes.
492 * @thread EMT
493 */
494PDMBOTHCBDECL(int) vnetIOPortOut(PPDMDEVINS pDevIns, void *pvUser,
495 RTIOPORT port, uint32_t u32, unsigned cb)
496{
497 return vpciIOPortOut(pDevIns, pvUser, port, u32, cb,
498 vnetGetHostMinimalFeatures,
499 vnetGetHostFeatures,
500 vnetSetHostFeatures,
501 vnetReset,
502 vnetReady,
503 vnetSetConfig);
504}
505
506
507#ifdef IN_RING3
508
509/**
510 * Check if the device can receive data now.
511 * This must be called before the pfnRecieve() method is called.
512 *
513 * @remarks As a side effect this function enables queue notification
514 * if it cannot receive because the queue is empty.
515 * It disables notification if it can receive.
516 *
517 * @returns VERR_NET_NO_BUFFER_SPACE if it cannot.
518 * @param pInterface Pointer to the interface structure containing the called function pointer.
519 * @thread RX
520 */
521static int vnetCanReceive(VNETSTATE *pState)
522{
523 int rc = vnetCsRxEnter(pState, VERR_SEM_BUSY);
524 AssertRCReturn(rc, rc);
525
526 LogFlow(("%s vnetCanReceive\n", INSTANCE(pState)));
527 if (!(pState->VPCI.uStatus & VPCI_STATUS_DRV_OK))
528 rc = VERR_NET_NO_BUFFER_SPACE;
529 else if (!vqueueIsReady(&pState->VPCI, pState->pRxQueue))
530 rc = VERR_NET_NO_BUFFER_SPACE;
531 else if (vqueueIsEmpty(&pState->VPCI, pState->pRxQueue))
532 {
533 vringSetNotification(&pState->VPCI, &pState->pRxQueue->VRing, true);
534 rc = VERR_NET_NO_BUFFER_SPACE;
535 }
536 else
537 {
538 vringSetNotification(&pState->VPCI, &pState->pRxQueue->VRing, false);
539 rc = VINF_SUCCESS;
540 }
541
542 LogFlow(("%s vnetCanReceive -> %Rrc\n", INSTANCE(pState), rc));
543 vnetCsRxLeave(pState);
544 return rc;
545}
546
547/**
548 * @interface_method_impl{PDMINETWORKDOWN,pfnWaitReceiveAvail}
549 */
550static DECLCALLBACK(int) vnetNetworkDown_WaitReceiveAvail(PPDMINETWORKDOWN pInterface, RTMSINTERVAL cMillies)
551{
552 VNETSTATE *pState = RT_FROM_MEMBER(pInterface, VNETSTATE, INetworkDown);
553 LogFlow(("%s vnetNetworkDown_WaitReceiveAvail(cMillies=%u)\n", INSTANCE(pState), cMillies));
554 int rc = vnetCanReceive(pState);
555
556 if (RT_SUCCESS(rc))
557 return VINF_SUCCESS;
558 if (RT_UNLIKELY(cMillies == 0))
559 return VERR_NET_NO_BUFFER_SPACE;
560
561 rc = VERR_INTERRUPTED;
562 ASMAtomicXchgBool(&pState->fMaybeOutOfSpace, true);
563 STAM_PROFILE_START(&pState->StatRxOverflow, a);
564
565 VMSTATE enmVMState;
566 while (RT_LIKELY( (enmVMState = PDMDevHlpVMState(pState->VPCI.CTX_SUFF(pDevIns))) == VMSTATE_RUNNING
567 || enmVMState == VMSTATE_RUNNING_LS))
568 {
569 int rc2 = vnetCanReceive(pState);
570 if (RT_SUCCESS(rc2))
571 {
572 rc = VINF_SUCCESS;
573 break;
574 }
575 Log(("%s vnetNetworkDown_WaitReceiveAvail: waiting cMillies=%u...\n",
576 INSTANCE(pState), cMillies));
577 RTSemEventWait(pState->hEventMoreRxDescAvail, cMillies);
578 }
579 STAM_PROFILE_STOP(&pState->StatRxOverflow, a);
580 ASMAtomicXchgBool(&pState->fMaybeOutOfSpace, false);
581
582 LogFlow(("%s vnetNetworkDown_WaitReceiveAvail -> %d\n", INSTANCE(pState), rc));
583 return rc;
584}
585
586
587/**
588 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
589 */
590static DECLCALLBACK(void *) vnetQueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
591{
592 VNETSTATE *pThis = RT_FROM_MEMBER(pInterface, VNETSTATE, VPCI.IBase);
593 Assert(&pThis->VPCI.IBase == pInterface);
594
595 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKDOWN, &pThis->INetworkDown);
596 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThis->INetworkConfig);
597 return vpciQueryInterface(pInterface, pszIID);
598}
599
600/**
601 * Returns true if it is a broadcast packet.
602 *
603 * @returns true if destination address indicates broadcast.
604 * @param pvBuf The ethernet packet.
605 */
606DECLINLINE(bool) vnetIsBroadcast(const void *pvBuf)
607{
608 static const uint8_t s_abBcastAddr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
609 return memcmp(pvBuf, s_abBcastAddr, sizeof(s_abBcastAddr)) == 0;
610}
611
612/**
613 * Returns true if it is a multicast packet.
614 *
615 * @remarks returns true for broadcast packets as well.
616 * @returns true if destination address indicates multicast.
617 * @param pvBuf The ethernet packet.
618 */
619DECLINLINE(bool) vnetIsMulticast(const void *pvBuf)
620{
621 return (*(char*)pvBuf) & 1;
622}
623
624/**
625 * Determines if the packet is to be delivered to upper layer.
626 *
627 * @returns true if packet is intended for this node.
628 * @param pState Pointer to the state structure.
629 * @param pvBuf The ethernet packet.
630 * @param cb Number of bytes available in the packet.
631 */
632static bool vnetAddressFilter(PVNETSTATE pState, const void *pvBuf, size_t cb)
633{
634 if (pState->fPromiscuous)
635 return true;
636
637 /* Ignore everything outside of our VLANs */
638 uint16_t *u16Ptr = (uint16_t*)pvBuf;
639 /* Compare TPID with VLAN Ether Type */
640 if ( u16Ptr[6] == RT_H2BE_U16(0x8100)
641 && !ASMBitTest(pState->aVlanFilter, RT_BE2H_U16(u16Ptr[7]) & 0xFFF))
642 return false;
643
644 if (vnetIsBroadcast(pvBuf))
645 return true;
646
647 if (pState->fAllMulti && vnetIsMulticast(pvBuf))
648 return true;
649
650 if (!memcmp(pState->config.mac.au8, pvBuf, sizeof(RTMAC)))
651 return true;
652
653 for (unsigned i = 0; i < pState->nMacFilterEntries; i++)
654 if (!memcmp(&pState->aMacFilter[i], pvBuf, sizeof(RTMAC)))
655 return true;
656
657 return false;
658}
659
660/**
661 * Pad and store received packet.
662 *
663 * @remarks Make sure that the packet appears to upper layer as one coming
664 * from real Ethernet: pad it and insert FCS.
665 *
666 * @returns VBox status code.
667 * @param pState The device state structure.
668 * @param pvBuf The available data.
669 * @param cb Number of bytes available in the buffer.
670 * @thread RX
671 */
672static int vnetHandleRxPacket(PVNETSTATE pState, const void *pvBuf, size_t cb)
673{
674 VNETHDR hdr;
675
676 hdr.u8Flags = 0;
677 hdr.u8GSOType = VNETHDR_GSO_NONE;
678
679 vnetPacketDump(pState, (const uint8_t*)pvBuf, cb, "<-- Incoming");
680
681 unsigned int uOffset = 0;
682 for (unsigned int nElem = 0; uOffset < cb; nElem++)
683 {
684 VQUEUEELEM elem;
685 unsigned int nSeg = 0, uElemSize = 0;
686
687 if (!vqueueGet(&pState->VPCI, pState->pRxQueue, &elem))
688 {
689 Log(("%s vnetHandleRxPacket: Suddenly there is no space in receive queue!\n", INSTANCE(pState)));
690 return VERR_INTERNAL_ERROR;
691 }
692
693 if (elem.nIn < 1)
694 {
695 Log(("%s vnetHandleRxPacket: No writable descriptors in receive queue!\n", INSTANCE(pState)));
696 return VERR_INTERNAL_ERROR;
697 }
698
699 if (nElem == 0)
700 {
701 /* The very first segment of the very first element gets the header. */
702 if (elem.aSegsIn[nSeg].cb != sizeof(VNETHDR))
703 {
704 Log(("%s vnetHandleRxPacket: The first descriptor does match the header size!\n", INSTANCE(pState)));
705 return VERR_INTERNAL_ERROR;
706 }
707
708 elem.aSegsIn[nSeg++].pv = &hdr;
709 uElemSize += sizeof(VNETHDR);
710 }
711
712 while (nSeg < elem.nIn && uOffset < cb)
713 {
714 unsigned int uSize = (unsigned int)RT_MIN(elem.aSegsIn[nSeg].cb, cb - uOffset);
715 elem.aSegsIn[nSeg++].pv = (uint8_t*)pvBuf + uOffset;
716 uOffset += uSize;
717 uElemSize += uSize;
718 }
719 STAM_PROFILE_START(&pState->StatReceiveStore, a);
720 vqueuePut(&pState->VPCI, pState->pRxQueue, &elem, uElemSize);
721 STAM_PROFILE_STOP(&pState->StatReceiveStore, a);
722 }
723 vqueueSync(&pState->VPCI, pState->pRxQueue);
724
725 return VINF_SUCCESS;
726}
727
728/**
729 * @interface_method_impl{PDMINETWORKDOWN,pfnReceive}
730 */
731static DECLCALLBACK(int) vnetNetworkDown_Receive(PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb)
732{
733 VNETSTATE *pState = RT_FROM_MEMBER(pInterface, VNETSTATE, INetworkDown);
734
735 Log2(("%s vnetNetworkDown_Receive: pvBuf=%p cb=%u\n", INSTANCE(pState), pvBuf, cb));
736 int rc = vnetCanReceive(pState);
737 if (RT_FAILURE(rc))
738 return rc;
739
740 /* Drop packets if VM is not running or cable is disconnected. */
741 VMSTATE enmVMState = PDMDevHlpVMState(pState->VPCI.CTX_SUFF(pDevIns));
742 if (( enmVMState != VMSTATE_RUNNING
743 && enmVMState != VMSTATE_RUNNING_LS)
744 || !(STATUS & VNET_S_LINK_UP))
745 return VINF_SUCCESS;
746
747 STAM_PROFILE_START(&pState->StatReceive, a);
748 vpciSetReadLed(&pState->VPCI, true);
749 if (vnetAddressFilter(pState, pvBuf, cb))
750 {
751 rc = vnetCsRxEnter(pState, VERR_SEM_BUSY);
752 if (RT_SUCCESS(rc))
753 {
754 rc = vnetHandleRxPacket(pState, pvBuf, cb);
755 STAM_REL_COUNTER_ADD(&pState->StatReceiveBytes, cb);
756 vnetCsRxLeave(pState);
757 }
758 }
759 vpciSetReadLed(&pState->VPCI, false);
760 STAM_PROFILE_STOP(&pState->StatReceive, a);
761 return rc;
762}
763
764/**
765 * Gets the current Media Access Control (MAC) address.
766 *
767 * @returns VBox status code.
768 * @param pInterface Pointer to the interface structure containing the called function pointer.
769 * @param pMac Where to store the MAC address.
770 * @thread EMT
771 */
772static DECLCALLBACK(int) vnetGetMac(PPDMINETWORKCONFIG pInterface, PRTMAC pMac)
773{
774 VNETSTATE *pState = RT_FROM_MEMBER(pInterface, VNETSTATE, INetworkConfig);
775 memcpy(pMac, pState->config.mac.au8, sizeof(RTMAC));
776 return VINF_SUCCESS;
777}
778
779/**
780 * Gets the new link state.
781 *
782 * @returns The current link state.
783 * @param pInterface Pointer to the interface structure containing the called function pointer.
784 * @thread EMT
785 */
786static DECLCALLBACK(PDMNETWORKLINKSTATE) vnetGetLinkState(PPDMINETWORKCONFIG pInterface)
787{
788 VNETSTATE *pState = RT_FROM_MEMBER(pInterface, VNETSTATE, INetworkConfig);
789 if (STATUS & VNET_S_LINK_UP)
790 return PDMNETWORKLINKSTATE_UP;
791 return PDMNETWORKLINKSTATE_DOWN;
792}
793
794
795/**
796 * Sets the new link state.
797 *
798 * @returns VBox status code.
799 * @param pInterface Pointer to the interface structure containing the called function pointer.
800 * @param enmState The new link state
801 */
802static DECLCALLBACK(int) vnetSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
803{
804 VNETSTATE *pState = RT_FROM_MEMBER(pInterface, VNETSTATE, INetworkConfig);
805 bool fOldUp = !!(STATUS & VNET_S_LINK_UP);
806 bool fNewUp = enmState == PDMNETWORKLINKSTATE_UP;
807
808 if (fNewUp != fOldUp)
809 {
810 if (fNewUp)
811 {
812 Log(("%s Link is up\n", INSTANCE(pState)));
813 STATUS |= VNET_S_LINK_UP;
814 vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
815 }
816 else
817 {
818 Log(("%s Link is down\n", INSTANCE(pState)));
819 STATUS &= ~VNET_S_LINK_UP;
820 vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
821 }
822 if (pState->pDrv)
823 pState->pDrv->pfnNotifyLinkChanged(pState->pDrv, enmState);
824 }
825 return VINF_SUCCESS;
826}
827
828static DECLCALLBACK(void) vnetQueueReceive(void *pvState, PVQUEUE pQueue)
829{
830 VNETSTATE *pState = (VNETSTATE*)pvState;
831 Log(("%s Receive buffers has been added, waking up receive thread.\n", INSTANCE(pState)));
832 vnetWakeupReceive(pState->VPCI.CTX_SUFF(pDevIns));
833}
834
835static void vnetTransmitPendingPackets(PVNETSTATE pState, PVQUEUE pQueue, bool fOnWorkerThread)
836{
837 /*
838 * Only one thread is allowed to transmit at a time, others should skip
839 * transmission as the packets will be picked up by the transmitting
840 * thread.
841 */
842 if (!ASMAtomicCmpXchgU32(&pState->uIsTransmitting, 1, 0))
843 return;
844
845 if ((pState->VPCI.uStatus & VPCI_STATUS_DRV_OK) == 0)
846 {
847 Log(("%s Ignoring transmit requests from non-existent driver (status=0x%x).\n",
848 INSTANCE(pState), pState->VPCI.uStatus));
849 return;
850 }
851
852 PPDMINETWORKUP pDrv = pState->pDrv;
853 if (pDrv)
854 {
855 int rc = pDrv->pfnBeginXmit(pDrv, fOnWorkerThread);
856 Assert(rc == VINF_SUCCESS || rc == VERR_TRY_AGAIN);
857 if (rc == VERR_TRY_AGAIN)
858 {
859 ASMAtomicWriteU32(&pState->uIsTransmitting, 0);
860 return;
861 }
862 }
863
864 Log3(("%s vnetTransmitPendingPackets: About to trasmit %d pending packets\n", INSTANCE(pState),
865 vringReadAvailIndex(&pState->VPCI, &pState->pTxQueue->VRing) - pState->pTxQueue->uNextAvailIndex));
866
867 vpciSetWriteLed(&pState->VPCI, true);
868
869 VQUEUEELEM elem;
870 while (vqueueGet(&pState->VPCI, pQueue, &elem))
871 {
872 unsigned int uOffset = 0;
873 if (elem.nOut < 2 || elem.aSegsOut[0].cb != sizeof(VNETHDR))
874 {
875 Log(("%s vnetQueueTransmit: The first segment is not the header! (%u < 2 || %u != %u).\n",
876 INSTANCE(pState), elem.nOut, elem.aSegsOut[0].cb, sizeof(VNETHDR)));
877 break; /* For now we simply ignore the header, but it must be there anyway! */
878 }
879 else
880 {
881 STAM_PROFILE_ADV_START(&pState->StatTransmit, a);
882 /* Assemble a complete frame. */
883 for (unsigned int i = 1; i < elem.nOut && uOffset < VNET_MAX_FRAME_SIZE; i++)
884 {
885 unsigned int uSize = elem.aSegsOut[i].cb;
886 if (uSize > VNET_MAX_FRAME_SIZE - uOffset)
887 {
888 Log(("%s vnetQueueTransmit: Packet is too big (>64k), truncating...\n", INSTANCE(pState)));
889 uSize = VNET_MAX_FRAME_SIZE - uOffset;
890 }
891 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns), elem.aSegsOut[i].addr,
892 pState->pTxBuf + uOffset, uSize);
893 uOffset += uSize;
894 }
895 if (pState->pDrv)
896 {
897 vnetPacketDump(pState, pState->pTxBuf, uOffset, "--> Outgoing");
898
899 STAM_PROFILE_START(&pState->StatTransmitSend, a);
900
901 /** @todo Optimize away the extra copying! (lazy bird) */
902 PPDMSCATTERGATHER pSgBuf;
903 int rc = pState->pDrv->pfnAllocBuf(pState->pDrv, uOffset, NULL /*pGso*/, &pSgBuf);
904 if (RT_SUCCESS(rc))
905 {
906 Assert(pSgBuf->cSegs == 1);
907 memcpy(pSgBuf->aSegs[0].pvSeg, pState->pTxBuf, uOffset);
908 pSgBuf->cbUsed = uOffset;
909 rc = pState->pDrv->pfnSendBuf(pState->pDrv, pSgBuf, false);
910 }
911
912 STAM_PROFILE_STOP(&pState->StatTransmitSend, a);
913 STAM_REL_COUNTER_ADD(&pState->StatTransmitBytes, uOffset);
914 }
915 }
916 vqueuePut(&pState->VPCI, pQueue, &elem, sizeof(VNETHDR) + uOffset);
917 vqueueSync(&pState->VPCI, pQueue);
918 STAM_PROFILE_ADV_STOP(&pState->StatTransmit, a);
919 }
920 vpciSetWriteLed(&pState->VPCI, false);
921
922 if (pDrv)
923 pDrv->pfnEndXmit(pDrv);
924 ASMAtomicWriteU32(&pState->uIsTransmitting, 0);
925}
926
927/**
928 * @interface_method_impl{PDMINETWORKDOWN,pfnXmitPending}
929 */
930static DECLCALLBACK(void) vnetNetworkDown_XmitPending(PPDMINETWORKDOWN pInterface)
931{
932 VNETSTATE *pThis = RT_FROM_MEMBER(pInterface, VNETSTATE, INetworkDown);
933 vnetTransmitPendingPackets(pThis, pThis->pTxQueue, false /*fOnWorkerThread*/);
934}
935
936#ifdef VNET_TX_DELAY
937
938static DECLCALLBACK(void) vnetQueueTransmit(void *pvState, PVQUEUE pQueue)
939{
940 VNETSTATE *pState = (VNETSTATE*)pvState;
941
942 if (TMTimerIsActive(pState->CTX_SUFF(pTxTimer)))
943 {
944 int rc = TMTimerStop(pState->CTX_SUFF(pTxTimer));
945 Log3(("%s vnetQueueTransmit: Got kicked with notification disabled, "
946 "re-enable notification and flush TX queue\n", INSTANCE(pState)));
947 vnetTransmitPendingPackets(pState, pQueue, false /*fOnWorkerThread*/);
948 if (RT_FAILURE(vnetCsEnter(pState, VERR_SEM_BUSY)))
949 LogRel(("vnetQueueTransmit: Failed to enter critical section!/n"));
950 else
951 {
952 vringSetNotification(&pState->VPCI, &pState->pTxQueue->VRing, true);
953 vnetCsLeave(pState);
954 }
955 }
956 else
957 {
958 if (RT_FAILURE(vnetCsEnter(pState, VERR_SEM_BUSY)))
959 LogRel(("vnetQueueTransmit: Failed to enter critical section!/n"));
960 else
961 {
962 vringSetNotification(&pState->VPCI, &pState->pTxQueue->VRing, false);
963 TMTimerSetMicro(pState->CTX_SUFF(pTxTimer), VNET_TX_DELAY);
964 pState->u64NanoTS = RTTimeNanoTS();
965 vnetCsLeave(pState);
966 }
967 }
968}
969
970/**
971 * Transmit Delay Timer handler.
972 *
973 * @remarks We only get here when the timer expires.
974 *
975 * @param pDevIns Pointer to device instance structure.
976 * @param pTimer Pointer to the timer.
977 * @param pvUser NULL.
978 * @thread EMT
979 */
980static DECLCALLBACK(void) vnetTxTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
981{
982 VNETSTATE *pState = (VNETSTATE*)pvUser;
983
984 uint32_t u32MicroDiff = (uint32_t)((RTTimeNanoTS() - pState->u64NanoTS)/1000);
985 if (u32MicroDiff < pState->u32MinDiff)
986 pState->u32MinDiff = u32MicroDiff;
987 if (u32MicroDiff > pState->u32MaxDiff)
988 pState->u32MaxDiff = u32MicroDiff;
989 pState->u32AvgDiff = (pState->u32AvgDiff * pState->u32i + u32MicroDiff) / (pState->u32i + 1);
990 pState->u32i++;
991 Log3(("vnetTxTimer: Expired, diff %9d usec, avg %9d usec, min %9d usec, max %9d usec\n",
992 u32MicroDiff, pState->u32AvgDiff, pState->u32MinDiff, pState->u32MaxDiff));
993
994// Log3(("%s vnetTxTimer: Expired\n", INSTANCE(pState)));
995 vnetTransmitPendingPackets(pState, pState->pTxQueue, false /*fOnWorkerThread*/);
996 if (RT_FAILURE(vnetCsEnter(pState, VERR_SEM_BUSY)))
997 {
998 LogRel(("vnetTxTimer: Failed to enter critical section!/n"));
999 return;
1000 }
1001 vringSetNotification(&pState->VPCI, &pState->pTxQueue->VRing, true);
1002 vnetCsLeave(pState);
1003}
1004
1005#else /* !VNET_TX_DELAY */
1006
1007static DECLCALLBACK(void) vnetQueueTransmit(void *pvState, PVQUEUE pQueue)
1008{
1009 VNETSTATE *pState = (VNETSTATE*)pvState;
1010
1011 vnetTransmitPendingPackets(pState, pQueue, false /*fOnWorkerThread*/);
1012}
1013
1014#endif /* !VNET_TX_DELAY */
1015
1016static uint8_t vnetControlRx(PVNETSTATE pState, PVNETCTLHDR pCtlHdr, PVQUEUEELEM pElem)
1017{
1018 uint8_t u8Ack = VNET_OK;
1019 uint8_t fOn, fDrvWasPromisc = pState->fPromiscuous | pState->fAllMulti;
1020 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
1021 pElem->aSegsOut[1].addr,
1022 &fOn, sizeof(fOn));
1023 Log(("%s vnetControlRx: uCommand=%u fOn=%u\n", INSTANCE(pState), pCtlHdr->u8Command, fOn));
1024 switch (pCtlHdr->u8Command)
1025 {
1026 case VNET_CTRL_CMD_RX_MODE_PROMISC:
1027 pState->fPromiscuous = !!fOn;
1028 break;
1029 case VNET_CTRL_CMD_RX_MODE_ALLMULTI:
1030 pState->fAllMulti = !!fOn;
1031 break;
1032 default:
1033 u8Ack = VNET_ERROR;
1034 }
1035 if (fDrvWasPromisc != (pState->fPromiscuous | pState->fAllMulti) && pState->pDrv)
1036 pState->pDrv->pfnSetPromiscuousMode(pState->pDrv,
1037 (pState->fPromiscuous | pState->fAllMulti));
1038
1039 return u8Ack;
1040}
1041
1042static uint8_t vnetControlMac(PVNETSTATE pState, PVNETCTLHDR pCtlHdr, PVQUEUEELEM pElem)
1043{
1044 uint32_t nMacs = 0;
1045
1046 if (pCtlHdr->u8Command != VNET_CTRL_CMD_MAC_TABLE_SET
1047 || pElem->nOut != 3
1048 || pElem->aSegsOut[1].cb < sizeof(nMacs)
1049 || pElem->aSegsOut[2].cb < sizeof(nMacs))
1050 {
1051 Log(("%s vnetControlMac: Segment layout is wrong "
1052 "(u8Command=%u nOut=%u cb1=%u cb2=%u)\n", INSTANCE(pState),
1053 pCtlHdr->u8Command, pElem->nOut,
1054 pElem->aSegsOut[1].cb, pElem->aSegsOut[2].cb));
1055 return VNET_ERROR;
1056 }
1057
1058 /* Load unicast addresses */
1059 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
1060 pElem->aSegsOut[1].addr,
1061 &nMacs, sizeof(nMacs));
1062
1063 if (pElem->aSegsOut[1].cb < nMacs * sizeof(RTMAC) + sizeof(nMacs))
1064 {
1065 Log(("%s vnetControlMac: The unicast mac segment is too small "
1066 "(nMacs=%u cb=%u)\n", INSTANCE(pState), pElem->aSegsOut[1].cb));
1067 return VNET_ERROR;
1068 }
1069
1070 if (nMacs > VNET_MAC_FILTER_LEN)
1071 {
1072 Log(("%s vnetControlMac: MAC table is too big, have to use promiscuous"
1073 " mode (nMacs=%u)\n", INSTANCE(pState), nMacs));
1074 pState->fPromiscuous = true;
1075 }
1076 else
1077 {
1078 if (nMacs)
1079 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
1080 pElem->aSegsOut[1].addr + sizeof(nMacs),
1081 pState->aMacFilter, nMacs * sizeof(RTMAC));
1082 pState->nMacFilterEntries = nMacs;
1083#ifdef DEBUG
1084 Log(("%s vnetControlMac: unicast macs:\n", INSTANCE(pState)));
1085 for(unsigned i = 0; i < nMacs; i++)
1086 Log((" %RTmac\n", &pState->aMacFilter[i]));
1087#endif /* DEBUG */
1088 }
1089
1090 /* Load multicast addresses */
1091 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
1092 pElem->aSegsOut[2].addr,
1093 &nMacs, sizeof(nMacs));
1094
1095 if (pElem->aSegsOut[2].cb < nMacs * sizeof(RTMAC) + sizeof(nMacs))
1096 {
1097 Log(("%s vnetControlMac: The multicast mac segment is too small "
1098 "(nMacs=%u cb=%u)\n", INSTANCE(pState), pElem->aSegsOut[2].cb));
1099 return VNET_ERROR;
1100 }
1101
1102 if (nMacs > VNET_MAC_FILTER_LEN - pState->nMacFilterEntries)
1103 {
1104 Log(("%s vnetControlMac: MAC table is too big, have to use allmulti"
1105 " mode (nMacs=%u)\n", INSTANCE(pState), nMacs));
1106 pState->fAllMulti = true;
1107 }
1108 else
1109 {
1110 if (nMacs)
1111 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
1112 pElem->aSegsOut[2].addr + sizeof(nMacs),
1113 &pState->aMacFilter[pState->nMacFilterEntries],
1114 nMacs * sizeof(RTMAC));
1115#ifdef DEBUG
1116 Log(("%s vnetControlMac: multicast macs:\n", INSTANCE(pState)));
1117 for(unsigned i = 0; i < nMacs; i++)
1118 Log((" %RTmac\n",
1119 &pState->aMacFilter[i+pState->nMacFilterEntries]));
1120#endif /* DEBUG */
1121 pState->nMacFilterEntries += nMacs;
1122 }
1123
1124 return VNET_OK;
1125}
1126
1127static uint8_t vnetControlVlan(PVNETSTATE pState, PVNETCTLHDR pCtlHdr, PVQUEUEELEM pElem)
1128{
1129 uint8_t u8Ack = VNET_OK;
1130 uint16_t u16Vid;
1131
1132 if (pElem->nOut != 2 || pElem->aSegsOut[1].cb != sizeof(u16Vid))
1133 {
1134 Log(("%s vnetControlVlan: Segment layout is wrong "
1135 "(u8Command=%u nOut=%u cb=%u)\n", INSTANCE(pState),
1136 pCtlHdr->u8Command, pElem->nOut, pElem->aSegsOut[1].cb));
1137 return VNET_ERROR;
1138 }
1139
1140 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
1141 pElem->aSegsOut[1].addr,
1142 &u16Vid, sizeof(u16Vid));
1143
1144 if (u16Vid >= VNET_MAX_VID)
1145 {
1146 Log(("%s vnetControlVlan: VLAN ID is out of range "
1147 "(VID=%u)\n", INSTANCE(pState), u16Vid));
1148 return VNET_ERROR;
1149 }
1150
1151 Log(("%s vnetControlVlan: uCommand=%u VID=%u\n", INSTANCE(pState),
1152 pCtlHdr->u8Command, u16Vid));
1153
1154 switch (pCtlHdr->u8Command)
1155 {
1156 case VNET_CTRL_CMD_VLAN_ADD:
1157 ASMBitSet(pState->aVlanFilter, u16Vid);
1158 break;
1159 case VNET_CTRL_CMD_VLAN_DEL:
1160 ASMBitClear(pState->aVlanFilter, u16Vid);
1161 break;
1162 default:
1163 u8Ack = VNET_ERROR;
1164 }
1165
1166 return u8Ack;
1167}
1168
1169
1170static DECLCALLBACK(void) vnetQueueControl(void *pvState, PVQUEUE pQueue)
1171{
1172 VNETSTATE *pState = (VNETSTATE*)pvState;
1173 uint8_t u8Ack;
1174 VQUEUEELEM elem;
1175 while (vqueueGet(&pState->VPCI, pQueue, &elem))
1176 {
1177 unsigned int uOffset = 0;
1178 if (elem.nOut < 1 || elem.aSegsOut[0].cb < sizeof(VNETCTLHDR))
1179 {
1180 Log(("%s vnetQueueControl: The first 'out' segment is not the "
1181 "header! (%u < 1 || %u < %u).\n", INSTANCE(pState), elem.nOut,
1182 elem.aSegsOut[0].cb,sizeof(VNETCTLHDR)));
1183 break; /* Skip the element and hope the next one is good. */
1184 }
1185 else if ( elem.nIn < 1
1186 || elem.aSegsIn[elem.nIn - 1].cb < sizeof(VNETCTLACK))
1187 {
1188 Log(("%s vnetQueueControl: The last 'in' segment is too small "
1189 "to hold the acknowledge! (%u < 1 || %u < %u).\n",
1190 INSTANCE(pState), elem.nIn, elem.aSegsIn[elem.nIn - 1].cb,
1191 sizeof(VNETCTLACK)));
1192 break; /* Skip the element and hope the next one is good. */
1193 }
1194 else
1195 {
1196 VNETCTLHDR CtlHdr;
1197 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
1198 elem.aSegsOut[0].addr,
1199 &CtlHdr, sizeof(CtlHdr));
1200 switch (CtlHdr.u8Class)
1201 {
1202 case VNET_CTRL_CLS_RX_MODE:
1203 u8Ack = vnetControlRx(pState, &CtlHdr, &elem);
1204 break;
1205 case VNET_CTRL_CLS_MAC:
1206 u8Ack = vnetControlMac(pState, &CtlHdr, &elem);
1207 break;
1208 case VNET_CTRL_CLS_VLAN:
1209 u8Ack = vnetControlVlan(pState, &CtlHdr, &elem);
1210 break;
1211 default:
1212 u8Ack = VNET_ERROR;
1213 }
1214 Log(("%s Processed control message %u, ack=%u.\n", INSTANCE(pState),
1215 CtlHdr.u8Class, u8Ack));
1216 PDMDevHlpPhysWrite(pState->VPCI.CTX_SUFF(pDevIns),
1217 elem.aSegsIn[elem.nIn - 1].addr,
1218 &u8Ack, sizeof(u8Ack));
1219 }
1220 vqueuePut(&pState->VPCI, pQueue, &elem, sizeof(u8Ack));
1221 vqueueSync(&pState->VPCI, pQueue);
1222 }
1223}
1224
1225/**
1226 * Saves the configuration.
1227 *
1228 * @param pState The VNET state.
1229 * @param pSSM The handle to the saved state.
1230 */
1231static void vnetSaveConfig(VNETSTATE *pState, PSSMHANDLE pSSM)
1232{
1233 SSMR3PutMem(pSSM, &pState->macConfigured, sizeof(pState->macConfigured));
1234}
1235
1236/**
1237 * Live save - save basic configuration.
1238 *
1239 * @returns VBox status code.
1240 * @param pDevIns The device instance.
1241 * @param pSSM The handle to the saved state.
1242 * @param uPass
1243 */
1244static DECLCALLBACK(int) vnetLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
1245{
1246 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1247 vnetSaveConfig(pState, pSSM);
1248 return VINF_SSM_DONT_CALL_AGAIN;
1249}
1250
1251/**
1252 * Prepares for state saving.
1253 *
1254 * @returns VBox status code.
1255 * @param pDevIns The device instance.
1256 * @param pSSM The handle to the saved state.
1257 */
1258static DECLCALLBACK(int) vnetSavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1259{
1260 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1261
1262 int rc = vnetCsRxEnter(pState, VERR_SEM_BUSY);
1263 if (RT_UNLIKELY(rc != VINF_SUCCESS))
1264 return rc;
1265 vnetCsRxLeave(pState);
1266 return VINF_SUCCESS;
1267}
1268
1269/**
1270 * Saves the state of device.
1271 *
1272 * @returns VBox status code.
1273 * @param pDevIns The device instance.
1274 * @param pSSM The handle to the saved state.
1275 */
1276static DECLCALLBACK(int) vnetSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1277{
1278 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1279
1280 /* Save config first */
1281 vnetSaveConfig(pState, pSSM);
1282
1283 /* Save the common part */
1284 int rc = vpciSaveExec(&pState->VPCI, pSSM);
1285 AssertRCReturn(rc, rc);
1286 /* Save device-specific part */
1287 rc = SSMR3PutMem( pSSM, pState->config.mac.au8, sizeof(pState->config.mac));
1288 AssertRCReturn(rc, rc);
1289 rc = SSMR3PutBool(pSSM, pState->fPromiscuous);
1290 AssertRCReturn(rc, rc);
1291 rc = SSMR3PutBool(pSSM, pState->fAllMulti);
1292 AssertRCReturn(rc, rc);
1293 rc = SSMR3PutU32( pSSM, pState->nMacFilterEntries);
1294 AssertRCReturn(rc, rc);
1295 rc = SSMR3PutMem( pSSM, pState->aMacFilter,
1296 pState->nMacFilterEntries * sizeof(RTMAC));
1297 AssertRCReturn(rc, rc);
1298 rc = SSMR3PutMem( pSSM, pState->aVlanFilter, sizeof(pState->aVlanFilter));
1299 AssertRCReturn(rc, rc);
1300 Log(("%s State has been saved\n", INSTANCE(pState)));
1301 return VINF_SUCCESS;
1302}
1303
1304
1305/**
1306 * Serializes the receive thread, it may be working inside the critsect.
1307 *
1308 * @returns VBox status code.
1309 * @param pDevIns The device instance.
1310 * @param pSSM The handle to the saved state.
1311 */
1312static DECLCALLBACK(int) vnetLoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1313{
1314 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1315
1316 int rc = vnetCsRxEnter(pState, VERR_SEM_BUSY);
1317 if (RT_UNLIKELY(rc != VINF_SUCCESS))
1318 return rc;
1319 vnetCsRxLeave(pState);
1320 return VINF_SUCCESS;
1321}
1322
1323/**
1324 * Takes down the link temporarily if it's current status is up.
1325 *
1326 * This is used during restore and when replumbing the network link.
1327 *
1328 * The temporary link outage is supposed to indicate to the OS that all network
1329 * connections have been lost and that it for instance is appropriate to
1330 * renegotiate any DHCP lease.
1331 *
1332 * @param pThis The PCNet instance data.
1333 */
1334static void vnetTempLinkDown(PVNETSTATE pState)
1335{
1336 if (STATUS & VNET_S_LINK_UP)
1337 {
1338 STATUS &= ~VNET_S_LINK_UP;
1339 vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
1340 /* Restore the link back in 5 seconds. */
1341 int rc = TMTimerSetMillies(pState->pLinkUpTimer, 5000);
1342 AssertRC(rc);
1343 }
1344}
1345
1346
1347/**
1348 * Restore previously saved state of device.
1349 *
1350 * @returns VBox status code.
1351 * @param pDevIns The device instance.
1352 * @param pSSM The handle to the saved state.
1353 * @param uVersion The data unit version number.
1354 * @param uPass The data pass.
1355 */
1356static DECLCALLBACK(int) vnetLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1357{
1358 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1359 int rc;
1360
1361 /* config checks */
1362 RTMAC macConfigured;
1363 rc = SSMR3GetMem(pSSM, &macConfigured, sizeof(macConfigured));
1364 AssertRCReturn(rc, rc);
1365 if (memcmp(&macConfigured, &pState->macConfigured, sizeof(macConfigured))
1366 && (uPass == 0 || !PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns)))
1367 LogRel(("%s: The mac address differs: config=%RTmac saved=%RTmac\n", INSTANCE(pState), &pState->macConfigured, &macConfigured));
1368
1369 rc = vpciLoadExec(&pState->VPCI, pSSM, uVersion, uPass, VNET_N_QUEUES);
1370 AssertRCReturn(rc, rc);
1371
1372 if (uPass == SSM_PASS_FINAL)
1373 {
1374 rc = SSMR3GetMem( pSSM, pState->config.mac.au8,
1375 sizeof(pState->config.mac));
1376 AssertRCReturn(rc, rc);
1377 if (uVersion > VIRTIO_SAVEDSTATE_VERSION_3_1_BETA1)
1378 {
1379 rc = SSMR3GetBool(pSSM, &pState->fPromiscuous);
1380 AssertRCReturn(rc, rc);
1381 rc = SSMR3GetBool(pSSM, &pState->fAllMulti);
1382 AssertRCReturn(rc, rc);
1383 rc = SSMR3GetU32(pSSM, &pState->nMacFilterEntries);
1384 AssertRCReturn(rc, rc);
1385 rc = SSMR3GetMem(pSSM, pState->aMacFilter,
1386 pState->nMacFilterEntries * sizeof(RTMAC));
1387 AssertRCReturn(rc, rc);
1388 /* Clear the rest. */
1389 if (pState->nMacFilterEntries < VNET_MAC_FILTER_LEN)
1390 memset(&pState->aMacFilter[pState->nMacFilterEntries],
1391 0,
1392 (VNET_MAC_FILTER_LEN - pState->nMacFilterEntries)
1393 * sizeof(RTMAC));
1394 rc = SSMR3GetMem(pSSM, pState->aVlanFilter,
1395 sizeof(pState->aVlanFilter));
1396 AssertRCReturn(rc, rc);
1397 }
1398 else
1399 {
1400 pState->fPromiscuous = true;
1401 pState->fAllMulti = false;
1402 pState->nMacFilterEntries = 0;
1403 memset(pState->aMacFilter, 0, VNET_MAC_FILTER_LEN * sizeof(RTMAC));
1404 memset(pState->aVlanFilter, 0, sizeof(pState->aVlanFilter));
1405 if (pState->pDrv)
1406 pState->pDrv->pfnSetPromiscuousMode(pState->pDrv, true);
1407 }
1408 }
1409
1410 return rc;
1411}
1412
1413/**
1414 * Link status adjustments after loading.
1415 *
1416 * @returns VBox status code.
1417 * @param pDevIns The device instance.
1418 * @param pSSM The handle to the saved state.
1419 */
1420static DECLCALLBACK(int) vnetLoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1421{
1422 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1423
1424 if (pState->pDrv)
1425 pState->pDrv->pfnSetPromiscuousMode(pState->pDrv,
1426 (pState->fPromiscuous | pState->fAllMulti));
1427 /*
1428 * Indicate link down to the guest OS that all network connections have
1429 * been lost, unless we've been teleported here.
1430 */
1431 if (!PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns))
1432 vnetTempLinkDown(pState);
1433
1434 return VINF_SUCCESS;
1435}
1436
1437/**
1438 * Map PCI I/O region.
1439 *
1440 * @return VBox status code.
1441 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
1442 * @param iRegion The region number.
1443 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
1444 * I/O port, else it's a physical address.
1445 * This address is *NOT* relative to pci_mem_base like earlier!
1446 * @param cb Region size.
1447 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
1448 * @thread EMT
1449 */
1450static DECLCALLBACK(int) vnetMap(PPCIDEVICE pPciDev, int iRegion,
1451 RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
1452{
1453 int rc;
1454 VNETSTATE *pState = PDMINS_2_DATA(pPciDev->pDevIns, VNETSTATE*);
1455
1456 if (enmType != PCI_ADDRESS_SPACE_IO)
1457 {
1458 /* We should never get here */
1459 AssertMsgFailed(("Invalid PCI address space param in map callback"));
1460 return VERR_INTERNAL_ERROR;
1461 }
1462
1463 pState->VPCI.addrIOPort = (RTIOPORT)GCPhysAddress;
1464 rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns, pState->VPCI.addrIOPort,
1465 cb, 0, vnetIOPortOut, vnetIOPortIn,
1466 NULL, NULL, "VirtioNet");
1467#ifdef VNET_GC_SUPPORT
1468 AssertRCReturn(rc, rc);
1469 rc = PDMDevHlpIOPortRegisterR0(pPciDev->pDevIns, pState->VPCI.addrIOPort,
1470 cb, 0, "vnetIOPortOut", "vnetIOPortIn",
1471 NULL, NULL, "VirtioNet");
1472 AssertRCReturn(rc, rc);
1473 rc = PDMDevHlpIOPortRegisterRC(pPciDev->pDevIns, pState->VPCI.addrIOPort,
1474 cb, 0, "vnetIOPortOut", "vnetIOPortIn",
1475 NULL, NULL, "VirtioNet");
1476#endif
1477 AssertRC(rc);
1478 return rc;
1479}
1480
1481/* -=-=-=-=- PDMDEVREG -=-=-=-=- */
1482
1483#ifdef VBOX_DYNAMIC_NET_ATTACH
1484
1485/**
1486 * Detach notification.
1487 *
1488 * One port on the network card has been disconnected from the network.
1489 *
1490 * @param pDevIns The device instance.
1491 * @param iLUN The logical unit which is being detached.
1492 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1493 */
1494static DECLCALLBACK(void) vnetDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1495{
1496 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1497 Log(("%s vnetDetach:\n", INSTANCE(pState)));
1498
1499 AssertLogRelReturnVoid(iLUN == 0);
1500
1501 int rc = vnetCsEnter(pState, VERR_SEM_BUSY);
1502 if (RT_FAILURE(rc))
1503 {
1504 LogRel(("vnetDetach failed to enter critical section!\n"));
1505 return;
1506 }
1507
1508 /*
1509 * Zero some important members.
1510 */
1511 pState->pDrvBase = NULL;
1512 pState->pDrv = NULL;
1513
1514 vnetCsLeave(pState);
1515}
1516
1517
1518/**
1519 * Attach the Network attachment.
1520 *
1521 * One port on the network card has been connected to a network.
1522 *
1523 * @returns VBox status code.
1524 * @param pDevIns The device instance.
1525 * @param iLUN The logical unit which is being attached.
1526 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1527 *
1528 * @remarks This code path is not used during construction.
1529 */
1530static DECLCALLBACK(int) vnetAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1531{
1532 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1533 LogFlow(("%s vnetAttach:\n", INSTANCE(pState)));
1534
1535 AssertLogRelReturn(iLUN == 0, VERR_PDM_NO_SUCH_LUN);
1536
1537 int rc = vnetCsEnter(pState, VERR_SEM_BUSY);
1538 if (RT_FAILURE(rc))
1539 {
1540 LogRel(("vnetAttach failed to enter critical section!\n"));
1541 return rc;
1542 }
1543
1544 /*
1545 * Attach the driver.
1546 */
1547 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pState->VPCI.IBase, &pState->pDrvBase, "Network Port");
1548 if (RT_SUCCESS(rc))
1549 {
1550 if (rc == VINF_NAT_DNS)
1551 {
1552#ifdef RT_OS_LINUX
1553 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
1554 N_("A Domain Name Server (DNS) for NAT networking could not be determined. Please check your /etc/resolv.conf for <tt>nameserver</tt> entries. Either add one manually (<i>man resolv.conf</i>) or ensure that your host is correctly connected to an ISP. If you ignore this warning the guest will not be able to perform nameserver lookups and it will probably observe delays if trying so"));
1555#else
1556 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
1557 N_("A Domain Name Server (DNS) for NAT networking could not be determined. Ensure that your host is correctly connected to an ISP. If you ignore this warning the guest will not be able to perform nameserver lookups and it will probably observe delays if trying so"));
1558#endif
1559 }
1560 pState->pDrv = PDMIBASE_QUERY_INTERFACE(pState->pDrvBase, PDMINETWORKUP);
1561 AssertMsgStmt(pState->pDrv, ("Failed to obtain the PDMINETWORKUP interface!\n"),
1562 rc = VERR_PDM_MISSING_INTERFACE_BELOW);
1563 }
1564 else if ( rc == VERR_PDM_NO_ATTACHED_DRIVER
1565 || rc == VERR_PDM_CFG_MISSING_DRIVER_NAME)
1566 {
1567 /* This should never happen because this function is not called
1568 * if there is no driver to attach! */
1569 Log(("%s No attached driver!\n", INSTANCE(pState)));
1570 }
1571
1572 /*
1573 * Temporary set the link down if it was up so that the guest
1574 * will know that we have change the configuration of the
1575 * network card
1576 */
1577 if (RT_SUCCESS(rc))
1578 vnetTempLinkDown(pState);
1579
1580 vnetCsLeave(pState);
1581 return rc;
1582
1583}
1584
1585#endif /* VBOX_DYNAMIC_NET_ATTACH */
1586
1587/**
1588 * @copydoc FNPDMDEVSUSPEND
1589 */
1590static DECLCALLBACK(void) vnetSuspend(PPDMDEVINS pDevIns)
1591{
1592 /* Poke thread waiting for buffer space. */
1593 vnetWakeupReceive(pDevIns);
1594}
1595
1596/**
1597 * @copydoc FNPDMDEVPOWEROFF
1598 */
1599static DECLCALLBACK(void) vnetPowerOff(PPDMDEVINS pDevIns)
1600{
1601 /* Poke thread waiting for buffer space. */
1602 vnetWakeupReceive(pDevIns);
1603}
1604
1605/**
1606 * Device relocation callback.
1607 *
1608 * When this callback is called the device instance data, and if the
1609 * device have a GC component, is being relocated, or/and the selectors
1610 * have been changed. The device must use the chance to perform the
1611 * necessary pointer relocations and data updates.
1612 *
1613 * Before the GC code is executed the first time, this function will be
1614 * called with a 0 delta so GC pointer calculations can be one in one place.
1615 *
1616 * @param pDevIns Pointer to the device instance.
1617 * @param offDelta The relocation delta relative to the old location.
1618 *
1619 * @remark A relocation CANNOT fail.
1620 */
1621static DECLCALLBACK(void) vnetRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1622{
1623 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1624 vpciRelocate(pDevIns, offDelta);
1625 pState->pCanRxQueueRC = PDMQueueRCPtr(pState->pCanRxQueueR3);
1626#ifdef VNET_TX_DELAY
1627 pState->pTxTimerRC = TMTimerRCPtr(pState->pTxTimerR3);
1628#endif /* VNET_TX_DELAY */
1629 // TBD
1630}
1631
1632/**
1633 * Destruct a device instance.
1634 *
1635 * We need to free non-VM resources only.
1636 *
1637 * @returns VBox status.
1638 * @param pDevIns The device instance data.
1639 * @thread EMT
1640 */
1641static DECLCALLBACK(int) vnetDestruct(PPDMDEVINS pDevIns)
1642{
1643 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1644 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
1645
1646 LogRel(("TxTimer stats (avg/min/max): %7d usec %7d usec %7d usec\n",
1647 pState->u32AvgDiff, pState->u32MinDiff, pState->u32MaxDiff));
1648 Log(("%s Destroying instance\n", INSTANCE(pState)));
1649 if (pState->hEventMoreRxDescAvail != NIL_RTSEMEVENT)
1650 {
1651 RTSemEventSignal(pState->hEventMoreRxDescAvail);
1652 RTSemEventDestroy(pState->hEventMoreRxDescAvail);
1653 pState->hEventMoreRxDescAvail = NIL_RTSEMEVENT;
1654 }
1655
1656 if (pState->pTxBuf)
1657 {
1658 RTMemFree(pState->pTxBuf);
1659 pState->pTxBuf = NULL;
1660 }
1661 // if (PDMCritSectIsInitialized(&pState->csRx))
1662 // PDMR3CritSectDelete(&pState->csRx);
1663
1664 return vpciDestruct(&pState->VPCI);
1665}
1666
1667/**
1668 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1669 */
1670static DECLCALLBACK(int) vnetConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1671{
1672 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1673 int rc;
1674 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1675
1676 /* Initialize PCI part first. */
1677 pState->VPCI.IBase.pfnQueryInterface = vnetQueryInterface;
1678 rc = vpciConstruct(pDevIns, &pState->VPCI, iInstance,
1679 VNET_NAME_FMT, VNET_PCI_SUBSYSTEM_ID,
1680 VNET_PCI_CLASS, VNET_N_QUEUES);
1681 pState->pRxQueue = vpciAddQueue(&pState->VPCI, 256, vnetQueueReceive, "RX ");
1682 pState->pTxQueue = vpciAddQueue(&pState->VPCI, 256, vnetQueueTransmit, "TX ");
1683 pState->pCtlQueue = vpciAddQueue(&pState->VPCI, 16, vnetQueueControl, "CTL");
1684
1685 Log(("%s Constructing new instance\n", INSTANCE(pState)));
1686
1687 pState->hEventMoreRxDescAvail = NIL_RTSEMEVENT;
1688
1689 /*
1690 * Validate configuration.
1691 */
1692 if (!CFGMR3AreValuesValid(pCfg, "MAC\0" "CableConnected\0" "LineSpeed\0"))
1693 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
1694 N_("Invalid configuration for VirtioNet device"));
1695
1696 /* Get config params */
1697 rc = CFGMR3QueryBytes(pCfg, "MAC", pState->macConfigured.au8,
1698 sizeof(pState->macConfigured));
1699 if (RT_FAILURE(rc))
1700 return PDMDEV_SET_ERROR(pDevIns, rc,
1701 N_("Configuration error: Failed to get MAC address"));
1702 rc = CFGMR3QueryBool(pCfg, "CableConnected", &pState->fCableConnected);
1703 if (RT_FAILURE(rc))
1704 return PDMDEV_SET_ERROR(pDevIns, rc,
1705 N_("Configuration error: Failed to get the value of 'CableConnected'"));
1706
1707 /* Initialize PCI config space */
1708 memcpy(pState->config.mac.au8, pState->macConfigured.au8, sizeof(pState->config.mac.au8));
1709 pState->config.uStatus = 0;
1710
1711 /* Initialize state structure */
1712 pState->u32PktNo = 1;
1713
1714 /* Interfaces */
1715 pState->INetworkDown.pfnWaitReceiveAvail = vnetNetworkDown_WaitReceiveAvail;
1716 pState->INetworkDown.pfnReceive = vnetNetworkDown_Receive;
1717 pState->INetworkDown.pfnXmitPending = vnetNetworkDown_XmitPending;
1718
1719 pState->INetworkConfig.pfnGetMac = vnetGetMac;
1720 pState->INetworkConfig.pfnGetLinkState = vnetGetLinkState;
1721 pState->INetworkConfig.pfnSetLinkState = vnetSetLinkState;
1722
1723 pState->pTxBuf = (uint8_t *)RTMemAllocZ(VNET_MAX_FRAME_SIZE);
1724 AssertMsgReturn(pState->pTxBuf,
1725 ("Cannot allocate TX buffer for virtio-net device\n"), VERR_NO_MEMORY);
1726
1727 /* Initialize critical section. */
1728 // char szTmp[sizeof(pState->VPCI.szInstance) + 2];
1729 // RTStrPrintf(szTmp, sizeof(szTmp), "%sRX", pState->VPCI.szInstance);
1730 // rc = PDMDevHlpCritSectInit(pDevIns, &pState->csRx, szTmp);
1731 // if (RT_FAILURE(rc))
1732 // return rc;
1733
1734 /* Map our ports to IO space. */
1735 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0,
1736 VPCI_CONFIG + sizeof(VNetPCIConfig),
1737 PCI_ADDRESS_SPACE_IO, vnetMap);
1738 if (RT_FAILURE(rc))
1739 return rc;
1740
1741
1742 /* Register save/restore state handlers. */
1743 rc = PDMDevHlpSSMRegisterEx(pDevIns, VIRTIO_SAVEDSTATE_VERSION, sizeof(VNETSTATE), NULL,
1744 NULL, vnetLiveExec, NULL,
1745 vnetSavePrep, vnetSaveExec, NULL,
1746 vnetLoadPrep, vnetLoadExec, vnetLoadDone);
1747 if (RT_FAILURE(rc))
1748 return rc;
1749
1750 /* Create the RX notifier signaller. */
1751 rc = PDMDevHlpQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 1, 0,
1752 vnetCanRxQueueConsumer, true, "VNet-Rcv", &pState->pCanRxQueueR3);
1753 if (RT_FAILURE(rc))
1754 return rc;
1755 pState->pCanRxQueueR0 = PDMQueueR0Ptr(pState->pCanRxQueueR3);
1756 pState->pCanRxQueueRC = PDMQueueRCPtr(pState->pCanRxQueueR3);
1757
1758 /* Create Link Up Timer */
1759 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, vnetLinkUpTimer, pState,
1760 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, /** @todo check locking here. */
1761 "VirtioNet Link Up Timer", &pState->pLinkUpTimer);
1762 if (RT_FAILURE(rc))
1763 return rc;
1764
1765#ifdef VNET_TX_DELAY
1766 /* Create Transmit Delay Timer */
1767 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, vnetTxTimer, pState,
1768 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, /** @todo check locking here. */
1769 "VirtioNet TX Delay Timer", &pState->pTxTimerR3);
1770 if (RT_FAILURE(rc))
1771 return rc;
1772 pState->pTxTimerR0 = TMTimerR0Ptr(pState->pTxTimerR3);
1773 pState->pTxTimerRC = TMTimerRCPtr(pState->pTxTimerR3);
1774
1775 pState->u32i = pState->u32AvgDiff = pState->u32MaxDiff = 0;
1776 pState->u32MinDiff = ~0;
1777#endif /* VNET_TX_DELAY */
1778
1779 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pState->VPCI.IBase, &pState->pDrvBase, "Network Port");
1780 if (RT_SUCCESS(rc))
1781 {
1782 if (rc == VINF_NAT_DNS)
1783 {
1784 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
1785 N_("A Domain Name Server (DNS) for NAT networking could not be determined. Ensure that your host is correctly connected to an ISP. If you ignore this warning the guest will not be able to perform nameserver lookups and it will probably observe delays if trying so"));
1786 }
1787 pState->pDrv = PDMIBASE_QUERY_INTERFACE(pState->pDrvBase, PDMINETWORKUP);
1788 AssertMsgReturn(pState->pDrv, ("Failed to obtain the PDMINETWORKUP interface!\n"),
1789 VERR_PDM_MISSING_INTERFACE_BELOW);
1790 }
1791 else if ( rc == VERR_PDM_NO_ATTACHED_DRIVER
1792 || rc == VERR_PDM_CFG_MISSING_DRIVER_NAME )
1793 {
1794 /* No error! */
1795 Log(("%s This adapter is not attached to any network!\n", INSTANCE(pState)));
1796 }
1797 else
1798 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach the network LUN"));
1799
1800 rc = RTSemEventCreate(&pState->hEventMoreRxDescAvail);
1801 if (RT_FAILURE(rc))
1802 return rc;
1803
1804 rc = vnetReset(pState);
1805 AssertRC(rc);
1806
1807 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceiveBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data received", "/Devices/VNet%d/ReceiveBytes", iInstance);
1808 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data transmitted", "/Devices/VNet%d/TransmitBytes", iInstance);
1809#if defined(VBOX_WITH_STATISTICS)
1810 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive", "/Devices/VNet%d/Receive/Total", iInstance);
1811 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceiveStore, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive storing", "/Devices/VNet%d/Receive/Store", iInstance);
1812 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatRxOverflow, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, "Profiling RX overflows", "/Devices/VNet%d/RxOverflow", iInstance);
1813 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatRxOverflowWakeup, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of RX overflow wakeups", "/Devices/VNet%d/RxOverflowWakeup", iInstance);
1814 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling transmits in HC", "/Devices/VNet%d/Transmit/Total", iInstance);
1815 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitSend, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling send transmit in HC", "/Devices/VNet%d/Transmit/Send", iInstance);
1816#endif /* VBOX_WITH_STATISTICS */
1817
1818 return VINF_SUCCESS;
1819}
1820
1821/**
1822 * The device registration structure.
1823 */
1824const PDMDEVREG g_DeviceVirtioNet =
1825{
1826 /* Structure version. PDM_DEVREG_VERSION defines the current version. */
1827 PDM_DEVREG_VERSION,
1828 /* Device name. */
1829 "virtio-net",
1830 /* Name of guest context module (no path).
1831 * Only evalutated if PDM_DEVREG_FLAGS_RC is set. */
1832 "VBoxDDGC.gc",
1833 /* Name of ring-0 module (no path).
1834 * Only evalutated if PDM_DEVREG_FLAGS_RC is set. */
1835 "VBoxDDR0.r0",
1836 /* The description of the device. The UTF-8 string pointed to shall, like this structure,
1837 * remain unchanged from registration till VM destruction. */
1838 "Virtio Ethernet.\n",
1839
1840 /* Flags, combination of the PDM_DEVREG_FLAGS_* \#defines. */
1841#ifdef VNET_GC_SUPPORT
1842 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
1843#else
1844 PDM_DEVREG_FLAGS_DEFAULT_BITS,
1845#endif
1846 /* Device class(es), combination of the PDM_DEVREG_CLASS_* \#defines. */
1847 PDM_DEVREG_CLASS_NETWORK,
1848 /* Maximum number of instances (per VM). */
1849 8,
1850 /* Size of the instance data. */
1851 sizeof(VNETSTATE),
1852
1853 /* Construct instance - required. */
1854 vnetConstruct,
1855 /* Destruct instance - optional. */
1856 vnetDestruct,
1857 /* Relocation command - optional. */
1858 vnetRelocate,
1859 /* I/O Control interface - optional. */
1860 NULL,
1861 /* Power on notification - optional. */
1862 NULL,
1863 /* Reset notification - optional. */
1864 NULL,
1865 /* Suspend notification - optional. */
1866 vnetSuspend,
1867 /* Resume notification - optional. */
1868 NULL,
1869#ifdef VBOX_DYNAMIC_NET_ATTACH
1870 /* Attach command - optional. */
1871 vnetAttach,
1872 /* Detach notification - optional. */
1873 vnetDetach,
1874#else /* !VBOX_DYNAMIC_NET_ATTACH */
1875 /* Attach command - optional. */
1876 NULL,
1877 /* Detach notification - optional. */
1878 NULL,
1879#endif /* !VBOX_DYNAMIC_NET_ATTACH */
1880 /* Query a LUN base interface - optional. */
1881 NULL,
1882 /* Init complete notification - optional. */
1883 NULL,
1884 /* Power off notification - optional. */
1885 vnetPowerOff,
1886 /* pfnSoftReset */
1887 NULL,
1888 /* u32VersionEnd */
1889 PDM_DEVREG_VERSION
1890};
1891
1892#endif /* IN_RING3 */
1893#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
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