mirror of
https://github.com/espressif/openthread.git
synced 2026-09-15 21:50:08 +00:00
[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:
+109
-113
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user