ALGO.C

/*++ 

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(