~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« back to all changes in this revision

Viewing changes to src/VBox/Devices/Network/DevVirtioNet.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: DevVirtioNet.cpp $ */
 
1
/* $Id: DevVirtioNet.cpp 35387 2010-12-31 18:42:48Z vboxsync $ */
2
2
/** @file
3
3
 * DevVirtioNet - Virtio Network Device
4
4
 */
18
18
 
19
19
#define LOG_GROUP LOG_GROUP_DEV_VIRTIO_NET
20
20
#define VNET_GC_SUPPORT
 
21
#define VNET_WITH_GSO
 
22
#define VNET_WITH_MERGEABLE_RX_BUFS
21
23
 
22
 
#include <VBox/pdmdev.h>
23
 
#include <VBox/pdmnetifs.h>
 
24
#include <VBox/vmm/pdmdev.h>
 
25
#include <VBox/vmm/pdmnetifs.h>
24
26
#include <iprt/asm.h>
 
27
#include <iprt/net.h>
25
28
#include <iprt/semaphore.h>
26
29
#ifdef IN_RING3
27
30
# include <iprt/mem.h>
28
31
# include <iprt/uuid.h>
29
32
#endif /* IN_RING3 */
30
 
#include "../Builtins.h"
 
33
#include "VBoxDD.h"
31
34
#include "../VirtIO/Virtio.h"
32
35
 
33
36
 
122
125
    R3PTRTYPE(PPDMQUEUE)    pCanRxQueueR3;           /**< Rx wakeup signaller - R3. */
123
126
    R0PTRTYPE(PPDMQUEUE)    pCanRxQueueR0;           /**< Rx wakeup signaller - R0. */
124
127
    RCPTRTYPE(PPDMQUEUE)    pCanRxQueueRC;           /**< Rx wakeup signaller - RC. */
125
 
 
126
 
#if HC_ARCH_BITS == 64
127
 
    uint32_t    padding;
128
 
#endif
129
 
 
130
 
    /** transmit buffer */
131
 
    R3PTRTYPE(uint8_t*)     pTxBuf;
 
128
# if HC_ARCH_BITS == 64
 
129
    uint32_t                padding;
 
130
# endif
 
131
 
132
132
    /**< Link Up(/Restore) Timer. */
133
133
    PTMTIMERR3              pLinkUpTimer;
 
134
 
134
135
#ifdef VNET_TX_DELAY
135
136
    /**< Transmit Delay Timer - R3. */
136
137
    PTMTIMERR3              pTxTimerR3;
139
140
    /**< Transmit Delay Timer - GC. */
140
141
    PTMTIMERRC              pTxTimerRC;
141
142
 
142
 
#if HC_ARCH_BITS == 64
143
 
    uint32_t    padding2;
144
 
#endif
145
 
 
146
 
    uint32_t   u32i;
147
 
    uint32_t   u32AvgDiff;
148
 
    uint32_t   u32MinDiff;
149
 
    uint32_t   u32MaxDiff;
150
 
    uint64_t   u64NanoTS;
151
 
 
 
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
152
#endif /* VNET_TX_DELAY */
 
153
 
153
154
    /** Indicates transmission in progress -- only one thread is allowed. */
154
155
    uint32_t                uIsTransmitting;
155
156
 
189
190
 
190
191
    STAMCOUNTER             StatReceiveBytes;
191
192
    STAMCOUNTER             StatTransmitBytes;
 
193
    STAMCOUNTER             StatReceiveGSO;
 
194
    STAMCOUNTER             StatTransmitPackets;
 
195
    STAMCOUNTER             StatTransmitGSO;
 
196
    STAMCOUNTER             StatTransmitCSum;
192
197
#if defined(VBOX_WITH_STATISTICS)
193
198
    STAMPROFILE             StatReceive;
194
199
    STAMPROFILE             StatReceiveStore;
204
209
 
205
210
#ifndef VBOX_DEVICE_STRUCT_TESTCASE
206
211
 
207
 
#define VNETHDR_GSO_NONE 0
 
212
#define VNETHDR_F_NEEDS_CSUM     1       // Use u16CSumStart, u16CSumOffset
 
213
 
 
214
#define VNETHDR_GSO_NONE         0       // Not a GSO frame
 
215
#define VNETHDR_GSO_TCPV4        1       // GSO frame, IPv4 TCP (TSO)
 
216
#define VNETHDR_GSO_UDP          3       // GSO frame, IPv4 UDP (UFO)
 
217
#define VNETHDR_GSO_TCPV6        4       // GSO frame, IPv6 TCP
 
218
#define VNETHDR_GSO_ECN          0x80    // TCP has ECN set
208
219
 
