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