2 * @file IxEthDBEvents.c
4 * @brief Implementation of the event processor component
7 * IXP400 SW Release version 2.0
9 * -- Copyright Notice --
12 * Copyright 2001-2005, Intel Corporation.
13 * All rights reserved.
16 * SPDX-License-Identifier: BSD-3-Clause
18 * -- End of Copyright Notice --
22 #include <IxFeatureCtrl.h>
24 #include "IxEthDB_p.h"
26 /* forward prototype declarations */
27 IX_ETH_DB_PUBLIC void ixEthDBEventProcessorLoop(void *);
28 IX_ETH_DB_PUBLIC void ixEthDBNPEEventCallback(IxNpeMhNpeId npeID, IxNpeMhMessage msg);
29 IX_ETH_DB_PRIVATE void ixEthDBProcessEvent(PortEvent *local_event, IxEthDBPortMap triggerPorts);
30 IX_ETH_DB_PRIVATE IxEthDBStatus ixEthDBTriggerPortUpdate(UINT32 eventType, IxEthDBMacAddr *macAddr, IxEthDBPortId portID, BOOL staticEntry);
31 IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBStartLearningFunction(void);
32 IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBStopLearningFunction(void);
35 IX_ETH_DB_PRIVATE IxOsalSemaphore eventQueueSemaphore;
36 IX_ETH_DB_PRIVATE PortEventQueue eventQueue;
37 IX_ETH_DB_PRIVATE IxOsalMutex eventQueueLock;
38 IX_ETH_DB_PRIVATE IxOsalMutex portUpdateLock;
40 IX_ETH_DB_PRIVATE BOOL ixEthDBLearningShutdown = false;
41 IX_ETH_DB_PRIVATE BOOL ixEthDBEventProcessorRunning = false;
44 extern HashTable dbHashtable;
47 * @brief initializes the event processor
49 * Initializes the event processor queue and processing thread.
50 * Called from ixEthDBInit() DB-subcomponent master init function.
52 * @warning do not call directly
54 * @retval IX_ETH_DB_SUCCESS initialization was successful
55 * @retval IX_ETH_DB_FAIL initialization failed (OSAL or mutex init failure)
60 IxEthDBStatus ixEthDBEventProcessorInit(void)
62 if (ixOsalMutexInit(&portUpdateLock) != IX_SUCCESS)
64 return IX_ETH_DB_FAIL;
67 if (ixOsalMutexInit(&eventQueueLock) != IX_SUCCESS)
69 return IX_ETH_DB_FAIL;
72 if (IX_FEATURE_CTRL_SWCONFIG_ENABLED ==
73 ixFeatureCtrlSwConfigurationCheck (IX_FEATURECTRL_ETH_LEARNING))
76 /* start processor loop thread */
77 if (ixEthDBStartLearningFunction() != IX_ETH_DB_SUCCESS)
79 return IX_ETH_DB_FAIL;
83 return IX_ETH_DB_SUCCESS;
87 * @brief initializes the event queue and the event processor
89 * This function is called by the component initialization
90 * function, ixEthDBInit().
92 * @warning do not call directly
94 * @return IX_ETH_DB_SUCCESS if the operation completed
95 * successfully or IX_ETH_DB_FAIL otherwise
100 IxEthDBStatus ixEthDBStartLearningFunction(void)
102 IxOsalThread eventProcessorThread;
103 IxOsalThreadAttr threadAttr;
105 threadAttr.name = "EthDB event thread";
106 threadAttr.stackSize = 32 * 1024; /* 32kbytes */
107 threadAttr.priority = 128;
109 /* reset event queue */
110 ixOsalMutexLock(&eventQueueLock, IX_OSAL_WAIT_FOREVER);
112 RESET_QUEUE(&eventQueue);
114 ixOsalMutexUnlock(&eventQueueLock);
116 /* init event queue semaphore */
117 if (ixOsalSemaphoreInit(&eventQueueSemaphore, 0) != IX_SUCCESS)
119 return IX_ETH_DB_FAIL;
122 ixEthDBLearningShutdown = false;
124 /* create processor loop thread */
125 if (ixOsalThreadCreate(&eventProcessorThread, &threadAttr, ixEthDBEventProcessorLoop, NULL) != IX_SUCCESS)
127 return IX_ETH_DB_FAIL;
130 /* start event processor */
131 ixOsalThreadStart(&eventProcessorThread);
133 return IX_ETH_DB_SUCCESS;
137 * @brief stops the event processor
139 * Stops the event processor and frees the event queue semaphore
140 * Called by the component de-initialization function, ixEthDBUnload()
142 * @warning do not call directly
144 * @return IX_ETH_DB_SUCCESS if the operation completed
145 * successfully or IX_ETH_DB_FAIL otherwise;
150 IxEthDBStatus ixEthDBStopLearningFunction(void)
152 ixEthDBLearningShutdown = true;
154 /* wake up event processing loop to actually process the shutdown event */
155 ixOsalSemaphorePost(&eventQueueSemaphore);
157 if (ixOsalSemaphoreDestroy(&eventQueueSemaphore) != IX_SUCCESS)
159 return IX_ETH_DB_FAIL;
162 return IX_ETH_DB_SUCCESS;
166 * @brief default NPE event processing callback
168 * @param npeID ID of the NPE that generated the event
169 * @param msg NPE message (encapsulated event)
171 * Creates an event object on the Ethernet event processor queue
172 * and signals the new event by incrementing the event queue semaphore.
173 * Events are processed by @ref ixEthDBEventProcessorLoop() which runs
176 * @see ixEthDBEventProcessorLoop()
178 * @warning do not call directly
183 void ixEthDBNPEEventCallback(IxNpeMhNpeId npeID, IxNpeMhMessage msg)
185 PortEvent *local_event;
187 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);
189 if (CAN_ENQUEUE(&eventQueue))
191 TEST_FIXTURE_LOCK_EVENT_QUEUE;
193 local_event = QUEUE_HEAD(&eventQueue);
195 /* create event structure on queue */
196 local_event->eventType = NPE_MSG_ID(msg);
197 local_event->portID = IX_ETH_DB_NPE_TO_PORT_ID(npeID);
200 PUSH_UPDATE_QUEUE(&eventQueue);
202 TEST_FIXTURE_UNLOCK_EVENT_QUEUE;
204 IX_ETH_DB_IRQ_EVENTS_TRACE("DB: (Events) Waking up main processor loop...\n", 0, 0, 0, 0, 0, 0);
206 /* increment event queue semaphore */
207 ixOsalSemaphorePost(&eventQueueSemaphore);
211 IX_ETH_DB_IRQ_EVENTS_TRACE("DB: (Events) Warning: could not enqueue event (overflow)\n", 0, 0, 0, 0, 0, 0);
216 * @brief Ethernet event processor loop
218 * Extracts at most EVENT_PROCESSING_LIMIT batches of events and
219 * sends them for processing to @ref ixEthDBProcessEvent().
220 * Triggers port updates which normally follow learning events.
222 * @warning do not call directly, executes in separate thread
227 void ixEthDBEventProcessorLoop(void *unused1)
229 IxEthDBPortMap triggerPorts;
230 IxEthDBPortId portIndex;
232 ixEthDBEventProcessorRunning = true;
234 IX_ETH_DB_EVENTS_TRACE("DB: (Events) Event processor loop was started\n");
236 while (!ixEthDBLearningShutdown)
238 BOOL keepProcessing = true;
239 UINT32 processedEvents = 0;
241 IX_ETH_DB_EVENTS_VERBOSE_TRACE("DB: (Events) Waiting for new learning event...\n");
243 ixOsalSemaphoreWait(&eventQueueSemaphore, IX_OSAL_WAIT_FOREVER);
245 IX_ETH_DB_EVENTS_VERBOSE_TRACE("DB: (Events) Received new event\n");
247 if (!ixEthDBLearningShutdown)
249 /* port update handling */
250 SET_EMPTY_DEPENDENCY_MAP(triggerPorts);
252 while (keepProcessing)
254 PortEvent local_event;
258 ixOsalMutexLock(&eventQueueLock, IX_OSAL_WAIT_FOREVER);
260 /* lock NPE interrupts */
261 intLockKey = ixOsalIrqLock();
264 local_event = *(QUEUE_TAIL(&eventQueue));
266 SHIFT_UPDATE_QUEUE(&eventQueue);
268 ixOsalIrqUnlock(intLockKey);
270 ixOsalMutexUnlock(&eventQueueLock);
272 IX_ETH_DB_EVENTS_TRACE("DB: (Events) Processing event with ID 0x%X\n", local_event.eventType);
274 ixEthDBProcessEvent(&local_event, triggerPorts);
278 if (processedEvents > EVENT_PROCESSING_LIMIT /* maximum burst reached? */
279 || ixOsalSemaphoreTryWait(&eventQueueSemaphore) != IX_SUCCESS) /* or empty queue? */
281 keepProcessing = false;
285 ixEthDBUpdatePortLearningTrees(triggerPorts);
289 /* turn off automatic updates */
290 for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++)
292 ixEthDBPortInfo[portIndex].updateMethod.updateEnabled = false;
295 ixEthDBEventProcessorRunning = false;
299 * @brief event processor routine
301 * @param event event to be processed
302 * @param triggerPorts port map accumulating ports to be updated
304 * Processes learning events by synchronizing the database with
305 * newly learnt data. Called only by @ref ixEthDBEventProcessorLoop().
307 * @warning do not call directly
312 void ixEthDBProcessEvent(PortEvent *local_event, IxEthDBPortMap triggerPorts)
314 MacDescriptor recordTemplate;
316 switch (local_event->eventType)
318 case IX_ETH_DB_ADD_FILTERING_RECORD:
320 memset(&recordTemplate, 0, sizeof (recordTemplate));
321 memcpy(recordTemplate.macAddress, local_event->macAddr.macAddress, sizeof (IxEthDBMacAddr));
323 recordTemplate.type = IX_ETH_DB_FILTERING_RECORD;
324 recordTemplate.portID = local_event->portID;
325 recordTemplate.recordData.filteringData.staticEntry = local_event->staticEntry;
327 ixEthDBAdd(&recordTemplate, triggerPorts);
329 IX_ETH_DB_EVENTS_TRACE("DB: (Events) Added record on port %d\n", local_event->portID);
333 case IX_ETH_DB_REMOVE_FILTERING_RECORD:
335 memset(&recordTemplate, 0, sizeof (recordTemplate));
336 memcpy(recordTemplate.macAddress, local_event->macAddr.macAddress, sizeof (IxEthDBMacAddr));
338 recordTemplate.type = IX_ETH_DB_FILTERING_RECORD | IX_ETH_DB_FILTERING_VLAN_RECORD;
340 ixEthDBRemove(&recordTemplate, triggerPorts);
342 IX_ETH_DB_EVENTS_TRACE("DB: (Events) Removed record on port %d\n", local_event->portID);
347 /* can't handle/not interested in this event type */
348 ERROR_LOG("DB: (Events) Event processor received an unknown event type (0x%X)\n", local_event->eventType);
355 * @brief asynchronously adds a filtering record
356 * by posting an ADD_FILTERING_RECORD event to the event queue
358 * @param macAddr MAC address of the new record
359 * @param portID port ID of the new record
360 * @param staticEntry true if record is static, false if dynamic
362 * @return IX_ETH_DB_SUCCESS if the event creation was
363 * successfull or IX_ETH_DB_BUSY if the event queue is full
368 IxEthDBStatus ixEthDBTriggerAddPortUpdate(IxEthDBMacAddr *macAddr, IxEthDBPortId portID, BOOL staticEntry)
370 MacDescriptor reference;
372 TEST_FIXTURE_INCREMENT_DB_CORE_ACCESS_COUNTER;
374 /* fill search fields */
375 memcpy(reference.macAddress, macAddr, sizeof (IxEthDBMacAddr));
376 reference.portID = portID;
378 /* set acceptable record types */
379 reference.type = IX_ETH_DB_ALL_FILTERING_RECORDS;
381 if (ixEthDBPeekHashEntry(&dbHashtable, IX_ETH_DB_MAC_PORT_KEY, &reference) == IX_ETH_DB_SUCCESS)
383 /* already have an identical record */
384 return IX_ETH_DB_SUCCESS;
388 return ixEthDBTriggerPortUpdate(IX_ETH_DB_ADD_FILTERING_RECORD, macAddr, portID, staticEntry);
393 * @brief asynchronously removes a filtering record
394 * by posting a REMOVE_FILTERING_RECORD event to the event queue
396 * @param macAddr MAC address of the record to remove
397 * @param portID port ID of the record to remove
399 * @return IX_ETH_DB_SUCCESS if the event creation was
400 * successfull or IX_ETH_DB_BUSY if the event queue is full
405 IxEthDBStatus ixEthDBTriggerRemovePortUpdate(IxEthDBMacAddr *macAddr, IxEthDBPortId portID)
407 if (ixEthDBPeek(macAddr, IX_ETH_DB_ALL_FILTERING_RECORDS) != IX_ETH_DB_NO_SUCH_ADDR)
409 return ixEthDBTriggerPortUpdate(IX_ETH_DB_REMOVE_FILTERING_RECORD, macAddr, portID, false);
413 return IX_ETH_DB_NO_SUCH_ADDR;
418 * @brief adds an ADD or REMOVE event to the main event queue
420 * @param eventType event type - IX_ETH_DB_ADD_FILTERING_RECORD
421 * to add and IX_ETH_DB_REMOVE_FILTERING_RECORD to remove a
424 * @return IX_ETH_DB_SUCCESS if the event was successfully
425 * sent or IX_ETH_DB_BUSY if the event queue is full
430 IxEthDBStatus ixEthDBTriggerPortUpdate(UINT32 eventType, IxEthDBMacAddr *macAddr, IxEthDBPortId portID, BOOL staticEntry)
434 /* lock interrupts to protect queue */
435 intLockKey = ixOsalIrqLock();
437 if (CAN_ENQUEUE(&eventQueue))
439 PortEvent *queueEvent = QUEUE_HEAD(&eventQueue);
441 /* update fields on the queue */
442 memcpy(queueEvent->macAddr.macAddress, macAddr->macAddress, sizeof (IxEthDBMacAddr));
444 queueEvent->eventType = eventType;
445 queueEvent->portID = portID;
446 queueEvent->staticEntry = staticEntry;
448 PUSH_UPDATE_QUEUE(&eventQueue);
450 /* imcrement event queue semaphore */
451 ixOsalSemaphorePost(&eventQueueSemaphore);
453 /* unlock interrupts */
454 ixOsalIrqUnlock(intLockKey);
456 return IX_ETH_DB_SUCCESS;
458 else /* event queue full */
460 /* unlock interrupts */
461 ixOsalIrqUnlock(intLockKey);
463 return IX_ETH_DB_BUSY;
468 * @brief Locks learning tree updates and port disable
471 * This function locks portUpdateLock single mutex. It is primarily used
472 * to avoid executing 'port disable' during ELT maintenance.
477 void ixEthDBUpdateLock(void)
479 ixOsalMutexLock(&portUpdateLock, IX_OSAL_WAIT_FOREVER);
483 * @brief Unlocks learning tree updates and port disable
486 * This function unlocks a portUpdateLock mutex. It is primarily used
487 * to avoid executing 'port disable' during ELT maintenance.
492 void ixEthDBUpdateUnlock(void)
494 ixOsalMutexUnlock(&portUpdateLock);