mirror of https://github.com/tongzx/nt5src
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.
483 lines
12 KiB
483 lines
12 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
trie.c
|
|
|
|
Abstract:
|
|
|
|
Contains wrapper routines around the
|
|
fast & slow IP route lookup schemes
|
|
|
|
Author:
|
|
|
|
Chaitanya Kodeboyina (chaitk) 26-Nov-1997
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include "strie.h"
|
|
#include "ftrie.h"
|
|
|
|
UINT
|
|
CreateTrie(IN ULONG levels,
|
|
IN ULONG flags,
|
|
IN ULONG maxSTMemory,
|
|
IN ULONG maxFTMemory,
|
|
OUT Trie ** ppTrie)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes S-Trie(Slow Trie) and F-Trie(Fast Trie)
|
|
components in the trie [ wrapper structure ].
|
|
|
|
The Slow Trie component keeps all the routes, while
|
|
the Fast Trie keeps only a pointer the destination
|
|
that holds the list of all routes to the IP address
|
|
of the destination network and cache of best routes.
|
|
|
|
The flags parameter determines the trie's behavior,
|
|
and among other things if we are using a fast trie.
|
|
A fast trie (which is a fast copy of the slow trie)
|
|
enables faster route lookup, but needs more memory.
|
|
|
|
Arguments:
|
|
|
|
pTrie - Pointer to the trie to be initialized
|
|
levels - Bitmap of expanded levels in the F-Trie
|
|
flags - Flags that determine trie's behaviour
|
|
maxSTMemory - Limit on memory taken by the S-Trie
|
|
maxFTMemory - Limit on memory taken by the F-Trie
|
|
|
|
Return Value:
|
|
|
|
TRIE_SUCCESS or ERROR_TRIE_*
|
|
|
|
--*/
|
|
{
|
|
Trie *pTrie;
|
|
UINT nBytes;
|
|
UINT initStatus;
|
|
|
|
// Allocate memory for the tries
|
|
nBytes = sizeof(Trie) + sizeof(STrie);
|
|
if (flags & TFLAG_FAST_TRIE_ENABLED) {
|
|
nBytes += sizeof(FTrie);
|
|
}
|
|
*ppTrie = AllocMemory0(nBytes);
|
|
if (*ppTrie == NULL) {
|
|
return ERROR_TRIE_RESOURCES;
|
|
}
|
|
pTrie = *ppTrie;
|
|
|
|
// Initialize the behavior flags
|
|
pTrie->flags = flags;
|
|
|
|
// Initialize the trie pointers
|
|
pTrie->sTrie = (STrie *) ((UCHAR *) pTrie +
|
|
sizeof(Trie));
|
|
|
|
pTrie->fTrie = NULL;
|
|
if (flags & TFLAG_FAST_TRIE_ENABLED) {
|
|
pTrie->fTrie = (FTrie *) ((UCHAR *) pTrie +
|
|
sizeof(Trie) +
|
|
sizeof(STrie));
|
|
}
|
|
do {
|
|
// Initialize the Slow Component
|
|
if ((initStatus = InitSTrie(pTrie->sTrie,
|
|
maxSTMemory)) != TRIE_SUCCESS)
|
|
break;
|
|
|
|
// Are we using the fast trie ?
|
|
if (!(flags & TFLAG_FAST_TRIE_ENABLED))
|
|
return TRIE_SUCCESS;
|
|
|
|
// Initialize the Fast Component
|
|
if ((initStatus = InitFTrie(pTrie->fTrie,
|
|
levels,
|
|
maxFTMemory)) != TRIE_SUCCESS)
|
|
break;
|
|
|
|
return TRIE_SUCCESS;
|
|
}
|
|
while (FALSE);
|
|
|
|
// An error occurred - Clean up
|
|
|
|
// Clean up slow component
|
|
if (CleanupSTrie(pTrie->sTrie) != TRIE_SUCCESS)
|
|
return initStatus;
|
|
|
|
// Do we have a fast trie ?
|
|
if (!(pTrie->flags & TFLAG_FAST_TRIE_ENABLED))
|
|
return initStatus;
|
|
|
|
// Clean up fast component
|
|
if (CleanupFTrie(pTrie->fTrie) != TRIE_SUCCESS)
|
|
return initStatus;
|
|
|
|
// Zero the flags to be safe
|
|
pTrie->flags = 0;
|
|
|
|
return initStatus;
|
|
}
|
|
|
|
VOID
|
|
DestroyTrie(IN Trie * pTrie,
|
|
OUT UINT * status)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cleans up a trie if it is empty.
|
|
|
|
Arguments:
|
|
|
|
pTrie - Pointer to the trie
|
|
status - The Cleanup status
|
|
|
|
Return Value:
|
|
|
|
TRIE_SUCCESS or ERROR_TRIE_*
|
|
--*/
|
|
{
|
|
// Clean up slow component
|
|
if ((*status = CleanupSTrie(pTrie->sTrie)) != TRIE_SUCCESS)
|
|
return;
|
|
|
|
// Do we have a fast trie
|
|
if (!(pTrie->flags & TFLAG_FAST_TRIE_ENABLED))
|
|
return;
|
|
|
|
// Clean up fast component
|
|
if ((*status = CleanupFTrie(pTrie->fTrie)) != TRIE_SUCCESS)
|
|
return;
|
|
|
|
// Deallocate the trie memory
|
|
FreeMemory0(pTrie);
|
|
}
|
|
|
|
UINT
|
|
CALLCONV
|
|
InsertIntoTrie(IN Trie * pTrie,
|
|
IN Route * pIncRoute,
|
|
IN ULONG matchFlags,
|
|
OUT Route ** ppInsRoute,
|
|
OUT Route ** ppOldBestRoute,
|
|
OUT Route ** ppNewBestRoute)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Inserts a route corresponding to an address
|
|
prefix into the slow trie. If this is a new
|
|
address prefix, then the corresponding dest
|
|
is added to the FTrie (if it is being used).
|
|
|
|
Arguments:
|
|
|
|
pTrie - Pointer to the Trie to insert into
|
|
pIncRoute - Pointer to the incoming route
|
|
matchFlags - Flags to direct route matching
|
|
ppInsRoute - Pointer to the route inserted
|
|
ppOldBestRoute - Best route before insertion
|
|
ppNewBestRoute - Best route after insertion
|
|
|
|
Return Value:
|
|
|
|
TRIE_SUCCESS or ERROR_TRIE_*
|
|
|
|
--*/
|
|
{
|
|
Dest *pOldBestDest;
|
|
Dest *pNewBestDest;
|
|
Route *pDelRoute;
|
|
UINT retVal;
|
|
|
|
*ppOldBestRoute = *ppNewBestRoute = *ppInsRoute = NULL;
|
|
|
|
pOldBestDest = pNewBestDest = NULL;
|
|
|
|
// Insert into the slow trie
|
|
if ((retVal = InsertIntoSTrie(pTrie->sTrie,
|
|
pIncRoute,
|
|
matchFlags,
|
|
ppInsRoute,
|
|
&pOldBestDest,
|
|
&pNewBestDest,
|
|
ppOldBestRoute)) == TRIE_SUCCESS) {
|
|
// Insertion successful - return new route
|
|
*ppNewBestRoute = pNewBestDest->firstRoute;
|
|
|
|
#if _DBG_
|
|
Print("\n@ pInsRTE = %08x\n@ pOldBestRTE = %08x\n@ pOldBestDest = %08x\n@ pNewBestDest = %08x\n",
|
|
*ppInsRoute, *ppOldBestRoute, pOldBestDest, pNewBestDest);
|
|
#endif
|
|
|
|
// Are we using a fast trie ?
|
|
if (pTrie->flags & TFLAG_FAST_TRIE_ENABLED) {
|
|
// Did we have a new destination ?
|
|
if (pOldBestDest != pNewBestDest) {
|
|
// Tweak the fast trie
|
|
if ((InsertIntoFTrie(pTrie->fTrie,
|
|
*ppInsRoute,
|
|
pNewBestDest,
|
|
pOldBestDest)) != TRIE_SUCCESS) {
|
|
// Not enough memory in F-Trie
|
|
// Switch back to the S-Trie
|
|
pTrie->flags &= ~TFLAG_FAST_TRIE_ENABLED;
|
|
|
|
// And clean up the fast trie
|
|
CleanupFTrie(pTrie->fTrie);
|
|
|
|
return retVal;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
UINT
|
|
CALLCONV
|
|
DeleteFromTrie(IN Trie * pTrie,
|
|
IN Route * pIncRoute,
|
|
IN ULONG matchFlags,
|
|
OUT Route ** ppDelRoute,
|
|
OUT Route ** ppOldBestRoute,
|
|
OUT Route ** ppNewBestRoute)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deletes a route corresponding to an address
|
|
prefix into the S-trie. If this is the last
|
|
route on dest, then dest is freed and it is
|
|
replaced in the F-Trie by the next best dest.
|
|
|
|
The route deleted is returned to the caller,
|
|
who is responsible for freeing its memory.
|
|
|
|
Arguments:
|
|
|
|
pTrie - Pointer to trie to delete from
|
|
pIncRoute - Pointer to the incoming route
|
|
matchFlags - Flags to direct route matching
|
|
ppDelRoute - Pointer to the route deleted
|
|
ppOldBestRoute - Best route before deletion
|
|
ppNewBestRoute - Best route after deletion
|
|
|
|
Return Value:
|
|
|
|
TRIE_SUCCESS or ERROR_TRIE_*
|
|
--*/
|
|
{
|
|
Dest *pOldBestDest;
|
|
Dest *pNewBestDest;
|
|
UINT retVal;
|
|
|
|
*ppDelRoute = *ppOldBestRoute = *ppNewBestRoute = NULL;
|
|
|
|
pOldBestDest = pNewBestDest = NULL;
|
|
|
|
// Delete from slow trie
|
|
if ((retVal = DeleteFromSTrie(pTrie->sTrie,
|
|
pIncRoute,
|
|
matchFlags,
|
|
ppDelRoute,
|
|
&pOldBestDest,
|
|
&pNewBestDest,
|
|
ppOldBestRoute)) == TRIE_SUCCESS) {
|
|
// Deletion successful - return new route
|
|
*ppNewBestRoute = pNewBestDest ? pNewBestDest->firstRoute : NULL;
|
|
|
|
#if _DBG_
|
|
Print("\n@ pDelRTE = %08x\n@ pOldBestRTE = %08x\n@ pOldBestDest = %08x\n@ pNewBestDest = %08x\n",
|
|
*ppDelRoute, *ppOldBestRoute, pOldBestDest, pNewBestDest);
|
|
#endif
|
|
|
|
// Are we using a fast trie ?
|
|
if (pTrie->flags & TFLAG_FAST_TRIE_ENABLED) {
|
|
// Was deleted route last one on dest ?
|
|
if (pOldBestDest != pNewBestDest) {
|
|
// Tweak the fast trie
|
|
retVal = DeleteFromFTrie(pTrie->fTrie,
|
|
*ppDelRoute,
|
|
pOldBestDest,
|
|
pNewBestDest,
|
|
NORMAL);
|
|
|
|
// Operation cannot fail
|
|
Assert(retVal == TRIE_SUCCESS);
|
|
}
|
|
}
|
|
// Reclaim route's memory - in the caller
|
|
// FreeRouteInSTrie(pTrie->sTrie, *ppDelRoute);
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
#if DBG
|
|
|
|
Dest *
|
|
SearchAddrInTrie(IN Trie * pTrie,
|
|
IN ULONG Addr)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Search for an address in a trie
|
|
|
|
Arguments:
|
|
|
|
pTrie - Pointer to the trie to search
|
|
Addr - Pointer to addr being queried
|
|
|
|
Return Value:
|
|
Return best dest match for this address
|
|
|
|
--*/
|
|
{
|
|
Dest *pBestDest1, *pBestDest2;
|
|
|
|
#if _DBG_
|
|
// Just pretend that you are searching just one trie
|
|
if (pTrie->flags & TFLAG_FAST_TRIE_ENABLED)
|
|
Print("Looking up fast trie for %08x\n", Addr);
|
|
else
|
|
Print("Looking up slow trie for %08x\n", Addr);
|
|
#endif
|
|
|
|
pBestDest1 = SearchAddrInSTrie(pTrie->sTrie, Addr);
|
|
|
|
// Make sure that the S-Trie and F-Trie are consistent
|
|
if (pTrie->flags & TFLAG_FAST_TRIE_ENABLED) {
|
|
pBestDest2 = SearchAddrInFTrie(pTrie->fTrie, Addr);
|
|
Assert(pBestDest1 == pBestDest2);
|
|
}
|
|
// Return best dest returned (same by both operations)
|
|
return pBestDest1;
|
|
}
|
|
|
|
#else // DBG
|
|
|
|
#define SearchAddrInTrie(_pTrie_, _Addr_) \
|
|
(((_pTrie_)->flags & TFLAG_FAST_TRIE_ENABLED) \
|
|
? SearchAddrInFTrie((_pTrie_)->fTrie, _Addr_) \
|
|
: SearchAddrInSTrie((_pTrie_)->sTrie, _Addr_)) \
|
|
|
|
#endif // DBG
|
|
|
|
#if DBG
|
|
|
|
VOID
|
|
PrintTrie(IN Trie * pTrie,
|
|
IN UINT flags)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints a trie to the console
|
|
|
|
Arguments:
|
|
|
|
pTrie - Pointer to the trie
|
|
|
|
Return Value:
|
|
|
|
None
|
|
--*/
|
|
{
|
|
// Print the Slow Trie
|
|
if (flags & SLOW)
|
|
PrintSTrie(pTrie->sTrie, flags & FULL);
|
|
|
|
// Is fast trie enabled
|
|
if (!(pTrie->flags & TFLAG_FAST_TRIE_ENABLED))
|
|
return;
|
|
|
|
// Print the Fast Trie
|
|
if (flags & FAST)
|
|
PrintFTrie(pTrie->fTrie, flags & FULL);
|
|
}
|
|
|
|
//
|
|
// Miscellaneous Helper Functions
|
|
//
|
|
|
|
VOID
|
|
PrintDest(IN Dest * dest)
|
|
{
|
|
Route *route;
|
|
UINT i;
|
|
|
|
if (NULL_DEST(dest)) {
|
|
Print("NULL dest\n");
|
|
} else {
|
|
route = dest->firstRoute;
|
|
|
|
Print("Dest: ");
|
|
PrintIPAddr(&DEST(route));
|
|
Print("/ %2d, Metric = %3lu\n", LEN(route), METRIC(route));
|
|
|
|
Print("Best Routes: \n");
|
|
for (i = 0; i < dest->numBestRoutes; i++) {
|
|
route = dest->bestRoutes[i];
|
|
|
|
Print("Route %d @ %p: ", i, route);
|
|
|
|
if (NULL_ROUTE(route)) {
|
|
Print("NULL Route\n");
|
|
} else {
|
|
Print("NHop = ");
|
|
PrintIPAddr(&NHOP(route));
|
|
|
|
Print(", IF = %08x\n", IF(route));
|
|
}
|
|
}
|
|
Print("\n");
|
|
}
|
|
}
|
|
|
|
VOID
|
|
PrintRoute(IN Route * route)
|
|
{
|
|
UINT i;
|
|
|
|
Print("Route: Len = %2d", LEN(route));
|
|
|
|
Print(", Addr = ");
|
|
PrintIPAddr(&DEST(route));
|
|
Print(", ");
|
|
|
|
Print("NHop = ");
|
|
PrintIPAddr(&NHOP(route));
|
|
|
|
Print(", IF = %08x", IF(route));
|
|
Print(", Metric = %3lu\n", METRIC(route));
|
|
}
|
|
|
|
VOID
|
|
PrintIPAddr(IN ULONG * addr)
|
|
{
|
|
UCHAR *addrBytes = (UCHAR *) addr;
|
|
UINT i;
|
|
|
|
if (addrBytes) {
|
|
for (i = 0; i < 4; i++) {
|
|
Print("%3d.", addrBytes[i]);
|
|
}
|
|
Print(" ");
|
|
} else {
|
|
Print("NULL Addr ");
|
|
}
|
|
}
|
|
|
|
#endif // DBG
|
|
|