/** * @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; }
/** * @brief enables a port * * @param portID ID of the port to enable * * This function is fully documented in the main * header file, IxEthDB.h * * @return IX_ETH_DB_SUCCESS if enabling was * accomplished, or a meaningful error message otherwise */ IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBPortEnable(IxEthDBPortId portID) { IxEthDBPortMap triggerPorts; PortInfo *portInfo; 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; } SET_DEPENDENCY_MAP(triggerPorts, portID); /* mark as enabled */ portInfo->enabled = TRUE; /* Operation stops here when Ethernet Learning is not enabled */ if(IX_FEATURE_CTRL_SWCONFIG_DISABLED == ixFeatureCtrlSwConfigurationCheck(IX_FEATURECTRL_ETH_LEARNING)) { return IX_ETH_DB_SUCCESS; } if (ixEthDBPortDefinitions[portID].type == IX_ETH_NPE && !portInfo->macAddressUploaded) { IX_ETH_DB_SUPPORT_TRACE("DB: (Support) MAC address not set on port %d, enable failed\n", portID); /* must use UnicastAddressSet() before enabling an NPE port */ return IX_ETH_DB_MAC_UNINITIALIZED; } if (ixEthDBPortDefinitions[portID].type == IX_ETH_NPE) { IX_ETH_DB_SUPPORT_TRACE("DB: (Support) Attempting to enable the NPE callback for port %d...\n", portID); if (!portInfo->updateMethod.userControlled && ((portInfo->featureCapability & IX_ETH_DB_FILTERING) != 0)) { portInfo->updateMethod.updateEnabled = TRUE; } /* if this is first time initialization then we already have write access to the tree and can AccessRelease directly */ if (!portInfo->updateMethod.treeInitialized) { IX_ETH_DB_SUPPORT_TRACE("DB: (Support) Initializing tree for port %d\n", portID); /* create an initial tree and release access into it */ ixEthDBUpdatePortLearningTrees(triggerPorts); /* mark tree as being initialized */ portInfo->updateMethod.treeInitialized = TRUE; } } if (ixEthDBPortState[portID].saved) { /* previous configuration data stored, restore state */ if ((portInfo->featureCapability & IX_ETH_DB_FIREWALL) != 0) { ixEthDBFirewallModeSet(portID, ixEthDBPortState[portID].firewallMode); ixEthDBFirewallInvalidAddressFilterEnable(portID, ixEthDBPortState[portID].srcAddressFilterEnabled); } if ((portInfo->featureCapability & IX_ETH_DB_VLAN_QOS) != 0) { ixEthDBAcceptableFrameTypeSet(portID, ixEthDBPortState[portID].frameFilter); ixEthDBIngressVlanTaggingEnabledSet(portID, ixEthDBPortState[portID].taggingAction); ixEthDBEgressVlanTaggingEnabledSet(portID, ixEthDBPortState[portID].transmitTaggingInfo); ixEthDBPortVlanMembershipSet(portID, ixEthDBPortState[portID].vlanMembership); ixEthDBPriorityMappingTableSet(portID, ixEthDBPortState[portID].priorityTable); } if ((portInfo->featureCapability & IX_ETH_DB_SPANNING_TREE_PROTOCOL) != 0) { ixEthDBSpanningTreeBlockingStateSet(portID, ixEthDBPortState[portID].stpBlocked); } ixEthDBFilteringPortMaximumRxFrameSizeSet(portID, ixEthDBPortState[portID].maxRxFrameSize); ixEthDBFilteringPortMaximumTxFrameSizeSet(portID, ixEthDBPortState[portID].maxTxFrameSize); /* discard previous save */ ixEthDBPortState[portID].saved = FALSE; } IX_ETH_DB_SUPPORT_TRACE("DB: (Support) Enabling succeeded for port %d\n", portID); return IX_ETH_DB_SUCCESS; }
/** * @brief scans the capabilities of the loaded NPE images * * This function MUST be called by the ixEthDBInit() function. * No EthDB features (including learning and filtering) are enabled * before this function is called. * * @return none * * @internal */ IX_ETH_DB_PUBLIC void ixEthDBFeatureCapabilityScan(void) { IxNpeDlImageId imageId, npeAImageId; IxEthDBPortId portIndex; PortInfo *portInfo; IxEthDBPriorityTable defaultPriorityTable; IX_STATUS result; UINT32 queueIndex; UINT32 queueStructureIndex; UINT32 trafficClassDefinitionIndex; /* read version of NPE A - required to set the AQM queues for B and C */ npeAImageId.functionalityId = 0; ixNpeDlLoadedImageGet(IX_NPEDL_NPEID_NPEA, &npeAImageId); for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++) { IxNpeMhMessage msg; portInfo = &ixEthDBPortInfo[portIndex]; /* check and bypass if NPE B or C is fused out */ if (ixEthDBSingleEthNpeCheck(portIndex) != IX_ETH_DB_SUCCESS) continue; /* all ports are capable of LEARNING by default */ portInfo->featureCapability |= IX_ETH_DB_LEARNING; portInfo->featureStatus |= IX_ETH_DB_LEARNING; if (ixEthDBPortDefinitions[portIndex].type == IX_ETH_NPE) { if (ixNpeDlLoadedImageGet(IX_ETH_DB_PORT_ID_TO_NPE(portIndex), &imageId) != IX_SUCCESS) { WARNING_LOG("DB: (FeatureScan) NpeDl did not provide the image ID for NPE port %d\n", portIndex); } else { /* initialize and empty NPE response mutex */ ixOsalMutexInit(&portInfo->npeAckLock); ixOsalMutexLock(&portInfo->npeAckLock, IX_OSAL_WAIT_FOREVER); /* check NPE response to GetStatus */ msg.data[0] = IX_ETHNPE_NPE_GETSTATUS << 24; msg.data[1] = 0; IX_ETHDB_SEND_NPE_MSG(IX_ETH_DB_PORT_ID_TO_NPE(portIndex), msg, result); if (result != IX_SUCCESS) { WARNING_LOG("DB: (FeatureScan) warning, could not send message to the NPE\n"); continue; } if (imageId.functionalityId == 0x00 || imageId.functionalityId == 0x03 || imageId.functionalityId == 0x04 || imageId.functionalityId == 0x80) { portInfo->featureCapability |= IX_ETH_DB_FILTERING; portInfo->featureCapability |= IX_ETH_DB_FIREWALL; portInfo->featureCapability |= IX_ETH_DB_SPANNING_TREE_PROTOCOL; } else if (imageId.functionalityId == 0x01 || imageId.functionalityId == 0x81) { portInfo->featureCapability |= IX_ETH_DB_FILTERING; portInfo->featureCapability |= IX_ETH_DB_FIREWALL; portInfo->featureCapability |= IX_ETH_DB_SPANNING_TREE_PROTOCOL; portInfo->featureCapability |= IX_ETH_DB_VLAN_QOS; } else if (imageId.functionalityId == 0x02 || imageId.functionalityId == 0x82) { portInfo->featureCapability |= IX_ETH_DB_WIFI_HEADER_CONVERSION; portInfo->featureCapability |= IX_ETH_DB_FIREWALL; portInfo->featureCapability |= IX_ETH_DB_SPANNING_TREE_PROTOCOL; portInfo->featureCapability |= IX_ETH_DB_VLAN_QOS; } /* reset AQM queues */ memset(portInfo->ixEthDBTrafficClassAQMAssignments, 0, sizeof (portInfo->ixEthDBTrafficClassAQMAssignments)); /* ensure there's at least one traffic class record in the definition table, otherwise we have no default case, hence no queues */ IX_ENSURE(sizeof (ixEthDBTrafficClassDefinitions) != 0, "DB: no traffic class definitions found, check IxEthDBQoS.h"); /* find the traffic class definition index compatible with the current NPE A functionality ID */ for (trafficClassDefinitionIndex = 0 ; trafficClassDefinitionIndex < sizeof (ixEthDBTrafficClassDefinitions) / sizeof (ixEthDBTrafficClassDefinitions[0]); trafficClassDefinitionIndex++) { if (ixEthDBTrafficClassDefinitions[trafficClassDefinitionIndex][IX_ETH_DB_NPE_A_FUNCTIONALITY_ID_INDEX] == npeAImageId.functionalityId) { /* found it */ break; } } /* select the default case if we went over the array boundary */ if (trafficClassDefinitionIndex == sizeof (ixEthDBTrafficClassDefinitions) / sizeof (ixEthDBTrafficClassDefinitions[0])) { trafficClassDefinitionIndex = 0; /* the first record is the default case */ } /* select queue assignment structure based on the traffic class configuration index */ queueStructureIndex = ixEthDBTrafficClassDefinitions[trafficClassDefinitionIndex][IX_ETH_DB_QUEUE_ASSIGNMENT_INDEX]; /* only traffic class 0 is active at initialization time */ portInfo->ixEthDBTrafficClassCount = 1; /* enable port, VLAN and Firewall feature bits to initialize QoS/VLAN/Firewall configuration */ portInfo->featureStatus |= IX_ETH_DB_VLAN_QOS; portInfo->featureStatus |= IX_ETH_DB_FIREWALL; portInfo->enabled = TRUE; #define CONFIG_WITH_VLAN /* test-only: VLAN support not included to save space!!! */ #ifdef CONFIG_WITH_VLAN /* test-only: VLAN support not included to save space!!! */ /* set VLAN initial configuration (permissive) */ if ((portInfo->featureCapability & IX_ETH_DB_VLAN_QOS) != 0) /* QoS-enabled image */ { /* QoS capable */ portInfo->ixEthDBTrafficClassAvailable = ixEthDBTrafficClassDefinitions[trafficClassDefinitionIndex][IX_ETH_DB_TRAFFIC_CLASS_COUNT_INDEX]; /* set AQM queues */ for (queueIndex = 0 ; queueIndex < IX_IEEE802_1Q_QOS_PRIORITY_COUNT ; queueIndex++) { portInfo->ixEthDBTrafficClassAQMAssignments[queueIndex] = ixEthDBQueueAssignments[queueStructureIndex][queueIndex]; } /* set default PVID (0) and default traffic class 0 */ ixEthDBPortVlanTagSet(portIndex, 0); /* enable reception of all frames */ ixEthDBAcceptableFrameTypeSet(portIndex, IX_ETH_DB_ACCEPT_ALL_FRAMES); /* clear full VLAN membership */ ixEthDBPortVlanMembershipRangeRemove(portIndex, 0, IX_ETH_DB_802_1Q_MAX_VLAN_ID); /* clear TTI table - no VLAN tagged frames will be transmitted */ ixEthDBEgressVlanRangeTaggingEnabledSet(portIndex, 0, 4094, FALSE); /* set membership on 0, otherwise no Tx or Rx is working */ ixEthDBPortVlanMembershipAdd(portIndex, 0); } else /* QoS not available in this image */ #endif /* test-only */ { /* initialize traffic class availability (only class 0 is available) */ portInfo->ixEthDBTrafficClassAvailable = 1; /* point all AQM queues to traffic class 0 */ for (queueIndex = 0 ; queueIndex < IX_IEEE802_1Q_QOS_PRIORITY_COUNT ; queueIndex++) { portInfo->ixEthDBTrafficClassAQMAssignments[queueIndex] = ixEthDBQueueAssignments[queueStructureIndex][0]; } } #ifdef CONFIG_WITH_VLAN /* test-only: VLAN support not included to save space!!! */ /* download priority mapping table and Rx queue configuration */ memset (defaultPriorityTable, 0, sizeof (defaultPriorityTable)); ixEthDBPriorityMappingTableSet(portIndex, defaultPriorityTable); #endif /* by default we turn off invalid source MAC address filtering */ ixEthDBFirewallInvalidAddressFilterEnable(portIndex, FALSE); /* disable port, VLAN, Firewall feature bits */ portInfo->featureStatus &= ~IX_ETH_DB_VLAN_QOS; portInfo->featureStatus &= ~IX_ETH_DB_FIREWALL; portInfo->enabled = FALSE; /* enable filtering by default if present */ if ((portInfo->featureCapability & IX_ETH_DB_FILTERING) != 0) { portInfo->featureStatus |= IX_ETH_DB_FILTERING; } } } } }
/** * @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 scans the capabilities of the loaded NPE images * * This function MUST be called by the ixEthDBInit() function. * No EthDB features (including learning and filtering) are enabled * before this function is called. * * @return none * * @internal */ IX_ETH_DB_PUBLIC void ixEthDBFeatureCapabilityScan(void) { UINT8 functionalityId, npeAFunctionalityId; IxEthDBPortId portIndex; PortInfo *portInfo; IxEthDBPriorityTable defaultPriorityTable; IX_STATUS result; UINT32 queueIndex; UINT32 queueStructureIndex; UINT32 trafficClassDefinitionIndex, totalTrafficClass; totalTrafficClass = sizeof (ixEthDBTrafficClassDefinitions) / sizeof (ixEthDBTrafficClassDefinitions[0]); /* ensure there's at least 2 traffic class records in the definition table, otherwise we have no default cases, hence no queues */ IX_ENSURE(totalTrafficClass >= 2, "DB: no traffic class definitions found, check IxEthDBQoS.h"); /* read version of NPE A - required to set the AQM queues for B and C */ npeAFunctionalityId = 0; if(IX_FAIL == ixNpeDlLoadedImageFunctionalityGet(IX_NPEDL_NPEID_NPEA, &npeAFunctionalityId)) { /* IX_FAIL is returned when there is no image loaded in NPEA. Then we can use all 8 queues */ trafficClassDefinitionIndex = 1; /* the second record is the default if no image loaded */ } else { /* find the traffic class definition index compatible with the current NPE A functionality ID */ for (trafficClassDefinitionIndex = 0 ; trafficClassDefinitionIndex < totalTrafficClass ; trafficClassDefinitionIndex++) { if (ixEthDBTrafficClassDefinitions[trafficClassDefinitionIndex][IX_ETH_DB_NPE_A_FUNCTIONALITY_ID_INDEX] == npeAFunctionalityId) { /* found it */ break; } } /* select the default case if we went over the array boundary */ if (trafficClassDefinitionIndex == totalTrafficClass) { trafficClassDefinitionIndex = 0; /* the first record is the default case */ } } /* To decide port definition for NPE A - IX_ETH_NPE or IX_ETH_GENERIC IX_ETH_NPE will be set for NPE A when the functionality id is ranged from 0x80 to 0x8F and ethernet + hss co-exists images range from 0x90 to 0x9F. For the rest of functionality Ids, the port type will be set to IX_ETH_GENERIC. */ if ((npeAFunctionalityId & 0xF0) != 0x80 && (npeAFunctionalityId & 0xF0) != 0x90) { /* NPEA is not Ethernet capable. Override default port definition */ ixEthDBPortDefinitions[IX_NPEA_PORT].type = IX_ETH_GENERIC; } /* select queue assignment structure based on the traffic class configuration index */ queueStructureIndex = ixEthDBTrafficClassDefinitions[trafficClassDefinitionIndex][IX_ETH_DB_QUEUE_ASSIGNMENT_INDEX]; for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++) { IxNpeMhMessage msg; portInfo = &ixEthDBPortInfo[portIndex]; /* check and bypass if NPE A, B or C is fused out */ if (ixEthDBSingleEthNpeCheck(portIndex) != IX_ETH_DB_SUCCESS) continue; /* all ports are capable of LEARNING by default */ portInfo->featureCapability = IX_ETH_DB_LEARNING; portInfo->featureStatus = IX_ETH_DB_LEARNING; if (ixEthDBPortDefinitions[portIndex].type == IX_ETH_NPE) { if (IX_SUCCESS != ixNpeDlLoadedImageFunctionalityGet(IX_ETHNPE_PHYSICAL_ID_TO_NODE(portIndex), &functionalityId)) { WARNING_LOG("DB: (FeatureScan) NpeDl did not provide the image ID for NPE port %d\n", portIndex); } else { /* initialize and empty NPE response mutex */ ixOsalMutexInit(&portInfo->npeAckLock); ixOsalMutexLock(&portInfo->npeAckLock, IX_OSAL_WAIT_FOREVER); /* check NPE response to GetStatus */ msg.data[0] = IX_ETHNPE_NPE_GETSTATUS << 24; msg.data[1] = 0; IX_ETHDB_SEND_NPE_MSG(IX_ETHNPE_PHYSICAL_ID_TO_NODE(portIndex), msg, result); if (result != IX_SUCCESS) { WARNING_LOG("DB: (FeatureScan) warning, %d port could not send message to the NPE\n", portIndex); continue; } if (functionalityId == 0x00 || functionalityId == 0x03 || functionalityId == 0x04 || functionalityId == 0x80) { portInfo->featureCapability |= IX_ETH_DB_FILTERING; portInfo->featureCapability |= IX_ETH_DB_FIREWALL; portInfo->featureCapability |= IX_ETH_DB_SPANNING_TREE_PROTOCOL; } else if (functionalityId == 0x01 || functionalityId == 0x81 || functionalityId == 0x0B || functionalityId == 0x8B || functionalityId == 0x90) { portInfo->featureCapability |= IX_ETH_DB_FILTERING; portInfo->featureCapability |= IX_ETH_DB_FIREWALL; portInfo->featureCapability |= IX_ETH_DB_SPANNING_TREE_PROTOCOL; portInfo->featureCapability |= IX_ETH_DB_VLAN_QOS; } else if (functionalityId == 0x02 || functionalityId == 0x82 || functionalityId == 0x0D || functionalityId == 0x8D || functionalityId == 0x91) { portInfo->featureCapability |= IX_ETH_DB_WIFI_HEADER_CONVERSION; portInfo->featureCapability |= IX_ETH_DB_FIREWALL; portInfo->featureCapability |= IX_ETH_DB_SPANNING_TREE_PROTOCOL; portInfo->featureCapability |= IX_ETH_DB_VLAN_QOS; } else if (functionalityId == 0x0C || functionalityId == 0x8C) { portInfo->featureCapability |= IX_ETH_DB_WIFI_HEADER_CONVERSION; portInfo->featureCapability |= IX_ETH_DB_SPANNING_TREE_PROTOCOL; portInfo->featureCapability |= IX_ETH_DB_VLAN_QOS; } /* check if image supports mask based firewall */ if (functionalityId == 0x0B || functionalityId == 0x8B || functionalityId == 0x0D || functionalityId == 0x8D || functionalityId == 0x90 || functionalityId == 0x91) { /* this feature is always on and is based on the NPE */ portInfo->featureStatus |= IX_ETH_DB_ADDRESS_MASKING; portInfo->featureCapability |= IX_ETH_DB_ADDRESS_MASKING; } /* reset AQM queues */ ixOsalMemSet(portInfo->ixEthDBTrafficClassAQMAssignments, 0, sizeof (portInfo->ixEthDBTrafficClassAQMAssignments)); /* only traffic class 0 is active at initialization time */ portInfo->ixEthDBTrafficClassCount = 1; /* enable port, VLAN and Firewall feature bits to initialize QoS/VLAN/Firewall configuration */ portInfo->featureStatus |= IX_ETH_DB_VLAN_QOS; portInfo->featureStatus |= IX_ETH_DB_FIREWALL; portInfo->enabled = TRUE; /* set VLAN initial configuration (permissive) */ if ((portInfo->featureCapability & IX_ETH_DB_VLAN_QOS) != 0) /* QoS-enabled image */ { /* QoS capable */ portInfo->ixEthDBTrafficClassAvailable = ixEthDBTrafficClassDefinitions[trafficClassDefinitionIndex][IX_ETH_DB_TRAFFIC_CLASS_COUNT_INDEX]; /* set AQM queues */ for (queueIndex = 0 ; queueIndex < IX_IEEE802_1Q_QOS_PRIORITY_COUNT ; queueIndex++) { portInfo->ixEthDBTrafficClassAQMAssignments[queueIndex] = ixEthDBQueueAssignments[queueStructureIndex][queueIndex]; } /* set default PVID (0) and default traffic class 0 */ ixEthDBPortVlanTagSet(portIndex, 0); /* enable reception of all frames */ ixEthDBAcceptableFrameTypeSet(portIndex, IX_ETH_DB_ACCEPT_ALL_FRAMES); /* clear full VLAN membership */ ixEthDBPortVlanMembershipRangeRemove(portIndex, 0, IX_ETH_DB_802_1Q_MAX_VLAN_ID); /* clear TTI table - no VLAN tagged frames will be transmitted */ ixEthDBEgressVlanRangeTaggingEnabledSet(portIndex, 0, 4094, FALSE); /* set membership on 0, otherwise no Tx or Rx is working */ ixEthDBPortVlanMembershipAdd(portIndex, 0); } else /* QoS not available in this image */ { /* initialize traffic class availability (only class 0 is available) */ portInfo->ixEthDBTrafficClassAvailable = 1; /* point all AQM queues to traffic class 0 */ for (queueIndex = 0 ; queueIndex < IX_IEEE802_1Q_QOS_PRIORITY_COUNT ; queueIndex++) { portInfo->ixEthDBTrafficClassAQMAssignments[queueIndex] = ixEthDBQueueAssignments[queueStructureIndex][0]; } } /* download priority mapping table and Rx queue configuration */ ixOsalMemSet (defaultPriorityTable, 0, sizeof (defaultPriorityTable)); ixEthDBPriorityMappingTableSet(portIndex, defaultPriorityTable); /* by default we turn on invalid source MAC address filtering */ ixEthDBFirewallInvalidAddressFilterEnable(portIndex, TRUE); /* Notify VLAN tagging is disabled */ if (ixEthDBIngressVlanTaggingEnabledSet(portIndex, IX_ETH_DB_DISABLE_VLAN) != IX_SUCCESS) { WARNING_LOG("DB: (FeatureScan) warning, %d port could not disable VLAN \n", portIndex); continue; } /* disable port, VLAN, Firewall feature bits */ portInfo->featureStatus &= ~IX_ETH_DB_VLAN_QOS; portInfo->featureStatus &= ~IX_ETH_DB_FIREWALL; portInfo->enabled = FALSE; /* enable filtering by default if present */ if ((portInfo->featureCapability & IX_ETH_DB_FILTERING) != 0) { portInfo->featureStatus |= IX_ETH_DB_FILTERING; } } } } }
/* * Function definition: ixEthAccCodeletSwBridgeQoSStart() * * Configure QoS and Start bridge datapath */ IX_STATUS ixEthAccCodeletSwBridgeQoSStart(IxEthAccPortId firstPortId, IxEthAccPortId secondPortId) { UINT32 firstPortCbTag = firstPortId | (secondPortId << 16); UINT32 secondPortCbTag = secondPortId | (firstPortId << 16); IxEthDBPriorityTable priorityTable = { 0,1,2,3,4,5,6,7}; IxEthDBFeature featureSet = 0; if (firstPortId == secondPortId) { printf("SwBridgeQoS: Cannot configure a Bridge Operation between port %u and port %u (ports must be different)\n", firstPortId, secondPortId); return (IX_FAIL); } /* initialize pendingTx for both ports */ pendingTx[firstPortId] = pendingTx[secondPortId] = 0; /* register the rx/tx callback */ if ( ixEthAccCodeletPortConfigure(firstPortId, ixEthAccCodeletSwBridgeQoSTaggedToUntaggedRxCB, (IxEthAccPortMultiBufferRxCallback) NULL, ixEthAccCodeletSwBridgeQoSTxCB, firstPortCbTag) != IX_SUCCESS) { printf("SwBridgeQoS: Failed to configure the Bridge Operation for port %u\n", firstPortId); return (IX_FAIL); } if ( ixEthAccCodeletPortConfigure(secondPortId, ixEthAccCodeletSwBridgeQoSUntaggedToTaggedRxCB, NULL, ixEthAccCodeletSwBridgeQoSTxCB, secondPortCbTag) != IX_SUCCESS) { printf("SwBridgeQoS: Failed to configure the Bridge Operation for port %u\n", secondPortId); return (IX_FAIL); } /* Enable the VLAN/QoS Feature in EthDB for each port but first * check that the Firmware downloaded to the NPE can support it */ ixEthDBFeatureCapabilityGet((IxEthDBPortId)firstPortId, &featureSet); if ((featureSet & IX_ETH_DB_VLAN_QOS) == 0) { printf("SwBridgeQoS: Port %u NPE image not VLAN/QoS capable\n", firstPortId); return (IX_FAIL); } if ( ixEthDBFeatureEnable((IxEthDBPortId)firstPortId, IX_ETH_DB_VLAN_QOS, TRUE) != IX_ETH_DB_SUCCESS ) { printf("SwBridgeQoS: Failed to enable VLAN/QoS on port %u\n", firstPortId); return (IX_FAIL); } /* Enable the EthDB Port in order to configure and download the * VLAN/QoS configuration information */ if ((ixEthDBPortEnable(firstPortId)) != IX_ETH_DB_SUCCESS) { printf("SwBridgeQoS: Cannot enable port %u\n", firstPortId); return (IX_FAIL); } if ((ixEthDBPortEnable(secondPortId)) != IX_ETH_DB_SUCCESS) { printf("SwBridgeQos: Cannot enable port %u\n", secondPortId); return (IX_FAIL); } /* Configure Xscale QoS : the access layer datapath * prioritizes the different classes of traffic. */ printf("Set Tx Scheduling discipline...\n"); if (ixEthAccTxSchedulingDisciplineSet(firstPortId, FIFO_PRIORITY) != IX_ETH_ACC_SUCCESS) { printf("SwBridgeQos: Failed to set Tx Scheduling for discipline port %u\n", (UINT32)firstPortId); return (IX_FAIL); } if (ixEthAccTxSchedulingDisciplineSet(secondPortId, FIFO_PRIORITY) != IX_ETH_ACC_SUCCESS) { printf("SwBridgeQos: Failed to set Tx Scheduling for discipline port %u\n", (UINT32)secondPortId); return (IX_FAIL); } printf("Set Rx Scheduling discipline...\n"); if (ixEthAccRxSchedulingDisciplineSet(FIFO_PRIORITY) != IX_ETH_ACC_SUCCESS) { printf("SwBridgeQos: Failed to set Rx Scheduling discipline!\n"); return (IX_FAIL); } /* NPE QoS : Configure VLAN traffic for highest priority * on first port. Tagging is enabled on Egress (use default tag * for this port) and untagging is enabled on ingress. * The traffic running on this bridge will be untagged. */ printf("Set VLAN default tag...\n"); if (ixEthDBPortVlanTagSet(firstPortId, IX_ETHACC_CODELET_VLANID_DEFAULT) != IX_ETH_DB_SUCCESS) { printf("SwBridgeQos: Failed to set the default VLAN ID for port %u\n", firstPortId); return (IX_FAIL); } printf("Enable tagged frames...\n"); if (ixEthDBAcceptableFrameTypeSet(firstPortId, IX_ETH_DB_VLAN_TAGGED_FRAMES | IX_ETH_DB_UNTAGGED_FRAMES) != IX_ETH_DB_SUCCESS) { printf("SwBridgeQos: Failed to set the acceptable frame type for port %u\n", firstPortId); return (IX_FAIL); } printf("Setting VLAN membership...\n"); /* by default the entire VLAN range 0-4094 is included in the port VLAN membership table, therefore we need to remove all VLAN IDs but 0 (which is required to accept untagged frames) */ if (ixEthDBPortVlanMembershipRangeRemove(firstPortId, 1, IX_ETH_DB_802_1Q_MAX_VLAN_ID) != IX_ETH_DB_SUCCESS) { printf("SwBridgeQos: Failed to set VLAN membership for port %u\n", firstPortId); return (IX_FAIL); } /* now add the range used by this codelet */ if (ixEthDBPortVlanMembershipRangeAdd(firstPortId, IX_ETHACC_CODELET_VLANID_MIN, IX_ETHACC_CODELET_VLANID_MAX) != IX_ETH_DB_SUCCESS) { printf("SwBridgeQos: Failed to set VLAN membership for port %u\n", firstPortId); return (IX_FAIL); } printf("Enable Egress VLAN tagging...\n"); if (ixEthDBEgressVlanRangeTaggingEnabledSet(firstPortId, IX_ETHACC_CODELET_VLANID_MIN, IX_ETHACC_CODELET_VLANID_MAX, TRUE) != IX_ETH_DB_SUCCESS) { printf("SwBridgeQos: Failed to enable VLAN Egress tagging for port %u\n", firstPortId); return (IX_FAIL); } printf("Enable Ingress VLAN untagging...\n"); if (ixEthDBIngressVlanTaggingEnabledSet(firstPortId, IX_ETH_DB_REMOVE_TAG) != IX_ETH_DB_SUCCESS) { printf("SwBridgeQos: Failed to enable VLAN Ingress untagging for port %u\n", firstPortId); return (IX_FAIL); } printf("Setup priority mapping table...\n"); if (ixEthDBPriorityMappingTableSet(firstPortId, priorityTable) != IX_ETH_DB_SUCCESS) { printf("SwBridgeQos: Failed to set the priority mapping Table for port %u\n", firstPortId); return (IX_FAIL); } /* Configure 10 mb/s on second port to create a * traffic congestion on the bridge : the high * priority traffic should pass, the low priority * traffic should starve. */ if (ixEthAccCodeletLinkSlowSpeedSet(secondPortId) != IX_SUCCESS) { printf("SwBridgeQos: Failed to set port %u to 10 Mbit\n", secondPortId); return (IX_FAIL); } /* Allow RX and TX traffic to run */ if ( ixEthAccPortEnable(firstPortId) != IX_SUCCESS) { printf("SwBridgeQos: Failed to start the Bridge Operation for port %u\n", firstPortId); return (IX_FAIL); } if ( ixEthAccPortEnable(secondPortId) != IX_SUCCESS) { printf("SwBridgeQos: Failed to start the Bridge Operation for port %u\n", secondPortId); return (IX_FAIL); } /* display the default settings for both ports */ printf("Port %u configuration:\n", (UINT32)firstPortId); printf("- Accept Ingress VLAN-tagged traffic, VLAN tag range is [%u-%u]\n", (UINT32)IX_ETHACC_CODELET_VLANID_MIN, (UINT32)IX_ETHACC_CODELET_VLANID_MAX); printf("- Strip tag from ingress traffic\n"); printf("- Bridge Ingress to port %u without tag\n", (UINT32)secondPortId); printf("- Frame priorities may change the frame order (QoS enabled)\n"); printf("- Insert a default tag [%u] to egress traffic\n", (UINT32)IX_ETHACC_CODELET_VLANID_DEFAULT); printf("Port %u configuration:\n", (UINT32)secondPortId); printf("- Set as default\n\n"); return (IX_SUCCESS); }