209
220
struct VNetHdr
210
221
{
219
230
typedef VNETHDR *PVNETHDR;
220
231
AssertCompileSize(VNETHDR, 10);
221
232
 
 
233
struct VNetHdrMrx
 
234
{
 
235
    VNETHDR  Hdr;
 
236
    uint16_t u16NumBufs;
 
237
};
 
238
typedef struct VNetHdrMrx VNETHDRMRX;
 
239
typedef VNETHDRMRX *PVNETHDRMRX;
 
240
AssertCompileSize(VNETHDRMRX, 12);
 
241
 
222
242
AssertCompileMemberOffset(VNETSTATE, VPCI, 0);
223
243
 
224
244
#define VNET_OK                    0
246
266
typedef VNETCTLHDR *PVNETCTLHDR;
247
267
AssertCompileSize(VNETCTLHDR, 2);
248
268
 
 
269
/* Returns true if large packets are written into several RX buffers. */
 
270
DECLINLINE(bool) vnetMergeableRxBuffers(PVNETSTATE pState)
 
271
{
 
272
    return !!(pState->VPCI.uGuestFeatures & VNET_F_MRG_RXBUF);
 
273
}
 
274
 
249
275
DECLINLINE(int) vnetCsEnter(PVNETSTATE pState, int rcBusy)
250
276
{
251
277
    return vpciCsEnter(&pState->VPCI, rcBusy);
283
309
#ifdef DEBUG
284
310
    Log(("%s %s packet #%d (%d bytes):\n",
285
311
         INSTANCE(pState), cszText, ++pState->u32PktNo, cb));
286
 
    //Log3(("%.*Rhxd\n", cb, cpPacket));
 
312
    Log3(("%.*Rhxd\n", cb, cpPacket));
287
313
#endif
288
314
}
289
315
 
303
329
        | VNET_F_STATUS
304
330
        | VNET_F_CTRL_VQ
305
331
        | VNET_F_CTRL_RX
306
 
        | VNET_F_CTRL_VLAN;
 
332
        | VNET_F_CTRL_VLAN
 
333
#ifdef VNET_WITH_GSO
 
334
        | VNET_F_CSUM
 
335
        | VNET_F_HOST_TSO4
 
336
        | VNET_F_HOST_TSO6
 
337
        | VNET_F_HOST_UFO
 
338
#endif
 
339
#ifdef VNET_WITH_MERGEABLE_RX_BUFS
 
340
        | VNET_F_MRG_RXBUF
 
341
#endif
 
342
        ;
307
343
}
308
344
 
309
345
PDMBOTHCBDECL(uint32_t) vnetGetHostMinimalFeatures(void *pvState)
369
405
        STATUS = VNET_S_LINK_UP;
370
406
    else
371
407
        STATUS = 0;
 
408
 
372
409
    /*
373
410
     * By default we pass all packets up since the older guests cannot control
374
411
     * virtio mode.
639
676
    /* Compare TPID with VLAN Ether Type */
640
677
    if (   u16Ptr[6] == RT_H2BE_U16(0x8100)
641
678
        && !ASMBitTest(pState->aVlanFilter, RT_BE2H_U16(u16Ptr[7]) & 0xFFF))
 
679
    {
 
680
        Log4(("%s vnetAddressFilter: not our VLAN, returning false\n", INSTANCE(pState)));
642
681
        return false;
 
682
    }
643
683
 
644
684
    if (vnetIsBroadcast(pvBuf))
645
685
        return true;
649
689
 
650
690
    if (!memcmp(pState->config.mac.au8, pvBuf, sizeof(RTMAC)))
651
691
        return true;
 
692
    Log4(("%s vnetAddressFilter: %RTmac (conf) != %RTmac (dest)\n",
 
693
          INSTANCE(pState), pState->config.mac.au8, pvBuf));
652
694
 
653
695
    for (unsigned i = 0; i < pState->nMacFilterEntries; i++)
654
696
        if (!memcmp(&pState->aMacFilter[i], pvBuf, sizeof(RTMAC)))
655
697
            return true;
656
698
 
 
699
    Log2(("%s vnetAddressFilter: failed all tests, returning false, packet dump follows:\n", INSTANCE(pState)));
 
700
    vnetPacketDump(pState, (const uint8_t*)pvBuf, cb, "<-- Incoming");
 
701
 
657
702
    return false;
658
703
}
659
704
 
669
714
 * @param   cb              Number of bytes available in the buffer.
670
715
 * @thread  RX
671
716
 */
672
 
static int vnetHandleRxPacket(PVNETSTATE pState, const void *pvBuf, size_t cb)
 
