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.

2129 lines
54 KiB

  1. /*++
  2. Copyright (c) 1997 - 98, Microsoft Corporation
  3. Module Name:
  4. rtmrout.c
  5. Abstract:
  6. Contains routines for adding and deleting
  7. routes in the RTM.
  8. Author:
  9. Chaitanya Kodeboyina (chaitk) 24-Aug-1998
  10. Revision History:
  11. --*/
  12. #include "pchrtm.h"
  13. #pragma hdrstop
  14. DWORD
  15. WINAPI
  16. RtmAddRouteToDest (
  17. IN RTM_ENTITY_HANDLE RtmRegHandle,
  18. IN OUT PRTM_ROUTE_HANDLE RouteHandle OPTIONAL,
  19. IN PRTM_NET_ADDRESS DestAddress,
  20. IN PRTM_ROUTE_INFO RouteInfo,
  21. IN ULONG TimeToLive,
  22. IN RTM_ROUTE_LIST_HANDLE RouteListHandle OPTIONAL,
  23. IN RTM_NOTIFY_FLAGS ChangeType,
  24. IN RTM_NOTIFY_HANDLE NotifyHandle OPTIONAL,
  25. IN OUT PRTM_ROUTE_CHANGE_FLAGS ChangeFlags
  26. )
  27. /*++
  28. Routine Description:
  29. Adds a new route (or) updates an existing route to a destination.
  30. Arguments:
  31. RtmRegHandle - RTM registration handle for calling entity,
  32. RouteHandle - Handle to the route being updated (or NULL)
  33. is passed in; Passing a route handle avoids
  34. a search in the route table.
  35. Handle to new or updated route is returned,
  36. DestAddress - Destination network address for this route,
  37. RouteInfo - Info for the new route/route being updated,
  38. TimeToLive - Time (in ms) after which route is expired,
  39. RouteListHandle - Route list to which route is being moved,
  40. Notify Type -
  41. Notify Handle -
  42. ChangeFlags - Whether to add a new route or update an
  43. already existing one;
  44. The type of actual change (i.e) new add or
  45. update, and if best route changed is retd,
  46. Return Value:
  47. Status of the operation
  48. --*/
  49. {
  50. PADDRFAM_INFO AddrFamInfo;
  51. PENTITY_INFO Entity;
  52. PROUTE_LIST RouteList;
  53. PDEST_INFO Dest;
  54. PROUTE_INFO Route;
  55. PROUTE_INFO CurrRoute;
  56. PROUTE_INFO BestRoute;
  57. BOOL TableWriteLocked;
  58. LOOKUP_CONTEXT Context;
  59. PLOOKUP_LINKAGE DestData;
  60. BOOL DestCreated;
  61. LONG PrefChanged;
  62. PRTM_VIEW_ID ViewIndices;
  63. RTM_VIEW_SET ViewSet;
  64. RTM_VIEW_SET BelongedToViews;
  65. RTM_VIEW_SET WorseInViews;
  66. RTM_VIEW_SET BetterInViews;
  67. RTM_VIEW_SET RouteOldBestInViews;
  68. RTM_VIEW_SET RouteNewBestInViews;
  69. RTM_VIEW_SET RouteCurBestInViews;
  70. ULONG RouteInfoChanged;
  71. ULONG ForwardingInfoChanged;
  72. PROUTE_TIMER TimerContext;
  73. DWORD NotifyToCNs;
  74. PLOOKUP_LINKAGE NextData;
  75. PDEST_INFO NextDest;
  76. DWORD ViewsForCT[RTM_NUM_CHANGE_TYPES];
  77. DWORD DestMarkedBits;
  78. PLIST_ENTRY p;
  79. UINT i;
  80. DWORD Status;
  81. BOOL Success;
  82. UNREFERENCED_PARAMETER(ChangeType);
  83. UNREFERENCED_PARAMETER(NotifyHandle);
  84. VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
  85. AddrFamInfo = Entity->OwningAddrFamily;
  86. //
  87. // Validate input parameters before taking locks
  88. //
  89. // We should be adding only to supported views
  90. if (RouteInfo->BelongsToViews & ~AddrFamInfo->ViewsSupported)
  91. {
  92. return ERROR_INVALID_PARAMETER;
  93. }
  94. // Check the route list handle for validity
  95. RouteList = NULL;
  96. if (ARGUMENT_PRESENT(RouteListHandle))
  97. {
  98. VALIDATE_ROUTE_LIST_HANDLE(RouteListHandle, &RouteList);
  99. }
  100. DestCreated = FALSE;
  101. #if WRN
  102. Dest = NULL;
  103. #endif
  104. //
  105. // Check if we have a route handle present
  106. //
  107. if (ARGUMENT_PRESENT(RouteHandle) && (*RouteHandle))
  108. {
  109. //
  110. // No flags apply here as this is an update
  111. //
  112. if (*ChangeFlags != 0)
  113. {
  114. return ERROR_INVALID_PARAMETER;
  115. }
  116. //
  117. // Make sure that route handle is valid here
  118. //
  119. Route = ROUTE_FROM_HANDLE(*RouteHandle);
  120. if (Route == NULL)
  121. {
  122. return ERROR_INVALID_HANDLE;
  123. }
  124. //
  125. // Do further checking after acquiring lock
  126. //
  127. Dest = DEST_FROM_HANDLE(Route->RouteInfo.DestHandle);
  128. Status = NO_ERROR;
  129. ACQUIRE_DEST_WRITE_LOCK(Dest);
  130. //
  131. // Only the owner has perms to modify the route
  132. //
  133. if (Route->RouteInfo.RouteOwner != RtmRegHandle)
  134. {
  135. Status = ERROR_ACCESS_DENIED;
  136. }
  137. //
  138. // Was this route already deleted ?
  139. //
  140. if (Route->RouteInfo.State == RTM_ROUTE_STATE_DELETED)
  141. {
  142. Status = ERROR_INVALID_HANDLE;
  143. }
  144. if (Status != NO_ERROR)
  145. {
  146. RELEASE_DEST_WRITE_LOCK(Dest);
  147. return Status;
  148. }
  149. }
  150. else
  151. {
  152. //
  153. // Search the table for the dest for this route
  154. //
  155. Route = NULL;
  156. TableWriteLocked = FALSE;
  157. ACQUIRE_ROUTE_TABLE_READ_LOCK(AddrFamInfo);
  158. Status = SearchInTable(AddrFamInfo->RouteTable,
  159. DestAddress->NumBits,
  160. DestAddress->AddrBits,
  161. NULL,
  162. &DestData);
  163. if (SUCCESS(Status))
  164. {
  165. Dest = CONTAINING_RECORD(DestData, DEST_INFO, LookupLinkage);
  166. }
  167. else
  168. {
  169. //
  170. // We did'nt find a matching destination
  171. //
  172. RELEASE_ROUTE_TABLE_READ_LOCK(AddrFamInfo);
  173. TableWriteLocked = TRUE;
  174. ACQUIRE_ROUTE_TABLE_WRITE_LOCK(AddrFamInfo);
  175. //
  176. // We upgraded our route table lock from a
  177. // read lock to a write lock. We need to
  178. // search again to see if the dest has been
  179. // added after we released the read lock.
  180. //
  181. // If we do not find a destination even now,
  182. // we create a new one and insert into table
  183. //
  184. Status = SearchInTable(AddrFamInfo->RouteTable,
  185. DestAddress->NumBits,
  186. DestAddress->AddrBits,
  187. &Context,
  188. &DestData);
  189. if (SUCCESS(Status))
  190. {
  191. Dest = CONTAINING_RECORD(DestData, DEST_INFO, LookupLinkage);
  192. }
  193. else
  194. {
  195. //
  196. // Did not find the dest; so create new route and dest
  197. //
  198. Status = CreateRoute(Entity, RouteInfo, &Route);
  199. if (SUCCESS(Status))
  200. {
  201. Status = CreateDest(AddrFamInfo, DestAddress, &Dest);
  202. if (SUCCESS(Status))
  203. {
  204. Status = InsertIntoTable(AddrFamInfo->RouteTable,
  205. DestAddress->NumBits,
  206. DestAddress->AddrBits,
  207. &Context,
  208. &Dest->LookupLinkage);
  209. if (SUCCESS(Status))
  210. {
  211. *ChangeFlags = RTM_ROUTE_CHANGE_NEW;
  212. AddrFamInfo->NumDests++;
  213. #if DBG_REF
  214. REFERENCE_DEST(Dest, ROUTE_REF);
  215. DEREFERENCE_DEST(Dest, CREATION_REF);
  216. #endif
  217. DestCreated = TRUE;
  218. Route->RouteInfo.DestHandle =
  219. MAKE_HANDLE_FROM_POINTER(Dest);
  220. }
  221. else
  222. {
  223. //
  224. // Free alloc'ed memory as insert failed
  225. //
  226. DEREFERENCE_DEST(Dest, CREATION_REF);
  227. DEREFERENCE_ROUTE(Route, CREATION_REF);
  228. }
  229. }
  230. else
  231. {
  232. DEREFERENCE_ROUTE(Route, CREATION_REF);
  233. }
  234. }
  235. }
  236. }
  237. if (SUCCESS(Status))
  238. {
  239. ACQUIRE_DEST_WRITE_LOCK(Dest);
  240. }
  241. //
  242. // Release route table lock as you have the dest
  243. //
  244. if (!TableWriteLocked)
  245. {
  246. RELEASE_ROUTE_TABLE_READ_LOCK(AddrFamInfo);
  247. }
  248. else
  249. {
  250. RELEASE_ROUTE_TABLE_WRITE_LOCK(AddrFamInfo);
  251. }
  252. }
  253. if (SUCCESS(Status))
  254. {
  255. //
  256. // We have found an existing dest, or created a new one
  257. // In any case, we have a write lock on the destination
  258. //
  259. if (Route == NULL)
  260. {
  261. //
  262. // Do we have to add a new route or can we update ?
  263. //
  264. if ((*ChangeFlags & RTM_ROUTE_CHANGE_NEW) == 0)
  265. {
  266. //
  267. // Search for a matching route to update
  268. //
  269. for (p = Dest->RouteList.Flink;
  270. p != &Dest->RouteList;
  271. p = p->Flink)
  272. {
  273. Route = CONTAINING_RECORD(p, ROUTE_INFO, DestLE);
  274. //
  275. // Normally we consider two routes equal if
  276. // they have the same owner and were learnt
  277. // from the same neigbour, but if xxx_FIRST
  278. // flag is set, we skip the neighbour check
  279. //
  280. if ((Route->RouteInfo.RouteOwner == RtmRegHandle) &&
  281. ((*ChangeFlags & RTM_ROUTE_CHANGE_FIRST) ||
  282. (Route->RouteInfo.Neighbour == RouteInfo->Neighbour)))
  283. {
  284. break;
  285. }
  286. }
  287. }
  288. else
  289. {
  290. p = &Dest->RouteList;
  291. }
  292. if (p == &Dest->RouteList)
  293. {
  294. //
  295. // Need to create a new route on dest
  296. //
  297. Status = CreateRoute(Entity, RouteInfo, &Route);
  298. if (SUCCESS(Status))
  299. {
  300. *ChangeFlags = RTM_ROUTE_CHANGE_NEW;
  301. REFERENCE_DEST(Dest, ROUTE_REF);
  302. Route->RouteInfo.DestHandle =
  303. MAKE_HANDLE_FROM_POINTER(Dest);
  304. }
  305. else
  306. {
  307. RELEASE_DEST_WRITE_LOCK(Dest);
  308. return Status;
  309. }
  310. }
  311. }
  312. //
  313. // At this point, we either created a new route
  314. // or found a existing route on the destination
  315. //
  316. if (*ChangeFlags == RTM_ROUTE_CHANGE_NEW)
  317. {
  318. //
  319. // New add -> route belonged to no views
  320. //
  321. BelongedToViews = 0;
  322. PrefChanged = +1;
  323. //
  324. // Actual insert is done after this block
  325. //
  326. InterlockedIncrement(&AddrFamInfo->NumRoutes);
  327. }
  328. else
  329. {
  330. BelongedToViews = Route->RouteInfo.BelongsToViews;
  331. PrefChanged = ComparePref(RouteInfo,
  332. &Route->RouteInfo);
  333. if (PrefChanged != 0)
  334. {
  335. Dest->NumRoutes--;
  336. RemoveEntryList(&Route->DestLE);
  337. }
  338. //
  339. // Update existing route with only information
  340. // needed to calc the new best route on dest.
  341. // The rest is updated at end of this function
  342. // after we determine what info has changed.
  343. //
  344. Route->RouteInfo.PrefInfo = RouteInfo->PrefInfo;
  345. Route->RouteInfo.BelongsToViews = RouteInfo->BelongsToViews;
  346. }
  347. if (PrefChanged)
  348. {
  349. //
  350. // Insert the route in sorted order of preference info
  351. //
  352. for (p = Dest->RouteList.Flink; p != &Dest->RouteList; p= p->Flink)
  353. {
  354. CurrRoute = CONTAINING_RECORD(p, ROUTE_INFO, DestLE);
  355. if (ComparePref(&CurrRoute->RouteInfo,
  356. &Route->RouteInfo) < 0)
  357. {
  358. break;
  359. }
  360. }
  361. InsertTailList(p, &Route->DestLE);
  362. Dest->NumRoutes++;
  363. }
  364. //
  365. // Return the route handle if not passed in by the caller
  366. //
  367. if (ARGUMENT_PRESENT(RouteHandle))
  368. {
  369. if (*RouteHandle == NULL)
  370. {
  371. *RouteHandle = MAKE_HANDLE_FROM_POINTER(Route);
  372. REFERENCE_ROUTE(Route, HANDLE_REF);
  373. }
  374. }
  375. //
  376. // Adjust the best route information in each view
  377. //
  378. ViewIndices = AddrFamInfo->ViewIndexFromId;
  379. //
  380. // We have 3 cases that this add / update can trigger,
  381. // In a particular view -
  382. // 1) Route was the view's best route but not anymore,
  383. // 2) Route was and is still the best route after add,
  384. // 3) Route has become this view's "new" best route.
  385. //
  386. // If none of the above,
  387. // 4) Route was not the best before and is still not.
  388. //
  389. RouteCurBestInViews = 0;
  390. RouteNewBestInViews = 0;
  391. RouteOldBestInViews = 0;
  392. //
  393. // Compute all views in which this is the best route
  394. //
  395. ViewSet = BelongedToViews;
  396. for (i = 0; ViewSet && (i < RTM_VIEW_MASK_SIZE); i++)
  397. {
  398. if (ViewSet & 0x01)
  399. {
  400. // Update dest information in view i
  401. // Get best route in current view
  402. BestRoute = Dest->ViewInfo[ViewIndices[i]].BestRoute;
  403. // Was this the best route in view ?
  404. if (BestRoute == Route)
  405. {
  406. RouteCurBestInViews |= VIEW_MASK(i);
  407. }
  408. }
  409. ViewSet >>= 1;
  410. }
  411. //
  412. // Update views where route preference got better
  413. //
  414. if (PrefChanged > 0)
  415. {
  416. BetterInViews = RouteInfo->BelongsToViews;
  417. }
  418. else
  419. {
  420. BetterInViews = ~BelongedToViews & RouteInfo->BelongsToViews;
  421. }
  422. Dest->BelongsToViews |= BetterInViews;
  423. ViewSet = BetterInViews;
  424. for (i = 0; ViewSet && (i < RTM_VIEW_MASK_SIZE); i++)
  425. {
  426. if (ViewSet & 0x01)
  427. {
  428. //
  429. // Update dest information in view i
  430. //
  431. // Get best route in current view
  432. BestRoute = Dest->ViewInfo[ViewIndices[i]].BestRoute;
  433. //
  434. // Is route most preferred now, while
  435. // it was not so before this update ?
  436. //
  437. if ((!BestRoute) ||
  438. ((BestRoute != Route) &&
  439. (ComparePref(RouteInfo,
  440. &BestRoute->RouteInfo) > 0)))
  441. {
  442. Dest->ViewInfo[ViewIndices[i]].BestRoute = Route;
  443. RouteNewBestInViews |= VIEW_MASK(i);
  444. }
  445. }
  446. ViewSet >>= 1;
  447. }
  448. //
  449. // Update in views where the route preference got worse
  450. //
  451. if (PrefChanged < 0)
  452. {
  453. WorseInViews = RouteCurBestInViews;
  454. }
  455. else
  456. {
  457. WorseInViews = RouteCurBestInViews & ~RouteInfo->BelongsToViews;
  458. }
  459. //
  460. // In the views that you were the best, update best route
  461. //
  462. for (p = Dest->RouteList.Flink;
  463. WorseInViews && (p != &Dest->RouteList);
  464. p = p->Flink)
  465. {
  466. CurrRoute = CONTAINING_RECORD(p, ROUTE_INFO, DestLE);
  467. ViewSet = CurrRoute->RouteInfo.BelongsToViews & WorseInViews;
  468. for (i = 0; ViewSet && (i < RTM_VIEW_MASK_SIZE); i++)
  469. {
  470. if (ViewSet & 0x01)
  471. {
  472. // Get best route in current view
  473. BestRoute = Dest->ViewInfo[ViewIndices[i]].BestRoute;
  474. if (BestRoute != CurrRoute)
  475. {
  476. Dest->ViewInfo[ViewIndices[i]].BestRoute = CurrRoute;
  477. RouteOldBestInViews |= VIEW_MASK(i);
  478. }
  479. }
  480. ViewSet >>= 1;
  481. }
  482. WorseInViews &= ~CurrRoute->RouteInfo.BelongsToViews;
  483. }
  484. //
  485. // For some views, we end up not having a best route
  486. //
  487. ViewSet = WorseInViews;
  488. for (i = 0; ViewSet && (i < RTM_VIEW_MASK_SIZE); i++)
  489. {
  490. if (ViewSet & 0x01)
  491. {
  492. Dest->ViewInfo[ViewIndices[i]].BestRoute = NULL;
  493. RouteOldBestInViews |= VIEW_MASK(i);
  494. }
  495. ViewSet >>= 1;
  496. }
  497. Dest->BelongsToViews &= ~WorseInViews;
  498. //
  499. // Update the views in which route remains the best
  500. //
  501. RouteCurBestInViews &= ~RouteOldBestInViews;
  502. //
  503. // The following bit masks as all mutually exclusive
  504. //
  505. ASSERT(!(RouteOldBestInViews & RouteCurBestInViews));
  506. ASSERT(!(RouteCurBestInViews & RouteNewBestInViews));
  507. ASSERT(!(RouteNewBestInViews & RouteOldBestInViews));
  508. //
  509. // Compute the views for each change type occurred
  510. //
  511. //
  512. // All views affected by this add are notified
  513. // -views route belonged to and now belongs to
  514. //
  515. ViewsForCT[RTM_CHANGE_TYPE_ID_ALL] =
  516. BelongedToViews | RouteInfo->BelongsToViews;
  517. //
  518. // If the route's posn as the best route changed,
  519. // then it is definitely a best and fwding change
  520. //
  521. ViewsForCT[RTM_CHANGE_TYPE_ID_FORWARDING] =
  522. ViewsForCT[RTM_CHANGE_TYPE_ID_BEST] =
  523. RouteNewBestInViews | RouteOldBestInViews;
  524. if (RouteCurBestInViews)
  525. {
  526. //
  527. // Figure out what information has changed
  528. //
  529. ComputeRouteInfoChange(&Route->RouteInfo,
  530. RouteInfo,
  531. PrefChanged,
  532. &RouteInfoChanged,
  533. &ForwardingInfoChanged);
  534. //
  535. // If the route was and is still the best
  536. // route, then the change types depend on
  537. // kind of information that was modified.
  538. //
  539. ViewsForCT[RTM_CHANGE_TYPE_ID_BEST] |=
  540. RouteInfoChanged & RouteCurBestInViews;
  541. ViewsForCT[RTM_CHANGE_TYPE_ID_FORWARDING] |=
  542. ForwardingInfoChanged & RouteCurBestInViews;
  543. }
  544. //
  545. // If not a new route, update with new info
  546. //
  547. if (*ChangeFlags != RTM_ROUTE_CHANGE_NEW)
  548. {
  549. CopyToRoute(Entity, RouteInfo, Route);
  550. }
  551. //
  552. // Update output flags if best route changed
  553. //
  554. if (ViewsForCT[RTM_CHANGE_TYPE_ID_BEST])
  555. {
  556. *ChangeFlags |= RTM_ROUTE_CHANGE_BEST;
  557. }
  558. //
  559. // Calculate the CNs that need to be notified
  560. //
  561. ACQUIRE_NOTIFICATIONS_READ_LOCK(AddrFamInfo);
  562. if (!DestCreated)
  563. {
  564. DestMarkedBits = Dest->DestMarkedBits;
  565. }
  566. else
  567. {
  568. DestMarkedBits = 0;
  569. NextMatchInTable(AddrFamInfo->RouteTable,
  570. &Dest->LookupLinkage,
  571. &NextData);
  572. if (NextData)
  573. {
  574. NextDest =
  575. CONTAINING_RECORD(NextData, DEST_INFO, LookupLinkage);
  576. DestMarkedBits = NextDest->DestMarkedBits;
  577. }
  578. }
  579. NotifyToCNs = ComputeCNsToBeNotified(AddrFamInfo,
  580. DestMarkedBits,
  581. ViewsForCT);
  582. //
  583. // Add to the global change list if required
  584. //
  585. if (NotifyToCNs)
  586. {
  587. AddToChangedDestLists(AddrFamInfo,
  588. Dest,
  589. NotifyToCNs);
  590. }
  591. RELEASE_NOTIFICATIONS_READ_LOCK(AddrFamInfo);
  592. //
  593. // Remove from old route list, and put in the new one
  594. //
  595. if (RouteList)
  596. {
  597. ACQUIRE_ROUTE_LISTS_WRITE_LOCK(Entity);
  598. if (!IsListEmpty(&Route->RouteListLE))
  599. {
  600. RemoveEntryList(&Route->RouteListLE);
  601. }
  602. else
  603. {
  604. REFERENCE_ROUTE(Route, LIST_REF);
  605. }
  606. InsertTailList(&RouteList->ListHead, &Route->RouteListLE);
  607. RELEASE_ROUTE_LISTS_WRITE_LOCK(Entity);
  608. }
  609. //
  610. // Set a timer if we want to age out the route
  611. //
  612. TimerContext = Route->TimerContext;
  613. if (TimeToLive == INFINITE)
  614. {
  615. Route->TimerContext = NULL;
  616. }
  617. else
  618. {
  619. Route->TimerContext = AllocMemory(sizeof(ROUTE_TIMER));
  620. if (Route->TimerContext)
  621. {
  622. Route->TimerContext->Route = Route;
  623. Success = CreateTimerQueueTimer(&Route->TimerContext->Timer,
  624. AddrFamInfo->RouteTimerQueue,
  625. RouteExpiryTimeoutCallback,
  626. Route->TimerContext,
  627. TimeToLive,
  628. 0,
  629. 0);
  630. if (Success)
  631. {
  632. REFERENCE_ROUTE(Route, TIMER_REF);
  633. }
  634. else
  635. {
  636. Status = GetLastError();
  637. FreeMemory(Route->TimerContext);
  638. Route->TimerContext = NULL;
  639. }
  640. }
  641. }
  642. #if DBG_TRACE
  643. //
  644. // Print the route and the dest in the tracing
  645. //
  646. if (TRACING_ENABLED(ROUTE))
  647. {
  648. ULONG TempAddr, TempMask;
  649. RTM_IPV4_GET_ADDR_AND_MASK(TempAddr, TempMask, &Dest->DestAddress);
  650. Trace0(ROUTE, "Adding Route with address: ");
  651. TracePrintAddress(ROUTE, TempAddr, TempMask);
  652. Trace2(ROUTE, "Dest = %p and Route = %p\n", Dest, Route);
  653. }
  654. #endif
  655. RELEASE_DEST_WRITE_LOCK(Dest);
  656. //
  657. // Cancel the timer that was attached to the route
  658. //
  659. if (TimerContext)
  660. {
  661. if (DeleteTimerQueueTimer(AddrFamInfo->RouteTimerQueue,
  662. TimerContext->Timer,
  663. (HANDLE) -1))
  664. {
  665. // Timer cancelled - delete the context
  666. FreeMemory(TimerContext);
  667. DEREFERENCE_ROUTE(Route, TIMER_REF);
  668. }
  669. }
  670. return NO_ERROR;
  671. }
  672. return Status;
  673. }
  674. DWORD
  675. WINAPI
  676. RtmDeleteRouteToDest (
  677. IN RTM_ENTITY_HANDLE RtmRegHandle,
  678. IN RTM_ROUTE_HANDLE RouteHandle,
  679. OUT PRTM_ROUTE_CHANGE_FLAGS ChangeFlags
  680. )
  681. /*++
  682. Routine Description:
  683. Deletes a route from the route table, and updates the
  684. best route information on the corresponding dest.
  685. Arguments:
  686. RtmRegHandle - RTM registration handle for calling entity,
  687. RouteHandle - Handle to the route to be deleted,
  688. ChangeFlags - Flags whether the best route info changed.
  689. Return Value:
  690. Status of the operation
  691. --*/
  692. {
  693. PADDRFAM_INFO AddrFamInfo;
  694. PENTITY_INFO Entity;
  695. PDEST_INFO Dest;
  696. PROUTE_INFO BestRoute;
  697. PROUTE_INFO CurrRoute;
  698. PROUTE_INFO Route;
  699. BOOL TableLocked;
  700. PLOOKUP_LINKAGE DestData;
  701. PRTM_VIEW_ID ViewIndices;
  702. RTM_VIEW_SET ViewSet;
  703. RTM_VIEW_SET WorseInViews;
  704. RTM_VIEW_SET RouteCurBestInViews;
  705. ULONG MaxHoldTime;
  706. PROUTE_TIMER TimerContext;
  707. ULONG NotifyToCNs;
  708. DWORD ViewsForCT[RTM_NUM_CHANGE_TYPES];
  709. PLIST_ENTRY p;
  710. UINT i, j;
  711. DWORD Status;
  712. BOOL Success;
  713. VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
  714. AddrFamInfo = Entity->OwningAddrFamily;
  715. VALIDATE_ROUTE_HANDLE(RouteHandle, &Route);
  716. //
  717. // Only the owner has perms to delete the route
  718. //
  719. if (Route->RouteInfo.RouteOwner != RtmRegHandle)
  720. {
  721. return ERROR_ACCESS_DENIED;
  722. }
  723. Dest = DEST_FROM_HANDLE(Route->RouteInfo.DestHandle);
  724. #if DBG_TRACE
  725. //
  726. // Print the route and the dest in the tracing
  727. //
  728. if (TRACING_ENABLED(ROUTE))
  729. {
  730. ULONG TempAddr, TempMask;
  731. RTM_IPV4_GET_ADDR_AND_MASK(TempAddr, TempMask, &Dest->DestAddress);
  732. Trace0(ROUTE, "Deleting Route with address: ");
  733. TracePrintAddress(ROUTE, TempAddr, TempMask);
  734. Trace2(ROUTE, "Dest = %p and Route = %p\n", Dest, Route);
  735. }
  736. #endif
  737. //
  738. // We attempt to delete the route on the dest
  739. // without having to lock the entire table.
  740. // This is possible as long as the route is
  741. // not the only route on this destination.
  742. //
  743. TableLocked = FALSE;
  744. ACQUIRE_DEST_WRITE_LOCK(Dest);
  745. //
  746. // Check if this is the last route on dest,
  747. // there is no holddown already that would
  748. // prevent the dest from getting deleted,
  749. // and this route isnt going into holddown
  750. //
  751. if ((Dest->NumRoutes == 1) &&
  752. (Dest->HoldRefCount == 0) &&
  753. ((Dest->ToHoldInViews & Route->RouteInfo.BelongsToViews) == 0))
  754. {
  755. if (Route->RouteInfo.State != RTM_ROUTE_STATE_DELETED)
  756. {
  757. // Mark the state of the route as 'deleting'
  758. Route->RouteInfo.State = RTM_ROUTE_STATE_DELETING;
  759. //
  760. // Re-grab dest lock after locking route table
  761. //
  762. RELEASE_DEST_WRITE_LOCK(Dest);
  763. TableLocked = TRUE;
  764. ACQUIRE_ROUTE_TABLE_WRITE_LOCK(AddrFamInfo);
  765. ACQUIRE_DEST_WRITE_LOCK(Dest);
  766. //
  767. // Was route updated while we re-acquired locks
  768. //
  769. if (Route->RouteInfo.State != RTM_ROUTE_STATE_DELETING)
  770. {
  771. RELEASE_ROUTE_TABLE_WRITE_LOCK(AddrFamInfo);
  772. RELEASE_DEST_WRITE_LOCK(Dest);
  773. return NO_ERROR;
  774. }
  775. }
  776. }
  777. //
  778. // Get out if this route is already deleted
  779. //
  780. if (Route->RouteInfo.State != RTM_ROUTE_STATE_DELETED)
  781. {
  782. ASSERT(!IsListEmpty(&Route->DestLE));
  783. //
  784. // Remove the route from the list of routes on dest
  785. //
  786. Route->RouteInfo.State = RTM_ROUTE_STATE_DELETED;
  787. RemoveEntryList(&Route->DestLE);
  788. Dest->NumRoutes--;
  789. *ChangeFlags = 0;
  790. if (TableLocked)
  791. {
  792. //
  793. // Have u removed all routes on dest ?
  794. // Do we have any routes in holddown ?
  795. // Is current delete causing holddown ?
  796. //
  797. if ((Dest->NumRoutes == 0) &&
  798. (Dest->HoldRefCount == 0) &&
  799. ((Dest->ToHoldInViews & Route->RouteInfo.BelongsToViews) == 0))
  800. {
  801. Dest->State = DEST_STATE_DELETED;
  802. Status = DeleteFromTable(AddrFamInfo->RouteTable,
  803. Dest->DestAddress.NumBits,
  804. Dest->DestAddress.AddrBits,
  805. NULL,
  806. &DestData);
  807. ASSERT(SUCCESS(Status));
  808. AddrFamInfo->NumDests--;
  809. }
  810. //
  811. // You no longer need to keep a lock to the table
  812. // [ You have a lock on the destination however ]
  813. //
  814. RELEASE_ROUTE_TABLE_WRITE_LOCK(AddrFamInfo);
  815. }
  816. ViewIndices = AddrFamInfo->ViewIndexFromId;
  817. //
  818. // Update best route in views the route was present
  819. //
  820. ViewSet = Route->RouteInfo.BelongsToViews;
  821. //
  822. // See if you are best route in any of these views
  823. //
  824. RouteCurBestInViews = 0;
  825. for (i = 0; ViewSet && (i < RTM_VIEW_MASK_SIZE); i++)
  826. {
  827. if (ViewSet & 0x01)
  828. {
  829. // Update dest information in view i
  830. // Get best route in current view
  831. BestRoute = Dest->ViewInfo[ViewIndices[i]].BestRoute;
  832. // Was this the best route in view ?
  833. if (BestRoute == Route)
  834. {
  835. RouteCurBestInViews |= VIEW_MASK(i);
  836. }
  837. }
  838. ViewSet >>= 1;
  839. }
  840. //
  841. // In the views that you were the best, update best route
  842. //
  843. WorseInViews = RouteCurBestInViews;
  844. for (p = Dest->RouteList.Flink;
  845. (p != &Dest->RouteList) && WorseInViews;
  846. p = p->Flink)
  847. {
  848. CurrRoute = CONTAINING_RECORD(p, ROUTE_INFO, DestLE);
  849. ViewSet = CurrRoute->RouteInfo.BelongsToViews & WorseInViews;
  850. for (i = 0; ViewSet && (i < RTM_VIEW_MASK_SIZE); i++)
  851. {
  852. if (ViewSet & 0x01)
  853. {
  854. // Update best route in current view
  855. Dest->ViewInfo[ViewIndices[i]].BestRoute = CurrRoute;
  856. }
  857. ViewSet >>= 1;
  858. }
  859. WorseInViews &= ~CurrRoute->RouteInfo.BelongsToViews;
  860. }
  861. //
  862. // For some views, we end up not having a best route
  863. //
  864. ViewSet = WorseInViews;
  865. MaxHoldTime = 0;
  866. for (i = 0; ViewSet && (i < RTM_VIEW_MASK_SIZE); i++)
  867. {
  868. if (ViewSet & 0x01)
  869. {
  870. j = ViewIndices[i];
  871. ASSERT(Dest->ViewInfo[j].BestRoute == Route);
  872. Dest->ViewInfo[j].BestRoute = NULL;
  873. //
  874. // If dest is marked for holddown in this view,
  875. // store deleted route as the holddown route
  876. // if there was no other held route before this
  877. //
  878. if (Dest->ViewInfo[j].HoldTime)
  879. {
  880. if (Dest->ViewInfo[j].HoldRoute == NULL)
  881. {
  882. Dest->ViewInfo[j].HoldRoute = Route;
  883. REFERENCE_ROUTE(Route, HOLD_REF);
  884. if (MaxHoldTime < Dest->ViewInfo[j].HoldTime)
  885. {
  886. MaxHoldTime = Dest->ViewInfo[j].HoldTime;
  887. }
  888. }
  889. Dest->ViewInfo[j].HoldTime = 0;
  890. }
  891. }
  892. ViewSet >>= 1;
  893. }
  894. Dest->BelongsToViews &= ~WorseInViews;
  895. Dest->ToHoldInViews &= ~WorseInViews;
  896. //
  897. // Compute the views for each change type occurred
  898. //
  899. ViewsForCT[RTM_CHANGE_TYPE_ID_ALL] = Route->RouteInfo.BelongsToViews;
  900. ViewsForCT[RTM_CHANGE_TYPE_ID_BEST] =
  901. ViewsForCT[RTM_CHANGE_TYPE_ID_FORWARDING] = RouteCurBestInViews;
  902. //
  903. // Update output flags if best route changed
  904. //
  905. if (ViewsForCT[RTM_CHANGE_TYPE_ID_BEST])
  906. {
  907. *ChangeFlags |= RTM_ROUTE_CHANGE_BEST;
  908. }
  909. //
  910. // Calculate the CNs that need to be notified
  911. //
  912. ACQUIRE_NOTIFICATIONS_READ_LOCK(AddrFamInfo);
  913. NotifyToCNs = ComputeCNsToBeNotified(AddrFamInfo,
  914. Dest->DestMarkedBits,
  915. ViewsForCT);
  916. //
  917. // Add to the global change list if required
  918. //
  919. if (NotifyToCNs)
  920. {
  921. AddToChangedDestLists(AddrFamInfo,
  922. Dest,
  923. NotifyToCNs);
  924. }
  925. RELEASE_NOTIFICATIONS_READ_LOCK(AddrFamInfo);
  926. //
  927. // Invalidate any outstanding timers on route
  928. //
  929. TimerContext = Route->TimerContext;
  930. Route->TimerContext = NULL;
  931. //
  932. // Did this route delete result in a holddown
  933. //
  934. if (MaxHoldTime)
  935. {
  936. //
  937. // We should not delete the destination
  938. // while we have its routes in holddown
  939. //
  940. Dest->HoldRefCount++;
  941. //
  942. // Create a timer to remove this hold
  943. //
  944. Route->TimerContext = AllocMemory(sizeof(ROUTE_TIMER));
  945. if (Route->TimerContext)
  946. {
  947. Route->TimerContext->Route = Route;
  948. Success = CreateTimerQueueTimer(&Route->TimerContext->Timer,
  949. AddrFamInfo->RouteTimerQueue,
  950. RouteHolddownTimeoutCallback,
  951. Route->TimerContext,
  952. MaxHoldTime,
  953. 0,
  954. 0);
  955. if (Success)
  956. {
  957. REFERENCE_ROUTE(Route, TIMER_REF);
  958. }
  959. else
  960. {
  961. Status = GetLastError();
  962. FreeMemory(Route->TimerContext);
  963. Route->TimerContext = NULL;
  964. }
  965. }
  966. }
  967. RELEASE_DEST_WRITE_LOCK(Dest);
  968. //
  969. // Cancel any outstanding timers on the route
  970. //
  971. if (TimerContext)
  972. {
  973. if (DeleteTimerQueueTimer(AddrFamInfo->RouteTimerQueue,
  974. TimerContext->Timer,
  975. (HANDLE) -1))
  976. {
  977. // Timer cancelled - delete the context
  978. FreeMemory(TimerContext);
  979. DEREFERENCE_ROUTE(Route, TIMER_REF);
  980. }
  981. }
  982. //
  983. // Remove appropriate references on route
  984. //
  985. InterlockedDecrement(&AddrFamInfo->NumRoutes);
  986. DEREFERENCE_ROUTE(Route, CREATION_REF);
  987. DEREFERENCE_ROUTE(Route, HANDLE_REF);
  988. return NO_ERROR;
  989. }
  990. else
  991. {
  992. //
  993. // This route has already been deleted
  994. //
  995. if (TableLocked)
  996. {
  997. RELEASE_ROUTE_TABLE_WRITE_LOCK(AddrFamInfo);
  998. }
  999. RELEASE_DEST_WRITE_LOCK(Dest);
  1000. return ERROR_INVALID_HANDLE;
  1001. }
  1002. }
  1003. DWORD
  1004. WINAPI
  1005. RtmHoldDestination (
  1006. IN RTM_ENTITY_HANDLE RtmRegHandle,
  1007. IN RTM_DEST_HANDLE DestHandle,
  1008. IN RTM_VIEW_SET TargetViews,
  1009. IN ULONG HoldTime
  1010. )
  1011. /*++
  1012. Routine Description:
  1013. Marks a destination to be put in the holddown state
  1014. for a certain time once the last route in any view
  1015. gets deleted.
  1016. When the last route in a view gets deleted, the old
  1017. best route moved to the holddown route on the dest.
  1018. The holddown protocols continue to advertise this
  1019. route until the hold expires, even if newer routes
  1020. arrive in the meantime.
  1021. To be perfectly right, we should have this hold time
  1022. per view. But we trade off convergence time in favor
  1023. of memory resources by holding on to the held routes
  1024. in all views for a single (the max) holddown time.
  1025. Arguments:
  1026. RtmRegHandle - RTM registration handle for calling entity,
  1027. DestHandle - Handle to the dest that is being helddown,
  1028. HoldTime - Time for which dest is marked for holddown
  1029. (after the last route to this dest is gone).
  1030. Return Value:
  1031. Status of the operation
  1032. --*/
  1033. {
  1034. PENTITY_INFO Entity;
  1035. PDEST_INFO Dest;
  1036. PRTM_VIEW_ID ViewIndices;
  1037. RTM_VIEW_SET ViewSet;
  1038. UINT i, j;
  1039. DWORD Status;
  1040. VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
  1041. VALIDATE_DEST_HANDLE(DestHandle, &Dest);
  1042. // Limit caller's interest to set of views supported
  1043. TargetViews &= Entity->OwningAddrFamily->ViewsSupported;
  1044. if (HoldTime == 0)
  1045. {
  1046. return ERROR_INVALID_PARAMETER;
  1047. }
  1048. ACQUIRE_DEST_WRITE_LOCK(Dest);
  1049. //
  1050. // Add a hold if dest is not already deleted
  1051. //
  1052. if (Dest->State != DEST_STATE_DELETED)
  1053. {
  1054. ViewIndices = Entity->OwningAddrFamily->ViewIndexFromId;
  1055. ViewSet = TargetViews;
  1056. for (i = 0; ViewSet && (i < RTM_VIEW_MASK_SIZE); i++)
  1057. {
  1058. if (ViewSet & 0x01)
  1059. {
  1060. j = ViewIndices[i];
  1061. // Increase hold time in the view if needed
  1062. if (Dest->ViewInfo[j].HoldTime < HoldTime)
  1063. {
  1064. Dest->ViewInfo[j].HoldTime = HoldTime;
  1065. }
  1066. }
  1067. ViewSet >>= 1;
  1068. }
  1069. Dest->ToHoldInViews |= TargetViews;
  1070. Status = NO_ERROR;
  1071. }
  1072. else
  1073. {
  1074. Status = ERROR_INVALID_HANDLE;
  1075. }
  1076. RELEASE_DEST_WRITE_LOCK(Dest);
  1077. return Status;
  1078. }
  1079. DWORD
  1080. WINAPI
  1081. RtmGetRoutePointer (
  1082. IN RTM_ENTITY_HANDLE RtmRegHandle,
  1083. IN RTM_ROUTE_HANDLE RouteHandle,
  1084. OUT PRTM_ROUTE_INFO *RoutePointer
  1085. )
  1086. /*++
  1087. Routine Description:
  1088. Gets a direct pointer to the route for read/write by its owner.
  1089. Arguments:
  1090. RtmRegHandle - RTM registration handle for calling entity,
  1091. RouteHandle - Handle to the route whose pointer we want,
  1092. RoutePointer - A pointer to the route is returned for fast
  1093. direct access by the caller, only if the
  1094. caller is the owner of the route passed in.
  1095. Return Value:
  1096. Status of the operation
  1097. --*/
  1098. {
  1099. PENTITY_INFO Entity;
  1100. PROUTE_INFO Route;
  1101. DBG_VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
  1102. VALIDATE_ROUTE_HANDLE(RouteHandle, &Route);
  1103. //
  1104. // Return a pointer only if caller owns the route
  1105. //
  1106. if (Route->RouteInfo.RouteOwner != RtmRegHandle)
  1107. {
  1108. return ERROR_ACCESS_DENIED;
  1109. }
  1110. *RoutePointer = &Route->RouteInfo;
  1111. return NO_ERROR;
  1112. }
  1113. DWORD
  1114. WINAPI
  1115. RtmLockRoute(
  1116. IN RTM_ENTITY_HANDLE RtmRegHandle,
  1117. IN RTM_ROUTE_HANDLE RouteHandle,
  1118. IN BOOL Exclusive,
  1119. IN BOOL LockRoute,
  1120. OUT PRTM_ROUTE_INFO *RoutePointer OPTIONAL
  1121. )
  1122. /*++
  1123. Routine Description:
  1124. Locks/unlocks a route in the route table. This function is
  1125. used to guard the route while it is being updated in place.
  1126. Arguments:
  1127. RtmRegHandle - RTM registration handle for calling entity,
  1128. RouteHandle - Handle to the route to be locked,
  1129. Exclusive - TRUE to lock in write mode, else read mode,
  1130. LockRoute - Flag that tells whether to lock or unlock.
  1131. RoutePointer - A pointer to the route is returned for fast
  1132. direct access by the owner of this route.
  1133. Return Value:
  1134. Status of the operation
  1135. --*/
  1136. {
  1137. PENTITY_INFO Entity;
  1138. PDEST_INFO Dest;
  1139. PROUTE_INFO Route;
  1140. DWORD Status;
  1141. DBG_VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
  1142. VALIDATE_ROUTE_HANDLE(RouteHandle, &Route);
  1143. //
  1144. // Only the owner has perms to lock the route
  1145. //
  1146. if (Route->RouteInfo.RouteOwner != RtmRegHandle)
  1147. {
  1148. return ERROR_ACCESS_DENIED;
  1149. }
  1150. // Return a direct pointer for use in update
  1151. if (ARGUMENT_PRESENT(RoutePointer))
  1152. {
  1153. *RoutePointer = &Route->RouteInfo;
  1154. }
  1155. //
  1156. // Lock or unlock the route as the case may be
  1157. //
  1158. Dest = DEST_FROM_HANDLE(Route->RouteInfo.DestHandle);
  1159. Status = NO_ERROR;
  1160. if (LockRoute)
  1161. {
  1162. if (Exclusive)
  1163. {
  1164. ACQUIRE_DEST_WRITE_LOCK(Dest);
  1165. }
  1166. else
  1167. {
  1168. ACQUIRE_DEST_READ_LOCK(Dest);
  1169. }
  1170. //
  1171. // You are done if the route wasn't deleted
  1172. //
  1173. if (Route->RouteInfo.State == RTM_ROUTE_STATE_CREATED)
  1174. {
  1175. return NO_ERROR;
  1176. }
  1177. Status = ERROR_INVALID_HANDLE;
  1178. }
  1179. //
  1180. // This is an unlock or a case of a failed lock
  1181. //
  1182. if (Exclusive)
  1183. {
  1184. RELEASE_DEST_WRITE_LOCK(Dest);
  1185. }
  1186. else
  1187. {
  1188. RELEASE_DEST_READ_LOCK(Dest);
  1189. }
  1190. return Status;
  1191. }
  1192. DWORD
  1193. WINAPI
  1194. RtmUpdateAndUnlockRoute(
  1195. IN RTM_ENTITY_HANDLE RtmRegHandle,
  1196. IN RTM_ROUTE_HANDLE RouteHandle,
  1197. IN ULONG TimeToLive,
  1198. IN RTM_ROUTE_LIST_HANDLE RouteListHandle OPTIONAL,
  1199. IN RTM_NOTIFY_FLAGS ChangeType,
  1200. IN RTM_NOTIFY_HANDLE NotifyHandle OPTIONAL,
  1201. OUT PRTM_ROUTE_CHANGE_FLAGS ChangeFlags
  1202. )
  1203. /*++
  1204. Routine Description:
  1205. Updates the position of the route on the list of routes on
  1206. the dest, and adjusts best route information on the dest.
  1207. This function invocation is part of the following sequence,
  1208. The caller calls RtmLockRoute to lock the route.
  1209. [ Actually this locks the route's destination ]
  1210. The caller uses a direct pointer to the route
  1211. to update the route in place. Only ceratin set of
  1212. route fields can be changed using this method.
  1213. The caller then calls RtmUpdateAndUnlockRoute to
  1214. inform RTM of the change, which causes the dest to
  1215. be updated by RTM to reflect the new route info.
  1216. Finally the caller releases the locks taken in
  1217. RtmLockRoute by calling RtmLockRoute with FALSE.
  1218. Arguments:
  1219. RtmRegHandle - RTM registration handle for calling entity,
  1220. RouteHandle - Route that has been changed in place,
  1221. ChangeFlags - "If the best route changed" is returned,
  1222. Return Value:
  1223. Status of the operation
  1224. --*/
  1225. {
  1226. PADDRFAM_INFO AddrFamInfo;
  1227. PENTITY_INFO Entity;
  1228. PROUTE_LIST RouteList;
  1229. PDEST_INFO Dest;
  1230. PROUTE_INFO Route;
  1231. PROUTE_INFO CurrRoute;
  1232. PROUTE_INFO BestRoute;
  1233. LONG PrefChanged;
  1234. PRTM_VIEW_ID ViewIndices;
  1235. RTM_VIEW_SET BelongedToViews;
  1236. RTM_VIEW_SET ViewSet;
  1237. RTM_VIEW_SET WorseInViews;
  1238. RTM_VIEW_SET BetterInViews;
  1239. RTM_VIEW_SET RouteNewBestInViews;
  1240. RTM_VIEW_SET RouteCurBestInViews;
  1241. PROUTE_TIMER TimerContext;
  1242. ULONG NotifyToCNs;
  1243. DWORD ViewsForCT[RTM_NUM_CHANGE_TYPES];
  1244. PLIST_ENTRY p;
  1245. UINT i;
  1246. DWORD Status;
  1247. BOOL Success;
  1248. UNREFERENCED_PARAMETER(ChangeType);
  1249. UNREFERENCED_PARAMETER(NotifyHandle);
  1250. VALIDATE_ENTITY_HANDLE(RtmRegHandle, &Entity);
  1251. AddrFamInfo = Entity->OwningAddrFamily;
  1252. VALIDATE_ROUTE_HANDLE(RouteHandle, &Route);
  1253. //
  1254. // Only the owner has perms to update the route
  1255. //
  1256. if (Route->RouteInfo.RouteOwner != RtmRegHandle)
  1257. {
  1258. return ERROR_ACCESS_DENIED;
  1259. }
  1260. //
  1261. // Validate the updated route before re-adjusting
  1262. //
  1263. // We should be adding only to supported views
  1264. Route->RouteInfo.BelongsToViews &= AddrFamInfo->ViewsSupported;
  1265. Dest = DEST_FROM_HANDLE(Route->RouteInfo.DestHandle);
  1266. // Print the route and the dest in the traces
  1267. #if DBG_TRACE
  1268. //
  1269. // Print the route and the dest in the tracing
  1270. //
  1271. if (TRACING_ENABLED(ROUTE))
  1272. {
  1273. ULONG TempAddr, TempMask;
  1274. RTM_IPV4_GET_ADDR_AND_MASK(TempAddr, TempMask, &Dest->DestAddress);
  1275. Trace0(ROUTE, "Updating Route with address: ");
  1276. TracePrintAddress(ROUTE, TempAddr, TempMask);
  1277. Trace2(ROUTE, "Dest = %p and Route = %p\n", Dest, Route);
  1278. }
  1279. #endif
  1280. //
  1281. // Route has been updated in place and the route's
  1282. // PrefInfo and BelongsToViews values have changed
  1283. //
  1284. *ChangeFlags = 0;
  1285. //
  1286. // Check if route's preference has gone up or down
  1287. //
  1288. PrefChanged = 0;
  1289. if (PrefChanged == 0)
  1290. {
  1291. // Compare the pref with that of the prev route in list
  1292. if (Route->DestLE.Blink != &Dest->RouteList)
  1293. {
  1294. CurrRoute = CONTAINING_RECORD(Route->DestLE.Blink,
  1295. ROUTE_INFO,
  1296. DestLE);
  1297. if (ComparePref(&CurrRoute->RouteInfo,
  1298. &Route->RouteInfo) < 0)
  1299. {
  1300. // Preference has gone up from prev value
  1301. PrefChanged = +1;
  1302. //
  1303. // Re-Insert the route in sorted pref order
  1304. //
  1305. RemoveEntryList(&Route->DestLE);
  1306. for (p = CurrRoute->DestLE.Blink;
  1307. p != &Dest->RouteList;
  1308. p = p->Blink)
  1309. {
  1310. CurrRoute = CONTAINING_RECORD(p, ROUTE_INFO, DestLE);
  1311. if (ComparePref(&CurrRoute->RouteInfo,
  1312. &Route->RouteInfo) >= 0)
  1313. {
  1314. break;
  1315. }
  1316. }
  1317. InsertHeadList(p, &Route->DestLE);
  1318. }
  1319. }
  1320. }
  1321. if (PrefChanged == 0)
  1322. {
  1323. // Compare the pref with that of the next route in list
  1324. if (Route->DestLE.Flink != &Dest->RouteList)
  1325. {
  1326. CurrRoute = CONTAINING_RECORD(Route->DestLE.Flink,
  1327. ROUTE_INFO,
  1328. DestLE);
  1329. if (ComparePref(&CurrRoute->RouteInfo,
  1330. &Route->RouteInfo) > 0)
  1331. {
  1332. // Preference has gone down from prev value
  1333. PrefChanged = -1;
  1334. //
  1335. // Re-Insert the route in sorted pref order
  1336. //
  1337. RemoveEntryList(&Route->DestLE);
  1338. for (p = CurrRoute->DestLE.Flink;
  1339. p != &Dest->RouteList;
  1340. p = p->Flink)
  1341. {
  1342. CurrRoute = CONTAINING_RECORD(p, ROUTE_INFO, DestLE);
  1343. if (ComparePref(&CurrRoute->RouteInfo,
  1344. &Route->RouteInfo) <= 0)
  1345. {
  1346. break;
  1347. }
  1348. }
  1349. InsertTailList(p, &Route->DestLE);
  1350. }
  1351. }
  1352. }
  1353. //
  1354. // Adjust the best route information in each view
  1355. //
  1356. ViewIndices = AddrFamInfo->ViewIndexFromId;
  1357. BelongedToViews = Dest->BelongsToViews;
  1358. //
  1359. // We have 3 cases that this add / update can trigger,
  1360. // In a particular view -
  1361. // 1) Route was the view's best route but not anymore,
  1362. // 2) Route was and is still the best route after add,
  1363. // 3) Route has become this view's "new" best route.
  1364. //
  1365. // As we have no idea what changed in the case of (2),
  1366. // we will trigger best route and forwarding changes.
  1367. //
  1368. RouteCurBestInViews = 0;
  1369. RouteNewBestInViews = 0;
  1370. //
  1371. // Check if this route is best in any view
  1372. //
  1373. ViewSet = BelongedToViews;
  1374. for (i = 0; ViewSet && (i < RTM_VIEW_MASK_SIZE); i++)
  1375. {
  1376. if (ViewSet & 0x01)
  1377. {
  1378. // Update dest information in view i
  1379. // Get best route in current view
  1380. BestRoute = Dest->ViewInfo[ViewIndices[i]].BestRoute;
  1381. // Was this the best route in view ?
  1382. if (BestRoute == Route)
  1383. {
  1384. RouteCurBestInViews |= VIEW_MASK(i);
  1385. }
  1386. }
  1387. ViewSet >>= 1;
  1388. }
  1389. //
  1390. // Compute the views where route got worse
  1391. //
  1392. WorseInViews = RouteCurBestInViews;
  1393. if (PrefChanged >= 0)
  1394. {
  1395. WorseInViews &= ~Route->RouteInfo.BelongsToViews;
  1396. }
  1397. //
  1398. // In the views that you were the best, update best route
  1399. //
  1400. for (p = Dest->RouteList.Flink;
  1401. WorseInViews && (p != &Dest->RouteList);
  1402. p = p->Flink)
  1403. {
  1404. CurrRoute = CONTAINING_RECORD(p, ROUTE_INFO, DestLE);
  1405. ViewSet = CurrRoute->RouteInfo.BelongsToViews & WorseInViews;
  1406. for (i = 0; ViewSet && (i < RTM_VIEW_MASK_SIZE); i++)
  1407. {
  1408. if (ViewSet & 0x01)
  1409. {
  1410. // Get best route in current view
  1411. BestRoute = Dest->ViewInfo[ViewIndices[i]].BestRoute;
  1412. if (BestRoute != CurrRoute)
  1413. {
  1414. Dest->ViewInfo[ViewIndices[i]].BestRoute = CurrRoute;
  1415. }
  1416. }
  1417. ViewSet >>= 1;
  1418. }
  1419. WorseInViews &= ~CurrRoute->RouteInfo.BelongsToViews;
  1420. }
  1421. //
  1422. // For some views, we end up not having a best route
  1423. //
  1424. ViewSet = WorseInViews;
  1425. for (i = 0; ViewSet && (i < RTM_VIEW_MASK_SIZE); i++)
  1426. {
  1427. if (ViewSet & 0x01)
  1428. {
  1429. Dest->ViewInfo[ViewIndices[i]].BestRoute = NULL;
  1430. }
  1431. ViewSet >>= 1;
  1432. }
  1433. Dest->BelongsToViews &= ~WorseInViews;
  1434. //
  1435. // Compute the views where route got better
  1436. //
  1437. BetterInViews = Route->RouteInfo.BelongsToViews;
  1438. //
  1439. // Check if route is best in any of its views
  1440. //
  1441. ViewSet = BetterInViews;
  1442. for (i = 0; ViewSet && (i < RTM_VIEW_MASK_SIZE); i++)
  1443. {
  1444. if (ViewSet & 0x01)
  1445. {
  1446. //
  1447. // Update dest information in view i
  1448. //
  1449. // Get best route in current view
  1450. BestRoute = Dest->ViewInfo[ViewIndices[i]].BestRoute;
  1451. //
  1452. // Is route most preferred now, while
  1453. // it was not so before this update ?
  1454. //
  1455. if ((!BestRoute) ||
  1456. ((BestRoute != Route) &&
  1457. (ComparePref(&Route->RouteInfo,
  1458. &BestRoute->RouteInfo) > 0)))
  1459. {
  1460. Dest->ViewInfo[ViewIndices[i]].BestRoute = Route;
  1461. RouteNewBestInViews |= VIEW_MASK(i);
  1462. }
  1463. }
  1464. ViewSet >>= 1;
  1465. }
  1466. Dest->BelongsToViews |= BetterInViews;
  1467. //
  1468. // Compute the views for each change type occurred
  1469. //
  1470. //
  1471. // All views affected by this add are notified
  1472. // -views route belonged to and now belongs to
  1473. //
  1474. ViewsForCT[RTM_CHANGE_TYPE_ID_ALL] =
  1475. BelongedToViews | Route->RouteInfo.BelongsToViews;
  1476. //
  1477. // If the route was or is now the best route then
  1478. // it is considered a best and forwarding change
  1479. // as we cannot tell better what exactly changed
  1480. //
  1481. ViewsForCT[RTM_CHANGE_TYPE_ID_FORWARDING] =
  1482. ViewsForCT[RTM_CHANGE_TYPE_ID_BEST] =
  1483. RouteCurBestInViews | RouteNewBestInViews;
  1484. //
  1485. // Update output flags if best route changed
  1486. //
  1487. if (ViewsForCT[RTM_CHANGE_TYPE_ID_BEST])
  1488. {
  1489. *ChangeFlags |= RTM_ROUTE_CHANGE_BEST;
  1490. }
  1491. //
  1492. // Calculate the CNs that need to be notified
  1493. //
  1494. ACQUIRE_NOTIFICATIONS_READ_LOCK(AddrFamInfo);
  1495. NotifyToCNs = ComputeCNsToBeNotified(AddrFamInfo,
  1496. Dest->DestMarkedBits,
  1497. ViewsForCT);
  1498. //
  1499. // Add to the global change list if required
  1500. //
  1501. if (NotifyToCNs)
  1502. {
  1503. AddToChangedDestLists(AddrFamInfo,
  1504. Dest,
  1505. NotifyToCNs);
  1506. }
  1507. RELEASE_NOTIFICATIONS_READ_LOCK(AddrFamInfo);
  1508. //
  1509. // Remove from old route list, and put in the new one
  1510. //
  1511. // Check the route list handle for validity
  1512. if (ARGUMENT_PRESENT(RouteListHandle))
  1513. {
  1514. RouteList = ROUTE_LIST_FROM_HANDLE(RouteListHandle);
  1515. if (RouteList)
  1516. {
  1517. ACQUIRE_ROUTE_LISTS_WRITE_LOCK(Entity);
  1518. if (!IsListEmpty(&Route->RouteListLE))
  1519. {
  1520. RemoveEntryList(&Route->RouteListLE);
  1521. }
  1522. else
  1523. {
  1524. REFERENCE_ROUTE(Route, LIST_REF);
  1525. }
  1526. InsertTailList(&RouteList->ListHead, &Route->RouteListLE);
  1527. RELEASE_ROUTE_LISTS_WRITE_LOCK(Entity);
  1528. }
  1529. }
  1530. //
  1531. // Set a timer if we want to age out the route
  1532. //
  1533. TimerContext = Route->TimerContext;
  1534. if (TimeToLive == INFINITE)
  1535. {
  1536. Route->TimerContext = NULL;
  1537. }
  1538. else
  1539. {
  1540. Route->TimerContext = AllocMemory(sizeof(ROUTE_TIMER));
  1541. if (Route->TimerContext)
  1542. {
  1543. Route->TimerContext->Route = Route;
  1544. Success = CreateTimerQueueTimer(&Route->TimerContext->Timer,
  1545. AddrFamInfo->RouteTimerQueue,
  1546. RouteExpiryTimeoutCallback,
  1547. Route->TimerContext,
  1548. TimeToLive,
  1549. 0,
  1550. 0);
  1551. if (Success)
  1552. {
  1553. REFERENCE_ROUTE(Route, TIMER_REF);
  1554. }
  1555. else
  1556. {
  1557. Status = GetLastError();
  1558. FreeMemory(Route->TimerContext);
  1559. Route->TimerContext = NULL;
  1560. }
  1561. }
  1562. }
  1563. RELEASE_DEST_WRITE_LOCK(Dest);
  1564. //
  1565. // Cancel the timer that was attached to the route
  1566. //
  1567. if (TimerContext)
  1568. {
  1569. if (DeleteTimerQueueTimer(AddrFamInfo->RouteTimerQueue,
  1570. TimerContext->Timer,
  1571. (HANDLE) -1))
  1572. {
  1573. // Timer cancelled - delete the context
  1574. FreeMemory(TimerContext);
  1575. DEREFERENCE_ROUTE(Route, TIMER_REF);
  1576. }
  1577. }
  1578. return NO_ERROR;
  1579. }