VirtualBox

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

Last change on this file since 41809 was 41809, checked in by vboxsync, 12 years ago

virtio: netshaper support (#5582)

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