Example #1
0
IX_ETH_DB_PUBLIC
void ixEthDBDatabaseMaintenance()
{
    HashIterator iterator;
    UINT32 portIndex;
    BOOL agingRequired = FALSE;

    /* ports who will have deleted records and therefore will need updating */
    IxEthDBPortMap triggerPorts;

    if (IX_FEATURE_CTRL_SWCONFIG_ENABLED !=
        ixFeatureCtrlSwConfigurationCheck (IX_FEATURECTRL_ETH_LEARNING))
    {
        return;
    }

    SET_EMPTY_DEPENDENCY_MAP(triggerPorts);

    /* check if there's at least a port that needs aging */
    for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++)
    {
        if (ixEthDBPortInfo[portIndex].agingEnabled && ixEthDBPortInfo[portIndex].enabled)
        {
            agingRequired = TRUE;
        }
    }

    if (agingRequired)
    {
        /* ask each NPE port to write back the database for aging inspection */
        for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++)
        {
            if (ixEthDBPortDefinitions[portIndex].type == IX_ETH_NPE
                && ixEthDBPortInfo[portIndex].agingEnabled
                && ixEthDBPortInfo[portIndex].enabled)
            {
                IxNpeMhMessage message;
                IX_STATUS result;
                
                /* send EDB_GetMACAddressDatabase message */
                FILL_GETMACADDRESSDATABASE(message, 
                    0 /* unused */, 
                    IX_OSAL_MMU_VIRT_TO_PHYS(ixEthDBPortInfo[portIndex].updateMethod.npeUpdateZone));

                IX_ETHDB_SEND_NPE_MSG(IX_ETHNPE_PHYSICAL_ID_TO_NODE(portIndex), message, result);

                if (result == IX_SUCCESS)
                {
                    /* analyze NPE copy */
                    ixEthDBNPESyncScan(portIndex, ixEthDBPortInfo[portIndex].updateMethod.npeUpdateZone, FULL_ELT_BYTE_SIZE);

                    IX_ETH_DB_SUPPORT_TRACE("DB: (API) Finished scanning NPE tree on port %d\n", portIndex);
                }
                else
                {
                     ixOsalLog(IX_OSAL_LOG_LVL_WARNING,
                        IX_OSAL_LOG_DEV_STDOUT, 
                        "EthDB: (Maintenance) warning, Clearing Database records for all types for port %d\n",
                        portIndex, 0, 0, 0, 0, 0);

                    ixEthDBDatabaseClear(portIndex, IX_ETH_DB_ALL_RECORD_TYPES);
                }
            }
        }

        /* browse database and age entries */
        BUSY_RETRY(ixEthDBInitHashIterator(&dbHashtable, &iterator));

        while (IS_ITERATOR_VALID(&iterator))
        {
            MacDescriptor *descriptor = (MacDescriptor *) iterator.node->data;
            UINT32 *age               = NULL;
            BOOL staticEntry          = TRUE;

            if (descriptor->type == IX_ETH_DB_FILTERING_RECORD)
            {
                age         = &descriptor->recordData.filteringData.age;
                staticEntry = descriptor->recordData.filteringData.staticEntry;
            }
            else if (descriptor->type == IX_ETH_DB_FILTERING_VLAN_RECORD)
            {
                age         = &descriptor->recordData.filteringVlanData.age;
                staticEntry = descriptor->recordData.filteringVlanData.staticEntry;
            }
            else
            {
                staticEntry = TRUE;
            }

            if (ixEthDBPortInfo[descriptor->portID].agingEnabled && (staticEntry == FALSE))
            {
                /* manually increment the age if the port has no such capability */
                if ((ixEthDBPortDefinitions[descriptor->portID].capabilities & IX_ETH_ENTRY_AGING) == 0)
                {
                    *age += (IX_ETH_DB_MAINTENANCE_TIME / 60);
                }

                /* age entry if it exceeded the maximum time to live */
                if (*age >= (IX_ETH_DB_LEARNING_ENTRY_AGE_TIME / 60))
                {
                    /* add port to the set of update trigger ports */
                    JOIN_PORT_TO_MAP(triggerPorts, descriptor->portID);

                    /* delete entry */
                    BUSY_RETRY(ixEthDBRemoveEntryAtHashIterator(&dbHashtable, &iterator));
                }
                else
                {
                    /* move to the next record */
                    BUSY_RETRY(ixEthDBIncrementHashIterator(&dbHashtable, &iterator));
                }
            }
            else
            {
                /* move to the next record */
                BUSY_RETRY(ixEthDBIncrementHashIterator(&dbHashtable, &iterator));
            }
        }

        /* update ports which lost records */
        ixEthDBUpdatePortLearningTrees(triggerPorts);
    }
}
/**
 * @brief enables or disables a port capability
 *
 * @param portID ID of the port
 * @param feature feature to enable or disable
 * @param enabled TRUE to enable the selected feature or FALSE to disable it
 *
 * Note that this function is documented in the main component
 * header file, IxEthDB.h.
 *
 * @return IX_ETH_DB_SUCCESS if the operation completed
 * successfully or an appropriate error message otherwise
 */
