VirtualBox

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

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

Automated rebranding to Oracle copyright/license strings via filemuncher

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