| /** |
| * @file IxEthDBDBMem.c |
| * |
| * @brief Memory handling routines for the MAC address database |
| * |
| * @par |
| * IXP400 SW Release version 2.0 |
| * |
| * -- Copyright Notice -- |
| * |
| * @par |
| * Copyright 2001-2005, Intel Corporation. |
| * All rights reserved. |
| * |
| * @par |
| * SPDX-License-Identifier: BSD-3-Clause |
| * @par |
| * -- End of Copyright Notice -- |
| */ |
| |
| |
| #include "IxEthDB_p.h" |
| |
| IX_ETH_DB_PRIVATE HashNode *nodePool = NULL; |
| IX_ETH_DB_PRIVATE MacDescriptor *macPool = NULL; |
| IX_ETH_DB_PRIVATE MacTreeNode *treePool = NULL; |
| |
| IX_ETH_DB_PRIVATE HashNode nodePoolArea[NODE_POOL_SIZE]; |
| IX_ETH_DB_PRIVATE MacDescriptor macPoolArea[MAC_POOL_SIZE]; |
| IX_ETH_DB_PRIVATE MacTreeNode treePoolArea[TREE_POOL_SIZE]; |
| |
| IX_ETH_DB_PRIVATE IxOsalMutex nodePoolLock; |
| IX_ETH_DB_PRIVATE IxOsalMutex macPoolLock; |
| IX_ETH_DB_PRIVATE IxOsalMutex treePoolLock; |
| |
| #define LOCK_NODE_POOL { ixOsalMutexLock(&nodePoolLock, IX_OSAL_WAIT_FOREVER); } |
| #define UNLOCK_NODE_POOL { ixOsalMutexUnlock(&nodePoolLock); } |
| |
| #define LOCK_MAC_POOL { ixOsalMutexLock(&macPoolLock, IX_OSAL_WAIT_FOREVER); } |
| #define UNLOCK_MAC_POOL { ixOsalMutexUnlock(&macPoolLock); } |
| |
| #define LOCK_TREE_POOL { ixOsalMutexLock(&treePoolLock, IX_OSAL_WAIT_FOREVER); } |
| #define UNLOCK_TREE_POOL { ixOsalMutexUnlock(&treePoolLock); } |
| |
| /* private function prototypes */ |
| IX_ETH_DB_PRIVATE MacDescriptor* ixEthDBPoolAllocMacDescriptor(void); |
| IX_ETH_DB_PRIVATE void ixEthDBPoolFreeMacDescriptor(MacDescriptor *macDescriptor); |
| |
| /** |
| * @addtogroup EthMemoryManagement |
| * |
| * @{ |
| */ |
| |
| /** |
| * @brief initializes the memory pools used by the ethernet database component |
| * |
| * Initializes the hash table node, mac descriptor and mac tree node pools. |
| * Called at initialization time by @ref ixEthDBInit(). |
| * |
| * @internal |
| */ |
| IX_ETH_DB_PUBLIC |
| void ixEthDBInitMemoryPools(void) |
| { |
| int local_index; |
| |
| /* HashNode pool */ |
| ixOsalMutexInit(&nodePoolLock); |
| |
| for (local_index = 0 ; local_index < NODE_POOL_SIZE ; local_index++) |
| { |
| HashNode *freeNode = &nodePoolArea[local_index]; |
| |
| freeNode->nextFree = nodePool; |
| nodePool = freeNode; |
| } |
| |
| /* MacDescriptor pool */ |
| ixOsalMutexInit(&macPoolLock); |
| |
| for (local_index = 0 ; local_index < MAC_POOL_SIZE ; local_index++) |
| { |
| MacDescriptor *freeDescriptor = &macPoolArea[local_index]; |
| |
| freeDescriptor->nextFree = macPool; |
| macPool = freeDescriptor; |
| } |
| |
| /* MacTreeNode pool */ |
| ixOsalMutexInit(&treePoolLock); |
| |
| for (local_index = 0 ; local_index < TREE_POOL_SIZE ; local_index++) |
| { |
| MacTreeNode *freeNode = &treePoolArea[local_index]; |
| |
| freeNode->nextFree = treePool; |
| treePool = freeNode; |
| } |
| } |
| |
| /** |
| * @brief allocates a hash node from the pool |
| * |
| * Allocates a hash node and resets its value. |
| * |
| * @return the allocated hash node or NULL if the pool is empty |
| * |
| * @internal |
| */ |
| IX_ETH_DB_PUBLIC |
| HashNode* ixEthDBAllocHashNode(void) |
| { |
| HashNode *allocatedNode = NULL; |
| |
| if (nodePool != NULL) |
| { |
| LOCK_NODE_POOL; |
| |
| allocatedNode = nodePool; |
| nodePool = nodePool->nextFree; |
| |
| UNLOCK_NODE_POOL; |
| |
| memset(allocatedNode, 0, sizeof(HashNode)); |
| } |
| |
| return allocatedNode; |
| } |
| |
| /** |
| * @brief frees a hash node into the pool |
| * |
| * @param hashNode node to be freed |
| * |
| * @internal |
| */ |
| IX_ETH_DB_PUBLIC |
| void ixEthDBFreeHashNode(HashNode *hashNode) |
| { |
| if (hashNode != NULL) |
| { |
| LOCK_NODE_POOL; |
| |
| hashNode->nextFree = nodePool; |
| nodePool = hashNode; |
| |
| UNLOCK_NODE_POOL; |
| } |
| } |
| |
| /** |
| * @brief allocates a mac descriptor from the pool |
| * |
| * Allocates a mac descriptor and resets its value. |
| * This function is not used directly, instead @ref ixEthDBAllocMacDescriptor() |
| * is used, which keeps track of the pointer reference count. |
| * |
| * @see ixEthDBAllocMacDescriptor() |
| * |
| * @warning this function is not used directly by any other function |
| * apart from ixEthDBAllocMacDescriptor() |
| * |
| * @return the allocated mac descriptor or NULL if the pool is empty |
| * |
| * @internal |
| */ |
| IX_ETH_DB_PRIVATE |
| MacDescriptor* ixEthDBPoolAllocMacDescriptor(void) |
| { |
| MacDescriptor *allocatedDescriptor = NULL; |
| |
| if (macPool != NULL) |
| { |
| LOCK_MAC_POOL; |
| |
| allocatedDescriptor = macPool; |
| macPool = macPool->nextFree; |
| |
| UNLOCK_MAC_POOL; |
| |
| memset(allocatedDescriptor, 0, sizeof(MacDescriptor)); |
| } |
| |
| return allocatedDescriptor; |
| } |
| |
| /** |
| * @brief allocates and initializes a mac descriptor smart pointer |
| * |
| * Uses @ref ixEthDBPoolAllocMacDescriptor() to allocate a mac descriptor |
| * from the pool and initializes its reference count. |
| * |
| * @see ixEthDBPoolAllocMacDescriptor() |
| * |
| * @return the allocated mac descriptor or NULL if the pool is empty |
| * |
| * @internal |
| */ |
| IX_ETH_DB_PUBLIC |
| MacDescriptor* ixEthDBAllocMacDescriptor(void) |
| { |
| MacDescriptor *allocatedDescriptor = ixEthDBPoolAllocMacDescriptor(); |
| |
| if (allocatedDescriptor != NULL) |
| { |
| LOCK_MAC_POOL; |
| |
| allocatedDescriptor->refCount++; |
| |
| UNLOCK_MAC_POOL; |
| } |
| |
| return allocatedDescriptor; |
| } |
| |
| /** |
| * @brief frees a mac descriptor back into the pool |
| * |
| * @param macDescriptor mac descriptor to be freed |
| * |
| * @warning this function is not to be called by anyone but |
| * ixEthDBFreeMacDescriptor() |
| * |
| * @see ixEthDBFreeMacDescriptor() |
| * |
| * @internal |
| */ |
| IX_ETH_DB_PRIVATE |
| void ixEthDBPoolFreeMacDescriptor(MacDescriptor *macDescriptor) |
| { |
| LOCK_MAC_POOL; |
| |
| macDescriptor->nextFree = macPool; |
| macPool = macDescriptor; |
| |
| UNLOCK_MAC_POOL; |
| } |
| |
| /** |
| * @brief frees or reduces the usage count of a mac descriptor smart pointer |
| * |
| * If the reference count reaches 0 (structure is no longer used anywhere) |
| * then the descriptor is freed back into the pool using ixEthDBPoolFreeMacDescriptor(). |
| * |
| * @see ixEthDBPoolFreeMacDescriptor() |
| * |
| * @internal |
| */ |
| IX_ETH_DB_PUBLIC |
| void ixEthDBFreeMacDescriptor(MacDescriptor *macDescriptor) |
| { |
| if (macDescriptor != NULL) |
| { |
| LOCK_MAC_POOL; |
| |
| if (macDescriptor->refCount > 0) |
| { |
| macDescriptor->refCount--; |
| |
| if (macDescriptor->refCount == 0) |
| { |
| UNLOCK_MAC_POOL; |
| |
| ixEthDBPoolFreeMacDescriptor(macDescriptor); |
| } |
| else |
| { |
| UNLOCK_MAC_POOL; |
| } |
| } |
| else |
| { |
| UNLOCK_MAC_POOL; |
| } |
| } |
| } |
| |
| /** |
| * @brief clones a mac descriptor smart pointer |
| * |
| * @param macDescriptor mac descriptor to clone |
| * |
| * Increments the usage count of the smart pointer |
| * |
| * @returns the cloned smart pointer |
| * |
| * @internal |
| */ |
| IX_ETH_DB_PUBLIC |
| MacDescriptor* ixEthDBCloneMacDescriptor(MacDescriptor *macDescriptor) |
| { |
| LOCK_MAC_POOL; |
| |
| if (macDescriptor->refCount == 0) |
| { |
| UNLOCK_MAC_POOL; |
| |
| return NULL; |
| } |
| |
| macDescriptor->refCount++; |
| |
| UNLOCK_MAC_POOL; |
| |
| return macDescriptor; |
| } |
| |
| /** |
| * @brief allocates a mac tree node from the pool |
| * |
| * Allocates and initializes a mac tree node from the pool. |
| * |
| * @return the allocated mac tree node or NULL if the pool is empty |
| * |
| * @internal |
| */ |
| IX_ETH_DB_PUBLIC |
| MacTreeNode* ixEthDBAllocMacTreeNode(void) |
| { |
| MacTreeNode *allocatedNode = NULL; |
| |
| if (treePool != NULL) |
| { |
| LOCK_TREE_POOL; |
| |
| allocatedNode = treePool; |
| treePool = treePool->nextFree; |
| |
| UNLOCK_TREE_POOL; |
| |
| memset(allocatedNode, 0, sizeof(MacTreeNode)); |
| } |
| |
| return allocatedNode; |
| } |
| |
| /** |
| * @brief frees a mac tree node back into the pool |
| * |
| * @param macNode mac tree node to be freed |
| * |
| * @warning not to be used except from ixEthDBFreeMacTreeNode(). |
| * |
| * @see ixEthDBFreeMacTreeNode() |
| * |
| * @internal |
| */ |
| void ixEthDBPoolFreeMacTreeNode(MacTreeNode *macNode) |
| { |
| if (macNode != NULL) |
| { |
| LOCK_TREE_POOL; |
| |
| macNode->nextFree = treePool; |
| treePool = macNode; |
| |
| UNLOCK_TREE_POOL; |
| } |
| } |
| |
| /** |
| * @brief frees or reduces the usage count of a mac tree node smart pointer |
| * |
| * @param macNode mac tree node to free |
| * |
| * Reduces the usage count of the given mac node. If the usage count |
| * reaches 0 the node is freed back into the pool using ixEthDBPoolFreeMacTreeNode() |
| * |
| * @internal |
| */ |
| IX_ETH_DB_PUBLIC |
| void ixEthDBFreeMacTreeNode(MacTreeNode *macNode) |
| { |
| if (macNode->descriptor != NULL) |
| { |
| ixEthDBFreeMacDescriptor(macNode->descriptor); |
| } |
| |
| if (macNode->left != NULL) |
| { |
| ixEthDBFreeMacTreeNode(macNode->left); |
| } |
| |
| if (macNode->right != NULL) |
| { |
| ixEthDBFreeMacTreeNode(macNode->right); |
| } |
| |
| ixEthDBPoolFreeMacTreeNode(macNode); |
| } |
| |
| /** |
| * @brief clones a mac tree node |
| * |
| * @param macNode mac tree node to be cloned |
| * |
| * Increments the usage count of the node, <i>its associated descriptor |
| * and <b>recursively</b> of all its child nodes</i>. |
| * |
| * @warning this function is recursive and clones whole trees/subtrees, use only for |
| * root nodes |
| * |
| * @internal |
| */ |
| IX_ETH_DB_PUBLIC |
| MacTreeNode* ixEthDBCloneMacTreeNode(MacTreeNode *macNode) |
| { |
| if (macNode != NULL) |
| { |
| MacTreeNode *clonedMacNode = ixEthDBAllocMacTreeNode(); |
| |
| if (clonedMacNode != NULL) |
| { |
| if (macNode->right != NULL) |
| { |
| clonedMacNode->right = ixEthDBCloneMacTreeNode(macNode->right); |
| } |
| |
| if (macNode->left != NULL) |
| { |
| clonedMacNode->left = ixEthDBCloneMacTreeNode(macNode->left); |
| } |
| |
| if (macNode->descriptor != NULL) |
| { |
| clonedMacNode->descriptor = ixEthDBCloneMacDescriptor(macNode->descriptor); |
| } |
| } |
| |
| return clonedMacNode; |
| } |
| else |
| { |
| return NULL; |
| } |
| } |
| |
| #ifndef NDEBUG |
| /* Debug statistical functions for memory usage */ |
| |
| extern HashTable dbHashtable; |
| int ixEthDBNumHashElements(void); |
| |
| int ixEthDBNumHashElements(void) |
| { |
| UINT32 bucketIndex; |
| int numElements = 0; |
| HashTable *hashTable = &dbHashtable; |
| |
| for (bucketIndex = 0 ; bucketIndex < hashTable->numBuckets ; bucketIndex++) |
| { |
| if (hashTable->hashBuckets[bucketIndex] != NULL) |
| { |
| HashNode *node = hashTable->hashBuckets[bucketIndex]; |
| |
| while (node != NULL) |
| { |
| numElements++; |
| |
| node = node->next; |
| } |
| } |
| } |
| |
| return numElements; |
| } |
| |
| UINT32 ixEthDBSearchTreeUsageGet(MacTreeNode *tree) |
| { |
| if (tree == NULL) |
| { |
| return 0; |
| } |
| else |
| { |
| return 1 /* this node */ + ixEthDBSearchTreeUsageGet(tree->left) + ixEthDBSearchTreeUsageGet(tree->right); |
| } |
| } |
| |
| int ixEthDBShowMemoryStatus(void) |
| { |
| MacDescriptor *mac; |
| MacTreeNode *tree; |
| HashNode *node; |
| |
| int macCounter = 0; |
| int treeCounter = 0; |
| int nodeCounter = 0; |
| |
| int totalTreeUsage = 0; |
| int totalDescriptorUsage = 0; |
| int totalCloneDescriptorUsage = 0; |
| int totalNodeUsage = 0; |
| |
| UINT32 portIndex; |
| |
| LOCK_NODE_POOL; |
| LOCK_MAC_POOL; |
| LOCK_TREE_POOL; |
| |
| mac = macPool; |
| tree = treePool; |
| node = nodePool; |
| |
| while (mac != NULL) |
| { |
| macCounter++; |
| |
| mac = mac->nextFree; |
| |
| if (macCounter > MAC_POOL_SIZE) |
| { |
| break; |
| } |
| } |
| |
| while (tree != NULL) |
| { |
| treeCounter++; |
| |
| tree = tree->nextFree; |
| |
| if (treeCounter > TREE_POOL_SIZE) |
| { |
| break; |
| } |
| } |
| |
| while (node != NULL) |
| { |
| nodeCounter++; |
| |
| node = node->nextFree; |
| |
| if (nodeCounter > NODE_POOL_SIZE) |
| { |
| break; |
| } |
| } |
| |
| for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++) |
| { |
| int treeUsage = ixEthDBSearchTreeUsageGet(ixEthDBPortInfo[portIndex].updateMethod.searchTree); |
| |
| totalTreeUsage += treeUsage; |
| totalCloneDescriptorUsage += treeUsage; /* each tree node contains a descriptor */ |
| } |
| |
| totalNodeUsage = ixEthDBNumHashElements(); |
| totalDescriptorUsage += totalNodeUsage; /* each hash table entry contains a descriptor */ |
| |
| UNLOCK_NODE_POOL; |
| UNLOCK_MAC_POOL; |
| UNLOCK_TREE_POOL; |
| |
| printf("Ethernet database memory usage stats:\n\n"); |
| |
| if (macCounter <= MAC_POOL_SIZE) |
| { |
| printf("\tMAC descriptor pool : %d free out of %d entries (%d%%)\n", macCounter, MAC_POOL_SIZE, macCounter * 100 / MAC_POOL_SIZE); |
| } |
| else |
| { |
| printf("\tMAC descriptor pool : invalid state (ring within the pool), normally %d entries\n", MAC_POOL_SIZE); |
| } |
| |
| if (treeCounter <= TREE_POOL_SIZE) |
| { |
| printf("\tTree node pool : %d free out of %d entries (%d%%)\n", treeCounter, TREE_POOL_SIZE, treeCounter * 100 / TREE_POOL_SIZE); |
| } |
| else |
| { |
| printf("\tTREE descriptor pool : invalid state (ring within the pool), normally %d entries\n", TREE_POOL_SIZE); |
| } |
| |
| if (nodeCounter <= NODE_POOL_SIZE) |
| { |
| printf("\tHash node pool : %d free out of %d entries (%d%%)\n", nodeCounter, NODE_POOL_SIZE, nodeCounter * 100 / NODE_POOL_SIZE); |
| } |
| else |
| { |
| printf("\tNODE descriptor pool : invalid state (ring within the pool), normally %d entries\n", NODE_POOL_SIZE); |
| } |
| |
| printf("\n"); |
| printf("\tMAC descriptor usage : %d entries, %d cloned\n", totalDescriptorUsage, totalCloneDescriptorUsage); |
| printf("\tTree node usage : %d entries\n", totalTreeUsage); |
| printf("\tHash node usage : %d entries\n", totalNodeUsage); |
| printf("\n"); |
| |
| /* search for duplicate nodes in the mac pool */ |
| { |
| MacDescriptor *reference = macPool; |
| |
| while (reference != NULL) |
| { |
| MacDescriptor *comparison = reference->nextFree; |
| |
| while (comparison != NULL) |
| { |
| if (reference == comparison) |
| { |
| printf("Warning: reached a duplicate (%p), invalid MAC pool state\n", reference); |
| |
| return 1; |
| } |
| |
| comparison = comparison->nextFree; |
| } |
| |
| reference = reference->nextFree; |
| } |
| } |
| |
| printf("No duplicates found in the MAC pool (sanity check ok)\n"); |
| |
| return 0; |
| } |
| |
| #endif /* NDEBUG */ |
| |
| /** |
| * @} EthMemoryManagement |
| */ |