| /** | |
| * @file IxEthDBEvents.c | |
| * | |
| * @brief Implementation of the event processor component | |
| * | |
| * @par | |
| * IXP400 SW Release version 2.0 | |
| * | |
| * -- Copyright Notice -- | |
| * | |
| * @par | |
| * Copyright 2001-2005, Intel Corporation. | |
| * All rights reserved. | |
| * | |
| * @par | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions | |
| * are met: | |
| * 1. Redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer. | |
| * 2. Redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution. | |
| * 3. Neither the name of the Intel Corporation nor the names of its contributors | |
| * may be used to endorse or promote products derived from this software | |
| * without specific prior written permission. | |
| * | |
| * @par | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' | |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE | |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| * SUCH DAMAGE. | |
| * | |
| * @par | |
| * -- End of Copyright Notice -- | |
| */ | |
| #include <IxNpeMh.h> | |
| #include <IxFeatureCtrl.h> | |
| #include "IxEthDB_p.h" | |
| /* forward prototype declarations */ | |
| IX_ETH_DB_PUBLIC void ixEthDBEventProcessorLoop(void *); | |
| IX_ETH_DB_PUBLIC void ixEthDBNPEEventCallback(IxNpeMhNpeId npeID, IxNpeMhMessage msg); | |
| IX_ETH_DB_PRIVATE void ixEthDBProcessEvent(PortEvent *local_event, IxEthDBPortMap triggerPorts); | |
| IX_ETH_DB_PRIVATE IxEthDBStatus ixEthDBTriggerPortUpdate(UINT32 eventType, IxEthDBMacAddr *macAddr, IxEthDBPortId portID, BOOL staticEntry); | |
| IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBStartLearningFunction(void); | |
| IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBStopLearningFunction(void); | |
| /* data */ | |
| IX_ETH_DB_PRIVATE IxOsalSemaphore eventQueueSemaphore; | |
| IX_ETH_DB_PRIVATE PortEventQueue eventQueue; | |
| IX_ETH_DB_PRIVATE IxOsalMutex eventQueueLock; | |
| IX_ETH_DB_PRIVATE IxOsalMutex portUpdateLock; | |
| IX_ETH_DB_PRIVATE BOOL ixEthDBLearningShutdown = FALSE; | |
| IX_ETH_DB_PRIVATE BOOL ixEthDBEventProcessorRunning = FALSE; | |
| /* imported data */ | |
| extern HashTable dbHashtable; | |
| /** | |
| * @brief initializes the event processor | |
| * | |
| * Initializes the event processor queue and processing thread. | |
| * Called from ixEthDBInit() DB-subcomponent master init function. | |
| * | |
| * @warning do not call directly | |
| * | |
| * @retval IX_ETH_DB_SUCCESS initialization was successful | |
| * @retval IX_ETH_DB_FAIL initialization failed (OSAL or mutex init failure) | |
| * | |
| * @internal | |
| */ | |
| IX_ETH_DB_PUBLIC | |
| IxEthDBStatus ixEthDBEventProcessorInit(void) | |
| { | |
| if (ixOsalMutexInit(&portUpdateLock) != IX_SUCCESS) | |
| { | |
| return IX_ETH_DB_FAIL; | |
| } | |
| if (ixOsalMutexInit(&eventQueueLock) != IX_SUCCESS) | |
| { | |
| return IX_ETH_DB_FAIL; | |
| } | |
| if (IX_FEATURE_CTRL_SWCONFIG_ENABLED == | |
| ixFeatureCtrlSwConfigurationCheck (IX_FEATURECTRL_ETH_LEARNING)) | |
| { | |
| /* start processor loop thread */ | |
| if (ixEthDBStartLearningFunction() != IX_ETH_DB_SUCCESS) | |
| { | |
| return IX_ETH_DB_FAIL; | |
| } | |
| } | |
| return IX_ETH_DB_SUCCESS; | |
| } | |
| /** | |
| * @brief initializes the event queue and the event processor | |
| * | |
| * This function is called by the component initialization | |
| * function, ixEthDBInit(). | |
| * | |
| * @warning do not call directly | |
| * | |
| * @return IX_ETH_DB_SUCCESS if the operation completed | |
| * successfully or IX_ETH_DB_FAIL otherwise | |
| * | |
| * @internal | |
| */ | |
| IX_ETH_DB_PUBLIC | |
| IxEthDBStatus ixEthDBStartLearningFunction(void) | |
| { | |
| IxOsalThread eventProcessorThread; | |
| IxOsalThreadAttr threadAttr; | |
| threadAttr.name = "EthDB event thread"; | |
| threadAttr.stackSize = 32 * 1024; /* 32kbytes */ | |
| threadAttr.priority = 128; | |
| /* reset event queue */ | |
| ixOsalMutexLock(&eventQueueLock, IX_OSAL_WAIT_FOREVER); | |
| RESET_QUEUE(&eventQueue); | |
| ixOsalMutexUnlock(&eventQueueLock); | |
| /* init event queue semaphore */ | |
| if (ixOsalSemaphoreInit(&eventQueueSemaphore, 0) != IX_SUCCESS) | |
| { | |
| return IX_ETH_DB_FAIL; | |
| } | |
| ixEthDBLearningShutdown = FALSE; | |
| /* create processor loop thread */ | |
| if (ixOsalThreadCreate(&eventProcessorThread, &threadAttr, ixEthDBEventProcessorLoop, NULL) != IX_SUCCESS) | |
| { | |
| return IX_ETH_DB_FAIL; | |
| } | |
| /* start event processor */ | |
| ixOsalThreadStart(&eventProcessorThread); | |
| return IX_ETH_DB_SUCCESS; | |
| } | |
| /** | |
| * @brief stops the event processor | |
| * | |
| * Stops the event processor and frees the event queue semaphore | |
| * Called by the component de-initialization function, ixEthDBUnload() | |
| * | |
| * @warning do not call directly | |
| * | |
| * @return IX_ETH_DB_SUCCESS if the operation completed | |
| * successfully or IX_ETH_DB_FAIL otherwise; | |
| * | |
| * @internal | |
| */ | |
| IX_ETH_DB_PUBLIC | |
| IxEthDBStatus ixEthDBStopLearningFunction(void) | |
| { | |
| ixEthDBLearningShutdown = TRUE; | |
| /* wake up event processing loop to actually process the shutdown event */ | |
| ixOsalSemaphorePost(&eventQueueSemaphore); | |
| if (ixOsalSemaphoreDestroy(&eventQueueSemaphore) != IX_SUCCESS) | |
| { | |
| return IX_ETH_DB_FAIL; | |
| } | |
| return IX_ETH_DB_SUCCESS; | |
| } | |
| /** | |
| * @brief default NPE event processing callback | |
| * | |
| * @param npeID ID of the NPE that generated the event | |
| * @param msg NPE message (encapsulated event) | |
| * | |
| * Creates an event object on the Ethernet event processor queue | |
| * and signals the new event by incrementing the event queue semaphore. | |
| * Events are processed by @ref ixEthDBEventProcessorLoop() which runs | |
| * at user level. | |
| * | |
| * @see ixEthDBEventProcessorLoop() | |
| * | |
| * @warning do not call directly | |
| * | |
| * @internal | |
| */ | |
| IX_ETH_DB_PUBLIC | |
| void ixEthDBNPEEventCallback(IxNpeMhNpeId npeID, IxNpeMhMessage msg) | |
| { | |
| PortEvent *local_event; | |
| IX_ETH_DB_IRQ_EVENTS_TRACE("DB: (Events) new event received by processor callback from port %d, id 0x%X\n", IX_ETH_DB_NPE_TO_PORT_ID(npeID), NPE_MSG_ID(msg), 0, 0, 0, 0); | |
| if (CAN_ENQUEUE(&eventQueue)) | |
| { | |
| TEST_FIXTURE_LOCK_EVENT_QUEUE; | |
| local_event = QUEUE_HEAD(&eventQueue); | |
| /* create event structure on queue */ | |
| local_event->eventType = NPE_MSG_ID(msg); | |
| local_event->portID = IX_ETH_DB_NPE_TO_PORT_ID(npeID); | |
| /* update queue */ | |
| PUSH_UPDATE_QUEUE(&eventQueue); | |
| TEST_FIXTURE_UNLOCK_EVENT_QUEUE; | |
| IX_ETH_DB_IRQ_EVENTS_TRACE("DB: (Events) Waking up main processor loop...\n", 0, 0, 0, 0, 0, 0); | |
| /* increment event queue semaphore */ | |
| ixOsalSemaphorePost(&eventQueueSemaphore); | |
| } | |
| else | |
| { | |
| IX_ETH_DB_IRQ_EVENTS_TRACE("DB: (Events) Warning: could not enqueue event (overflow)\n", 0, 0, 0, 0, 0, 0); | |
| } | |
| } | |
| /** | |
| * @brief Ethernet event processor loop | |
| * | |
| * Extracts at most EVENT_PROCESSING_LIMIT batches of events and | |
| * sends them for processing to @ref ixEthDBProcessEvent(). | |
| * Triggers port updates which normally follow learning events. | |
| * | |
| * @warning do not call directly, executes in separate thread | |
| * | |
| * @internal | |
| */ | |
| IX_ETH_DB_PUBLIC | |
| void ixEthDBEventProcessorLoop(void *unused1) | |
| { | |
| IxEthDBPortMap triggerPorts; | |
| IxEthDBPortId portIndex; | |
| ixEthDBEventProcessorRunning = TRUE; | |
| IX_ETH_DB_EVENTS_TRACE("DB: (Events) Event processor loop was started\n"); | |
| while (!ixEthDBLearningShutdown) | |
| { | |
| BOOL keepProcessing = TRUE; | |
| UINT32 processedEvents = 0; | |
| IX_ETH_DB_EVENTS_VERBOSE_TRACE("DB: (Events) Waiting for new learning event...\n"); | |
| ixOsalSemaphoreWait(&eventQueueSemaphore, IX_OSAL_WAIT_FOREVER); | |
| IX_ETH_DB_EVENTS_VERBOSE_TRACE("DB: (Events) Received new event\n"); | |
| if (!ixEthDBLearningShutdown) | |
| { | |
| /* port update handling */ | |
| SET_EMPTY_DEPENDENCY_MAP(triggerPorts); | |
| while (keepProcessing) | |
| { | |
| PortEvent local_event; | |
| UINT32 intLockKey; | |
| /* lock queue */ | |
| ixOsalMutexLock(&eventQueueLock, IX_OSAL_WAIT_FOREVER); | |
| /* lock NPE interrupts */ | |
| intLockKey = ixOsalIrqLock(); | |
| /* extract event */ | |
| local_event = *(QUEUE_TAIL(&eventQueue)); | |
| SHIFT_UPDATE_QUEUE(&eventQueue); | |
| ixOsalIrqUnlock(intLockKey); | |
| ixOsalMutexUnlock(&eventQueueLock); | |
| IX_ETH_DB_EVENTS_TRACE("DB: (Events) Processing event with ID 0x%X\n", local_event.eventType); | |
| ixEthDBProcessEvent(&local_event, triggerPorts); | |
| processedEvents++; | |
| if (processedEvents > EVENT_PROCESSING_LIMIT /* maximum burst reached? */ | |
| || ixOsalSemaphoreTryWait(&eventQueueSemaphore) != IX_SUCCESS) /* or empty queue? */ | |
| { | |
| keepProcessing = FALSE; | |
| } | |
| } | |
| ixEthDBUpdatePortLearningTrees(triggerPorts); | |
| } | |
| } | |
| /* turn off automatic updates */ | |
| for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++) | |
| { | |
| ixEthDBPortInfo[portIndex].updateMethod.updateEnabled = FALSE; | |
| } | |
| ixEthDBEventProcessorRunning = FALSE; | |
| } | |
| /** | |
| * @brief event processor routine | |
| * | |
| * @param event event to be processed | |
| * @param triggerPorts port map accumulating ports to be updated | |
| * | |
| * Processes learning events by synchronizing the database with | |
| * newly learnt data. Called only by @ref ixEthDBEventProcessorLoop(). | |
| * | |
| * @warning do not call directly | |
| * | |
| * @internal | |
| */ | |
| IX_ETH_DB_PRIVATE | |
| void ixEthDBProcessEvent(PortEvent *local_event, IxEthDBPortMap triggerPorts) | |
| { | |
| MacDescriptor recordTemplate; | |
| switch (local_event->eventType) | |
| { | |
| case IX_ETH_DB_ADD_FILTERING_RECORD: | |
| /* add record */ | |
| memset(&recordTemplate, 0, sizeof (recordTemplate)); | |
| memcpy(recordTemplate.macAddress, local_event->macAddr.macAddress, sizeof (IxEthDBMacAddr)); | |
| recordTemplate.type = IX_ETH_DB_FILTERING_RECORD; | |
| recordTemplate.portID = local_event->portID; | |
| recordTemplate.recordData.filteringData.staticEntry = local_event->staticEntry; | |
| ixEthDBAdd(&recordTemplate, triggerPorts); | |
| IX_ETH_DB_EVENTS_TRACE("DB: (Events) Added record on port %d\n", local_event->portID); | |
| break; | |
| case IX_ETH_DB_REMOVE_FILTERING_RECORD: | |
| /* remove record */ | |
| memset(&recordTemplate, 0, sizeof (recordTemplate)); | |
| memcpy(recordTemplate.macAddress, local_event->macAddr.macAddress, sizeof (IxEthDBMacAddr)); | |
| recordTemplate.type = IX_ETH_DB_FILTERING_RECORD | IX_ETH_DB_FILTERING_VLAN_RECORD; | |
| ixEthDBRemove(&recordTemplate, triggerPorts); | |
| IX_ETH_DB_EVENTS_TRACE("DB: (Events) Removed record on port %d\n", local_event->portID); | |
| break; | |
| default: | |
| /* can't handle/not interested in this event type */ | |
| ERROR_LOG("DB: (Events) Event processor received an unknown event type (0x%X)\n", local_event->eventType); | |
| return; | |
| } | |
| } | |
| /** | |
| * @brief asynchronously adds a filtering record | |
| * by posting an ADD_FILTERING_RECORD event to the event queue | |
| * | |
| * @param macAddr MAC address of the new record | |
| * @param portID port ID of the new record | |
| * @param staticEntry TRUE if record is static, FALSE if dynamic | |
| * | |
| * @return IX_ETH_DB_SUCCESS if the event creation was | |
| * successfull or IX_ETH_DB_BUSY if the event queue is full | |
| * | |
| * @internal | |
| */ | |
| IX_ETH_DB_PUBLIC | |
| IxEthDBStatus ixEthDBTriggerAddPortUpdate(IxEthDBMacAddr *macAddr, IxEthDBPortId portID, BOOL staticEntry) | |
| { | |
| MacDescriptor reference; | |
| TEST_FIXTURE_INCREMENT_DB_CORE_ACCESS_COUNTER; | |
| /* fill search fields */ | |
| memcpy(reference.macAddress, macAddr, sizeof (IxEthDBMacAddr)); | |
| reference.portID = portID; | |
| /* set acceptable record types */ | |
| reference.type = IX_ETH_DB_ALL_FILTERING_RECORDS; | |
| if (ixEthDBPeekHashEntry(&dbHashtable, IX_ETH_DB_MAC_PORT_KEY, &reference) == IX_ETH_DB_SUCCESS) | |
| { | |
| /* already have an identical record */ | |
| return IX_ETH_DB_SUCCESS; | |
| } | |
| else | |
| { | |
| return ixEthDBTriggerPortUpdate(IX_ETH_DB_ADD_FILTERING_RECORD, macAddr, portID, staticEntry); | |
| } | |
| } | |
| /** | |
| * @brief asynchronously removes a filtering record | |
| * by posting a REMOVE_FILTERING_RECORD event to the event queue | |
| * | |
| * @param macAddr MAC address of the record to remove | |
| * @param portID port ID of the record to remove | |
| * | |
| * @return IX_ETH_DB_SUCCESS if the event creation was | |
| * successfull or IX_ETH_DB_BUSY if the event queue is full | |
| * | |
| * @internal | |
| */ | |
| IX_ETH_DB_PUBLIC | |
| IxEthDBStatus ixEthDBTriggerRemovePortUpdate(IxEthDBMacAddr *macAddr, IxEthDBPortId portID) | |
| { | |
| if (ixEthDBPeek(macAddr, IX_ETH_DB_ALL_FILTERING_RECORDS) != IX_ETH_DB_NO_SUCH_ADDR) | |
| { | |
| return ixEthDBTriggerPortUpdate(IX_ETH_DB_REMOVE_FILTERING_RECORD, macAddr, portID, FALSE); | |
| } | |
| else | |
| { | |
| return IX_ETH_DB_NO_SUCH_ADDR; | |
| } | |
| } | |
| /** | |
| * @brief adds an ADD or REMOVE event to the main event queue | |
| * | |
| * @param eventType event type - IX_ETH_DB_ADD_FILTERING_RECORD | |
| * to add and IX_ETH_DB_REMOVE_FILTERING_RECORD to remove a | |
| * record. | |
| * | |
| * @return IX_ETH_DB_SUCCESS if the event was successfully | |
| * sent or IX_ETH_DB_BUSY if the event queue is full | |
| * | |
| * @internal | |
| */ | |
| IX_ETH_DB_PRIVATE | |
| IxEthDBStatus ixEthDBTriggerPortUpdate(UINT32 eventType, IxEthDBMacAddr *macAddr, IxEthDBPortId portID, BOOL staticEntry) | |
| { | |
| UINT32 intLockKey; | |
| /* lock interrupts to protect queue */ | |
| intLockKey = ixOsalIrqLock(); | |
| if (CAN_ENQUEUE(&eventQueue)) | |
| { | |
| PortEvent *queueEvent = QUEUE_HEAD(&eventQueue); | |
| /* update fields on the queue */ | |
| memcpy(queueEvent->macAddr.macAddress, macAddr->macAddress, sizeof (IxEthDBMacAddr)); | |
| queueEvent->eventType = eventType; | |
| queueEvent->portID = portID; | |
| queueEvent->staticEntry = staticEntry; | |
| PUSH_UPDATE_QUEUE(&eventQueue); | |
| /* imcrement event queue semaphore */ | |
| ixOsalSemaphorePost(&eventQueueSemaphore); | |
| /* unlock interrupts */ | |
| ixOsalIrqUnlock(intLockKey); | |
| return IX_ETH_DB_SUCCESS; | |
| } | |
| else /* event queue full */ | |
| { | |
| /* unlock interrupts */ | |
| ixOsalIrqUnlock(intLockKey); | |
| return IX_ETH_DB_BUSY; | |
| } | |
| } | |
| /** | |
| * @brief Locks learning tree updates and port disable | |
| * | |
| * | |
| * This function locks portUpdateLock single mutex. It is primarily used | |
| * to avoid executing 'port disable' during ELT maintenance. | |
| * | |
| * @internal | |
| */ | |
| IX_ETH_DB_PUBLIC | |
| void ixEthDBUpdateLock(void) | |
| { | |
| ixOsalMutexLock(&portUpdateLock, IX_OSAL_WAIT_FOREVER); | |
| } | |
| /** | |
| * @brief Unlocks learning tree updates and port disable | |
| * | |
| * | |
| * This function unlocks a portUpdateLock mutex. It is primarily used | |
| * to avoid executing 'port disable' during ELT maintenance. | |
| * | |
| * @internal | |
| */ | |
| IX_ETH_DB_PUBLIC | |
| void ixEthDBUpdateUnlock(void) | |
| { | |
| ixOsalMutexUnlock(&portUpdateLock); | |
| } | |