717
static int vnetHandleRxPacket(PVNETSTATE pState, const void *pvBuf, size_t cb,
 
718
                              PCPDMNETWORKGSO pGso)
673
719
{
674
 
    VNETHDR hdr;
675
 
 
676
 
    hdr.u8Flags   = 0;
677
 
    hdr.u8GSOType = VNETHDR_GSO_NONE;
 
720
    VNETHDRMRX   Hdr;
 
721
    PVNETHDRMRX pHdr;
 
722
    unsigned    uHdrLen;
 
723
    RTGCPHYS     addrHdrMrx = 0;
 
724
 
 
725
    if (pGso)
 
726
    {
 
727
        Log2(("%s vnetHandleRxPacket: gso type=%x cbHdr=%u mss=%u"
 
728
              " off1=0x%x off2=0x%x\n", INSTANCE(pState), pGso->u8Type,
 
729
              pGso->cbHdrs, pGso->cbMaxSeg, pGso->offHdr1, pGso->offHdr2));
 
730
        Hdr.Hdr.u8Flags = VNETHDR_F_NEEDS_CSUM;
 
731
        switch (pGso->u8Type)
 
732
        {
 
733
            case PDMNETWORKGSOTYPE_IPV4_TCP:
 
734
                Hdr.Hdr.u8GSOType = VNETHDR_GSO_TCPV4;
 
735
                Hdr.Hdr.u16CSumOffset = RT_OFFSETOF(RTNETTCP, th_sum);
 
736
                break;
 
737
            case PDMNETWORKGSOTYPE_IPV6_TCP:
 
738
                Hdr.Hdr.u8GSOType = VNETHDR_GSO_TCPV6;
 
739
                Hdr.Hdr.u16CSumOffset = RT_OFFSETOF(RTNETTCP, th_sum);
 
740
                break;
 
741
            case PDMNETWORKGSOTYPE_IPV4_UDP:
 
742
                Hdr.Hdr.u8GSOType = VNETHDR_GSO_UDP;
 
743
                Hdr.Hdr.u16CSumOffset = RT_OFFSETOF(RTNETUDP, uh_sum);
 
744
                break;
 
745
            default:
 
746
                return VERR_INVALID_PARAMETER;
 
747
        }
 
748
        Hdr.Hdr.u16HdrLen = pGso->cbHdrs;
 
749
        Hdr.Hdr.u16GSOSize = pGso->cbMaxSeg;
 
750
        Hdr.Hdr.u16CSumStart = pGso->offHdr2;
 
751
        STAM_REL_COUNTER_INC(&pState->StatReceiveGSO);
 
752
    }
 
753
    else
 
754
    {
 
755
        Hdr.Hdr.u8Flags   = 0;
 
756
        Hdr.Hdr.u8GSOType = VNETHDR_GSO_NONE;
 
757
    }
 
758
 
 
759
    if (vnetMergeableRxBuffers(pState))
 
760
        uHdrLen = sizeof(VNETHDRMRX);
 
761
    else
 
762
        uHdrLen = sizeof(VNETHDR);
678
763
 
679
764
    vnetPacketDump(pState, (const uint8_t*)pvBuf, cb, "<-- Incoming");
680
765
 
681
766
    unsigned int uOffset = 0;
682
 
    for (unsigned int nElem = 0; uOffset < cb; nElem++)
 
767
    unsigned int nElem;
 
768
    for (nElem = 0; uOffset < cb; nElem++)
683
769
    {
684
770
        VQUEUEELEM elem;
685
 
        unsigned int nSeg = 0, uElemSize = 0;
 
771
        unsigned int nSeg = 0, uElemSize = 0, cbReserved = 0;
686
772
 
687
773
        if (!vqueueGet(&pState->VPCI, pState->pRxQueue, &elem))
688
774
        {
 
775
            /*
 
776
             * @todo: It is possible to run out of RX buffers if only a few
 
777
             * were added and we received a big packet.
 
778
             */
689
779
            Log(("%s vnetHandleRxPacket: Suddenly there is no space in receive queue!\n", INSTANCE(pState)));
690
780
            return VERR_INTERNAL_ERROR;
691
781
        }
698
788
 
699
789
        if (nElem == 0)
700
790
        {
701
 
            /* The very first segment of the very first element gets the header. */
702
 
            if (elem.aSegsIn[nSeg].cb != sizeof(VNETHDR))
703
 
            {
704
 
                Log(("%s vnetHandleRxPacket: The first descriptor does match the header size!\n", INSTANCE(pState)));
705
 
                return VERR_INTERNAL_ERROR;
706
 
            }
707
 
 
708
 
            elem.aSegsIn[nSeg++].pv = &hdr;
709
 
            uElemSize += sizeof(VNETHDR);
 
791
            if (vnetMergeableRxBuffers(pState))
 
792
            {
 
793
                addrHdrMrx = elem.aSegsIn[nSeg].addr;
 
794
                cbReserved = uHdrLen;
 
795
            }
 
796
            else
 
797
            {
 
798
                /* The very first segment of the very first element gets the header. */
 
799
                if (elem.aSegsIn[nSeg].cb != sizeof(VNETHDR))
 
800
                {
 
801
                    Log(("%s vnetHandleRxPacket: The first descriptor does match the header size!\n", INSTANCE(pState)));
 
802
                    return VERR_INTERNAL_ERROR;
 
803
                }
 
804
                elem.aSegsIn[nSeg++].pv = &Hdr;
 
805
            }
 
806
            uElemSize += uHdrLen;
710
807
        }
711
 
 
712
808
        while (nSeg < elem.nIn && uOffset < cb)
713
809
        {
714
 
            unsigned int uSize = RT_MIN(elem.aSegsIn[nSeg].cb, cb - uOffset);
 
810
            unsigned int uSize = (unsigned int)RT_MIN(elem.aSegsIn[nSeg].cb - (nSeg?0:cbReserved),
 
811
                                                      cb - uOffset);
715
812
            elem.aSegsIn[nSeg++].pv = (uint8_t*)pvBuf + uOffset;
716
813
            uOffset += uSize;
717
814
            uElemSize += uSize;
718
815
        }
719
816
        STAM_PROFILE_START(&pState->StatReceiveStore, a);
720
 
        vqueuePut(&pState->VPCI, pState->pRxQueue, &elem, uElemSize);
 
817
        vqueuePut(&pState->VPCI, pState->pRxQueue, &elem, uElemSize, cbReserved);
721
818
        STAM_PROFILE_STOP(&pState->StatReceiveStore, a);
 
819
        if (!vnetMergeableRxBuffers(pState))
 
820
            break;
 
821
        cbReserved = 0;
 
822
    }
 
823
    if (vnetMergeableRxBuffers(pState))
 
824
    {
 
825
        Hdr.u16NumBufs = nElem;
 
826
        int rc = PDMDevHlpPhysWrite(pState->VPCI.CTX_SUFF(pDevIns), addrHdrMrx,
 
827
                                    &Hdr, sizeof(Hdr));
 
828
        if (RT_FAILURE(rc))
 
829
        {
 
830
            Log(("%s vnetHandleRxPacket: Failed to write merged RX buf header: %Rrc\n",
 
831
                 INSTANCE(pState), rc));
 
832
            return rc;
 
833
        }
722
834
    }
723
835
    vqueueSync(&pState->VPCI, pState->pRxQueue);
 
836
    if (uOffset < cb)
 
837
    {
 
838
        Log(("%s vnetHandleRxPacket: Packet did not fit into RX queue (packet size=%u)!\n",
 
839
             INSTANCE(pState), cb));
 
840
        return VERR_TOO_MUCH_DATA;
 
841
    }
724
842
 
725
843
    return VINF_SUCCESS;
726
844
}
727
845
 
