[mle] fix MleRouter::UpdateRoutes (#4146)

- Move updating link quality ahead of updating routes to fix potential
  wrong routing path switch

  - In each do-while loop, the method traverse each router id and
    update the routing path to the router (RU) according to new
    Route64 TLV received from the neighbor, and also update link
    quality out to the neighbor (LU) when the router id is that of the
    receiver. So, there could be RUs before LU and also after LU. The
    RUs before LU are using wrong link quality to the neighbor for
    comparison, thus could cause lower cost routing path be replaced
    by higher cost routing path or even lost.

  - This commit moves LU ahead of RUs to make sure all RUs are using
    correct link quality to the neighbor for calculation.

- Remove the unnecessary do-while loop

  - The do-while loop is unnecessary after LU is moved.

  - For each RU, the calculation depends on following factors:

    - F1: Routing cost to the router using current nexthop

    - F2: Routing cost to the router using the neighbor as nexthop

  - So, each RU is independent of each other, and all RUs can be
    updated in one loop.

- Skip RU when router == neighbor is satisfied

  - The original RU code actually do nothing when router == neighbor
    is satisfied. Real routing updates only happen in if (router !=
    neighbor) blocks.

  - Logically speaking, the routing path to the neighbor can not be
    updated by processing Route64 TLV from the neighbor itself.

  - By skipping earlier, the code is more clear and easier to
    understand.

- Replace (cost + mRouterTable.GetLinkCost(*neighbor) <=
  kMaxRouteCost) with (cost + mRouterTable.GetLinkCost(*neighbor) <
  kMaxRouteCost)

  - Even through the routing path with cost == kMaxRotueCost can be
    established, it will never be utilized in the current OT
    implementation. In method MleRouter::GetNextHop, nexthop is only
    used if ((routeCost + GetLinkCost(router->GetNextHop())) <
    linkCost). Since linkCost <= kMaxRouteCost, nexthop with routing
    path cost >= kMaxRouteCost will never be used.

  - Use cost < kMaxRouteCost to indicate finite routing cost and cost
    >= kMaxRouteCost to indicate infinite routing cost for consistency
This commit is contained in:
Simon Lin
2019-10-08 09:21:00 -07:00
committed by Jonathan Hui
parent 386746b1bf
commit cc91b2c72b
2 changed files with 110 additions and 113 deletions
+109 -113
View File
@@ -1421,132 +1421,89 @@ exit:
void MleRouter::UpdateRoutes(const RouteTlv &aRoute, uint8_t aRouterId)
{
Router *neighbor;
uint8_t curCost;
uint8_t newCost;
uint8_t oldNextHop;
uint8_t cost;
uint8_t linkQuality;
bool update;
bool resetAdvInterval = false;
bool changed = false;
neighbor = mRouterTable.GetRouter(aRouterId);
VerifyOrExit(neighbor != NULL);
// update link quality out to neighbor
changed = UpdateLinkQualityOut(aRoute, *neighbor, resetAdvInterval);
// update routes
do
for (uint8_t i = 0, routeCount = 0; i <= kMaxRouterId; i++)
{
update = false;
Router *router;
Router *nextHop;
uint8_t oldNextHop;
uint8_t cost;
for (uint8_t i = 0, routeCount = 0; i <= kMaxRouterId; i++)
if (!aRoute.IsRouterIdSet(i))
{
Router *router;
Router *nextHop;
if (!aRoute.IsRouterIdSet(i))
{
continue;
}
router = mRouterTable.GetRouter(i);
if (router == NULL)
{
routeCount++;
continue;
}
if (router->GetRloc16() == GetRloc16())
{
linkQuality = aRoute.GetLinkQualityIn(routeCount);
if (neighbor->GetLinkQualityOut() != linkQuality)
{
uint8_t oldLinkCost = mRouterTable.GetLinkCost(*neighbor);
neighbor->SetLinkQualityOut(linkQuality);
nextHop = mRouterTable.GetRouter(neighbor->GetNextHop());
// reset MLE advertisement timer if neighbor route cost changed to or from infinite
if (nextHop == NULL &&
(oldLinkCost >= kMaxRouteCost) != (mRouterTable.GetLinkCost(*neighbor) >= kMaxRouteCost))
{
resetAdvInterval = true;
}
update = true;
}
}
else
{
oldNextHop = router->GetNextHop();
nextHop = mRouterTable.GetRouter(oldNextHop);
if (router == neighbor)
{
cost = 0;
}
else
{
cost = aRoute.GetRouteCost(routeCount);
if (cost == 0)
{
cost = kMaxRouteCost;
}
}
if (nextHop == NULL || nextHop == neighbor)
{
// route has no next hop or next hop is neighbor (sender)
if (router != neighbor)
{
if (cost + mRouterTable.GetLinkCost(*neighbor) <= kMaxRouteCost)
{
if (nextHop == NULL && mRouterTable.GetLinkCost(*router) >= kMaxRouteCost)
{
resetAdvInterval = true;
}
router->SetNextHop(aRouterId);
router->SetCost(cost);
changed = true;
}
else if (nextHop == neighbor)
{
if (mRouterTable.GetLinkCost(*router) >= kMaxRouteCost)
{
resetAdvInterval = true;
}
router->SetNextHop(kInvalidRouterId);
router->SetCost(0);
router->SetLastHeard(TimerMilli::GetNow());
changed = true;
}
}
}
else
{
curCost = router->GetCost() + mRouterTable.GetLinkCost(*nextHop);
newCost = cost + mRouterTable.GetLinkCost(*neighbor);
if (newCost < curCost && router != neighbor)
{
router->SetNextHop(aRouterId);
router->SetCost(cost);
changed = true;
}
}
update |= router->GetNextHop() != oldNextHop;
}
routeCount++;
continue;
}
changed |= update;
router = mRouterTable.GetRouter(i);
} while (update);
if (router == NULL || router->GetRloc16() == GetRloc16() || router == neighbor)
{
routeCount++;
continue;
}
oldNextHop = router->GetNextHop();
nextHop = mRouterTable.GetRouter(oldNextHop);
cost = aRoute.GetRouteCost(routeCount);
if (cost == 0)
{
cost = kMaxRouteCost;
}
if (nextHop == NULL || nextHop == neighbor)
{
// route has no next hop or next hop is neighbor (sender)
if (cost + mRouterTable.GetLinkCost(*neighbor) < kMaxRouteCost)
{
if (nextHop == NULL && mRouterTable.GetLinkCost(*router) >= kMaxRouteCost)
{
resetAdvInterval = true;
}
router->SetNextHop(aRouterId);
router->SetCost(cost);
changed = true;
}
else if (nextHop == neighbor)
{
if (mRouterTable.GetLinkCost(*router) >= kMaxRouteCost)
{
resetAdvInterval = true;
}
router->SetNextHop(kInvalidRouterId);
router->SetCost(0);
router->SetLastHeard(TimerMilli::GetNow());
changed = true;
}
}
else
{
uint8_t curCost = router->GetCost() + mRouterTable.GetLinkCost(*nextHop);
uint8_t newCost = cost + mRouterTable.GetLinkCost(*neighbor);
if (newCost < curCost)
{
router->SetNextHop(aRouterId);
router->SetCost(cost);
changed = true;
}
}
routeCount++;
}
if (resetAdvInterval)
{
@@ -1567,12 +1524,51 @@ void MleRouter::UpdateRoutes(const RouteTlv &aRoute, uint8_t aRouterId)
router.GetLinkInfo().GetLinkQuality(), router.GetLinkQualityOut());
}
#else
OT_UNUSED_VARIABLE(changed);
#endif
exit:
return;
}
bool MleRouter::UpdateLinkQualityOut(const RouteTlv &aRoute, Router &aNeighbor, bool &aResetAdvInterval)
{
bool changed = false;
uint8_t linkQuality;
uint8_t myRouterId;
uint8_t myRouteCount;
uint8_t oldLinkCost;
Router *nextHop;
myRouterId = GetRouterId(GetRloc16());
VerifyOrExit(aRoute.IsRouterIdSet(myRouterId));
myRouteCount = 0;
for (uint8_t i = 0; i < myRouterId; i++)
{
myRouteCount += aRoute.IsRouterIdSet(i);
}
linkQuality = aRoute.GetLinkQualityIn(myRouteCount);
VerifyOrExit(aNeighbor.GetLinkQualityOut() != linkQuality);
oldLinkCost = mRouterTable.GetLinkCost(aNeighbor);
aNeighbor.SetLinkQualityOut(linkQuality);
nextHop = mRouterTable.GetRouter(aNeighbor.GetNextHop());
// reset MLE advertisement timer if neighbor route cost changed to or from infinite
if (nextHop == NULL && (oldLinkCost >= kMaxRouteCost) != (mRouterTable.GetLinkCost(aNeighbor) >= kMaxRouteCost))
{
aResetAdvInterval = true;
}
changed = true;
exit:
return changed;
}
otError MleRouter::HandleParentRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
otError error = OT_ERROR_NONE;
+1
View File
@@ -731,6 +731,7 @@ private:
void SynchronizeChildNetworkData(void);
otError UpdateChildAddresses(const Message &aMessage, uint16_t aOffset, Child &aChild);
void UpdateRoutes(const RouteTlv &aRoute, uint8_t aRouterId);
bool UpdateLinkQualityOut(const RouteTlv &aRoute, Router &aNeighbor, bool &aResetAdvInterval);
static void HandleAddressSolicitResponse(void * aContext,
otMessage * aMessage,