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