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.

717 lines
18 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. UNREFERENCED_PARAMETER(Index);
  182. // Start looking for most specific match
  183. lookupPri = MaxPri;
  184. do {
  185. // Use lookupPri to mask xs bits
  186. addr = RtlConvertEndianLong(Dest);
  187. addr = ShowMostSigNBits(addr, lookupPri);
  188. Dest = RtlConvertEndianLong(addr);
  189. addr = ShowMostSigNBits(~0, lookupPri);
  190. mask = RtlConvertEndianLong(addr);
  191. // Try to match destination
  192. SearchRouteInTrie(RouteTable,
  193. Dest,
  194. mask,
  195. 0, NULL,
  196. MATCH_NONE,
  197. &pBestRoute);
  198. if ((NULL_ROUTE(pBestRoute)) || (LEN(pBestRoute) < MinPri)) {
  199. return NULL;
  200. }
  201. // Just in case we need to loop
  202. lookupPri = LEN(pBestRoute) - 1;
  203. // Search for a valid route
  204. while (pBestRoute) {
  205. if ((FLAGS(pBestRoute) & RTE_VALID) && (!(FLAGS(pBestRoute) & RTE_DEADGW)))
  206. break;
  207. pBestRoute = NEXT(pBestRoute);
  208. }
  209. // Do we match source too ?
  210. if (!IP_ADDR_EQUAL(Source, NULL_IP_ADDR) || UnicastIf) {
  211. // Dest match - Match source
  212. pCurrRoute = pBestRoute;
  213. while (pCurrRoute) {
  214. if (!UnicastIf) {
  215. if (METRIC(pCurrRoute) > METRIC(pBestRoute)) {
  216. // No Source match
  217. break;
  218. }
  219. }
  220. // Get next valid route
  221. if (((FLAGS(pCurrRoute) & RTE_VALID) && (!(FLAGS(pCurrRoute) & RTE_DEADGW))) &&
  222. ((!IP_ADDR_EQUAL(Source, NULL_IP_ADDR) &&
  223. AddrOnIF(IF(pCurrRoute), Source)) ||
  224. (UnicastIf &&
  225. IF(pCurrRoute)->if_index == UnicastIf))) {
  226. // Source match too
  227. pBestRoute = pCurrRoute;
  228. break;
  229. }
  230. pCurrRoute = NEXT(pCurrRoute);
  231. }
  232. if (UnicastIf && (pCurrRoute == NULL)) {
  233. pBestRoute = NULL;
  234. }
  235. }
  236. }
  237. while ((NULL_ROUTE(pBestRoute)) && (lookupPri >= (INT) MinPri));
  238. return pBestRoute;
  239. }
  240. RouteTableEntry *
  241. LookupRTE(IPAddr Dest, IPAddr Source, UINT MaxPri, UINT UnicastIf)
  242. /*++
  243. Routine Description:
  244. Searches for a best route for IP addr.
  245. The route returned is a Semi-Read-
  246. Only-Version. The following fields
  247. should be changed only by calling
  248. the InsRoute function -
  249. 1) Next,
  250. 2) Dest,
  251. 3) Mask,
  252. 4) Priority, &
  253. 5) Route Metric.
  254. Remaining fields can be changed by
  255. directly modifying returned route.
  256. Comments:
  257. *LookupRTE* assumes that VALID flag
  258. can be set on/off only for default
  259. routes. Because in case we find a
  260. chain with all invalid routes we do
  261. not enough information to go up in
  262. the F-trie for less specific routes
  263. Arguments:
  264. IN -
  265. Dest - Destination IP Addr
  266. Source - Source to match IF
  267. MaxPri - *Value is ignored*
  268. Return Value:
  269. Matching RTE or NULL if not match
  270. --*/
  271. {
  272. DestinationEntry *pBestDest;
  273. RouteTableEntry *pBestRoute;
  274. RouteTableEntry *pCurrRoute = NULL;
  275. UNREFERENCED_PARAMETER(MaxPri);
  276. // Try to match destination
  277. pBestDest = SearchAddrInTrie(RouteTable, Dest);
  278. // No prefix match - quit
  279. if (pBestDest == NULL) {
  280. return NULL;
  281. }
  282. // Search for a valid route
  283. pBestRoute = pBestDest->firstRoute;
  284. while (pBestRoute) {
  285. if ((FLAGS(pBestRoute) & RTE_VALID) && (!(FLAGS(pBestRoute) & RTE_DEADGW)))
  286. break;
  287. pBestRoute = NEXT(pBestRoute);
  288. }
  289. // Do we match source too ?
  290. if (!IP_ADDR_EQUAL(Source, NULL_IP_ADDR) || UnicastIf) {
  291. // Dest match - Match source
  292. pCurrRoute = pBestRoute;
  293. while (pCurrRoute) {
  294. // Are we doing a weak host lookup ?
  295. if (!UnicastIf) {
  296. if (METRIC(pCurrRoute) > METRIC(pBestRoute)) {
  297. // No Source match
  298. break;
  299. }
  300. }
  301. // Get next valid route
  302. if (((FLAGS(pCurrRoute) & RTE_VALID) && (!(FLAGS(pCurrRoute) & RTE_DEADGW))) &&
  303. ((!IP_ADDR_EQUAL(Source, NULL_IP_ADDR) &&
  304. AddrOnIF(IF(pCurrRoute), Source)) ||
  305. (UnicastIf &&
  306. IF(pCurrRoute)->if_index == UnicastIf))) {
  307. // Source match too
  308. pBestRoute = pCurrRoute;
  309. break;
  310. }
  311. pCurrRoute = NEXT(pCurrRoute);
  312. }
  313. }
  314. // All routes on the list might be invalid
  315. // Fault to the slow path that backtracks
  316. // Or we want to do a strong host routing and haven't found the match
  317. if ((pBestRoute == NULL) || (UnicastIf && (pCurrRoute == NULL))) {
  318. return FindRTE(Dest, Source, 0, HOST_ROUTE_PRI, DEFAULT_ROUTE_PRI, UnicastIf);
  319. }
  320. return pBestRoute;
  321. }
  322. RouteTableEntry *
  323. LookupForwardRTE(IPAddr Dest, IPAddr Source, BOOLEAN Multipath)
  324. /*++
  325. Routine Description:
  326. Searches for a best route for IP addr
  327. on the forward path. If Multipath is
  328. TRUE, it does a hash on the source and
  329. dest addr. to pick one of the best
  330. routes to the destination. This enables
  331. the network to be utilized effectively
  332. by providing load balancing.
  333. Comments:
  334. *LookupRTE* assumes that VALID flag
  335. can be set on/off only for default
  336. routes. Because in case we find a
  337. chain with all invalid routes we do
  338. not enough information to go up in
  339. the F-trie for less specific routes
  340. Arguments:
  341. IN -
  342. Dest - Destination IP Addr
  343. Source - Source IP Addr
  344. Multipath - To do a equal cost multipath lookup or not
  345. Return Value:
  346. Matching RTE or NULL if not match
  347. --*/
  348. {
  349. DestinationEntry *pBestDest;
  350. RouteTableEntry *pBestRoute;
  351. UINT hashValue;
  352. UINT routeIndex;
  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. pFirstRoute = pDest->firstRoute;
  473. if (!pFirstRoute) {
  474. return;
  475. }
  476. pDest->firstRoute = NULL;
  477. while (pFirstRoute) {
  478. Route* pNextRoute;
  479. uint FirstOrder, CurrOrder;
  480. if (FLAGS(pFirstRoute) & RTE_IF_VALID) {
  481. FirstOrder = IF(pFirstRoute)->if_order;
  482. } else {
  483. FirstOrder = MAXLONG;
  484. }
  485. for (ppCurrRoute = &pDest->firstRoute; *ppCurrRoute;
  486. ppCurrRoute = &NEXT(*ppCurrRoute)) {
  487. if (FLAGS(*ppCurrRoute) & RTE_IF_VALID) {
  488. CurrOrder = IF(*ppCurrRoute)->if_order;
  489. } else {
  490. CurrOrder = MAXLONG;
  491. }
  492. // N.B. The following sequence of comparisons ensure a *stable*
  493. // sort, which is important to minimize the impact of this routine
  494. // on ongoing sessions.
  495. if (METRIC(pFirstRoute) > METRIC(*ppCurrRoute)) {
  496. continue;
  497. } else if (METRIC(pFirstRoute) < METRIC(*ppCurrRoute)) {
  498. break;
  499. }
  500. if (FirstOrder < CurrOrder) {
  501. break;
  502. }
  503. }
  504. pNextRoute = NEXT(pFirstRoute);
  505. NEXT(pFirstRoute) = *ppCurrRoute;
  506. *ppCurrRoute = pFirstRoute;
  507. pFirstRoute = pNextRoute;
  508. }
  509. // Finally, reconstruct the array of best routes cached in the destination
  510. if (pDest->firstRoute) {
  511. CacheBestRoutesInDest(pDest);
  512. }
  513. }
  514. /*++
  515. Routine Description:
  516. Re-orders all routes in the route-list of the destination
  517. corresponding to a given route.
  518. Assumes RouteTableLock is held by the caller.
  519. Arguments:
  520. IN -
  521. pRTE - route whose destination's route-list is to be sorted
  522. Return Value:
  523. none.
  524. --*/
  525. VOID
  526. SortRoutesInDestByRTE(Route *pRTE)
  527. {
  528. Dest* pDest = SearchAddrInTrie(RouteTable, DEST(pRTE));
  529. if (pDest) {
  530. SortRoutesInDest(pDest);
  531. }
  532. }
  533. UINT
  534. RTValidateContext(VOID * Context, UINT * Valid)
  535. {
  536. UINT retVal;
  537. retVal = IsTrieIteratorValid(RouteTable, Context);
  538. switch (retVal) {
  539. case ERROR_TRIE_BAD_PARAM:
  540. *Valid = FALSE;
  541. return FALSE;
  542. case ERROR_TRIE_NO_ROUTES:
  543. *Valid = TRUE;
  544. return FALSE;
  545. case TRIE_SUCCESS:
  546. *Valid = TRUE;
  547. return TRUE;
  548. }
  549. return FALSE;
  550. }