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.

1522 lines
46 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. strie.c
  5. Abstract:
  6. This module contains routines that manipulate
  7. an S-trie data stucture, that forms the slow
  8. path in a fast IP route lookup implementation.
  9. Author:
  10. Chaitanya Kodeboyina (chaitk) 26-Nov-1997
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #include "strie.h"
  15. UINT
  16. CALLCONV
  17. InitSTrie(IN STrie * pSTrie,
  18. IN ULONG maxMemory)
  19. /*++
  20. Routine Description:
  21. Initializes an S-trie. This should be done prior
  22. to any other trie operations.
  23. Arguments:
  24. pSTrie - Pointer to the trie to be initialized
  25. maxMemory - Limit on memory taken by the S-Trie
  26. Return Value:
  27. TRIE_SUCCESS
  28. --*/
  29. {
  30. // Zero all the memory for the trie header
  31. RtlZeroMemory(pSTrie, sizeof(STrie));
  32. // Set a limit on the memory for trie/nodes
  33. pSTrie->availMemory = maxMemory;
  34. return TRIE_SUCCESS;
  35. }
  36. UINT
  37. CALLCONV
  38. InsertIntoSTrie(IN STrie * pSTrie,
  39. IN Route * pIncRoute,
  40. IN ULONG matchFlags,
  41. OUT Route ** ppInsRoute,
  42. OUT Dest ** ppOldBestDest,
  43. OUT Dest ** ppNewBestDest,
  44. OUT Route ** ppOldBestRoute
  45. )
  46. /*++
  47. Routine Description:
  48. Inserts a route corresponding to an address
  49. prefix into a S-trie, and fills in best
  50. dest for addresses that match this prefix
  51. both before and after insertion of route.
  52. Arguments:
  53. pSTrie - Pointer to trie to insert into
  54. pIncRoute - Pointer to the incoming route
  55. matchFlags - Flags to direct route matching
  56. ppInsRoute - Pointer to the route inserted
  57. ppOldBestDest - Best dest before insertion
  58. ppNewBestDest - Best dest after insertion
  59. ppOldBestRoute - Best route before insertion
  60. Return Value:
  61. TRIE_SUCCESS or ERROR_TRIE_*
  62. --*/
  63. {
  64. STrieNode *pNewNode;
  65. STrieNode *pPrevNode;
  66. STrieNode *pCurrNode;
  67. STrieNode *pOthNode;
  68. Dest *pCurrDest;
  69. Dest *pNewDest;
  70. Dest *pBestDest;
  71. Route *pNewRoute;
  72. Route *pPrevRoute;
  73. Route *pCurrRoute;
  74. ULONG addrBits;
  75. ULONG tempBits;
  76. UINT numBits;
  77. UINT nextBits;
  78. UINT matchBits;
  79. UINT bitsLeft;
  80. UINT distPos;
  81. UINT nextChild;
  82. UINT i, j;
  83. #if DBG
  84. // Make sure the trie is initialized
  85. if (!pSTrie) {
  86. Fatal("Insert Route: STrie not initialized",
  87. ERROR_TRIE_NOT_INITED);
  88. }
  89. #endif
  90. // Make sure input route is valid
  91. if (NULL_ROUTE(pIncRoute)) {
  92. Error("Insert Route: NULL or invalid route",
  93. ERROR_TRIE_BAD_PARAM);
  94. }
  95. if (LEN(pIncRoute) > ADDRSIZE) {
  96. Error("Insert Route: Invalid mask length",
  97. ERROR_TRIE_BAD_PARAM);
  98. }
  99. // Use addr bits to index the trie
  100. addrBits = RtlConvertEndianLong(DEST(pIncRoute));
  101. bitsLeft = LEN(pIncRoute);
  102. // Make sure addr and mask agree
  103. if (ShowMostSigNBits(addrBits, bitsLeft) != addrBits) {
  104. Error("Insert Route: Addr & mask don't agree",
  105. ERROR_TRIE_BAD_PARAM);
  106. }
  107. TRY_BLOCK
  108. {
  109. // Start going down the search trie
  110. // Initialize any new allocations
  111. pNewNode = NULL;
  112. pOthNode = NULL;
  113. pNewDest = NULL;
  114. pNewRoute = NULL;
  115. // Initialize other loop variables
  116. pBestDest = NULL;
  117. nextChild = 0;
  118. pPrevNode = STRUCT_OF(STrieNode, &pSTrie->trieRoot, child[0]);
  119. do {
  120. // Start this loop by advancing to the next child
  121. pCurrNode = pPrevNode->child[nextChild];
  122. if (pCurrNode == NULL) {
  123. // Case 1: Found a NULL - insert now
  124. // Make a copy of the incoming route
  125. NewRouteInSTrie(pSTrie, pNewRoute, pIncRoute);
  126. // Allocate a dest with the new route
  127. NewDestInSTrie(pSTrie, pNewRoute, pNewDest);
  128. // New node with bits left unmatched
  129. NewSTrieNode(pSTrie,
  130. pNewNode,
  131. bitsLeft,
  132. addrBits,
  133. pNewDest);
  134. // Stick it as the correct child of node
  135. pPrevNode->child[nextChild] = pNewNode;
  136. break;
  137. }
  138. // Number of bits to match in this trie node
  139. nextBits = pCurrNode->numBits;
  140. matchBits = (nextBits > bitsLeft) ? bitsLeft : nextBits;
  141. // Adjust next node bits for dist posn check
  142. // Get distinguishing postion for bit patterns
  143. distPos = PickDistPosition(pCurrNode->keyBits,
  144. addrBits,
  145. matchBits,
  146. tempBits);
  147. if (distPos == nextBits) {
  148. // Completely matches next node
  149. if (distPos == bitsLeft) {
  150. // We have exhausted all incoming bits
  151. if (!NULL_DEST(pCurrNode->dest)) {
  152. // Case 2: This trie node has a route
  153. // Insert in sorted order of metric
  154. pCurrDest = pCurrNode->dest;
  155. // Give a ptr to the old best route
  156. CopyRoutePtr(ppOldBestRoute, pCurrDest->firstRoute);
  157. pPrevRoute = NULL;
  158. pCurrRoute = pCurrDest->firstRoute;
  159. // Search for an adequate match (IF, NHop)
  160. do {
  161. // Use the flags to control matching
  162. if ((((matchFlags & MATCH_INTF) == 0) ||
  163. (IF(pCurrRoute) == IF(pIncRoute))) &&
  164. (((matchFlags & MATCH_NHOP) == 0) ||
  165. (NHOP(pCurrRoute) == NHOP(pIncRoute))))
  166. break;
  167. pPrevRoute = pCurrRoute;
  168. pCurrRoute = NEXT(pPrevRoute);
  169. }
  170. while (!NULL_ROUTE(pCurrRoute));
  171. if (NULL_ROUTE(pCurrRoute)) {
  172. // Case 2.1: No matching route
  173. // Create a new copy of route
  174. NewRouteInSTrie(pSTrie, pNewRoute, pIncRoute);
  175. } else {
  176. // Case 2.2: A Matching Route
  177. // Has the metric changed ?
  178. if (METRIC(pCurrRoute) != METRIC(pIncRoute)) {
  179. // Remove route from current position
  180. if (!NULL_ROUTE(pPrevRoute)) {
  181. // Remove it from middle of list
  182. NEXT(pPrevRoute) = NEXT(pCurrRoute);
  183. } else {
  184. // Remove from beginning of list
  185. pCurrDest->firstRoute = NEXT(pCurrRoute);
  186. }
  187. }
  188. // Keep the new/updated route for later
  189. pNewRoute = pCurrRoute;
  190. }
  191. if (NULL_ROUTE(pCurrRoute) ||
  192. (METRIC(pCurrRoute) != METRIC(pIncRoute))) {
  193. // Update metric for new / changing route
  194. METRIC(pNewRoute) = METRIC(pIncRoute);
  195. // Traverse list looking for new position
  196. pPrevRoute = NULL;
  197. pCurrRoute = pCurrDest->firstRoute;
  198. while (!NULL_ROUTE(pCurrRoute)) {
  199. if (METRIC(pCurrRoute) > METRIC(pIncRoute))
  200. break;
  201. pPrevRoute = pCurrRoute;
  202. pCurrRoute = NEXT(pPrevRoute);
  203. }
  204. // Insert at the new proper position
  205. NEXT(pNewRoute) = pCurrRoute;
  206. if (!NULL_ROUTE(pPrevRoute)) {
  207. // Insert in the middle of list
  208. NEXT(pPrevRoute) = pNewRoute;
  209. } else {
  210. // Insert at beginning of list
  211. pCurrDest->firstRoute = pNewRoute;
  212. }
  213. }
  214. // Give a ptr to newly inserted route
  215. CopyRoutePtr(ppInsRoute, pNewRoute);
  216. // Give a ptr to the old best dest
  217. CopyDestPtr(ppOldBestDest, pCurrDest);
  218. // Give a ptr to the new best dest
  219. CopyDestPtr(ppNewBestDest, pCurrDest);
  220. // Update the best routes cache on node
  221. CacheBestRoutesInDest(pCurrDest);
  222. return TRIE_SUCCESS;
  223. } else {
  224. // Case 3: This node was a marker
  225. // Create a new route & attach it
  226. // Create a new copy of this route
  227. NewRouteInSTrie(pSTrie, pNewRoute, pIncRoute);
  228. // Allocate a dest with the new route
  229. NewDestInSTrie(pSTrie, pNewRoute, pNewDest);
  230. // And attach dest to the marker node
  231. pCurrNode->dest = pNewDest;
  232. }
  233. break;
  234. } else {
  235. // Case 4: We still have bits left here
  236. // Go down for more specific match
  237. // Update node with best dest so far
  238. if (!NULL_DEST(pCurrNode->dest)) {
  239. pBestDest = pCurrNode->dest;
  240. }
  241. // Discard used bits for this iteration
  242. addrBits <<= matchBits;
  243. bitsLeft -= matchBits;
  244. // Prepare node for the next iteration
  245. pPrevNode = pCurrNode;
  246. // Bit 1 gives direction to search next
  247. nextChild = PickMostSigNBits(addrBits, 1);
  248. }
  249. } else {
  250. if (distPos == bitsLeft) {
  251. // Case 5: The route falls on this branch
  252. // Insert a new node in the same branch
  253. // Make a copy of the new route
  254. NewRouteInSTrie(pSTrie, pNewRoute, pIncRoute);
  255. // Allocate a dest with the new route
  256. NewDestInSTrie(pSTrie, pNewRoute, pNewDest);
  257. // New node with bits left unmatched
  258. NewSTrieNode(pSTrie,
  259. pNewNode,
  260. distPos,
  261. ShowMostSigNBits(addrBits, distPos),
  262. pNewDest);
  263. pPrevNode->child[nextChild] = pNewNode;
  264. // Adjust the next node - numbits etc
  265. pCurrNode->keyBits <<= distPos,
  266. pCurrNode->numBits -= distPos;
  267. // Stick next node in the correct child
  268. nextChild = PickMostSigNBits(pCurrNode->keyBits, 1);
  269. pNewNode->child[nextChild] = pCurrNode;
  270. break;
  271. } else {
  272. // Case 6: The route fragments the path
  273. // Create a new branch with two nodes
  274. // First make a copy of the new route
  275. NewRouteInSTrie(pSTrie, pNewRoute, pIncRoute);
  276. // Allocate a dest with the new route
  277. NewDestInSTrie(pSTrie, pNewRoute, pNewDest);
  278. // Branch node with non distinguishing bits
  279. NewSTrieNode(pSTrie,
  280. pOthNode,
  281. distPos,
  282. ShowMostSigNBits(addrBits, distPos),
  283. NULL);
  284. // A Leaf node with the distinguishing bits
  285. bitsLeft -= distPos;
  286. addrBits <<= distPos;
  287. NewSTrieNode(pSTrie,
  288. pNewNode,
  289. bitsLeft,
  290. addrBits,
  291. pNewDest);
  292. // Stick new branch node into the trie
  293. pPrevNode->child[nextChild] = pOthNode;
  294. // Set the children of the branch node
  295. // Adjust the next node - numbits etc
  296. pCurrNode->keyBits <<= distPos,
  297. pCurrNode->numBits -= distPos;
  298. // Stick next node in the correct child
  299. nextChild = PickMostSigNBits(pCurrNode->keyBits, 1);
  300. pOthNode->child[nextChild] = pCurrNode;
  301. // Stick new leaf node as the other child
  302. pOthNode->child[1 - nextChild] = pNewNode;
  303. break;
  304. }
  305. }
  306. }
  307. while (TRUE);
  308. // Give a ptr to the inserted route
  309. CopyRoutePtr(ppInsRoute, pNewRoute);
  310. // Give a ptr to the old best dest
  311. CopyDestPtr(ppOldBestDest, pBestDest);
  312. // Give a ptr to the old best route
  313. if (!NULL_DEST(pBestDest)) {
  314. CopyRoutePtr(ppOldBestRoute, pBestDest->firstRoute);
  315. }
  316. // Give a ptr to the new best dest
  317. CopyDestPtr(ppNewBestDest, pNewDest);
  318. // Route is the only route on dest
  319. if (pNewDest->maxBestRoutes > 0) {
  320. pNewDest->numBestRoutes = 1;
  321. pNewDest->bestRoutes[0] = pNewRoute;
  322. }
  323. return TRIE_SUCCESS;
  324. }
  325. ERR_BLOCK
  326. {
  327. // Not enough RESOURCES to add a new route
  328. // Free the memory for the new route alloc
  329. if (pNewRoute) {
  330. FreeRouteInSTrie(pSTrie, pNewRoute);
  331. }
  332. // Free memory for the dest on the new node
  333. if (pNewDest) {
  334. FreeDestInSTrie(pSTrie, pNewDest);
  335. }
  336. // Free the memory for the new tnode alloc
  337. if (pNewNode) {
  338. FreeSTrieNode(pSTrie, pNewNode);
  339. }
  340. // Free memory for any other new tnode alloc
  341. if (pOthNode) {
  342. FreeSTrieNode(pSTrie, pOthNode);
  343. }
  344. }
  345. END_BLOCK
  346. }
  347. UINT
  348. CALLCONV
  349. DeleteFromSTrie(IN STrie * pSTrie,
  350. IN Route * pIncRoute,
  351. IN ULONG matchFlags,
  352. OUT Route ** ppDelRoute,
  353. OUT Dest ** ppOldBestDest,
  354. OUT Dest ** ppNewBestDest,
  355. OUT Route ** ppOldBestRoute
  356. )
  357. /*++
  358. Routine Description:
  359. Deletes a route corresponding to an address
  360. prefix into a S-trie, and fills in best
  361. dest for addresses that match this prefix
  362. both before and after deletion of route.
  363. Arguments:
  364. pSTrie - Pointer to trie to delete from
  365. pIncRoute - Pointer to the incoming route
  366. matchFlags - Flags to direct route matching
  367. ppDelRoute - Pointer to the route deleted
  368. ppOldBestDest - Best dest before deletion
  369. ppNewBestDest - Best dest after deletion
  370. ppOldBestRoute - Best route before deletion
  371. Return Value:
  372. TRIE_SUCCESS or ERROR_TRIE_*
  373. --*/
  374. {
  375. STrieNode *pPrevNode;
  376. STrieNode *pCurrNode;
  377. STrieNode *pNextNode;
  378. STrieNode *pOtherNode;
  379. Dest *pBestDest;
  380. Dest *pCurrDest;
  381. Route *pPrevRoute;
  382. Route *pCurrRoute;
  383. ULONG addrBits;
  384. ULONG tempBits;
  385. UINT numBits;
  386. UINT nextBits;
  387. UINT matchBits;
  388. UINT bitsLeft;
  389. UINT distPos;
  390. UINT nextChild;
  391. UINT i, j;
  392. #if DBG
  393. if (!pSTrie) {
  394. Fatal("Delete Route: STrie not initialized",
  395. ERROR_TRIE_NOT_INITED);
  396. }
  397. #endif
  398. // Make sure input route is valid
  399. if (NULL_ROUTE(pIncRoute)) {
  400. Error("Delete Route: NULL or invalid route",
  401. ERROR_TRIE_BAD_PARAM);
  402. }
  403. if (LEN(pIncRoute) > ADDRSIZE) {
  404. Error("Delete Route: Invalid mask length",
  405. ERROR_TRIE_BAD_PARAM);
  406. }
  407. // Use addr bits to index the trie
  408. addrBits = RtlConvertEndianLong(DEST(pIncRoute));
  409. bitsLeft = LEN(pIncRoute);
  410. // Make sure addr and mask agree
  411. if (ShowMostSigNBits(addrBits, bitsLeft) != addrBits) {
  412. Error("Delete Route: Addr & mask don't agree",
  413. ERROR_TRIE_BAD_PARAM);
  414. }
  415. // Start going down the search trie
  416. pBestDest = NULL;
  417. nextChild = 0;
  418. pPrevNode = STRUCT_OF(STrieNode, &pSTrie->trieRoot, child[0]);
  419. do {
  420. // Start this loop by advancing to the next child
  421. pCurrNode = pPrevNode->child[nextChild];
  422. if (pCurrNode == NULL) {
  423. // Case 1: Found a NULL, end search
  424. // Route not found, return an error
  425. Error("Delete Route #0: Route not found",
  426. ERROR_TRIE_NO_ROUTES);
  427. }
  428. // Number of bits to match in this trie node
  429. nextBits = pCurrNode->numBits;
  430. matchBits = (nextBits > bitsLeft) ? bitsLeft : nextBits;
  431. // Adjust next node bits for dist posn check
  432. // Get distinguishing postion for bit patterns
  433. distPos = PickDistPosition(pCurrNode->keyBits,
  434. addrBits,
  435. matchBits,
  436. tempBits);
  437. if (distPos == nextBits) {
  438. // Completely matches next node
  439. if (distPos == bitsLeft) {
  440. // We have exhausted all incoming bits
  441. // End search, see if we found a route
  442. if (!NULL_DEST(pCurrNode->dest)) {
  443. pCurrDest = pCurrNode->dest;
  444. // This node starts a valid route list
  445. // Give a ptr to the old best dest
  446. CopyDestPtr(ppOldBestDest, pCurrDest);
  447. // Give a ptr to the old best route
  448. CopyRoutePtr(ppOldBestRoute, pCurrDest->firstRoute);
  449. // Give a ptr to the new best dest
  450. CopyDestPtr(ppNewBestDest, pCurrDest);
  451. // Match the rest by walking the list
  452. // sorted increasing order of metric
  453. pPrevRoute = NULL;
  454. pCurrRoute = pCurrDest->firstRoute;
  455. do {
  456. // Use the flags to control matching
  457. // N.B. Note that certain clients are not allowed
  458. // to delete local routes.
  459. if ((((matchFlags & MATCH_INTF) == 0) ||
  460. (IF(pCurrRoute) == IF(pIncRoute))) &&
  461. (((matchFlags & MATCH_NHOP) == 0) ||
  462. (NHOP(pCurrRoute) == NHOP(pIncRoute))) &&
  463. (((matchFlags & MATCH_EXCLUDE_LOCAL) == 0) ||
  464. (PROTO(pCurrRoute) != IRE_PROTO_LOCAL))) {
  465. // Case 2: Found an adequate match
  466. //* Do the actual deletion here *
  467. if (!NULL_ROUTE(pPrevRoute)) {
  468. // Delete from middle of the list
  469. NEXT(pPrevRoute) = NEXT(pCurrRoute);
  470. } else {
  471. // Delete from beginning of list
  472. pCurrDest->firstRoute = NEXT(pCurrRoute);
  473. }
  474. break;
  475. }
  476. pPrevRoute = pCurrRoute;
  477. pCurrRoute = NEXT(pPrevRoute);
  478. }
  479. while (!NULL_ROUTE(pCurrRoute));
  480. if (NULL_ROUTE(pCurrRoute)) {
  481. // Route not found, return an error
  482. Error("Delete Route #1: Route not found",
  483. ERROR_TRIE_NO_ROUTES);
  484. }
  485. // Give a ptr to newly deleted route
  486. CopyRoutePtr(ppDelRoute, pCurrRoute);
  487. // Did the list become empty after deletion ?
  488. if (NULL_ROUTE(pCurrDest->firstRoute)) {
  489. // List is empty, so garbage collection
  490. // Give a ptr to the new best dest
  491. CopyDestPtr(ppNewBestDest, pBestDest);
  492. // Free destination as all routes gone
  493. FreeDestInSTrie(pSTrie, pCurrNode->dest);
  494. if (pCurrNode->child[0] && pCurrNode->child[1]) {
  495. // Case 3: Both children are non NULL
  496. // Just remove route from the node
  497. // Route already removed from node
  498. } else if (pCurrNode->child[0] || pCurrNode->child[1]) {
  499. // Case 4: One of the children is not NULL
  500. // Pull up lonely child in place of node
  501. // Pick the correct child to pull up
  502. if (pCurrNode->child[0])
  503. pNextNode = pCurrNode->child[0];
  504. else
  505. pNextNode = pCurrNode->child[1];
  506. // Child node bears bits of deleted node
  507. pNextNode->keyBits >>= pCurrNode->numBits;
  508. pNextNode->keyBits |= pCurrNode->keyBits;
  509. pNextNode->numBits += pCurrNode->numBits;
  510. pPrevNode->child[nextChild] = pNextNode;
  511. // Destroy trie node marked for deletion
  512. FreeSTrieNode(pSTrie, pCurrNode);
  513. } else {
  514. // Node to be deleted has no children
  515. if (&pPrevNode->child[nextChild] == &pSTrie->trieRoot) {
  516. // Case 5: Root node is being deleted
  517. // Detach node from trie root & delete
  518. // Just detach by removing the pointer
  519. pPrevNode->child[nextChild] = NULL;
  520. // Destroy trie node marked for deletion
  521. FreeSTrieNode(pSTrie, pCurrNode);
  522. } else {
  523. if (!NULL_DEST(pPrevNode->dest)) {
  524. // Case 6: Parent has a route on it
  525. // Detach child from parent & delete
  526. // Just detach by removing the pointer
  527. pPrevNode->child[nextChild] = NULL;
  528. // Destroy trie node marked for deletion
  529. FreeSTrieNode(pSTrie, pCurrNode);
  530. } else {
  531. // Case 7: Parent has no route on it
  532. // Pull up other child of parent node
  533. pOtherNode = pPrevNode->child[1 - nextChild];
  534. // Make sure no 1-way branching
  535. Assert(pOtherNode != NULL);
  536. // Parent node bears bits of sibling node
  537. pPrevNode->keyBits |=
  538. (pOtherNode->keyBits >>
  539. pPrevNode->numBits);
  540. pPrevNode->numBits += pOtherNode->numBits;
  541. // Move the route up too - move content
  542. pPrevNode->dest = pOtherNode->dest;
  543. pPrevNode->child[0] = pOtherNode->child[0];
  544. pPrevNode->child[1] = pOtherNode->child[1];
  545. FreeSTrieNode(pSTrie, pCurrNode);
  546. FreeSTrieNode(pSTrie, pOtherNode);
  547. }
  548. }
  549. }
  550. } else {
  551. // We still have some routes on the dest
  552. // Update the best routes cache on node
  553. CacheBestRoutesInDest(pCurrDest);
  554. }
  555. // Consider route as deleted at this point
  556. // FreeRouteInSTrie(pSTrie, pCurrRoute);
  557. break;
  558. } else {
  559. // Case 7: This node was a marker
  560. // No Route to delete in this node
  561. Error("Delete Route #2: Route not found",
  562. ERROR_TRIE_NO_ROUTES);
  563. }
  564. } else {
  565. // Case 8: We still have bits left here
  566. // Go down for more specific match
  567. // Update best value of route so far
  568. if (!NULL_DEST(pCurrNode->dest)) {
  569. pBestDest = pCurrNode->dest;
  570. }
  571. // Discard used bits for this iteration
  572. addrBits <<= matchBits;
  573. bitsLeft -= matchBits;
  574. // Prepare node for the next iteration
  575. pPrevNode = pCurrNode;
  576. // Bit 1 gives direction to search next
  577. nextChild = PickMostSigNBits(addrBits, 1);
  578. }
  579. } else {
  580. // Case 9: Did not match the next node
  581. // Route not found, fill next best
  582. Error("Delete Route #3: Route not found",
  583. ERROR_TRIE_NO_ROUTES);
  584. }
  585. }
  586. while (TRUE);
  587. return TRIE_SUCCESS;
  588. }
  589. UINT
  590. CALLCONV
  591. SearchRouteInSTrie(IN STrie * pSTrie,
  592. IN ULONG routeDest,
  593. IN ULONG routeMask,
  594. IN ULONG routeNHop,
  595. IN PVOID routeOutIF,
  596. IN ULONG matchFlags,
  597. OUT Route ** ppOutRoute)
  598. /*++
  599. Routine Description:
  600. Search for a specific route in an S-trie
  601. Arguments:
  602. pSTrie - Pointer to the S-trie to search
  603. routeDest - Dest of route being looked up
  604. routeMask - Mask of route being looked up
  605. routeNHop - NHop of route being looked up
  606. routeOutIF - Outgoing IF for this route
  607. matchFlags - Flags to direct route matching
  608. ppOutRoute - To return the best route match
  609. Return Value:
  610. TRIE_SUCCESS or ERROR_TRIE_*
  611. --*/
  612. {
  613. STrieNode *pPrevNode;
  614. STrieNode *pCurrNode;
  615. STrieNode *pNextNode;
  616. STrieNode *pOtherNode;
  617. Dest *pCurrDest;
  618. Dest *pBestDest;
  619. Route *pPrevRoute;
  620. Route *pCurrRoute;
  621. ULONG addrBits;
  622. ULONG tempBits;
  623. UINT numBits;
  624. UINT nextBits;
  625. UINT matchBits;
  626. UINT bitsLeft;
  627. UINT distPos;
  628. UINT nextChild;
  629. UINT bestMetric;
  630. UINT i, j;
  631. #if DBG
  632. if (!pSTrie) {
  633. Fatal("Search Route: STrie not initialized",
  634. ERROR_TRIE_NOT_INITED);
  635. }
  636. #endif
  637. *ppOutRoute = NULL;
  638. // Use addr bits to index the trie
  639. addrBits = RtlConvertEndianLong(routeDest);
  640. //* Assume an contiguous IP mask *
  641. tempBits = RtlConvertEndianLong(routeMask);
  642. bitsLeft = 0;
  643. while (tempBits != 0) {
  644. bitsLeft++;
  645. tempBits <<= 1;
  646. }
  647. // Make sure addr and mask agree
  648. if (ShowMostSigNBits(addrBits, bitsLeft) != addrBits) {
  649. Error("Search Route: Addr & mask don't agree",
  650. ERROR_TRIE_BAD_PARAM);
  651. }
  652. // Start going down the search trie
  653. pBestDest = NULL;
  654. nextChild = 0;
  655. pPrevNode = STRUCT_OF(STrieNode, &pSTrie->trieRoot, child[0]);
  656. do {
  657. // Start this loop by advancing to the next child
  658. pCurrNode = pPrevNode->child[nextChild];
  659. if (pCurrNode == NULL) {
  660. // Case 1: Found a NULL, end search
  661. // Route not found, fill next best
  662. // Give a copy of the next best route
  663. if (!NULL_DEST(pBestDest)) {
  664. CopyRoutePtr(ppOutRoute, pBestDest->firstRoute);
  665. }
  666. Error("Search Route #0: Route not found",
  667. ERROR_TRIE_NO_ROUTES);
  668. }
  669. // Number of bits to match in this trie node
  670. nextBits = pCurrNode->numBits;
  671. matchBits = (nextBits > bitsLeft) ? bitsLeft : nextBits;
  672. // Adjust next node bits for dist posn check
  673. // Get distinguishing postion for bit patterns
  674. distPos = PickDistPosition(pCurrNode->keyBits,
  675. addrBits,
  676. matchBits,
  677. tempBits);
  678. if (distPos == nextBits) {
  679. // Completely matches next node
  680. if (distPos == bitsLeft) {
  681. // We have exhausted all incoming bits
  682. // End search, see if we found a route
  683. if (!NULL_DEST(pCurrNode->dest)) {
  684. // This node starts a valid route list
  685. pCurrDest = pCurrNode->dest;
  686. // Match the rest by walking the list
  687. // sorted increasing order of metric
  688. pPrevRoute = NULL;
  689. pCurrRoute = pCurrDest->firstRoute;
  690. do {
  691. // Use the flags to control matching
  692. if ((((matchFlags & MATCH_INTF) == 0) ||
  693. (IF(pCurrRoute) == routeOutIF)) &&
  694. (((matchFlags & MATCH_NHOP) == 0) ||
  695. (NHOP(pCurrRoute) == routeNHop))) {
  696. // Found adequately matched route
  697. // Just copy the route and return
  698. CopyRoutePtr(ppOutRoute, pCurrRoute);
  699. return TRIE_SUCCESS;
  700. }
  701. pPrevRoute = pCurrRoute;
  702. pCurrRoute = NEXT(pPrevRoute);
  703. }
  704. while (!NULL_ROUTE(pCurrRoute));
  705. // Give a copy of the old route, or best route
  706. // for that prefix in case of no exact match
  707. if (NULL_ROUTE(pCurrRoute)) {
  708. CopyRoutePtr(ppOutRoute, pCurrDest->firstRoute);
  709. Error("Search Route #1: Route not found",
  710. ERROR_TRIE_NO_ROUTES);
  711. }
  712. break;
  713. } else {
  714. // Case 7: This node was a marker
  715. // No Route present in this node
  716. // Give a copy of the next best route
  717. if (!NULL_DEST(pBestDest)) {
  718. CopyRoutePtr(ppOutRoute, pBestDest->firstRoute);
  719. }
  720. Error("Search Route #2: Route not found",
  721. ERROR_TRIE_NO_ROUTES);
  722. }
  723. } else {
  724. // Case 8: We still have bits left here
  725. // Go down for more specific match
  726. // Update node with best dest so far
  727. if (!NULL_DEST(pCurrNode->dest)) {
  728. pBestDest = pCurrNode->dest;
  729. }
  730. // Discard used bits for this iteration
  731. addrBits <<= matchBits;
  732. bitsLeft -= matchBits;
  733. // Prepare node for the next iteration
  734. pPrevNode = pCurrNode;
  735. // Bit 1 gives direction to search next
  736. nextChild = PickMostSigNBits(addrBits, 1);
  737. }
  738. } else {
  739. // Case 9: Did not match the next node
  740. // Route not found, fill the next best
  741. // Give a copy of the next best route
  742. if (!NULL_DEST(pBestDest)) {
  743. CopyRoutePtr(ppOutRoute, pBestDest->firstRoute);
  744. }
  745. Error("Search Route #3: Route not found",
  746. ERROR_TRIE_NO_ROUTES);
  747. }
  748. }
  749. while (TRUE);
  750. return TRIE_SUCCESS;
  751. }
  752. Dest *
  753. CALLCONV
  754. SearchAddrInSTrie(IN STrie * pSTrie,
  755. IN ULONG Addr)
  756. /*++
  757. Routine Description:
  758. Search for an address in an S-trie
  759. Arguments:
  760. pSTrie - Pointer to the trie to search
  761. Addr - Pointer to addr being queried
  762. Return Value:
  763. Return best route match for this address
  764. --*/
  765. {
  766. STrieNode *pCurrNode;
  767. Dest *pBestDest;
  768. UINT nextChild;
  769. ULONG addrBits;
  770. ULONG keyMask;
  771. ULONG keyBits;
  772. #if DBG
  773. if (!pSTrie) {
  774. Fatal("Search Addr: STrie not initialized",
  775. ERROR_TRIE_NOT_INITED);
  776. }
  777. #endif
  778. addrBits = RtlConvertEndianLong(Addr);
  779. // Start going down the search trie
  780. pBestDest = NULL;
  781. nextChild = 0;
  782. pCurrNode = STRUCT_OF(STrieNode, &pSTrie->trieRoot, child[0]);
  783. do {
  784. // Start this loop by advancing to next child
  785. pCurrNode = pCurrNode->child[nextChild];
  786. if (pCurrNode == NULL) {
  787. // Case 1: Found a NULL, end search
  788. break;
  789. }
  790. // Mask of bits to use in this trie node
  791. keyMask = MaskBits(pCurrNode->numBits);
  792. // Value of non-masked bits to match now
  793. keyBits = pCurrNode->keyBits;
  794. // Try to match the bits with above mask
  795. if ((addrBits & keyMask) != keyBits) {
  796. // Case 2: Failed to match this node
  797. break;
  798. }
  799. // Update best value of route so far
  800. if (!NULL_DEST(pCurrNode->dest)) {
  801. pBestDest = pCurrNode->dest;
  802. }
  803. // Go down for more specific match
  804. addrBits <<= pCurrNode->numBits;
  805. // Bit 1 gives direction to search next
  806. nextChild = PickMostSigNBits(addrBits, 1);
  807. }
  808. while (TRUE);
  809. return pBestDest;
  810. }
  811. UINT
  812. CALLCONV
  813. IterateOverSTrie(IN STrie * pSTrie,
  814. IN STrieCtxt * pCtxt,
  815. OUT Route ** ppRoute,
  816. OUT Dest** ppDest)
  817. /*++
  818. Routine Description:
  819. Get the next route in the S-Trie
  820. Arguments:
  821. pSTrie - Pointer to trie to iterate over
  822. pCtxt - Pointer to iterator context
  823. ppRoute - To return the next S-trie route
  824. ppDest - To return destinations instead of routes
  825. Return Value:
  826. TRIE_SUCCESS or ERROR_TRIE_*
  827. --*/
  828. {
  829. STrieNode *nodeInLevel[MAXLEVEL + 1];
  830. STrieNode *pPrevNode;
  831. STrieNode *pCurrNode;
  832. STrieNode *pNextNode;
  833. STrieNode *pOtherNode;
  834. Route *pPrevRoute;
  835. Route *pCurrRoute;
  836. ULONG addrBits;
  837. ULONG tempBits;
  838. UINT numLevels;
  839. UINT numBits;
  840. UINT nextBits;
  841. UINT matchBits;
  842. UINT bitsLeft;
  843. UINT distPos;
  844. UINT nextChild;
  845. UINT i, j;
  846. BOOLEAN routeToReturn;
  847. Dest *pCurrDest;
  848. #if DBG
  849. if (!pSTrie) {
  850. Fatal("Iterate Over STrie: STrie not initialized",
  851. ERROR_TRIE_NOT_INITED);
  852. }
  853. #endif
  854. // Check if the context is a valid one
  855. if (NULL_ROUTE(pCtxt->pCRoute)) {
  856. // NULL Context Case -- First Time
  857. // Do we have any routes at all ?
  858. if (pSTrie->trieRoot == NULL) {
  859. return ERROR_TRIE_NO_ROUTES;
  860. }
  861. // Start from the very beginning
  862. // Fill in actual context
  863. pCtxt->currAddr = 0;
  864. pCtxt->currALen = 0;
  865. pCurrDest = pSTrie->trieRoot->dest;
  866. pCtxt->pCRoute = pCurrDest ? pCurrDest->firstRoute : NULL;
  867. // Fill generated context
  868. numLevels = 1;
  869. nodeInLevel[0] = pSTrie->trieRoot;
  870. } else {
  871. // Non NULL Context -- Generate path
  872. // of current route from trie's root
  873. // Use addr bits to index the trie
  874. addrBits = RtlConvertEndianLong(pCtxt->currAddr);
  875. bitsLeft = pCtxt->currALen;
  876. #if DBG
  877. // Make sure addr and mask agree
  878. if (ShowMostSigNBits(addrBits, bitsLeft) != addrBits) {
  879. Fatal("Search Route: Addr & mask don't agree",
  880. ERROR_TRIE_BAD_PARAM);
  881. }
  882. #endif
  883. // Start going down the search trie
  884. numLevels = 0;
  885. nextChild = 0;
  886. pPrevNode = STRUCT_OF(STrieNode, &pSTrie->trieRoot, child[0]);
  887. do {
  888. // Start this loop by advancing to the next child
  889. pCurrNode = pPrevNode->child[nextChild];
  890. // Push pointer to this trie node into the stack
  891. nodeInLevel[numLevels++] = pCurrNode;
  892. // Valid context always matches all nodes exactly
  893. Assert(pCurrNode != NULL);
  894. // Get Number of bits to match in this trie node
  895. nextBits = pCurrNode->numBits;
  896. matchBits = (nextBits > bitsLeft) ? bitsLeft : nextBits;
  897. // Adjust next node bits for dist posn check
  898. // Get distinguishing postion for bit patterns
  899. distPos = PickDistPosition(pCurrNode->keyBits,
  900. addrBits,
  901. matchBits,
  902. tempBits);
  903. // Valid context always matches all nodes exactly
  904. Assert(distPos == nextBits);
  905. if (distPos == bitsLeft) {
  906. // We have exhausted all incoming bits
  907. // We should have found a route (list)
  908. pCurrDest = pCurrNode->dest;
  909. #if DBG
  910. // This node starts a valid route list
  911. Assert(pCurrDest);
  912. // Try matching the route in context
  913. pCurrRoute = pCurrDest->firstRoute;
  914. do {
  915. if (pCurrRoute == pCtxt->pCRoute) {
  916. break;
  917. }
  918. pCurrRoute = NEXT(pCurrRoute);
  919. }
  920. while (!NULL_ROUTE(pCurrRoute));
  921. // We should find a definite match
  922. Assert(!NULL_ROUTE(pCurrRoute));
  923. #endif // DBG
  924. // We have the full path from root to
  925. // current node in the stack of nodes
  926. break;
  927. }
  928. // We still have key bits left here
  929. // Go down for more specific match
  930. // Discard used bits for this iteration
  931. addrBits <<= matchBits;
  932. bitsLeft -= matchBits;
  933. // Prepare node for the next iteration
  934. pPrevNode = pCurrNode;
  935. // Bit 1 gives direction to search next
  936. nextChild = PickMostSigNBits(addrBits, 1);
  937. }
  938. while (TRUE);
  939. }
  940. // We have no routes to return at this point
  941. routeToReturn = FALSE;
  942. // Set direction to print route in context
  943. nextChild = LCHILD;
  944. do {
  945. // Get pointer to the current node & direction
  946. pCurrNode = nodeInLevel[numLevels - 1];
  947. // Return route its first time on top of stack
  948. if (nextChild == LCHILD) {
  949. pCurrRoute = pCtxt->pCRoute;
  950. if (!NULL_ROUTE(pCurrRoute)) {
  951. // We have a valid route to return
  952. routeToReturn = TRUE;
  953. if (ppDest) {
  954. CopyDestPtr(ppDest, pCurrDest);
  955. } else {
  956. CopyRoutePtr(ppRoute, pCurrRoute);
  957. // Got a valid next route - return
  958. pCtxt->pCRoute = NEXT(pCurrRoute);
  959. if (!NULL_ROUTE(NEXT(pCurrRoute))) {
  960. // Update the context and return
  961. pCtxt->currAddr = DEST(pCtxt->pCRoute);
  962. pCtxt->currALen = LEN(pCtxt->pCRoute);
  963. return ERROR_TRIE_NOT_EMPTY;
  964. }
  965. }
  966. // Search for the valid next route
  967. }
  968. }
  969. // Update the context to reflect an access
  970. switch (nextChild) {
  971. case LCHILD:
  972. // Push left child if not NULL
  973. pNextNode = pCurrNode->child[0];
  974. if (pNextNode != NULL) {
  975. // Push next level on the stack - Go Left
  976. nodeInLevel[numLevels++] = pNextNode;
  977. nextChild = LCHILD;
  978. pCtxt->pCRoute = pNextNode->dest
  979. ? pNextNode->dest->firstRoute
  980. : NULL;
  981. // Return if we have a route to send back
  982. // & we also have located the next route
  983. if ((routeToReturn) && !NULL_DEST(pNextNode->dest)) {
  984. // Update the context and return
  985. pCtxt->currAddr = DEST(pCtxt->pCRoute);
  986. pCtxt->currALen = LEN(pCtxt->pCRoute);
  987. return ERROR_TRIE_NOT_EMPTY;
  988. }
  989. continue;
  990. }
  991. case RCHILD:
  992. // Push right child if not NULL
  993. pNextNode = pCurrNode->child[1];
  994. if (pNextNode != NULL) {
  995. // Push next level on the stack - Go Left
  996. nodeInLevel[numLevels++] = pNextNode;
  997. nextChild = LCHILD;
  998. pCtxt->pCRoute = pNextNode->dest
  999. ? pNextNode->dest->firstRoute
  1000. : NULL;
  1001. // Return if we have a route to send back
  1002. // & we also have located the next route
  1003. if ((routeToReturn) && !NULL_DEST(pNextNode->dest)) {
  1004. // Update the context and return
  1005. pCtxt->currAddr = DEST(pCtxt->pCRoute);
  1006. pCtxt->currALen = LEN(pCtxt->pCRoute);
  1007. return ERROR_TRIE_NOT_EMPTY;
  1008. }
  1009. continue;
  1010. }
  1011. case PARENT:
  1012. // Pop node & calculate new direction
  1013. // Are we done iterating ?
  1014. if (--numLevels == 0) {
  1015. return TRIE_SUCCESS;
  1016. }
  1017. pPrevNode = nodeInLevel[numLevels - 1];
  1018. if (pPrevNode->child[0] == pCurrNode) {
  1019. nextChild = RCHILD;
  1020. } else {
  1021. nextChild = PARENT;
  1022. }
  1023. continue;
  1024. }
  1025. }
  1026. while (TRUE);
  1027. }
  1028. UINT
  1029. CALLCONV
  1030. IsSTrieIteratorValid(IN STrie * pSTrie,
  1031. IN STrieCtxt * pCtxt)
  1032. /*++
  1033. Routine Description:
  1034. Make sure that iterator's context is valid
  1035. Arguments:
  1036. pSTrie - Pointer to trie to iterate over
  1037. pCtxt - Pointer to iterator context
  1038. Return Value:
  1039. TRIE_SUCCESS or ERROR_TRIE_*
  1040. --*/
  1041. {
  1042. Route *pCurrRoute;
  1043. ULONG addrMask;
  1044. ULONG maskBits;
  1045. if (NULL_ROUTE(pCtxt->pCRoute)) {
  1046. // NULL Context Case
  1047. if (pSTrie->trieRoot != NULL) {
  1048. return TRIE_SUCCESS;
  1049. }
  1050. return ERROR_TRIE_NO_ROUTES;
  1051. } else {
  1052. // Non NULL Context
  1053. // Make sure current route is valid
  1054. // Search for a node with dest, len
  1055. // Generate mask from address length
  1056. maskBits = MaskBits(pCtxt->currALen);
  1057. // Convert endian - search needs it
  1058. addrMask = RtlConvertEndianLong(maskBits);
  1059. if (SearchRouteInSTrie(pSTrie,
  1060. pCtxt->currAddr,
  1061. addrMask,
  1062. 0, NULL,
  1063. MATCH_NONE,
  1064. &pCurrRoute) != TRIE_SUCCESS) {
  1065. return ERROR_TRIE_BAD_PARAM;
  1066. }
  1067. // Search for the route in context
  1068. while (!NULL_ROUTE(pCurrRoute)) {
  1069. if (pCurrRoute == pCtxt->pCRoute) {
  1070. return TRIE_SUCCESS;
  1071. }
  1072. pCurrRoute = NEXT(pCurrRoute);
  1073. }
  1074. return ERROR_TRIE_BAD_PARAM;
  1075. }
  1076. }
  1077. UINT
  1078. CALLCONV
  1079. CleanupSTrie(IN STrie * pSTrie)
  1080. /*++
  1081. Routine Description:
  1082. Deletes an S-trie if it is empty
  1083. Arguments:
  1084. ppSTrie - Ptr to the S-trie
  1085. Return Value:
  1086. TRIE_SUCCESS or ERROR_TRIE_*
  1087. --*/
  1088. {
  1089. // Zero the memory for the trie header
  1090. RtlZeroMemory(pSTrie, sizeof(STrie));
  1091. return TRIE_SUCCESS;
  1092. }
  1093. VOID
  1094. CALLCONV
  1095. CacheBestRoutesInDest(IN Dest * pDest)
  1096. /*++
  1097. Routine Description:
  1098. Updates a destination's best-routes cache
  1099. Arguments:
  1100. pDest - Ptr to the destination
  1101. Return Value:
  1102. none.
  1103. --*/
  1104. {
  1105. Route* pCurrRoute;
  1106. UINT bestMetric, i;
  1107. if (!(pCurrRoute = pDest->firstRoute)) {
  1108. return;
  1109. }
  1110. // Get metric of the current best route, and store as many routes with the
  1111. // same metric as possible
  1112. bestMetric = METRIC(pCurrRoute);
  1113. for (i = 0; i < pDest->maxBestRoutes; i++) {
  1114. if (NULL_ROUTE(pCurrRoute) || (METRIC(pCurrRoute) != bestMetric)) {
  1115. break;
  1116. }
  1117. pDest->bestRoutes[i] = pCurrRoute;
  1118. pCurrRoute = NEXT(pCurrRoute);
  1119. }
  1120. pDest->numBestRoutes = (USHORT) i;
  1121. }
  1122. #if DBG
  1123. VOID
  1124. CALLCONV
  1125. PrintSTrie(IN STrie * pSTrie,
  1126. IN UINT printFlags)
  1127. /*++
  1128. Routine Description:
  1129. Print an S-Trie
  1130. Arguments:
  1131. pSTrie - Pointer to the S-Trie
  1132. printFlags - Information to print
  1133. Return Value:
  1134. None
  1135. --*/
  1136. {
  1137. if (pSTrie == NULL) {
  1138. Print("%s", "Uninitialized STrie\n\n");
  1139. return;
  1140. }
  1141. if ((printFlags & SUMM) == SUMM) {
  1142. Print("\n\n/***Slow-Trie------------------------------------------------");
  1143. Print("\n/***---------------------------------------------------------\n");
  1144. }
  1145. if (printFlags & POOL) {
  1146. Print("Available Memory: %10lu\n\n", pSTrie->availMemory);
  1147. }
  1148. if (printFlags & STAT) {
  1149. Print("Statistics:\n\n");
  1150. Print("Total Number of Nodes : %d\n", pSTrie->numNodes);
  1151. Print("Total Number of Routes: %d\n", pSTrie->numRoutes);
  1152. Print("Total Number of Dests : %d\n", pSTrie->numDests);
  1153. }
  1154. if (printFlags & TRIE) {
  1155. if (pSTrie->trieRoot == NULL) {
  1156. Print("\nEmpty STrie\n");
  1157. } else {
  1158. PrintSTrieNode(pSTrie->trieRoot);
  1159. }
  1160. }
  1161. if ((printFlags & SUMM) == SUMM) {
  1162. Print("\n---------------------------------------------------------***/\n");
  1163. Print("---------------------------------------------------------***/\n\n");
  1164. }
  1165. }
  1166. VOID
  1167. CALLCONV
  1168. PrintSTrieNode(IN STrieNode * pSTrieNode)
  1169. /*++
  1170. Routine Description:
  1171. Print an S-trie node
  1172. Arguments:
  1173. pSTrieNode - Pointer to the S-trie node
  1174. Return Value:
  1175. None
  1176. --*/
  1177. {
  1178. if (pSTrieNode == NULL) {
  1179. return;
  1180. }
  1181. Print("\n--------------------------------------------------------\n");
  1182. Print("Child @ %08x", pSTrieNode);
  1183. Print("\n--------------------------------------------------------\n");
  1184. Print("Key: Num of Bits : %8d, Value of Bits: %08x\n",
  1185. pSTrieNode->numBits,
  1186. pSTrieNode->keyBits);
  1187. if (NULL_DEST(pSTrieNode->dest)) {
  1188. Print("NULL Dest\n");
  1189. } else {
  1190. PrintDest(pSTrieNode->dest);
  1191. }
  1192. Print("Children: On the left %08x, On the right %08x\n",
  1193. pSTrieNode->child[0],
  1194. pSTrieNode->child[1]);
  1195. Print("\n--------------------------------------------------------\n");
  1196. Print("\n\n");
  1197. PrintSTrieNode(pSTrieNode->child[0]);
  1198. PrintSTrieNode(pSTrieNode->child[1]);
  1199. }
  1200. #endif // DBG