IxEthDBEvents.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. /**
  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. #include <IxNpeMh.h>
  45. #include <IxFeatureCtrl.h>
  46. #include "IxEthDB_p.h"
  47. /* forward prototype declarations */
  48. IX_ETH_DB_PUBLIC void ixEthDBEventProcessorLoop(void *);
  49. IX_ETH_DB_PUBLIC void ixEthDBNPEEventCallback(IxNpeMhNpeId npeID, IxNpeMhMessage msg);
  50. IX_ETH_DB_PRIVATE void ixEthDBProcessEvent(PortEvent *local_event, IxEthDBPortMap triggerPorts);
  51. IX_ETH_DB_PRIVATE IxEthDBStatus ixEthDBTriggerPortUpdate(UINT32 eventType, IxEthDBMacAddr *macAddr, IxEthDBPortId portID, BOOL staticEntry);
  52. IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBStartLearningFunction(void);
  53. IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBStopLearningFunction(void);
  54. /* data */
  55. IX_ETH_DB_PRIVATE IxOsalSemaphore eventQueueSemaphore;
  56. IX_ETH_DB_PRIVATE PortEventQueue eventQueue;
  57. IX_ETH_DB_PRIVATE IxOsalMutex eventQueueLock;
  58. IX_ETH_DB_PRIVATE IxOsalMutex portUpdateLock;
  59. IX_ETH_DB_PRIVATE BOOL ixEthDBLearningShutdown = FALSE;
  60. IX_ETH_DB_PRIVATE BOOL ixEthDBEventProcessorRunning = FALSE;
  61. /* imported data */
  62. extern HashTable dbHashtable;
  63. /**
  64. * @brief initializes the event processor
  65. *
  66. * Initializes the event processor queue and processing thread.
  67. * Called from ixEthDBInit() DB-subcomponent master init function.
  68. *
  69. * @warning do not call directly
  70. *
  71. * @retval IX_ETH_DB_SUCCESS initialization was successful
  72. * @retval IX_ETH_DB_FAIL initialization failed (OSAL or mutex init failure)
  73. *
  74. * @internal
  75. */
  76. IX_ETH_DB_PUBLIC
  77. IxEthDBStatus ixEthDBEventProcessorInit(void)
  78. {
  79. if (ixOsalMutexInit(&portUpdateLock) != IX_SUCCESS)
  80. {
  81. return IX_ETH_DB_FAIL;
  82. }
  83. if (ixOsalMutexInit(&eventQueueLock) != IX_SUCCESS)
  84. {
  85. return IX_ETH_DB_FAIL;
  86. }
  87. if (IX_FEATURE_CTRL_SWCONFIG_ENABLED ==
  88. ixFeatureCtrlSwConfigurationCheck (IX_FEATURECTRL_ETH_LEARNING))
  89. {
  90. /* start processor loop thread */
  91. if (ixEthDBStartLearningFunction() != IX_ETH_DB_SUCCESS)
  92. {
  93. return IX_ETH_DB_FAIL;
  94. }
  95. }
  96. return IX_ETH_DB_SUCCESS;
  97. }
  98. /**
  99. * @brief initializes the event queue and the event processor
  100. *
  101. * This function is called by the component initialization
  102. * function, ixEthDBInit().
  103. *
  104. * @warning do not call directly
  105. *
  106. * @return IX_ETH_DB_SUCCESS if the operation completed
  107. * successfully or IX_ETH_DB_FAIL otherwise
  108. *
  109. * @internal
  110. */
  111. IX_ETH_DB_PUBLIC
  112. IxEthDBStatus ixEthDBStartLearningFunction(void)
  113. {
  114. IxOsalThread eventProcessorThread;
  115. IxOsalThreadAttr threadAttr;
  116. threadAttr.name = "EthDB event thread";
  117. threadAttr.stackSize = 32 * 1024; /* 32kbytes */
  118. threadAttr.priority = 128;
  119. /* reset event queue */
  120. ixOsalMutexLock(&eventQueueLock, IX_OSAL_WAIT_FOREVER);
  121. RESET_QUEUE(&eventQueue);
  122. ixOsalMutexUnlock(&eventQueueLock);
  123. /* init event queue semaphore */
  124. if (ixOsalSemaphoreInit(&eventQueueSemaphore, 0) != IX_SUCCESS)
  125. {
  126. return IX_ETH_DB_FAIL;
  127. }
  128. ixEthDBLearningShutdown = FALSE;
  129. /* create processor loop thread */
  130. if (ixOsalThreadCreate(&eventProcessorThread, &threadAttr, ixEthDBEventProcessorLoop, NULL) != IX_SUCCESS)
  131. {
  132. return IX_ETH_DB_FAIL;
  133. }
  134. /* start event processor */
  135. ixOsalThreadStart(&eventProcessorThread);
  136. return IX_ETH_DB_SUCCESS;
  137. }
  138. /**
  139. * @brief stops the event processor
  140. *
  141. * Stops the event processor and frees the event queue semaphore
  142. * Called by the component de-initialization function, ixEthDBUnload()
  143. *
  144. * @warning do not call directly
  145. *
  146. * @return IX_ETH_DB_SUCCESS if the operation completed
  147. * successfully or IX_ETH_DB_FAIL otherwise;
  148. *
  149. * @internal
  150. */
  151. IX_ETH_DB_PUBLIC
  152. IxEthDBStatus ixEthDBStopLearningFunction(void)
  153. {
  154. ixEthDBLearningShutdown = TRUE;
  155. /* wake up event processing loop to actually process the shutdown event */
  156. ixOsalSemaphorePost(&eventQueueSemaphore);
  157. if (ixOsalSemaphoreDestroy(&eventQueueSemaphore) != IX_SUCCESS)
  158. {
  159. return IX_ETH_DB_FAIL;
  160. }
  161. return IX_ETH_DB_SUCCESS;
  162. }
  163. /**
  164. * @brief default NPE event processing callback
  165. *
  166. * @param npeID ID of the NPE that generated the event
  167. * @param msg NPE message (encapsulated event)
  168. *
  169. * Creates an event object on the Ethernet event processor queue
  170. * and signals the new event by incrementing the event queue semaphore.
  171. * Events are processed by @ref ixEthDBEventProcessorLoop() which runs
  172. * at user level.
  173. *
  174. * @see ixEthDBEventProcessorLoop()
  175. *
  176. * @warning do not call directly
  177. *
  178. * @internal
  179. */
  180. IX_ETH_DB_PUBLIC
  181. void ixEthDBNPEEventCallback(IxNpeMhNpeId npeID, IxNpeMhMessage msg)
  182. {
  183. PortEvent *local_event;
  184. 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);
  185. if (CAN_ENQUEUE(&eventQueue))
  186. {
  187. TEST_FIXTURE_LOCK_EVENT_QUEUE;
  188. local_event = QUEUE_HEAD(&eventQueue);
  189. /* create event structure on queue */
  190. local_event->eventType = NPE_MSG_ID(msg);
  191. local_event->portID = IX_ETH_DB_NPE_TO_PORT_ID(npeID);
  192. /* update queue */
  193. PUSH_UPDATE_QUEUE(&eventQueue);
  194. TEST_FIXTURE_UNLOCK_EVENT_QUEUE;
  195. IX_ETH_DB_IRQ_EVENTS_TRACE("DB: (Events) Waking up main processor loop...\n", 0, 0, 0, 0, 0, 0);
  196. /* increment event queue semaphore */
  197. ixOsalSemaphorePost(&eventQueueSemaphore);
  198. }
  199. else
  200. {
  201. IX_ETH_DB_IRQ_EVENTS_TRACE("DB: (Events) Warning: could not enqueue event (overflow)\n", 0, 0, 0, 0, 0, 0);
  202. }
  203. }
  204. /**
  205. * @brief Ethernet event processor loop
  206. *
  207. * Extracts at most EVENT_PROCESSING_LIMIT batches of events and
  208. * sends them for processing to @ref ixEthDBProcessEvent().
  209. * Triggers port updates which normally follow learning events.
  210. *
  211. * @warning do not call directly, executes in separate thread
  212. *
  213. * @internal
  214. */
  215. IX_ETH_DB_PUBLIC
  216. void ixEthDBEventProcessorLoop(void *unused1)
  217. {
  218. IxEthDBPortMap triggerPorts;
  219. IxEthDBPortId portIndex;
  220. ixEthDBEventProcessorRunning = TRUE;
  221. IX_ETH_DB_EVENTS_TRACE("DB: (Events) Event processor loop was started\n");
  222. while (!ixEthDBLearningShutdown)
  223. {
  224. BOOL keepProcessing = TRUE;
  225. UINT32 processedEvents = 0;
  226. IX_ETH_DB_EVENTS_VERBOSE_TRACE("DB: (Events) Waiting for new learning event...\n");
  227. ixOsalSemaphoreWait(&eventQueueSemaphore, IX_OSAL_WAIT_FOREVER);
  228. IX_ETH_DB_EVENTS_VERBOSE_TRACE("DB: (Events) Received new event\n");
  229. if (!ixEthDBLearningShutdown)
  230. {
  231. /* port update handling */
  232. SET_EMPTY_DEPENDENCY_MAP(triggerPorts);
  233. while (keepProcessing)
  234. {
  235. PortEvent local_event;
  236. UINT32 intLockKey;
  237. /* lock queue */
  238. ixOsalMutexLock(&eventQueueLock, IX_OSAL_WAIT_FOREVER);
  239. /* lock NPE interrupts */
  240. intLockKey = ixOsalIrqLock();
  241. /* extract event */
  242. local_event = *(QUEUE_TAIL(&eventQueue));
  243. SHIFT_UPDATE_QUEUE(&eventQueue);
  244. ixOsalIrqUnlock(intLockKey);
  245. ixOsalMutexUnlock(&eventQueueLock);
  246. IX_ETH_DB_EVENTS_TRACE("DB: (Events) Processing event with ID 0x%X\n", local_event.eventType);
  247. ixEthDBProcessEvent(&local_event, triggerPorts);
  248. processedEvents++;
  249. if (processedEvents > EVENT_PROCESSING_LIMIT /* maximum burst reached? */
  250. || ixOsalSemaphoreTryWait(&eventQueueSemaphore) != IX_SUCCESS) /* or empty queue? */
  251. {
  252. keepProcessing = FALSE;
  253. }
  254. }
  255. ixEthDBUpdatePortLearningTrees(triggerPorts);
  256. }
  257. }
  258. /* turn off automatic updates */
  259. for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++)
  260. {
  261. ixEthDBPortInfo[portIndex].updateMethod.updateEnabled = FALSE;
  262. }
  263. ixEthDBEventProcessorRunning = FALSE;
  264. }
  265. /**
  266. * @brief event processor routine
  267. *
  268. * @param event event to be processed
  269. * @param triggerPorts port map accumulating ports to be updated
  270. *
  271. * Processes learning events by synchronizing the database with
  272. * newly learnt data. Called only by @ref ixEthDBEventProcessorLoop().
  273. *
  274. * @warning do not call directly
  275. *
  276. * @internal
  277. */
  278. IX_ETH_DB_PRIVATE
  279. void ixEthDBProcessEvent(PortEvent *local_event, IxEthDBPortMap triggerPorts)
  280. {
  281. MacDescriptor recordTemplate;
  282. switch (local_event->eventType)
  283. {
  284. case IX_ETH_DB_ADD_FILTERING_RECORD:
  285. /* add record */
  286. memset(&recordTemplate, 0, sizeof (recordTemplate));
  287. memcpy(recordTemplate.macAddress, local_event->macAddr.macAddress, sizeof (IxEthDBMacAddr));
  288. recordTemplate.type = IX_ETH_DB_FILTERING_RECORD;
  289. recordTemplate.portID = local_event->portID;
  290. recordTemplate.recordData.filteringData.staticEntry = local_event->staticEntry;
  291. ixEthDBAdd(&recordTemplate, triggerPorts);
  292. IX_ETH_DB_EVENTS_TRACE("DB: (Events) Added record on port %d\n", local_event->portID);
  293. break;
  294. case IX_ETH_DB_REMOVE_FILTERING_RECORD:
  295. /* remove record */
  296. memset(&recordTemplate, 0, sizeof (recordTemplate));
  297. memcpy(recordTemplate.macAddress, local_event->macAddr.macAddress, sizeof (IxEthDBMacAddr));
  298. recordTemplate.type = IX_ETH_DB_FILTERING_RECORD | IX_ETH_DB_FILTERING_VLAN_RECORD;
  299. ixEthDBRemove(&recordTemplate, triggerPorts);
  300. IX_ETH_DB_EVENTS_TRACE("DB: (Events) Removed record on port %d\n", local_event->portID);
  301. break;
  302. default:
  303. /* can't handle/not interested in this event type */
  304. ERROR_LOG("DB: (Events) Event processor received an unknown event type (0x%X)\n", local_event->eventType);
  305. return;
  306. }
  307. }
  308. /**
  309. * @brief asynchronously adds a filtering record
  310. * by posting an ADD_FILTERING_RECORD event to the event queue
  311. *
  312. * @param macAddr MAC address of the new record
  313. * @param portID port ID of the new record
  314. * @param staticEntry TRUE if record is static, FALSE if dynamic
  315. *
  316. * @return IX_ETH_DB_SUCCESS if the event creation was
  317. * successfull or IX_ETH_DB_BUSY if the event queue is full
  318. *
  319. * @internal
  320. */
  321. IX_ETH_DB_PUBLIC
  322. IxEthDBStatus ixEthDBTriggerAddPortUpdate(IxEthDBMacAddr *macAddr, IxEthDBPortId portID, BOOL staticEntry)
  323. {
  324. MacDescriptor reference;
  325. TEST_FIXTURE_INCREMENT_DB_CORE_ACCESS_COUNTER;
  326. /* fill search fields */
  327. memcpy(reference.macAddress, macAddr, sizeof (IxEthDBMacAddr));
  328. reference.portID = portID;
  329. /* set acceptable record types */
  330. reference.type = IX_ETH_DB_ALL_FILTERING_RECORDS;
  331. if (ixEthDBPeekHashEntry(&dbHashtable, IX_ETH_DB_MAC_PORT_KEY, &reference) == IX_ETH_DB_SUCCESS)
  332. {
  333. /* already have an identical record */
  334. return IX_ETH_DB_SUCCESS;
  335. }
  336. else
  337. {
  338. return ixEthDBTriggerPortUpdate(IX_ETH_DB_ADD_FILTERING_RECORD, macAddr, portID, staticEntry);
  339. }
  340. }
  341. /**
  342. * @brief asynchronously removes a filtering record
  343. * by posting a REMOVE_FILTERING_RECORD event to the event queue
  344. *
  345. * @param macAddr MAC address of the record to remove
  346. * @param portID port ID of the record to remove
  347. *
  348. * @return IX_ETH_DB_SUCCESS if the event creation was
  349. * successfull or IX_ETH_DB_BUSY if the event queue is full
  350. *
  351. * @internal
  352. */
  353. IX_ETH_DB_PUBLIC
  354. IxEthDBStatus ixEthDBTriggerRemovePortUpdate(IxEthDBMacAddr *macAddr, IxEthDBPortId portID)
  355. {
  356. if (ixEthDBPeek(macAddr, IX_ETH_DB_ALL_FILTERING_RECORDS) != IX_ETH_DB_NO_SUCH_ADDR)
  357. {
  358. return ixEthDBTriggerPortUpdate(IX_ETH_DB_REMOVE_FILTERING_RECORD, macAddr, portID, FALSE);
  359. }
  360. else
  361. {
  362. return IX_ETH_DB_NO_SUCH_ADDR;
  363. }
  364. }
  365. /**
  366. * @brief adds an ADD or REMOVE event to the main event queue
  367. *
  368. * @param eventType event type - IX_ETH_DB_ADD_FILTERING_RECORD
  369. * to add and IX_ETH_DB_REMOVE_FILTERING_RECORD to remove a
  370. * record.
  371. *
  372. * @return IX_ETH_DB_SUCCESS if the event was successfully
  373. * sent or IX_ETH_DB_BUSY if the event queue is full
  374. *
  375. * @internal
  376. */
  377. IX_ETH_DB_PRIVATE
  378. IxEthDBStatus ixEthDBTriggerPortUpdate(UINT32 eventType, IxEthDBMacAddr *macAddr, IxEthDBPortId portID, BOOL staticEntry)
  379. {
  380. UINT32 intLockKey;
  381. /* lock interrupts to protect queue */
  382. intLockKey = ixOsalIrqLock();
  383. if (CAN_ENQUEUE(&eventQueue))
  384. {
  385. PortEvent *queueEvent = QUEUE_HEAD(&eventQueue);
  386. /* update fields on the queue */
  387. memcpy(queueEvent->macAddr.macAddress, macAddr->macAddress, sizeof (IxEthDBMacAddr));
  388. queueEvent->eventType = eventType;
  389. queueEvent->portID = portID;
  390. queueEvent->staticEntry = staticEntry;
  391. PUSH_UPDATE_QUEUE(&eventQueue);
  392. /* imcrement event queue semaphore */
  393. ixOsalSemaphorePost(&eventQueueSemaphore);
  394. /* unlock interrupts */
  395. ixOsalIrqUnlock(intLockKey);
  396. return IX_ETH_DB_SUCCESS;
  397. }
  398. else /* event queue full */
  399. {
  400. /* unlock interrupts */
  401. ixOsalIrqUnlock(intLockKey);
  402. return IX_ETH_DB_BUSY;
  403. }
  404. }
  405. /**
  406. * @brief Locks learning tree updates and port disable
  407. *
  408. *
  409. * This function locks portUpdateLock single mutex. It is primarily used
  410. * to avoid executing 'port disable' during ELT maintenance.
  411. *
  412. * @internal
  413. */
  414. IX_ETH_DB_PUBLIC
  415. void ixEthDBUpdateLock(void)
  416. {
  417. ixOsalMutexLock(&portUpdateLock, IX_OSAL_WAIT_FOREVER);
  418. }
  419. /**
  420. * @brief Unlocks learning tree updates and port disable
  421. *
  422. *
  423. * This function unlocks a portUpdateLock mutex. It is primarily used
  424. * to avoid executing 'port disable' during ELT maintenance.
  425. *
  426. * @internal
  427. */
  428. IX_ETH_DB_PUBLIC
  429. void ixEthDBUpdateUnlock(void)
  430. {
  431. ixOsalMutexUnlock(&portUpdateLock);
  432. }