/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
net\ip\lookup\algo.c
Abstract:
Revision History:
--*/
DWORD g_dwBitMask = {0x00000001,
0x00000002,
0x00000004,
0x00000008,
0x00000010,
0x00000020,
0x00000040,
0x00000080,
0x00000100,
0x00000200,
0x00000400,
0x00000800,
0x00001000,
0x00002000,
0x00004000,
0x00008000,
0x00010000,
0x00020000,
0x00040000,
0x00080000,
0x00100000,
0x00200000,
0x00400000,
0x00800000,
0x01000000,
0x02000000,
0x04000000,
0x08000000,
0x10000000,
0x20000000,
0x40000000,
0x80000000};
DWORD g_dwPrefixMask = {0x00000001,
0x00000003,
0x00000007,
0x0000000F,
0x0000001F,
0x0000003F,
0x0000007F,
0x000000FF,
0x000001FF,
0x000003FF,
0x000007FF,
0x00000FFF,
0x00001FFF,
0x00003FFF,
0x00007FFF,
0x0000FFFF,
0x0001FFFF,
0x0003FFFF,
0x0007FFFF,
0x000FFFFF,
0x001FFFFF,
0x003FFFFF,
0x007FFFFF,
0x00FFFFFF,
0x01FFFFFF,
0x03FFFFFF,
0x07FFFFFF,
0x0FFFFFFF,
0x1FFFFFFF,
0x3FFFFFFF,
0x7FFFFFFF,
0xFFFFFFFF}
BYTE
DistPos(
IN PTRIE_KEY ptkKey1,
IN PTRIE_KEY ptkKey2
)
/*++
Routine Description
Returns the position of the distinguishing bit for two keys. This is
the first bit that differs between the two keys. If one key is a prefix
of another (strict or non strict), then the dist bit is 1+width of the smaller
key (== length of smaller key)
Notationally:
DistBit(K1, K2) = Min{i|K1[i] != K2[i]}
DistBit(K1, K2) = Length(K1) iff K1 is a prefix of K2
Arguments
Return Value
NO_ERROR
--*/
{
BYTE byLength;
byLength = MAX(Length(ptkKey1),
Length(ptkKey2));
for(i = 0; i < byLength; i++)
{
if(ptkKey1->dwAddr & g_dwBitMask[i] isnot
ptkKey2->dwAddr & g_dwBitMask[i])
{
break;
}
}
return i;
}
PTRIE_KEY
GetKey(
IN PTRIE_NODE ptnNode,
IN PTRIE_KEY ptkKey,
OUT PBYTE pbyPosition
)
/*++
Routine Description
Given a input key and node, returns the stored key in the node
whose index bit matches with the input key
Arguments
Return Value
NO_ERROR
--*/
{
if(Width(ptkKey) < Index(ptnNode))
{
return NULL;
}
*pbyPosition = GetRelevantBit(ptkKey->dwAddr, Index(ptnNode));
#if DBG
//
// A little consistency check here
//
if(LeftKey(ptnNode))
{
ASSERT(ptnNode->byPosition is LEFT);
}
if(RightKey(ptnNode))
{
ASSERT(ptnNode->byPosition is RIGHT);
}
#endif
return GetKeyByPosition(ptnNode,
*pbyPosition);
}
PTRIE_NODE
GetSubTrie(
IN PTRIE_NODE ptnNode,
IN PTRIE_KEY ptkKey,
OUT PBYTE pbyPosition
)
/*++
Routine Description
Locks
Arguments
Return Value
NO_ERROR
--*/
{
if(Width(ptkKey) < Index(ptnNode))
{
return NULL;
}
*pbyPosition = GetRelevantBit(ptkKey->dwAddr, Index(ptnNode));
#if DBG
//
// A little consistency check here
//
if(LeftSubTrie(ptnNode))
{
ASSERT(ptnNode->ptnTrie[LEFT]->byPosition is LEFT);
}
if(RightSubTrie(ptnNode))
{
ASSERT(ptnNode->ptnTrie[RIGHT]->byPosition is RIGHT);
}
#endif
return GetSubTrieByPosition(ptnNode,
*pbyPosition);
}
PTRIE_KEY
GetClosestKey(
PTRIE_NODE ptnNode,
PTRIE_KEY ptkKey
)
/*++
Routine Description
If the length of the key is greater than or equal to the index, return
any Key.
else
If a key with matching relevant bit is found, return that, else
return the other key
Locks
Arguments
Return Value
NO_ERROR
--*/
{
PTRIE_KEY ptkTemp;
BYTE byPos;
if(Width(ptkKey) >= Index(ptnNode))
{
ptkTemp = GetKey(ptnNode,
ptkKey,
&byPos);
if(ptkTemp isnot NULL)
{
return ptkTemp;
}
else
{
return GetKeyByPosition(ptnNode,
ComplementPosition(byPos))
}
}
else
{
//
// For now we return the left key first
//
ptkTemp = GetKeyByPosition(ptnNode,
LEFT);
if(ptkTemp)
{
return ptkTemp;
}
else
{
return GetKeyByPosition(ptnNode,
RIGHT);
}
}
}
PTRIE_NODE
GetClosestSubTrie(
PTRIE_NODE ptnNode,
PTRIE_KEY ptkKey
)
/*++
Routine Description
If the length of the key is greater than or equal to the index, return
any sub trie.
else
If a trie with matching relevant bit is found, return that, else
return the other trie
Locks
Arguments
Return Value
NO_ERROR
--*/
{
PTRIE_NODE ptnTemp;
BYTE byPos;
if(Width(ptkKey) >= Index(ptnNode))
{
ptnTemp = GetSubTrie(ptnNode,
ptkKey,
&byPos);
if(ptnTemp isnot NULL)
{
return ptnTemp;
}
else
{
return GetSubTrieByPosition(ptnNode,
ComplementPosition(byPos))
}
}
else
{
//
// For now we return the left trie first
//
ptkTemp = GetSubTrieByPosition(ptnNode,
LEFT);
if(ptkTemp)
{
return ptkTemp;
}
else
{
return GetSubTrieByPosition(ptnNode,
RIGHT);
}
}
}
PTRIE_NODE
CreateNode(
IN BYTE byIndex,
IN PTRIE_KEY ptkKey
)
/*++
Routine Description
Locks
Arguments
Return Value
NO_ERROR
--*/
{
PTRIE_NODE ptnNode;
ptnNode = HeapAlloc(g_hPrivateHeap,
0,
sizeof(TRIE_NODE));
if(ptnNode is NULL)
{
printf("Unable to allocate node. Error %d\n",
GetLastError());
return NULL;
}
ptnNode->ptnTrie[LEFT] = NULL;
ptnNode->ptnTrie[RIGHT] = NULL;
ptnNode->ptnParent = NULL;
ptnNode->byIndex = byIndex;
//
// See where the key would go into the allocated node
//
GetKey(ptnNode,
ptkKey,
&byPos);
//
// Since we are going to be inserting the key here, set
// its position field also
//
ptkKey->byPos = byPos;
ptnNode->rgptkKey[byPos] = ptkKey;
ptnNode->rgptkKey[ComplementPosition(byPos)] = NULL;
return ptnNode;
}
DWORD
InsertKey(
PTRIE_NODE *pptnRoot,
PTRIE_KEY ptkKey
)
/*++
Routine Description
Locks
Arguments
Return Value
NO_ERROR
--*/
{
PTRIE_NODE ptnTempNode;
if(*pptnRoot is NULL)
{
*pptnRoot = AllocateNode(Width(ptkKey),
ptkKey);
if(*pptnRoot is NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
return NO_ERROR;
}
ptnTempNode = *pptnRoot;
//
// Descend the tree, branching according to the Index bit
// Stop when the node is a leaf OR
// when the index is greater than the width of the key OR
// when the prefix of the node is not the same as the key
//
// The prefix is found by (ptkKey->dwAddr & g_dwPrefixMask[Index])
//
while(!IsLeafNode(ptnTempNode) and
(Width(ptkKey) > Index(ptnTempNode)) and
(ptnTempNode->rgptkKey[ptnTempNode->byNonNullKey] & g_dwPrefixMask[Index(ptnTempNode)] is
ptkKey[
{
ptnTempNode = ClosestSubTrie(ptnTempNode,
ptkKey);
}
byDistPost = DistPos(key,
ClosestKey(ptnNode,ptkKey));
byIndex = MIN(Lenght(Key), byDistPos);
if(ptnTempNode is *pptnRoot)
{
InsertInOrAbove(pptnRoot,
ptnTempNode,
ptkKey,
byDistPos);
}
else
{
if(GetSubTrie(ptnNode, ptkKey) is NULL)
{
InsertWithEmptySubTrie(ptnNode,
ptkKey,
byDistPos);
}
else
{
InsertWithNonEmptySubTrie(ptnNode,
ptkKey,
byDistPos);
}
}
return NO_ERROR;
}
DWORD
InsertInOrAbove(
PTRIE_NODE *pptnRoot,
PTRIE_NODE ptnNode,
PTRIE_KEY ptkKey,
BYTE byDistPos
)
/*++
Routine Description
Locks
Arguments
Return Value
NO_ERROR
--*/
{
if(