IX_ETH_DB_PUBLIC
IxEthDBStatus ixEthDBFeatureEnable(IxEthDBPortId portID, IxEthDBFeature feature, BOOL enable)
{
    PortInfo *portInfo;
    IxEthDBPriorityTable defaultPriorityTable;
    IxEthDBVlanSet vlanSet;
    IxEthDBStatus status = IX_ETH_DB_SUCCESS;
    BOOL portEnabled;

    IX_ETH_DB_CHECK_PORT_INITIALIZED(portID);

    portInfo    = &ixEthDBPortInfo[portID];
    portEnabled = portInfo->enabled;

    /* check that only one feature is selected */
    if (!ixEthDBCheckSingleBitValue(feature))
    {
        return IX_ETH_DB_FEATURE_UNAVAILABLE;
    }

    /* port capable of this feature? */
    if ((portInfo->featureCapability & feature) == 0)
    {
        return IX_ETH_DB_FEATURE_UNAVAILABLE;
    }

    /* mutual exclusion between learning and WiFi header conversion */
    if (enable && ((feature | portInfo->featureStatus) & (IX_ETH_DB_FILTERING | IX_ETH_DB_WIFI_HEADER_CONVERSION))
            == (IX_ETH_DB_FILTERING | IX_ETH_DB_WIFI_HEADER_CONVERSION))
    {
        return IX_ETH_DB_NO_PERMISSION;
    }

    /* learning must be enabled before filtering */
    if (enable && (feature == IX_ETH_DB_FILTERING) && ((portInfo->featureStatus & IX_ETH_DB_LEARNING) == 0))
    {
        return IX_ETH_DB_NO_PERMISSION;
    }

    /* filtering must be disabled before learning */
    if (!enable && (feature == IX_ETH_DB_LEARNING) && ((portInfo->featureStatus & IX_ETH_DB_FILTERING) != 0))
    {
        return IX_ETH_DB_NO_PERMISSION;
    }

    /* redundant enabling or disabling */
    if ((!enable && ((portInfo->featureStatus & feature) == 0))
        || (enable && ((portInfo->featureStatus & feature) != 0)))
    {
        /* do nothing */
        return IX_ETH_DB_SUCCESS;
    }

    /* force port enabled */
    portInfo->enabled = TRUE;

    if (enable)
    {
        /* turn on enable bit */
        portInfo->featureStatus |= feature;

#ifdef CONFIG_WITH_VLAN /* test-only: VLAN support not included to save space!!! */
        /* if this is VLAN/QoS set the default priority table */
        if (feature == IX_ETH_DB_VLAN_QOS)
        {
            /* turn on VLAN/QoS (most permissive mode):
                - set default 802.1Q priority mapping table, in accordance to the
                  availability of traffic classes
                - set the acceptable frame filter to accept all
                - set the Ingress tagging mode to pass-through
                - set full VLAN membership list
                - set full TTI table
                - set the default 802.1Q tag to 0 (VLAN ID 0, Pri 0, CFI 0)
                - enable TPID port extraction
            */

            portInfo->ixEthDBTrafficClassCount = portInfo->ixEthDBTrafficClassAvailable;

            /* set default 802.1Q priority mapping table - note that C indexing starts from 0, so we substract 1 here */
            memcpy (defaultPriorityTable,
                (const void *) ixEthIEEE802_1QUserPriorityToTrafficClassMapping[portInfo->ixEthDBTrafficClassCount - 1],
                sizeof (defaultPriorityTable));

            /* update priority mapping and AQM queue assignments */
            status = ixEthDBPriorityMappingTableSet(portID, defaultPriorityTable);

            if (status == IX_ETH_DB_SUCCESS)
            {
                status = ixEthDBAcceptableFrameTypeSet(portID, IX_ETH_DB_ACCEPT_ALL_FRAMES);
            }

            if (status == IX_ETH_DB_SUCCESS)
            {
                status = ixEthDBIngressVlanTaggingEnabledSet(portID, IX_ETH_DB_PASS_THROUGH);
            }

            /* set membership and TTI tables */
            memset (vlanSet, 0xFF, sizeof (vlanSet));

            if (status == IX_ETH_DB_SUCCESS)
            {
                /* use the internal function to bypass PVID check */
                status = ixEthDBPortVlanTableSet(portID, portInfo->vlanMembership, vlanSet);
            }

            if (status == IX_ETH_DB_SUCCESS)
            {
                /* use the internal function to bypass PVID check */
                status = ixEthDBPortVlanTableSet(portID, portInfo->transmitTaggingInfo, vlanSet);
            }

            /* reset the PVID */
            if (status == IX_ETH_DB_SUCCESS)
            {
                status = ixEthDBPortVlanTagSet(portID, 0);
            }

            /* enable TPID port extraction */
            if (status == IX_ETH_DB_SUCCESS)
            {
                status = ixEthDBVlanPortExtractionEnable(portID, TRUE);
            }
        }
        else if (feature == IX_ETH_DB_FIREWALL)
#endif
        {
            /* firewall starts in black-list mode unless otherwise configured before *
             * note that invalid source MAC address filtering is disabled by default */
            if (portInfo->firewallMode != IX_ETH_DB_FIREWALL_BLACK_LIST
                && portInfo->firewallMode != IX_ETH_DB_FIREWALL_WHITE_LIST)
            {
                status = ixEthDBFirewallModeSet(portID, IX_ETH_DB_FIREWALL_BLACK_LIST);

                if (status == IX_ETH_DB_SUCCESS)
                {
                    status = ixEthDBFirewallInvalidAddressFilterEnable(portID, FALSE);
                }
            }
        }

        if (status != IX_ETH_DB_SUCCESS)
        {
            /* checks failed, disable */
            portInfo->featureStatus &= ~feature;
        }
    }
    else
    {
        /* turn off features */
        if (feature == IX_ETH_DB_FIREWALL)
        {
            /* turning off the firewall is equivalent to:
                - set to black-list mode
                - clear all the entries and download the new table
                - turn off the invalid source address checking
            */

            status = ixEthDBDatabaseClear(portID, IX_ETH_DB_FIREWALL_RECORD);

            if (status == IX_ETH_DB_SUCCESS)
            {
                status = ixEthDBFirewallModeSet(portID, IX_ETH_DB_FIREWALL_BLACK_LIST);
            }

            if (status == IX_ETH_DB_SUCCESS)
            {
                status = ixEthDBFirewallInvalidAddressFilterEnable(portID, FALSE);
            }

            if (status == IX_ETH_DB_SUCCESS)
            {
                status = ixEthDBFirewallTableDownload(portID);
            }
        }
        else if (feature == IX_ETH_DB_WIFI_HEADER_CONVERSION)
        {
            /* turn off header conversion */
            status = ixEthDBDatabaseClear(portID, IX_ETH_DB_WIFI_RECORD);

            if (status == IX_ETH_DB_SUCCESS)
            {
                status = ixEthDBWiFiConversionTableDownload(portID);
            }
        }
#ifdef CONFIG_WITH_VLAN /* test-only: VLAN support not included to save space!!! */
        else if (feature == IX_ETH_DB_VLAN_QOS)
        {
            /* turn off VLAN/QoS:
                - set a priority mapping table with one traffic class
                - set the acceptable frame filter to accept all
                - set the Ingress tagging mode to pass-through
                - clear the VLAN membership list
                - clear the TTI table
                - set the default 802.1Q tag to 0 (VLAN ID 0, Pri 0, CFI 0)
                - disable TPID port extraction
            */

            /* initialize all => traffic class 0 priority mapping table */
            memset (defaultPriorityTable, 0, sizeof (defaultPriorityTable));
            portInfo->ixEthDBTrafficClassCount = 1;
            status = ixEthDBPriorityMappingTableSet(portID, defaultPriorityTable);

            if (status == IX_ETH_DB_SUCCESS)
            {
                status = ixEthDBAcceptableFrameTypeSet(portID, IX_ETH_DB_ACCEPT_ALL_FRAMES);
            }

            if (status == IX_ETH_DB_SUCCESS)
            {
                status = ixEthDBIngressVlanTaggingEnabledSet(portID, IX_ETH_DB_PASS_THROUGH);
            }

            /* clear membership and TTI tables */
            memset (vlanSet, 0, sizeof (vlanSet));

            if (status == IX_ETH_DB_SUCCESS)
            {
                /* use the internal function to bypass PVID check */
                status = ixEthDBPortVlanTableSet(portID, portInfo->vlanMembership, vlanSet);
            }

            if (status == IX_ETH_DB_SUCCESS)
            {
                /* use the internal function to bypass PVID check */
                status = ixEthDBPortVlanTableSet(portID, portInfo->transmitTaggingInfo, vlanSet);
            }

            /* reset the PVID */
            if (status == IX_ETH_DB_SUCCESS)
            {
                status = ixEthDBPortVlanTagSet(portID, 0);
            }

            /* disable TPID port extraction */
            if (status == IX_ETH_DB_SUCCESS)
            {
                status = ixEthDBVlanPortExtractionEnable(portID, FALSE);
            }
        }
#endif

        if (status == IX_ETH_DB_SUCCESS)
        {
            /* checks passed, disable */
            portInfo->featureStatus &= ~feature;
        }
    }

    /* restore port enabled state */
    portInfo->enabled = portEnabled;

    return status;
}
Example #3
0
/**
 * @brief standard NPE update handler
 *
 * @param portID id of the port to be updated
 * @param type record type to be pushed during this update
 *
 * The NPE update handler manages updating the NPE databases
 * given a certain record type.
 *
 * @internal
 */
