Leaked source code of windows server 2003
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.

476 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 (UINT) 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. // Initialize the Slow Component
  68. if ((initStatus = InitSTrie(pTrie->sTrie,
  69. maxSTMemory)) != TRIE_SUCCESS) {
  70. } else if (!(flags & TFLAG_FAST_TRIE_ENABLED)) {
  71. // Are we using the fast trie ?
  72. return TRIE_SUCCESS;
  73. } else if ((initStatus = InitFTrie(pTrie->fTrie,
  74. levels,
  75. maxFTMemory)) != TRIE_SUCCESS) {
  76. // Initialize the Fast Component
  77. } else {
  78. return TRIE_SUCCESS;
  79. }
  80. // An error occurred - Clean up
  81. // Clean up slow component
  82. if (CleanupSTrie(pTrie->sTrie) != TRIE_SUCCESS)
  83. return initStatus;
  84. // Do we have a fast trie ?
  85. if (!(pTrie->flags & TFLAG_FAST_TRIE_ENABLED))
  86. return initStatus;
  87. // Clean up fast component
  88. if (CleanupFTrie(pTrie->fTrie) != TRIE_SUCCESS)
  89. return initStatus;
  90. // Zero the flags to be safe
  91. pTrie->flags = 0;
  92. return initStatus;
  93. }
  94. VOID
  95. DestroyTrie(IN Trie * pTrie,
  96. OUT UINT * status)
  97. /*++
  98. Routine Description:
  99. Cleans up a trie if it is empty.
  100. Arguments:
  101. pTrie - Pointer to the trie
  102. status - The Cleanup status
  103. Return Value:
  104. TRIE_SUCCESS or ERROR_TRIE_*
  105. --*/
  106. {
  107. // Clean up slow component
  108. if ((*status = CleanupSTrie(pTrie->sTrie)) != TRIE_SUCCESS)
  109. return;
  110. // Do we have a fast trie
  111. if (!(pTrie->flags & TFLAG_FAST_TRIE_ENABLED))
  112. return;
  113. // Clean up fast component
  114. if ((*status = CleanupFTrie(pTrie->fTrie)) != TRIE_SUCCESS)
  115. return;
  116. // Deallocate the trie memory
  117. FreeMemory0(pTrie);
  118. }
  119. UINT
  120. CALLCONV
  121. InsertIntoTrie(IN Trie * pTrie,
  122. IN Route * pIncRoute,
  123. IN ULONG matchFlags,
  124. OUT Route ** ppInsRoute,
  125. OUT Route ** ppOldBestRoute,
  126. OUT Route ** ppNewBestRoute)
  127. /*++
  128. Routine Description:
  129. Inserts a route corresponding to an address
  130. prefix into the slow trie. If this is a new
  131. address prefix, then the corresponding dest
  132. is added to the FTrie (if it is being used).
  133. Arguments:
  134. pTrie - Pointer to the Trie to insert into
  135. pIncRoute - Pointer to the incoming route
  136. matchFlags - Flags to direct route matching
  137. ppInsRoute - Pointer to the route inserted
  138. ppOldBestRoute - Best route before insertion
  139. ppNewBestRoute - Best route after insertion
  140. Return Value:
  141. TRIE_SUCCESS or ERROR_TRIE_*
  142. --*/
  143. {
  144. Dest *pOldBestDest;
  145. Dest *pNewBestDest;
  146. UINT retVal;
  147. *ppOldBestRoute = *ppNewBestRoute = *ppInsRoute = NULL;
  148. pOldBestDest = pNewBestDest = NULL;
  149. // Insert into the slow trie
  150. if ((retVal = InsertIntoSTrie(pTrie->sTrie,
  151. pIncRoute,
  152. matchFlags,
  153. ppInsRoute,
  154. &pOldBestDest,
  155. &pNewBestDest,
  156. ppOldBestRoute)) == TRIE_SUCCESS) {
  157. // Insertion successful - return new route
  158. *ppNewBestRoute = pNewBestDest->firstRoute;
  159. #if _DBG_
  160. Print("\n@ pInsRTE = %08x\n@ pOldBestRTE = %08x\n@ pOldBestDest = %08x\n@ pNewBestDest = %08x\n",
  161. *ppInsRoute, *ppOldBestRoute, pOldBestDest, pNewBestDest);
  162. #endif
  163. // Are we using a fast trie ?
  164. if (pTrie->flags & TFLAG_FAST_TRIE_ENABLED) {
  165. // Did we have a new destination ?
  166. if (pOldBestDest != pNewBestDest) {
  167. // Tweak the fast trie
  168. if ((InsertIntoFTrie(pTrie->fTrie,
  169. *ppInsRoute,
  170. pNewBestDest,
  171. pOldBestDest)) != TRIE_SUCCESS) {
  172. // Not enough memory in F-Trie
  173. // Switch back to the S-Trie
  174. pTrie->flags &= ~TFLAG_FAST_TRIE_ENABLED;
  175. // And clean up the fast trie
  176. CleanupFTrie(pTrie->fTrie);
  177. return retVal;
  178. }
  179. }
  180. }
  181. }
  182. return retVal;
  183. }
  184. UINT
  185. CALLCONV
  186. DeleteFromTrie(IN Trie * pTrie,
  187. IN Route * pIncRoute,
  188. IN ULONG matchFlags,
  189. OUT Route ** ppDelRoute,
  190. OUT Route ** ppOldBestRoute,
  191. OUT Route ** ppNewBestRoute)
  192. /*++
  193. Routine Description:
  194. Deletes a route corresponding to an address
  195. prefix into the S-trie. If this is the last
  196. route on dest, then dest is freed and it is
  197. replaced in the F-Trie by the next best dest.
  198. The route deleted is returned to the caller,
  199. who is responsible for freeing its memory.
  200. Arguments:
  201. pTrie - Pointer to trie to delete from
  202. pIncRoute - Pointer to the incoming route
  203. matchFlags - Flags to direct route matching
  204. ppDelRoute - Pointer to the route deleted
  205. ppOldBestRoute - Best route before deletion
  206. ppNewBestRoute - Best route after deletion
  207. Return Value:
  208. TRIE_SUCCESS or ERROR_TRIE_*
  209. --*/
  210. {
  211. Dest *pOldBestDest;
  212. Dest *pNewBestDest;
  213. UINT retVal;
  214. *ppDelRoute = *ppOldBestRoute = *ppNewBestRoute = NULL;
  215. pOldBestDest = pNewBestDest = NULL;
  216. // Delete from slow trie
  217. if ((retVal = DeleteFromSTrie(pTrie->sTrie,
  218. pIncRoute,
  219. matchFlags,
  220. ppDelRoute,
  221. &pOldBestDest,
  222. &pNewBestDest,
  223. ppOldBestRoute)) == TRIE_SUCCESS) {
  224. // Deletion successful - return new route
  225. *ppNewBestRoute = pNewBestDest ? pNewBestDest->firstRoute : NULL;
  226. #if _DBG_
  227. Print("\n@ pDelRTE = %08x\n@ pOldBestRTE = %08x\n@ pOldBestDest = %08x\n@ pNewBestDest = %08x\n",
  228. *ppDelRoute, *ppOldBestRoute, pOldBestDest, pNewBestDest);
  229. #endif
  230. // Are we using a fast trie ?
  231. if (pTrie->flags & TFLAG_FAST_TRIE_ENABLED) {
  232. // Was deleted route last one on dest ?
  233. if (pOldBestDest != pNewBestDest) {
  234. // Tweak the fast trie
  235. retVal = DeleteFromFTrie(pTrie->fTrie,
  236. *ppDelRoute,
  237. pOldBestDest,
  238. pNewBestDest,
  239. NORMAL);
  240. // Operation cannot fail
  241. Assert(retVal == TRIE_SUCCESS);
  242. }
  243. }
  244. // Reclaim route's memory - in the caller
  245. // FreeRouteInSTrie(pTrie->sTrie, *ppDelRoute);
  246. }
  247. return retVal;
  248. }
  249. #if DBG
  250. Dest *
  251. SearchAddrInTrie(IN Trie * pTrie,
  252. IN ULONG Addr)
  253. /*++
  254. Routine Description:
  255. Search for an address in a trie
  256. Arguments:
  257. pTrie - Pointer to the trie to search
  258. Addr - Pointer to addr being queried
  259. Return Value:
  260. Return best dest match for this address
  261. --*/
  262. {
  263. Dest *pBestDest1, *pBestDest2;
  264. #if _DBG_
  265. // Just pretend that you are searching just one trie
  266. if (pTrie->flags & TFLAG_FAST_TRIE_ENABLED)
  267. Print("Looking up fast trie for %08x\n", Addr);
  268. else
  269. Print("Looking up slow trie for %08x\n", Addr);
  270. #endif
  271. pBestDest1 = SearchAddrInSTrie(pTrie->sTrie, Addr);
  272. // Make sure that the S-Trie and F-Trie are consistent
  273. if (pTrie->flags & TFLAG_FAST_TRIE_ENABLED) {
  274. pBestDest2 = SearchAddrInFTrie(pTrie->fTrie, Addr);
  275. Assert(pBestDest1 == pBestDest2);
  276. }
  277. // Return best dest returned (same by both operations)
  278. return pBestDest1;
  279. }
  280. #else // DBG
  281. #define SearchAddrInTrie(_pTrie_, _Addr_) \
  282. (((_pTrie_)->flags & TFLAG_FAST_TRIE_ENABLED) \
  283. ? SearchAddrInFTrie((_pTrie_)->fTrie, _Addr_) \
  284. : SearchAddrInSTrie((_pTrie_)->sTrie, _Addr_)) \
  285. #endif // DBG
  286. #if DBG
  287. VOID
  288. PrintTrie(IN Trie * pTrie,
  289. IN UINT flags)
  290. /*++
  291. Routine Description:
  292. Prints a trie to the console
  293. Arguments:
  294. pTrie - Pointer to the trie
  295. Return Value:
  296. None
  297. --*/
  298. {
  299. // Print the Slow Trie
  300. if (flags & SLOW)
  301. PrintSTrie(pTrie->sTrie, flags & FULL);
  302. // Is fast trie enabled
  303. if (!(pTrie->flags & TFLAG_FAST_TRIE_ENABLED))
  304. return;
  305. // Print the Fast Trie
  306. if (flags & FAST)
  307. PrintFTrie(pTrie->fTrie, flags & FULL);
  308. }
  309. //
  310. // Miscellaneous Helper Functions
  311. //
  312. VOID
  313. PrintDest(IN Dest * dest)
  314. {
  315. Route *route;
  316. UINT i;
  317. if (NULL_DEST(dest)) {
  318. Print("NULL dest\n");
  319. } else {
  320. route = dest->firstRoute;
  321. Print("Dest: ");
  322. PrintIPAddr(&DEST(route));
  323. Print("/ %2d, Metric = %3lu\n", LEN(route), METRIC(route));
  324. Print("Best Routes: \n");
  325. for (i = 0; i < dest->numBestRoutes; i++) {
  326. route = dest->bestRoutes[i];
  327. Print("Route %d @ %p: ", i, route);
  328. if (NULL_ROUTE(route)) {
  329. Print("NULL Route\n");
  330. } else {
  331. Print("NHop = ");
  332. PrintIPAddr(&NHOP(route));
  333. Print(", IF = %08x\n", IF(route));
  334. }
  335. }
  336. Print("\n");
  337. }
  338. }
  339. VOID
  340. PrintRoute(IN Route * route)
  341. {
  342. Print("Route: Len = %2d", LEN(route));
  343. Print(", Addr = ");
  344. PrintIPAddr(&DEST(route));
  345. Print(", ");
  346. Print("NHop = ");
  347. PrintIPAddr(&NHOP(route));
  348. Print(", IF = %08x", IF(route));
  349. Print(", Metric = %3lu\n", METRIC(route));
  350. }
  351. VOID
  352. PrintIPAddr(IN ULONG * addr)
  353. {
  354. UCHAR *addrBytes = (UCHAR *) addr;
  355. UINT i;
  356. if (addrBytes) {
  357. for (i = 0; i < 4; i++) {
  358. Print("%3d.", addrBytes[i]);
  359. }
  360. Print(" ");
  361. } else {
  362. Print("NULL Addr ");
  363. }
  364. }
  365. #endif // DBG
  366.