870 lines
23 KiB
C
870 lines
23 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1997-2000 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
ftrie.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains routines that manipulate
|
|||
|
an F-trie data stucture, that forms the fast
|
|||
|
path in a fast IP route lookup implementation.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Chaitanya Kodeboyina (chaitk) 26-Nov-1997
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "precomp.h"
|
|||
|
#include "ftrie.h"
|
|||
|
|
|||
|
UINT
|
|||
|
CALLCONV
|
|||
|
InitFTrie(IN FTrie * pFTrie,
|
|||
|
IN ULONG levels,
|
|||
|
IN ULONG maxMemory)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Initialises an F-trie. This should be done prior to
|
|||
|
any other trie operations.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pFTrie - Pointer to the trie to be initialized
|
|||
|
levels - Bitmap [ 32 bits ] of expanded levels
|
|||
|
maxMemory - Limit on memory taken by the F-Trie
|
|||
|
|
|||
|
For example, levels = 0xF0F0F0F0 [8,16,24,32 bits]
|
|||
|
means -> all prefixes are expanded to these levels
|
|||
|
and only these trie levels have any dests at all
|
|||
|
|
|||
|
Num of Levels + 2 memory accesses are needed in the
|
|||
|
worst case to get to the dest corresponding to a
|
|||
|
prefix - Num of Levels + 1 accesses including the
|
|||
|
zero level access, and 1 access to read the dest.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRIE_SUCCESS or ERROR_TRIE_*
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
UINT prevLevel;
|
|||
|
UINT currLevel;
|
|||
|
UINT nBytes, i;
|
|||
|
|
|||
|
TRY_BLOCK
|
|||
|
{
|
|||
|
if (levels == 0) {
|
|||
|
Error("NewFTrie: No levels specified", ERROR_TRIE_BAD_PARAM);
|
|||
|
}
|
|||
|
// Zero all the memory for the trie header
|
|||
|
RtlZeroMemory(pFTrie, sizeof(FTrie));
|
|||
|
|
|||
|
// Set a limit on the memory for trie/nodes
|
|||
|
pFTrie->availMemory = maxMemory;
|
|||
|
|
|||
|
// Initialize list of trienodes allocated
|
|||
|
InitializeListHead(&pFTrie->listofNodes);
|
|||
|
|
|||
|
// Initialize root node with a NULL dest
|
|||
|
pFTrie->trieRoot = StoreDestPtr(NULL);
|
|||
|
|
|||
|
// Initialize the number of bits in each level
|
|||
|
nBytes = (MAXLEVEL + 1) * sizeof(UINT);
|
|||
|
AllocMemory2(pFTrie->bitsInLevel,
|
|||
|
nBytes,
|
|||
|
pFTrie->availMemory);
|
|||
|
RtlZeroMemory(pFTrie->bitsInLevel, nBytes);
|
|||
|
|
|||
|
// Get the number of index bits at each level
|
|||
|
prevLevel = 0;
|
|||
|
i = 0;
|
|||
|
|
|||
|
for (currLevel = 1; currLevel <= MAXLEVEL; currLevel++) {
|
|||
|
if (levels & 1) {
|
|||
|
pFTrie->bitsInLevel[i++] = currLevel - prevLevel;
|
|||
|
|
|||
|
prevLevel = currLevel;
|
|||
|
}
|
|||
|
levels >>= 1;
|
|||
|
}
|
|||
|
|
|||
|
pFTrie->numLevels = i;
|
|||
|
|
|||
|
// Make sure that the last level is MAXLEVEL
|
|||
|
if (pFTrie->bitsInLevel[i] = MAXLEVEL - prevLevel) {
|
|||
|
pFTrie->numLevels++;
|
|||
|
}
|
|||
|
#if DBG
|
|||
|
Print("Num of levels: %d\n", pFTrie->numLevels);
|
|||
|
Print("Bits In Level:\n");
|
|||
|
for (i = 0; i < pFTrie->numLevels; i++) {
|
|||
|
Print("\t%d", pFTrie->bitsInLevel[i]);
|
|||
|
if (i % 8 == 7)
|
|||
|
Print("\n");
|
|||
|
}
|
|||
|
Print("\n\n");
|
|||
|
#endif
|
|||
|
|
|||
|
// Allocate and Zero all the statistics variables
|
|||
|
nBytes = (MAXLEVEL + 1) * sizeof(UINT);
|
|||
|
AllocMemory2(pFTrie->numDestsInOrigLevel,
|
|||
|
nBytes,
|
|||
|
pFTrie->availMemory);
|
|||
|
RtlZeroMemory(pFTrie->numDestsInOrigLevel, nBytes);
|
|||
|
|
|||
|
nBytes = pFTrie->numLevels * sizeof(UINT);
|
|||
|
AllocMemory2(pFTrie->numNodesInExpnLevel,
|
|||
|
nBytes,
|
|||
|
pFTrie->availMemory);
|
|||
|
RtlZeroMemory(pFTrie->numNodesInExpnLevel, nBytes);
|
|||
|
|
|||
|
nBytes = pFTrie->numLevels * sizeof(UINT);
|
|||
|
AllocMemory2(pFTrie->numDestsInExpnLevel,
|
|||
|
nBytes,
|
|||
|
pFTrie->availMemory);
|
|||
|
RtlZeroMemory(pFTrie->numDestsInExpnLevel, nBytes);
|
|||
|
|
|||
|
return TRIE_SUCCESS;
|
|||
|
}
|
|||
|
ERR_BLOCK
|
|||
|
{
|
|||
|
// Not enough resources to create an FTrie
|
|||
|
CleanupFTrie(pFTrie);
|
|||
|
}
|
|||
|
END_BLOCK
|
|||
|
}
|
|||
|
|
|||
|
UINT
|
|||
|
CALLCONV
|
|||
|
InsertIntoFTrie(IN FTrie * pFTrie,
|
|||
|
IN Route * pInsRoute,
|
|||
|
IN Dest * pInsDest,
|
|||
|
IN Dest * pOldDest)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Inserts a dest corresponding to an address
|
|||
|
prefix into a F-trie. It actually replaces
|
|||
|
all pointers to OldDest by that of InsDest.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pFTrie - Pointer to the F-Trie to insert into
|
|||
|
pInsRoute - Pointer to best route on new dest
|
|||
|
pInsDest - Pointer to the dest being inserted
|
|||
|
pOldDest - Pointer to the dest being replaced
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRIE_SUCCESS or ERROR_TRIE_*
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
FTrieNode **ppCurrNode;
|
|||
|
FTrieNode *pCurrNode;
|
|||
|
Dest *pBestDest;
|
|||
|
Dest *pComDest;
|
|||
|
UINT startIndex;
|
|||
|
UINT stopIndex;
|
|||
|
UINT nextIndex;
|
|||
|
UINT shiftIndex;
|
|||
|
UINT addrBits;
|
|||
|
UINT numBits;
|
|||
|
UINT bitsLeft;
|
|||
|
UINT i, j;
|
|||
|
|
|||
|
#if DBG
|
|||
|
// Make sure the trie is initialized
|
|||
|
if (!pFTrie || !pFTrie->trieRoot) {
|
|||
|
Fatal("Insert Dest: FTrie not initialized",
|
|||
|
ERROR_TRIE_NOT_INITED);
|
|||
|
}
|
|||
|
// Make sure input dest is valid
|
|||
|
|
|||
|
if (NULL_DEST(pInsDest)) {
|
|||
|
Fatal("Insert Dest: NULL or invalid dest",
|
|||
|
ERROR_TRIE_BAD_PARAM);
|
|||
|
}
|
|||
|
// Make sure input route is valid
|
|||
|
|
|||
|
if (NULL_ROUTE(pInsRoute)) {
|
|||
|
Fatal("Insert Dest: NULL or invalid route",
|
|||
|
ERROR_TRIE_BAD_PARAM);
|
|||
|
}
|
|||
|
if (LEN(pInsRoute) > ADDRSIZE) {
|
|||
|
Fatal("Insert Dest: Invalid mask length",
|
|||
|
ERROR_TRIE_BAD_PARAM);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
Assert(pInsDest != pOldDest);
|
|||
|
|
|||
|
// Use addr bits to index the trie
|
|||
|
addrBits = RtlConvertEndianLong(DEST(pInsRoute));
|
|||
|
bitsLeft = LEN(pInsRoute);
|
|||
|
|
|||
|
#if DBG
|
|||
|
// Make sure addr and mask agree
|
|||
|
if (ShowMostSigNBits(addrBits, bitsLeft) != addrBits) {
|
|||
|
Fatal("Insert Dest: Addr & mask don't agree",
|
|||
|
ERROR_TRIE_BAD_PARAM);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
TRY_BLOCK
|
|||
|
{
|
|||
|
// Special case: Default Prefix
|
|||
|
if (LEN(pInsRoute) == 0) {
|
|||
|
// Do we have a subtree in the trie's root node ?
|
|||
|
if (IsPtrADestPtr(pFTrie->trieRoot)) {
|
|||
|
// Make sure you are replacing right dest
|
|||
|
Assert(pFTrie->trieRoot == StoreDestPtr(pOldDest));
|
|||
|
|
|||
|
// Make the root to point to the new default
|
|||
|
pFTrie->trieRoot = StoreDestPtr(pInsDest);
|
|||
|
} else {
|
|||
|
// Make sure you are replacing right dest
|
|||
|
Assert(pFTrie->trieRoot->comDest == pOldDest);
|
|||
|
|
|||
|
// Make new dest the common subtrie dest
|
|||
|
pFTrie->trieRoot->comDest = pInsDest;
|
|||
|
}
|
|||
|
|
|||
|
return TRIE_SUCCESS;
|
|||
|
}
|
|||
|
// Start going down the trie using addr bits
|
|||
|
|
|||
|
pBestDest = NULL;
|
|||
|
|
|||
|
ppCurrNode = &pFTrie->trieRoot;
|
|||
|
|
|||
|
for (i = 0; /* NOTHING */ ; i++) {
|
|||
|
pCurrNode = *ppCurrNode;
|
|||
|
|
|||
|
if (IsPtrADestPtr(pCurrNode)) {
|
|||
|
// Creating a new subtree for the current level
|
|||
|
|
|||
|
// This pointer actually points to a dest node
|
|||
|
pComDest = RestoreDestPtr(pCurrNode);
|
|||
|
|
|||
|
// Create, initialize a new FTrie node (grow it)
|
|||
|
NewFTrieNode(pFTrie,
|
|||
|
pCurrNode,
|
|||
|
pFTrie->bitsInLevel[i],
|
|||
|
pComDest);
|
|||
|
|
|||
|
// Attach it to the FTrie
|
|||
|
*ppCurrNode = pCurrNode;
|
|||
|
|
|||
|
// Update FTrie Statistics
|
|||
|
pFTrie->numNodesInExpnLevel[i]++;
|
|||
|
}
|
|||
|
// Update the best dest seen so far - used later
|
|||
|
pComDest = pCurrNode->comDest;
|
|||
|
if (pComDest) {
|
|||
|
pBestDest = pComDest;
|
|||
|
}
|
|||
|
// Increment the number of dests in this subtrie
|
|||
|
pCurrNode->numDests++;
|
|||
|
|
|||
|
// Can I pass this level with remaining bits ?
|
|||
|
if (bitsLeft <= pFTrie->bitsInLevel[i]) {
|
|||
|
break;
|
|||
|
}
|
|||
|
// Get the next index from the IP addr
|
|||
|
numBits = pCurrNode->numBits;
|
|||
|
|
|||
|
nextIndex = PickMostSigNBits(addrBits, numBits);
|
|||
|
ppCurrNode = &pCurrNode->child[nextIndex];
|
|||
|
|
|||
|
// Throw away the used bits
|
|||
|
addrBits <<= numBits;
|
|||
|
bitsLeft -= numBits;
|
|||
|
}
|
|||
|
|
|||
|
// Update FTrie stats before expanding
|
|||
|
// Update if this isn't a dest change
|
|||
|
pFTrie->numDestsInExpnLevel[i]++;
|
|||
|
pFTrie->numDestsInOrigLevel[LEN(pInsRoute)]++;
|
|||
|
|
|||
|
// At this level, expand and add the dest
|
|||
|
nextIndex = PickMostSigNBits(addrBits, bitsLeft);
|
|||
|
shiftIndex = pFTrie->bitsInLevel[i] - bitsLeft;
|
|||
|
|
|||
|
startIndex = nextIndex << shiftIndex;
|
|||
|
stopIndex = (nextIndex + 1) << shiftIndex;
|
|||
|
|
|||
|
// Have you seen the old dest already ?
|
|||
|
if (pBestDest == pOldDest) {
|
|||
|
pOldDest = NULL;
|
|||
|
}
|
|||
|
// These dests cannot be the same here
|
|||
|
Assert(pInsDest != pOldDest);
|
|||
|
|
|||
|
// Fill the expanded range with the dest
|
|||
|
for (i = startIndex; i < stopIndex; i++) {
|
|||
|
if (IsPtrADestPtr(pCurrNode->child[i])) {
|
|||
|
// A dest pointer - replace with new one
|
|||
|
ReplaceDestPtr(StoreDestPtr(pInsDest),
|
|||
|
StoreDestPtr(pOldDest),
|
|||
|
&pCurrNode->child[i]);
|
|||
|
} else {
|
|||
|
// Node pointer - update subtree's dest
|
|||
|
ReplaceDestPtr(pInsDest,
|
|||
|
pOldDest,
|
|||
|
&pCurrNode->child[i]->comDest);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return TRIE_SUCCESS;
|
|||
|
}
|
|||
|
ERR_BLOCK
|
|||
|
{
|
|||
|
// Not enough resources - rollback to original state
|
|||
|
DeleteFromFTrie(pFTrie, pInsRoute, pInsDest, pOldDest, PARTIAL);
|
|||
|
}
|
|||
|
END_BLOCK
|
|||
|
}
|
|||
|
|
|||
|
UINT
|
|||
|
CALLCONV
|
|||
|
DeleteFromFTrie(IN FTrie * pFTrie,
|
|||
|
IN Route * pDelRoute,
|
|||
|
IN Dest * pDelDest,
|
|||
|
IN Dest * pNewDest,
|
|||
|
IN BOOLEAN trieState)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Deletes a dest corresponding to an address
|
|||
|
prefix from a F-trie. It actually replaces
|
|||
|
all pointers to DelDest by that of NewDest.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pFTrie - Pointer to the F-Trie to delete from
|
|||
|
pDelRoute - Pointer to last route on old dest
|
|||
|
pDelDest - Pointer to the dest being deleted
|
|||
|
pNewDest - Pointer to the dest replacing above
|
|||
|
trieState - NORMAL - deleting from a consistent FTrie
|
|||
|
PARTIAL - cleaning up an incomplete insert
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRIE_SUCCESS or ERROR_TRIE_*
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
FTrieNode **ppCurrNode;
|
|||
|
FTrieNode *pCurrNode;
|
|||
|
FTrieNode *pPrevNode;
|
|||
|
FTrieNode *pNextNode;
|
|||
|
Dest *pBestDest;
|
|||
|
Dest *pComDest;
|
|||
|
UINT startIndex;
|
|||
|
UINT stopIndex;
|
|||
|
UINT nextIndex;
|
|||
|
UINT shiftIndex;
|
|||
|
UINT addrBits;
|
|||
|
UINT numBits;
|
|||
|
UINT bitsLeft;
|
|||
|
UINT i, j;
|
|||
|
|
|||
|
#if DBG
|
|||
|
// Make sure the trie is initialized
|
|||
|
if (!pFTrie || !pFTrie->trieRoot) {
|
|||
|
Fatal("Delete Dest: FTrie not initialized",
|
|||
|
ERROR_TRIE_NOT_INITED);
|
|||
|
}
|
|||
|
// Make sure input dest is valid
|
|||
|
|
|||
|
if (NULL_DEST(pDelDest)) {
|
|||
|
Fatal("Delete Dest: NULL or invalid dest",
|
|||
|
ERROR_TRIE_BAD_PARAM);
|
|||
|
}
|
|||
|
// Make sure input route is valid
|
|||
|
|
|||
|
if (NULL_ROUTE(pDelRoute)) {
|
|||
|
Fatal("Delete Dest: NULL or invalid route",
|
|||
|
ERROR_TRIE_BAD_PARAM);
|
|||
|
}
|
|||
|
if (LEN(pDelRoute) > ADDRSIZE) {
|
|||
|
Fatal("Delete Dest: Invalid mask length",
|
|||
|
ERROR_TRIE_BAD_PARAM);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
// Use addr bits to index the trie
|
|||
|
addrBits = RtlConvertEndianLong(DEST(pDelRoute));
|
|||
|
bitsLeft = LEN(pDelRoute);
|
|||
|
|
|||
|
#if DBG
|
|||
|
// Make sure addr and mask agree
|
|||
|
if (ShowMostSigNBits(addrBits, bitsLeft) != addrBits) {
|
|||
|
Fatal("Delete Dest: Addr & mask don't agree",
|
|||
|
ERROR_TRIE_BAD_PARAM);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
Assert(pDelDest != pNewDest);
|
|||
|
|
|||
|
// Special case: Default Prefix
|
|||
|
if (LEN(pDelRoute) == 0) {
|
|||
|
// Do we have a subtree in the trie's root node ?
|
|||
|
if (IsPtrADestPtr(pFTrie->trieRoot)) {
|
|||
|
// Make sure you are replacing right dest
|
|||
|
Assert(pFTrie->trieRoot == StoreDestPtr(pDelDest));
|
|||
|
|
|||
|
// Make the root to point to the new default
|
|||
|
pFTrie->trieRoot = StoreDestPtr(pNewDest);
|
|||
|
} else {
|
|||
|
// Make sure you are replacing right dest
|
|||
|
Assert(pFTrie->trieRoot->comDest == pDelDest);
|
|||
|
|
|||
|
// Make new dest the common subtrie dest
|
|||
|
pFTrie->trieRoot->comDest = pNewDest;
|
|||
|
}
|
|||
|
|
|||
|
return TRIE_SUCCESS;
|
|||
|
}
|
|||
|
// Start going down the trie using addr bits
|
|||
|
|
|||
|
pBestDest = NULL;
|
|||
|
|
|||
|
ppCurrNode = &pFTrie->trieRoot;
|
|||
|
|
|||
|
pPrevNode = pCurrNode = *ppCurrNode;
|
|||
|
|
|||
|
for (i = 0; /* NOTHING */ ; i++) {
|
|||
|
// We still have bits left, so we go down the trie
|
|||
|
|
|||
|
// Do we have a valid subtree at the current node
|
|||
|
if (IsPtrADestPtr(pCurrNode)) {
|
|||
|
// We are cleaning a partial (failed) insert
|
|||
|
Assert(trieState == PARTIAL);
|
|||
|
|
|||
|
// We have cleaned up the trie - return now
|
|||
|
return TRIE_SUCCESS;
|
|||
|
}
|
|||
|
// We have a valid subtree, so we go down the trie
|
|||
|
|
|||
|
// Update the best dest seen so far - used later
|
|||
|
pComDest = pCurrNode->comDest;
|
|||
|
if (pComDest) {
|
|||
|
pBestDest = pComDest;
|
|||
|
}
|
|||
|
// Decrement the number of dests in this subtrie
|
|||
|
pCurrNode->numDests--;
|
|||
|
|
|||
|
// Is the number of dests in curr subtree zero ?
|
|||
|
if (pCurrNode->numDests == 0) {
|
|||
|
#if DBG
|
|||
|
int k = 0;
|
|||
|
|
|||
|
// Just make sure that only one dest exists
|
|||
|
for (j = 1; j < (UINT) 1 << pCurrNode->numBits; j++) {
|
|||
|
if (pCurrNode->child[j - 1] != pCurrNode->child[j]) {
|
|||
|
Assert((pCurrNode->child[j] == StoreDestPtr(NULL)) ||
|
|||
|
(pCurrNode->child[j - 1] == StoreDestPtr(NULL)));
|
|||
|
k++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (trieState == NORMAL) {
|
|||
|
if ((k != 1) && (k != 2)) {
|
|||
|
Print("k = %d\n", k);
|
|||
|
Assert(FALSE);
|
|||
|
}
|
|||
|
} else {
|
|||
|
if ((k != 0) && (k != 1) && (k != 2)) {
|
|||
|
Print("k = %d\n", k);
|
|||
|
Assert(FALSE);
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
// Remove link from its parent (if it exists)
|
|||
|
if (pPrevNode) {
|
|||
|
*ppCurrNode = StoreDestPtr(pCurrNode->comDest);
|
|||
|
}
|
|||
|
}
|
|||
|
// Can I pass this level with remaining bits ?
|
|||
|
if (bitsLeft <= pFTrie->bitsInLevel[i]) {
|
|||
|
break;
|
|||
|
}
|
|||
|
// Get the next index from the IP addr
|
|||
|
numBits = pCurrNode->numBits;
|
|||
|
|
|||
|
nextIndex = PickMostSigNBits(addrBits, numBits);
|
|||
|
ppCurrNode = &pCurrNode->child[nextIndex];
|
|||
|
|
|||
|
pNextNode = *ppCurrNode;
|
|||
|
|
|||
|
// Throw away the used bits
|
|||
|
addrBits <<= numBits;
|
|||
|
bitsLeft -= numBits;
|
|||
|
|
|||
|
// Is the number of dests in subtree zero ?
|
|||
|
if (pCurrNode->numDests == 0) {
|
|||
|
// Deallocate it (shrink FTrie)
|
|||
|
FreeFTrieNode(pFTrie, pCurrNode);
|
|||
|
|
|||
|
// Update FTrie Statistics
|
|||
|
pFTrie->numNodesInExpnLevel[i]--;
|
|||
|
}
|
|||
|
pPrevNode = pCurrNode;
|
|||
|
pCurrNode = pNextNode;
|
|||
|
}
|
|||
|
|
|||
|
// Update F-Trie stats before deleting
|
|||
|
pFTrie->numDestsInExpnLevel[i]--;
|
|||
|
pFTrie->numDestsInOrigLevel[LEN(pDelRoute)]--;
|
|||
|
|
|||
|
// Is the number of dests in curr subtree zero ?
|
|||
|
if (pCurrNode->numDests == 0) {
|
|||
|
// Deallocate it (shrink FTrie)
|
|||
|
FreeFTrieNode(pFTrie, pCurrNode);
|
|||
|
|
|||
|
// Update FTrie Statistics
|
|||
|
pFTrie->numNodesInExpnLevel[i]--;
|
|||
|
} else {
|
|||
|
// At this level, expand and add the dest
|
|||
|
nextIndex = PickMostSigNBits(addrBits, bitsLeft);
|
|||
|
shiftIndex = pFTrie->bitsInLevel[i] - bitsLeft;
|
|||
|
|
|||
|
startIndex = nextIndex << shiftIndex;
|
|||
|
stopIndex = (nextIndex + 1) << shiftIndex;
|
|||
|
|
|||
|
// Have you seen the new dest already ?
|
|||
|
if (pBestDest == pNewDest) {
|
|||
|
pNewDest = NULL;
|
|||
|
}
|
|||
|
// These dests cannot be the same here
|
|||
|
Assert(pDelDest != pNewDest);
|
|||
|
|
|||
|
// Fill the expanded range with the dest
|
|||
|
for (i = startIndex; i < stopIndex; i++) {
|
|||
|
if (IsPtrADestPtr(pCurrNode->child[i])) {
|
|||
|
// A dest pointer - replace with new one
|
|||
|
ReplaceDestPtr(StoreDestPtr(pNewDest),
|
|||
|
StoreDestPtr(pDelDest),
|
|||
|
&pCurrNode->child[i]);
|
|||
|
} else {
|
|||
|
// Node pointer - update subtree's dest
|
|||
|
ReplaceDestPtr(pNewDest,
|
|||
|
pDelDest,
|
|||
|
&pCurrNode->child[i]->comDest);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return TRIE_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
UINT
|
|||
|
CALLCONV
|
|||
|
SearchDestInFTrie(IN FTrie * pFTrie,
|
|||
|
IN Dest * pSerDest,
|
|||
|
OUT UINT * pNumPtrs,
|
|||
|
OUT Dest ** pStartPtr)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Search for a specific dest in an F-trie,
|
|||
|
returns the expanded range for the dest
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pFTrie - Pointer to the F-trie to search
|
|||
|
pSerDest - Pointer to dest being searched
|
|||
|
pStartPtr - Start of dest's expanded range
|
|||
|
pNumPtrs - Number of pointers in the range
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRIE_SUCCESS or ERROR_TRIE_*
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
return ERROR_TRIE_BAD_PARAM;
|
|||
|
}
|
|||
|
|
|||
|
Dest *
|
|||
|
CALLCONV
|
|||
|
SearchAddrInFTrie(IN FTrie * pFTrie,
|
|||
|
IN ULONG Addr)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Search for an address in an F-trie
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pFTrie - Pointer to the trie to search
|
|||
|
Addr - Pointer to addr being queried
|
|||
|
|
|||
|
Return Value:
|
|||
|
Return best dest match for this address
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
FTrieNode *pCurrNode;
|
|||
|
Dest *pBestDest;
|
|||
|
Dest *pDest;
|
|||
|
ULONG addrBits;
|
|||
|
UINT numBits;
|
|||
|
UINT nextIndex;
|
|||
|
|
|||
|
#if DBG
|
|||
|
if (!pFTrie || !pFTrie->trieRoot) {
|
|||
|
Fatal("Searching into an uninitialized FTrie",
|
|||
|
ERROR_TRIE_NOT_INITED);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
addrBits = RtlConvertEndianLong(Addr);
|
|||
|
|
|||
|
pBestDest = NULL;
|
|||
|
|
|||
|
pCurrNode = pFTrie->trieRoot;
|
|||
|
|
|||
|
do {
|
|||
|
// Have we reached the end of this search ?
|
|||
|
if (IsPtrADestPtr(pCurrNode)) {
|
|||
|
// Get the best matching dest until now
|
|||
|
pDest = RestoreDestPtr(pCurrNode);
|
|||
|
if (!NULL_DEST(pDest)) {
|
|||
|
pBestDest = pDest;
|
|||
|
}
|
|||
|
return pBestDest;
|
|||
|
} else {
|
|||
|
// Get the best matching dest until now
|
|||
|
pDest = pCurrNode->comDest;
|
|||
|
if (!NULL_DEST(pDest)) {
|
|||
|
pBestDest = pDest;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Number of bits to use in this FTrie level
|
|||
|
numBits = pCurrNode->numBits;
|
|||
|
|
|||
|
// Get the next index from IP address bits
|
|||
|
nextIndex = PickMostSigNBits(addrBits, numBits);
|
|||
|
|
|||
|
// And go down the tree with the new index
|
|||
|
pCurrNode = pCurrNode->child[nextIndex];
|
|||
|
|
|||
|
// Throw away the used bits for this iteration
|
|||
|
addrBits <<= numBits;
|
|||
|
}
|
|||
|
while (TRUE);
|
|||
|
}
|
|||
|
|
|||
|
UINT
|
|||
|
CALLCONV
|
|||
|
CleanupFTrie(IN FTrie * pFTrie)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Deletes an F-trie if it is empty
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ppFTrie - Ptr to the F-trie
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRIE_SUCCESS or ERROR_TRIE_*
|
|||
|
--*/
|
|||
|
{
|
|||
|
FTrieNode *pCurrNode;
|
|||
|
LIST_ENTRY *p;
|
|||
|
|
|||
|
// Free all trie nodes and corresponding memory
|
|||
|
while (!IsListEmpty(&pFTrie->listofNodes)) {
|
|||
|
p = RemoveHeadList(&pFTrie->listofNodes);
|
|||
|
pCurrNode = CONTAINING_RECORD(p, FTrieNode, linkage);
|
|||
|
FreeFTrieNode(pFTrie, pCurrNode);
|
|||
|
}
|
|||
|
|
|||
|
// Free the memory for the arr of levels
|
|||
|
if (pFTrie->bitsInLevel) {
|
|||
|
FreeMemory1(pFTrie->bitsInLevel,
|
|||
|
(MAXLEVEL + 1) * sizeof(UINT),
|
|||
|
pFTrie->availMemory);
|
|||
|
}
|
|||
|
// Free memory allocated for statistics
|
|||
|
if (pFTrie->numDestsInOrigLevel) {
|
|||
|
FreeMemory1(pFTrie->numDestsInOrigLevel,
|
|||
|
(MAXLEVEL + 1) * sizeof(UINT),
|
|||
|
pFTrie->availMemory);
|
|||
|
}
|
|||
|
if (pFTrie->numNodesInExpnLevel) {
|
|||
|
FreeMemory1(pFTrie->numNodesInExpnLevel,
|
|||
|
pFTrie->numLevels * sizeof(UINT),
|
|||
|
pFTrie->availMemory);
|
|||
|
}
|
|||
|
if (pFTrie->numDestsInExpnLevel) {
|
|||
|
FreeMemory1(pFTrie->numDestsInExpnLevel,
|
|||
|
pFTrie->numLevels * sizeof(UINT),
|
|||
|
pFTrie->availMemory);
|
|||
|
}
|
|||
|
// Reset other fields in trie structure
|
|||
|
pFTrie->trieRoot = NULL;
|
|||
|
pFTrie->numLevels = 0;
|
|||
|
|
|||
|
return TRIE_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
#if DBG
|
|||
|
|
|||
|
VOID
|
|||
|
CALLCONV
|
|||
|
PrintFTrie(IN FTrie * pFTrie,
|
|||
|
IN UINT printFlags)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Print an F-Trie
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pFTrie - Pointer to the F-Trie
|
|||
|
printFlags - Information to print
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
--*/
|
|||
|
{
|
|||
|
FTrieNode *pCurrNode;
|
|||
|
UINT i;
|
|||
|
|
|||
|
if (pFTrie == NULL) {
|
|||
|
Print("%s", "Uninitialized FTrie\n\n");
|
|||
|
return;
|
|||
|
}
|
|||
|
if ((printFlags & SUMM) == SUMM) {
|
|||
|
Print("\n\n/***Fast-Trie------------------------------------------------");
|
|||
|
Print("\n/***---------------------------------------------------------\n");
|
|||
|
}
|
|||
|
if (printFlags & POOL) {
|
|||
|
Print("Available Memory: %10lu\n\n", pFTrie->availMemory);
|
|||
|
}
|
|||
|
if (printFlags & STAT) {
|
|||
|
Print("Statistics:\n\n");
|
|||
|
|
|||
|
Print("Num of levels: %d\n", pFTrie->numLevels);
|
|||
|
Print("Bits In Level:\n");
|
|||
|
for (i = 0; i < pFTrie->numLevels; i++) {
|
|||
|
Print("\t%d", pFTrie->bitsInLevel[i]);
|
|||
|
if (i % 8 == 7)
|
|||
|
Print("\n");
|
|||
|
}
|
|||
|
Print("\n\n");
|
|||
|
|
|||
|
Print("Num of Nodes in Expanded Levels:\n");
|
|||
|
for (i = 0; i < pFTrie->numLevels; i++) {
|
|||
|
Print("\t%d", pFTrie->numNodesInExpnLevel[i]);
|
|||
|
if (i % 8 == 7)
|
|||
|
Print("\n");
|
|||
|
}
|
|||
|
Print("\n\n");
|
|||
|
|
|||
|
Print("Num of Dests in Original Levels:\n");
|
|||
|
for (i = 0; i < MAXLEVEL + 1; i++) {
|
|||
|
Print("\t%d", pFTrie->numDestsInOrigLevel[i]);
|
|||
|
if (i % 8 == 0)
|
|||
|
Print("\n");
|
|||
|
}
|
|||
|
Print("\n\n");
|
|||
|
|
|||
|
Print("Num of Dests in Expanded Levels:\n");
|
|||
|
for (i = 0; i < pFTrie->numLevels; i++) {
|
|||
|
Print("\t%d", pFTrie->numDestsInExpnLevel[i]);
|
|||
|
if (i % 8 == 7)
|
|||
|
Print("\n");
|
|||
|
}
|
|||
|
Print("\n\n");
|
|||
|
}
|
|||
|
if (printFlags & TRIE) {
|
|||
|
if (!IsPtrADestPtr(pFTrie->trieRoot)) {
|
|||
|
PrintFTrieNode(pFTrie->trieRoot, 0);
|
|||
|
} else {
|
|||
|
PrintDest(RestoreDestPtr(pFTrie->trieRoot));
|
|||
|
}
|
|||
|
}
|
|||
|
if ((printFlags & SUMM) == SUMM) {
|
|||
|
Print("\n---------------------------------------------------------***/\n");
|
|||
|
Print("---------------------------------------------------------***/\n\n");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
CALLCONV
|
|||
|
PrintFTrieNode(IN FTrieNode * pFTrieNode,
|
|||
|
IN UINT levelNumber)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Print an F-Trie node
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pFTrieNode - Pointer to the FTrie node
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
--*/
|
|||
|
{
|
|||
|
FTrieNode *pCurrNode;
|
|||
|
UINT numElmts;
|
|||
|
UINT i, j;
|
|||
|
|
|||
|
Print("\n/*-----------------------------------------------------------\n");
|
|||
|
Print("Num of bits at level %3d : %d\n", levelNumber, pFTrieNode->numBits);
|
|||
|
Print("Number of Subtrie Dests : %d\n", pFTrieNode->numDests);
|
|||
|
Print("Common SubTree Dest : ");
|
|||
|
PrintDest(pFTrieNode->comDest);
|
|||
|
Print("\n");
|
|||
|
|
|||
|
numElmts = 1 << pFTrieNode->numBits;
|
|||
|
pCurrNode = StoreDestPtr(NULL);
|
|||
|
|
|||
|
Print("Child Ptrs:\n\n");
|
|||
|
for (i = 0; i < numElmts; i++) {
|
|||
|
if (pFTrieNode->child[i] != pCurrNode) {
|
|||
|
pCurrNode = pFTrieNode->child[i];
|
|||
|
|
|||
|
Print("Child Index: %8lu ", i);
|
|||
|
|
|||
|
if (IsPtrADestPtr(pCurrNode)) {
|
|||
|
PrintDest(RestoreDestPtr(pCurrNode));
|
|||
|
} else {
|
|||
|
PrintFTrieNode(pCurrNode, levelNumber + 1);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
Print("-----------------------------------------------------------*/\n\n");
|
|||
|
}
|
|||
|
|
|||
|
#endif // DBG
|
|||
|
|
|||
|
|