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; }
/** * @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; }