483 lines
12 KiB
C
483 lines
12 KiB
C
/*++
|
||
|
||
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
|
||
|