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.

714 lines
17 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. lookup.c
  5. Abstract:
  6. This module contains routines for a wrapper
  7. that integrates the trie lookup into TCPIP.
  8. Author:
  9. Chaitanya Kodeboyina (chaitk) 11-Dec-1997
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #include "lookup.h"
  14. #include "info.h"
  15. // Wrapper Constants
  16. // MaskBitsArr[i] = First 'i' bits set to 1 in an unsigned long
  17. const ULONG MaskBitsArr[] =
  18. {
  19. 0x00000000, 0x80000000, 0xC0000000, 0xE0000000,
  20. 0xF0000000, 0xF8000000, 0xFC000000, 0xFE000000,
  21. 0xFF000000, 0xFF800000, 0xFFC00000, 0xFFE00000,
  22. 0xFFF00000, 0xFFF80000, 0xFFFC0000, 0xFFFE0000,
  23. 0xFFFF0000, 0xFFFF8000, 0xFFFFC000, 0xFFFFE000,
  24. 0xFFFFF000, 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00,
  25. 0xFFFFFF00, 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0,
  26. 0xFFFFFFF0, 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE,
  27. 0xFFFFFFFF
  28. };
  29. // Wrapper Globals
  30. // IP Route Table
  31. Trie *RouteTable;
  32. // Eq Cost Routes
  33. USHORT MaxEqualCostRoutes = 0;
  34. extern uint DefGWActive;
  35. extern uint DefGWConfigured;
  36. extern uint ValidateDefaultGWs(IPAddr Addr);
  37. UINT
  38. InsRoute(IPAddr Dest, IPMask Mask, IPAddr FirstHop, VOID * OutIF,
  39. UINT Metric, ULONG MatchFlags, RouteTableEntry ** ppInsRTE,
  40. RouteTableEntry ** ppOldBestRTE, RouteTableEntry ** ppNewBestRTE)
  41. /*++
  42. Routine Description:
  43. Inserts a route into the route table
  44. We update only
  45. 1) Dest Addr,
  46. 2) Dest Mask,
  47. 3) Priority,
  48. 4) Route Metric
  49. The rest of the RTE fields are left
  50. untouched - to enable the caller to
  51. read the old values (if this route
  52. already existed in the route table)
  53. Arguments:
  54. IN -
  55. Dest - Destination IP Addr
  56. Mask - Destination IP Mask
  57. FirstHop - IP Addr of Next Hop
  58. OutIF - Outgoing Interface
  59. Metric - Metric for the route
  60. MatchFlags - RTE Fields to match
  61. OUT -
  62. ppInsRTE - Ptr to Ptr to new/updated RTE
  63. ppOldBestRTE - Ptr to Ptr to old best RTE
  64. ppNewBestRTE - Ptr to Ptr to new best RTE
  65. Return Value:
  66. STATUS_SUCCESS or Error Code
  67. --*/
  68. {
  69. Route route;
  70. ULONG temp;
  71. DEST(&route) = Dest;
  72. MASK(&route) = Mask;
  73. NHOP(&route) = FirstHop;
  74. IF(&route) = OutIF;
  75. temp = RtlConvertEndianLong(Mask);
  76. LEN(&route) = 0;
  77. while (temp != 0) {
  78. LEN(&route)++;
  79. temp <<= 1;
  80. }
  81. METRIC(&route) = Metric;
  82. switch (InsertIntoTrie(RouteTable, &route, MatchFlags,
  83. ppInsRTE, ppOldBestRTE, ppNewBestRTE)) {
  84. case TRIE_SUCCESS:
  85. return IP_SUCCESS;
  86. case ERROR_TRIE_BAD_PARAM:
  87. return IP_BAD_REQ;
  88. case ERROR_TRIE_RESOURCES:
  89. return IP_NO_RESOURCES;
  90. }
  91. Assert(FALSE);
  92. return IP_GENERAL_FAILURE;
  93. }
  94. UINT
  95. DelRoute(IPAddr Dest, IPMask Mask, IPAddr FirstHop, VOID * OutIF,
  96. ULONG MatchFlags, RouteTableEntry ** ppDelRTE,
  97. RouteTableEntry ** ppOldBestRTE, RouteTableEntry ** ppNewBestRTE)
  98. /*++
  99. Routine Description:
  100. Deletes a route from the route table
  101. The memory for the route(allocated
  102. on the heap) should be deallocated
  103. upon return, after all information
  104. required is read and processed.
  105. Arguments:
  106. IN -
  107. Dest - Destination IP Addr
  108. Mask - Destination IP Mask
  109. FirstHop - IP Addr of Next Hop
  110. OutIF - Outgoing Interface
  111. Metric - Metric for the route
  112. MatchFlags - RTE Fields to match
  113. OUT -
  114. ppDelRTE - Ptr to Ptr to the deleted RTE
  115. ppOldBestRTE - Ptr to Ptr to old best RTE
  116. ppNewBestRTE - Ptr to Ptr to new best RTE
  117. Return Value:
  118. STATUS_SUCCESS or Error Code
  119. --*/
  120. {
  121. Route route;
  122. ULONG temp;
  123. DEST(&route) = Dest;
  124. MASK(&route) = Mask;
  125. NHOP(&route) = FirstHop;
  126. IF(&route) = OutIF;
  127. temp = RtlConvertEndianLong(Mask);
  128. LEN(&route) = 0;
  129. while (temp != 0) {
  130. LEN(&route)++;
  131. temp <<= 1;
  132. }
  133. switch (DeleteFromTrie(RouteTable, &route, MatchFlags,
  134. ppDelRTE, ppOldBestRTE, ppNewBestRTE)) {
  135. case TRIE_SUCCESS:
  136. return IP_SUCCESS;
  137. case ERROR_TRIE_NO_ROUTES:
  138. return IP_BAD_ROUTE;
  139. case ERROR_TRIE_BAD_PARAM:
  140. return IP_BAD_REQ;
  141. case ERROR_TRIE_RESOURCES:
  142. return IP_NO_RESOURCES;
  143. }
  144. Assert(FALSE);
  145. return IP_GENERAL_FAILURE;
  146. }
  147. RouteTableEntry *
  148. FindRTE(IPAddr Dest, IPAddr Source, UINT Index, UINT MaxPri, UINT MinPri, UINT UnicastIf)
  149. /*++
  150. Routine Description:
  151. Searches for a route given a prefix,
  152. with a mask len between the given
  153. minimum and maximum values.
  154. The route returned is a Semi-Read-
  155. Only-Version. The following fields
  156. should be changed only by calling
  157. the InsRoute function -
  158. 1) Next,
  159. 2) Dest,
  160. 3) Mask,
  161. 4) Priority, &
  162. 5) Route Metric.
  163. Remaining fields can be changed by
  164. directly modifying returned route.
  165. Arguments:
  166. IN -
  167. Dest - Destination IP Addr
  168. Source - Source to match IF
  169. Index - *Value is ignored*
  170. MaxPri - Max mask len of RTE
  171. MinPri - Min mask len of RTE
  172. Return Value:
  173. Matching RTE or NULL if not match
  174. --*/
  175. {
  176. RouteTableEntry *pBestRoute;
  177. RouteTableEntry *pCurrRoute;
  178. ULONG addr;
  179. ULONG mask;
  180. INT lookupPri;
  181. // Start looking for most specific match
  182. lookupPri = MaxPri;
  183. do {
  184. // Use lookupPri to mask xs bits
  185. addr = RtlConvertEndianLong(Dest);
  186. addr = ShowMostSigNBits(addr, lookupPri);
  187. Dest = RtlConvertEndianLong(addr);
  188. addr = ShowMostSigNBits(~0, lookupPri);
  189. mask = RtlConvertEndianLong(addr);
  190. // Try to match destination
  191. SearchRouteInTrie(RouteTable,
  192. Dest,
  193. mask,
  194. 0, NULL,
  195. MATCH_NONE,
  196. &pBestRoute);
  197. if ((NULL_ROUTE(pBestRoute)) || (LEN(pBestRoute) < MinPri)) {
  198. return NULL;
  199. }
  200. // Just in case we need to loop
  201. lookupPri = LEN(pBestRoute) - 1;
  202. // Search for a valid route
  203. while (pBestRoute) {
  204. if ((FLAGS(pBestRoute) & RTE_VALID) && (!(FLAGS(pBestRoute) & RTE_DEADGW)))
  205. break;
  206. pBestRoute = NEXT(pBestRoute);
  207. }
  208. // Do we match source too ?
  209. if (!IP_ADDR_EQUAL(Source, NULL_IP_ADDR) || UnicastIf) {
  210. // Dest match - Match source
  211. pCurrRoute = pBestRoute;
  212. while (pCurrRoute) {
  213. if (!UnicastIf) {
  214. if (METRIC(pCurrRoute) > METRIC(pBestRoute)) {
  215. // No Source match
  216. break;
  217. }
  218. }
  219. // Get next valid route
  220. if (((FLAGS(pCurrRoute) & RTE_VALID) && (!(FLAGS(pCurrRoute) & RTE_DEADGW))) &&
  221. ((!IP_ADDR_EQUAL(Source, NULL_IP_ADDR) &&
  222. AddrOnIF(IF(pCurrRoute), Source)) ||
  223. (UnicastIf &&
  224. IF(pCurrRoute)->if_index == UnicastIf))) {
  225. // Source match too
  226. pBestRoute = pCurrRoute;
  227. break;
  228. }
  229. pCurrRoute = NEXT(pCurrRoute);
  230. }
  231. if (UnicastIf && (pCurrRoute == NULL)) {
  232. pBestRoute = NULL;
  233. }
  234. }
  235. }
  236. while ((NULL_ROUTE(pBestRoute)) && (lookupPri >= (INT) MinPri));
  237. return pBestRoute;
  238. }
  239. RouteTableEntry *
  240. LookupRTE(IPAddr Dest, IPAddr Source, UINT MaxPri, UINT UnicastIf)
  241. /*++
  242. Routine Description:
  243. Searches for a best route for IP addr.
  244. The route returned is a Semi-Read-
  245. Only-Version. The following fields
  246. should be changed only by calling
  247. the InsRoute function -
  248. 1) Next,
  249. 2) Dest,
  250. 3) Mask,
  251. 4) Priority, &
  252. 5) Route Metric.
  253. Remaining fields can be changed by
  254. directly modifying returned route.
  255. Comments:
  256. *LookupRTE* assumes that VALID flag
  257. can be set on/off only for default
  258. routes. Because in case we find a
  259. chain with all invalid routes we do
  260. not enough information to go up in
  261. the F-trie for less specific routes
  262. Arguments:
  263. IN -
  264. Dest - Destination IP Addr
  265. Source - Source to match IF
  266. MaxPri - *Value is ignored*
  267. Return Value:
  268. Matching RTE or NULL if not match
  269. --*/
  270. {
  271. DestinationEntry *pBestDest;
  272. RouteTableEntry *pBestRoute;
  273. RouteTableEntry *pCurrRoute;
  274. UINT routeIndex;
  275. // Try to match destination
  276. pBestDest = SearchAddrInTrie(RouteTable, Dest);
  277. // No prefix match - quit
  278. if (pBestDest == NULL) {
  279. return NULL;
  280. }
  281. // Search for a valid route
  282. pBestRoute = pBestDest->firstRoute;
  283. while (pBestRoute) {
  284. if ((FLAGS(pBestRoute) & RTE_VALID) && (!(FLAGS(pBestRoute) & RTE_DEADGW)))
  285. break;
  286. pBestRoute = NEXT(pBestRoute);
  287. }
  288. // Do we match source too ?
  289. if (!IP_ADDR_EQUAL(Source, NULL_IP_ADDR) || UnicastIf) {
  290. // Dest match - Match source
  291. pCurrRoute = pBestRoute;
  292. while (pCurrRoute) {
  293. // Are we doing a weak host lookup ?
  294. if (!UnicastIf) {
  295. if (METRIC(pCurrRoute) > METRIC(pBestRoute)) {
  296. // No Source match
  297. break;
  298. }
  299. }
  300. // Get next valid route
  301. if (((FLAGS(pCurrRoute) & RTE_VALID) && (!(FLAGS(pCurrRoute) & RTE_DEADGW))) &&
  302. ((!IP_ADDR_EQUAL(Source, NULL_IP_ADDR) &&
  303. AddrOnIF(IF(pCurrRoute), Source)) ||
  304. (UnicastIf &&
  305. IF(pCurrRoute)->if_index == UnicastIf))) {
  306. // Source match too
  307. pBestRoute = pCurrRoute;
  308. break;
  309. }
  310. pCurrRoute = NEXT(pCurrRoute);
  311. }
  312. }
  313. // All routes on the list might be invalid
  314. // Fault to the slow path that backtracks
  315. // Or we want to do a strong host routing and haven't found the match
  316. if ((pBestRoute == NULL) || (UnicastIf && (pCurrRoute == NULL))) {
  317. return FindRTE(Dest, Source, 0, HOST_ROUTE_PRI, DEFAULT_ROUTE_PRI, UnicastIf);
  318. }
  319. return pBestRoute;
  320. }
  321. RouteTableEntry *
  322. LookupForwardRTE(IPAddr Dest, IPAddr Source, BOOLEAN Multipath)
  323. /*++
  324. Routine Description:
  325. Searches for a best route for IP addr
  326. on the forward path. If Multipath is
  327. TRUE, it does a hash on the source and
  328. dest addr. to pick one of the best
  329. routes to the destination. This enables
  330. the network to be utilized effectively
  331. by providing load balancing.
  332. Comments:
  333. *LookupRTE* assumes that VALID flag
  334. can be set on/off only for default
  335. routes. Because in case we find a
  336. chain with all invalid routes we do
  337. not enough information to go up in
  338. the F-trie for less specific routes
  339. Arguments:
  340. IN -
  341. Dest - Destination IP Addr
  342. Source - Source IP Addr
  343. Multipath - To do a equal cost multipath lookup or not
  344. Return Value:
  345. Matching RTE or NULL if not match
  346. --*/
  347. {
  348. DestinationEntry *pBestDest;
  349. RouteTableEntry *pBestRoute;
  350. UINT hashValue;
  351. UINT routeIndex;
  352. UINT i;
  353. // Try to match destination
  354. pBestDest = SearchAddrInTrie(RouteTable, Dest);
  355. // No prefix match - quit
  356. if (pBestDest == NULL) {
  357. return NULL;
  358. }
  359. // Search for a valid route
  360. pBestRoute = pBestDest->firstRoute;
  361. if (Multipath) {
  362. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"\nIn Fwd RTE:\n Max = %d, Num = %d\n",
  363. pBestDest->maxBestRoutes,
  364. pBestDest->numBestRoutes));
  365. // Get best route on dest from best routes' cache
  366. if (pBestDest->numBestRoutes > 1) {
  367. // Hash on the src, dest to get best route
  368. hashValue = Source + Dest;
  369. hashValue += (hashValue >> 16);
  370. hashValue += (hashValue >> 8);
  371. routeIndex = ((USHORT) hashValue) % pBestDest->numBestRoutes;
  372. pBestRoute = pBestDest->bestRoutes[routeIndex];
  373. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"S = %08x, D = %08x\nH = %08x, I = %d\nR = %p, N = %08x\n\n",
  374. Source,
  375. Dest,
  376. hashValue,
  377. routeIndex,
  378. pBestRoute,
  379. NHOP(pBestRoute)));
  380. if ((FLAGS(pBestRoute) & RTE_VALID) && (!(FLAGS(pBestRoute) & RTE_DEADGW))) {
  381. return pBestRoute;
  382. }
  383. }
  384. // We do not want to match the source addr below
  385. Source = NULL_IP_ADDR;
  386. }
  387. // Search for a valid route
  388. pBestRoute = pBestDest->firstRoute;
  389. while (pBestRoute) {
  390. if ((FLAGS(pBestRoute) & RTE_VALID) &&
  391. (!(FLAGS(pBestRoute) & RTE_DEADGW)))
  392. break;
  393. pBestRoute = NEXT(pBestRoute);
  394. }
  395. // All routes on the list might be invalid
  396. // Fault to the slow path that backtracks
  397. if (pBestRoute == NULL) {
  398. return FindRTE(Dest, Source, 0, HOST_ROUTE_PRI, DEFAULT_ROUTE_PRI, 0);
  399. }
  400. return pBestRoute;
  401. }
  402. /*++
  403. Routine Description:
  404. Gets next route in the route-table.
  405. The route returned is a Semi-Read-
  406. Only-Version. The following fields
  407. should be changed only by calling
  408. the InsRoute function -
  409. 1) Next,
  410. 2) Dest,
  411. 3) Mask,
  412. 4) Priority, &
  413. 5) Route Metric.
  414. Remaining fields can be changed by
  415. directly modifying returned route.
  416. Arguments:
  417. IN -
  418. Context - Iterator Context,
  419. OUT -
  420. ppRoute - To return route
  421. Return Value:
  422. TRUE if more routes, FALSE if not
  423. --*/
  424. UINT
  425. GetNextRoute(VOID * Context, Route ** ppRoute)
  426. {
  427. UINT retVal;
  428. // Get Next Route
  429. retVal = IterateOverTrie(RouteTable, Context, ppRoute, NULL);
  430. // We have routes
  431. Assert(retVal != ERROR_TRIE_NO_ROUTES);
  432. // Return Status
  433. return (retVal == ERROR_TRIE_NOT_EMPTY) ? TRUE : FALSE;
  434. }
  435. /*++
  436. Routine Description:
  437. Enumerates all destinations in the route-table.
  438. Assumes RouteTableLock is held by the caller.
  439. Arguments:
  440. IN -
  441. Context - iterator context, zeroed to begin enumeration.
  442. OUT -
  443. ppDest - receives enumerated destination, if any.
  444. Return Value:
  445. TRUE if more destinations, FALSE otherwise.
  446. --*/
  447. UINT
  448. GetNextDest(VOID * Context, Dest ** ppDest)
  449. {
  450. UINT retVal;
  451. // Get Next Destination
  452. retVal = IterateOverTrie(RouteTable, Context, NULL, ppDest);
  453. return (retVal == ERROR_TRIE_NOT_EMPTY) ? TRUE : FALSE;
  454. }
  455. /*++
  456. Routine Description:
  457. Re-orders all routes in a destination's route-list.
  458. Assumes RouteTableLock is held by the caller.
  459. Arguments:
  460. IN -
  461. pDest - destination whose route-list is to be sorted
  462. Return Value:
  463. none.
  464. --*/
  465. VOID
  466. SortRoutesInDest(Dest* pDest)
  467. {
  468. Route* pFirstRoute;
  469. Route** ppCurrRoute;
  470. // Pick up the current head of the route list, and replace it with NULL.
  471. // We'll then rebuild the list by reinserting each item in order.
  472. if (!(pFirstRoute = pDest->firstRoute)) {
  473. return;
  474. }
  475. pDest->firstRoute = NULL;
  476. while (pFirstRoute) {
  477. Route* pNextRoute;
  478. uint FirstOrder, CurrOrder;
  479. if (FLAGS(pFirstRoute) & RTE_IF_VALID) {
  480. FirstOrder = IF(pFirstRoute)->if_order;
  481. } else {
  482. FirstOrder = MAXLONG;
  483. }
  484. for (ppCurrRoute = &pDest->firstRoute; *ppCurrRoute;
  485. ppCurrRoute = &NEXT(*ppCurrRoute)) {
  486. if (FLAGS(*ppCurrRoute) & RTE_IF_VALID) {
  487. CurrOrder = IF(*ppCurrRoute)->if_order;
  488. } else {
  489. CurrOrder = MAXLONG;
  490. }
  491. // N.B. The following sequence of comparisons ensure a *stable*
  492. // sort, which is important to minimize the impact of this routine
  493. // on ongoing sessions.
  494. if (METRIC(pFirstRoute) > METRIC(*ppCurrRoute)) {
  495. continue;
  496. } else if (METRIC(pFirstRoute) < METRIC(*ppCurrRoute)) {
  497. break;
  498. }
  499. if (FirstOrder < CurrOrder) {
  500. break;
  501. }
  502. }
  503. pNextRoute = NEXT(pFirstRoute);
  504. NEXT(pFirstRoute) = *ppCurrRoute;
  505. *ppCurrRoute = pFirstRoute;
  506. pFirstRoute = pNextRoute;
  507. }
  508. // Finally, reconstruct the array of best routes cached in the destination
  509. if (pDest->firstRoute) {
  510. CacheBestRoutesInDest(pDest);
  511. }
  512. }
  513. /*++
  514. Routine Description:
  515. Re-orders all routes in the route-list of the destination
  516. corresponding to a given route.
  517. Assumes RouteTableLock is held by the caller.
  518. Arguments:
  519. IN -
  520. pRTE - route whose destination's route-list is to be sorted
  521. Return Value:
  522. none.
  523. --*/
  524. VOID
  525. SortRoutesInDestByRTE(Route *pRTE)
  526. {
  527. Dest* pDest = SearchAddrInTrie(RouteTable, DEST(pRTE));
  528. if (pDest) {
  529. SortRoutesInDest(pDest);
  530. }
  531. }
  532. UINT
  533. RTValidateContext(VOID * Context, UINT * Valid)
  534. {
  535. UINT retVal;
  536. retVal = IsTrieIteratorValid(RouteTable, Context);
  537. switch (retVal) {
  538. case ERROR_TRIE_BAD_PARAM:
  539. *Valid = FALSE;
  540. return FALSE;
  541. case ERROR_TRIE_NO_ROUTES:
  542. *Valid = TRUE;
  543. return FALSE;
  544. case TRIE_SUCCESS:
  545. *Valid = TRUE;
  546. return TRUE;
  547. }
  548. return FALSE;
  549. }