728
846
/**
729
 
 * @interface_method_impl{PDMINETWORKDOWN,pfnReceive}
 
847
 * @interface_method_impl{PDMINETWORKDOWN,pfnReceiveGso}
730
848
 */
731
 
static DECLCALLBACK(int) vnetNetworkDown_Receive(PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb)
 
849
static DECLCALLBACK(int) vnetNetworkDown_ReceiveGso(PPDMINETWORKDOWN pInterface,
 
850
                                                    const void *pvBuf, size_t cb,
 
851
                                                    PCPDMNETWORKGSO pGso)
732
852
{
733
853
    VNETSTATE *pState = RT_FROM_MEMBER(pInterface, VNETSTATE, INetworkDown);
734
854
 
735
 
    Log2(("%s vnetNetworkDown_Receive: pvBuf=%p cb=%u\n", INSTANCE(pState), pvBuf, cb));
 
855
    Log2(("%s vnetNetworkDown_ReceiveGso: pvBuf=%p cb=%u pGso=%p\n",
 
856
          INSTANCE(pState), pvBuf, cb, pGso));
736
857
    int rc = vnetCanReceive(pState);
737
858
    if (RT_FAILURE(rc))
738
859
        return rc;
751
872
        rc = vnetCsRxEnter(pState, VERR_SEM_BUSY);
752
873
        if (RT_SUCCESS(rc))
753
874
        {
754
 
            rc = vnetHandleRxPacket(pState, pvBuf, cb);
 
875
            rc = vnetHandleRxPacket(pState, pvBuf, cb, pGso);
755
876
            STAM_REL_COUNTER_ADD(&pState->StatReceiveBytes, cb);
756
877
            vnetCsRxLeave(pState);
757
878
        }
762
883
}
763
884
 