IX_ETH_DB_PUBLIC
IxEthDBStatus ixEthDBNPEUpdateHandler(IxEthDBPortId portID, IxEthDBRecordType type)
{
    UINT32 epDelta, blockCount;
    IxNpeMhMessage message;
    UINT32 treeSize = 0;
    PortInfo *port = &ixEthDBPortInfo[portID];

    /* size selection and type check */
    if (type == IX_ETH_DB_FILTERING_RECORD || type == IX_ETH_DB_WIFI_RECORD)
    {
        treeSize = FULL_ELT_BYTE_SIZE;
    }
    else if (type == IX_ETH_DB_FIREWALL_RECORD)
    {
        treeSize = FULL_FW_BYTE_SIZE;
    }
    else if (type == IX_ETH_DB_MASKED_FIREWALL_RECORD)
    {
        treeSize = FULL_FW_M_BYTE_SIZE;
    }
    else
    {
        return IX_ETH_DB_INVALID_ARG;
    }
    
    /* serialize tree into memory */
    ixEthDBNPETreeWrite(type, treeSize, port->updateMethod.npeUpdateZone, port->updateMethod.searchTree, &epDelta, &blockCount);

    /* free internal copy */
    if (port->updateMethod.searchTree != NULL)
    {
        ixEthDBFreeMacTreeNode(port->updateMethod.searchTree);
    }

    /* forget last used search tree */
    port->updateMethod.searchTree             = NULL;
    port->updateMethod.searchTreePendingWrite = FALSE;

    /* dependending on the update type we do different things */
    if (type == IX_ETH_DB_FILTERING_RECORD || type == IX_ETH_DB_WIFI_RECORD)
    {
        IX_STATUS result;

        FILL_SETMACADDRESSDATABASE_MSG(message, IX_ETHNPE_PHYSICAL_ID_TO_NODE_LOGICAL_ID(portID), 
            epDelta, blockCount, 
            IX_OSAL_MMU_VIRT_TO_PHYS(port->updateMethod.npeUpdateZone));

        IX_ETHDB_SEND_NPE_MSG(IX_ETHNPE_PHYSICAL_ID_TO_NODE(portID), message, result);

        if (result == IX_SUCCESS)
	{
            IX_ETH_DB_UPDATE_TRACE("DB: (PortUpdate) Finished downloading NPE tree on port %d\n", portID);
        }
        else
        {
            ixEthDBPortInfo[portID].agingEnabled                = FALSE;
            ixEthDBPortInfo[portID].updateMethod.updateEnabled  = FALSE;
            ixEthDBPortInfo[portID].updateMethod.userControlled = TRUE;

            ERROR_LOG("EthDB: (PortUpdate) disabling aging and updates on port %d (assumed dead)\n", portID);

            ixEthDBDatabaseClear(portID, IX_ETH_DB_ALL_RECORD_TYPES);

            return IX_ETH_DB_FAIL;
        }

	return IX_ETH_DB_SUCCESS;
    }
    else if (type & IX_ETH_DB_FIREWALL_RECORD)
    {
        return ixEthDBFirewallUpdate(portID, port->updateMethod.npeUpdateZone, epDelta);
    }
    
    return IX_ETH_DB_INVALID_ARG;
}