blob: 4d44e0333757458ee3fa15a2ce0c04160acfd3dd [file] [log] [blame]
Wolfgang Denk4646d2a2006-05-30 15:56:48 +02001/**
2 * @file IxEthDBEvents.c
3 *
4 * @brief Implementation of the event processor component
5 *
6 * @par
7 * IXP400 SW Release version 2.0
8 *
9 * -- Copyright Notice --
10 *
11 * @par
12 * Copyright 2001-2005, Intel Corporation.
13 * All rights reserved.
14 *
15 * @par
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
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.
27 *
28 * @par
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
39 * SUCH DAMAGE.
40 *
41 * @par
42 * -- End of Copyright Notice --
43 */
44
45#include <IxNpeMh.h>
46#include <IxFeatureCtrl.h>
47
48#include "IxEthDB_p.h"
49
50/* forward prototype declarations */
51IX_ETH_DB_PUBLIC void ixEthDBEventProcessorLoop(void *);
52IX_ETH_DB_PUBLIC void ixEthDBNPEEventCallback(IxNpeMhNpeId npeID, IxNpeMhMessage msg);
53IX_ETH_DB_PRIVATE void ixEthDBProcessEvent(PortEvent *local_event, IxEthDBPortMap triggerPorts);
54IX_ETH_DB_PRIVATE IxEthDBStatus ixEthDBTriggerPortUpdate(UINT32 eventType, IxEthDBMacAddr *macAddr, IxEthDBPortId portID, BOOL staticEntry);
55IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBStartLearningFunction(void);
56IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBStopLearningFunction(void);
57
58/* data */
59IX_ETH_DB_PRIVATE IxOsalSemaphore eventQueueSemaphore;
60IX_ETH_DB_PRIVATE PortEventQueue eventQueue;
61IX_ETH_DB_PRIVATE IxOsalMutex eventQueueLock;
62IX_ETH_DB_PRIVATE IxOsalMutex portUpdateLock;
63
64IX_ETH_DB_PRIVATE BOOL ixEthDBLearningShutdown = FALSE;
65IX_ETH_DB_PRIVATE BOOL ixEthDBEventProcessorRunning = FALSE;
66
67/* imported data */
68extern HashTable dbHashtable;
69
70/**
71 * @brief initializes the event processor
72 *
73 * Initializes the event processor queue and processing thread.
74 * Called from ixEthDBInit() DB-subcomponent master init function.
75 *
76 * @warning do not call directly
77 *
78 * @retval IX_ETH_DB_SUCCESS initialization was successful
79 * @retval IX_ETH_DB_FAIL initialization failed (OSAL or mutex init failure)
80 *
81 * @internal
82 */
83IX_ETH_DB_PUBLIC
84IxEthDBStatus ixEthDBEventProcessorInit(void)
85{
86 if (ixOsalMutexInit(&portUpdateLock) != IX_SUCCESS)
87 {
88 return IX_ETH_DB_FAIL;
89 }
90
91 if (ixOsalMutexInit(&eventQueueLock) != IX_SUCCESS)
92 {
93 return IX_ETH_DB_FAIL;
94 }
95
96 if (IX_FEATURE_CTRL_SWCONFIG_ENABLED ==
97 ixFeatureCtrlSwConfigurationCheck (IX_FEATURECTRL_ETH_LEARNING))
98 {
99
100 /* start processor loop thread */
101 if (ixEthDBStartLearningFunction() != IX_ETH_DB_SUCCESS)
102 {
103 return IX_ETH_DB_FAIL;
104 }
105 }
106
107 return IX_ETH_DB_SUCCESS;
108}
109
110/**
111 * @brief initializes the event queue and the event processor
112 *
113 * This function is called by the component initialization
114 * function, ixEthDBInit().
115 *
116 * @warning do not call directly
117 *
118 * @return IX_ETH_DB_SUCCESS if the operation completed
119 * successfully or IX_ETH_DB_FAIL otherwise
120 *
121 * @internal
122 */
123IX_ETH_DB_PUBLIC
124IxEthDBStatus ixEthDBStartLearningFunction(void)
125{
126 IxOsalThread eventProcessorThread;
127 IxOsalThreadAttr threadAttr;
128
129 threadAttr.name = "EthDB event thread";
130 threadAttr.stackSize = 32 * 1024; /* 32kbytes */
131 threadAttr.priority = 128;
132
133 /* reset event queue */
134 ixOsalMutexLock(&eventQueueLock, IX_OSAL_WAIT_FOREVER);
135
136 RESET_QUEUE(&eventQueue);
137
138 ixOsalMutexUnlock(&eventQueueLock);
139
140 /* init event queue semaphore */
141 if (ixOsalSemaphoreInit(&eventQueueSemaphore, 0) != IX_SUCCESS)
142 {
143 return IX_ETH_DB_FAIL;
144 }
145
146 ixEthDBLearningShutdown = FALSE;
147
148 /* create processor loop thread */
149 if (ixOsalThreadCreate(&eventProcessorThread, &threadAttr, ixEthDBEventProcessorLoop, NULL) != IX_SUCCESS)
150 {
151 return IX_ETH_DB_FAIL;
152 }
153
154 /* start event processor */
155 ixOsalThreadStart(&eventProcessorThread);
156
157 return IX_ETH_DB_SUCCESS;
158}
159
160/**
161 * @brief stops the event processor
162 *
163 * Stops the event processor and frees the event queue semaphore
164 * Called by the component de-initialization function, ixEthDBUnload()
165 *
166 * @warning do not call directly
167 *
168 * @return IX_ETH_DB_SUCCESS if the operation completed
169 * successfully or IX_ETH_DB_FAIL otherwise;
170 *
171 * @internal
172 */
173IX_ETH_DB_PUBLIC
174IxEthDBStatus ixEthDBStopLearningFunction(void)
175{
176 ixEthDBLearningShutdown = TRUE;
177
178 /* wake up event processing loop to actually process the shutdown event */
179 ixOsalSemaphorePost(&eventQueueSemaphore);
180
181 if (ixOsalSemaphoreDestroy(&eventQueueSemaphore) != IX_SUCCESS)
182 {
183 return IX_ETH_DB_FAIL;
184 }
185
186 return IX_ETH_DB_SUCCESS;
187}
188
189/**
190 * @brief default NPE event processing callback
191 *
192 * @param npeID ID of the NPE that generated the event
193 * @param msg NPE message (encapsulated event)
194 *
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
198 * at user level.
199 *
200 * @see ixEthDBEventProcessorLoop()
201 *
202 * @warning do not call directly
203 *
204 * @internal
205 */
206IX_ETH_DB_PUBLIC
207void ixEthDBNPEEventCallback(IxNpeMhNpeId npeID, IxNpeMhMessage msg)
208{
209 PortEvent *local_event;
210
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);
212
213 if (CAN_ENQUEUE(&eventQueue))
214 {
215 TEST_FIXTURE_LOCK_EVENT_QUEUE;
216
217 local_event = QUEUE_HEAD(&eventQueue);
218
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);
222
223 /* update queue */
224 PUSH_UPDATE_QUEUE(&eventQueue);
225
226 TEST_FIXTURE_UNLOCK_EVENT_QUEUE;
227
228 IX_ETH_DB_IRQ_EVENTS_TRACE("DB: (Events) Waking up main processor loop...\n", 0, 0, 0, 0, 0, 0);
229
230 /* increment event queue semaphore */
231 ixOsalSemaphorePost(&eventQueueSemaphore);
232 }
233 else
234 {
235 IX_ETH_DB_IRQ_EVENTS_TRACE("DB: (Events) Warning: could not enqueue event (overflow)\n", 0, 0, 0, 0, 0, 0);
236 }
237}
238
239/**
240 * @brief Ethernet event processor loop
241 *
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.
245 *
246 * @warning do not call directly, executes in separate thread
247 *
248 * @internal
249 */
250IX_ETH_DB_PUBLIC
251void ixEthDBEventProcessorLoop(void *unused1)
252{
253 IxEthDBPortMap triggerPorts;
254 IxEthDBPortId portIndex;
255
256 ixEthDBEventProcessorRunning = TRUE;
257
258 IX_ETH_DB_EVENTS_TRACE("DB: (Events) Event processor loop was started\n");
259
260 while (!ixEthDBLearningShutdown)
261 {
262 BOOL keepProcessing = TRUE;
263 UINT32 processedEvents = 0;
264
265 IX_ETH_DB_EVENTS_VERBOSE_TRACE("DB: (Events) Waiting for new learning event...\n");
266
267 ixOsalSemaphoreWait(&eventQueueSemaphore, IX_OSAL_WAIT_FOREVER);
268
269 IX_ETH_DB_EVENTS_VERBOSE_TRACE("DB: (Events) Received new event\n");
270
271 if (!ixEthDBLearningShutdown)
272 {
273 /* port update handling */
274 SET_EMPTY_DEPENDENCY_MAP(triggerPorts);
275
276 while (keepProcessing)
277 {
278 PortEvent local_event;
279 UINT32 intLockKey;
280
281 /* lock queue */
282 ixOsalMutexLock(&eventQueueLock, IX_OSAL_WAIT_FOREVER);
283
284 /* lock NPE interrupts */
285 intLockKey = ixOsalIrqLock();
286
287 /* extract event */
288 local_event = *(QUEUE_TAIL(&eventQueue));
289
290 SHIFT_UPDATE_QUEUE(&eventQueue);
291
292 ixOsalIrqUnlock(intLockKey);
293
294 ixOsalMutexUnlock(&eventQueueLock);
295
296 IX_ETH_DB_EVENTS_TRACE("DB: (Events) Processing event with ID 0x%X\n", local_event.eventType);
297
298 ixEthDBProcessEvent(&local_event, triggerPorts);
299
300 processedEvents++;
301
302 if (processedEvents > EVENT_PROCESSING_LIMIT /* maximum burst reached? */
303 || ixOsalSemaphoreTryWait(&eventQueueSemaphore) != IX_SUCCESS) /* or empty queue? */
304 {
305 keepProcessing = FALSE;
306 }
307 }
308
309 ixEthDBUpdatePortLearningTrees(triggerPorts);
310 }
311 }
312
313 /* turn off automatic updates */
314 for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++)
315 {
316 ixEthDBPortInfo[portIndex].updateMethod.updateEnabled = FALSE;
317 }
318
319 ixEthDBEventProcessorRunning = FALSE;
320}
321
322/**
323 * @brief event processor routine
324 *
325 * @param event event to be processed
326 * @param triggerPorts port map accumulating ports to be updated
327 *
328 * Processes learning events by synchronizing the database with
329 * newly learnt data. Called only by @ref ixEthDBEventProcessorLoop().
330 *
331 * @warning do not call directly
332 *
333 * @internal
334 */
335IX_ETH_DB_PRIVATE
336void ixEthDBProcessEvent(PortEvent *local_event, IxEthDBPortMap triggerPorts)
337{
338 MacDescriptor recordTemplate;
339
340 switch (local_event->eventType)
341 {
342 case IX_ETH_DB_ADD_FILTERING_RECORD:
343 /* add record */
344 memset(&recordTemplate, 0, sizeof (recordTemplate));
345 memcpy(recordTemplate.macAddress, local_event->macAddr.macAddress, sizeof (IxEthDBMacAddr));
346
347 recordTemplate.type = IX_ETH_DB_FILTERING_RECORD;
348 recordTemplate.portID = local_event->portID;
349 recordTemplate.recordData.filteringData.staticEntry = local_event->staticEntry;
350
351 ixEthDBAdd(&recordTemplate, triggerPorts);
352
353 IX_ETH_DB_EVENTS_TRACE("DB: (Events) Added record on port %d\n", local_event->portID);
354
355 break;
356
357 case IX_ETH_DB_REMOVE_FILTERING_RECORD:
358 /* remove record */
359 memset(&recordTemplate, 0, sizeof (recordTemplate));
360 memcpy(recordTemplate.macAddress, local_event->macAddr.macAddress, sizeof (IxEthDBMacAddr));
361
362 recordTemplate.type = IX_ETH_DB_FILTERING_RECORD | IX_ETH_DB_FILTERING_VLAN_RECORD;
363
364 ixEthDBRemove(&recordTemplate, triggerPorts);
365
366 IX_ETH_DB_EVENTS_TRACE("DB: (Events) Removed record on port %d\n", local_event->portID);
367
368 break;
369
370 default:
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);
373
374 return;
375 }
376}
377
378/**
379 * @brief asynchronously adds a filtering record
380 * by posting an ADD_FILTERING_RECORD event to the event queue
381 *
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
385 *
386 * @return IX_ETH_DB_SUCCESS if the event creation was
387 * successfull or IX_ETH_DB_BUSY if the event queue is full
388 *
389 * @internal
390 */
391IX_ETH_DB_PUBLIC
392IxEthDBStatus ixEthDBTriggerAddPortUpdate(IxEthDBMacAddr *macAddr, IxEthDBPortId portID, BOOL staticEntry)
393{
394 MacDescriptor reference;
395
396 TEST_FIXTURE_INCREMENT_DB_CORE_ACCESS_COUNTER;
397
398 /* fill search fields */
399 memcpy(reference.macAddress, macAddr, sizeof (IxEthDBMacAddr));
400 reference.portID = portID;
401
402 /* set acceptable record types */
403 reference.type = IX_ETH_DB_ALL_FILTERING_RECORDS;
404
405 if (ixEthDBPeekHashEntry(&dbHashtable, IX_ETH_DB_MAC_PORT_KEY, &reference) == IX_ETH_DB_SUCCESS)
406 {
407 /* already have an identical record */
408 return IX_ETH_DB_SUCCESS;
409 }
410 else
411 {
412 return ixEthDBTriggerPortUpdate(IX_ETH_DB_ADD_FILTERING_RECORD, macAddr, portID, staticEntry);
413 }
414}
415
416/**
417 * @brief asynchronously removes a filtering record
418 * by posting a REMOVE_FILTERING_RECORD event to the event queue
419 *
420 * @param macAddr MAC address of the record to remove
421 * @param portID port ID of the record to remove
422 *
423 * @return IX_ETH_DB_SUCCESS if the event creation was
424 * successfull or IX_ETH_DB_BUSY if the event queue is full
425 *
426 * @internal
427 */
428IX_ETH_DB_PUBLIC
429IxEthDBStatus ixEthDBTriggerRemovePortUpdate(IxEthDBMacAddr *macAddr, IxEthDBPortId portID)
430{
431 if (ixEthDBPeek(macAddr, IX_ETH_DB_ALL_FILTERING_RECORDS) != IX_ETH_DB_NO_SUCH_ADDR)
432 {
433 return ixEthDBTriggerPortUpdate(IX_ETH_DB_REMOVE_FILTERING_RECORD, macAddr, portID, FALSE);
434 }
435 else
436 {
437 return IX_ETH_DB_NO_SUCH_ADDR;
438 }
439}
440
441/**
442 * @brief adds an ADD or REMOVE event to the main event queue
443 *
444 * @param eventType event type - IX_ETH_DB_ADD_FILTERING_RECORD
445 * to add and IX_ETH_DB_REMOVE_FILTERING_RECORD to remove a
446 * record.
447 *
448 * @return IX_ETH_DB_SUCCESS if the event was successfully
449 * sent or IX_ETH_DB_BUSY if the event queue is full
450 *
451 * @internal
452 */
453IX_ETH_DB_PRIVATE
454IxEthDBStatus ixEthDBTriggerPortUpdate(UINT32 eventType, IxEthDBMacAddr *macAddr, IxEthDBPortId portID, BOOL staticEntry)
455{
456 UINT32 intLockKey;
457
458 /* lock interrupts to protect queue */
459 intLockKey = ixOsalIrqLock();
460
461 if (CAN_ENQUEUE(&eventQueue))
462 {
463 PortEvent *queueEvent = QUEUE_HEAD(&eventQueue);
464
465 /* update fields on the queue */
466 memcpy(queueEvent->macAddr.macAddress, macAddr->macAddress, sizeof (IxEthDBMacAddr));
467
468 queueEvent->eventType = eventType;
469 queueEvent->portID = portID;
470 queueEvent->staticEntry = staticEntry;
471
472 PUSH_UPDATE_QUEUE(&eventQueue);
473
474 /* imcrement event queue semaphore */
475 ixOsalSemaphorePost(&eventQueueSemaphore);
476
477 /* unlock interrupts */
478 ixOsalIrqUnlock(intLockKey);
479
480 return IX_ETH_DB_SUCCESS;
481 }
482 else /* event queue full */
483 {
484 /* unlock interrupts */
485 ixOsalIrqUnlock(intLockKey);
486
487 return IX_ETH_DB_BUSY;
488 }
489}
490
491/**
492 * @brief Locks learning tree updates and port disable
493 *
494 *
495 * This function locks portUpdateLock single mutex. It is primarily used
496 * to avoid executing 'port disable' during ELT maintenance.
497 *
498 * @internal
499 */
500IX_ETH_DB_PUBLIC
501void ixEthDBUpdateLock(void)
502{
503 ixOsalMutexLock(&portUpdateLock, IX_OSAL_WAIT_FOREVER);
504}
505
506/**
507 * @brief Unlocks learning tree updates and port disable
508 *
509 *
510 * This function unlocks a portUpdateLock mutex. It is primarily used
511 * to avoid executing 'port disable' during ELT maintenance.
512 *
513 * @internal
514 */
515IX_ETH_DB_PUBLIC
516void ixEthDBUpdateUnlock(void)
517{
518 ixOsalMutexUnlock(&portUpdateLock);
519}
520