1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45#include "IxEthDB_p.h"
46
47
48IX_ETH_DB_PRIVATE MacTreeNode* ixEthDBTreeInsert(MacTreeNode *searchTree, MacDescriptor *descriptor);
49IX_ETH_DB_PRIVATE void ixEthDBCreateTrees(IxEthDBPortMap updatePorts);
50IX_ETH_DB_PRIVATE MacTreeNode* ixEthDBTreeRebalance(MacTreeNode *searchTree);
51IX_ETH_DB_PRIVATE void ixEthDBRebalanceTreeToVine(MacTreeNode *root, UINT32 *size);
52IX_ETH_DB_PRIVATE void ixEthDBRebalanceVineToTree(MacTreeNode *root, UINT32 size);
53IX_ETH_DB_PRIVATE void ixEthDBRebalanceCompression(MacTreeNode *root, UINT32 count);
54IX_ETH_DB_PRIVATE UINT32 ixEthDBRebalanceLog2Floor(UINT32 x);
55
56extern HashTable dbHashtable;
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84IX_ETH_DB_PUBLIC
85UINT32 ixEthDBUpdateTypeRegister(BOOL *typeArray)
86{
87 typeArray[IX_ETH_DB_FILTERING_RECORD] = TRUE;
88 typeArray[IX_ETH_DB_FILTERING_VLAN_RECORD] = TRUE;
89
90 return 2;
91}
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106IX_ETH_DB_PUBLIC
107void ixEthDBUpdatePortLearningTrees(IxEthDBPortMap triggerPorts)
108{
109 IxEthDBPortMap updatePorts;
110 UINT32 portIndex;
111
112 ixEthDBUpdateLock();
113
114 SET_EMPTY_DEPENDENCY_MAP(updatePorts);
115
116 for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++)
117 {
118 PortInfo *port = &ixEthDBPortInfo[portIndex];
119 BOOL mapsCollide;
120
121 MAPS_COLLIDE(mapsCollide, triggerPorts, port->dependencyPortMap);
122
123 if (mapsCollide
124 && !IS_PORT_INCLUDED(portIndex, updatePorts)
125 && port->updateMethod.updateEnabled)
126 {
127 IX_ETH_DB_UPDATE_TRACE("DB: (Update) Adding port %d to update set\n", portIndex);
128
129 JOIN_PORT_TO_MAP(updatePorts, portIndex);
130 }
131 else
132 {
133 IX_ETH_DB_UPDATE_TRACE("DB: (Update) Didn't add port %d to update set, reasons follow:\n", portIndex);
134
135 if (!mapsCollide)
136 {
137 IX_ETH_DB_UPDATE_TRACE("\tMaps don't collide on port %d\n", portIndex);
138 }
139
140 if (IS_PORT_INCLUDED(portIndex, updatePorts))
141 {
142 IX_ETH_DB_UPDATE_TRACE("\tPort %d is already in the update set\n", portIndex);
143 }
144
145 if (!port->updateMethod.updateEnabled)
146 {
147 IX_ETH_DB_UPDATE_TRACE("\tPort %d doesn't have updateEnabled set\n", portIndex);
148 }
149 }
150 }
151
152 IX_ETH_DB_UPDATE_TRACE("DB: (Update) Updating port set\n");
153
154 ixEthDBCreateTrees(updatePorts);
155
156 ixEthDBUpdateUnlock();
157}
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172IX_ETH_DB_PRIVATE
173void ixEthDBCreateTrees(IxEthDBPortMap updatePorts)
174{
175 UINT32 portIndex;
176 BOOL result;
177 BOOL portsLeft = TRUE;
178
179 while (portsLeft)
180 {
181
182 UINT32 minPortIndex = MAX_PORT_SIZE;
183 UINT32 minimalSize = MAX_PORT_SIZE;
184
185 for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++)
186 {
187 UINT32 size;
188 PortInfo *port = &ixEthDBPortInfo[portIndex];
189
190
191 if (!port->updateMethod.searchTreePendingWrite && IS_PORT_INCLUDED(portIndex, updatePorts))
192 {
193 GET_MAP_SIZE(port->dependencyPortMap, size);
194
195 IX_ETH_DB_UPDATE_TRACE("DB: (Update) Dependency map for port %d: size %d\n",
196 portIndex, size);
197
198 if (size < minimalSize)
199 {
200 minPortIndex = portIndex;
201 minimalSize = size;
202 }
203 }
204 else
205 {
206 IX_ETH_DB_UPDATE_TRACE("DB: (Update) Skipped port %d from tree diff (%s)\n", portIndex,
207 port->updateMethod.searchTreePendingWrite ? "pending write access" : "ignored by query");
208 }
209 }
210
211
212 if (minimalSize != MAX_PORT_SIZE)
213 {
214
215 PortInfo *port = &ixEthDBPortInfo[minPortIndex];
216
217 IxEthDBPortMap query;
218 MacTreeNode *baseTree;
219
220
221 PortInfo *minimalDiffPort = NULL;
222 UINT32 minimalDiff = MAX_PORT_SIZE;
223
224 IX_ETH_DB_UPDATE_TRACE("DB: (Update) Minimal size port is %d\n", minPortIndex);
225
226 for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++)
227 {
228 PortInfo *diffPort = &ixEthDBPortInfo[portIndex];
229 BOOL mapIsSubset;
230
231 IS_MAP_SUBSET(mapIsSubset, diffPort->dependencyPortMap, port->dependencyPortMap);
232
233
234 if (portIndex != minPortIndex
235 && diffPort->updateMethod.searchTree != NULL
236 && mapIsSubset)
237 {
238
239 UINT32 diffPortSize;
240 UINT32 sizeDifference;
241
242 GET_MAP_SIZE(diffPort->dependencyPortMap, diffPortSize);
243
244 IX_ETH_DB_UPDATE_TRACE("DB: (Update) Checking port %d for differences...\n", portIndex);
245
246 sizeDifference = minimalSize - diffPortSize;
247
248 if (sizeDifference < minimalDiff)
249 {
250 minimalDiffPort = diffPort;
251 minimalDiff = sizeDifference;
252
253 IX_ETH_DB_UPDATE_TRACE("DB: (Update) Minimal difference 0x%x was found on port %d\n",
254 minimalDiff, portIndex);
255 }
256 }
257 }
258
259
260 if ((port->featureStatus & IX_ETH_DB_FILTERING) != 0)
261 {
262
263 if (minimalDiff != MAX_PORT_SIZE)
264 {
265 baseTree = ixEthDBCloneMacTreeNode(minimalDiffPort->updateMethod.searchTree);
266 DIFF_MAPS(query, port->dependencyPortMap , minimalDiffPort->dependencyPortMap);
267
268 IX_ETH_DB_UPDATE_TRACE("DB: (Update) Found minimal diff, extending tree %d on query\n",
269 minimalDiffPort->portID);
270 }
271 else
272 {
273 baseTree = NULL;
274
275 COPY_DEPENDENCY_MAP(query, port->dependencyPortMap);
276
277 IX_ETH_DB_UPDATE_TRACE("DB: (Update) No similar diff, creating tree from query\n");
278 }
279
280 IS_EMPTY_DEPENDENCY_MAP(result, query);
281
282 if (!result)
283 {
284 IX_ETH_DB_UPDATE_TRACE("DB: (Update) Adding query tree to port %d\n", minPortIndex);
285
286
287 port->updateMethod.searchTree = ixEthDBQuery(baseTree, query, IX_ETH_DB_ALL_FILTERING_RECORDS, MAX_ELT_SIZE);
288 }
289 else
290 {
291 IX_ETH_DB_UPDATE_TRACE("DB: (Update) Query is empty, assuming identical nearest tree\n");
292
293 port->updateMethod.searchTree = baseTree;
294 }
295 }
296 else
297 {
298
299 if (port->updateMethod.searchTree != NULL)
300 {
301 ixEthDBFreeMacTreeNode(port->updateMethod.searchTree);
302 }
303
304 port->updateMethod.searchTree = NULL;
305 }
306
307
308 port->updateMethod.searchTreePendingWrite = TRUE;
309 }
310 else
311 {
312 portsLeft = FALSE;
313
314 IX_ETH_DB_UPDATE_TRACE("DB: (Update) No trees to create this round\n");
315 }
316 }
317
318 for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++)
319 {
320 PortInfo *updatePort = &ixEthDBPortInfo[portIndex];
321
322 if (updatePort->updateMethod.searchTreePendingWrite)
323 {
324 IX_ETH_DB_UPDATE_TRACE("DB: (PortUpdate) Starting procedure to upload new search tree (%snull) into NPE %d\n",
325 updatePort->updateMethod.searchTree != NULL ? "not " : "",
326 portIndex);
327
328 updatePort->updateMethod.updateHandler(portIndex, IX_ETH_DB_FILTERING_RECORD);
329 }
330 }
331}
332
333
334
335
336
337
338
339
340
341
342
343
344IX_ETH_DB_PUBLIC
345IxEthDBStatus ixEthDBNPEUpdateHandler(IxEthDBPortId portID, IxEthDBRecordType type)
346{
347 UINT32 epDelta, blockCount;
348 IxNpeMhMessage message;
349 UINT32 treeSize = 0;
350 PortInfo *port = &ixEthDBPortInfo[portID];
351
352
353 if (type == IX_ETH_DB_FILTERING_RECORD || type == IX_ETH_DB_WIFI_RECORD)
354 {
355 treeSize = FULL_ELT_BYTE_SIZE;
356 }
357 else if (type == IX_ETH_DB_FIREWALL_RECORD)
358 {
359 treeSize = FULL_FW_BYTE_SIZE;
360 }
361 else
362 {
363 return IX_ETH_DB_INVALID_ARG;
364 }
365
366
367 ixEthDBNPETreeWrite(type, treeSize, port->updateMethod.npeUpdateZone, port->updateMethod.searchTree, &epDelta, &blockCount);
368
369
370 if (port->updateMethod.searchTree != NULL)
371 {
372 ixEthDBFreeMacTreeNode(port->updateMethod.searchTree);
373 }
374
375
376 port->updateMethod.searchTree = NULL;
377 port->updateMethod.searchTreePendingWrite = FALSE;
378
379
380 if (type == IX_ETH_DB_FILTERING_RECORD || type == IX_ETH_DB_WIFI_RECORD)
381 {
382 IX_STATUS result;
383
384 FILL_SETMACADDRESSDATABASE_MSG(message, IX_ETH_DB_PORT_ID_TO_NPE_LOGICAL_ID(portID),
385 epDelta, blockCount,
386 IX_OSAL_MMU_VIRT_TO_PHYS(port->updateMethod.npeUpdateZone));
387
388 IX_ETHDB_SEND_NPE_MSG(IX_ETH_DB_PORT_ID_TO_NPE(portID), message, result);
389
390 if (result == IX_SUCCESS)
391 {
392 IX_ETH_DB_UPDATE_TRACE("DB: (PortUpdate) Finished downloading NPE tree on port %d\n", portID);
393 }
394 else
395 {
396 ixEthDBPortInfo[portID].agingEnabled = FALSE;
397 ixEthDBPortInfo[portID].updateMethod.updateEnabled = FALSE;
398 ixEthDBPortInfo[portID].updateMethod.userControlled = TRUE;
399
400 ERROR_LOG("EthDB: (PortUpdate) disabling aging and updates on port %d (assumed dead)\n", portID);
401
402 ixEthDBDatabaseClear(portID, IX_ETH_DB_ALL_RECORD_TYPES);
403
404 return IX_ETH_DB_FAIL;
405 }
406
407 return IX_ETH_DB_SUCCESS;
408 }
409 else if (type == IX_ETH_DB_FIREWALL_RECORD)
410 {
411 return ixEthDBFirewallUpdate(portID, port->updateMethod.npeUpdateZone, epDelta);
412 }
413
414 return IX_ETH_DB_INVALID_ARG;
415}
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433IX_ETH_DB_PUBLIC
434MacTreeNode* ixEthDBQuery(MacTreeNode *searchTree, IxEthDBPortMap query, IxEthDBRecordType recordFilter, UINT32 maxEntries)
435{
436 HashIterator iterator;
437 UINT32 entryCount = 0;
438
439
440 BUSY_RETRY(ixEthDBInitHashIterator(&dbHashtable, &iterator));
441
442 while (IS_ITERATOR_VALID(&iterator))
443 {
444 MacDescriptor *descriptor = (MacDescriptor *) iterator.node->data;
445
446 IX_ETH_DB_UPDATE_TRACE("DB: (PortUpdate) querying [%s]:%d on port map ... ",
447 mac2string(descriptor->macAddress),
448 descriptor->portID);
449
450 if ((descriptor->type & recordFilter) != 0
451 && IS_PORT_INCLUDED(descriptor->portID, query))
452 {
453 MacDescriptor *descriptorClone = ixEthDBCloneMacDescriptor(descriptor);
454
455 IX_ETH_DB_UPDATE_TRACE("match\n");
456
457 if (descriptorClone != NULL)
458 {
459
460 searchTree = ixEthDBTreeInsert(searchTree, descriptorClone);
461
462 entryCount++;
463 }
464 }
465 else
466 {
467 IX_ETH_DB_UPDATE_TRACE("no match\n");
468 }
469
470 if (entryCount < maxEntries)
471 {
472
473 BUSY_RETRY(ixEthDBIncrementHashIterator(&dbHashtable, &iterator));
474 }
475 else
476 {
477
478 ixEthDBReleaseHashIterator(&iterator);
479
480 IX_ETH_DB_UPDATE_TRACE("DB: (PortUpdate) number of elements reached maximum supported by port\n");
481
482 break;
483 }
484 }
485
486 IX_ETH_DB_UPDATE_TRACE("DB: (PortUpdate) query inserted %d records in the search tree\n", entryCount);
487
488 return ixEthDBTreeRebalance(searchTree);
489}
490
491
492
493
494
495
496
497
498
499
500
501IX_ETH_DB_PRIVATE
502MacTreeNode* ixEthDBTreeInsert(MacTreeNode *searchTree, MacDescriptor *descriptor)
503{
504 MacTreeNode *currentNode = searchTree;
505 MacTreeNode *insertLocation = NULL;
506 MacTreeNode *newNode;
507 INT32 insertPosition = RIGHT;
508
509 if (descriptor == NULL)
510 {
511 return searchTree;
512 }
513
514
515 newNode = ixEthDBAllocMacTreeNode();
516
517 if (newNode == NULL)
518 {
519
520 ERROR_LOG("Warning: ixEthDBAllocMacTreeNode returned NULL in file %s:%d (out of memory?)\n", __FILE__, __LINE__);
521
522 ixEthDBFreeMacDescriptor(descriptor);
523
524 return NULL;
525 }
526
527
528 newNode->descriptor = descriptor;
529
530
531 if (searchTree == NULL)
532 {
533 return newNode;
534 }
535
536
537 while (insertLocation == NULL)
538 {
539 MacTreeNode *nextNode;
540
541
542 insertPosition = ixEthDBAddressCompare(descriptor->macAddress, currentNode->descriptor->macAddress);
543
544
545 if (insertPosition == RIGHT)
546 {
547 nextNode = currentNode->right;
548 }
549 else if (insertPosition == LEFT)
550 {
551 nextNode = currentNode->left;
552 }
553 else
554 {
555
556 ERROR_LOG("Warning: trapped insertion of a duplicate MAC address in an NPE search tree\n");
557
558
559 ixEthDBFreeMacTreeNode(newNode);
560
561 return searchTree;
562 }
563
564
565 if (nextNode != NULL)
566 {
567 currentNode = nextNode;
568 }
569 else
570 {
571 insertLocation = currentNode;
572 }
573 }
574
575
576 if (insertPosition == RIGHT)
577 {
578 insertLocation->right = newNode;
579 }
580 else
581 {
582 insertLocation->left = newNode;
583 }
584
585 return searchTree;
586}
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602IX_ETH_DB_PRIVATE
603MacTreeNode* ixEthDBTreeRebalance(MacTreeNode *searchTree)
604{
605 MacTreeNode *pseudoRoot = ixEthDBAllocMacTreeNode();
606 UINT32 size;
607
608 if (pseudoRoot == NULL)
609 {
610
611 return NULL;
612 }
613
614 pseudoRoot->right = searchTree;
615
616 ixEthDBRebalanceTreeToVine(pseudoRoot, &size);
617 ixEthDBRebalanceVineToTree(pseudoRoot, size);
618
619 searchTree = pseudoRoot->right;
620
621
622 pseudoRoot->right = NULL;
623
624 ixEthDBFreeMacTreeNode(pseudoRoot);
625
626 return searchTree;
627}
628
629
630
631
632
633
634
635
636
637IX_ETH_DB_PRIVATE
638void ixEthDBRebalanceTreeToVine(MacTreeNode *root, UINT32 *size)
639{
640 MacTreeNode *vineTail = root;
641 MacTreeNode *remainder = vineTail->right;
642 MacTreeNode *tempPtr;
643
644 *size = 0;
645
646 while (remainder != NULL)
647 {
648 if (remainder->left == NULL)
649 {
650
651 vineTail = remainder;
652 remainder = remainder->right;
653 (*size)++;
654 }
655 else
656 {
657
658 tempPtr = remainder->left;
659 remainder->left = tempPtr->right;
660 tempPtr->right = remainder;
661 remainder = tempPtr;
662 vineTail->right = tempPtr;
663 }
664 }
665}
666
667
668
669
670
671
672
673
674
675IX_ETH_DB_PRIVATE
676void ixEthDBRebalanceVineToTree(MacTreeNode *root, UINT32 size)
677{
678 UINT32 leafCount = size + 1 - (1 << ixEthDBRebalanceLog2Floor(size + 1));
679
680 ixEthDBRebalanceCompression(root, leafCount);
681
682 size = size - leafCount;
683
684 while (size > 1)
685 {
686 ixEthDBRebalanceCompression(root, size / 2);
687
688 size /= 2;
689 }
690}
691
692
693
694
695
696
697
698
699
700IX_ETH_DB_PRIVATE
701void ixEthDBRebalanceCompression(MacTreeNode *root, UINT32 count)
702{
703 MacTreeNode *scanner = root;
704 MacTreeNode *child;
705 UINT32 local_index;
706
707 for (local_index = 0 ; local_index < count ; local_index++)
708 {
709 child = scanner->right;
710 scanner->right = child->right;
711 scanner = scanner->right;
712 child->right = scanner->left;
713 scanner->left = child;
714 }
715}
716
717
718
719
720
721
722
723
724
725
726IX_ETH_DB_PRIVATE
727UINT32 ixEthDBRebalanceLog2Floor(UINT32 x)
728{
729 UINT32 log = 0;
730 UINT32 val = 1;
731
732 while (val < x)
733 {
734 log++;
735 val <<= 1;
736 }
737
738 return val == x ? log : log - 1;
739}
740
741