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.

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