764
885
/**
 
886
 * @interface_method_impl{PDMINETWORKDOWN,pfnReceive}
 
887
 */
 
888
static DECLCALLBACK(int) vnetNetworkDown_Receive(PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb)
 
889
{
 
890
    return vnetNetworkDown_ReceiveGso(pInterface, pvBuf, cb, NULL);
 
891
}
 
892
 
 
893
/**
765
894
 * Gets the current Media Access Control (MAC) address.
766
895
 *
767
896
 * @returns VBox status code.
832
961
    vnetWakeupReceive(pState->VPCI.CTX_SUFF(pDevIns));
833
962
}
834
963
 
 
964
/**
 
965
 * Sets up the GSO context according to the Virtio header.
 
966
 *
 
967
 * @param   pGso                The GSO context to setup.
 
968
 * @param   pCtx                The context descriptor.
 
969
 */
 
970
DECLINLINE(PPDMNETWORKGSO) vnetSetupGsoCtx(PPDMNETWORKGSO pGso, VNETHDR const *pHdr)
 
971
{
 
972
    pGso->u8Type = PDMNETWORKGSOTYPE_INVALID;
 
973
 
 
974
    if (pHdr->u8GSOType & VNETHDR_GSO_ECN)
 
975
    {
 
976
        AssertMsgFailed(("Unsupported flag in virtio header: ECN\n"));
 
977
        return NULL;
 
978
    }
 
979
    switch (pHdr->u8GSOType & ~VNETHDR_GSO_ECN)
 
980
    {
 
981
        case VNETHDR_GSO_TCPV4:
 
982
            pGso->u8Type = PDMNETWORKGSOTYPE_IPV4_TCP;
 
983
            break;
 
984
        case VNETHDR_GSO_TCPV6:
 
985
            pGso->u8Type = PDMNETWORKGSOTYPE_IPV6_TCP;
 
986
            break;
 
987
        case VNETHDR_GSO_UDP:
 
988
            pGso->u8Type = PDMNETWORKGSOTYPE_IPV4_UDP;
 
989
            break;
 
990
        default:
 
991
            return NULL;
 
992
    }
 
993
    if (pHdr->u8Flags & VNETHDR_F_NEEDS_CSUM)
 
994
        pGso->offHdr2  = pHdr->u16CSumStart;
 
995
    else
 
996
    {
 
997
        AssertMsgFailed(("GSO without checksum offloading!\n"));
 
998
        return NULL;
 
999
    }
 
1000
    pGso->offHdr1  = sizeof(RTNETETHERHDR);
 
1001
    pGso->cbHdrs   = pHdr->u16HdrLen;
 
1002
    pGso->cbMaxSeg = pHdr->u16GSOSize;
 
1003
    return pGso;
 
1004
}
 
1005
 
 
1006
DECLINLINE(uint16_t) vnetCSum16(const void *pvBuf, size_t cb)
 
1007
{
 
1008
    uint32_t  csum = 0;
 
1009
    uint16_t *pu16 = (uint16_t *)pvBuf;
 
1010
 
 
1011
    while (cb > 1)
 
1012
    {
 
1013
        csum += *pu16++;
 
1014
        cb -= 2;
 
1015
    }
 
1016
    if (cb)
 
1017
        csum += *(uint8_t*)pu16;
 
1018
    while (csum >> 16)
 
1019
        csum = (csum >> 16) + (csum & 0xFFFF);
 
1020
    return ~csum;
 
1021
}
 
1022
 
 
1023
DECLINLINE(void) vnetCompleteChecksum(uint8_t *pBuf, unsigned cbSize, uint16_t uStart, uint16_t uOffset)
 
1024
{
 
1025
    *(uint16_t*)(pBuf + uStart + uOffset) = vnetCSum16(pBuf + uStart, cbSize - uStart);
 
1026
}
 
1027
 
835
1028
static void vnetTransmitPendingPackets(PVNETSTATE pState, PVQUEUE pQueue, bool fOnWorkerThread)
836
1029
{
837
1030
    /*
861
1054
        }
862
1055
    }
863
1056
 
864
 
    Log3(("%s vnetTransmitPendingPackets: About to trasmit %d pending packets\n", INSTANCE(pState),
 
1057
    unsigned int uHdrLen;
 
1058
    if (vnetMergeableRxBuffers(pState))
 
1059
        uHdrLen = sizeof(VNETHDRMRX);
 
1060
    else
 
1061
        uHdrLen = sizeof(VNETHDR);
 
1062
 
 
1063
    Log3(("%s vnetTransmitPendingPackets: About to transmit %d pending packets\n", INSTANCE(pState),
865
1064
          vringReadAvailIndex(&pState->VPCI, &pState->pTxQueue->VRing) - pState->pTxQueue->uNextAvailIndex));
866
1065
 
867
1066
    vpciSetWriteLed(&pState->VPCI, true);
870
1069
    while (vqueueGet(&pState->VPCI, pQueue, &elem))
871
1070
    {
872
1071
        unsigned int uOffset = 0;
873
 
        if (elem.nOut < 2 || elem.aSegsOut[0].cb != sizeof(VNETHDR))
 
1072
        if (elem.nOut < 2 || elem.aSegsOut[0].cb != uHdrLen)
874
1073
        {
875
1074
            Log(("%s vnetQueueTransmit: The first segment is not the header! (%u < 2 || %u != %u).\n",
876
 
                 INSTANCE(pState), elem.nOut, elem.aSegsOut[0].cb, sizeof(VNETHDR)));
 
1075
                 INSTANCE(pState), elem.nOut, elem.aSegsOut[0].cb, uHdrLen));
877
1076
            break; /* For now we simply ignore the header, but it must be there anyway! */
878
1077
        }
879
1078
        else
880
1079
        {
 
1080
            unsigned int uSize = 0;
881
1081
            STAM_PROFILE_ADV_START(&pState->StatTransmit, a);
882
 
            /* Assemble a complete frame. */
883
 
            for (unsigned int i = 1; i < elem.nOut && uOffset < VNET_MAX_FRAME_SIZE; i++)
884
 
            {
885
 
                unsigned int uSize = elem.aSegsOut[i].cb;
886
 
                if (uSize > VNET_MAX_FRAME_SIZE - uOffset)
887
 
                {
888
 
                    Log(("%s vnetQueueTransmit: Packet is too big (>64k), truncating...\n", INSTANCE(pState)));
889
 
                    uSize = VNET_MAX_FRAME_SIZE - uOffset;
890
 
                }
891
 
                PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns), elem.aSegsOut[i].addr,
892
 
                                  pState->pTxBuf + uOffset, uSize);
893
 
                uOffset += uSize;
894
 
            }
 
1082
            /* Compute total frame size. */
 
1083
            for (unsigned int i = 1; i < elem.nOut; i++)
 
1084
                uSize += elem.aSegsOut[i].cb;
 
1085
            Assert(uSize <= VNET_MAX_FRAME_SIZE);
895
1086
            if (pState->pDrv)
896
1087
            {
897
 
                vnetPacketDump(pState, pState->pTxBuf, uOffset, "--> Outgoing");
 
1088
                VNETHDR Hdr;
 
1089
                PDMNETWORKGSO Gso, *pGso;
 
1090
 
 
1091
                PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns), elem.aSegsOut[0].addr,
 
1092
                                  &Hdr, sizeof(Hdr));
 
1093
 
 
1094
                STAM_REL_COUNTER_INC(&pState->StatTransmitPackets);
898
1095
 
899
1096
                STAM_PROFILE_START(&pState->StatTransmitSend, a);
900
1097
 
 
1098
                pGso = vnetSetupGsoCtx(&Gso, &Hdr);
901
1099
                /** @todo Optimize away the extra copying! (lazy bird) */
902
1100
                PPDMSCATTERGATHER pSgBuf;
903
 
                int rc = pState->pDrv->pfnAllocBuf(pState->pDrv, uOffset, NULL /*pGso*/, &pSgBuf);
 
1101
                int rc = pState->pDrv->pfnAllocBuf(pState->pDrv, uSize, pGso, &pSgBuf);
904
1102
                if (RT_SUCCESS(rc))
905
1103
                {
906
1104
                    Assert(pSgBuf->cSegs == 1);
907
 
                    memcpy(pSgBuf->aSegs[0].pvSeg, pState->pTxBuf, uOffset);
908
 
                    pSgBuf->cbUsed = uOffset;
 
1105
                    /* Assemble a complete frame. */
 
1106
                    for (unsigned int i = 1; i < elem.nOut; i++)
 
1107
                    {
 
1108
                        PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns), elem.aSegsOut[i].addr,
 
1109
                                          ((uint8_t*)pSgBuf->aSegs[0].pvSeg) + uOffset,
 
1110
                                          elem.aSegsOut[i].cb);
 
1111
                        uOffset += elem.aSegsOut[i].cb;
 
1112
                    }
 
1113
                    pSgBuf->cbUsed = uSize;
 
