VirtualBox

Changeset 64194 in vbox for trunk/src


Ignore:
Timestamp:
Oct 11, 2016 6:48:49 AM (8 years ago)
Author:
vboxsync
Message:

NetFlt/Linux (bugref:8599) Scatter/gather support enabled

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostDrivers/VBoxNetFlt/linux/VBoxNetFlt-linux.c

    r62490 r64194  
    147147#endif
    148148
    149 #if 0
     149#if 1
    150150/** Create scatter / gather segments for fragments. When not used, we will
    151151 *  linearize the socket buffer before creating the internal networking SG. */
     
    781781
    782782/**
     783 * Return the offset where to start checksum computation from.
     784 *
     785 * @returns the offset relative to pBuf->data.
     786 * @param   pBuf                The socket buffer.
     787 */
     788DECLINLINE(unsigned) vboxNetFltLinuxGetChecksumStartOffset(struct sk_buff *pBuf)
     789{
     790# if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 21)
     791    unsigned char *pTransportHdr = pBuf->h.raw;
     792#  if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
     793    /*
     794     * Try to work around the problem with CentOS 4.7 and 5.2 (2.6.9
     795     * and 2.6.18 kernels), they pass wrong 'h' pointer down. We take IP
     796     * header length from the header itself and reconstruct 'h' pointer
     797     * to TCP (or whatever) header.
     798     */
     799    if (pBuf->h.raw == pBuf->nh.raw && pBuf->protocol == htons(ETH_P_IP))
     800        pTransportHdr = pBuf->nh.raw + pBuf->nh.iph->ihl * 4;
     801#  endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) */
     802    return pTransportHdr - pBuf->data;
     803# else /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 21) */
     804    return skb_checksum_start_offset(pBuf);
     805# endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 21) */
     806}
     807
     808
     809/**
    783810 * Initializes a SG list from an sk_buff.
    784811 *
     
    787814 * @param   pBuf                The sk_buff.
    788815 * @param   pSG                 The SG.
     816 * @param   cExtra              The number of bytes of extra space allocated immediately after the SG.
    789817 * @param   cSegs               The number of segments allocated for the SG.
    790818 *                              This should match the number in the mbuf exactly!
     
    793821 *                              internal network frame.  NULL if regular frame.
    794822 */
    795 DECLINLINE(void) vboxNetFltLinuxSkBufToSG(PVBOXNETFLTINS pThis, struct sk_buff *pBuf, PINTNETSG pSG,
    796                                          unsigned cSegs, uint32_t fSrc, PCPDMNETWORKGSO pGsoCtx)
     823static void vboxNetFltLinuxSkBufToSG(PVBOXNETFLTINS pThis, struct sk_buff *pBuf, PINTNETSG pSG,
     824                                     unsigned cbExtra, unsigned cSegs, uint32_t fSrc, PCPDMNETWORKGSO pGsoCtx)
    797825{
    798826    int i;
    799827    NOREF(pThis);
    800828
     829#ifndef VBOXNETFLT_SG_SUPPORT
    801830    Assert(!skb_shinfo(pBuf)->frag_list);
     831#else /* VBOXNETFLT_SG_SUPPORT */
     832    uint8_t *pExtra = (uint8_t *)&pSG->aSegs[cSegs];
     833    unsigned cbConsumed = 0;
     834    unsigned cbProduced = 0;
     835
     836# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
     837    /* Restore VLAN tag stripped by host hardware */
     838    if (vlan_tx_tag_present(pBuf))
     839    {
     840        uint8_t *pMac = pBuf->data;
     841        struct vlan_ethhdr *pVHdr = (struct vlan_ethhdr *)pExtra;
     842        Assert(ETH_ALEN * 2 + VLAN_HLEN <= cbExtra);
     843        memmove(pVHdr, pMac, ETH_ALEN * 2);
     844        cbConsumed += ETH_ALEN * 2;
     845        pVHdr->h_vlan_proto = RT_H2N_U16(ETH_P_8021Q);
     846        pVHdr->h_vlan_TCI   = RT_H2N_U16(vlan_tx_tag_get(pBuf));
     847        pVHdr->h_vlan_encapsulated_proto = *(uint16_t*)(pMac + ETH_ALEN * 2);
     848        cbProduced += VLAN_ETH_HLEN;
     849    }
     850# endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */
     851
     852    if (pBuf->ip_summed == CHECKSUM_PARTIAL && pBuf->pkt_type == PACKET_OUTGOING)
     853    {
     854        unsigned uCsumStartOffset = vboxNetFltLinuxGetChecksumStartOffset(pBuf);
     855        unsigned uCsumStoreOffset = uCsumStartOffset + pBuf->csum_offset - cbConsumed;
     856        Log3(("cbConsumed=%u cbProduced=%u uCsumStartOffset=%u uCsumStoreOffset=%u\n",
     857              cbConsumed, cbProduced, uCsumStartOffset, uCsumStoreOffset));
     858        Assert(cbProduced + uCsumStoreOffset + sizeof(uint16_t) <= cbExtra);
     859        /*
     860         * We assume that the checksum is stored at the very end of the transport header
     861         * so we will have all headers in a single fragment. If our assumption is wrong
     862         * we may see suboptimal performance.
     863         */
     864        memmove(pExtra + cbProduced,
     865                pBuf->data + cbConsumed,
     866                uCsumStoreOffset);
     867        unsigned uChecksum = skb_checksum(pBuf, uCsumStartOffset, pBuf->len - uCsumStartOffset, 0);
     868        *(uint16_t*)(pExtra + cbProduced + uCsumStoreOffset) = csum_fold(uChecksum);
     869        cbProduced += uCsumStoreOffset + sizeof(uint16_t);
     870        cbConsumed += uCsumStoreOffset + sizeof(uint16_t);
     871    }
     872#endif /* VBOXNETFLT_SG_SUPPORT */
    802873
    803874    if (!pGsoCtx)
     
    806877        IntNetSgInitTempSegsGso(pSG, pBuf->len, cSegs, 0 /*cSegsUsed*/, pGsoCtx);
    807878
     879    int iSeg = 0;
    808880#ifdef VBOXNETFLT_SG_SUPPORT
    809     pSG->aSegs[0].cb = skb_headlen(pBuf);
    810     pSG->aSegs[0].pv = pBuf->data;
    811     pSG->aSegs[0].Phys = NIL_RTHCPHYS;
    812 
     881    if (cbProduced)
     882    {
     883        pSG->aSegs[iSeg].cb = cbProduced;
     884        pSG->aSegs[iSeg].pv = pExtra;
     885        pSG->aSegs[iSeg++].Phys = NIL_RTHCPHYS;
     886    }
     887    pSG->aSegs[iSeg].cb = skb_headlen(pBuf) - cbConsumed;
     888    pSG->aSegs[iSeg].pv = pBuf->data + cbConsumed;
     889    pSG->aSegs[iSeg++].Phys = NIL_RTHCPHYS;
     890    Assert(iSeg <= pSG->cSegsAlloc);
     891
     892# ifdef LOG_ENABLED
     893    if (pBuf->data_len)
     894        Log6(("  kmap_atomic:"));
     895# endif /* LOG_ENABLED */
    813896    for (i = 0; i < skb_shinfo(pBuf)->nr_frags; i++)
    814897    {
    815898        skb_frag_t *pFrag = &skb_shinfo(pBuf)->frags[i];
    816         pSG->aSegs[i+1].cb = pFrag->size;
    817         pSG->aSegs[i+1].pv = kmap(pFrag->page);
    818         printk("%p = kmap()\n", pSG->aSegs[i+1].pv);
    819         pSG->aSegs[i+1].Phys = NIL_RTHCPHYS;
    820     }
    821     ++i;
    822 
     899        pSG->aSegs[iSeg].cb = pFrag->size;
     900        pSG->aSegs[iSeg].pv = kmap_atomic(pFrag->page.p) + pFrag->page_offset;
     901        Log6((" %p", pSG->aSegs[iSeg].pv));
     902        pSG->aSegs[iSeg++].Phys = NIL_RTHCPHYS;
     903        Assert(iSeg <= pSG->cSegsAlloc);
     904    }
     905    struct sk_buff *pFragBuf;
     906    for (pFragBuf = skb_shinfo(pBuf)->frag_list; pFragBuf; pFragBuf = pFragBuf->next)
     907    {
     908        pSG->aSegs[iSeg].cb = skb_headlen(pFragBuf);
     909        pSG->aSegs[iSeg].pv = pFragBuf->data;
     910        pSG->aSegs[iSeg++].Phys = NIL_RTHCPHYS;
     911        Assert(iSeg <= pSG->cSegsAlloc);
     912        for (i = 0; i < skb_shinfo(pFragBuf)->nr_frags; i++)
     913        {
     914            skb_frag_t *pFrag = &skb_shinfo(pFragBuf)->frags[i];
     915            pSG->aSegs[iSeg].cb = pFrag->size;
     916            pSG->aSegs[iSeg].pv = kmap_atomic(pFrag->page.p) + pFrag->page_offset;
     917            Log6((" %p", pSG->aSegs[iSeg].pv));
     918            pSG->aSegs[iSeg++].Phys = NIL_RTHCPHYS;
     919            Assert(iSeg <= pSG->cSegsAlloc);
     920        }
     921    }
     922# ifdef LOG_ENABLED
     923    if (pBuf->data_len)
     924        Log6(("\n"));
     925# endif /* LOG_ENABLED */
    823926#else
    824     pSG->aSegs[0].cb = pBuf->len;
    825     pSG->aSegs[0].pv = pBuf->data;
    826     pSG->aSegs[0].Phys = NIL_RTHCPHYS;
    827     i = 1;
    828 #endif
    829 
    830     pSG->cSegsUsed = i;
     927    pSG->aSegs[iSeg].cb = pBuf->len;
     928    pSG->aSegs[iSeg].pv = pBuf->data;
     929    pSG->aSegs[iSeg++].Phys = NIL_RTHCPHYS;
     930#endif
     931
     932    pSG->cSegsUsed = iSeg;
    831933
    832934#ifdef PADD_RUNT_FRAMES_FROM_HOST
     
    840942    if (pSG->cbTotal < 60 && (fSrc & INTNETTRUNKDIR_HOST))
    841943    {
     944        Assert(pBuf->data_len == 0); /* Packets with fragments are never small! */
    842945        static uint8_t const s_abZero[128] = {0};
    843946
    844         AssertReturnVoid(i < cSegs);
    845 
    846         pSG->aSegs[i].Phys = NIL_RTHCPHYS;
    847         pSG->aSegs[i].pv = (void *)&s_abZero[0];
    848         pSG->aSegs[i].cb = 60 - pSG->cbTotal;
     947        AssertReturnVoid(iSeg < cSegs);
     948
     949        pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
     950        pSG->aSegs[iSeg].pv = (void *)&s_abZero[0];
     951        pSG->aSegs[iSeg++].cb = 60 - pSG->cbTotal;
    849952        pSG->cbTotal = 60;
    850953        pSG->cSegsUsed++;
    851         Assert(i + 1 <= pSG->cSegsAlloc)
    852     }
    853 #endif
    854 
    855     Log4(("vboxNetFltLinuxSkBufToSG: allocated=%d, segments=%d frags=%d next=%p frag_list=%p pkt_type=%x fSrc=%x\n",
     954        Assert(iSeg <= pSG->cSegsAlloc)
     955    }
     956#endif
     957
     958    Log6(("vboxNetFltLinuxSkBufToSG: allocated=%d, segments=%d frags=%d next=%p frag_list=%p pkt_type=%x fSrc=%x\n",
    856959          pSG->cSegsAlloc, pSG->cSegsUsed, skb_shinfo(pBuf)->nr_frags, pBuf->next, skb_shinfo(pBuf)->frag_list, pBuf->pkt_type, fSrc));
    857960    for (i = 0; i < pSG->cSegsUsed; i++)
    858         Log4(("vboxNetFltLinuxSkBufToSG:   #%d: cb=%d pv=%p\n",
     961        Log6(("vboxNetFltLinuxSkBufToSG:   #%d: cb=%d pv=%p\n",
    859962              i, pSG->aSegs[i].cb, pSG->aSegs[i].pv));
    860963}
     
    884987          pBuf->len, pBuf->data_len, pBuf->truesize, pBuf->next, skb_shinfo(pBuf)->nr_frags, skb_shinfo(pBuf)->gso_size, skb_shinfo(pBuf)->gso_segs, skb_shinfo(pBuf)->gso_type, skb_shinfo(pBuf)->frag_list, pBuf->pkt_type));
    885988# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
    886     Log4(("vboxNetFltLinuxPacketHandler: packet dump follows:\n%.*Rhxd\n", pBuf->len-pBuf->data_len, skb_mac_header(pBuf)));
     989    Log6(("vboxNetFltLinuxPacketHandler: packet dump follows:\n%.*Rhxd\n", pBuf->len-pBuf->data_len, skb_mac_header(pBuf)));
    887990# endif
    888991#else
     
    9161019    }
    9171020
    918     Log4(("vboxNetFltLinuxPacketHandler: pBuf->cb dump:\n%.*Rhxd\n", sizeof(pBuf->cb), pBuf->cb));
     1021    Log6(("vboxNetFltLinuxPacketHandler: pBuf->cb dump:\n%.*Rhxd\n", sizeof(pBuf->cb), pBuf->cb));
    9191022    if (vboxNetFltLinuxSkBufIsOur(pBuf))
    9201023    {
     
    9581061              pBuf->len, pBuf->data_len, pBuf->truesize, pBuf->next, skb_shinfo(pBuf)->nr_frags, skb_shinfo(pBuf)->gso_size, skb_shinfo(pBuf)->gso_segs, skb_shinfo(pBuf)->gso_type, skb_shinfo(pBuf)->frag_list, pBuf->pkt_type));
    9591062#  if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
    960         Log4(("vboxNetFltLinuxPacketHandler: packet dump follows:\n%.*Rhxd\n", pBuf->len-pBuf->data_len, skb_mac_header(pBuf)));
    961 #  endif
    962 # else
     1063        Log6(("vboxNetFltLinuxPacketHandler: packet dump follows:\n%.*Rhxd\n", pBuf->len-pBuf->data_len, skb_mac_header(pBuf)));
     1064#  endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) */
     1065# else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) */
    9631066        Log3(("vboxNetFltLinuxPacketHandler: skb copy len=%u data_len=%u truesize=%u next=%p nr_frags=%u tso_size=%u tso_seqs=%u frag_list=%p pkt_type=%x\n",
    9641067              pBuf->len, pBuf->data_len, pBuf->truesize, pBuf->next, skb_shinfo(pBuf)->nr_frags, skb_shinfo(pBuf)->tso_size, skb_shinfo(pBuf)->tso_segs, skb_shinfo(pBuf)->frag_list, pBuf->pkt_type));
    965 # endif
    966     }
    967 #endif
     1068# endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) */
     1069    }
     1070#endif /* !VBOXNETFLT_SG_SUPPORT */
    9681071
    9691072#ifdef VBOXNETFLT_LINUX_NO_XMIT_QUEUE
    9701073    /* Forward it to the internal network. */
    9711074    vboxNetFltLinuxForwardToIntNet(pThis, pBuf);
    972 #else
     1075#else /* !VBOXNETFLT_LINUX_NO_XMIT_QUEUE */
    9731076    /* Add the packet to transmit queue and schedule the bottom half. */
    9741077    skb_queue_tail(&pThis->u.s.XmitQueue, pBuf);
    9751078    schedule_work(&pThis->u.s.XmitTask);
    976     Log4(("vboxNetFltLinuxPacketHandler: scheduled work %p for sk_buff %p\n",
     1079    Log6(("vboxNetFltLinuxPacketHandler: scheduled work %p for sk_buff %p\n",
    9771080          &pThis->u.s.XmitTask, pBuf));
    978 #endif
     1081#endif /* !VBOXNETFLT_LINUX_NO_XMIT_QUEUE */
    9791082
    9801083    /* It does not really matter what we return, it is ignored by the kernel. */
     
    9871090 * @returns Segment count.
    9881091 * @param   pBuf                The socket buffer.
    989  */
    990 DECLINLINE(unsigned) vboxNetFltLinuxCalcSGSegments(struct sk_buff *pBuf)
    991 {
     1092 * @param   pcbTemp             Where to store the number of bytes of the part
     1093 *                              of the socket buffer that will be copied to
     1094 *                              a temporary storage.
     1095 */
     1096DECLINLINE(unsigned) vboxNetFltLinuxCalcSGSegments(struct sk_buff *pBuf, unsigned *pcbTemp)
     1097{
     1098    *pcbTemp = 0;
    9921099#ifdef VBOXNETFLT_SG_SUPPORT
    9931100    unsigned cSegs = 1 + skb_shinfo(pBuf)->nr_frags;
     1101    if (pBuf->ip_summed == CHECKSUM_PARTIAL && pBuf->pkt_type == PACKET_OUTGOING)
     1102    {
     1103        *pcbTemp = vboxNetFltLinuxGetChecksumStartOffset(pBuf) + pBuf->csum_offset + sizeof(uint16_t);
     1104    }
     1105# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
     1106    if (vlan_tx_tag_present(pBuf))
     1107    {
     1108        if (*pcbTemp)
     1109            *pcbTemp += VLAN_HLEN;
     1110        else
     1111            *pcbTemp = VLAN_ETH_HLEN;
     1112    }
     1113# endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */
     1114    if (*pcbTemp)
     1115        ++cSegs;
     1116    struct sk_buff *pFrag;
     1117    for (pFrag = skb_shinfo(pBuf)->frag_list; pFrag; pFrag = pFrag->next)
     1118    {
     1119        Log6(("vboxNetFltLinuxCalcSGSegments: frag=%p len=%d data_len=%d frags=%d frag_list=%p next=%p\n",
     1120              pFrag, pFrag->len, pFrag->data_len, skb_shinfo(pFrag)->nr_frags, skb_shinfo(pFrag)->frag_list, pFrag->next));
     1121        cSegs += 1 + skb_shinfo(pFrag)->nr_frags;
     1122    }
    9941123#else
    9951124    unsigned cSegs = 1;
     
    10031132}
    10041133
     1134
    10051135/**
    10061136 * Destroy the intnet scatter / gather buffer created by
    10071137 * vboxNetFltLinuxSkBufToSG.
    1008  */
    1009 static void vboxNetFltLinuxDestroySG(PINTNETSG pSG)
     1138 *
     1139 * @param   pSG             The (scatter/)gather list.
     1140 * @param   pBuf            The original socket buffer that was used to create
     1141 *                          the scatter/gather list.
     1142 */
     1143static void vboxNetFltLinuxDestroySG(PINTNETSG pSG, struct sk_buff *pBuf)
    10101144{
    10111145#ifdef VBOXNETFLT_SG_SUPPORT
    1012     int i;
    1013 
     1146    int i, iSeg = 1; /* Skip non-paged part of SKB */
     1147    /* Check if the extra buffer behind SG structure was used for modified packet header */
     1148    if (pBuf->data != pSG->aSegs[0].pv)
     1149        ++iSeg; /* Skip it as well */
     1150# ifdef LOG_ENABLED
     1151    if (pBuf->data_len)
     1152        Log6(("kunmap_atomic:"));
     1153# endif /* LOG_ENABLED */
     1154    /* iSeg now points to the first mapped fragment if there are any */
    10141155    for (i = 0; i < skb_shinfo(pBuf)->nr_frags; i++)
    10151156    {
    1016         printk("kunmap(%p)\n", pSG->aSegs[i+1].pv);
    1017         kunmap(pSG->aSegs[i+1].pv);
    1018     }
     1157        Log6((" %p", pSG->aSegs[iSeg].pv));
     1158        kunmap_atomic(pSG->aSegs[iSeg++].pv);
     1159    }
     1160    struct sk_buff *pFragBuf;
     1161    for (pFragBuf = skb_shinfo(pBuf)->frag_list; pFragBuf; pFragBuf = pFragBuf->next)
     1162    {
     1163        ++iSeg; /* Non-fragment (unmapped) portion of chained SKB */
     1164        for (i = 0; i < skb_shinfo(pFragBuf)->nr_frags; i++)
     1165        {
     1166            Log6((" %p", pSG->aSegs[iSeg].pv));
     1167            kunmap_atomic(pSG->aSegs[iSeg++].pv);
     1168        }
     1169    }
     1170# ifdef LOG_ENABLED
     1171    if (pBuf->data_len)
     1172        Log6(("\n"));
     1173# endif /* LOG_ENABLED */
    10191174#endif
    10201175    NOREF(pSG);
     
    10491204    if (pSG->cSegsUsed == 1)
    10501205    {
    1051         Log3(("%.*Rhxd\n", pSG->aSegs[0].cb, pSG->aSegs[0].pv));
     1206        Log4(("%.*Rhxd\n", pSG->aSegs[0].cb, pSG->aSegs[0].pv));
    10521207    }
    10531208    else
     
    10551210        for (i = 0, offSeg = 0; i < pSG->cSegsUsed; i++)
    10561211        {
    1057             Log3(("-- segment %d at 0x%x (%d bytes) --\n%.*Rhxd\n",
     1212            Log4(("-- segment %d at 0x%x (%d bytes)\n --\n%.*Rhxd\n",
    10581213                  i, offSeg, pSG->aSegs[i].cb, pSG->aSegs[i].cb, pSG->aSegs[i].pv));
    10591214            offSeg += pSG->aSegs[i].cb;
    10601215        }
    10611216    }
    1062 
    10631217}
    10641218#else
     
    11111265        Log5(("vboxNetFltLinuxCanForwardAsGso: gso_size=%#x skb_len=%#x (max=%#x)\n", skb_shinfo(pSkb)->gso_size, pSkb->len, VBOX_MAX_GSO_SIZE));
    11121266        return false;
    1113     }
    1114     /*
    1115      * It is possible to receive GSO packets from wire if GRO is enabled.
    1116      */
    1117     if (RT_UNLIKELY(fSrc & INTNETTRUNKDIR_WIRE))
    1118     {
    1119         Log5(("vboxNetFltLinuxCanForwardAsGso: fSrc=wire\n"));
    1120 #ifdef VBOXNETFLT_WITH_GRO
    1121         /*
    1122          * The packet came from the wire and the driver has already consumed
    1123          * mac header. We need to restore it back.
    1124          */
    1125         pSkb->mac_len = skb_network_header(pSkb) - skb_mac_header(pSkb);
    1126         skb_push(pSkb, pSkb->mac_len);
    1127         Log5(("vboxNetFltLinuxCanForwardAsGso: mac_len=%d data=%p mac_header=%p network_header=%p\n",
    1128               pSkb->mac_len, pSkb->data, skb_mac_header(pSkb), skb_network_header(pSkb)));
    1129 #else /* !VBOXNETFLT_WITH_GRO */
    1130         /* Older kernels didn't have GRO. */
    1131         return false;
    1132 #endif /* !VBOXNETFLT_WITH_GRO */
    1133     }
    1134     else
    1135     {
    1136         /*
    1137          * skb_gso_segment does the following. Do we need to do it as well?
    1138          */
    1139 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
    1140         skb_reset_mac_header(pSkb);
    1141         pSkb->mac_len = pSkb->network_header - pSkb->mac_header;
    1142 #else
    1143         pSkb->mac.raw = pSkb->data;
    1144         pSkb->mac_len = pSkb->nh.raw - pSkb->data;
    1145 #endif
    11461267    }
    11471268
     
    12931414{
    12941415    int         rc;
    1295     unsigned    cSegs = vboxNetFltLinuxCalcSGSegments(pSkb);
    1296     if (RT_LIKELY(cSegs <= MAX_SKB_FRAGS + 1))
    1297     {
    1298         PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
    1299         if (RT_LIKELY(pSG))
    1300         {
    1301             vboxNetFltLinuxSkBufToSG(pThis, pSkb, pSG, cSegs, fSrc, pGsoCtx);
    1302 
    1303             vboxNetFltDumpPacket(pSG, false, (fSrc & INTNETTRUNKDIR_HOST) ? "host" : "wire", 1);
    1304             pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL /* pvIf */, pSG, fSrc);
    1305 
    1306             vboxNetFltLinuxDestroySG(pSG);
    1307             rc = VINF_SUCCESS;
    1308         }
    1309         else
    1310         {
    1311             Log(("VBoxNetFlt: Dropping the sk_buff (failure case).\n"));
    1312             rc = VERR_NO_MEMORY;
    1313         }
     1416    unsigned    cbExtra;
     1417    unsigned    cSegs = vboxNetFltLinuxCalcSGSegments(pSkb, &cbExtra);
     1418    PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs]) + cbExtra);
     1419    if (RT_LIKELY(pSG))
     1420    {
     1421        vboxNetFltLinuxSkBufToSG(pThis, pSkb, pSG, cbExtra, cSegs, fSrc, pGsoCtx);
     1422
     1423        vboxNetFltDumpPacket(pSG, false, (fSrc & INTNETTRUNKDIR_HOST) ? "host" : "wire", 1);
     1424        pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL /* pvIf */, pSG, fSrc);
     1425
     1426        vboxNetFltLinuxDestroySG(pSG, pSkb);
     1427        rc = VINF_SUCCESS;
    13141428    }
    13151429    else
    13161430    {
    1317         Log(("VBoxNetFlt: Bad sk_buff? cSegs=%#x.\n", cSegs));
    1318         rc = VERR_INTERNAL_ERROR_3;
    1319     }
    1320 
    1321     Log4(("VBoxNetFlt: Dropping the sk_buff.\n"));
    1322     dev_kfree_skb(pSkb);
     1431        Log(("VBoxNetFlt: Dropping the sk_buff (failure case).\n"));
     1432        rc = VERR_NO_MEMORY;
     1433    }
    13231434    return rc;
    13241435}
     
    13371448{
    13381449    int         rc;
    1339     unsigned    cSegs = vboxNetFltLinuxCalcSGSegments(pBuf);
    1340     if (cSegs <= MAX_SKB_FRAGS + 1)
    1341     {
    1342         PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
    1343         if (RT_LIKELY(pSG))
    1344         {
    1345             if (fSrc & INTNETTRUNKDIR_WIRE)
    1346             {
    1347                 /*
    1348                  * The packet came from wire, ethernet header was removed by device driver.
    1349                  * Restore it using mac_len field. This takes into account VLAN headers too.
    1350                  */
    1351                 skb_push(pBuf, pBuf->mac_len);
    1352             }
    1353 
    1354             vboxNetFltLinuxSkBufToSG(pThis, pBuf, pSG, cSegs, fSrc, NULL /*pGsoCtx*/);
    1355 
    1356             vboxNetFltDumpPacket(pSG, false, (fSrc & INTNETTRUNKDIR_HOST) ? "host" : "wire", 1);
    1357             pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL /* pvIf */, pSG, fSrc);
    1358 
    1359             vboxNetFltLinuxDestroySG(pSG);
    1360             rc = VINF_SUCCESS;
    1361         }
    1362         else
    1363         {
    1364             Log(("VBoxNetFlt: Failed to allocate SG buffer.\n"));
    1365             rc = VERR_NO_MEMORY;
    1366         }
     1450    unsigned    cbExtra;
     1451    unsigned    cSegs = vboxNetFltLinuxCalcSGSegments(pBuf, &cbExtra);
     1452    PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs]) + cbExtra);
     1453    if (RT_LIKELY(pSG))
     1454    {
     1455        vboxNetFltLinuxSkBufToSG(pThis, pBuf, pSG, cbExtra, cSegs, fSrc, NULL /*pGsoCtx*/);
     1456
     1457        vboxNetFltDumpPacket(pSG, false, (fSrc & INTNETTRUNKDIR_HOST) ? "host" : "wire", 1);
     1458        pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL /* pvIf */, pSG, fSrc);
     1459
     1460        vboxNetFltLinuxDestroySG(pSG, pBuf);
     1461        rc = VINF_SUCCESS;
    13671462    }
    13681463    else
    13691464    {
    1370         Log(("VBoxNetFlt: Bad sk_buff? cSegs=%#x.\n", cSegs));
    1371         rc = VERR_INTERNAL_ERROR_3;
    1372     }
    1373 
    1374     Log4(("VBoxNetFlt: Dropping the sk_buff.\n"));
    1375     dev_kfree_skb(pBuf);
     1465        Log(("VBoxNetFlt: Failed to allocate SG buffer.\n"));
     1466        rc = VERR_NO_MEMORY;
     1467    }
    13761468    return rc;
    13771469}
    13781470
     1471
    13791472/**
    13801473 * I won't disclose what I do, figure it out yourself, including pThis referencing.
    13811474 *
    13821475 * @param   pThis       The net filter instance.
    1383  * @param   pBuf        The socket buffer.  This is consumed by this function.
    1384  */
    1385 static void vboxNetFltLinuxForwardToIntNet(PVBOXNETFLTINS pThis, struct sk_buff *pBuf)
    1386 {
    1387     uint32_t fSrc = pBuf->pkt_type == PACKET_OUTGOING ? INTNETTRUNKDIR_HOST : INTNETTRUNKDIR_WIRE;
    1388 
     1476 * @param   pBuf        The socket buffer.
     1477 * @param   fSrc        Where the packet comes from.
     1478 */
     1479static void vboxNetFltLinuxForwardToIntNetInner(PVBOXNETFLTINS pThis, struct sk_buff *pBuf, uint32_t fSrc)
     1480{
    13891481#ifdef VBOXNETFLT_WITH_GSO
    13901482    if (skb_is_gso(pBuf))
    13911483    {
    13921484        PDMNETWORKGSO GsoCtx;
    1393         Log3(("vboxNetFltLinuxForwardToIntNet: skb len=%u data_len=%u truesize=%u next=%p nr_frags=%u gso_size=%u gso_seqs=%u gso_type=%x frag_list=%p pkt_type=%x ip_summed=%d\n",
    1394               pBuf->len, pBuf->data_len, pBuf->truesize, pBuf->next, skb_shinfo(pBuf)->nr_frags, skb_shinfo(pBuf)->gso_size, skb_shinfo(pBuf)->gso_segs, skb_shinfo(pBuf)->gso_type, skb_shinfo(pBuf)->frag_list, pBuf->pkt_type, pBuf->ip_summed));
     1485        Log6(("vboxNetFltLinuxForwardToIntNetInner: skb len=%u data_len=%u truesize=%u next=%p"
     1486              " nr_frags=%u gso_size=%u gso_seqs=%u gso_type=%x frag_list=%p pkt_type=%x ip_summed=%d\n",
     1487              pBuf->len, pBuf->data_len, pBuf->truesize, pBuf->next,
     1488              skb_shinfo(pBuf)->nr_frags, skb_shinfo(pBuf)->gso_size,
     1489              skb_shinfo(pBuf)->gso_segs, skb_shinfo(pBuf)->gso_type,
     1490              skb_shinfo(pBuf)->frag_list, pBuf->pkt_type, pBuf->ip_summed));
     1491#ifndef VBOXNETFLT_SG_SUPPORT
     1492        if (RT_LIKELY(fSrc & INTNETTRUNKDIR_HOST))
     1493        {
     1494            /*
     1495             * skb_gso_segment does the following. Do we need to do it as well?
     1496             */
     1497# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
     1498            skb_reset_mac_header(pBuf);
     1499            pBuf->mac_len = pBuf->network_header - pBuf->mac_header;
     1500# else
     1501            pBuf->mac.raw = pBuf->data;
     1502            pBuf->mac_len = pBuf->nh.raw - pBuf->data;
     1503# endif
     1504        }
     1505#endif /* !VBOXNETFLT_SG_SUPPORT */
    13951506# ifdef VBOXNETFLT_WITH_GSO_RECV
    13961507        if (   (skb_shinfo(pBuf)->gso_type & (SKB_GSO_UDP | SKB_GSO_TCPV6 | SKB_GSO_TCPV4))
     
    13981509            vboxNetFltLinuxForwardAsGso(pThis, pBuf, fSrc, &GsoCtx);
    13991510        else
    1400 # endif
     1511# endif /* VBOXNETFLT_WITH_GSO_RECV */
    14011512        {
    14021513            /* Need to segment the packet */
     
    14051516            if (IS_ERR(pSegment))
    14061517            {
    1407                 dev_kfree_skb(pBuf);
    14081518                LogRel(("VBoxNetFlt: Failed to segment a packet (%d).\n", PTR_ERR(pSegment)));
    14091519                return;
     
    14121522            for (; pSegment; pSegment = pNext)
    14131523            {
    1414                 Log3(("vboxNetFltLinuxForwardToIntNet: segment len=%u data_len=%u truesize=%u next=%p nr_frags=%u gso_size=%u gso_seqs=%u gso_type=%x frag_list=%p pkt_type=%x\n",
    1415                       pSegment->len, pSegment->data_len, pSegment->truesize, pSegment->next, skb_shinfo(pSegment)->nr_frags, skb_shinfo(pSegment)->gso_size, skb_shinfo(pSegment)->gso_segs, skb_shinfo(pSegment)->gso_type, skb_shinfo(pSegment)->frag_list, pSegment->pkt_type));
     1524                Log6(("vboxNetFltLinuxForwardToIntNetInner: segment len=%u data_len=%u truesize=%u next=%p"
     1525                      " nr_frags=%u gso_size=%u gso_seqs=%u gso_type=%x frag_list=%p pkt_type=%x\n",
     1526                      pSegment->len, pSegment->data_len, pSegment->truesize, pSegment->next,
     1527                      skb_shinfo(pSegment)->nr_frags, skb_shinfo(pSegment)->gso_size,
     1528                      skb_shinfo(pSegment)->gso_segs, skb_shinfo(pSegment)->gso_type,
     1529                      skb_shinfo(pSegment)->frag_list, pSegment->pkt_type));
    14161530                pNext = pSegment->next;
    14171531                pSegment->next = 0;
    14181532                vboxNetFltLinuxForwardSegment(pThis, pSegment, fSrc);
     1533                dev_kfree_skb(pSegment);
    14191534            }
    1420             dev_kfree_skb(pBuf);
    14211535        }
    14221536    }
     
    14241538#endif /* VBOXNETFLT_WITH_GSO */
    14251539    {
     1540        Log6(("vboxNetFltLinuxForwardToIntNetInner: ptk_type=%d ip_summed=%d len=%d"
     1541              " data_len=%d headroom=%d hdr_len=%d csum_offset=%d\n",
     1542              pBuf->pkt_type, pBuf->ip_summed, pBuf->len, pBuf->data_len, skb_headroom(pBuf),
     1543              skb_headlen(pBuf), skb_checksum_start_offset(pBuf)));
     1544#ifndef VBOXNETFLT_SG_SUPPORT
    14261545        if (pBuf->ip_summed == CHECKSUM_PARTIAL && pBuf->pkt_type == PACKET_OUTGOING)
    14271546        {
     
    14371556                pBuf->h.raw = pBuf->nh.raw + pBuf->nh.iph->ihl * 4;
    14381557#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) */
    1439             if (VBOX_SKB_CHECKSUM_HELP(pBuf))
    1440             {
    1441                 LogRel(("VBoxNetFlt: Failed to compute checksum, dropping the packet.\n"));
    1442                 dev_kfree_skb(pBuf);
    1443                 return;
    1444             }
     1558            int rc = VBOX_SKB_CHECKSUM_HELP(pBuf);
    14451559#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
    14461560            /* Restore the original (wrong) pointer. */
    14471561            pBuf->h.raw = tmp;
    14481562#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) */
    1449         }
     1563            if (rc) {
     1564                LogRel(("VBoxNetFlt: Failed to compute checksum, dropping the packet.\n"));
     1565                return;
     1566            }
     1567        }
     1568#endif /* !VBOXNETFLT_SG_SUPPORT */
    14501569        vboxNetFltLinuxForwardSegment(pThis, pBuf, fSrc);
    14511570    }
    14521571}
     1572
     1573
     1574/**
     1575 * Temporarily adjust pBuf->data so it always points to the Ethernet header,
     1576 * then forward it to the internal network.
     1577 *
     1578 * @param   pThis       The net filter instance.
     1579 * @param   pBuf        The socket buffer.  This is consumed by this function.
     1580 */
     1581static void vboxNetFltLinuxForwardToIntNet(PVBOXNETFLTINS pThis, struct sk_buff *pBuf)
     1582{
     1583    uint32_t fSrc = pBuf->pkt_type == PACKET_OUTGOING ? INTNETTRUNKDIR_HOST : INTNETTRUNKDIR_WIRE;
     1584
     1585    if (RT_UNLIKELY(fSrc & INTNETTRUNKDIR_WIRE))
     1586    {
     1587        /*
     1588         * The packet came from the wire and the driver has already consumed
     1589         * mac header. We need to restore it back. Moreover, after we are
     1590         * through with this skb we need to restore its original state!
     1591         */
     1592        skb_push(pBuf, pBuf->mac_len);
     1593        Log5(("vboxNetFltLinuxForwardToIntNet: mac_len=%d data=%p mac_header=%p network_header=%p\n",
     1594              pBuf->mac_len, pBuf->data, skb_mac_header(pBuf), skb_network_header(pBuf)));
     1595    }
     1596
     1597    vboxNetFltLinuxForwardToIntNetInner(pThis, pBuf, fSrc);
     1598   
     1599    /*
     1600     * Restore the original state of skb as there are other handlers this skb
     1601     * will be provided to.
     1602     */
     1603    if (RT_UNLIKELY(fSrc & INTNETTRUNKDIR_WIRE))
     1604        skb_pull(pBuf, pBuf->mac_len);
     1605
     1606    dev_kfree_skb(pBuf);
     1607}
     1608
    14531609
    14541610#ifndef VBOXNETFLT_LINUX_NO_XMIT_QUEUE
     
    14681624    struct sk_buff *pBuf;
    14691625
    1470     Log4(("vboxNetFltLinuxXmitTask: Got work %p.\n", pWork));
     1626    Log6(("vboxNetFltLinuxXmitTask: Got work %p.\n", pWork));
    14711627
    14721628    /*
     
    21072263            {
    21082264                vboxNetFltDumpPacket(pSG, true, "wire", 1);
    2109                 Log4(("vboxNetFltPortOsXmit: pBuf->cb dump:\n%.*Rhxd\n", sizeof(pBuf->cb), pBuf->cb));
    2110                 Log4(("vboxNetFltPortOsXmit: dev_queue_xmit(%p)\n", pBuf));
     2265                Log6(("vboxNetFltPortOsXmit: pBuf->cb dump:\n%.*Rhxd\n", sizeof(pBuf->cb), pBuf->cb));
     2266                Log6(("vboxNetFltPortOsXmit: dev_queue_xmit(%p)\n", pBuf));
    21112267                err = dev_queue_xmit(pBuf);
    21122268                if (err)
     
    21262282            {
    21272283                vboxNetFltDumpPacket(pSG, true, "host", (fDst & INTNETTRUNKDIR_WIRE) ? 0 : 1);
    2128                 Log4(("vboxNetFltPortOsXmit: pBuf->cb dump:\n%.*Rhxd\n", sizeof(pBuf->cb), pBuf->cb));
    2129                 Log4(("vboxNetFltPortOsXmit: netif_rx_ni(%p)\n", pBuf));
     2284                Log6(("vboxNetFltPortOsXmit: pBuf->cb dump:\n%.*Rhxd\n", sizeof(pBuf->cb), pBuf->cb));
     2285                Log6(("vboxNetFltPortOsXmit: netif_rx_ni(%p)\n", pBuf));
    21302286                err = netif_rx_ni(pBuf);
    21312287                if (err)
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette