VirtualBox

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

Last change on this file since 41783 was 41409, checked in by vboxsync, 13 years ago

Network: renamed uLinkUpDelay to cMsLinkUpDelay

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 75.3 KB
Line 
1/* $Id: DevVirtioNet.cpp 41409 2012-05-22 18:12:28Z 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 while (vqueueGet(&pState->VPCI, pQueue, &elem))
1077 {
1078 unsigned int uOffset = 0;
1079 if (elem.nOut < 2 || elem.aSegsOut[0].cb != uHdrLen)
1080 {
1081 Log(("%s vnetQueueTransmit: The first segment is not the header! (%u < 2 || %u != %u).\n",
1082 INSTANCE(pState), elem.nOut, elem.aSegsOut[0].cb, uHdrLen));
1083 break; /* For now we simply ignore the header, but it must be there anyway! */
1084 }
1085 else
1086 {
1087 unsigned int uSize = 0;
1088 STAM_PROFILE_ADV_START(&pState->StatTransmit, a);
1089 /* Compute total frame size. */
1090 for (unsigned int i = 1; i < elem.nOut; i++)
1091 uSize += elem.aSegsOut[i].cb;
1092 Assert(uSize <= VNET_MAX_FRAME_SIZE);
1093 if (pState->pDrv)
1094 {
1095 VNETHDR Hdr;
1096 PDMNETWORKGSO Gso, *pGso;
1097
1098 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns), elem.aSegsOut[0].addr,
1099 &Hdr, sizeof(Hdr));
1100
1101 STAM_REL_COUNTER_INC(&pState->StatTransmitPackets);
1102
1103 STAM_PROFILE_START(&pState->StatTransmitSend, a);
1104
1105 pGso = vnetSetupGsoCtx(&Gso, &Hdr);
1106 /** @todo Optimize away the extra copying! (lazy bird) */
1107 PPDMSCATTERGATHER pSgBuf;
1108 int rc = pState->pDrv->pfnAllocBuf(pState->pDrv, uSize, pGso, &pSgBuf);
1109 if (RT_SUCCESS(rc))
1110 {
1111 Assert(pSgBuf->cSegs == 1);
1112 /* Assemble a complete frame. */
1113 for (unsigned int i = 1; i < elem.nOut; i++)
1114 {
1115 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns), elem.aSegsOut[i].addr,
1116 ((uint8_t*)pSgBuf->aSegs[0].pvSeg) + uOffset,
1117 elem.aSegsOut[i].cb);
1118 uOffset += elem.aSegsOut[i].cb;
1119 }
1120 pSgBuf->cbUsed = uSize;
1121 vnetPacketDump(pState, (uint8_t*)pSgBuf->aSegs[0].pvSeg, uSize, "--> Outgoing");
1122 if (pGso)
1123 {
1124 /* Some guests (RHEL) may report HdrLen excluding transport layer header! */
1125 /*
1126 * We cannot use cdHdrs provided by the guest because of different ways
1127 * it gets filled out by different versions of kernels.
1128 */
1129 //if (pGso->cbHdrs < Hdr.u16CSumStart + Hdr.u16CSumOffset + 2)
1130 {
1131 Log4(("%s vnetTransmitPendingPackets: HdrLen before adjustment %d.\n",
1132 INSTANCE(pState), pGso->cbHdrsTotal));
1133 switch (pGso->u8Type)
1134 {
1135 case PDMNETWORKGSOTYPE_IPV4_TCP:
1136 case PDMNETWORKGSOTYPE_IPV6_TCP:
1137 pGso->cbHdrsTotal = Hdr.u16CSumStart +
1138 ((PRTNETTCP)(((uint8_t*)pSgBuf->aSegs[0].pvSeg) + Hdr.u16CSumStart))->th_off * 4;
1139 break;
1140 case PDMNETWORKGSOTYPE_IPV4_UDP:
1141 pGso->cbHdrsTotal = Hdr.u16CSumStart + sizeof(RTNETUDP);
1142 break;
1143 }
1144 /* Update GSO structure embedded into the frame */
1145 ((PPDMNETWORKGSO)pSgBuf->pvUser)->cbHdrsTotal = pGso->cbHdrsTotal;
1146 Log4(("%s vnetTransmitPendingPackets: adjusted HdrLen to %d.\n",
1147 INSTANCE(pState), pGso->cbHdrsTotal));
1148 }
1149 Log2(("%s vnetTransmitPendingPackets: gso type=%x cbHdrsTotal=%u cbHdrsSeg=%u mss=%u"
1150 " off1=0x%x off2=0x%x\n", INSTANCE(pState), pGso->u8Type,
1151 pGso->cbHdrsTotal, pGso->cbHdrsSeg, pGso->cbMaxSeg, pGso->offHdr1, pGso->offHdr2));
1152 STAM_REL_COUNTER_INC(&pState->StatTransmitGSO);
1153 }
1154 else if (Hdr.u8Flags & VNETHDR_F_NEEDS_CSUM)
1155 {
1156 STAM_REL_COUNTER_INC(&pState->StatTransmitCSum);
1157 /*
1158 * This is not GSO frame but checksum offloading is requested.
1159 */
1160 vnetCompleteChecksum((uint8_t*)pSgBuf->aSegs[0].pvSeg, uSize,
1161 Hdr.u16CSumStart, Hdr.u16CSumOffset);
1162 }
1163
1164 rc = pState->pDrv->pfnSendBuf(pState->pDrv, pSgBuf, false);
1165 }
1166 else
1167 LogRel(("virtio-net: failed to allocate SG buffer: size=%u rc=%Rrc\n", uSize, rc));
1168
1169 STAM_PROFILE_STOP(&pState->StatTransmitSend, a);
1170 STAM_REL_COUNTER_ADD(&pState->StatTransmitBytes, uOffset);
1171 }
1172 }
1173 vqueuePut(&pState->VPCI, pQueue, &elem, sizeof(VNETHDR) + uOffset);
1174 vqueueSync(&pState->VPCI, pQueue);
1175 STAM_PROFILE_ADV_STOP(&pState->StatTransmit, a);
1176 }
1177 vpciSetWriteLed(&pState->VPCI, false);
1178
1179 if (pDrv)
1180 pDrv->pfnEndXmit(pDrv);
1181 ASMAtomicWriteU32(&pState->uIsTransmitting, 0);
1182}
1183
1184/**
1185 * @interface_method_impl{PDMINETWORKDOWN,pfnXmitPending}
1186 */
1187static DECLCALLBACK(void) vnetNetworkDown_XmitPending(PPDMINETWORKDOWN pInterface)
1188{
1189 VNETSTATE *pThis = RT_FROM_MEMBER(pInterface, VNETSTATE, INetworkDown);
1190 vnetTransmitPendingPackets(pThis, pThis->pTxQueue, false /*fOnWorkerThread*/);
1191}
1192
1193#ifdef VNET_TX_DELAY
1194
1195static DECLCALLBACK(void) vnetQueueTransmit(void *pvState, PVQUEUE pQueue)
1196{
1197 VNETSTATE *pState = (VNETSTATE*)pvState;
1198
1199 if (TMTimerIsActive(pState->CTX_SUFF(pTxTimer)))
1200 {
1201 int rc = TMTimerStop(pState->CTX_SUFF(pTxTimer));
1202 Log3(("%s vnetQueueTransmit: Got kicked with notification disabled, "
1203 "re-enable notification and flush TX queue\n", INSTANCE(pState)));
1204 vnetTransmitPendingPackets(pState, pQueue, false /*fOnWorkerThread*/);
1205 if (RT_FAILURE(vnetCsEnter(pState, VERR_SEM_BUSY)))
1206 LogRel(("vnetQueueTransmit: Failed to enter critical section!/n"));
1207 else
1208 {
1209 vringSetNotification(&pState->VPCI, &pState->pTxQueue->VRing, true);
1210 vnetCsLeave(pState);
1211 }
1212 }
1213 else
1214 {
1215 if (RT_FAILURE(vnetCsEnter(pState, VERR_SEM_BUSY)))
1216 LogRel(("vnetQueueTransmit: Failed to enter critical section!/n"));
1217 else
1218 {
1219 vringSetNotification(&pState->VPCI, &pState->pTxQueue->VRing, false);
1220 TMTimerSetMicro(pState->CTX_SUFF(pTxTimer), VNET_TX_DELAY);
1221 pState->u64NanoTS = RTTimeNanoTS();
1222 vnetCsLeave(pState);
1223 }
1224 }
1225}
1226
1227/**
1228 * Transmit Delay Timer handler.
1229 *
1230 * @remarks We only get here when the timer expires.
1231 *
1232 * @param pDevIns Pointer to device instance structure.
1233 * @param pTimer Pointer to the timer.
1234 * @param pvUser NULL.
1235 * @thread EMT
1236 */
1237static DECLCALLBACK(void) vnetTxTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1238{
1239 VNETSTATE *pState = (VNETSTATE*)pvUser;
1240
1241 uint32_t u32MicroDiff = (uint32_t)((RTTimeNanoTS() - pState->u64NanoTS)/1000);
1242 if (u32MicroDiff < pState->u32MinDiff)
1243 pState->u32MinDiff = u32MicroDiff;
1244 if (u32MicroDiff > pState->u32MaxDiff)
1245 pState->u32MaxDiff = u32MicroDiff;
1246 pState->u32AvgDiff = (pState->u32AvgDiff * pState->u32i + u32MicroDiff) / (pState->u32i + 1);
1247 pState->u32i++;
1248 Log3(("vnetTxTimer: Expired, diff %9d usec, avg %9d usec, min %9d usec, max %9d usec\n",
1249 u32MicroDiff, pState->u32AvgDiff, pState->u32MinDiff, pState->u32MaxDiff));
1250
1251// Log3(("%s vnetTxTimer: Expired\n", INSTANCE(pState)));
1252 vnetTransmitPendingPackets(pState, pState->pTxQueue, false /*fOnWorkerThread*/);
1253 if (RT_FAILURE(vnetCsEnter(pState, VERR_SEM_BUSY)))
1254 {
1255 LogRel(("vnetTxTimer: Failed to enter critical section!/n"));
1256 return;
1257 }
1258 vringSetNotification(&pState->VPCI, &pState->pTxQueue->VRing, true);
1259 vnetCsLeave(pState);
1260}
1261
1262#else /* !VNET_TX_DELAY */
1263
1264static DECLCALLBACK(void) vnetQueueTransmit(void *pvState, PVQUEUE pQueue)
1265{
1266 VNETSTATE *pState = (VNETSTATE*)pvState;
1267
1268 vnetTransmitPendingPackets(pState, pQueue, false /*fOnWorkerThread*/);
1269}
1270
1271#endif /* !VNET_TX_DELAY */
1272
1273static uint8_t vnetControlRx(PVNETSTATE pState, PVNETCTLHDR pCtlHdr, PVQUEUEELEM pElem)
1274{
1275 uint8_t u8Ack = VNET_OK;
1276 uint8_t fOn, fDrvWasPromisc = pState->fPromiscuous | pState->fAllMulti;
1277 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
1278 pElem->aSegsOut[1].addr,
1279 &fOn, sizeof(fOn));
1280 Log(("%s vnetControlRx: uCommand=%u fOn=%u\n", INSTANCE(pState), pCtlHdr->u8Command, fOn));
1281 switch (pCtlHdr->u8Command)
1282 {
1283 case VNET_CTRL_CMD_RX_MODE_PROMISC:
1284 pState->fPromiscuous = !!fOn;
1285 break;
1286 case VNET_CTRL_CMD_RX_MODE_ALLMULTI:
1287 pState->fAllMulti = !!fOn;
1288 break;
1289 default:
1290 u8Ack = VNET_ERROR;
1291 }
1292 if (fDrvWasPromisc != (pState->fPromiscuous | pState->fAllMulti) && pState->pDrv)
1293 pState->pDrv->pfnSetPromiscuousMode(pState->pDrv,
1294 (pState->fPromiscuous | pState->fAllMulti));
1295
1296 return u8Ack;
1297}
1298
1299static uint8_t vnetControlMac(PVNETSTATE pState, PVNETCTLHDR pCtlHdr, PVQUEUEELEM pElem)
1300{
1301 uint32_t nMacs = 0;
1302
1303 if (pCtlHdr->u8Command != VNET_CTRL_CMD_MAC_TABLE_SET
1304 || pElem->nOut != 3
1305 || pElem->aSegsOut[1].cb < sizeof(nMacs)
1306 || pElem->aSegsOut[2].cb < sizeof(nMacs))
1307 {
1308 Log(("%s vnetControlMac: Segment layout is wrong "
1309 "(u8Command=%u nOut=%u cb1=%u cb2=%u)\n", INSTANCE(pState),
1310 pCtlHdr->u8Command, pElem->nOut,
1311 pElem->aSegsOut[1].cb, pElem->aSegsOut[2].cb));
1312 return VNET_ERROR;
1313 }
1314
1315 /* Load unicast addresses */
1316 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
1317 pElem->aSegsOut[1].addr,
1318 &nMacs, sizeof(nMacs));
1319
1320 if (pElem->aSegsOut[1].cb < nMacs * sizeof(RTMAC) + sizeof(nMacs))
1321 {
1322 Log(("%s vnetControlMac: The unicast mac segment is too small "
1323 "(nMacs=%u cb=%u)\n", INSTANCE(pState), pElem->aSegsOut[1].cb));
1324 return VNET_ERROR;
1325 }
1326
1327 if (nMacs > VNET_MAC_FILTER_LEN)
1328 {
1329 Log(("%s vnetControlMac: MAC table is too big, have to use promiscuous"
1330 " mode (nMacs=%u)\n", INSTANCE(pState), nMacs));
1331 pState->fPromiscuous = true;
1332 }
1333 else
1334 {
1335 if (nMacs)
1336 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
1337 pElem->aSegsOut[1].addr + sizeof(nMacs),
1338 pState->aMacFilter, nMacs * sizeof(RTMAC));
1339 pState->nMacFilterEntries = nMacs;
1340#ifdef DEBUG
1341 Log(("%s vnetControlMac: unicast macs:\n", INSTANCE(pState)));
1342 for(unsigned i = 0; i < nMacs; i++)
1343 Log((" %RTmac\n", &pState->aMacFilter[i]));
1344#endif /* DEBUG */
1345 }
1346
1347 /* Load multicast addresses */
1348 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
1349 pElem->aSegsOut[2].addr,
1350 &nMacs, sizeof(nMacs));
1351
1352 if (pElem->aSegsOut[2].cb < nMacs * sizeof(RTMAC) + sizeof(nMacs))
1353 {
1354 Log(("%s vnetControlMac: The multicast mac segment is too small "
1355 "(nMacs=%u cb=%u)\n", INSTANCE(pState), pElem->aSegsOut[2].cb));
1356 return VNET_ERROR;
1357 }
1358
1359 if (nMacs > VNET_MAC_FILTER_LEN - pState->nMacFilterEntries)
1360 {
1361 Log(("%s vnetControlMac: MAC table is too big, have to use allmulti"
1362 " mode (nMacs=%u)\n", INSTANCE(pState), nMacs));
1363 pState->fAllMulti = true;
1364 }
1365 else
1366 {
1367 if (nMacs)
1368 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
1369 pElem->aSegsOut[2].addr + sizeof(nMacs),
1370 &pState->aMacFilter[pState->nMacFilterEntries],
1371 nMacs * sizeof(RTMAC));
1372#ifdef DEBUG
1373 Log(("%s vnetControlMac: multicast macs:\n", INSTANCE(pState)));
1374 for(unsigned i = 0; i < nMacs; i++)
1375 Log((" %RTmac\n",
1376 &pState->aMacFilter[i+pState->nMacFilterEntries]));
1377#endif /* DEBUG */
1378 pState->nMacFilterEntries += nMacs;
1379 }
1380
1381 return VNET_OK;
1382}
1383
1384static uint8_t vnetControlVlan(PVNETSTATE pState, PVNETCTLHDR pCtlHdr, PVQUEUEELEM pElem)
1385{
1386 uint8_t u8Ack = VNET_OK;
1387 uint16_t u16Vid;
1388
1389 if (pElem->nOut != 2 || pElem->aSegsOut[1].cb != sizeof(u16Vid))
1390 {
1391 Log(("%s vnetControlVlan: Segment layout is wrong "
1392 "(u8Command=%u nOut=%u cb=%u)\n", INSTANCE(pState),
1393 pCtlHdr->u8Command, pElem->nOut, pElem->aSegsOut[1].cb));
1394 return VNET_ERROR;
1395 }
1396
1397 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
1398 pElem->aSegsOut[1].addr,
1399 &u16Vid, sizeof(u16Vid));
1400
1401 if (u16Vid >= VNET_MAX_VID)
1402 {
1403 Log(("%s vnetControlVlan: VLAN ID is out of range "
1404 "(VID=%u)\n", INSTANCE(pState), u16Vid));
1405 return VNET_ERROR;
1406 }
1407
1408 Log(("%s vnetControlVlan: uCommand=%u VID=%u\n", INSTANCE(pState),
1409 pCtlHdr->u8Command, u16Vid));
1410
1411 switch (pCtlHdr->u8Command)
1412 {
1413 case VNET_CTRL_CMD_VLAN_ADD:
1414 ASMBitSet(pState->aVlanFilter, u16Vid);
1415 break;
1416 case VNET_CTRL_CMD_VLAN_DEL:
1417 ASMBitClear(pState->aVlanFilter, u16Vid);
1418 break;
1419 default:
1420 u8Ack = VNET_ERROR;
1421 }
1422
1423 return u8Ack;
1424}
1425
1426
1427static DECLCALLBACK(void) vnetQueueControl(void *pvState, PVQUEUE pQueue)
1428{
1429 VNETSTATE *pState = (VNETSTATE*)pvState;
1430 uint8_t u8Ack;
1431 VQUEUEELEM elem;
1432 while (vqueueGet(&pState->VPCI, pQueue, &elem))
1433 {
1434 unsigned int uOffset = 0;
1435 if (elem.nOut < 1 || elem.aSegsOut[0].cb < sizeof(VNETCTLHDR))
1436 {
1437 Log(("%s vnetQueueControl: The first 'out' segment is not the "
1438 "header! (%u < 1 || %u < %u).\n", INSTANCE(pState), elem.nOut,
1439 elem.aSegsOut[0].cb,sizeof(VNETCTLHDR)));
1440 break; /* Skip the element and hope the next one is good. */
1441 }
1442 else if ( elem.nIn < 1
1443 || elem.aSegsIn[elem.nIn - 1].cb < sizeof(VNETCTLACK))
1444 {
1445 Log(("%s vnetQueueControl: The last 'in' segment is too small "
1446 "to hold the acknowledge! (%u < 1 || %u < %u).\n",
1447 INSTANCE(pState), elem.nIn, elem.aSegsIn[elem.nIn - 1].cb,
1448 sizeof(VNETCTLACK)));
1449 break; /* Skip the element and hope the next one is good. */
1450 }
1451 else
1452 {
1453 VNETCTLHDR CtlHdr;
1454 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
1455 elem.aSegsOut[0].addr,
1456 &CtlHdr, sizeof(CtlHdr));
1457 switch (CtlHdr.u8Class)
1458 {
1459 case VNET_CTRL_CLS_RX_MODE:
1460 u8Ack = vnetControlRx(pState, &CtlHdr, &elem);
1461 break;
1462 case VNET_CTRL_CLS_MAC:
1463 u8Ack = vnetControlMac(pState, &CtlHdr, &elem);
1464 break;
1465 case VNET_CTRL_CLS_VLAN:
1466 u8Ack = vnetControlVlan(pState, &CtlHdr, &elem);
1467 break;
1468 default:
1469 u8Ack = VNET_ERROR;
1470 }
1471 Log(("%s Processed control message %u, ack=%u.\n", INSTANCE(pState),
1472 CtlHdr.u8Class, u8Ack));
1473 PDMDevHlpPhysWrite(pState->VPCI.CTX_SUFF(pDevIns),
1474 elem.aSegsIn[elem.nIn - 1].addr,
1475 &u8Ack, sizeof(u8Ack));
1476 }
1477 vqueuePut(&pState->VPCI, pQueue, &elem, sizeof(u8Ack));
1478 vqueueSync(&pState->VPCI, pQueue);
1479 }
1480}
1481
1482/**
1483 * Saves the configuration.
1484 *
1485 * @param pState The VNET state.
1486 * @param pSSM The handle to the saved state.
1487 */
1488static void vnetSaveConfig(VNETSTATE *pState, PSSMHANDLE pSSM)
1489{
1490 SSMR3PutMem(pSSM, &pState->macConfigured, sizeof(pState->macConfigured));
1491}
1492
1493/**
1494 * Live save - save basic configuration.
1495 *
1496 * @returns VBox status code.
1497 * @param pDevIns The device instance.
1498 * @param pSSM The handle to the saved state.
1499 * @param uPass
1500 */
1501static DECLCALLBACK(int) vnetLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
1502{
1503 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1504 vnetSaveConfig(pState, pSSM);
1505 return VINF_SSM_DONT_CALL_AGAIN;
1506}
1507
1508/**
1509 * Prepares for state saving.
1510 *
1511 * @returns VBox status code.
1512 * @param pDevIns The device instance.
1513 * @param pSSM The handle to the saved state.
1514 */
1515static DECLCALLBACK(int) vnetSavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1516{
1517 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1518
1519 int rc = vnetCsRxEnter(pState, VERR_SEM_BUSY);
1520 if (RT_UNLIKELY(rc != VINF_SUCCESS))
1521 return rc;
1522 vnetCsRxLeave(pState);
1523 return VINF_SUCCESS;
1524}
1525
1526/**
1527 * Saves the state of device.
1528 *
1529 * @returns VBox status code.
1530 * @param pDevIns The device instance.
1531 * @param pSSM The handle to the saved state.
1532 */
1533static DECLCALLBACK(int) vnetSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1534{
1535 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1536
1537 /* Save config first */
1538 vnetSaveConfig(pState, pSSM);
1539
1540 /* Save the common part */
1541 int rc = vpciSaveExec(&pState->VPCI, pSSM);
1542 AssertRCReturn(rc, rc);
1543 /* Save device-specific part */
1544 rc = SSMR3PutMem( pSSM, pState->config.mac.au8, sizeof(pState->config.mac));
1545 AssertRCReturn(rc, rc);
1546 rc = SSMR3PutBool(pSSM, pState->fPromiscuous);
1547 AssertRCReturn(rc, rc);
1548 rc = SSMR3PutBool(pSSM, pState->fAllMulti);
1549 AssertRCReturn(rc, rc);
1550 rc = SSMR3PutU32( pSSM, pState->nMacFilterEntries);
1551 AssertRCReturn(rc, rc);
1552 rc = SSMR3PutMem( pSSM, pState->aMacFilter,
1553 pState->nMacFilterEntries * sizeof(RTMAC));
1554 AssertRCReturn(rc, rc);
1555 rc = SSMR3PutMem( pSSM, pState->aVlanFilter, sizeof(pState->aVlanFilter));
1556 AssertRCReturn(rc, rc);
1557 Log(("%s State has been saved\n", INSTANCE(pState)));
1558 return VINF_SUCCESS;
1559}
1560
1561
1562/**
1563 * Serializes the receive thread, it may be working inside the critsect.
1564 *
1565 * @returns VBox status code.
1566 * @param pDevIns The device instance.
1567 * @param pSSM The handle to the saved state.
1568 */
1569static DECLCALLBACK(int) vnetLoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1570{
1571 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1572
1573 int rc = vnetCsRxEnter(pState, VERR_SEM_BUSY);
1574 if (RT_UNLIKELY(rc != VINF_SUCCESS))
1575 return rc;
1576 vnetCsRxLeave(pState);
1577 return VINF_SUCCESS;
1578}
1579
1580/**
1581 * Takes down the link temporarily if it's current status is up.
1582 *
1583 * This is used during restore and when replumbing the network link.
1584 *
1585 * The temporary link outage is supposed to indicate to the OS that all network
1586 * connections have been lost and that it for instance is appropriate to
1587 * renegotiate any DHCP lease.
1588 *
1589 * @param pThis The PCNet instance data.
1590 */
1591static void vnetTempLinkDown(PVNETSTATE pState)
1592{
1593 if (STATUS & VNET_S_LINK_UP)
1594 {
1595 STATUS &= ~VNET_S_LINK_UP;
1596 vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
1597 /* Restore the link back in 5 seconds. */
1598 int rc = TMTimerSetMillies(pState->pLinkUpTimer, pState->cMsLinkUpDelay);
1599 AssertRC(rc);
1600 }
1601}
1602
1603
1604/**
1605 * Restore previously saved state of device.
1606 *
1607 * @returns VBox status code.
1608 * @param pDevIns The device instance.
1609 * @param pSSM The handle to the saved state.
1610 * @param uVersion The data unit version number.
1611 * @param uPass The data pass.
1612 */
1613static DECLCALLBACK(int) vnetLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1614{
1615 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1616 int rc;
1617
1618 /* config checks */
1619 RTMAC macConfigured;
1620 rc = SSMR3GetMem(pSSM, &macConfigured, sizeof(macConfigured));
1621 AssertRCReturn(rc, rc);
1622 if (memcmp(&macConfigured, &pState->macConfigured, sizeof(macConfigured))
1623 && (uPass == 0 || !PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns)))
1624 LogRel(("%s: The mac address differs: config=%RTmac saved=%RTmac\n", INSTANCE(pState), &pState->macConfigured, &macConfigured));
1625
1626 rc = vpciLoadExec(&pState->VPCI, pSSM, uVersion, uPass, VNET_N_QUEUES);
1627 AssertRCReturn(rc, rc);
1628
1629 if (uPass == SSM_PASS_FINAL)
1630 {
1631 rc = SSMR3GetMem( pSSM, pState->config.mac.au8,
1632 sizeof(pState->config.mac));
1633 AssertRCReturn(rc, rc);
1634
1635 if (uVersion > VIRTIO_SAVEDSTATE_VERSION_3_1_BETA1)
1636 {
1637 rc = SSMR3GetBool(pSSM, &pState->fPromiscuous);
1638 AssertRCReturn(rc, rc);
1639 rc = SSMR3GetBool(pSSM, &pState->fAllMulti);
1640 AssertRCReturn(rc, rc);
1641 rc = SSMR3GetU32(pSSM, &pState->nMacFilterEntries);
1642 AssertRCReturn(rc, rc);
1643 rc = SSMR3GetMem(pSSM, pState->aMacFilter,
1644 pState->nMacFilterEntries * sizeof(RTMAC));
1645 AssertRCReturn(rc, rc);
1646 /* Clear the rest. */
1647 if (pState->nMacFilterEntries < VNET_MAC_FILTER_LEN)
1648 memset(&pState->aMacFilter[pState->nMacFilterEntries],
1649 0,
1650 (VNET_MAC_FILTER_LEN - pState->nMacFilterEntries)
1651 * sizeof(RTMAC));
1652 rc = SSMR3GetMem(pSSM, pState->aVlanFilter,
1653 sizeof(pState->aVlanFilter));
1654 AssertRCReturn(rc, rc);
1655 }
1656 else
1657 {
1658 pState->fPromiscuous = true;
1659 pState->fAllMulti = false;
1660 pState->nMacFilterEntries = 0;
1661 memset(pState->aMacFilter, 0, VNET_MAC_FILTER_LEN * sizeof(RTMAC));
1662 memset(pState->aVlanFilter, 0, sizeof(pState->aVlanFilter));
1663 if (pState->pDrv)
1664 pState->pDrv->pfnSetPromiscuousMode(pState->pDrv, true);
1665 }
1666 }
1667
1668 return rc;
1669}
1670
1671/**
1672 * Link status adjustments after loading.
1673 *
1674 * @returns VBox status code.
1675 * @param pDevIns The device instance.
1676 * @param pSSM The handle to the saved state.
1677 */
1678static DECLCALLBACK(int) vnetLoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1679{
1680 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1681
1682 if (pState->pDrv)
1683 pState->pDrv->pfnSetPromiscuousMode(pState->pDrv,
1684 (pState->fPromiscuous | pState->fAllMulti));
1685 /*
1686 * Indicate link down to the guest OS that all network connections have
1687 * been lost, unless we've been teleported here.
1688 */
1689 if (!PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns))
1690 vnetTempLinkDown(pState);
1691
1692 return VINF_SUCCESS;
1693}
1694
1695/**
1696 * Map PCI I/O region.
1697 *
1698 * @return VBox status code.
1699 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
1700 * @param iRegion The region number.
1701 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
1702 * I/O port, else it's a physical address.
1703 * This address is *NOT* relative to pci_mem_base like earlier!
1704 * @param cb Region size.
1705 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
1706 * @thread EMT
1707 */
1708static DECLCALLBACK(int) vnetMap(PPCIDEVICE pPciDev, int iRegion,
1709 RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
1710{
1711 int rc;
1712 VNETSTATE *pState = PDMINS_2_DATA(pPciDev->pDevIns, VNETSTATE*);
1713
1714 if (enmType != PCI_ADDRESS_SPACE_IO)
1715 {
1716 /* We should never get here */
1717 AssertMsgFailed(("Invalid PCI address space param in map callback"));
1718 return VERR_INTERNAL_ERROR;
1719 }
1720
1721 pState->VPCI.addrIOPort = (RTIOPORT)GCPhysAddress;
1722 rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns, pState->VPCI.addrIOPort,
1723 cb, 0, vnetIOPortOut, vnetIOPortIn,
1724 NULL, NULL, "VirtioNet");
1725#ifdef VNET_GC_SUPPORT
1726 AssertRCReturn(rc, rc);
1727 rc = PDMDevHlpIOPortRegisterR0(pPciDev->pDevIns, pState->VPCI.addrIOPort,
1728 cb, 0, "vnetIOPortOut", "vnetIOPortIn",
1729 NULL, NULL, "VirtioNet");
1730 AssertRCReturn(rc, rc);
1731 rc = PDMDevHlpIOPortRegisterRC(pPciDev->pDevIns, pState->VPCI.addrIOPort,
1732 cb, 0, "vnetIOPortOut", "vnetIOPortIn",
1733 NULL, NULL, "VirtioNet");
1734#endif
1735 AssertRC(rc);
1736 return rc;
1737}
1738
1739
1740/* -=-=-=-=- PDMDEVREG -=-=-=-=- */
1741
1742/**
1743 * Detach notification.
1744 *
1745 * One port on the network card has been disconnected from the network.
1746 *
1747 * @param pDevIns The device instance.
1748 * @param iLUN The logical unit which is being detached.
1749 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1750 */
1751static DECLCALLBACK(void) vnetDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1752{
1753 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1754 Log(("%s vnetDetach:\n", INSTANCE(pState)));
1755
1756 AssertLogRelReturnVoid(iLUN == 0);
1757
1758 int rc = vnetCsEnter(pState, VERR_SEM_BUSY);
1759 if (RT_FAILURE(rc))
1760 {
1761 LogRel(("vnetDetach failed to enter critical section!\n"));
1762 return;
1763 }
1764
1765 /*
1766 * Zero some important members.
1767 */
1768 pState->pDrvBase = NULL;
1769 pState->pDrv = NULL;
1770
1771 vnetCsLeave(pState);
1772}
1773
1774/**
1775 * Attach the Network attachment.
1776 *
1777 * One port on the network card has been connected to a network.
1778 *
1779 * @returns VBox status code.
1780 * @param pDevIns The device instance.
1781 * @param iLUN The logical unit which is being attached.
1782 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1783 *
1784 * @remarks This code path is not used during construction.
1785 */
1786static DECLCALLBACK(int) vnetAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1787{
1788 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1789 LogFlow(("%s vnetAttach:\n", INSTANCE(pState)));
1790
1791 AssertLogRelReturn(iLUN == 0, VERR_PDM_NO_SUCH_LUN);
1792
1793 int rc = vnetCsEnter(pState, VERR_SEM_BUSY);
1794 if (RT_FAILURE(rc))
1795 {
1796 LogRel(("vnetAttach failed to enter critical section!\n"));
1797 return rc;
1798 }
1799
1800 /*
1801 * Attach the driver.
1802 */
1803 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pState->VPCI.IBase, &pState->pDrvBase, "Network Port");
1804 if (RT_SUCCESS(rc))
1805 {
1806 if (rc == VINF_NAT_DNS)
1807 {
1808#ifdef RT_OS_LINUX
1809 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
1810 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"));
1811#else
1812 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
1813 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"));
1814#endif
1815 }
1816 pState->pDrv = PDMIBASE_QUERY_INTERFACE(pState->pDrvBase, PDMINETWORKUP);
1817 AssertMsgStmt(pState->pDrv, ("Failed to obtain the PDMINETWORKUP interface!\n"),
1818 rc = VERR_PDM_MISSING_INTERFACE_BELOW);
1819 }
1820 else if ( rc == VERR_PDM_NO_ATTACHED_DRIVER
1821 || rc == VERR_PDM_CFG_MISSING_DRIVER_NAME)
1822 {
1823 /* This should never happen because this function is not called
1824 * if there is no driver to attach! */
1825 Log(("%s No attached driver!\n", INSTANCE(pState)));
1826 }
1827
1828 /*
1829 * Temporary set the link down if it was up so that the guest
1830 * will know that we have change the configuration of the
1831 * network card
1832 */
1833 if (RT_SUCCESS(rc))
1834 vnetTempLinkDown(pState);
1835
1836 vnetCsLeave(pState);
1837 return rc;
1838
1839}
1840
1841/**
1842 * @copydoc FNPDMDEVSUSPEND
1843 */
1844static DECLCALLBACK(void) vnetSuspend(PPDMDEVINS pDevIns)
1845{
1846 /* Poke thread waiting for buffer space. */
1847 vnetWakeupReceive(pDevIns);
1848}
1849
1850/**
1851 * @copydoc FNPDMDEVPOWEROFF
1852 */
1853static DECLCALLBACK(void) vnetPowerOff(PPDMDEVINS pDevIns)
1854{
1855 /* Poke thread waiting for buffer space. */
1856 vnetWakeupReceive(pDevIns);
1857}
1858
1859/**
1860 * Device relocation callback.
1861 *
1862 * When this callback is called the device instance data, and if the
1863 * device have a GC component, is being relocated, or/and the selectors
1864 * have been changed. The device must use the chance to perform the
1865 * necessary pointer relocations and data updates.
1866 *
1867 * Before the GC code is executed the first time, this function will be
1868 * called with a 0 delta so GC pointer calculations can be one in one place.
1869 *
1870 * @param pDevIns Pointer to the device instance.
1871 * @param offDelta The relocation delta relative to the old location.
1872 *
1873 * @remark A relocation CANNOT fail.
1874 */
1875static DECLCALLBACK(void) vnetRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1876{
1877 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1878 vpciRelocate(pDevIns, offDelta);
1879 pState->pCanRxQueueRC = PDMQueueRCPtr(pState->pCanRxQueueR3);
1880#ifdef VNET_TX_DELAY
1881 pState->pTxTimerRC = TMTimerRCPtr(pState->pTxTimerR3);
1882#endif /* VNET_TX_DELAY */
1883 // TBD
1884}
1885
1886/**
1887 * Destruct a device instance.
1888 *
1889 * We need to free non-VM resources only.
1890 *
1891 * @returns VBox status.
1892 * @param pDevIns The device instance data.
1893 * @thread EMT
1894 */
1895static DECLCALLBACK(int) vnetDestruct(PPDMDEVINS pDevIns)
1896{
1897 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1898 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
1899
1900 LogRel(("TxTimer stats (avg/min/max): %7d usec %7d usec %7d usec\n",
1901 pState->u32AvgDiff, pState->u32MinDiff, pState->u32MaxDiff));
1902 Log(("%s Destroying instance\n", INSTANCE(pState)));
1903 if (pState->hEventMoreRxDescAvail != NIL_RTSEMEVENT)
1904 {
1905 RTSemEventSignal(pState->hEventMoreRxDescAvail);
1906 RTSemEventDestroy(pState->hEventMoreRxDescAvail);
1907 pState->hEventMoreRxDescAvail = NIL_RTSEMEVENT;
1908 }
1909
1910 // if (PDMCritSectIsInitialized(&pState->csRx))
1911 // PDMR3CritSectDelete(&pState->csRx);
1912
1913 return vpciDestruct(&pState->VPCI);
1914}
1915
1916/**
1917 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1918 */
1919static DECLCALLBACK(int) vnetConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1920{
1921 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1922 int rc;
1923 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1924
1925 /* Initialize PCI part first. */
1926 pState->VPCI.IBase.pfnQueryInterface = vnetQueryInterface;
1927 rc = vpciConstruct(pDevIns, &pState->VPCI, iInstance,
1928 VNET_NAME_FMT, VNET_PCI_SUBSYSTEM_ID,
1929 VNET_PCI_CLASS, VNET_N_QUEUES);
1930 pState->pRxQueue = vpciAddQueue(&pState->VPCI, 256, vnetQueueReceive, "RX ");
1931 pState->pTxQueue = vpciAddQueue(&pState->VPCI, 256, vnetQueueTransmit, "TX ");
1932 pState->pCtlQueue = vpciAddQueue(&pState->VPCI, 16, vnetQueueControl, "CTL");
1933
1934 Log(("%s Constructing new instance\n", INSTANCE(pState)));
1935
1936 pState->hEventMoreRxDescAvail = NIL_RTSEMEVENT;
1937
1938 /*
1939 * Validate configuration.
1940 */
1941 if (!CFGMR3AreValuesValid(pCfg, "MAC\0" "CableConnected\0" "LineSpeed\0" "LinkUpDelay\0"))
1942 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
1943 N_("Invalid configuration for VirtioNet device"));
1944
1945 /* Get config params */
1946 rc = CFGMR3QueryBytes(pCfg, "MAC", pState->macConfigured.au8,
1947 sizeof(pState->macConfigured));
1948 if (RT_FAILURE(rc))
1949 return PDMDEV_SET_ERROR(pDevIns, rc,
1950 N_("Configuration error: Failed to get MAC address"));
1951 rc = CFGMR3QueryBool(pCfg, "CableConnected", &pState->fCableConnected);
1952 if (RT_FAILURE(rc))
1953 return PDMDEV_SET_ERROR(pDevIns, rc,
1954 N_("Configuration error: Failed to get the value of 'CableConnected'"));
1955 rc = CFGMR3QueryU32Def(pCfg, "LinkUpDelay", (uint32_t*)&pState->cMsLinkUpDelay, 5000); /* ms */
1956 if (RT_FAILURE(rc))
1957 return PDMDEV_SET_ERROR(pDevIns, rc,
1958 N_("Configuration error: Failed to get the value of 'LinkUpDelay'"));
1959 Assert(pState->cMsLinkUpDelay <= 300000); /* less than 5 minutes */
1960 if (pState->cMsLinkUpDelay > 5000 || pState->cMsLinkUpDelay < 100)
1961 {
1962 LogRel(("%s WARNING! Link up delay is set to %u seconds!\n",
1963 INSTANCE(pState), pState->cMsLinkUpDelay / 1000));
1964 }
1965 Log(("%s Link up delay is set to %u seconds\n",
1966 INSTANCE(pState), pState->cMsLinkUpDelay / 1000));
1967
1968 /* Initialize PCI config space */
1969 memcpy(pState->config.mac.au8, pState->macConfigured.au8, sizeof(pState->config.mac.au8));
1970 pState->config.uStatus = 0;
1971
1972 /* Initialize state structure */
1973 pState->u32PktNo = 1;
1974
1975 /* Interfaces */
1976 pState->INetworkDown.pfnWaitReceiveAvail = vnetNetworkDown_WaitReceiveAvail;
1977 pState->INetworkDown.pfnReceive = vnetNetworkDown_Receive;
1978 pState->INetworkDown.pfnReceiveGso = vnetNetworkDown_ReceiveGso;
1979 pState->INetworkDown.pfnXmitPending = vnetNetworkDown_XmitPending;
1980
1981 pState->INetworkConfig.pfnGetMac = vnetGetMac;
1982 pState->INetworkConfig.pfnGetLinkState = vnetGetLinkState;
1983 pState->INetworkConfig.pfnSetLinkState = vnetSetLinkState;
1984
1985 /* Initialize critical section. */
1986 // char szTmp[sizeof(pState->VPCI.szInstance) + 2];
1987 // RTStrPrintf(szTmp, sizeof(szTmp), "%sRX", pState->VPCI.szInstance);
1988 // rc = PDMDevHlpCritSectInit(pDevIns, &pState->csRx, szTmp);
1989 // if (RT_FAILURE(rc))
1990 // return rc;
1991
1992 /* Map our ports to IO space. */
1993 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0,
1994 VPCI_CONFIG + sizeof(VNetPCIConfig),
1995 PCI_ADDRESS_SPACE_IO, vnetMap);
1996 if (RT_FAILURE(rc))
1997 return rc;
1998
1999
2000 /* Register save/restore state handlers. */
2001 rc = PDMDevHlpSSMRegisterEx(pDevIns, VIRTIO_SAVEDSTATE_VERSION, sizeof(VNETSTATE), NULL,
2002 NULL, vnetLiveExec, NULL,
2003 vnetSavePrep, vnetSaveExec, NULL,
2004 vnetLoadPrep, vnetLoadExec, vnetLoadDone);
2005 if (RT_FAILURE(rc))
2006 return rc;
2007
2008 /* Create the RX notifier signaller. */
2009 rc = PDMDevHlpQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 1, 0,
2010 vnetCanRxQueueConsumer, true, "VNet-Rcv", &pState->pCanRxQueueR3);
2011 if (RT_FAILURE(rc))
2012 return rc;
2013 pState->pCanRxQueueR0 = PDMQueueR0Ptr(pState->pCanRxQueueR3);
2014 pState->pCanRxQueueRC = PDMQueueRCPtr(pState->pCanRxQueueR3);
2015
2016 /* Create Link Up Timer */
2017 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, vnetLinkUpTimer, pState,
2018 TMTIMER_FLAGS_NO_CRIT_SECT,
2019 "VirtioNet Link Up Timer", &pState->pLinkUpTimer);
2020 if (RT_FAILURE(rc))
2021 return rc;
2022
2023#ifdef VNET_TX_DELAY
2024 /* Create Transmit Delay Timer */
2025 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, vnetTxTimer, pState,
2026 TMTIMER_FLAGS_NO_CRIT_SECT,
2027 "VirtioNet TX Delay Timer", &pState->pTxTimerR3);
2028 if (RT_FAILURE(rc))
2029 return rc;
2030 pState->pTxTimerR0 = TMTimerR0Ptr(pState->pTxTimerR3);
2031 pState->pTxTimerRC = TMTimerRCPtr(pState->pTxTimerR3);
2032
2033 pState->u32i = pState->u32AvgDiff = pState->u32MaxDiff = 0;
2034 pState->u32MinDiff = ~0;
2035#endif /* VNET_TX_DELAY */
2036
2037 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pState->VPCI.IBase, &pState->pDrvBase, "Network Port");
2038 if (RT_SUCCESS(rc))
2039 {
2040 if (rc == VINF_NAT_DNS)
2041 {
2042 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
2043 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"));
2044 }
2045 pState->pDrv = PDMIBASE_QUERY_INTERFACE(pState->pDrvBase, PDMINETWORKUP);
2046 AssertMsgReturn(pState->pDrv, ("Failed to obtain the PDMINETWORKUP interface!\n"),
2047 VERR_PDM_MISSING_INTERFACE_BELOW);
2048 }
2049 else if ( rc == VERR_PDM_NO_ATTACHED_DRIVER
2050 || rc == VERR_PDM_CFG_MISSING_DRIVER_NAME )
2051 {
2052 /* No error! */
2053 Log(("%s This adapter is not attached to any network!\n", INSTANCE(pState)));
2054 }
2055 else
2056 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach the network LUN"));
2057
2058 rc = RTSemEventCreate(&pState->hEventMoreRxDescAvail);
2059 if (RT_FAILURE(rc))
2060 return rc;
2061
2062 rc = vnetReset(pState);
2063 AssertRC(rc);
2064
2065 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceiveBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data received", "/Devices/VNet%d/Bytes/Receive", iInstance);
2066 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data transmitted", "/Devices/VNet%d/Bytes/Transmit", iInstance);
2067 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceiveGSO, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of received GSO packets", "/Devices/VNet%d/Packets/ReceiveGSO", iInstance);
2068 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitPackets, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of sent packets", "/Devices/VNet%d/Packets/Transmit", iInstance);
2069 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitGSO, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of sent GSO packets", "/Devices/VNet%d/Packets/Transmit-Gso", iInstance);
2070 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitCSum, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of completed TX checksums", "/Devices/VNet%d/Packets/Transmit-Csum", iInstance);
2071#if defined(VBOX_WITH_STATISTICS)
2072 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive", "/Devices/VNet%d/Receive/Total", iInstance);
2073 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceiveStore, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive storing", "/Devices/VNet%d/Receive/Store", iInstance);
2074 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatRxOverflow, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, "Profiling RX overflows", "/Devices/VNet%d/RxOverflow", iInstance);
2075 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatRxOverflowWakeup, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of RX overflow wakeups", "/Devices/VNet%d/RxOverflowWakeup", iInstance);
2076 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling transmits in HC", "/Devices/VNet%d/Transmit/Total", iInstance);
2077 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitSend, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling send transmit in HC", "/Devices/VNet%d/Transmit/Send", iInstance);
2078#endif /* VBOX_WITH_STATISTICS */
2079
2080 return VINF_SUCCESS;
2081}
2082
2083/**
2084 * The device registration structure.
2085 */
2086const PDMDEVREG g_DeviceVirtioNet =
2087{
2088 /* Structure version. PDM_DEVREG_VERSION defines the current version. */
2089 PDM_DEVREG_VERSION,
2090 /* Device name. */
2091 "virtio-net",
2092 /* Name of guest context module (no path).
2093 * Only evalutated if PDM_DEVREG_FLAGS_RC is set. */
2094 "VBoxDDGC.gc",
2095 /* Name of ring-0 module (no path).
2096 * Only evalutated if PDM_DEVREG_FLAGS_RC is set. */
2097 "VBoxDDR0.r0",
2098 /* The description of the device. The UTF-8 string pointed to shall, like this structure,
2099 * remain unchanged from registration till VM destruction. */
2100 "Virtio Ethernet.\n",
2101
2102 /* Flags, combination of the PDM_DEVREG_FLAGS_* \#defines. */
2103#ifdef VNET_GC_SUPPORT
2104 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
2105#else
2106 PDM_DEVREG_FLAGS_DEFAULT_BITS,
2107#endif
2108 /* Device class(es), combination of the PDM_DEVREG_CLASS_* \#defines. */
2109 PDM_DEVREG_CLASS_NETWORK,
2110 /* Maximum number of instances (per VM). */
2111 ~0U,
2112 /* Size of the instance data. */
2113 sizeof(VNETSTATE),
2114
2115 /* Construct instance - required. */
2116 vnetConstruct,
2117 /* Destruct instance - optional. */
2118 vnetDestruct,
2119 /* Relocation command - optional. */
2120 vnetRelocate,
2121 /* I/O Control interface - optional. */
2122 NULL,
2123 /* Power on notification - optional. */
2124 NULL,
2125 /* Reset notification - optional. */
2126 NULL,
2127 /* Suspend notification - optional. */
2128 vnetSuspend,
2129 /* Resume notification - optional. */
2130 NULL,
2131 /* Attach command - optional. */
2132 vnetAttach,
2133 /* Detach notification - optional. */
2134 vnetDetach,
2135 /* Query a LUN base interface - optional. */
2136 NULL,
2137 /* Init complete notification - optional. */
2138 NULL,
2139 /* Power off notification - optional. */
2140 vnetPowerOff,
2141 /* pfnSoftReset */
2142 NULL,
2143 /* u32VersionEnd */
2144 PDM_DEVREG_VERSION
2145};
2146
2147#endif /* IN_RING3 */
2148#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