VirtualBox

Changeset 24757 in vbox for trunk


Ignore:
Timestamp:
Nov 18, 2009 12:55:18 PM (15 years ago)
Author:
vboxsync
Message:

#3987: Virtio: Control queue implementation and address filtering.

Location:
trunk/src/VBox/Devices
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Network/DevVirtioNet.cpp

    r24712 r24757  
    219219    STAMPROFILEADV         StatIOWriteHC;
    220220    STAMCOUNTER            StatIntsRaised;
     221    STAMCOUNTER            StatIntsSkipped;
    221222#endif /* VBOX_WITH_STATISTICS */
    222223};
     
    496497            Log(("%s vqueueNotify: Failed to raise an interrupt (%Vrc).\n", INSTANCE(pState), rc));
    497498    }
     499    else
     500    {
     501        STAM_COUNTER_INC(&pState->StatIntsSkipped);
     502    }
     503
    498504}
    499505
     
    11181124    PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIOWriteHC,          STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in HC",          "/Devices/VNet%d/IO/WriteHC", iInstance);
    11191125    PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIntsRaised,         STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,     "Number of raised interrupts",        "/Devices/VNet%d/Interrupts/Raised", iInstance);
     1126    PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIntsSkipped,        STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,     "Number of skipped interrupts",        "/Devices/VNet%d/Interrupts/Skipped", iInstance);
    11201127#endif /* VBOX_WITH_STATISTICS */
    11211128
     
    12061213#define VNET_TX_DELAY           150   /* 150 microseconds */
    12071214#define VNET_MAX_FRAME_SIZE     65536  // TODO: Is it the right limit?
     1215#define VNET_MAC_FILTER_LEN     32
     1216#define VNET_MAX_VID            (1 << 12)
    12081217
    12091218/* Virtio net features */
     
    12891298    uint32_t                u32PktNo;
    12901299
    1291     /** Locked state -- no state alteration possible. */
    1292     bool                    fLocked;
    1293 
    12941300    /** N/A: */
    12951301    bool volatile           fMaybeOutOfSpace;
     1302
     1303    /** Promiscuous mode -- RX filter accepts all packets. */
     1304    bool                    fPromiscuous;
     1305    /** AllMulti mode -- RX filter accepts all multicast packets. */
     1306    bool                    fAllMulti;
     1307    /** The number of actually used slots in aMacTable. */
     1308    uint32_t                nMacFilterEntries;
     1309    /** Array of MAC addresses accepted by RX filter. */
     1310    RTMAC                   aMacFilter[VNET_MAC_FILTER_LEN];
     1311    /** Bit array of VLAN filter, one bit per VLAN ID. */
     1312    uint8_t                 aVlanFilter[VNET_MAX_VID / sizeof(uint8_t)];
     1313
     1314#if HC_ARCH_BITS == 64
     1315    uint32_t    padding3;
     1316#endif
    12961317
    12971318    R3PTRTYPE(PVQUEUE)      pRxQueue;
     
    13381359AssertCompileMemberOffset(VNETSTATE, VPCI, 0);
    13391360
     1361#define VNET_OK                    0
     1362#define VNET_ERROR                 1
     1363typedef uint8_t VNETCTLACK;
     1364
     1365#define VNET_CTRL_CLS_RX_MODE          0
     1366#define VNET_CTRL_CMD_RX_MODE_PROMISC  0
     1367#define VNET_CTRL_CMD_RX_MODE_ALLMULTI 1
     1368
     1369#define VNET_CTRL_CLS_MAC              1
     1370#define VNET_CTRL_CMD_MAC_TABLE_SET    0
     1371
     1372#define VNET_CTRL_CLS_VLAN             2
     1373#define VNET_CTRL_CMD_VLAN_ADD         0
     1374#define VNET_CTRL_CMD_VLAN_DEL         1
     1375
     1376
     1377struct VNetCtlHdr
     1378{
     1379    uint8_t  u8Class;
     1380    uint8_t  u8Command;
     1381};
     1382typedef struct VNetCtlHdr VNETCTLHDR;
     1383typedef VNETCTLHDR *PVNETCTLHDR;
     1384AssertCompileSize(VNETCTLHDR, 2);
     1385
    13401386//- TODO: Leave here ----------------------------------------------------------
    13411387
     
    13591405PDMBOTHCBDECL(uint32_t) vnetGetHostFeatures(void *pvState)
    13601406{
    1361     // TODO: implement
    1362     return VNET_F_MAC | VNET_F_STATUS;
     1407    /* We support:
     1408     * - Host-provided MAC address
     1409     * - Link status reporting in config space
     1410     * - Control queue
     1411     * - RX mode setting
     1412     * - MAC filter table
     1413     * - VLAN filter
     1414     */
     1415    return VNET_F_MAC
     1416        | VNET_F_STATUS
     1417        | VNET_F_CTRL_VQ
     1418        | VNET_F_CTRL_RX
     1419        | VNET_F_CTRL_VLAN;
    13631420}
    13641421
     
    14141471    else
    14151472        STATUS = 0;
     1473    /*
     1474     * By default we pass all packets up since the older guests cannot control
     1475     * virtio mode.
     1476     */
     1477    pState->fPromiscuous      = true;
     1478    pState->fAllMulti         = false;
     1479    pState->nMacFilterEntries = 0;
     1480    memset(pState->aMacFilter,  0, VNET_MAC_FILTER_LEN * sizeof(RTMAC));
     1481    memset(pState->aVlanFilter, 0, sizeof(pState->aVlanFilter));
    14161482}
    14171483
     
    15811647
    15821648/**
    1583  * Determines if the packet is to be delivered to upper layer. The following
    1584  * filters supported:
    1585  * - Exact Unicast/Multicast
    1586  * - Promiscuous Unicast/Multicast
    1587  * - Multicast
    1588  * - VLAN
     1649 * Returns true if it is a broadcast packet.
     1650 *
     1651 * @returns true if destination address indicates broadcast.
     1652 * @param   pvBuf           The ethernet packet.
     1653 */
     1654DECLINLINE(bool) vnetIsBroadcast(const void *pvBuf)
     1655{
     1656    static const uint8_t s_abBcastAddr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
     1657    return memcmp(pvBuf, s_abBcastAddr, sizeof(s_abBcastAddr)) == 0;
     1658}
     1659
     1660/**
     1661 * Returns true if it is a multicast packet.
     1662 *
     1663 * @remarks returns true for broadcast packets as well.
     1664 * @returns true if destination address indicates multicast.
     1665 * @param   pvBuf           The ethernet packet.
     1666 */
     1667DECLINLINE(bool) vnetIsMulticast(const void *pvBuf)
     1668{
     1669    return (*(char*)pvBuf) & 1;
     1670}
     1671
     1672/**
     1673 * Determines if the packet is to be delivered to upper layer.
    15891674 *
    15901675 * @returns true if packet is intended for this node.
     
    15951680static bool vnetAddressFilter(PVNETSTATE pState, const void *pvBuf, size_t cb)
    15961681{
    1597     return true; // TODO: Implement!
     1682    if (pState->fPromiscuous)
     1683        return true;
     1684
     1685    /* Ignore everything outside of our VLANs */
     1686    uint16_t *u16Ptr = (uint16_t*)pvBuf;
     1687    /* Compare TPID with VLAN Ether Type */
     1688    if (   u16Ptr[6] == RT_H2BE_U16(0x8100)
     1689        && !ASMBitTest(pState->aVlanFilter, RT_BE2H_U16(u16Ptr[7]) & 0xFFF))
     1690        return false;
     1691
     1692    if (vnetIsBroadcast(pvBuf))
     1693        return true;
     1694
     1695    if (pState->fAllMulti && vnetIsMulticast(pvBuf))
     1696        return true;
     1697
     1698    if (!memcmp(pState->config.mac.au8, pvBuf, sizeof(RTMAC)))
     1699        return true;
     1700
     1701    for (unsigned i = 0; i < pState->nMacFilterEntries; i++)
     1702        if (!memcmp(&pState->aMacFilter[i], pvBuf, sizeof(RTMAC)))
     1703            return true;
     1704
     1705    return false;
    15981706}
    15991707
     
    18711979#endif /* !VNET_TX_DELAY */
    18721980
     1981static uint8_t vnetControlRx(PVNETSTATE pState, PVNETCTLHDR pCtlHdr, PVQUEUEELEM pElem)
     1982{
     1983    uint8_t u8Ack = VNET_OK;
     1984    uint8_t fOn;
     1985    PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
     1986                      pElem->aSegsOut[1].addr,
     1987                      &fOn, sizeof(fOn));
     1988    Log(("%s vnetControlRx: uCommand=%u fOn=%u\n", INSTANCE(pState), pCtlHdr->u8Command, fOn));
     1989    switch (pCtlHdr->u8Command)
     1990    {
     1991        case VNET_CTRL_CMD_RX_MODE_PROMISC:
     1992            pState->fPromiscuous = !!fOn;
     1993            break;
     1994        case VNET_CTRL_CMD_RX_MODE_ALLMULTI:
     1995            pState->fAllMulti = !!fOn;
     1996            break;
     1997        default:
     1998            u8Ack = VNET_ERROR;
     1999    }
     2000
     2001    return u8Ack;
     2002}
     2003
     2004static uint8_t vnetControlMac(PVNETSTATE pState, PVNETCTLHDR pCtlHdr, PVQUEUEELEM pElem)
     2005{
     2006    uint32_t nMacs = 0;
     2007
     2008    if (pCtlHdr->u8Command != VNET_CTRL_CMD_MAC_TABLE_SET
     2009        || pElem->nOut != 3
     2010        || pElem->aSegsOut[1].cb < sizeof(nMacs)
     2011        || pElem->aSegsOut[2].cb < sizeof(nMacs))
     2012    {
     2013        Log(("%s vnetControlMac: Segment layout is wrong "
     2014             "(u8Command=%u nOut=%u cb1=%u cb2=%u)\n", INSTANCE(pState),
     2015             pCtlHdr->u8Command, pElem->nOut,
     2016             pElem->aSegsOut[1].cb, pElem->aSegsOut[2].cb));
     2017        return VNET_ERROR;
     2018    }
     2019
     2020    /* Load unicast addresses */
     2021    PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
     2022                      pElem->aSegsOut[1].addr,
     2023                      &nMacs, sizeof(nMacs));
     2024
     2025    if (pElem->aSegsOut[1].cb < nMacs * sizeof(RTMAC) + sizeof(nMacs))
     2026    {
     2027        Log(("%s vnetControlMac: The unicast mac segment is too small "
     2028             "(nMacs=%u cb=%u)\n", INSTANCE(pState), pElem->aSegsOut[1].cb));
     2029        return VNET_ERROR;
     2030    }
     2031
     2032    if (nMacs > VNET_MAC_FILTER_LEN)
     2033    {
     2034        Log(("%s vnetControlMac: MAC table is too big, have to use promiscuous"
     2035             " mode (nMacs=%u)\n", INSTANCE(pState), nMacs));
     2036        pState->fPromiscuous = true;
     2037    }
     2038    else
     2039    {
     2040        if (nMacs)
     2041            PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
     2042                              pElem->aSegsOut[1].addr + sizeof(nMacs),
     2043                              pState->aMacFilter, nMacs * sizeof(RTMAC));
     2044        pState->nMacFilterEntries = nMacs;
     2045#ifdef DEBUG
     2046        Log(("%s vnetControlMac: unicast macs:\n", INSTANCE(pState)));
     2047        for(unsigned i = 0; i < nMacs; i++)
     2048            Log(("         %RTmac\n", &pState->aMacFilter[i]));
     2049#endif /* DEBUG */
     2050    }
     2051
     2052    /* Load multicast addresses */
     2053    PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
     2054                      pElem->aSegsOut[2].addr,
     2055                      &nMacs, sizeof(nMacs));
     2056
     2057    if (pElem->aSegsOut[2].cb < nMacs * sizeof(RTMAC) + sizeof(nMacs))
     2058    {
     2059        Log(("%s vnetControlMac: The multicast mac segment is too small "
     2060             "(nMacs=%u cb=%u)\n", INSTANCE(pState), pElem->aSegsOut[2].cb));
     2061        return VNET_ERROR;
     2062    }
     2063
     2064    if (nMacs > VNET_MAC_FILTER_LEN - pState->nMacFilterEntries)
     2065    {
     2066        Log(("%s vnetControlMac: MAC table is too big, have to use allmulti"
     2067             " mode (nMacs=%u)\n", INSTANCE(pState), nMacs));
     2068        pState->fAllMulti = true;
     2069    }
     2070    else
     2071    {
     2072        if (nMacs)
     2073            PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
     2074                              pElem->aSegsOut[2].addr + sizeof(nMacs),
     2075                              &pState->aMacFilter[pState->nMacFilterEntries],
     2076                              nMacs * sizeof(RTMAC));
     2077#ifdef DEBUG
     2078        Log(("%s vnetControlMac: multicast macs:\n", INSTANCE(pState)));
     2079        for(unsigned i = 0; i < nMacs; i++)
     2080            Log(("         %RTmac\n",
     2081                 &pState->aMacFilter[i+pState->nMacFilterEntries]));
     2082#endif /* DEBUG */
     2083        pState->nMacFilterEntries += nMacs;
     2084    }
     2085
     2086    return VNET_OK;
     2087}
     2088
     2089static uint8_t vnetControlVlan(PVNETSTATE pState, PVNETCTLHDR pCtlHdr, PVQUEUEELEM pElem)
     2090{
     2091    uint8_t  u8Ack = VNET_OK;
     2092    uint16_t u16Vid;
     2093
     2094    if (pElem->nOut != 2 || pElem->aSegsOut[1].cb != sizeof(u16Vid))
     2095    {
     2096        Log(("%s vnetControlVlan: Segment layout is wrong "
     2097             "(u8Command=%u nOut=%u cb=%u)\n", INSTANCE(pState),
     2098             pCtlHdr->u8Command, pElem->nOut, pElem->aSegsOut[1].cb));
     2099        return VNET_ERROR;
     2100    }
     2101
     2102    PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
     2103                      pElem->aSegsOut[1].addr,
     2104                      &u16Vid, sizeof(u16Vid));
     2105
     2106    if (u16Vid >= VNET_MAX_VID)
     2107    {
     2108        Log(("%s vnetControlVlan: VLAN ID is out of range "
     2109             "(VID=%u)\n", INSTANCE(pState), u16Vid));
     2110        return VNET_ERROR;
     2111    }
     2112
     2113    Log(("%s vnetControlVlan: uCommand=%u VID=%u\n", INSTANCE(pState),
     2114         pCtlHdr->u8Command, u16Vid));
     2115
     2116    switch (pCtlHdr->u8Command)
     2117    {
     2118        case VNET_CTRL_CMD_VLAN_ADD:
     2119            ASMBitSet(pState->aVlanFilter, u16Vid);
     2120            break;
     2121        case VNET_CTRL_CMD_VLAN_DEL:
     2122            ASMBitClear(pState->aVlanFilter, u16Vid);
     2123            break;
     2124        default:
     2125            u8Ack = VNET_ERROR;
     2126    }
     2127
     2128    return u8Ack;
     2129}
     2130
     2131
    18732132static DECLCALLBACK(void) vnetQueueControl(void *pvState, PVQUEUE pQueue)
    18742133{
    18752134    VNETSTATE *pState = (VNETSTATE*)pvState;
    1876     Log(("%s Pending control message\n", INSTANCE(pState)));
     2135    uint8_t u8Ack;
     2136    VQUEUEELEM elem;
     2137    while (vqueueGet(&pState->VPCI, pQueue, &elem))
     2138    {
     2139        unsigned int uOffset = 0;
     2140        if (elem.nOut < 1 || elem.aSegsOut[0].cb < sizeof(VNETCTLHDR))
     2141        {
     2142            Log(("%s vnetQueueControl: The first 'out' segment is not the "
     2143                 "header! (%u < 1 || %u < %u).\n", INSTANCE(pState), elem.nOut,
     2144                 elem.aSegsOut[0].cb,sizeof(VNETCTLHDR)));
     2145            vqueueElemFree(&elem);
     2146            break; /* Skip the element and hope the next one is good. */
     2147        }
     2148        else if (   elem.nIn < 1
     2149                 || elem.aSegsIn[elem.nIn - 1].cb < sizeof(VNETCTLACK))
     2150        {
     2151            Log(("%s vnetQueueControl: The last 'in' segment is too small "
     2152                 "to hold the acknowledge! (%u < 1 || %u < %u).\n",
     2153                 INSTANCE(pState), elem.nIn, elem.aSegsIn[elem.nIn - 1].cb,
     2154                 sizeof(VNETCTLACK)));
     2155            vqueueElemFree(&elem);
     2156            break; /* Skip the element and hope the next one is good. */
     2157        }
     2158        else
     2159        {
     2160            VNETCTLHDR CtlHdr;
     2161            PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
     2162                              elem.aSegsOut[0].addr,
     2163                              &CtlHdr, sizeof(CtlHdr));
     2164            switch (CtlHdr.u8Class)
     2165            {
     2166                case VNET_CTRL_CLS_RX_MODE:
     2167                    u8Ack = vnetControlRx(pState, &CtlHdr, &elem);
     2168                    break;
     2169                case VNET_CTRL_CLS_MAC:
     2170                    u8Ack = vnetControlMac(pState, &CtlHdr, &elem);
     2171                    break;
     2172                case VNET_CTRL_CLS_VLAN:
     2173                    u8Ack = vnetControlVlan(pState, &CtlHdr, &elem);
     2174                    break;
     2175                default:
     2176                    u8Ack = VNET_ERROR;
     2177            }
     2178            Log(("%s Processed control message %u, ack=%u.\n", INSTANCE(pState),
     2179                 CtlHdr.u8Class, u8Ack));
     2180            PDMDevHlpPhysWrite(pState->VPCI.CTX_SUFF(pDevIns),
     2181                               elem.aSegsIn[elem.nIn - 1].addr,
     2182                               &u8Ack, sizeof(u8Ack));
     2183        }
     2184        vqueuePut(&pState->VPCI, pQueue, &elem, sizeof(u8Ack));
     2185        vqueueSync(&pState->VPCI, pQueue);
     2186    }
    18772187}
    18782188
     
    19402250    /* Save device-specific part */
    19412251    rc = SSMR3PutMem( pSSM, pState->config.mac.au8, sizeof(pState->config.mac));
     2252    AssertRCReturn(rc, rc);
     2253    rc = SSMR3PutBool(pSSM, pState->fPromiscuous);
     2254    AssertRCReturn(rc, rc);
     2255    rc = SSMR3PutBool(pSSM, pState->fAllMulti);
     2256    AssertRCReturn(rc, rc);
     2257    rc = SSMR3PutU32( pSSM, pState->nMacFilterEntries);
     2258    AssertRCReturn(rc, rc);
     2259    rc = SSMR3PutMem( pSSM, pState->aMacFilter,
     2260                      pState->nMacFilterEntries * sizeof(RTMAC));
     2261    AssertRCReturn(rc, rc);
     2262    rc = SSMR3PutMem( pSSM, pState->aVlanFilter, sizeof(pState->aVlanFilter));
    19422263    AssertRCReturn(rc, rc);
    19432264    Log(("%s State has been saved\n", INSTANCE(pState)));
     
    20142335    if (uPass == SSM_PASS_FINAL)
    20152336    {
    2016         rc = SSMR3GetMem( pSSM, pState->config.mac.au8, sizeof(pState->config.mac));
     2337        rc = SSMR3GetMem( pSSM, pState->config.mac.au8,
     2338                          sizeof(pState->config.mac));
    20172339        AssertRCReturn(rc, rc);
     2340        if (uVersion > VIRTIO_SAVEDSTATE_VERSION_3_1_BETA1)
     2341        {
     2342            rc = SSMR3GetBool(pSSM, &pState->fPromiscuous);
     2343            AssertRCReturn(rc, rc);
     2344            rc = SSMR3GetBool(pSSM, &pState->fAllMulti);
     2345            AssertRCReturn(rc, rc);
     2346            rc = SSMR3GetU32(pSSM, &pState->nMacFilterEntries);
     2347            AssertRCReturn(rc, rc);
     2348            rc = SSMR3GetMem(pSSM, pState->aMacFilter,
     2349                             pState->nMacFilterEntries * sizeof(RTMAC));
     2350            AssertRCReturn(rc, rc);
     2351            /* Clear the rest. */
     2352            if (pState->nMacFilterEntries < VNET_MAC_FILTER_LEN)
     2353                memset(&pState->aMacFilter[pState->nMacFilterEntries],
     2354                       0,
     2355                       (VNET_MAC_FILTER_LEN - pState->nMacFilterEntries)
     2356                       * sizeof(RTMAC));
     2357            rc = SSMR3GetMem(pSSM, pState->aVlanFilter,
     2358                             sizeof(pState->aVlanFilter));
     2359            AssertRCReturn(rc, rc);
     2360        }
     2361        else
     2362        {
     2363            pState->fPromiscuous = true;
     2364            pState->fAllMulti = false;
     2365            pState->nMacFilterEntries = 0;
     2366            memset(pState->aMacFilter, 0, VNET_MAC_FILTER_LEN * sizeof(RTMAC));
     2367            memset(pState->aVlanFilter, 0, sizeof(pState->aVlanFilter));
     2368        }
    20182369    }
    20192370
     
    20952446
    20962447    /* Initialize state structure */
    2097     pState->fLocked      = false;
    20982448    pState->u32PktNo     = 1;
    20992449
  • trunk/src/VBox/Devices/testcase/tstDeviceStructSizeGC.cpp

    r24749 r24757  
    13621362    GEN_CHECK_OFF(VNETSTATE, pTxBuf);
    13631363    GEN_CHECK_OFF(VNETSTATE, pLinkUpTimer);
     1364#ifdef VNET_TX_DELAY
     1365    GEN_CHECK_OFF(VNETSTATE, pTxTimerR3);
     1366    GEN_CHECK_OFF(VNETSTATE, pTxTimerR0);
     1367    GEN_CHECK_OFF(VNETSTATE, pTxTimerRC);
     1368#endif /* VNET_TX_DELAY */
    13641369    GEN_CHECK_OFF(VNETSTATE, config);
    13651370    GEN_CHECK_OFF(VNETSTATE, macConfigured);
    13661371    GEN_CHECK_OFF(VNETSTATE, fCableConnected);
    13671372    GEN_CHECK_OFF(VNETSTATE, u32PktNo);
    1368     GEN_CHECK_OFF(VNETSTATE, fLocked);
     1373    GEN_CHECK_OFF(VNETSTATE, fPromiscuous);
     1374    GEN_CHECK_OFF(VNETSTATE, fAllMulti);
    13691375    GEN_CHECK_OFF(VNETSTATE, pRxQueue);
    13701376    GEN_CHECK_OFF(VNETSTATE, pTxQueue);
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