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.

836 lines
21 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. routing\ip\load.c
  5. Abstract:
  6. The Load functions load the appropriate caches. They all follow a
  7. somewhat similar algorithm. They figure out how much space is needed
  8. for the cache. If there is a need to allocate memory, that is done.
  9. Then they read the tables from stack or RTM. They keep track of the
  10. space in the cache as the dwTotalEntries and the actual number of
  11. entries as the dwValidEntries
  12. Revision History:
  13. Amritansh Raghav 7/8/95 Created
  14. --*/
  15. #include "allinc.h"
  16. int
  17. __cdecl
  18. CompareIpAddrRow(
  19. CONST VOID *pvElem1,
  20. CONST VOID *pvElem2
  21. )
  22. {
  23. int iRes;
  24. PMIB_IPADDRROW pRow1 = (PMIB_IPADDRROW)pvElem1;
  25. PMIB_IPADDRROW pRow2 = (PMIB_IPADDRROW)pvElem2;
  26. InetCmp(pRow1->dwAddr,
  27. pRow2->dwAddr,
  28. iRes);
  29. return iRes;
  30. }
  31. int
  32. __cdecl
  33. CompareIpForwardRow(
  34. CONST VOID *pvElem1,
  35. CONST VOID *pvElem2
  36. )
  37. {
  38. LONG lResult;
  39. PMIB_IPFORWARDROW pRow1 = (PMIB_IPFORWARDROW)pvElem1;
  40. PMIB_IPFORWARDROW pRow2 = (PMIB_IPFORWARDROW)pvElem2;
  41. if(InetCmp(pRow1->dwForwardDest,
  42. pRow2->dwForwardDest,
  43. lResult) isnot 0)
  44. {
  45. return lResult;
  46. }
  47. if(Cmp(pRow1->dwForwardProto,
  48. pRow2->dwForwardProto,
  49. lResult) isnot 0)
  50. {
  51. return lResult;
  52. }
  53. if(Cmp(pRow1->dwForwardPolicy,
  54. pRow2->dwForwardPolicy,
  55. lResult) isnot 0)
  56. {
  57. return lResult;
  58. }
  59. return InetCmp(pRow1->dwForwardNextHop,
  60. pRow2->dwForwardNextHop,
  61. lResult);
  62. }
  63. int
  64. __cdecl
  65. CompareIpNetRow(
  66. CONST VOID *pvElem1,
  67. CONST VOID *pvElem2
  68. )
  69. {
  70. LONG lResult;
  71. PMIB_IPNETROW pRow1 = (PMIB_IPNETROW)pvElem1;
  72. PMIB_IPNETROW pRow2 = (PMIB_IPNETROW)pvElem2;
  73. if(Cmp(pRow1->dwIndex,
  74. pRow2->dwIndex,
  75. lResult) isnot 0)
  76. {
  77. return lResult;
  78. }
  79. else
  80. {
  81. return InetCmp(pRow1->dwAddr,
  82. pRow2->dwAddr,
  83. lResult);
  84. }
  85. }
  86. //
  87. // Since all these are called from within UpdateCache, the appropriate
  88. // lock is already being held as a writer so dont try and grab locks here
  89. //
  90. DWORD
  91. LoadUdpTable(
  92. VOID
  93. )
  94. /*++
  95. Routine Description
  96. Loads the UDP cache from the stack
  97. Locks
  98. UDP Cache lock must be taken as writer
  99. Arguments
  100. None
  101. Return Value
  102. NO_ERROR
  103. --*/
  104. {
  105. DWORD dwResult;
  106. ULONG ulRowsPresent,ulRowsNeeded;
  107. MIB_UDPSTATS usInfo;
  108. dwResult = GetUdpStatsFromStack(&usInfo);
  109. if(dwResult isnot NO_ERROR)
  110. {
  111. Trace1(ERR,
  112. "LoadUdpTable: Error %d trying to to determine table size",
  113. dwResult);
  114. TraceLeave("LoadUdpTable");
  115. return dwResult;
  116. }
  117. ulRowsNeeded = usInfo.dwNumAddrs + SPILLOVER;
  118. ulRowsPresent = g_UdpInfo.dwTotalEntries;
  119. if((ulRowsNeeded > ulRowsPresent) or
  120. (ulRowsPresent - ulRowsNeeded > MAX_DIFF))
  121. {
  122. //
  123. // Need to allocate space
  124. //
  125. if(g_UdpInfo.pUdpTable)
  126. {
  127. HeapFree(g_hUdpHeap,
  128. HEAP_NO_SERIALIZE,
  129. g_UdpInfo.pUdpTable);
  130. }
  131. ulRowsPresent = ulRowsNeeded + MAX_DIFF;
  132. g_UdpInfo.pUdpTable = HeapAlloc(g_hUdpHeap,
  133. HEAP_NO_SERIALIZE,
  134. SIZEOF_UDPTABLE(ulRowsPresent));
  135. if(g_UdpInfo.pUdpTable is NULL)
  136. {
  137. Trace1(ERR,
  138. "LoadUdpTable: Error allocating %d bytes for Udp table",
  139. SIZEOF_UDPTABLE(ulRowsPresent));
  140. g_UdpInfo.dwTotalEntries = 0;
  141. TraceLeave("LoadUdpTable");
  142. return ERROR_NOT_ENOUGH_MEMORY;
  143. }
  144. g_UdpInfo.dwTotalEntries = ulRowsPresent;
  145. }
  146. dwResult = GetUdpTableFromStack(g_UdpInfo.pUdpTable,
  147. SIZEOF_UDPTABLE(ulRowsPresent),
  148. TRUE);
  149. if(dwResult isnot NO_ERROR)
  150. {
  151. Trace1(ERR,
  152. "LoadUdpTable: NtStatus %x getting UdpTable from stack",
  153. dwResult);
  154. g_UdpInfo.pUdpTable->dwNumEntries = 0;
  155. }
  156. return dwResult;
  157. }
  158. DWORD
  159. LoadTcpTable(
  160. VOID
  161. )
  162. /*++
  163. Routine Description
  164. Loads the TCP cache from the stack
  165. Locks
  166. TCP Cache lock must be taken as writer
  167. Arguments
  168. None
  169. Return Value
  170. NO_ERROR
  171. --*/
  172. {
  173. DWORD dwResult;
  174. ULONG ulRowsPresent,ulRowsNeeded;
  175. MIB_TCPSTATS tsInfo;
  176. dwResult = GetTcpStatsFromStack(&tsInfo);
  177. if(dwResult isnot NO_ERROR)
  178. {
  179. Trace1(ERR,
  180. "LoadTcpTable: Error %d trying to determince table size",
  181. dwResult);
  182. TraceLeave("LoadTcpTable");
  183. return dwResult;
  184. }
  185. ulRowsNeeded = tsInfo.dwNumConns + SPILLOVER;
  186. ulRowsPresent = g_TcpInfo.dwTotalEntries;
  187. if((ulRowsNeeded > ulRowsPresent) or
  188. (ulRowsPresent - ulRowsNeeded > MAX_DIFF))
  189. {
  190. if(g_TcpInfo.pTcpTable)
  191. {
  192. HeapFree(g_hTcpHeap,
  193. HEAP_NO_SERIALIZE,
  194. g_TcpInfo.pTcpTable);
  195. }
  196. ulRowsPresent = ulRowsNeeded + MAX_DIFF;
  197. g_TcpInfo.pTcpTable = HeapAlloc(g_hTcpHeap,
  198. HEAP_NO_SERIALIZE,
  199. SIZEOF_TCPTABLE(ulRowsPresent));
  200. if(g_TcpInfo.pTcpTable is NULL)
  201. {
  202. Trace1(ERR,
  203. "LoadTcpTable: Error allocating %d bytes for tcp table",
  204. SIZEOF_TCPTABLE(ulRowsPresent));
  205. g_TcpInfo.dwTotalEntries = 0;
  206. TraceLeave("LoadTcpTable");
  207. return ERROR_NOT_ENOUGH_MEMORY;
  208. }
  209. g_TcpInfo.dwTotalEntries = ulRowsPresent;
  210. }
  211. dwResult = GetTcpTableFromStack(g_TcpInfo.pTcpTable,
  212. SIZEOF_TCPTABLE(ulRowsPresent),
  213. TRUE);
  214. if(dwResult isnot NO_ERROR)
  215. {
  216. Trace1(ERR,
  217. "LoadTcpTable: NtStatus %x load TcpTable from stack",
  218. dwResult);
  219. g_TcpInfo.pTcpTable->dwNumEntries = 0;
  220. }
  221. return dwResult;
  222. }
  223. DWORD
  224. LoadIpAddrTable(
  225. VOID
  226. )
  227. /*++
  228. Routine Description
  229. Loads the IPAddress cache. Unlike the other functions, this cache is
  230. loaded from the BINDING list kept in user mode. The binding list is
  231. however kept in a hash table (with no thread linking all the addresses
  232. in lexicographic order). Thus we just copy out all the address and then
  233. run qsort() over them
  234. Locks
  235. The IP Address Cache lock must be taken as writer
  236. Arguments
  237. None
  238. Return Value
  239. NO_ERROR
  240. --*/
  241. {
  242. ULONG ulRowsPresent,ulRowsNeeded;
  243. DWORD dwIndex, i, j;
  244. PLIST_ENTRY pleNode;
  245. PADAPTER_INFO pBind;
  246. ENTER_READER(BINDING_LIST);
  247. ulRowsNeeded = g_ulNumBindings + SPILLOVER;
  248. ulRowsPresent = g_IpInfo.dwTotalAddrEntries;
  249. if((ulRowsNeeded > ulRowsPresent) or
  250. (ulRowsPresent - ulRowsNeeded > MAX_DIFF))
  251. {
  252. if(g_IpInfo.pAddrTable)
  253. {
  254. HeapFree(g_hIpAddrHeap,
  255. HEAP_NO_SERIALIZE,
  256. g_IpInfo.pAddrTable);
  257. }
  258. ulRowsPresent = ulRowsNeeded + MAX_DIFF;
  259. g_IpInfo.pAddrTable = HeapAlloc(g_hIpAddrHeap,
  260. HEAP_NO_SERIALIZE,
  261. SIZEOF_IPADDRTABLE(ulRowsPresent));
  262. if(g_IpInfo.pAddrTable is NULL)
  263. {
  264. EXIT_LOCK(ICB_LIST);
  265. Trace1(ERR,
  266. "LoadIpAddrTable: Error allocating %d bytes for table",
  267. SIZEOF_IPADDRTABLE(ulRowsPresent));
  268. g_IpInfo.dwTotalAddrEntries = 0;
  269. TraceLeave("LoadIpAddrTable");
  270. return ERROR_NOT_ENOUGH_MEMORY;
  271. }
  272. g_IpInfo.dwTotalAddrEntries = ulRowsPresent;
  273. }
  274. dwIndex = 0;
  275. for(i = 0;
  276. i < BINDING_HASH_TABLE_SIZE;
  277. i++)
  278. {
  279. for(pleNode = g_leBindingTable[i].Flink;
  280. pleNode isnot &g_leBindingTable[i];
  281. pleNode = pleNode->Flink)
  282. {
  283. pBind = CONTAINING_RECORD(pleNode,
  284. ADAPTER_INFO,
  285. leHashLink);
  286. if(!pBind->bBound)
  287. {
  288. continue;
  289. }
  290. //
  291. // If the nte is bound, but has no address, we still have
  292. // space for 1 address
  293. //
  294. for(j = 0;
  295. j < (pBind->dwNumAddresses? pBind->dwNumAddresses : 1);
  296. j++)
  297. {
  298. g_IpInfo.pAddrTable->table[dwIndex].dwIndex =
  299. pBind->dwIfIndex;
  300. g_IpInfo.pAddrTable->table[dwIndex].dwBCastAddr =
  301. pBind->dwBCastBit;
  302. g_IpInfo.pAddrTable->table[dwIndex].dwReasmSize =
  303. pBind->dwReassemblySize;
  304. g_IpInfo.pAddrTable->table[dwIndex].dwAddr =
  305. pBind->rgibBinding[j].dwAddress;
  306. g_IpInfo.pAddrTable->table[dwIndex].dwMask =
  307. pBind->rgibBinding[j].dwMask;
  308. g_IpInfo.pAddrTable->table[dwIndex].wType = 1;
  309. dwIndex++;
  310. }
  311. }
  312. }
  313. g_IpInfo.pAddrTable->dwNumEntries = dwIndex;
  314. EXIT_LOCK(BINDING_LIST);
  315. if(g_IpInfo.pAddrTable->dwNumEntries > 0)
  316. {
  317. qsort(g_IpInfo.pAddrTable->table,
  318. dwIndex,
  319. sizeof(MIB_IPADDRROW),
  320. CompareIpAddrRow);
  321. }
  322. return NO_ERROR;
  323. }
  324. DWORD
  325. LoadIpForwardTable(
  326. VOID
  327. )
  328. /*++
  329. Routine Description
  330. Loads the UDP cache from the stack
  331. Locks
  332. UDP Cache lock must be taken as writer
  333. Arguments
  334. None
  335. Return Value
  336. NO_ERROR
  337. --*/
  338. {
  339. HANDLE hRtmEnum;
  340. PHANDLE hRoutes;
  341. PRTM_NET_ADDRESS pDestAddr;
  342. PRTM_ROUTE_INFO pRoute;
  343. RTM_NEXTHOP_INFO nhiInfo;
  344. RTM_ENTITY_INFO entityInfo;
  345. DWORD dwCount;
  346. DWORD dwResult;
  347. DWORD dwRoutes;
  348. DWORD i,j;
  349. IPSNMPInfo ipsiInfo;
  350. ULONG ulRowsPresent,ulRowsNeeded;
  351. ULONG ulEntities;
  352. RTM_ADDRESS_FAMILY_INFO rtmAddrFamilyInfo;
  353. LPVOID Tmp;
  354. //
  355. // Get the number of destinations in the RTM's table
  356. //
  357. dwResult = RtmGetAddressFamilyInfo(0, // routerId
  358. AF_INET,
  359. &rtmAddrFamilyInfo,
  360. &ulEntities,
  361. NULL);
  362. if(dwResult isnot NO_ERROR)
  363. {
  364. Trace1(ERR,
  365. "LoadIpForwardTable: Error %d getting number of destinations",
  366. dwResult);
  367. return dwResult;
  368. }
  369. //
  370. // Use an enumeration to retrieve routes from RTM
  371. //
  372. dwResult = RtmCreateRouteEnum(g_hLocalRoute,
  373. NULL,
  374. RTM_VIEW_MASK_UCAST,
  375. RTM_ENUM_ALL_ROUTES,
  376. NULL,
  377. 0,
  378. NULL,
  379. 0,
  380. &hRtmEnum);
  381. if(dwResult isnot NO_ERROR)
  382. {
  383. Trace1(ERR,
  384. "LoadIpForwardTable: Error %d creating RTM enumeration handle",
  385. dwResult);
  386. return dwResult;
  387. }
  388. ulRowsNeeded = rtmAddrFamilyInfo.NumDests + SPILLOVER;
  389. ulRowsPresent = g_IpInfo.dwTotalForwardEntries;
  390. if((ulRowsNeeded > ulRowsPresent) or
  391. (ulRowsPresent - ulRowsNeeded > MAX_DIFF))
  392. {
  393. if(g_IpInfo.pForwardTable)
  394. {
  395. HeapFree(g_hIpForwardHeap,
  396. HEAP_NO_SERIALIZE,
  397. g_IpInfo.pForwardTable);
  398. }
  399. ulRowsPresent = ulRowsNeeded + MAX_DIFF;
  400. g_IpInfo.pForwardTable = HeapAlloc(g_hIpForwardHeap,
  401. HEAP_NO_SERIALIZE,
  402. SIZEOF_IPFORWARDTABLE(ulRowsPresent));
  403. if(g_IpInfo.pForwardTable is NULL)
  404. {
  405. Trace1(ERR,
  406. "LoadIpForwardTable: Error allocating %d bytes for forward table",
  407. SIZEOF_IPFORWARDTABLE(ulRowsPresent));
  408. g_IpInfo.dwTotalForwardEntries = 0;
  409. RtmDeleteEnumHandle(g_hLocalRoute, hRtmEnum);
  410. TraceLeave("LoadIpForwardTable");
  411. return ERROR_NOT_ENOUGH_MEMORY;
  412. }
  413. g_IpInfo.dwTotalForwardEntries = ulRowsPresent;
  414. }
  415. //
  416. // Routes are enum'ed from the RTM route table
  417. //
  418. pRoute = HeapAlloc(
  419. IPRouterHeap,
  420. 0,
  421. RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
  422. );
  423. if (pRoute == NULL)
  424. {
  425. TraceLeave("LoadIpForwardTable");
  426. return ERROR_NOT_ENOUGH_MEMORY;
  427. }
  428. pDestAddr = HeapAlloc(
  429. IPRouterHeap,
  430. 0,
  431. sizeof(RTM_NET_ADDRESS)
  432. );
  433. if (pDestAddr == NULL)
  434. {
  435. TraceLeave("LoadIpForwardTable");
  436. HeapFree(IPRouterHeap, 0, pRoute);
  437. return ERROR_NOT_ENOUGH_MEMORY;
  438. }
  439. hRoutes = HeapAlloc(
  440. IPRouterHeap,
  441. 0,
  442. g_rtmProfile.MaxHandlesInEnum * sizeof(HANDLE)
  443. );
  444. if (hRoutes == NULL)
  445. {
  446. TraceLeave("LoadIpForwardTable");
  447. HeapFree(IPRouterHeap, 0, pRoute);
  448. HeapFree(IPRouterHeap, 0, pDestAddr);
  449. return ERROR_NOT_ENOUGH_MEMORY;
  450. }
  451. dwCount = 0;
  452. do
  453. {
  454. // Get next set of routes in RTM table
  455. dwRoutes = g_rtmProfile.MaxHandlesInEnum;
  456. RtmGetEnumRoutes(g_hLocalRoute,
  457. hRtmEnum,
  458. &dwRoutes,
  459. hRoutes);
  460. for (i = 0; i < dwRoutes; i++)
  461. {
  462. // Get the route info given the route handle
  463. dwResult = RtmGetRouteInfo(g_hLocalRoute,
  464. hRoutes[i],
  465. pRoute,
  466. pDestAddr);
  467. // Route would have got deleted meanwhile
  468. if (dwResult isnot NO_ERROR)
  469. {
  470. continue;
  471. }
  472. // Process info for the route from above
  473. // This route with multiple next hops
  474. // might end up as multiple ip routes
  475. if(dwCount + pRoute->NextHopsList.NumNextHops
  476. > g_IpInfo.dwTotalForwardEntries)
  477. {
  478. //
  479. // Hmm - we accounted for spillover and still have extra routes
  480. // Lets double the route table
  481. //
  482. g_IpInfo.dwTotalForwardEntries =
  483. (g_IpInfo.dwTotalForwardEntries)<<1;
  484. // Are we still short in terms of number of routes required ?
  485. if (g_IpInfo.dwTotalForwardEntries <
  486. dwCount + pRoute->NextHopsList.NumNextHops)
  487. {
  488. g_IpInfo.dwTotalForwardEntries =
  489. dwCount + pRoute->NextHopsList.NumNextHops;
  490. }
  491. Tmp = HeapReAlloc(g_hIpForwardHeap,
  492. HEAP_NO_SERIALIZE,
  493. g_IpInfo.pForwardTable,
  494. SIZEOF_IPFORWARDTABLE(g_IpInfo.dwTotalForwardEntries));
  495. if( Tmp is NULL)
  496. {
  497. Trace1(ERR,
  498. "LoadIpForwardTable: Error reallocating %d bytes for forward table",
  499. SIZEOF_IPFORWARDTABLE(g_IpInfo.dwTotalForwardEntries));
  500. if (g_IpInfo.pForwardTable)
  501. {
  502. HeapFree(g_hIpForwardHeap,
  503. HEAP_NO_SERIALIZE,
  504. g_IpInfo.pForwardTable);
  505. }
  506. g_IpInfo.pForwardTable = NULL;
  507. g_IpInfo.dwTotalForwardEntries = 0;
  508. RtmReleaseRouteInfo(g_hLocalRoute, pRoute);
  509. RtmReleaseRoutes(g_hLocalRoute, dwRoutes, hRoutes);
  510. RtmDeleteEnumHandle(g_hLocalRoute, hRtmEnum);
  511. HeapFree(IPRouterHeap, 0, pRoute);
  512. HeapFree(IPRouterHeap, 0, pDestAddr);
  513. HeapFree(IPRouterHeap, 0, hRoutes);
  514. TraceLeave("LoadIpForwardTable");
  515. return ERROR_NOT_ENOUGH_MEMORY;
  516. }
  517. else
  518. {
  519. g_IpInfo.pForwardTable = Tmp;
  520. }
  521. }
  522. if (RtmGetEntityInfo(g_hLocalRoute,
  523. pRoute->RouteOwner,
  524. &entityInfo) is NO_ERROR)
  525. {
  526. // Try getting the nexthop information from the route
  527. for (j = 0; j < pRoute->NextHopsList.NumNextHops; j++)
  528. {
  529. if (RtmGetNextHopInfo(g_hLocalRoute,
  530. pRoute->NextHopsList.NextHops[j],
  531. &nhiInfo) is NO_ERROR)
  532. {
  533. ConvertRtmToRouteInfo(entityInfo.EntityId.EntityProtocolId,
  534. pDestAddr,
  535. pRoute,
  536. &nhiInfo,
  537. (PINTERFACE_ROUTE_INFO)&(g_IpInfo.pForwardTable->table[dwCount++]));
  538. RtmReleaseNextHopInfo(g_hLocalRoute, &nhiInfo);
  539. }
  540. }
  541. }
  542. RtmReleaseRouteInfo(g_hLocalRoute, pRoute);
  543. }
  544. RtmReleaseRoutes(g_hLocalRoute, dwRoutes, hRoutes);
  545. }
  546. while (dwRoutes != 0);
  547. RtmDeleteEnumHandle(g_hLocalRoute, hRtmEnum);
  548. g_IpInfo.pForwardTable->dwNumEntries = dwCount;
  549. if(dwCount > 0)
  550. {
  551. qsort(g_IpInfo.pForwardTable->table,
  552. dwCount,
  553. sizeof(MIB_IPFORWARDROW),
  554. CompareIpForwardRow);
  555. }
  556. HeapFree(IPRouterHeap, 0, pRoute);
  557. HeapFree(IPRouterHeap, 0, pDestAddr);
  558. HeapFree(IPRouterHeap, 0, hRoutes);
  559. return NO_ERROR;
  560. }
  561. DWORD
  562. LoadIpNetTable(
  563. VOID
  564. )
  565. /*++
  566. Routine Description
  567. Loads the UDP cache from the stack
  568. Locks
  569. UDP Cache lock must be taken as writer
  570. Arguments
  571. None
  572. Return Value
  573. NO_ERROR
  574. --*/
  575. {
  576. DWORD dwResult, i;
  577. BOOL fUpdate;
  578. //
  579. // Arp entries change so fast that we deallocate the table
  580. // every time
  581. //
  582. if(g_IpInfo.pNetTable isnot NULL)
  583. {
  584. HeapFree(g_hIpNetHeap,
  585. HEAP_NO_SERIALIZE,
  586. g_IpInfo.pNetTable);
  587. }
  588. dwResult = AllocateAndGetIpNetTableFromStack(&(g_IpInfo.pNetTable),
  589. FALSE,
  590. g_hIpNetHeap,
  591. HEAP_NO_SERIALIZE,
  592. FALSE);
  593. if(dwResult is NO_ERROR)
  594. {
  595. Trace0(MIB,
  596. "LoadIpNetTable: Succesfully loaded net table");
  597. }
  598. else
  599. {
  600. HeapFree(g_hIpNetHeap,
  601. HEAP_NO_SERIALIZE,
  602. g_IpInfo.pNetTable);
  603. g_IpInfo.pNetTable = NULL;
  604. Trace1(ERR,
  605. "LoadIpNetTable: NtStatus %x loading IpNetTable from stack",
  606. dwResult);
  607. }
  608. if((g_IpInfo.pNetTable isnot NULL) and
  609. (g_IpInfo.pNetTable->dwNumEntries > 0))
  610. {
  611. qsort(g_IpInfo.pNetTable->table,
  612. g_IpInfo.pNetTable->dwNumEntries,
  613. sizeof(MIB_IPNETROW),
  614. CompareIpNetRow);
  615. }
  616. return dwResult;
  617. }