VirtualBox

Changeset 28140 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Apr 9, 2010 12:16:23 PM (15 years ago)
Author:
vboxsync
Message:

VBoxNetFlt-linux.c: Added some comments/todos and did some cleaning up while reading thru the code.

File:
1 edited

Legend:

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

    r28070 r28140  
    5050#include "../VBoxNetFltInternal.h"
    5151
    52 #define VBOX_FLT_NB_TO_INST(pNB) ((PVBOXNETFLTINS)((uint8_t *)pNB - \
    53                                   RT_OFFSETOF(VBOXNETFLTINS, u.s.Notifier)))
    54 #define VBOX_FLT_PT_TO_INST(pPT) ((PVBOXNETFLTINS)((uint8_t *)pPT - \
    55                                   RT_OFFSETOF(VBOXNETFLTINS, u.s.PacketType)))
    56 #define VBOX_FLT_XT_TO_INST(pXT) ((PVBOXNETFLTINS)((uint8_t *)pXT - \
    57                                   RT_OFFSETOF(VBOXNETFLTINS, u.s.XmitTask)))
    58 
    59 #define VBOX_GET_PCOUNT(pDev) (pDev->promiscuity)
     52
     53/*******************************************************************************
     54*   Defined Constants And Macros                                               *
     55*******************************************************************************/
     56#define VBOX_FLT_NB_TO_INST(pNB) ((PVBOXNETFLTINS)((uint8_t *)pNB - RT_OFFSETOF(VBOXNETFLTINS, u.s.Notifier)))
     57#define VBOX_FLT_PT_TO_INST(pPT) ((PVBOXNETFLTINS)((uint8_t *)pPT - RT_OFFSETOF(VBOXNETFLTINS, u.s.PacketType)))
     58#define VBOX_FLT_XT_TO_INST(pXT) ((PVBOXNETFLTINS)((uint8_t *)pXT - RT_OFFSETOF(VBOXNETFLTINS, u.s.XmitTask)))
    6059
    6160#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
    62 # define VBOX_SKB_RESET_NETWORK_HDR(skb) skb_reset_network_header(skb)
    63 # define VBOX_SKB_RESET_MAC_HDR(skb) skb_reset_mac_header(skb)
    64 #else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) */
    65 # define VBOX_SKB_RESET_NETWORK_HDR(skb) skb->nh.raw = skb->data
    66 # define VBOX_SKB_RESET_MAC_HDR(skb) skb->mac.raw = skb->data
    67 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) */
     61# define VBOX_SKB_RESET_NETWORK_HDR(skb)    skb_reset_network_header(skb)
     62# define VBOX_SKB_RESET_MAC_HDR(skb)        skb_reset_mac_header(skb)
     63#else
     64# define VBOX_SKB_RESET_NETWORK_HDR(skb)    skb->nh.raw = skb->data
     65# define VBOX_SKB_RESET_MAC_HDR(skb)        skb->mac.raw = skb->data
     66#endif
    6867
    6968#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
    70 # define VBOX_SKB_CHECKSUM_HELP(skb) skb_checksum_help(skb)
    71 #else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) */
    72 # define CHECKSUM_PARTIAL CHECKSUM_HW
     69# define VBOX_SKB_CHECKSUM_HELP(skb)        skb_checksum_help(skb)
     70#else
     71# define CHECKSUM_PARTIAL                   CHECKSUM_HW
    7372# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
    74 #  define VBOX_SKB_CHECKSUM_HELP(skb) skb_checksum_help(skb, 0)
    75 # else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) */
     73#  define VBOX_SKB_CHECKSUM_HELP(skb)       skb_checksum_help(skb, 0)
     74# else
    7675#  if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 7)
    77 #   define VBOX_SKB_CHECKSUM_HELP(skb) skb_checksum_help(&skb, 0)
    78 #  else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 7) */
    79 #   define VBOX_SKB_CHECKSUM_HELP(skb) (!skb_checksum_help(skb))
    80 #  endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 7) */
    81 # endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) */
    82 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) */
     76#   define VBOX_SKB_CHECKSUM_HELP(skb)      skb_checksum_help(&skb, 0)
     77#  else
     78#   define VBOX_SKB_CHECKSUM_HELP(skb)      (!skb_checksum_help(skb))
     79#  endif
     80# endif
     81#endif
    8382
    8483#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
    85 # define VBOX_SKB_IS_GSO(skb) skb_is_gso(skb)
    86                                         /* No features, very dumb device */
    87 # define VBOX_SKB_GSO_SEGMENT(skb) skb_gso_segment(skb, 0)
    88 #else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) */
    89 # define VBOX_SKB_IS_GSO(skb) false
    90 # define VBOX_SKB_GSO_SEGMENT(skb) NULL
    91 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) */
     84/** Indicates that the linux kernel may send us GSO frames. */
     85# define VBOXNETFLT_WITH_GSO  1
     86#endif
    9287
    9388#ifndef NET_IP_ALIGN
     
    9590#endif
    9691
    97 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
    98 unsigned dev_get_flags(const struct net_device *dev)
    99 {
    100         unsigned flags;
    101 
    102         flags = (dev->flags & ~(IFF_PROMISC |
    103                                 IFF_ALLMULTI |
    104                                 IFF_RUNNING)) |
    105                 (dev->gflags & (IFF_PROMISC |
    106                                 IFF_ALLMULTI));
    107 
    108         if (netif_running(dev) && netif_carrier_ok(dev))
    109                 flags |= IFF_RUNNING;
    110 
    111         return flags;
    112 }
    113 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) */
     92#if 0
     93/** Create scatter / gather segments for fragments. When not used, we will
     94 *  linearize the socket buffer before creating the internal networking SG. */
     95# define VBOXNETFLT_SG_SUPPORT 1
     96#endif
     97
    11498
    11599/*******************************************************************************
     
    137121MODULE_VERSION(VBOX_VERSION_STRING " (" RT_XSTR(INTNETTRUNKIFPORT_VERSION) ")");
    138122#endif
     123
     124
     125#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) && defined(LOG_ENABLED)
     126unsigned dev_get_flags(const struct net_device *dev)
     127{
     128    unsigned flags;
     129
     130    flags = (dev->flags & ~(IFF_PROMISC |
     131                            IFF_ALLMULTI |
     132                            IFF_RUNNING)) |
     133            (dev->gflags & (IFF_PROMISC |
     134                            IFF_ALLMULTI));
     135
     136    if (netif_running(dev) && netif_carrier_ok(dev))
     137        flags |= IFF_RUNNING;
     138
     139    return flags;
     140}
     141#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) */
    139142
    140143
     
    486489        }
    487490        pBuf = pCopy;
    488 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
     491# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
    489492        Log3(("vboxNetFltLinuxPacketHandler: skb copy 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",
    490493              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));
    491 #else
     494# else
    492495        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",
    493496              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));
    494 #endif
     497# endif
    495498    }
    496499#endif
     
    501504    Log4(("vboxNetFltLinuxPacketHandler: scheduled work %p for sk_buff %p\n",
    502505          &pThis->u.s.XmitTask, pBuf));
     506
    503507    /* It does not really matter what we return, it is ignored by the kernel. */
    504508    return 0;
    505509}
    506510
    507 static unsigned vboxNetFltLinuxSGSegments(PVBOXNETFLTINS pThis, struct sk_buff *pBuf)
     511/**
     512 * Calculate the number of INTNETSEG segments the socket buffer will need.
     513 *
     514 * @returns Segment count.
     515 * @param   pBuf                The socket buffer.
     516 */
     517DECLINLINE(unsigned) vboxNetFltLinuxCalcSGSegments(struct sk_buff *pBuf)
    508518{
    509519#ifdef VBOXNETFLT_SG_SUPPORT
     
    513523#endif
    514524#ifdef PADD_RUNT_FRAMES_FROM_HOST
    515     /*
    516      * Add a trailer if the frame is too small.
    517      */
     525    /* vboxNetFltLinuxSkBufToSG adds a padding segment if it's a runt. */
    518526    if (pBuf->len < 60)
    519527        cSegs++;
     
    522530}
    523531
    524 /* WARNING! This function should only be called after vboxNetFltLinuxSkBufToSG()! */
     532/**
     533 * Destroy the intnet scatter / gather buffer created by
     534 * vboxNetFltLinuxSkBufToSG and free the associated socket buffer.
     535 */
    525536static void  vboxNetFltLinuxFreeSkBuff(struct sk_buff *pBuf, PINTNETSG pSG)
    526537{
     
    566577#endif
    567578
     579/**
     580 * Worker for vboxNetFltLinuxForwardToIntNet.
     581 *
     582 * @returns VINF_SUCCESS or VERR_NO_MEMORY.
     583 * @param   pThis               The net filter instance.
     584 * @param   pBuf                The socket buffer.
     585 * @param   fSrc                The source.
     586 */
    568587static int vboxNetFltLinuxForwardSegment(PVBOXNETFLTINS pThis, struct sk_buff *pBuf, uint32_t fSrc)
    569588{
    570     unsigned cSegs = vboxNetFltLinuxSGSegments(pThis, pBuf);
    571     if (cSegs < MAX_SKB_FRAGS)
    572     {
    573         uint8_t *pTmp;
     589    unsigned cSegs = vboxNetFltLinuxCalcSGSegments(pBuf);
     590    if (cSegs < MAX_SKB_FRAGS + 1)
     591    {
    574592        PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs]));
    575593        if (!pSG)
     
    580598        vboxNetFltLinuxSkBufToSG(pThis, pBuf, pSG, cSegs, fSrc);
    581599
    582         pTmp = pSG->aSegs[0].pv;
    583600        vboxNetFltDumpPacket(pSG, false, (fSrc & INTNETTRUNKDIR_HOST) ? "host" : "wire", 1);
    584601        pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, fSrc);
     
    594611    uint32_t fSrc = pBuf->pkt_type == PACKET_OUTGOING ? INTNETTRUNKDIR_HOST : INTNETTRUNKDIR_WIRE;
    595612
    596     if (VBOX_SKB_IS_GSO(pBuf))
    597     {
    598         /* Need to segment the packet */
    599         struct sk_buff *pNext, *pSegment;
    600 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
    601     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",
    602           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));
    603 #endif
    604 
    605         pSegment = VBOX_SKB_GSO_SEGMENT(pBuf);
    606         if (IS_ERR(pSegment))
     613#ifdef VBOXNETFLT_WITH_GSO
     614    if (skb_is_gso(pBuf))
     615    {
     616        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",
     617              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));
     618# if 0 /** @todo receive -> GSO SGs. */
     619        if ()
    607620        {
     621            Log3(("vboxNetFltLinuxForwardToIntNet: GSO SG\n"));
     622            vboxNetFltLinuxForwardGso(pThis, pBuf, fSrc);
     623        }
     624        else
     625# endif
     626        {
     627            /* Need to segment the packet */
     628            struct sk_buff *pNext;
     629            struct sk_buff *pSegment = skb_gso_segment(pBuf, 0 /*supported features*/);
     630            if (IS_ERR(pSegment))
     631            {
     632                dev_kfree_skb(pBuf);
     633                LogRel(("VBoxNetFlt: Failed to segment a packet (%d).\n", PTR_ERR(pSegment)));
     634                return;
     635            }
     636            for (; pSegment; pSegment = pNext)
     637            {
     638                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",
     639                      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));
     640                pNext = pSegment->next;
     641                pSegment->next = 0;
     642                vboxNetFltLinuxForwardSegment(pThis, pSegment, fSrc);
     643            }
    608644            dev_kfree_skb(pBuf);
    609             LogRel(("VBoxNetFlt: Failed to segment a packet (%d).\n", PTR_ERR(pBuf)));
    610             return;
    611645        }
    612         for (; pSegment; pSegment = pNext)
    613         {
    614 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
    615             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",
    616                   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));
    617 #endif
    618             pNext = pSegment->next;
    619             pSegment->next = 0;
    620             vboxNetFltLinuxForwardSegment(pThis, pSegment, fSrc);
    621         }
    622         dev_kfree_skb(pBuf);
    623646    }
    624647    else
     648#endif /* VBOXNETFLT_WITH_GSO */
    625649    {
    626650        if (pBuf->ip_summed == CHECKSUM_PARTIAL && pBuf->pkt_type == PACKET_OUTGOING)
     
    650674        vboxNetFltLinuxForwardSegment(pThis, pBuf, fSrc);
    651675    }
    652     /*
    653      * Create a (scatter/)gather list for the sk_buff and feed it to the internal network.
    654      */
    655 }
    656 
     676}
     677
     678/**
     679 * Work queue handler that forwards the socket buffers queued by
     680 * vboxNetFltLinuxPacketHandler to the internal network.
     681 *
     682 * @param   pWork               The work queue.
     683 */
    657684#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
    658685static void vboxNetFltLinuxXmitTask(struct work_struct *pWork)
     
    661688#endif
    662689{
     690    PVBOXNETFLTINS  pThis   = VBOX_FLT_XT_TO_INST(pWork);
     691    RTSPINLOCKTMP   Tmp     = RTSPINLOCKTMP_INITIALIZER;
    663692    struct sk_buff *pBuf;
    664     bool fActive;
    665     PVBOXNETFLTINS pThis;
    666     RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
    667693
    668694    Log4(("vboxNetFltLinuxXmitTask: Got work %p.\n", pWork));
    669     pThis = VBOX_FLT_XT_TO_INST(pWork);
     695
    670696    /*
    671697     * Active? Retain the instance and increment the busy counter.
    672698     */
    673699    RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
    674     fActive = ASMAtomicUoReadBool(&pThis->fActive);
    675     if (fActive)
     700    if (ASMAtomicUoReadBool(&pThis->fActive))
     701    {
    676702        vboxNetFltRetain(pThis, true /* fBusy */);
    677     RTSpinlockRelease(pThis->hSpinlock, &Tmp);
    678     if (!fActive)
    679         return;
    680 
    681     while ((pBuf = skb_dequeue(&pThis->u.s.XmitQueue)) != 0)
    682         vboxNetFltLinuxForwardToIntNet(pThis, pBuf);
    683 
    684     vboxNetFltRelease(pThis, true /* fBusy */);
     703        RTSpinlockRelease(pThis->hSpinlock, &Tmp);
     704
     705        while ((pBuf = skb_dequeue(&pThis->u.s.XmitQueue)) != NULL)
     706            vboxNetFltLinuxForwardToIntNet(pThis, pBuf);
     707
     708        vboxNetFltRelease(pThis, true /* fBusy */);
     709    }
     710    else
     711    {
     712        RTSpinlockRelease(pThis->hSpinlock, &Tmp);
     713        /** @todo Shouldn't we just drop the packets here? There is little point in
     714         *        making them accumulate when the VM is paused and it'll only waste
     715         *        kernel memory anyway... Hmm. maybe wait a short while (2-5 secs)
     716         *        before start draining the packets (goes for the intnet ring buf
     717         *        too)? */
     718    }
    685719}
    686720
     
    777811        dev_set_promiscuity(pDev, 1);
    778812        ASMAtomicWriteBool(&pThis->u.s.fPromiscuousSet, true);
    779         Log(("vboxNetFltLinuxDeviceIsUp: enabled promiscuous mode on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pDev)));
     813        Log(("vboxNetFltLinuxDeviceIsUp: enabled promiscuous mode on %s (%d)\n", pThis->szName, pDev->promiscuity));
    780814    }
    781815    else
    782         Log(("vboxNetFltLinuxDeviceIsUp: no need to enable promiscuous mode on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pDev)));
     816        Log(("vboxNetFltLinuxDeviceIsUp: no need to enable promiscuous mode on %s (%d)\n", pThis->szName, pDev->promiscuity));
    783817    return NOTIFY_OK;
    784818}
     
    792826        dev_set_promiscuity(pDev, -1);
    793827        ASMAtomicWriteBool(&pThis->u.s.fPromiscuousSet, false);
    794         Log(("vboxNetFltLinuxDeviceGoingDown: disabled promiscuous mode on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pDev)));
     828        Log(("vboxNetFltLinuxDeviceGoingDown: disabled promiscuous mode on %s (%d)\n", pThis->szName, pDev->promiscuity));
    795829    }
    796830    else
    797         Log(("vboxNetFltLinuxDeviceGoingDown: no need to disable promiscuous mode on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pDev)));
     831        Log(("vboxNetFltLinuxDeviceGoingDown: no need to disable promiscuous mode on %s (%d)\n", pThis->szName, pDev->promiscuity));
    798832    return NOTIFY_OK;
    799833}
     
    9681002#ifdef LOG_ENABLED
    9691003        u_int16_t fIf;
    970         unsigned const cPromiscBefore = VBOX_GET_PCOUNT(pDev);
     1004        unsigned const cPromiscBefore = pDev->promiscuity;
    9711005#endif
    9721006        if (fActive)
     
    9781012            rtnl_unlock();
    9791013            pThis->u.s.fPromiscuousSet = true;
    980             Log(("vboxNetFltPortOsSetActive: enabled promiscuous mode on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pDev)));
     1014            Log(("vboxNetFltPortOsSetActive: enabled promiscuous mode on %s (%d)\n", pThis->szName, pDev->promiscuity));
    9811015        }
    9821016        else
     
    9871021                dev_set_promiscuity(pDev, -1);
    9881022                rtnl_unlock();
    989                 Log(("vboxNetFltPortOsSetActive: disabled promiscuous mode on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pDev)));
     1023                Log(("vboxNetFltPortOsSetActive: disabled promiscuous mode on %s (%d)\n", pThis->szName, pDev->promiscuity));
    9901024            }
    9911025            pThis->u.s.fPromiscuousSet = false;
     
    9931027#ifdef LOG_ENABLED
    9941028            fIf = dev_get_flags(pDev);
    995             Log(("VBoxNetFlt: fIf=%#x; %d->%d\n", fIf, cPromiscBefore, VBOX_GET_PCOUNT(pDev)));
     1029            Log(("VBoxNetFlt: fIf=%#x; %d->%d\n", fIf, cPromiscBefore, pDev->promiscuity));
    9961030#endif
    9971031        }
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