1114
                    vnetPacketDump(pState, (uint8_t*)pSgBuf->aSegs[0].pvSeg, uSize, "--> Outgoing");
 
1115
                    if (pGso)
 
1116
                    {
 
1117
                        /* Some guests (RHEL) may report HdrLen excluding transport layer header! */
 
1118
                        /*
 
1119
                         * We cannot use cdHdrs provided by the guest because of different ways
 
1120
                         * it gets filled out by different versions of kernels.
 
1121
                         */
 
1122
                        //if (pGso->cbHdrs < Hdr.u16CSumStart + Hdr.u16CSumOffset + 2)
 
1123
                        {
 
1124
                            Log4(("%s vnetTransmitPendingPackets: HdrLen before adjustment %d.\n",
 
1125
                                  INSTANCE(pState), pGso->cbHdrs));
 
1126
                            switch (pGso->u8Type)
 
1127
                            {
 
1128
                                case PDMNETWORKGSOTYPE_IPV4_TCP:
 
1129
                                case PDMNETWORKGSOTYPE_IPV6_TCP:
 
1130
                                    pGso->cbHdrs = Hdr.u16CSumStart +
 
1131
                                        ((PRTNETTCP)(((uint8_t*)pSgBuf->aSegs[0].pvSeg) + Hdr.u16CSumStart))->th_off * 4;
 
1132
                                    break;
 
1133
                                case PDMNETWORKGSOTYPE_IPV4_UDP:
 
1134
                                    pGso->cbHdrs = Hdr.u16CSumStart + sizeof(RTNETUDP);
 
1135
                                    break;
 
1136
                            }
 
1137
                            /* Update GSO structure embedded into the frame */
 
1138
                            ((PPDMNETWORKGSO)pSgBuf->pvUser)->cbHdrs = pGso->cbHdrs;
 
1139
                            Log4(("%s vnetTransmitPendingPackets: adjusted HdrLen to %d.\n",
 
1140
                                  INSTANCE(pState), pGso->cbHdrs));
 
1141
                        }
 
1142
                        Log2(("%s vnetTransmitPendingPackets: gso type=%x cbHdr=%u mss=%u"
 
1143
                              " off1=0x%x off2=0x%x\n", INSTANCE(pState), pGso->u8Type,
 
1144
                              pGso->cbHdrs, pGso->cbMaxSeg, pGso->offHdr1, pGso->offHdr2));
 
1145
                        STAM_REL_COUNTER_INC(&pState->StatTransmitGSO);
 
1146
                    }
 
1147
                    else if (Hdr.u8Flags & VNETHDR_F_NEEDS_CSUM)
 
1148
                    {
 
1149
                        STAM_REL_COUNTER_INC(&pState->StatTransmitCSum);
 
1150
                        /*
 
1151
                         * This is not GSO frame but checksum offloading is requested.
 
1152
                         */
 
1153
                        vnetCompleteChecksum((uint8_t*)pSgBuf->aSegs[0].pvSeg, uSize,
 
1154
                                             Hdr.u16CSumStart, Hdr.u16CSumOffset);
 
1155
                    }
 
1156
 
909
1157
                    rc = pState->pDrv->pfnSendBuf(pState->pDrv, pSgBuf, false);
910
1158
                }
 
1159
                else
 
1160
                    LogRel(("virtio-net: failed to allocate SG buffer: size=%u rc=%Rrc\n", uSize, rc));
911
1161
 
912
1162
                STAM_PROFILE_STOP(&pState->StatTransmitSend, a);
913
1163
                STAM_REL_COUNTER_ADD(&pState->StatTransmitBytes, uOffset);
1374
1624
        rc = SSMR3GetMem( pSSM, pState->config.mac.au8,
1375
1625
                          sizeof(pState->config.mac));
1376
1626
        AssertRCReturn(rc, rc);
 
1627
 
1377
1628
        if (uVersion > VIRTIO_SAVEDSTATE_VERSION_3_1_BETA1)
1378
1629
        {
1379
1630
            rc = SSMR3GetBool(pSSM, &pState->fPromiscuous);
1478
1729
    return rc;
1479
1730
}
1480
1731
 
 
1732
 
1481
1733
/* -=-=-=-=- PDMDEVREG -=-=-=-=- */
1482
1734
 
1483
 
#ifdef VBOX_DYNAMIC_NET_ATTACH
1484
 
 
1485
1735
/**
1486
1736
 * Detach notification.
1487
1737
 *
1514
1764
    vnetCsLeave(pState);
1515
1765
}
1516
1766
 
1517
 
 
1518
1767
/**
1519
1768
 * Attach the Network attachment.
1520
1769
 *
1582
1831
 
1583
1832
}
1584
1833
 
1585
 
#endif /* VBOX_DYNAMIC_NET_ATTACH */
1586
 
 
1587
1834
/**
1588
1835
 * @copydoc FNPDMDEVSUSPEND
1589
1836
 */
1653
1900
        pState->hEventMoreRxDescAvail = NIL_RTSEMEVENT;
1654
1901
    }
1655
1902
 
1656
 
    if (pState->pTxBuf)
1657
 
    {
1658
 
        RTMemFree(pState->pTxBuf);
1659
 
        pState->pTxBuf = NULL;
1660
 
    }
1661
1903
    // if (PDMCritSectIsInitialized(&pState->csRx))
1662
1904
    //     PDMR3CritSectDelete(&pState->csRx);
1663
1905
 
1714
1956
    /* Interfaces */
1715
1957
    pState->INetworkDown.pfnWaitReceiveAvail = vnetNetworkDown_WaitReceiveAvail;
1716
1958
    pState->INetworkDown.pfnReceive          = vnetNetworkDown_Receive;
 
1959
    pState->INetworkDown.pfnReceiveGso       = vnetNetworkDown_ReceiveGso;
1717
1960
    pState->INetworkDown.pfnXmitPending      = vnetNetworkDown_XmitPending;
1718
1961
 
1719
1962
    pState->INetworkConfig.pfnGetMac         = vnetGetMac;
1720
1963
    pState->INetworkConfig.pfnGetLinkState   = vnetGetLinkState;
1721
1964
    pState->INetworkConfig.pfnSetLinkState   = vnetSetLinkState;
1722
1965
 
1723
 
    pState->pTxBuf = (uint8_t *)RTMemAllocZ(VNET_MAX_FRAME_SIZE);
1724
 
    AssertMsgReturn(pState->pTxBuf,
1725
 
                    ("Cannot allocate TX buffer for virtio-net device\n"), VERR_NO_MEMORY);
1726
 
 
1727
1966
    /* Initialize critical section. */
1728
1967
    // char szTmp[sizeof(pState->VPCI.szInstance) + 2];
1729
1968
    // RTStrPrintf(szTmp, sizeof(szTmp), "%sRX", pState->VPCI.szInstance);
1804
2043
    rc = vnetReset(pState);
1805
2044
    AssertRC(rc);
1806
2045
 
1807
 
    PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceiveBytes,       STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,          "Amount of data received",            "/Devices/VNet%d/ReceiveBytes", iInstance);
1808
 
    PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitBytes,      STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,          "Amount of data transmitted",         "/Devices/VNet%d/TransmitBytes", iInstance);
 
2046
    PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceiveBytes,       STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,          "Amount of data received",            "/Devices/VNet%d/Bytes/Receive", iInstance);
 
2047
    PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitBytes,      STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,          "Amount of data transmitted",         "/Devices/VNet%d/Bytes/Transmit", iInstance);
 
2048
    PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceiveGSO,         STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,          "Number of received GSO packets",     "/Devices/VNet%d/Packets/ReceiveGSO", iInstance);
 
2049
    PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitPackets,    STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,          "Number of sent packets",             "/Devices/VNet%d/Packets/Transmit", iInstance);
 
2050
    PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitGSO,        STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,          "Number of sent GSO packets",         "/Devices/VNet%d/Packets/Transmit-Gso", iInstance);
 
2051
    PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitCSum,       STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,          "Number of completed TX checksums",   "/Devices/VNet%d/Packets/Transmit-Csum", iInstance);
1809
2052
#if defined(VBOX_WITH_STATISTICS)
1810
2053
    PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceive,            STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive",                  "/Devices/VNet%d/Receive/Total", iInstance);
1811
2054
    PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceiveStore,       STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive storing",          "/Devices/VNet%d/Receive/Store", iInstance);
1866
2109
    vnetSuspend,
1867
2110
    /* Resume notification - optional. */
1868
2111
    NULL,
1869
 
#ifdef VBOX_DYNAMIC_NET_ATTACH
1870
2112
    /* Attach command - optional. */
1871
2113
    vnetAttach,
1872
2114
    /* Detach notification - optional. */
1873
2115
    vnetDetach,
1874
 
#else /* !VBOX_DYNAMIC_NET_ATTACH */
1875
 
    /* Attach command - optional. */
1876
 
    NULL,
1877
 
    /* Detach notification - optional. */
1878
 
    NULL,
1879
 
#endif /* !VBOX_DYNAMIC_NET_ATTACH */
1880
2116
    /* Query a LUN base interface - optional. */
1881
2117
    NULL,
1882
2118
    /* Init complete notification - optional. */