VirtualBox

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

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

PDM,*: Redid the PDM structure versions. Check the instance and helper versions in every device and driver constructor.

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