Ejemplo n.º 1
0
/**
 * @brief computes dependencies and triggers port learning tree updates
 *
 * @param triggerPorts port map consisting in the ports which triggered the update
 *
 * This function browses through all the ports and determines how to waterfall the update
 * event from the trigger ports to all other ports depending on them.
 *
 * Once the list of ports to be updated is determined this function 
 * calls @ref ixEthDBCreateTrees.
 *
 * @internal
 */
IX_ETH_DB_PUBLIC
void ixEthDBUpdatePortLearningTrees(IxEthDBPortMap triggerPorts)
{
    IxEthDBPortMap updatePorts;
    UINT32 portIndex;
    
    ixEthDBUpdateLock();
    
    SET_EMPTY_DEPENDENCY_MAP(updatePorts);
    
    for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++)
    {
        PortInfo *port   = &ixEthDBPortInfo[portIndex];
        BOOL mapsCollide;
        
        MAPS_COLLIDE(mapsCollide, triggerPorts, port->dependencyPortMap);

        if (mapsCollide                                   /* do triggers influence this port? */
            && !IS_PORT_INCLUDED(portIndex, updatePorts)  /* and it's not already in the update list */
            && port->updateMethod.updateEnabled)          /* and we're allowed to update it */
        {
            IX_ETH_DB_UPDATE_TRACE("DB: (Update) Adding port %d to update set\n", portIndex);

            JOIN_PORT_TO_MAP(updatePorts, portIndex);
        }
        else
        {
            IX_ETH_DB_UPDATE_TRACE("DB: (Update) Didn't add port %d to update set, reasons follow:\n", portIndex);

            if (!mapsCollide)
            {
                IX_ETH_DB_UPDATE_TRACE("\tMaps don't collide on port %d\n", portIndex);
            }

            if (IS_PORT_INCLUDED(portIndex, updatePorts))
            {
                IX_ETH_DB_UPDATE_TRACE("\tPort %d is already in the update set\n", portIndex);
            }

            if (!port->updateMethod.updateEnabled)
            {
                IX_ETH_DB_UPDATE_TRACE("\tPort %d doesn't have updateEnabled set\n", portIndex);
            }
        }
    }
    
    IX_ETH_DB_UPDATE_TRACE("DB: (Update) Updating port set\n");

    ixEthDBCreateTrees(updatePorts);
        
    ixEthDBUpdateUnlock();
}
Ejemplo n.º 2
0
IX_ETH_DB_PUBLIC
IxEthDBStatus ixEthDBDatabaseClear(IxEthDBPortId portID, IxEthDBRecordType recordType)
{
    IxEthDBPortMap triggerPorts;
    HashIterator iterator;

    if (portID >= IX_ETH_DB_NUMBER_OF_PORTS && portID != IX_ETH_DB_ALL_PORTS)
    {
        return IX_ETH_DB_INVALID_PORT;
    }

    /* check if the user passes some extra bits */
    if ((recordType | IX_ETH_DB_ALL_RECORD_TYPES) != IX_ETH_DB_ALL_RECORD_TYPES)
    {
        return IX_ETH_DB_INVALID_ARG;
    }

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

    while (IS_ITERATOR_VALID(&iterator))
    {
        MacDescriptor *descriptor = (MacDescriptor *) iterator.node->data;

        if (((descriptor->portID == portID) || (portID == IX_ETH_DB_ALL_PORTS))
            && ((descriptor->type & recordType) != 0))
        {
            /* add to trigger if automatic updates are required */
            if (ixEthDBPortUpdateRequired[descriptor->type])
            {
                /* 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));
        }
    }

    /* update ports which lost records */
    ixEthDBUpdatePortLearningTrees(triggerPorts);
    
    return IX_ETH_DB_SUCCESS;
}
Ejemplo n.º 3
0
/**
 * @brief remove a record from the Ethernet database
 *
 * @param templateRecord template record used to determine
 * what record is to be removed
 * @param updateTrigger port map containing the update triggers
 * resulting from this update operation
 *
 * This function will examine the template record it receives
 * and attempts to delete a record of the same type and containing
 * the same keys as the template record. If deletion is successful
 * and the record type is registered for automatic port updates the
 * port will also be set in the updateTrigger port map, so that the
 * client can perform an update of the port.
 *
 * @retval IX_ETH_DB_SUCCESS removal was successful
 * @retval IX_ETH_DB_NO_SUCH_ADDR the record with the given MAC address was not found
 * @retval IX_ETH_DB_BUSY database busy, cannot remove due to locking
 *
 * @internal
 */
IX_ETH_DB_PUBLIC
IxEthDBStatus ixEthDBRemove(MacDescriptor *templateRecord, IxEthDBPortMap updateTrigger)
{
    IxEthDBStatus result;
    PortInfo *portInfo;
    
    TEST_FIXTURE_INCREMENT_DB_CORE_ACCESS_COUNTER;

    BUSY_RETRY_WITH_RESULT(ixEthDBRemoveHashEntry(&dbHashtable, ixEthDBKeyType[templateRecord->type], templateRecord), result);

    if (result != IX_ETH_DB_SUCCESS)
    {
        return IX_ETH_DB_NO_SUCH_ADDR; /* not found */
    }

    portInfo = &ixEthDBPortInfo[templateRecord->portID];

    if (templateRecord->type == IX_ETH_DB_WIFI_RECORD)
    {
        /* decrement the wifi records counter when entry is deleted from the database for the port */
	portInfo->wifiRecordsCount = portInfo->wifiRecordsCount - 1;
    }
        
    if (templateRecord->type == IX_ETH_DB_FIREWALL_RECORD || templateRecord->type == IX_ETH_DB_MASKED_FIREWALL_RECORD)
    {
        /* decrement the firewall records counter when entry is deleted from the database for the port */
	portInfo->fwRecordsCount = portInfo->fwRecordsCount - 1;
    }


    /* trigger add/remove update if required by type */
    if (updateTrigger != NULL 
        &&ixEthDBPortUpdateRequired[templateRecord->type])
    {
        /* add new port to update list */
        JOIN_PORT_TO_MAP(updateTrigger, templateRecord->portID);
    }
    
    return IX_ETH_DB_SUCCESS;
}
Ejemplo n.º 4
0
/**
 * @brief remove a record from the Ethernet database
 *
 * @param templateRecord template record used to determine
 * what record is to be removed
 * @param updateTrigger port map containing the update triggers
 * resulting from this update operation
 *
 * This function will examine the template record it receives
 * and attempts to delete a record of the same type and containing
 * the same keys as the template record. If deletion is successful
 * and the record type is registered for automatic port updates the
 * port will also be set in the updateTrigger port map, so that the
 * client can perform an update of the port.
 *
 * @retval IX_ETH_DB_SUCCESS removal was successful
 * @retval IX_ETH_DB_NO_SUCH_ADDR the record with the given MAC address was not found
 * @retval IX_ETH_DB_BUSY database busy, cannot remove due to locking
 *
 * @internal
 */
IX_ETH_DB_PUBLIC
IxEthDBStatus ixEthDBRemove(MacDescriptor *templateRecord, IxEthDBPortMap updateTrigger)
{
    IxEthDBStatus result;

    TEST_FIXTURE_INCREMENT_DB_CORE_ACCESS_COUNTER;

    BUSY_RETRY_WITH_RESULT(ixEthDBRemoveHashEntry(&dbHashtable, ixEthDBKeyType[templateRecord->type], templateRecord), result);

    if (result != IX_ETH_DB_SUCCESS)
    {
        return IX_ETH_DB_NO_SUCH_ADDR; /* not found */
    }

    /* trigger add/remove update if required by type */
    if (updateTrigger != NULL
        &&ixEthDBPortUpdateRequired[templateRecord->type])
    {
        /* add new port to update list */
        JOIN_PORT_TO_MAP(updateTrigger, templateRecord->portID);
    }

    return IX_ETH_DB_SUCCESS;
}
Ejemplo n.º 5
0
/**
 * @brief adds a new entry to the Ethernet database
 *
 * @param newRecordTemplate address of the record template to use
 * @param updateTrigger port map containing the update triggers
 * resulting from this update operation
 *
 * Creates a new database entry, populates it with the data
 * copied from the given template and adds the record to the
 * database hash table.
 * It also checks whether the new record type is registered to trigger
 * automatic updates; if it is, the update trigger will contain the
 * port on which the record insertion was performed, as well as the
 * old port in case the addition was a record migration (from one port
 * to the other). The caller can use the updateTrigger to trigger
 * automatic updates on the ports changed as a result of this addition.
 *
 * @retval IX_ETH_DB_SUCCESS addition successful
 * @retval IX_ETH_DB_NOMEM insertion failed, no memory left in the mac descriptor memory pool
 * @retval IX_ETH_DB_BUSY database busy, cannot insert due to locking
 *
 * @internal
 */
IX_ETH_DB_PUBLIC
IxEthDBStatus ixEthDBAdd(MacDescriptor *newRecordTemplate, IxEthDBPortMap updateTrigger)
{
    IxEthDBStatus result;
    MacDescriptor *newDescriptor;
    IxEthDBPortId originalPortID;
    HashNode *node = NULL;

    BUSY_RETRY(ixEthDBSearchHashEntry(&dbHashtable, ixEthDBKeyType[newRecordTemplate->type], newRecordTemplate, &node));

    TEST_FIXTURE_INCREMENT_DB_CORE_ACCESS_COUNTER;

    if (node == NULL)
    {
        /* not found, create a new one */
        newDescriptor = ixEthDBAllocMacDescriptor();

        if (newDescriptor == NULL)
        {
            return IX_ETH_DB_NOMEM; /* no memory */
        }

        /* old port does not exist, avoid unnecessary updates */
        originalPortID = newRecordTemplate->portID;
    }
    else
    {
        /* a node with the same key exists, will update node */
        newDescriptor = (MacDescriptor *) node->data;

        /* save original port id */
        originalPortID = newDescriptor->portID;
    }

    /* copy/update fields into new record */
    memcpy(newDescriptor->macAddress, newRecordTemplate->macAddress, sizeof (IxEthDBMacAddr));
    memcpy(&newDescriptor->recordData, &newRecordTemplate->recordData, sizeof (IxEthDBRecordData));

    newDescriptor->type   = newRecordTemplate->type;
    newDescriptor->portID = newRecordTemplate->portID;
    newDescriptor->user   = newRecordTemplate->user;

    if (node == NULL)
    {
        /* new record, insert into hashtable */
        BUSY_RETRY_WITH_RESULT(ixEthDBAddHashEntry(&dbHashtable, newDescriptor), result);

        if (result != IX_ETH_DB_SUCCESS)
        {
            ixEthDBFreeMacDescriptor(newDescriptor);

            return result; /* insertion failed */
        }
    }

    if (node != NULL)
    {
        /* release access */
        ixEthDBReleaseHashNode(node);
    }

    /* trigger add/remove update if required by type */
    if (updateTrigger != NULL &&
        ixEthDBPortUpdateRequired[newRecordTemplate->type])
    {
        /* add new port to update list */
        JOIN_PORT_TO_MAP(updateTrigger, newRecordTemplate->portID);

        /* check if record has moved, we'll need to update the old port as well */
        if (originalPortID != newDescriptor->portID)
        {
            JOIN_PORT_TO_MAP(updateTrigger, originalPortID);
        }
    }

    return IX_ETH_DB_SUCCESS;
}
Ejemplo n.º 6
0
/**
 * @brief disables a port
 *
 * @param portID ID of the port to disable
 *
 * This function is fully documented in the
 * main header file, IxEthDB.h
 *
 * @return IX_ETH_DB_SUCCESS if disabling was
 * successful or an appropriate error message 
 * otherwise
 */
IX_ETH_DB_PUBLIC
IxEthDBStatus ixEthDBPortDisable(IxEthDBPortId portID)
{
    HashIterator iterator;
    IxEthDBPortMap triggerPorts; /* ports who will have deleted records and therefore will need updating */
    BOOL result;
    PortInfo *portInfo;
    IxEthDBFeature learningEnabled;
    IxEthDBPriorityTable classZeroTable;

    IX_ETH_DB_CHECK_PORT_EXISTS(portID);

    IX_ETH_DB_CHECK_SINGLE_NPE(portID);
    
    portInfo = &ixEthDBPortInfo[portID];

    if (!portInfo->enabled)
    {
        /* redundant */
        return IX_ETH_DB_SUCCESS;
    }

    if (ixEthDBPortDefinitions[portID].type == IX_ETH_NPE)
    {
        /* save filtering state */
        ixEthDBPortState[portID].firewallMode            = portInfo->firewallMode;
        ixEthDBPortState[portID].frameFilter             = portInfo->frameFilter;
        ixEthDBPortState[portID].taggingAction           = portInfo->taggingAction;
        ixEthDBPortState[portID].stpBlocked              = portInfo->stpBlocked;
        ixEthDBPortState[portID].srcAddressFilterEnabled = portInfo->srcAddressFilterEnabled;
        ixEthDBPortState[portID].maxRxFrameSize          = portInfo->maxRxFrameSize;
        ixEthDBPortState[portID].maxTxFrameSize          = portInfo->maxTxFrameSize;

        memcpy(ixEthDBPortState[portID].vlanMembership, portInfo->vlanMembership, sizeof (IxEthDBVlanSet));
        memcpy(ixEthDBPortState[portID].transmitTaggingInfo, portInfo->transmitTaggingInfo, sizeof (IxEthDBVlanSet));
        memcpy(ixEthDBPortState[portID].priorityTable, portInfo->priorityTable, sizeof (IxEthDBPriorityTable));

        ixEthDBPortState[portID].saved = TRUE;

        /* now turn off all EthDB filtering features on the port */

        /* VLAN & QoS */
        if ((portInfo->featureCapability & IX_ETH_DB_VLAN_QOS) != 0)
        {
            ixEthDBPortVlanMembershipRangeAdd((IxEthDBPortId) portID, 0, IX_ETH_DB_802_1Q_MAX_VLAN_ID);
            ixEthDBEgressVlanRangeTaggingEnabledSet((IxEthDBPortId) portID, 0, IX_ETH_DB_802_1Q_MAX_VLAN_ID, FALSE);
            ixEthDBAcceptableFrameTypeSet((IxEthDBPortId) portID, IX_ETH_DB_ACCEPT_ALL_FRAMES);
            ixEthDBIngressVlanTaggingEnabledSet((IxEthDBPortId) portID, IX_ETH_DB_PASS_THROUGH);

            memset(classZeroTable, 0, sizeof (classZeroTable));
            ixEthDBPriorityMappingTableSet((IxEthDBPortId) portID, classZeroTable);
        }

        /* STP */
        if ((portInfo->featureCapability & IX_ETH_DB_SPANNING_TREE_PROTOCOL) != 0)
        {
            ixEthDBSpanningTreeBlockingStateSet((IxEthDBPortId) portID, FALSE);
        }

        /* Firewall */
        if ((portInfo->featureCapability & IX_ETH_DB_FIREWALL) != 0)
        {
            ixEthDBFirewallModeSet((IxEthDBPortId) portID, IX_ETH_DB_FIREWALL_BLACK_LIST);
            ixEthDBFirewallTableDownload((IxEthDBPortId) portID);
            ixEthDBFirewallInvalidAddressFilterEnable((IxEthDBPortId) portID, FALSE);
        }

        /* Frame size filter */
        ixEthDBFilteringPortMaximumFrameSizeSet((IxEthDBPortId) portID, IX_ETH_DB_DEFAULT_FRAME_SIZE);

        /* WiFi */
        if ((portInfo->featureCapability & IX_ETH_DB_WIFI_HEADER_CONVERSION) != 0)
        {
            ixEthDBWiFiConversionTableDownload((IxEthDBPortId) portID);
        }

        /* save and disable the learning feature bit */
        learningEnabled          = portInfo->featureStatus & IX_ETH_DB_LEARNING;
        portInfo->featureStatus &= ~IX_ETH_DB_LEARNING;
    }
    else
    {
        /* save the learning feature bit */
        learningEnabled          = portInfo->featureStatus & IX_ETH_DB_LEARNING;
    }
    
    SET_EMPTY_DEPENDENCY_MAP(triggerPorts);
    
    ixEthDBUpdateLock();
    
    /* wipe out current entries for this port */
    BUSY_RETRY(ixEthDBInitHashIterator(&dbHashtable, &iterator));

    while (IS_ITERATOR_VALID(&iterator))
    {
        MacDescriptor *descriptor =  (MacDescriptor *) iterator.node->data;
    
        /* check if the port match. If so, remove the entry  */
        if (descriptor->portID == portID 
                && (descriptor->type == IX_ETH_DB_FILTERING_RECORD || descriptor->type == IX_ETH_DB_FILTERING_VLAN_RECORD)
                && !descriptor->recordData.filteringData.staticEntry)
        {
            /* delete entry */
            BUSY_RETRY(ixEthDBRemoveEntryAtHashIterator(&dbHashtable, &iterator));
            
            /* add port to the set of update trigger ports */
            JOIN_PORT_TO_MAP(triggerPorts, portID);
        }
        else
        {
            /* move to the next record */
            BUSY_RETRY(ixEthDBIncrementHashIterator(&dbHashtable, &iterator));
        }
    }
    
    if (ixEthDBPortDefinitions[portID].type == IX_ETH_NPE)
    {
        if (portInfo->updateMethod.searchTree != NULL)
        {
            ixEthDBFreeMacTreeNode(portInfo->updateMethod.searchTree);
            portInfo->updateMethod.searchTree = NULL;
        }

        ixEthDBNPEUpdateHandler(portID, IX_ETH_DB_FILTERING_RECORD);
    }

    /* mark as disabled */
    portInfo->enabled = FALSE;
    
    /* disable updates unless the user has specifically altered the default behavior */
    if (ixEthDBPortDefinitions[portID].type == IX_ETH_NPE)
    {
        if (!portInfo->updateMethod.userControlled)
        {  
            portInfo->updateMethod.updateEnabled = FALSE;
        }
            
        /* make sure we re-initialize the NPE learning tree when the port is re-enabled */
        portInfo->updateMethod.treeInitialized = FALSE;
    }

    ixEthDBUpdateUnlock();

    /* restore learning feature bit */
    portInfo->featureStatus |= learningEnabled;

    /* if we've removed any records or lost any events make sure to force an update */
    IS_EMPTY_DEPENDENCY_MAP(result, triggerPorts);

    if (!result)
    {
        ixEthDBUpdatePortLearningTrees(triggerPorts);
    }
    
    return IX_ETH_DB_SUCCESS;
}
Ejemplo n.º 7
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);
    }
}