/** * @brief adds a new entry to the Ethernet database * * @param newRecordTemplate address of the record template to use * @param updateTrigger port map containing the update triggers * resulting from this update operation * * Creates a new database entry, populates it with the data * copied from the given template and adds the record to the * database hash table. * It also checks whether the new record type is registered to trigger * automatic updates; if it is, the update trigger will contain the * port on which the record insertion was performed, as well as the * old port in case the addition was a record migration (from one port * to the other). The caller can use the updateTrigger to trigger * automatic updates on the ports changed as a result of this addition. * * @retval IX_ETH_DB_SUCCESS addition successful * @retval IX_ETH_DB_NOMEM insertion failed, no memory left in the mac descriptor memory pool * @retval IX_ETH_DB_BUSY database busy, cannot insert due to locking * * @internal */ IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBAdd(MacDescriptor *newRecordTemplate, IxEthDBPortMap updateTrigger) { IxEthDBStatus result; MacDescriptor *newDescriptor; IxEthDBPortId originalPortID; HashNode *node = NULL; BUSY_RETRY(ixEthDBSearchHashEntry(&dbHashtable, ixEthDBKeyType[newRecordTemplate->type], newRecordTemplate, &node)); TEST_FIXTURE_INCREMENT_DB_CORE_ACCESS_COUNTER; if (node == NULL) { /* not found, create a new one */ newDescriptor = ixEthDBAllocMacDescriptor(); if (newDescriptor == NULL) { return IX_ETH_DB_NOMEM; /* no memory */ } /* old port does not exist, avoid unnecessary updates */ originalPortID = newRecordTemplate->portID; } else { /* a node with the same key exists, will update node */ newDescriptor = (MacDescriptor *) node->data; /* save original port id */ originalPortID = newDescriptor->portID; } /* copy/update fields into new record */ memcpy(newDescriptor->macAddress, newRecordTemplate->macAddress, sizeof (IxEthDBMacAddr)); memcpy(&newDescriptor->recordData, &newRecordTemplate->recordData, sizeof (IxEthDBRecordData)); newDescriptor->type = newRecordTemplate->type; newDescriptor->portID = newRecordTemplate->portID; newDescriptor->user = newRecordTemplate->user; if (node == NULL) { /* new record, insert into hashtable */ BUSY_RETRY_WITH_RESULT(ixEthDBAddHashEntry(&dbHashtable, newDescriptor), result); if (result != IX_ETH_DB_SUCCESS) { ixEthDBFreeMacDescriptor(newDescriptor); return result; /* insertion failed */ } } if (node != NULL) { /* release access */ ixEthDBReleaseHashNode(node); } /* trigger add/remove update if required by type */ if (updateTrigger != NULL && ixEthDBPortUpdateRequired[newRecordTemplate->type]) { /* add new port to update list */ JOIN_PORT_TO_MAP(updateTrigger, newRecordTemplate->portID); /* check if record has moved, we'll need to update the old port as well */ if (originalPortID != newDescriptor->portID) { JOIN_PORT_TO_MAP(updateTrigger, originalPortID); } } return IX_ETH_DB_SUCCESS; }
/** * @brief inserts a mac descriptor into an tree * * @param searchTree tree where the insertion is to be performed (may be NULL) * @param descriptor descriptor to insert into tree * * @return the tree root * * @internal */ IX_ETH_DB_PRIVATE MacTreeNode* ixEthDBTreeInsert(MacTreeNode *searchTree, MacDescriptor *descriptor) { MacTreeNode *currentNode = searchTree; MacTreeNode *insertLocation = NULL; MacTreeNode *newNode; INT32 insertPosition = RIGHT; if (descriptor == NULL) { return searchTree; } /* create a new node */ newNode = ixEthDBAllocMacTreeNode(); if (newNode == NULL) { /* out of memory */ ERROR_LOG("Warning: ixEthDBAllocMacTreeNode returned NULL in file %s:%d (out of memory?)\n", __FILE__, __LINE__); ixEthDBFreeMacDescriptor(descriptor); return NULL; } /* populate node */ newNode->descriptor = descriptor; /* an empty initial tree is a special case */ if (searchTree == NULL) { return newNode; } /* get insertion location */ while (insertLocation == NULL) { MacTreeNode *nextNode; /* compare given key with current node key */ insertPosition = ixEthDBAddressCompare(descriptor->macAddress, currentNode->descriptor->macAddress); /* navigate down */ if (insertPosition == RIGHT) { nextNode = currentNode->right; } else if (insertPosition == LEFT) { nextNode = currentNode->left; } else { /* error, duplicate key */ ERROR_LOG("Warning: trapped insertion of a duplicate MAC address in an NPE search tree\n"); /* this will free the MAC descriptor as well */ ixEthDBFreeMacTreeNode(newNode); return searchTree; } /* when we can no longer dive through the tree we found the insertion place */ if (nextNode != NULL) { currentNode = nextNode; } else { insertLocation = currentNode; } } /* insert node */ if (insertPosition == RIGHT) { insertLocation->right = newNode; } else { insertLocation->left = newNode; } return searchTree; }