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.

482 lines
12 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. trie.c
  5. Abstract:
  6. Contains wrapper routines around the
  7. fast & slow IP route lookup schemes
  8. Author:
  9. Chaitanya Kodeboyina (chaitk) 26-Nov-1997
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #include "strie.h"
  14. #include "ftrie.h"
  15. UINT
  16. CreateTrie(IN ULONG levels,
  17. IN ULONG flags,
  18. IN ULONG maxSTMemory,
  19. IN ULONG maxFTMemory,
  20. OUT Trie ** ppTrie)
  21. /*++
  22. Routine Description:
  23. Initializes S-Trie(Slow Trie) and F-Trie(Fast Trie)
  24. components in the trie [ wrapper structure ].
  25. The Slow Trie component keeps all the routes, while
  26. the Fast Trie keeps only a pointer the destination
  27. that holds the list of all routes to the IP address
  28. of the destination network and cache of best routes.
  29. The flags parameter determines the trie's behavior,
  30. and among other things if we are using a fast trie.
  31. A fast trie (which is a fast copy of the slow trie)
  32. enables faster route lookup, but needs more memory.
  33. Arguments:
  34. pTrie - Pointer to the trie to be initialized
  35. levels - Bitmap of expanded levels in the F-Trie
  36. flags - Flags that determine trie's behaviour
  37. maxSTMemory - Limit on memory taken by the S-Trie
  38. maxFTMemory - Limit on memory taken by the F-Trie
  39. Return Value:
  40. TRIE_SUCCESS or ERROR_TRIE_*
  41. --*/
  42. {
  43. Trie *pTrie;
  44. UINT nBytes;
  45. UINT initStatus;
  46. // Allocate memory for the tries
  47. nBytes = sizeof(Trie) + sizeof(STrie);
  48. if (flags & TFLAG_FAST_TRIE_ENABLED) {
  49. nBytes += sizeof(FTrie);
  50. }
  51. *ppTrie = AllocMemory0(nBytes);
  52. if (*ppTrie == NULL) {
  53. return ERROR_TRIE_RESOURCES;
  54. }
  55. pTrie = *ppTrie;
  56. // Initialize the behavior flags
  57. pTrie->flags = flags;
  58. // Initialize the trie pointers
  59. pTrie->sTrie = (STrie *) ((UCHAR *) pTrie +
  60. sizeof(Trie));
  61. pTrie->fTrie = NULL;
  62. if (flags & TFLAG_FAST_TRIE_ENABLED) {
  63. pTrie->fTrie = (FTrie *) ((UCHAR *) pTrie +
  64. sizeof(Trie) +
  65. sizeof(STrie));
  66. }
  67. do {
  68. // Initialize the Slow Component
  69. if ((initStatus = InitSTrie(pTrie->sTrie,
  70. maxSTMemory)) != TRIE_SUCCESS)
  71. break;
  72. // Are we using the fast trie ?
  73. if (!(flags & TFLAG_FAST_TRIE_ENABLED))
  74. return TRIE_SUCCESS;
  75. // Initialize the Fast Component
  76. if ((initStatus = InitFTrie(pTrie->fTrie,
  77. levels,
  78. maxFTMemory)) != TRIE_SUCCESS)
  79. break;
  80. return TRIE_SUCCESS;
  81. }
  82. while (FALSE);
  83. // An error occurred - Clean up
  84. // Clean up slow component
  85. if (CleanupSTrie(pTrie->sTrie) != TRIE_SUCCESS)
  86. return initStatus;
  87. // Do we have a fast trie ?
  88. if (!(pTrie->flags & TFLAG_FAST_TRIE_ENABLED))
  89. return initStatus;
  90. // Clean up fast component
  91. if (CleanupFTrie(pTrie->fTrie) != TRIE_SUCCESS)
  92. return initStatus;
  93. // Zero the flags to be safe
  94. pTrie->flags = 0;
  95. return initStatus;
  96. }
  97. VOID
  98. DestroyTrie(IN Trie * pTrie,
  99. OUT UINT * status)
  100. /*++
  101. Routine Description:
  102. Cleans up a trie if it is empty.
  103. Arguments:
  104. pTrie - Pointer to the trie
  105. status - The Cleanup status
  106. Return Value:
  107. TRIE_SUCCESS or ERROR_TRIE_*
  108. --*/
  109. {
  110. // Clean up slow component
  111. if ((*status = CleanupSTrie(pTrie->sTrie)) != TRIE_SUCCESS)
  112. return;
  113. // Do we have a fast trie
  114. if (!(pTrie->flags & TFLAG_FAST_TRIE_ENABLED))
  115. return;
  116. // Clean up fast component
  117. if ((*status = CleanupFTrie(pTrie->fTrie)) != TRIE_SUCCESS)
  118. return;
  119. // Deallocate the trie memory
  120. FreeMemory0(pTrie);
  121. }
  122. UINT
  123. CALLCONV
  124. InsertIntoTrie(IN Trie * pTrie,
  125. IN Route * pIncRoute,
  126. IN ULONG matchFlags,
  127. OUT Route ** ppInsRoute,
  128. OUT Route ** ppOldBestRoute,
  129. OUT Route ** ppNewBestRoute)
  130. /*++
  131. Routine Description:
  132. Inserts a route corresponding to an address
  133. prefix into the slow trie. If this is a new
  134. address prefix, then the corresponding dest
  135. is added to the FTrie (if it is being used).
  136. Arguments:
  137. pTrie - Pointer to the Trie to insert into
  138. pIncRoute - Pointer to the incoming route
  139. matchFlags - Flags to direct route matching
  140. ppInsRoute - Pointer to the route inserted
  141. ppOldBestRoute - Best route before insertion
  142. ppNewBestRoute - Best route after insertion
  143. Return Value:
  144. TRIE_SUCCESS or ERROR_TRIE_*
  145. --*/
  146. {
  147. Dest *pOldBestDest;
  148. Dest *pNewBestDest;
  149. Route *pDelRoute;
  150. UINT retVal;
  151. *ppOldBestRoute = *ppNewBestRoute = *ppInsRoute = NULL;
  152. pOldBestDest = pNewBestDest = NULL;
  153. // Insert into the slow trie
  154. if ((retVal = InsertIntoSTrie(pTrie->sTrie,
  155. pIncRoute,
  156. matchFlags,
  157. ppInsRoute,
  158. &pOldBestDest,
  159. &pNewBestDest,
  160. ppOldBestRoute)) == TRIE_SUCCESS) {
  161. // Insertion successful - return new route
  162. *ppNewBestRoute = pNewBestDest->firstRoute;
  163. #if _DBG_
  164. Print("\n@ pInsRTE = %08x\n@ pOldBestRTE = %08x\n@ pOldBestDest = %08x\n@ pNewBestDest = %08x\n",
  165. *ppInsRoute, *ppOldBestRoute, pOldBestDest, pNewBestDest);
  166. #endif
  167. // Are we using a fast trie ?
  168. if (pTrie->flags & TFLAG_FAST_TRIE_ENABLED) {
  169. // Did we have a new destination ?
  170. if (pOldBestDest != pNewBestDest) {
  171. // Tweak the fast trie
  172. if ((InsertIntoFTrie(pTrie->fTrie,
  173. *ppInsRoute,
  174. pNewBestDest,
  175. pOldBestDest)) != TRIE_SUCCESS) {
  176. // Not enough memory in F-Trie
  177. // Switch back to the S-Trie
  178. pTrie->flags &= ~TFLAG_FAST_TRIE_ENABLED;
  179. // And clean up the fast trie
  180. CleanupFTrie(pTrie->fTrie);
  181. return retVal;
  182. }
  183. }
  184. }
  185. }
  186. return retVal;
  187. }
  188. UINT
  189. CALLCONV
  190. DeleteFromTrie(IN Trie * pTrie,
  191. IN Route * pIncRoute,
  192. IN ULONG matchFlags,
  193. OUT Route ** ppDelRoute,
  194. OUT Route ** ppOldBestRoute,
  195. OUT Route ** ppNewBestRoute)
  196. /*++
  197. Routine Description:
  198. Deletes a route corresponding to an address
  199. prefix into the S-trie. If this is the last
  200. route on dest, then dest is freed and it is
  201. replaced in the F-Trie by the next best dest.
  202. The route deleted is returned to the caller,
  203. who is responsible for freeing its memory.
  204. Arguments:
  205. pTrie - Pointer to trie to delete from
  206. pIncRoute - Pointer to the incoming route
  207. matchFlags - Flags to direct route matching
  208. ppDelRoute - Pointer to the route deleted
  209. ppOldBestRoute - Best route before deletion
  210. ppNewBestRoute - Best route after deletion
  211. Return Value:
  212. TRIE_SUCCESS or ERROR_TRIE_*
  213. --*/
  214. {
  215. Dest *pOldBestDest;
  216. Dest *pNewBestDest;
  217. UINT retVal;
  218. *ppDelRoute = *ppOldBestRoute = *ppNewBestRoute = NULL;
  219. pOldBestDest = pNewBestDest = NULL;
  220. // Delete from slow trie
  221. if ((retVal = DeleteFromSTrie(pTrie->sTrie,
  222. pIncRoute,
  223. matchFlags,
  224. ppDelRoute,
  225. &pOldBestDest,
  226. &pNewBestDest,
  227. ppOldBestRoute)) == TRIE_SUCCESS) {
  228. // Deletion successful - return new route
  229. *ppNewBestRoute = pNewBestDest ? pNewBestDest->firstRoute : NULL;
  230. #if _DBG_
  231. Print("\n@ pDelRTE = %08x\n@ pOldBestRTE = %08x\n@ pOldBestDest = %08x\n@ pNewBestDest = %08x\n",
  232. *ppDelRoute, *ppOldBestRoute, pOldBestDest, pNewBestDest);
  233. #endif
  234. // Are we using a fast trie ?
  235. if (pTrie->flags & TFLAG_FAST_TRIE_ENABLED) {
  236. // Was deleted route last one on dest ?
  237. if (pOldBestDest != pNewBestDest) {
  238. // Tweak the fast trie
  239. retVal = DeleteFromFTrie(pTrie->fTrie,
  240. *ppDelRoute,
  241. pOldBestDest,
  242. pNewBestDest,
  243. NORMAL);
  244. // Operation cannot fail
  245. Assert(retVal == TRIE_SUCCESS);
  246. }
  247. }
  248. // Reclaim route's memory - in the caller
  249. // FreeRouteInSTrie(pTrie->sTrie, *ppDelRoute);
  250. }
  251. return retVal;
  252. }
  253. #if DBG
  254. Dest *
  255. SearchAddrInTrie(IN Trie * pTrie,
  256. IN ULONG Addr)
  257. /*++
  258. Routine Description:
  259. Search for an address in a trie
  260. Arguments:
  261. pTrie - Pointer to the trie to search
  262. Addr - Pointer to addr being queried
  263. Return Value:
  264. Return best dest match for this address
  265. --*/
  266. {
  267. Dest *pBestDest1, *pBestDest2;
  268. #if _DBG_
  269. // Just pretend that you are searching just one trie
  270. if (pTrie->flags & TFLAG_FAST_TRIE_ENABLED)
  271. Print("Looking up fast trie for %08x\n", Addr);
  272. else
  273. Print("Looking up slow trie for %08x\n", Addr);
  274. #endif
  275. pBestDest1 = SearchAddrInSTrie(pTrie->sTrie, Addr);
  276. // Make sure that the S-Trie and F-Trie are consistent
  277. if (pTrie->flags & TFLAG_FAST_TRIE_ENABLED) {
  278. pBestDest2 = SearchAddrInFTrie(pTrie->fTrie, Addr);
  279. Assert(pBestDest1 == pBestDest2);
  280. }
  281. // Return best dest returned (same by both operations)
  282. return pBestDest1;
  283. }
  284. #else // DBG
  285. #define SearchAddrInTrie(_pTrie_, _Addr_) \
  286. (((_pTrie_)->flags & TFLAG_FAST_TRIE_ENABLED) \
  287. ? SearchAddrInFTrie((_pTrie_)->fTrie, _Addr_) \
  288. : SearchAddrInSTrie((_pTrie_)->sTrie, _Addr_)) \
  289. #endif // DBG
  290. #if DBG
  291. VOID
  292. PrintTrie(IN Trie * pTrie,
  293. IN UINT flags)
  294. /*++
  295. Routine Description:
  296. Prints a trie to the console
  297. Arguments:
  298. pTrie - Pointer to the trie
  299. Return Value:
  300. None
  301. --*/
  302. {
  303. // Print the Slow Trie
  304. if (flags & SLOW)
  305. PrintSTrie(pTrie->sTrie, flags & FULL);
  306. // Is fast trie enabled
  307. if (!(pTrie->flags & TFLAG_FAST_TRIE_ENABLED))
  308. return;
  309. // Print the Fast Trie
  310. if (flags & FAST)
  311. PrintFTrie(pTrie->fTrie, flags & FULL);
  312. }
  313. //
  314. // Miscellaneous Helper Functions
  315. //
  316. VOID
  317. PrintDest(IN Dest * dest)
  318. {
  319. Route *route;
  320. UINT i;
  321. if (NULL_DEST(dest)) {
  322. Print("NULL dest\n");
  323. } else {
  324. route = dest->firstRoute;
  325. Print("Dest: ");
  326. PrintIPAddr(&DEST(route));
  327. Print("/ %2d, Metric = %3lu\n", LEN(route), METRIC(route));
  328. Print("Best Routes: \n");
  329. for (i = 0; i < dest->numBestRoutes; i++) {
  330. route = dest->bestRoutes[i];
  331. Print("Route %d @ %p: ", i, route);
  332. if (NULL_ROUTE(route)) {
  333. Print("NULL Route\n");
  334. } else {
  335. Print("NHop = ");
  336. PrintIPAddr(&NHOP(route));
  337. Print(", IF = %08x\n", IF(route));
  338. }
  339. }
  340. Print("\n");
  341. }
  342. }
  343. VOID
  344. PrintRoute(IN Route * route)
  345. {
  346. UINT i;
  347. Print("Route: Len = %2d", LEN(route));
  348. Print(", Addr = ");
  349. PrintIPAddr(&DEST(route));
  350. Print(", ");
  351. Print("NHop = ");
  352. PrintIPAddr(&NHOP(route));
  353. Print(", IF = %08x", IF(route));
  354. Print(", Metric = %3lu\n", METRIC(route));
  355. }
  356. VOID
  357. PrintIPAddr(IN ULONG * addr)
  358. {
  359. UCHAR *addrBytes = (UCHAR *) addr;
  360. UINT i;
  361. if (addrBytes) {
  362. for (i = 0; i < 4; i++) {
  363. Print("%3d.", addrBytes[i]);
  364. }
  365. Print(" ");
  366. } else {
  367. Print("NULL Addr ");
  368. }
  369. }
  370. #endif // DBG
  371.