Source code of Windows XP (NT5)
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

/*++
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