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 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 3. Neither the name of the Intel Corporation nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
30 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * -- End of Copyright Notice --
46 #include <IxFeatureCtrl.h>
48 #include "IxEthDB_p.h"
50 /* forward prototype declarations */
51 IX_ETH_DB_PUBLIC
void ixEthDBEventProcessorLoop(void *);
52 IX_ETH_DB_PUBLIC
void ixEthDBNPEEventCallback(IxNpeMhNpeId npeID
, IxNpeMhMessage msg
);
53 IX_ETH_DB_PRIVATE
void ixEthDBProcessEvent(PortEvent
*local_event
, IxEthDBPortMap triggerPorts
);
54 IX_ETH_DB_PRIVATE IxEthDBStatus
ixEthDBTriggerPortUpdate(UINT32 eventType
, IxEthDBMacAddr
*macAddr
, IxEthDBPortId portID
, BOOL staticEntry
);
55 IX_ETH_DB_PUBLIC IxEthDBStatus
ixEthDBStartLearningFunction(void);
56 IX_ETH_DB_PUBLIC IxEthDBStatus
ixEthDBStopLearningFunction(void);
59 IX_ETH_DB_PRIVATE IxOsalSemaphore eventQueueSemaphore
;
60 IX_ETH_DB_PRIVATE PortEventQueue eventQueue
;
61 IX_ETH_DB_PRIVATE IxOsalMutex eventQueueLock
;
62 IX_ETH_DB_PRIVATE IxOsalMutex portUpdateLock
;
64 IX_ETH_DB_PRIVATE BOOL ixEthDBLearningShutdown
= FALSE
;
65 IX_ETH_DB_PRIVATE BOOL ixEthDBEventProcessorRunning
= FALSE
;
68 extern HashTable dbHashtable
;
71 * @brief initializes the event processor
73 * Initializes the event processor queue and processing thread.
74 * Called from ixEthDBInit() DB-subcomponent master init function.
76 * @warning do not call directly
78 * @retval IX_ETH_DB_SUCCESS initialization was successful
79 * @retval IX_ETH_DB_FAIL initialization failed (OSAL or mutex init failure)
84 IxEthDBStatus
ixEthDBEventProcessorInit(void)
86 if (ixOsalMutexInit(&portUpdateLock
) != IX_SUCCESS
)
88 return IX_ETH_DB_FAIL
;
91 if (ixOsalMutexInit(&eventQueueLock
) != IX_SUCCESS
)
93 return IX_ETH_DB_FAIL
;
96 if (IX_FEATURE_CTRL_SWCONFIG_ENABLED
==
97 ixFeatureCtrlSwConfigurationCheck (IX_FEATURECTRL_ETH_LEARNING
))
100 /* start processor loop thread */
101 if (ixEthDBStartLearningFunction() != IX_ETH_DB_SUCCESS
)
103 return IX_ETH_DB_FAIL
;
107 return IX_ETH_DB_SUCCESS
;
111 * @brief initializes the event queue and the event processor
113 * This function is called by the component initialization
114 * function, ixEthDBInit().
116 * @warning do not call directly
118 * @return IX_ETH_DB_SUCCESS if the operation completed
119 * successfully or IX_ETH_DB_FAIL otherwise
124 IxEthDBStatus
ixEthDBStartLearningFunction(void)
126 IxOsalThread eventProcessorThread
;
127 IxOsalThreadAttr threadAttr
;
129 threadAttr
.name
= "EthDB event thread";
130 threadAttr
.stackSize
= 32 * 1024; /* 32kbytes */
131 threadAttr
.priority
= 128;
133 /* reset event queue */
134 ixOsalMutexLock(&eventQueueLock
, IX_OSAL_WAIT_FOREVER
);
136 RESET_QUEUE(&eventQueue
);
138 ixOsalMutexUnlock(&eventQueueLock
);
140 /* init event queue semaphore */
141 if (ixOsalSemaphoreInit(&eventQueueSemaphore
, 0) != IX_SUCCESS
)
143 return IX_ETH_DB_FAIL
;
146 ixEthDBLearningShutdown
= FALSE
;
148 /* create processor loop thread */
149 if (ixOsalThreadCreate(&eventProcessorThread
, &threadAttr
, ixEthDBEventProcessorLoop
, NULL
) != IX_SUCCESS
)
151 return IX_ETH_DB_FAIL
;
154 /* start event processor */
155 ixOsalThreadStart(&eventProcessorThread
);
157 return IX_ETH_DB_SUCCESS
;
161 * @brief stops the event processor
163 * Stops the event processor and frees the event queue semaphore
164 * Called by the component de-initialization function, ixEthDBUnload()
166 * @warning do not call directly
168 * @return IX_ETH_DB_SUCCESS if the operation completed
169 * successfully or IX_ETH_DB_FAIL otherwise;
174 IxEthDBStatus
ixEthDBStopLearningFunction(void)
176 ixEthDBLearningShutdown
= TRUE
;
178 /* wake up event processing loop to actually process the shutdown event */
179 ixOsalSemaphorePost(&eventQueueSemaphore
);
181 if (ixOsalSemaphoreDestroy(&eventQueueSemaphore
) != IX_SUCCESS
)
183 return IX_ETH_DB_FAIL
;
186 return IX_ETH_DB_SUCCESS
;
190 * @brief default NPE event processing callback
192 * @param npeID ID of the NPE that generated the event
193 * @param msg NPE message (encapsulated event)
195 * Creates an event object on the Ethernet event processor queue
196 * and signals the new event by incrementing the event queue semaphore.
197 * Events are processed by @ref ixEthDBEventProcessorLoop() which runs
200 * @see ixEthDBEventProcessorLoop()
202 * @warning do not call directly
207 void ixEthDBNPEEventCallback(IxNpeMhNpeId npeID
, IxNpeMhMessage msg
)
209 PortEvent
*local_event
;
211 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);
213 if (CAN_ENQUEUE(&eventQueue
))
215 TEST_FIXTURE_LOCK_EVENT_QUEUE
;
217 local_event
= QUEUE_HEAD(&eventQueue
);
219 /* create event structure on queue */
220 local_event
->eventType
= NPE_MSG_ID(msg
);
221 local_event
->portID
= IX_ETH_DB_NPE_TO_PORT_ID(npeID
);
224 PUSH_UPDATE_QUEUE(&eventQueue
);
226 TEST_FIXTURE_UNLOCK_EVENT_QUEUE
;
228 IX_ETH_DB_IRQ_EVENTS_TRACE("DB: (Events) Waking up main processor loop...\n", 0, 0, 0, 0, 0, 0);
230 /* increment event queue semaphore */
231 ixOsalSemaphorePost(&eventQueueSemaphore
);
235 IX_ETH_DB_IRQ_EVENTS_TRACE("DB: (Events) Warning: could not enqueue event (overflow)\n", 0, 0, 0, 0, 0, 0);
240 * @brief Ethernet event processor loop
242 * Extracts at most EVENT_PROCESSING_LIMIT batches of events and
243 * sends them for processing to @ref ixEthDBProcessEvent().
244 * Triggers port updates which normally follow learning events.
246 * @warning do not call directly, executes in separate thread
251 void ixEthDBEventProcessorLoop(void *unused1
)
253 IxEthDBPortMap triggerPorts
;
254 IxEthDBPortId portIndex
;
256 ixEthDBEventProcessorRunning
= TRUE
;
258 IX_ETH_DB_EVENTS_TRACE("DB: (Events) Event processor loop was started\n");
260 while (!ixEthDBLearningShutdown
)
262 BOOL keepProcessing
= TRUE
;
263 UINT32 processedEvents
= 0;
265 IX_ETH_DB_EVENTS_VERBOSE_TRACE("DB: (Events) Waiting for new learning event...\n");
267 ixOsalSemaphoreWait(&eventQueueSemaphore
, IX_OSAL_WAIT_FOREVER
);
269 IX_ETH_DB_EVENTS_VERBOSE_TRACE("DB: (Events) Received new event\n");
271 if (!ixEthDBLearningShutdown
)
273 /* port update handling */
274 SET_EMPTY_DEPENDENCY_MAP(triggerPorts
);
276 while (keepProcessing
)
278 PortEvent local_event
;
282 ixOsalMutexLock(&eventQueueLock
, IX_OSAL_WAIT_FOREVER
);
284 /* lock NPE interrupts */
285 intLockKey
= ixOsalIrqLock();
288 local_event
= *(QUEUE_TAIL(&eventQueue
));
290 SHIFT_UPDATE_QUEUE(&eventQueue
);
292 ixOsalIrqUnlock(intLockKey
);
294 ixOsalMutexUnlock(&eventQueueLock
);
296 IX_ETH_DB_EVENTS_TRACE("DB: (Events) Processing event with ID 0x%X\n", local_event
.eventType
);
298 ixEthDBProcessEvent(&local_event
, triggerPorts
);
302 if (processedEvents
> EVENT_PROCESSING_LIMIT
/* maximum burst reached? */
303 || ixOsalSemaphoreTryWait(&eventQueueSemaphore
) != IX_SUCCESS
) /* or empty queue? */
305 keepProcessing
= FALSE
;
309 ixEthDBUpdatePortLearningTrees(triggerPorts
);
313 /* turn off automatic updates */
314 for (portIndex
= 0 ; portIndex
< IX_ETH_DB_NUMBER_OF_PORTS
; portIndex
++)
316 ixEthDBPortInfo
[portIndex
].updateMethod
.updateEnabled
= FALSE
;
319 ixEthDBEventProcessorRunning
= FALSE
;
323 * @brief event processor routine
325 * @param event event to be processed
326 * @param triggerPorts port map accumulating ports to be updated
328 * Processes learning events by synchronizing the database with
329 * newly learnt data. Called only by @ref ixEthDBEventProcessorLoop().
331 * @warning do not call directly
336 void ixEthDBProcessEvent(PortEvent
*local_event
, IxEthDBPortMap triggerPorts
)
338 MacDescriptor recordTemplate
;
340 switch (local_event
->eventType
)
342 case IX_ETH_DB_ADD_FILTERING_RECORD
:
344 memset(&recordTemplate
, 0, sizeof (recordTemplate
));
345 memcpy(recordTemplate
.macAddress
, local_event
->macAddr
.macAddress
, sizeof (IxEthDBMacAddr
));
347 recordTemplate
.type
= IX_ETH_DB_FILTERING_RECORD
;
348 recordTemplate
.portID
= local_event
->portID
;
349 recordTemplate
.recordData
.filteringData
.staticEntry
= local_event
->staticEntry
;
351 ixEthDBAdd(&recordTemplate
, triggerPorts
);
353 IX_ETH_DB_EVENTS_TRACE("DB: (Events) Added record on port %d\n", local_event
->portID
);
357 case IX_ETH_DB_REMOVE_FILTERING_RECORD
:
359 memset(&recordTemplate
, 0, sizeof (recordTemplate
));
360 memcpy(recordTemplate
.macAddress
, local_event
->macAddr
.macAddress
, sizeof (IxEthDBMacAddr
));
362 recordTemplate
.type
= IX_ETH_DB_FILTERING_RECORD
| IX_ETH_DB_FILTERING_VLAN_RECORD
;
364 ixEthDBRemove(&recordTemplate
, triggerPorts
);
366 IX_ETH_DB_EVENTS_TRACE("DB: (Events) Removed record on port %d\n", local_event
->portID
);
371 /* can't handle/not interested in this event type */
372 ERROR_LOG("DB: (Events) Event processor received an unknown event type (0x%X)\n", local_event
->eventType
);
379 * @brief asynchronously adds a filtering record
380 * by posting an ADD_FILTERING_RECORD event to the event queue
382 * @param macAddr MAC address of the new record
383 * @param portID port ID of the new record
384 * @param staticEntry TRUE if record is static, FALSE if dynamic
386 * @return IX_ETH_DB_SUCCESS if the event creation was
387 * successfull or IX_ETH_DB_BUSY if the event queue is full
392 IxEthDBStatus
ixEthDBTriggerAddPortUpdate(IxEthDBMacAddr
*macAddr
, IxEthDBPortId portID
, BOOL staticEntry
)
394 MacDescriptor reference
;
396 TEST_FIXTURE_INCREMENT_DB_CORE_ACCESS_COUNTER
;
398 /* fill search fields */
399 memcpy(reference
.macAddress
, macAddr
, sizeof (IxEthDBMacAddr
));
400 reference
.portID
= portID
;
402 /* set acceptable record types */
403 reference
.type
= IX_ETH_DB_ALL_FILTERING_RECORDS
;
405 if (ixEthDBPeekHashEntry(&dbHashtable
, IX_ETH_DB_MAC_PORT_KEY
, &reference
) == IX_ETH_DB_SUCCESS
)
407 /* already have an identical record */
408 return IX_ETH_DB_SUCCESS
;
412 return ixEthDBTriggerPortUpdate(IX_ETH_DB_ADD_FILTERING_RECORD
, macAddr
, portID
, staticEntry
);
417 * @brief asynchronously removes a filtering record
418 * by posting a REMOVE_FILTERING_RECORD event to the event queue
420 * @param macAddr MAC address of the record to remove
421 * @param portID port ID of the record to remove
423 * @return IX_ETH_DB_SUCCESS if the event creation was
424 * successfull or IX_ETH_DB_BUSY if the event queue is full
429 IxEthDBStatus
ixEthDBTriggerRemovePortUpdate(IxEthDBMacAddr
*macAddr
, IxEthDBPortId portID
)
431 if (ixEthDBPeek(macAddr
, IX_ETH_DB_ALL_FILTERING_RECORDS
) != IX_ETH_DB_NO_SUCH_ADDR
)
433 return ixEthDBTriggerPortUpdate(IX_ETH_DB_REMOVE_FILTERING_RECORD
, macAddr
, portID
, FALSE
);
437 return IX_ETH_DB_NO_SUCH_ADDR
;
442 * @brief adds an ADD or REMOVE event to the main event queue
444 * @param eventType event type - IX_ETH_DB_ADD_FILTERING_RECORD
445 * to add and IX_ETH_DB_REMOVE_FILTERING_RECORD to remove a
448 * @return IX_ETH_DB_SUCCESS if the event was successfully
449 * sent or IX_ETH_DB_BUSY if the event queue is full
454 IxEthDBStatus
ixEthDBTriggerPortUpdate(UINT32 eventType
, IxEthDBMacAddr
*macAddr
, IxEthDBPortId portID
, BOOL staticEntry
)
458 /* lock interrupts to protect queue */
459 intLockKey
= ixOsalIrqLock();
461 if (CAN_ENQUEUE(&eventQueue
))
463 PortEvent
*queueEvent
= QUEUE_HEAD(&eventQueue
);
465 /* update fields on the queue */
466 memcpy(queueEvent
->macAddr
.macAddress
, macAddr
->macAddress
, sizeof (IxEthDBMacAddr
));
468 queueEvent
->eventType
= eventType
;
469 queueEvent
->portID
= portID
;
470 queueEvent
->staticEntry
= staticEntry
;
472 PUSH_UPDATE_QUEUE(&eventQueue
);
474 /* imcrement event queue semaphore */
475 ixOsalSemaphorePost(&eventQueueSemaphore
);
477 /* unlock interrupts */
478 ixOsalIrqUnlock(intLockKey
);
480 return IX_ETH_DB_SUCCESS
;
482 else /* event queue full */
484 /* unlock interrupts */
485 ixOsalIrqUnlock(intLockKey
);
487 return IX_ETH_DB_BUSY
;
492 * @brief Locks learning tree updates and port disable
495 * This function locks portUpdateLock single mutex. It is primarily used
496 * to avoid executing 'port disable' during ELT maintenance.
501 void ixEthDBUpdateLock(void)
503 ixOsalMutexLock(&portUpdateLock
, IX_OSAL_WAIT_FOREVER
);
507 * @brief Unlocks learning tree updates and port disable
510 * This function unlocks a portUpdateLock mutex. It is primarily used
511 * to avoid executing 'port disable' during ELT maintenance.
516 void ixEthDBUpdateUnlock(void)
518 ixOsalMutexUnlock(&portUpdateLock
);