You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1506 lines
47 KiB
1506 lines
47 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
strie.c
|
|
|
|
Abstract:
|
|
|
|
This module contains routines that manipulate
|
|
an S-trie data stucture, that forms the slow
|
|
path in a fast IP route lookup implementation.
|
|
|
|
Author:
|
|
|
|
Chaitanya Kodeboyina (chaitk) 26-Nov-1997
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include "strie.h"
|
|
|
|
UINT
|
|
CALLCONV
|
|
InitSTrie(IN STrie * pSTrie,
|
|
IN ULONG maxMemory)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes an S-trie. This should be done prior
|
|
to any other trie operations.
|
|
|
|
Arguments:
|
|
|
|
pSTrie - Pointer to the trie to be initialized
|
|
maxMemory - Limit on memory taken by the S-Trie
|
|
|
|
Return Value:
|
|
|
|
TRIE_SUCCESS
|
|
|
|
--*/
|
|
{
|
|
// Zero all the memory for the trie header
|
|
RtlZeroMemory(pSTrie, sizeof(STrie));
|
|
|
|
// Set a limit on the memory for trie/nodes
|
|
pSTrie->availMemory = maxMemory;
|
|
|
|
return TRIE_SUCCESS;
|
|
}
|
|
|
|
UINT
|
|
CALLCONV
|
|
InsertIntoSTrie(IN STrie * pSTrie,
|
|
IN Route * pIncRoute,
|
|
IN ULONG matchFlags,
|
|
OUT Route ** ppInsRoute,
|
|
OUT Dest ** ppOldBestDest,
|
|
OUT Dest ** ppNewBestDest,
|
|
OUT Route ** ppOldBestRoute
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Inserts a route corresponding to an address
|
|
prefix into a S-trie, and fills in best
|
|
dest for addresses that match this prefix
|
|
both before and after insertion of route.
|
|
|
|
Arguments:
|
|
|
|
pSTrie - Pointer to trie to insert into
|
|
pIncRoute - Pointer to the incoming route
|
|
matchFlags - Flags to direct route matching
|
|
ppInsRoute - Pointer to the route inserted
|
|
ppOldBestDest - Best dest before insertion
|
|
ppNewBestDest - Best dest after insertion
|
|
ppOldBestRoute - Best route before insertion
|
|
|
|
Return Value:
|
|
|
|
TRIE_SUCCESS or ERROR_TRIE_*
|
|
--*/
|
|
{
|
|
STrieNode *pNewNode;
|
|
STrieNode *pPrevNode;
|
|
STrieNode *pCurrNode;
|
|
STrieNode *pOthNode;
|
|
Dest *pCurrDest;
|
|
Dest *pNewDest;
|
|
Dest *pBestDest;
|
|
Route *pNewRoute;
|
|
Route *pPrevRoute;
|
|
Route *pCurrRoute;
|
|
ULONG addrBits;
|
|
ULONG tempBits;
|
|
UINT nextBits;
|
|
UINT matchBits;
|
|
UINT bitsLeft;
|
|
UINT distPos;
|
|
UINT nextChild;
|
|
|
|
#if DBG
|
|
// Make sure the trie is initialized
|
|
if (!pSTrie) {
|
|
Fatal("Insert Route: STrie not initialized",
|
|
ERROR_TRIE_NOT_INITED);
|
|
}
|
|
#endif
|
|
|
|
// Make sure input route is valid
|
|
|
|
if (NULL_ROUTE(pIncRoute)) {
|
|
Error("Insert Route: NULL or invalid route",
|
|
ERROR_TRIE_BAD_PARAM);
|
|
}
|
|
if (LEN(pIncRoute) > ADDRSIZE) {
|
|
Error("Insert Route: Invalid mask length",
|
|
ERROR_TRIE_BAD_PARAM);
|
|
}
|
|
// Use addr bits to index the trie
|
|
addrBits = RtlConvertEndianLong(DEST(pIncRoute));
|
|
bitsLeft = LEN(pIncRoute);
|
|
|
|
// Make sure addr and mask agree
|
|
if (ShowMostSigNBits(addrBits, bitsLeft) != addrBits) {
|
|
Error("Insert Route: Addr & mask don't agree",
|
|
ERROR_TRIE_BAD_PARAM);
|
|
}
|
|
TRY_BLOCK
|
|
{
|
|
// Start going down the search trie
|
|
|
|
// Initialize any new allocations
|
|
pNewNode = NULL;
|
|
pOthNode = NULL;
|
|
pNewDest = NULL;
|
|
pNewRoute = NULL;
|
|
|
|
// Initialize other loop variables
|
|
pBestDest = NULL;
|
|
|
|
nextChild = 0;
|
|
pPrevNode = STRUCT_OF(STrieNode, &pSTrie->trieRoot, child[0]);
|
|
|
|
for (;;) {
|
|
// Start this loop by advancing to the next child
|
|
pCurrNode = pPrevNode->child[nextChild];
|
|
|
|
if (pCurrNode == NULL) {
|
|
// Case 1: Found a NULL - insert now
|
|
|
|
// Make a copy of the incoming route
|
|
NewRouteInSTrie(pSTrie, pNewRoute, pIncRoute);
|
|
|
|
// Allocate a dest with the new route
|
|
NewDestInSTrie(pSTrie, pNewRoute, pNewDest);
|
|
|
|
// New node with bits left unmatched
|
|
NewSTrieNode(pSTrie,
|
|
pNewNode,
|
|
bitsLeft,
|
|
addrBits,
|
|
pNewDest);
|
|
|
|
// Stick it as the correct child of node
|
|
pPrevNode->child[nextChild] = pNewNode;
|
|
|
|
break;
|
|
}
|
|
// Number of bits to match in this trie node
|
|
nextBits = pCurrNode->numBits;
|
|
|
|
matchBits = (nextBits > bitsLeft) ? bitsLeft : nextBits;
|
|
|
|
// Adjust next node bits for dist posn check
|
|
|
|
// Get distinguishing postion for bit patterns
|
|
distPos = PickDistPosition(pCurrNode->keyBits,
|
|
addrBits,
|
|
matchBits,
|
|
&tempBits);
|
|
|
|
if (distPos == nextBits) {
|
|
// Completely matches next node
|
|
|
|
if (distPos == bitsLeft) {
|
|
// We have exhausted all incoming bits
|
|
|
|
if (!NULL_DEST(pCurrNode->dest)) {
|
|
// Case 2: This trie node has a route
|
|
// Insert in sorted order of metric
|
|
|
|
pCurrDest = pCurrNode->dest;
|
|
|
|
// Give a ptr to the old best route
|
|
CopyRoutePtr(ppOldBestRoute, pCurrDest->firstRoute);
|
|
|
|
pPrevRoute = NULL;
|
|
pCurrRoute = pCurrDest->firstRoute;
|
|
|
|
// Search for an adequate match (IF, NHop)
|
|
do {
|
|
// Use the flags to control matching
|
|
if ((((matchFlags & MATCH_INTF) == 0) ||
|
|
(IF(pCurrRoute) == IF(pIncRoute))) &&
|
|
(((matchFlags & MATCH_NHOP) == 0) ||
|
|
(NHOP(pCurrRoute) == NHOP(pIncRoute))))
|
|
break;
|
|
|
|
pPrevRoute = pCurrRoute;
|
|
pCurrRoute = NEXT(pPrevRoute);
|
|
}
|
|
while (!NULL_ROUTE(pCurrRoute));
|
|
|
|
if (NULL_ROUTE(pCurrRoute)) {
|
|
// Case 2.1: No matching route
|
|
|
|
// Create a new copy of route
|
|
NewRouteInSTrie(pSTrie, pNewRoute, pIncRoute);
|
|
} else {
|
|
// Case 2.2: A Matching Route
|
|
|
|
// Has the metric changed ?
|
|
if (METRIC(pCurrRoute) != METRIC(pIncRoute)) {
|
|
// Remove route from current position
|
|
if (!NULL_ROUTE(pPrevRoute)) {
|
|
// Remove it from middle of list
|
|
NEXT(pPrevRoute) = NEXT(pCurrRoute);
|
|
} else {
|
|
// Remove from beginning of list
|
|
pCurrDest->firstRoute = NEXT(pCurrRoute);
|
|
}
|
|
}
|
|
// Keep the new/updated route for later
|
|
pNewRoute = pCurrRoute;
|
|
}
|
|
|
|
if (NULL_ROUTE(pCurrRoute) ||
|
|
(METRIC(pCurrRoute) != METRIC(pIncRoute))) {
|
|
// Update metric for new / changing route
|
|
METRIC(pNewRoute) = METRIC(pIncRoute);
|
|
|
|
// Traverse list looking for new position
|
|
pPrevRoute = NULL;
|
|
pCurrRoute = pCurrDest->firstRoute;
|
|
|
|
while (!NULL_ROUTE(pCurrRoute)) {
|
|
if (METRIC(pCurrRoute) > METRIC(pIncRoute))
|
|
break;
|
|
|
|
pPrevRoute = pCurrRoute;
|
|
pCurrRoute = NEXT(pPrevRoute);
|
|
}
|
|
|
|
// Insert at the new proper position
|
|
NEXT(pNewRoute) = pCurrRoute;
|
|
|
|
if (!NULL_ROUTE(pPrevRoute)) {
|
|
// Insert in the middle of list
|
|
NEXT(pPrevRoute) = pNewRoute;
|
|
} else {
|
|
// Insert at beginning of list
|
|
pCurrDest->firstRoute = pNewRoute;
|
|
}
|
|
}
|
|
// Give a ptr to newly inserted route
|
|
CopyRoutePtr(ppInsRoute, pNewRoute);
|
|
|
|
// Give a ptr to the old best dest
|
|
CopyDestPtr(ppOldBestDest, pCurrDest);
|
|
|
|
// Give a ptr to the new best dest
|
|
CopyDestPtr(ppNewBestDest, pCurrDest);
|
|
|
|
// Update the best routes cache on node
|
|
|
|
CacheBestRoutesInDest(pCurrDest);
|
|
|
|
return TRIE_SUCCESS;
|
|
} else {
|
|
// Case 3: This node was a marker
|
|
// Create a new route & attach it
|
|
|
|
// Create a new copy of this route
|
|
NewRouteInSTrie(pSTrie, pNewRoute, pIncRoute);
|
|
|
|
// Allocate a dest with the new route
|
|
NewDestInSTrie(pSTrie, pNewRoute, pNewDest);
|
|
|
|
// And attach dest to the marker node
|
|
pCurrNode->dest = pNewDest;
|
|
}
|
|
|
|
break;
|
|
} else {
|
|
// Case 4: We still have bits left here
|
|
// Go down for more specific match
|
|
|
|
// Update node with best dest so far
|
|
if (!NULL_DEST(pCurrNode->dest)) {
|
|
pBestDest = pCurrNode->dest;
|
|
}
|
|
// Discard used bits for this iteration
|
|
addrBits <<= matchBits;
|
|
bitsLeft -= matchBits;
|
|
|
|
// Prepare node for the next iteration
|
|
pPrevNode = pCurrNode;
|
|
|
|
// Bit 1 gives direction to search next
|
|
nextChild = PickMostSigNBits(addrBits, 1);
|
|
}
|
|
} else {
|
|
if (distPos == bitsLeft) {
|
|
// Case 5: The route falls on this branch
|
|
// Insert a new node in the same branch
|
|
|
|
// Make a copy of the new route
|
|
NewRouteInSTrie(pSTrie, pNewRoute, pIncRoute);
|
|
|
|
// Allocate a dest with the new route
|
|
NewDestInSTrie(pSTrie, pNewRoute, pNewDest);
|
|
|
|
// New node with bits left unmatched
|
|
NewSTrieNode(pSTrie,
|
|
pNewNode,
|
|
distPos,
|
|
ShowMostSigNBits(addrBits, distPos),
|
|
pNewDest);
|
|
|
|
pPrevNode->child[nextChild] = pNewNode;
|
|
|
|
// Adjust the next node - numbits etc
|
|
pCurrNode->keyBits <<= distPos,
|
|
pCurrNode->numBits -= distPos;
|
|
|
|
// Stick next node in the correct child
|
|
nextChild = PickMostSigNBits(pCurrNode->keyBits, 1);
|
|
|
|
pNewNode->child[nextChild] = pCurrNode;
|
|
|
|
break;
|
|
} else {
|
|
// Case 6: The route fragments the path
|
|
// Create a new branch with two nodes
|
|
|
|
// First make a copy of the new route
|
|
NewRouteInSTrie(pSTrie, pNewRoute, pIncRoute);
|
|
|
|
// Allocate a dest with the new route
|
|
NewDestInSTrie(pSTrie, pNewRoute, pNewDest);
|
|
|
|
// Branch node with non distinguishing bits
|
|
NewSTrieNode(pSTrie,
|
|
pOthNode,
|
|
distPos,
|
|
ShowMostSigNBits(addrBits, distPos),
|
|
NULL);
|
|
|
|
// A Leaf node with the distinguishing bits
|
|
bitsLeft -= distPos;
|
|
addrBits <<= distPos;
|
|
|
|
NewSTrieNode(pSTrie,
|
|
pNewNode,
|
|
bitsLeft,
|
|
addrBits,
|
|
pNewDest);
|
|
|
|
// Stick new branch node into the trie
|
|
pPrevNode->child[nextChild] = pOthNode;
|
|
|
|
// Set the children of the branch node
|
|
|
|
// Adjust the next node - numbits etc
|
|
pCurrNode->keyBits <<= distPos,
|
|
pCurrNode->numBits -= distPos;
|
|
|
|
// Stick next node in the correct child
|
|
nextChild = PickMostSigNBits(pCurrNode->keyBits, 1);
|
|
|
|
pOthNode->child[nextChild] = pCurrNode;
|
|
|
|
// Stick new leaf node as the other child
|
|
pOthNode->child[1 - nextChild] = pNewNode;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Give a ptr to the inserted route
|
|
CopyRoutePtr(ppInsRoute, pNewRoute);
|
|
|
|
// Give a ptr to the old best dest
|
|
CopyDestPtr(ppOldBestDest, pBestDest);
|
|
|
|
// Give a ptr to the old best route
|
|
if (!NULL_DEST(pBestDest)) {
|
|
CopyRoutePtr(ppOldBestRoute, pBestDest->firstRoute);
|
|
}
|
|
// Give a ptr to the new best dest
|
|
CopyDestPtr(ppNewBestDest, pNewDest);
|
|
|
|
// Route is the only route on dest
|
|
|
|
if (pNewDest->maxBestRoutes > 0) {
|
|
pNewDest->numBestRoutes = 1;
|
|
pNewDest->bestRoutes[0] = pNewRoute;
|
|
}
|
|
|
|
return TRIE_SUCCESS;
|
|
}
|
|
ERR_BLOCK
|
|
{
|
|
// Not enough RESOURCES to add a new route
|
|
|
|
// Free the memory for the new route alloc
|
|
if (pNewRoute) {
|
|
FreeRouteInSTrie(pSTrie, pNewRoute);
|
|
}
|
|
// Free memory for the dest on the new node
|
|
if (pNewDest) {
|
|
FreeDestInSTrie(pSTrie, pNewDest);
|
|
}
|
|
// Free the memory for the new tnode alloc
|
|
if (pNewNode) {
|
|
FreeSTrieNode(pSTrie, pNewNode);
|
|
}
|
|
// Free memory for any other new tnode alloc
|
|
if (pOthNode) {
|
|
FreeSTrieNode(pSTrie, pOthNode);
|
|
}
|
|
}
|
|
END_BLOCK
|
|
}
|
|
|
|
UINT
|
|
CALLCONV
|
|
DeleteFromSTrie(IN STrie * pSTrie,
|
|
IN Route * pIncRoute,
|
|
IN ULONG matchFlags,
|
|
OUT Route ** ppDelRoute,
|
|
OUT Dest ** ppOldBestDest,
|
|
OUT Dest ** ppNewBestDest,
|
|
OUT Route ** ppOldBestRoute
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deletes a route corresponding to an address
|
|
prefix into a S-trie, and fills in best
|
|
dest for addresses that match this prefix
|
|
both before and after deletion of route.
|
|
|
|
Arguments:
|
|
|
|
pSTrie - Pointer to trie to delete from
|
|
pIncRoute - Pointer to the incoming route
|
|
matchFlags - Flags to direct route matching
|
|
ppDelRoute - Pointer to the route deleted
|
|
ppOldBestDest - Best dest before deletion
|
|
ppNewBestDest - Best dest after deletion
|
|
ppOldBestRoute - Best route before deletion
|
|
|
|
Return Value:
|
|
|
|
TRIE_SUCCESS or ERROR_TRIE_*
|
|
--*/
|
|
{
|
|
STrieNode *pPrevNode;
|
|
STrieNode *pCurrNode;
|
|
STrieNode *pNextNode;
|
|
STrieNode *pOtherNode;
|
|
Dest *pBestDest;
|
|
Dest *pCurrDest;
|
|
Route *pPrevRoute;
|
|
Route *pCurrRoute;
|
|
ULONG addrBits;
|
|
ULONG tempBits;
|
|
UINT nextBits;
|
|
UINT matchBits;
|
|
UINT bitsLeft;
|
|
UINT distPos;
|
|
UINT nextChild;
|
|
|
|
#if DBG
|
|
if (!pSTrie) {
|
|
Fatal("Delete Route: STrie not initialized",
|
|
ERROR_TRIE_NOT_INITED);
|
|
}
|
|
#endif
|
|
|
|
// Make sure input route is valid
|
|
|
|
if (NULL_ROUTE(pIncRoute)) {
|
|
Error("Delete Route: NULL or invalid route",
|
|
ERROR_TRIE_BAD_PARAM);
|
|
}
|
|
if (LEN(pIncRoute) > ADDRSIZE) {
|
|
Error("Delete Route: Invalid mask length",
|
|
ERROR_TRIE_BAD_PARAM);
|
|
}
|
|
// Use addr bits to index the trie
|
|
addrBits = RtlConvertEndianLong(DEST(pIncRoute));
|
|
bitsLeft = LEN(pIncRoute);
|
|
|
|
// Make sure addr and mask agree
|
|
if (ShowMostSigNBits(addrBits, bitsLeft) != addrBits) {
|
|
Error("Delete Route: Addr & mask don't agree",
|
|
ERROR_TRIE_BAD_PARAM);
|
|
}
|
|
// Start going down the search trie
|
|
|
|
pBestDest = NULL;
|
|
|
|
nextChild = 0;
|
|
pPrevNode = STRUCT_OF(STrieNode, &pSTrie->trieRoot, child[0]);
|
|
|
|
for (;;) {
|
|
// Start this loop by advancing to the next child
|
|
pCurrNode = pPrevNode->child[nextChild];
|
|
|
|
if (pCurrNode == NULL) {
|
|
// Case 1: Found a NULL, end search
|
|
// Route not found, return an error
|
|
|
|
Error("Delete Route #0: Route not found",
|
|
ERROR_TRIE_NO_ROUTES);
|
|
}
|
|
// Number of bits to match in this trie node
|
|
nextBits = pCurrNode->numBits;
|
|
|
|
matchBits = (nextBits > bitsLeft) ? bitsLeft : nextBits;
|
|
|
|
// Adjust next node bits for dist posn check
|
|
|
|
// Get distinguishing postion for bit patterns
|
|
distPos = PickDistPosition(pCurrNode->keyBits,
|
|
addrBits,
|
|
matchBits,
|
|
&tempBits);
|
|
|
|
if (distPos == nextBits) {
|
|
// Completely matches next node
|
|
|
|
if (distPos == bitsLeft) {
|
|
// We have exhausted all incoming bits
|
|
// End search, see if we found a route
|
|
|
|
if (!NULL_DEST(pCurrNode->dest)) {
|
|
pCurrDest = pCurrNode->dest;
|
|
|
|
// This node starts a valid route list
|
|
|
|
// Give a ptr to the old best dest
|
|
CopyDestPtr(ppOldBestDest, pCurrDest);
|
|
|
|
// Give a ptr to the old best route
|
|
CopyRoutePtr(ppOldBestRoute, pCurrDest->firstRoute);
|
|
|
|
// Give a ptr to the new best dest
|
|
CopyDestPtr(ppNewBestDest, pCurrDest);
|
|
|
|
// Match the rest by walking the list
|
|
// sorted increasing order of metric
|
|
|
|
pPrevRoute = NULL;
|
|
pCurrRoute = pCurrDest->firstRoute;
|
|
|
|
do {
|
|
// Use the flags to control matching
|
|
// N.B. Note that certain clients are not allowed
|
|
// to delete local routes.
|
|
if ((((matchFlags & MATCH_INTF) == 0) ||
|
|
(IF(pCurrRoute) == IF(pIncRoute))) &&
|
|
(((matchFlags & MATCH_NHOP) == 0) ||
|
|
(NHOP(pCurrRoute) == NHOP(pIncRoute))) &&
|
|
(((matchFlags & MATCH_EXCLUDE_LOCAL) == 0) ||
|
|
(PROTO(pCurrRoute) != IRE_PROTO_LOCAL))) {
|
|
// Case 2: Found an adequate match
|
|
//* Do the actual deletion here *
|
|
|
|
if (!NULL_ROUTE(pPrevRoute)) {
|
|
// Delete from middle of the list
|
|
NEXT(pPrevRoute) = NEXT(pCurrRoute);
|
|
} else {
|
|
// Delete from beginning of list
|
|
pCurrDest->firstRoute = NEXT(pCurrRoute);
|
|
}
|
|
|
|
break;
|
|
}
|
|
pPrevRoute = pCurrRoute;
|
|
pCurrRoute = NEXT(pPrevRoute);
|
|
}
|
|
while (!NULL_ROUTE(pCurrRoute));
|
|
|
|
if (NULL_ROUTE(pCurrRoute)) {
|
|
// Route not found, return an error
|
|
Error("Delete Route #1: Route not found",
|
|
ERROR_TRIE_NO_ROUTES);
|
|
}
|
|
// Give a ptr to newly deleted route
|
|
CopyRoutePtr(ppDelRoute, pCurrRoute);
|
|
|
|
// Did the list become empty after deletion ?
|
|
if (NULL_ROUTE(pCurrDest->firstRoute)) {
|
|
// List is empty, so garbage collection
|
|
|
|
// Give a ptr to the new best dest
|
|
CopyDestPtr(ppNewBestDest, pBestDest);
|
|
|
|
// Free destination as all routes gone
|
|
FreeDestInSTrie(pSTrie, pCurrNode->dest);
|
|
|
|
if (pCurrNode->child[0] && pCurrNode->child[1]) {
|
|
// Case 3: Both children are non NULL
|
|
// Just remove route from the node
|
|
|
|
// Route already removed from node
|
|
} else if (pCurrNode->child[0] || pCurrNode->child[1]) {
|
|
// Case 4: One of the children is not NULL
|
|
// Pull up lonely child in place of node
|
|
|
|
// Pick the correct child to pull up
|
|
if (pCurrNode->child[0])
|
|
pNextNode = pCurrNode->child[0];
|
|
else
|
|
pNextNode = pCurrNode->child[1];
|
|
|
|
// Child node bears bits of deleted node
|
|
pNextNode->keyBits >>= pCurrNode->numBits;
|
|
pNextNode->keyBits |= pCurrNode->keyBits;
|
|
pNextNode->numBits += pCurrNode->numBits;
|
|
|
|
pPrevNode->child[nextChild] = pNextNode;
|
|
|
|
// Destroy trie node marked for deletion
|
|
FreeSTrieNode(pSTrie, pCurrNode);
|
|
} else {
|
|
// Node to be deleted has no children
|
|
|
|
if (&pPrevNode->child[nextChild] == &pSTrie->trieRoot) {
|
|
// Case 5: Root node is being deleted
|
|
// Detach node from trie root & delete
|
|
|
|
// Just detach by removing the pointer
|
|
pPrevNode->child[nextChild] = NULL;
|
|
|
|
// Destroy trie node marked for deletion
|
|
FreeSTrieNode(pSTrie, pCurrNode);
|
|
} else {
|
|
if (!NULL_DEST(pPrevNode->dest)) {
|
|
// Case 6: Parent has a route on it
|
|
// Detach child from parent & delete
|
|
|
|
// Just detach by removing the pointer
|
|
pPrevNode->child[nextChild] = NULL;
|
|
|
|
// Destroy trie node marked for deletion
|
|
FreeSTrieNode(pSTrie, pCurrNode);
|
|
} else {
|
|
// Case 7: Parent has no route on it
|
|
// Pull up other child of parent node
|
|
|
|
pOtherNode = pPrevNode->child[1 - nextChild];
|
|
|
|
// Make sure no 1-way branching
|
|
Assert(pOtherNode != NULL);
|
|
|
|
// Parent node bears bits of sibling node
|
|
pPrevNode->keyBits |=
|
|
(pOtherNode->keyBits >>
|
|
pPrevNode->numBits);
|
|
pPrevNode->numBits += pOtherNode->numBits;
|
|
|
|
// Move the route up too - move content
|
|
pPrevNode->dest = pOtherNode->dest;
|
|
|
|
pPrevNode->child[0] = pOtherNode->child[0];
|
|
pPrevNode->child[1] = pOtherNode->child[1];
|
|
|
|
FreeSTrieNode(pSTrie, pCurrNode);
|
|
FreeSTrieNode(pSTrie, pOtherNode);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// We still have some routes on the dest
|
|
// Update the best routes cache on node
|
|
|
|
CacheBestRoutesInDest(pCurrDest);
|
|
}
|
|
|
|
// Consider route as deleted at this point
|
|
// FreeRouteInSTrie(pSTrie, pCurrRoute);
|
|
|
|
break;
|
|
} else {
|
|
// Case 7: This node was a marker
|
|
// No Route to delete in this node
|
|
Error("Delete Route #2: Route not found",
|
|
ERROR_TRIE_NO_ROUTES);
|
|
}
|
|
} else {
|
|
// Case 8: We still have bits left here
|
|
// Go down for more specific match
|
|
|
|
// Update best value of route so far
|
|
if (!NULL_DEST(pCurrNode->dest)) {
|
|
pBestDest = pCurrNode->dest;
|
|
}
|
|
// Discard used bits for this iteration
|
|
addrBits <<= matchBits;
|
|
bitsLeft -= matchBits;
|
|
|
|
// Prepare node for the next iteration
|
|
pPrevNode = pCurrNode;
|
|
|
|
// Bit 1 gives direction to search next
|
|
nextChild = PickMostSigNBits(addrBits, 1);
|
|
}
|
|
} else {
|
|
// Case 9: Did not match the next node
|
|
// Route not found, fill next best
|
|
Error("Delete Route #3: Route not found",
|
|
ERROR_TRIE_NO_ROUTES);
|
|
}
|
|
}
|
|
|
|
|
|
return TRIE_SUCCESS;
|
|
}
|
|
|
|
UINT
|
|
CALLCONV
|
|
SearchRouteInSTrie(IN STrie * pSTrie,
|
|
IN ULONG routeDest,
|
|
IN ULONG routeMask,
|
|
IN ULONG routeNHop,
|
|
IN PVOID routeOutIF,
|
|
IN ULONG matchFlags,
|
|
OUT Route ** ppOutRoute)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Search for a specific route in an S-trie
|
|
|
|
Arguments:
|
|
|
|
pSTrie - Pointer to the S-trie to search
|
|
routeDest - Dest of route being looked up
|
|
routeMask - Mask of route being looked up
|
|
routeNHop - NHop of route being looked up
|
|
routeOutIF - Outgoing IF for this route
|
|
matchFlags - Flags to direct route matching
|
|
ppOutRoute - To return the best route match
|
|
|
|
Return Value:
|
|
|
|
TRIE_SUCCESS or ERROR_TRIE_*
|
|
|
|
--*/
|
|
{
|
|
STrieNode *pPrevNode;
|
|
STrieNode *pCurrNode;
|
|
Dest *pCurrDest;
|
|
Dest *pBestDest;
|
|
Route *pPrevRoute;
|
|
Route *pCurrRoute;
|
|
ULONG addrBits;
|
|
ULONG tempBits;
|
|
UINT nextBits;
|
|
UINT matchBits;
|
|
UINT bitsLeft;
|
|
UINT distPos;
|
|
UINT nextChild;
|
|
|
|
#if DBG
|
|
if (!pSTrie) {
|
|
Fatal("Search Route: STrie not initialized",
|
|
ERROR_TRIE_NOT_INITED);
|
|
}
|
|
#endif
|
|
|
|
*ppOutRoute = NULL;
|
|
|
|
// Use addr bits to index the trie
|
|
addrBits = RtlConvertEndianLong(routeDest);
|
|
|
|
//* Assume an contiguous IP mask *
|
|
tempBits = RtlConvertEndianLong(routeMask);
|
|
|
|
bitsLeft = 0;
|
|
while (tempBits != 0) {
|
|
bitsLeft++;
|
|
tempBits <<= 1;
|
|
}
|
|
|
|
// Make sure addr and mask agree
|
|
if (ShowMostSigNBits(addrBits, bitsLeft) != addrBits) {
|
|
Error("Search Route: Addr & mask don't agree",
|
|
ERROR_TRIE_BAD_PARAM);
|
|
}
|
|
// Start going down the search trie
|
|
|
|
pBestDest = NULL;
|
|
|
|
nextChild = 0;
|
|
pPrevNode = STRUCT_OF(STrieNode, &pSTrie->trieRoot, child[0]);
|
|
|
|
for (;;) {
|
|
// Start this loop by advancing to the next child
|
|
pCurrNode = pPrevNode->child[nextChild];
|
|
|
|
if (pCurrNode == NULL) {
|
|
// Case 1: Found a NULL, end search
|
|
// Route not found, fill next best
|
|
|
|
// Give a copy of the next best route
|
|
if (!NULL_DEST(pBestDest)) {
|
|
CopyRoutePtr(ppOutRoute, pBestDest->firstRoute);
|
|
}
|
|
Error("Search Route #0: Route not found",
|
|
ERROR_TRIE_NO_ROUTES);
|
|
}
|
|
// Number of bits to match in this trie node
|
|
nextBits = pCurrNode->numBits;
|
|
|
|
matchBits = (nextBits > bitsLeft) ? bitsLeft : nextBits;
|
|
|
|
// Adjust next node bits for dist posn check
|
|
|
|
// Get distinguishing postion for bit patterns
|
|
distPos = PickDistPosition(pCurrNode->keyBits,
|
|
addrBits,
|
|
matchBits,
|
|
&tempBits);
|
|
|
|
if (distPos == nextBits) {
|
|
// Completely matches next node
|
|
|
|
if (distPos == bitsLeft) {
|
|
// We have exhausted all incoming bits
|
|
// End search, see if we found a route
|
|
|
|
if (!NULL_DEST(pCurrNode->dest)) {
|
|
// This node starts a valid route list
|
|
|
|
pCurrDest = pCurrNode->dest;
|
|
|
|
// Match the rest by walking the list
|
|
// sorted increasing order of metric
|
|
|
|
pPrevRoute = NULL;
|
|
pCurrRoute = pCurrDest->firstRoute;
|
|
|
|
do {
|
|
// Use the flags to control matching
|
|
if ((((matchFlags & MATCH_INTF) == 0) ||
|
|
(IF(pCurrRoute) == routeOutIF)) &&
|
|
(((matchFlags & MATCH_NHOP) == 0) ||
|
|
(NHOP(pCurrRoute) == routeNHop))) {
|
|
// Found adequately matched route
|
|
// Just copy the route and return
|
|
CopyRoutePtr(ppOutRoute, pCurrRoute);
|
|
return TRIE_SUCCESS;
|
|
}
|
|
pPrevRoute = pCurrRoute;
|
|
pCurrRoute = NEXT(pPrevRoute);
|
|
}
|
|
while (!NULL_ROUTE(pCurrRoute));
|
|
|
|
// Give a copy of the old route, or best route
|
|
// for that prefix in case of no exact match
|
|
|
|
if (NULL_ROUTE(pCurrRoute)) {
|
|
CopyRoutePtr(ppOutRoute, pCurrDest->firstRoute);
|
|
|
|
Error("Search Route #1: Route not found",
|
|
ERROR_TRIE_NO_ROUTES);
|
|
}
|
|
break;
|
|
} else {
|
|
// Case 7: This node was a marker
|
|
// No Route present in this node
|
|
|
|
// Give a copy of the next best route
|
|
if (!NULL_DEST(pBestDest)) {
|
|
CopyRoutePtr(ppOutRoute, pBestDest->firstRoute);
|
|
}
|
|
Error("Search Route #2: Route not found",
|
|
ERROR_TRIE_NO_ROUTES);
|
|
}
|
|
} else {
|
|
// Case 8: We still have bits left here
|
|
// Go down for more specific match
|
|
|
|
// Update node with best dest so far
|
|
if (!NULL_DEST(pCurrNode->dest)) {
|
|
pBestDest = pCurrNode->dest;
|
|
}
|
|
// Discard used bits for this iteration
|
|
addrBits <<= matchBits;
|
|
bitsLeft -= matchBits;
|
|
|
|
// Prepare node for the next iteration
|
|
pPrevNode = pCurrNode;
|
|
|
|
// Bit 1 gives direction to search next
|
|
nextChild = PickMostSigNBits(addrBits, 1);
|
|
}
|
|
} else {
|
|
// Case 9: Did not match the next node
|
|
// Route not found, fill the next best
|
|
|
|
// Give a copy of the next best route
|
|
if (!NULL_DEST(pBestDest)) {
|
|
CopyRoutePtr(ppOutRoute, pBestDest->firstRoute);
|
|
}
|
|
Error("Search Route #3: Route not found",
|
|
ERROR_TRIE_NO_ROUTES);
|
|
}
|
|
}
|
|
|
|
return TRIE_SUCCESS;
|
|
}
|
|
|
|
Dest *
|
|
CALLCONV
|
|
SearchAddrInSTrie(IN STrie * pSTrie,
|
|
IN ULONG Addr)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Search for an address in an S-trie
|
|
|
|
Arguments:
|
|
|
|
pSTrie - Pointer to the trie to search
|
|
Addr - Pointer to addr being queried
|
|
|
|
Return Value:
|
|
Return best route match for this address
|
|
|
|
--*/
|
|
{
|
|
STrieNode *pCurrNode;
|
|
Dest *pBestDest;
|
|
UINT nextChild;
|
|
ULONG addrBits;
|
|
ULONG keyMask;
|
|
ULONG keyBits;
|
|
|
|
#if DBG
|
|
if (!pSTrie) {
|
|
Fatal("Search Addr: STrie not initialized",
|
|
ERROR_TRIE_NOT_INITED);
|
|
}
|
|
#endif
|
|
|
|
addrBits = RtlConvertEndianLong(Addr);
|
|
|
|
// Start going down the search trie
|
|
|
|
pBestDest = NULL;
|
|
|
|
nextChild = 0;
|
|
pCurrNode = STRUCT_OF(STrieNode, &pSTrie->trieRoot, child[0]);
|
|
|
|
for (;;) {
|
|
// Start this loop by advancing to next child
|
|
pCurrNode = pCurrNode->child[nextChild];
|
|
|
|
if (pCurrNode == NULL) {
|
|
// Case 1: Found a NULL, end search
|
|
break;
|
|
}
|
|
// Mask of bits to use in this trie node
|
|
keyMask = MaskBits(pCurrNode->numBits);
|
|
|
|
// Value of non-masked bits to match now
|
|
keyBits = pCurrNode->keyBits;
|
|
|
|
// Try to match the bits with above mask
|
|
if ((addrBits & keyMask) != keyBits) {
|
|
// Case 2: Failed to match this node
|
|
break;
|
|
}
|
|
// Update best value of route so far
|
|
if (!NULL_DEST(pCurrNode->dest)) {
|
|
pBestDest = pCurrNode->dest;
|
|
}
|
|
// Go down for more specific match
|
|
addrBits <<= pCurrNode->numBits;
|
|
|
|
// Bit 1 gives direction to search next
|
|
nextChild = PickMostSigNBits(addrBits, 1);
|
|
}
|
|
|
|
return pBestDest;
|
|
}
|
|
|
|
UINT
|
|
CALLCONV
|
|
IterateOverSTrie(IN STrie * pSTrie,
|
|
IN STrieCtxt * pCtxt,
|
|
OUT Route ** ppRoute,
|
|
OUT Dest** ppDest)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the next route in the S-Trie
|
|
|
|
Arguments:
|
|
|
|
pSTrie - Pointer to trie to iterate over
|
|
pCtxt - Pointer to iterator context
|
|
ppRoute - To return the next S-trie route
|
|
ppDest - To return destinations instead of routes
|
|
|
|
Return Value:
|
|
TRIE_SUCCESS or ERROR_TRIE_*
|
|
|
|
--*/
|
|
{
|
|
STrieNode *nodeInLevel[MAXLEVEL + 1];
|
|
STrieNode *pPrevNode;
|
|
STrieNode *pCurrNode;
|
|
STrieNode *pNextNode;
|
|
Route *pCurrRoute;
|
|
ULONG addrBits;
|
|
ULONG tempBits;
|
|
UINT numLevels;
|
|
UINT nextBits;
|
|
UINT matchBits;
|
|
UINT bitsLeft;
|
|
UINT distPos;
|
|
UINT nextChild;
|
|
BOOLEAN routeToReturn;
|
|
Dest *pCurrDest;
|
|
|
|
#if DBG
|
|
if (!pSTrie) {
|
|
Fatal("Iterate Over STrie: STrie not initialized",
|
|
ERROR_TRIE_NOT_INITED);
|
|
}
|
|
#endif
|
|
|
|
// Check if the context is a valid one
|
|
if (NULL_ROUTE(pCtxt->pCRoute)) {
|
|
// NULL Context Case -- First Time
|
|
|
|
// Do we have any routes at all ?
|
|
if (pSTrie->trieRoot == NULL) {
|
|
return (UINT) ERROR_TRIE_NO_ROUTES;
|
|
}
|
|
// Start from the very beginning
|
|
|
|
// Fill in actual context
|
|
pCtxt->currAddr = 0;
|
|
pCtxt->currALen = 0;
|
|
|
|
pCurrDest = pSTrie->trieRoot->dest;
|
|
pCtxt->pCRoute = pCurrDest ? pCurrDest->firstRoute : NULL;
|
|
|
|
// Fill generated context
|
|
numLevels = 1;
|
|
nodeInLevel[0] = pSTrie->trieRoot;
|
|
} else {
|
|
// Non NULL Context -- Generate path
|
|
// of current route from trie's root
|
|
|
|
// Use addr bits to index the trie
|
|
addrBits = RtlConvertEndianLong(pCtxt->currAddr);
|
|
|
|
bitsLeft = pCtxt->currALen;
|
|
|
|
#if DBG
|
|
// Make sure addr and mask agree
|
|
if (ShowMostSigNBits(addrBits, bitsLeft) != addrBits) {
|
|
Fatal("Search Route: Addr & mask don't agree",
|
|
ERROR_TRIE_BAD_PARAM);
|
|
}
|
|
#endif
|
|
|
|
// Start going down the search trie
|
|
numLevels = 0;
|
|
|
|
nextChild = 0;
|
|
pPrevNode = STRUCT_OF(STrieNode, &pSTrie->trieRoot, child[0]);
|
|
|
|
for (;;) {
|
|
// Start this loop by advancing to the next child
|
|
pCurrNode = pPrevNode->child[nextChild];
|
|
|
|
// Push pointer to this trie node into the stack
|
|
nodeInLevel[numLevels++] = pCurrNode;
|
|
|
|
// Valid context always matches all nodes exactly
|
|
Assert(pCurrNode != NULL);
|
|
|
|
// Get Number of bits to match in this trie node
|
|
nextBits = pCurrNode->numBits;
|
|
|
|
matchBits = (nextBits > bitsLeft) ? bitsLeft : nextBits;
|
|
|
|
// Adjust next node bits for dist posn check
|
|
|
|
// Get distinguishing postion for bit patterns
|
|
distPos = PickDistPosition(pCurrNode->keyBits,
|
|
addrBits,
|
|
matchBits,
|
|
&tempBits);
|
|
|
|
// Valid context always matches all nodes exactly
|
|
Assert(distPos == nextBits);
|
|
|
|
if (distPos == bitsLeft) {
|
|
// We have exhausted all incoming bits
|
|
// We should have found a route (list)
|
|
|
|
pCurrDest = pCurrNode->dest;
|
|
#if DBG
|
|
// This node starts a valid route list
|
|
|
|
Assert(pCurrDest);
|
|
|
|
// Try matching the route in context
|
|
pCurrRoute = pCurrDest->firstRoute;
|
|
|
|
do {
|
|
if (pCurrRoute == pCtxt->pCRoute) {
|
|
break;
|
|
}
|
|
pCurrRoute = NEXT(pCurrRoute);
|
|
}
|
|
while (!NULL_ROUTE(pCurrRoute));
|
|
|
|
// We should find a definite match
|
|
Assert(!NULL_ROUTE(pCurrRoute));
|
|
#endif // DBG
|
|
|
|
// We have the full path from root to
|
|
// current node in the stack of nodes
|
|
break;
|
|
}
|
|
// We still have key bits left here
|
|
// Go down for more specific match
|
|
|
|
// Discard used bits for this iteration
|
|
addrBits <<= matchBits;
|
|
bitsLeft -= matchBits;
|
|
|
|
// Prepare node for the next iteration
|
|
pPrevNode = pCurrNode;
|
|
|
|
// Bit 1 gives direction to search next
|
|
nextChild = PickMostSigNBits(addrBits, 1);
|
|
}
|
|
}
|
|
|
|
// We have no routes to return at this point
|
|
routeToReturn = FALSE;
|
|
|
|
// Set direction to print route in context
|
|
nextChild = LCHILD;
|
|
|
|
for (;;) {
|
|
// Get pointer to the current node & direction
|
|
pCurrNode = nodeInLevel[numLevels - 1];
|
|
|
|
// Return route its first time on top of stack
|
|
if (nextChild == LCHILD) {
|
|
pCurrRoute = pCtxt->pCRoute;
|
|
if (!NULL_ROUTE(pCurrRoute)) {
|
|
// We have a valid route to return
|
|
routeToReturn = TRUE;
|
|
if (ppDest) {
|
|
CopyDestPtr(ppDest, pCurrDest);
|
|
} else {
|
|
CopyRoutePtr(ppRoute, pCurrRoute);
|
|
|
|
// Got a valid next route - return
|
|
pCtxt->pCRoute = NEXT(pCurrRoute);
|
|
if (!NULL_ROUTE(NEXT(pCurrRoute))) {
|
|
// Update the context and return
|
|
pCtxt->currAddr = DEST(pCtxt->pCRoute);
|
|
pCtxt->currALen = LEN(pCtxt->pCRoute);
|
|
|
|
return (UINT) ERROR_TRIE_NOT_EMPTY;
|
|
}
|
|
}
|
|
// Search for the valid next route
|
|
}
|
|
}
|
|
// Update the context to reflect an access
|
|
switch (nextChild) {
|
|
case LCHILD:
|
|
// Push left child if not NULL
|
|
pNextNode = pCurrNode->child[0];
|
|
|
|
if (pNextNode != NULL) {
|
|
// Push next level on the stack - Go Left
|
|
nodeInLevel[numLevels++] = pNextNode;
|
|
nextChild = LCHILD;
|
|
pCtxt->pCRoute = pNextNode->dest
|
|
? pNextNode->dest->firstRoute
|
|
: NULL;
|
|
|
|
// Return if we have a route to send back
|
|
// & we also have located the next route
|
|
if ((routeToReturn) && !NULL_DEST(pNextNode->dest)) {
|
|
// Update the context and return
|
|
pCtxt->currAddr = DEST(pCtxt->pCRoute);
|
|
pCtxt->currALen = LEN(pCtxt->pCRoute);
|
|
|
|
return (UINT) ERROR_TRIE_NOT_EMPTY;
|
|
}
|
|
continue;
|
|
}
|
|
case RCHILD:
|
|
// Push right child if not NULL
|
|
pNextNode = pCurrNode->child[1];
|
|
|
|
if (pNextNode != NULL) {
|
|
// Push next level on the stack - Go Left
|
|
nodeInLevel[numLevels++] = pNextNode;
|
|
nextChild = LCHILD;
|
|
pCtxt->pCRoute = pNextNode->dest
|
|
? pNextNode->dest->firstRoute
|
|
: NULL;
|
|
|
|
// Return if we have a route to send back
|
|
// & we also have located the next route
|
|
if ((routeToReturn) && !NULL_DEST(pNextNode->dest)) {
|
|
// Update the context and return
|
|
pCtxt->currAddr = DEST(pCtxt->pCRoute);
|
|
pCtxt->currALen = LEN(pCtxt->pCRoute);
|
|
|
|
return (UINT) ERROR_TRIE_NOT_EMPTY;
|
|
}
|
|
continue;
|
|
}
|
|
case PARENT:
|
|
// Pop node & calculate new direction
|
|
|
|
// Are we done iterating ?
|
|
if (--numLevels == 0) {
|
|
return TRIE_SUCCESS;
|
|
}
|
|
pPrevNode = nodeInLevel[numLevels - 1];
|
|
|
|
if (pPrevNode->child[0] == pCurrNode) {
|
|
nextChild = RCHILD;
|
|
} else {
|
|
nextChild = PARENT;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
UINT
|
|
CALLCONV
|
|
IsSTrieIteratorValid(IN STrie * pSTrie,
|
|
IN STrieCtxt * pCtxt)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Make sure that iterator's context is valid
|
|
|
|
Arguments:
|
|
|
|
pSTrie - Pointer to trie to iterate over
|
|
pCtxt - Pointer to iterator context
|
|
|
|
Return Value:
|
|
TRIE_SUCCESS or ERROR_TRIE_*
|
|
|
|
--*/
|
|
{
|
|
Route *pCurrRoute;
|
|
ULONG addrMask;
|
|
ULONG maskBits;
|
|
|
|
if (NULL_ROUTE(pCtxt->pCRoute)) {
|
|
// NULL Context Case
|
|
|
|
if (pSTrie->trieRoot != NULL) {
|
|
return TRIE_SUCCESS;
|
|
}
|
|
return (UINT) ERROR_TRIE_NO_ROUTES;
|
|
} else {
|
|
// Non NULL Context
|
|
|
|
// Make sure current route is valid
|
|
|
|
// Search for a node with dest, len
|
|
|
|
// Generate mask from address length
|
|
maskBits = MaskBits(pCtxt->currALen);
|
|
|
|
// Convert endian - search needs it
|
|
addrMask = RtlConvertEndianLong(maskBits);
|
|
|
|
if (SearchRouteInSTrie(pSTrie,
|
|
pCtxt->currAddr,
|
|
addrMask,
|
|
0, NULL,
|
|
MATCH_NONE,
|
|
&pCurrRoute) != TRIE_SUCCESS) {
|
|
return (UINT) ERROR_TRIE_BAD_PARAM;
|
|
}
|
|
// Search for the route in context
|
|
while (!NULL_ROUTE(pCurrRoute)) {
|
|
if (pCurrRoute == pCtxt->pCRoute) {
|
|
return TRIE_SUCCESS;
|
|
}
|
|
pCurrRoute = NEXT(pCurrRoute);
|
|
}
|
|
|
|
return (UINT) ERROR_TRIE_BAD_PARAM;
|
|
}
|
|
}
|
|
|
|
UINT
|
|
CALLCONV
|
|
CleanupSTrie(IN STrie * pSTrie)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deletes an S-trie if it is empty
|
|
|
|
Arguments:
|
|
|
|
ppSTrie - Ptr to the S-trie
|
|
|
|
Return Value:
|
|
|
|
TRIE_SUCCESS or ERROR_TRIE_*
|
|
--*/
|
|
{
|
|
// Zero the memory for the trie header
|
|
RtlZeroMemory(pSTrie, sizeof(STrie));
|
|
|
|
return TRIE_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
CALLCONV
|
|
CacheBestRoutesInDest(IN Dest * pDest)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Updates a destination's best-routes cache
|
|
|
|
Arguments:
|
|
|
|
pDest - Ptr to the destination
|
|
|
|
Return Value:
|
|
|
|
none.
|
|
--*/
|
|
{
|
|
Route* pCurrRoute;
|
|
UINT bestMetric, i;
|
|
|
|
pCurrRoute = pDest->firstRoute;
|
|
|
|
if (!pCurrRoute) {
|
|
return;
|
|
}
|
|
|
|
// Get metric of the current best route, and store as many routes with the
|
|
// same metric as possible
|
|
|
|
bestMetric = METRIC(pCurrRoute);
|
|
|
|
for (i = 0; i < pDest->maxBestRoutes; i++) {
|
|
if (NULL_ROUTE(pCurrRoute) || (METRIC(pCurrRoute) != bestMetric)) {
|
|
break;
|
|
}
|
|
pDest->bestRoutes[i] = pCurrRoute;
|
|
pCurrRoute = NEXT(pCurrRoute);
|
|
}
|
|
|
|
pDest->numBestRoutes = (USHORT) i;
|
|
}
|
|
|
|
#if DBG
|
|
|
|
VOID
|
|
CALLCONV
|
|
PrintSTrie(IN STrie * pSTrie,
|
|
IN UINT printFlags)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Print an S-Trie
|
|
|
|
Arguments:
|
|
|
|
pSTrie - Pointer to the S-Trie
|
|
printFlags - Information to print
|
|
|
|
Return Value:
|
|
|
|
None
|
|
--*/
|
|
{
|
|
if (pSTrie == NULL) {
|
|
Print("%s", "Uninitialized STrie\n\n");
|
|
return;
|
|
}
|
|
if ((printFlags & SUMM) == SUMM) {
|
|
Print("\n\n/***Slow-Trie------------------------------------------------");
|
|
Print("\n/***---------------------------------------------------------\n");
|
|
}
|
|
if (printFlags & POOL) {
|
|
Print("Available Memory: %10lu\n\n", pSTrie->availMemory);
|
|
}
|
|
if (printFlags & STAT) {
|
|
Print("Statistics:\n\n");
|
|
|
|
Print("Total Number of Nodes : %d\n", pSTrie->numNodes);
|
|
Print("Total Number of Routes: %d\n", pSTrie->numRoutes);
|
|
Print("Total Number of Dests : %d\n", pSTrie->numDests);
|
|
}
|
|
if (printFlags & TRIE) {
|
|
if (pSTrie->trieRoot == NULL) {
|
|
Print("\nEmpty STrie\n");
|
|
} else {
|
|
PrintSTrieNode(pSTrie->trieRoot);
|
|
}
|
|
}
|
|
if ((printFlags & SUMM) == SUMM) {
|
|
Print("\n---------------------------------------------------------***/\n");
|
|
Print("---------------------------------------------------------***/\n\n");
|
|
}
|
|
}
|
|
|
|
VOID
|
|
CALLCONV
|
|
PrintSTrieNode(IN STrieNode * pSTrieNode)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Print an S-trie node
|
|
|
|
Arguments:
|
|
|
|
pSTrieNode - Pointer to the S-trie node
|
|
|
|
Return Value:
|
|
|
|
None
|
|
--*/
|
|
{
|
|
if (pSTrieNode == NULL) {
|
|
return;
|
|
}
|
|
Print("\n--------------------------------------------------------\n");
|
|
Print("Child @ %08x", pSTrieNode);
|
|
Print("\n--------------------------------------------------------\n");
|
|
Print("Key: Num of Bits : %8d, Value of Bits: %08x\n",
|
|
pSTrieNode->numBits,
|
|
pSTrieNode->keyBits);
|
|
|
|
if (NULL_DEST(pSTrieNode->dest)) {
|
|
Print("NULL Dest\n");
|
|
} else {
|
|
PrintDest(pSTrieNode->dest);
|
|
}
|
|
|
|
Print("Children: On the left %08x, On the right %08x\n",
|
|
pSTrieNode->child[0],
|
|
pSTrieNode->child[1]);
|
|
Print("\n--------------------------------------------------------\n");
|
|
Print("\n\n");
|
|
|
|
PrintSTrieNode(pSTrieNode->child[0]);
|
|
PrintSTrieNode(pSTrieNode->child[1]);
|
|
}
|
|
|
|
#endif // DBG
|
|
|