diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 7af04cb16..9ddade460 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -962,7 +962,7 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest) switch (error = ProcessRouteTlv(aRxInfo, routeTlv)) { case kErrorNone: - UpdateRoutes(routeTlv, routerId); + mRouterTable.UpdateRoutes(routeTlv, routerId); // Need to update router after ProcessRouteTlv router = mRouterTable.FindRouterById(routerId); OT_ASSERT(router != nullptr); @@ -1035,22 +1035,6 @@ exit: return error; } -uint8_t MleRouter::GetLinkCost(uint8_t aRouterId) const -{ - uint8_t rval = kMaxRouteCost; - const Router *router; - - router = mRouterTable.FindRouterById(aRouterId); - - // `nullptr` aRouterId indicates non-existing next hop, hence return kMaxRouteCost for it. - VerifyOrExit(router != nullptr); - - rval = mRouterTable.GetLinkCost(*router); - -exit: - return rval; -} - Error MleRouter::SetRouterSelectionJitter(uint8_t aRouterJitter) { Error error = kErrorNone; @@ -1394,7 +1378,7 @@ Error MleRouter::HandleAdvertisement(RxInfo &aRxInfo) break; } - UpdateRoutes(routeTlv, routerId); + mRouterTable.UpdateRoutes(routeTlv, routerId); exit: if (aRxInfo.mNeighbor && aRxInfo.mNeighbor->GetRloc16() != sourceAddress) @@ -1406,150 +1390,6 @@ exit: return error; } -void MleRouter::UpdateRoutes(const RouteTlv &aRouteTlv, uint8_t aRouterId) -{ - Router *neighbor; - bool resetAdvInterval = false; - bool changed = false; - - neighbor = mRouterTable.FindRouterById(aRouterId); - VerifyOrExit(neighbor != nullptr); - - // update link quality out to neighbor - changed = UpdateLinkQualityOut(aRouteTlv, *neighbor, resetAdvInterval); - - // update routes - for (uint8_t routerId = 0, routeCount = 0; routerId <= kMaxRouterId; routerId++) - { - Router *router; - Router *nextHop; - uint8_t cost; - - if (!aRouteTlv.IsRouterIdSet(routerId)) - { - continue; - } - - router = mRouterTable.FindRouterById(routerId); - - if (router == nullptr || router->GetRloc16() == GetRloc16() || router == neighbor) - { - routeCount++; - continue; - } - - nextHop = mRouterTable.FindNextHopOf(*router); - - cost = aRouteTlv.GetRouteCost(routeCount); - - if (cost == 0) - { - cost = kMaxRouteCost; - } - - if (nextHop == nullptr || nextHop == neighbor) - { - // router has no next hop or next hop is neighbor (sender) - - if (cost + mRouterTable.GetLinkCost(*neighbor) < kMaxRouteCost) - { - if (nextHop == nullptr && mRouterTable.GetLinkCost(*router) >= kMaxRouteCost) - { - resetAdvInterval = true; - } - - if (router->GetNextHop() != aRouterId) - { - router->SetNextHop(aRouterId); - changed = true; - } - - if (router->GetCost() != cost) - { - 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) - { - ResetAdvertiseInterval(); - } - - if (changed) - { - Get().LogRouteTable(); - } - -exit: - return; -} - -bool MleRouter::UpdateLinkQualityOut(const RouteTlv &aRouteTlv, Router &aNeighbor, bool &aResetAdvInterval) -{ - bool changed = false; - LinkQuality linkQuality; - uint8_t myRouterId; - uint8_t myRouteCount; - uint8_t oldLinkCost; - Router *nextHop; - - myRouterId = RouterIdFromRloc16(GetRloc16()); - VerifyOrExit(aRouteTlv.IsRouterIdSet(myRouterId)); - - myRouteCount = 0; - for (uint8_t routerId = 0; routerId < myRouterId; routerId++) - { - myRouteCount += aRouteTlv.IsRouterIdSet(routerId); - } - - linkQuality = aRouteTlv.GetLinkQualityIn(myRouteCount); - VerifyOrExit(aNeighbor.GetLinkQualityOut() != linkQuality); - - oldLinkCost = mRouterTable.GetLinkCost(aNeighbor); - - aNeighbor.SetLinkQualityOut(linkQuality); - nextHop = mRouterTable.FindNextHopOf(aNeighbor); - - // reset MLE advertisement timer if neighbor route cost changed to or from infinite - if (nextHop == nullptr && (oldLinkCost >= kMaxRouteCost) != (mRouterTable.GetLinkCost(aNeighbor) >= kMaxRouteCost)) - { - aResetAdvInterval = true; - } - changed = true; - -exit: - return changed; -} - void MleRouter::HandleParentRequest(RxInfo &aRxInfo) { Error error = kErrorNone; @@ -1584,9 +1424,9 @@ void MleRouter::HandleParentRequest(RxInfo &aRxInfo) leader = mRouterTable.GetLeader(); OT_ASSERT(leader != nullptr); - VerifyOrExit(IsLeader() || GetLinkCost(GetLeaderId()) < kMaxRouteCost || + VerifyOrExit(IsLeader() || mRouterTable.GetLinkCost(GetLeaderId()) < kMaxRouteCost || (IsChild() && leader->GetCost() + 1 < kMaxRouteCost) || - (leader->GetCost() + GetLinkCost(leader->GetNextHop()) < kMaxRouteCost), + (leader->GetCost() + mRouterTable.GetLinkCost(leader->GetNextHop()) < kMaxRouteCost), error = kErrorDrop); // 4. It is a REED and there are already `kMaxRouters` active routers in @@ -3441,128 +3281,6 @@ exit: return; } -uint16_t MleRouter::GetNextHop(uint16_t aDestination) -{ - uint8_t destinationId = RouterIdFromRloc16(aDestination); - uint8_t routeCost; - uint8_t linkCost; - uint16_t rval = Mac::kShortAddrInvalid; - const Router *router; - const Router *nextHop; - - if (IsChild()) - { - ExitNow(rval = Mle::GetNextHop(aDestination)); - } - - // The frame is destined to a child - if (destinationId == mRouterId) - { - ExitNow(rval = aDestination); - } - - router = mRouterTable.FindRouterById(destinationId); - VerifyOrExit(router != nullptr); - - linkCost = GetLinkCost(destinationId); - routeCost = GetRouteCost(aDestination); - - if ((routeCost + GetLinkCost(router->GetNextHop())) < linkCost) - { - nextHop = mRouterTable.FindNextHopOf(*router); - VerifyOrExit(nextHop != nullptr && !nextHop->IsStateInvalid()); - - rval = Rloc16FromRouterId(router->GetNextHop()); - } - else if (linkCost < kMaxRouteCost) - { - rval = Rloc16FromRouterId(destinationId); - } - -exit: - return rval; -} - -uint8_t MleRouter::GetPathCost(uint16_t aDestRloc16) const -{ - uint8_t cost = kMaxRouteCost; - uint8_t destRouterId; - const Router *router; - const Router *nextHop; - - if (aDestRloc16 == GetRloc16()) - { - // Destination is this device, return cost as zero. - // This is also valid when device is a child. - ExitNow(cost = 0); - } - - if (IsChild()) - { - // If device is a child, then check if destination is our parent - // and determine cost based on the link quality to parent. - // Otherwise we cannot determine the cost. - - VerifyOrExit(aDestRloc16 == GetParent().GetRloc16()); - cost = CostForLinkQuality(GetParent().GetLinkQualityIn()); - ExitNow(); - } - - destRouterId = RouterIdFromRloc16(aDestRloc16); - - if (destRouterId == RouterIdFromRloc16(GetRloc16())) - { - // `aDestRloc16` is a one of device's children. We know the - // device is not a child from `IsChild()` check above and - // that the destination is not device itself (from first `if` - // check above). - - const Child *child = Get().FindChild(aDestRloc16, Child::kInStateValid); - - VerifyOrExit(child != nullptr); - ExitNow(cost = CostForLinkQuality(child->GetLinkQualityIn())); - } - - router = mRouterTable.FindRouterById(destRouterId); - - VerifyOrExit(router != nullptr); - - cost = mRouterTable.GetLinkCost(*router); - - nextHop = mRouterTable.FindNextHopOf(*router); - - if (nextHop != nullptr) - { - // Determine whether direct link or forwarding hop link - // has a lower cost. - cost = Min(cost, static_cast(router->GetCost() + mRouterTable.GetLinkCost(*nextHop))); - } - - if (!IsActiveRouter(aDestRloc16)) - { - // Destination is a child. we assume best link quality - // between destination and its parent router. - cost += kCostForLinkQuality3; - } - -exit: - return cost; -} - -uint8_t MleRouter::GetRouteCost(uint16_t aRloc16) const -{ - uint8_t rval = kMaxRouteCost; - const Router *router; - - router = mRouterTable.FindRouterByRloc16(aRloc16); - VerifyOrExit(router != nullptr && mRouterTable.FindNextHopOf(*router) != nullptr); - - rval = router->GetCost(); - -exit: - return rval; -} - Error MleRouter::SetPreferredRouterId(uint8_t aRouterId) { Error error = kErrorNone; @@ -4054,11 +3772,11 @@ void MleRouter::FillConnectivityTlv(ConnectivityTlv &aTlv) case kRoleRouter: if (leader != nullptr) { - cost += GetLinkCost(leader->GetNextHop()); + cost += mRouterTable.GetLinkCost(leader->GetNextHop()); - if (!IsRouterIdValid(leader->GetNextHop()) || GetLinkCost(GetLeaderId()) < cost) + if (!IsRouterIdValid(leader->GetNextHop()) || mRouterTable.GetLinkCost(GetLeaderId()) < cost) { - cost = GetLinkCost(GetLeaderId()); + cost = mRouterTable.GetLinkCost(GetLeaderId()); } } diff --git a/src/core/thread/mle_router.hpp b/src/core/thread/mle_router.hpp index b80721977..925b2fee9 100644 --- a/src/core/thread/mle_router.hpp +++ b/src/core/thread/mle_router.hpp @@ -222,7 +222,7 @@ public: * @returns A RLOC16 of the next hop if a route is known, kInvalidRloc16 otherwise. * */ - uint16_t GetNextHop(uint16_t aDestination); + uint16_t GetNextHop(uint16_t aDestination) { return mRouterTable.GetNextHop(aDestination); } /** * This method returns the NETWORK_ID_TIMEOUT value. @@ -240,26 +240,6 @@ public: */ void SetNetworkIdTimeout(uint8_t aTimeout) { mNetworkIdTimeout = aTimeout; } - /** - * This method returns the route cost to a RLOC16. - * - * @param[in] aRloc16 The RLOC16 of the destination. - * - * @returns The route cost to a RLOC16. - * - */ - uint8_t GetRouteCost(uint16_t aRloc16) const; - - /** - * This method returns the link cost to the given Router. - * - * @param[in] aRouterId The Router ID. - * - * @returns The link cost to the Router. - * - */ - uint8_t GetLinkCost(uint8_t aRouterId) const; - /** * This method returns the minimum mesh path cost to the given RLOC16 * @@ -268,7 +248,7 @@ public: * @returns The minimum mesh path cost to @p aDestRloc16 (via direct link or forwarding). * */ - uint8_t GetPathCost(uint16_t aDestRloc16) const; + uint8_t GetPathCost(uint16_t aDestRloc16) const { return mRouterTable.GetPathCost(aDestRloc16); } /** * This method returns the ROUTER_SELECTION_JITTER value. @@ -617,8 +597,6 @@ private: void StopLeader(void); void SynchronizeChildNetworkData(void); Error UpdateChildAddresses(const Message &aMessage, uint16_t aOffset, uint16_t aLength, Child &aChild); - void UpdateRoutes(const RouteTlv &aRouteTlv, uint8_t aRouterId); - bool UpdateLinkQualityOut(const RouteTlv &aRouteTlv, Router &aNeighbor, bool &aResetAdvInterval); bool HasNeighborWithGoodLinkQuality(void) const; static void HandleAddressSolicitResponse(void *aContext, diff --git a/src/core/thread/router_table.cpp b/src/core/thread/router_table.cpp index 838022a7a..70a723e8f 100644 --- a/src/core/thread/router_table.cpp +++ b/src/core/thread/router_table.cpp @@ -358,6 +358,147 @@ exit: return rval; } +uint8_t RouterTable::GetLinkCost(uint8_t aRouterId) const +{ + uint8_t rval = Mle::kMaxRouteCost; + const Router *router; + + router = FindRouterById(aRouterId); + + // `nullptr` aRouterId indicates non-existing next hop, hence return kMaxRouteCost for it. + VerifyOrExit(router != nullptr); + + rval = GetLinkCost(*router); + +exit: + return rval; +} + +uint8_t RouterTable::GetPathCost(uint16_t aDestRloc16) const +{ + uint8_t cost = Mle::kMaxRouteCost; + uint8_t destRouterId; + const Router *router; + const Router *nextHop; + + if (aDestRloc16 == Get().GetRloc16()) + { + // Destination is this device, return cost as zero. + // This is also valid when device is a child. + ExitNow(cost = 0); + } + + if (Get().IsChild()) + { + // If device is a child, then check if destination is our parent + // and determine cost based on the link quality to parent. + // Otherwise we cannot determine the cost. + + VerifyOrExit(aDestRloc16 == Get().GetParent().GetRloc16()); + cost = CostForLinkQuality(Get().GetParent().GetLinkQualityIn()); + ExitNow(); + } + + destRouterId = Mle::RouterIdFromRloc16(aDestRloc16); + + if (destRouterId == Mle::RouterIdFromRloc16(Get().GetRloc16())) + { + // `aDestRloc16` is a one of device's children. We know the + // device is not a child from `IsChild()` check above and + // that the destination is not device itself (from first `if` + // check above). + + const Child *child = Get().FindChild(aDestRloc16, Child::kInStateValid); + + VerifyOrExit(child != nullptr); + ExitNow(cost = CostForLinkQuality(child->GetLinkQualityIn())); + } + + router = FindRouterById(destRouterId); + + VerifyOrExit(router != nullptr); + + cost = GetLinkCost(*router); + + nextHop = FindNextHopOf(*router); + + if (nextHop != nullptr) + { + // Determine whether direct link or forwarding hop link + // has a lower cost. + cost = Min(cost, static_cast(router->GetCost() + GetLinkCost(*nextHop))); + } + + if (!Mle::IsActiveRouter(aDestRloc16)) + { + // Destination is a child. we assume best link quality + // between destination and its parent router. + cost += kCostForLinkQuality3; + } + +exit: + return cost; +} + +uint16_t RouterTable::GetNextHop(uint16_t aDestination) const +{ + uint8_t destinationId = Mle::RouterIdFromRloc16(aDestination); + uint8_t routeCost; + uint8_t linkCost; + uint16_t rval = Mac::kShortAddrInvalid; + const Router *router; + const Router *nextHop; + + if (Get().IsChild()) + { + const Router &parent = Get().GetParent(); + + VerifyOrExit(parent.IsStateValid()); + ExitNow(rval = parent.GetRloc16()); + } + + // The frame is destined to a child + if (destinationId == Mle::RouterIdFromRloc16(Get().GetRloc16())) + { + ExitNow(rval = aDestination); + } + + router = FindRouterById(destinationId); + VerifyOrExit(router != nullptr); + + linkCost = GetLinkCost(destinationId); + routeCost = GetRouteCost(aDestination); + + if ((routeCost + GetLinkCost(router->GetNextHop())) < linkCost) + { + nextHop = FindNextHopOf(*router); + VerifyOrExit(nextHop != nullptr && !nextHop->IsStateInvalid()); + + rval = Mle::Rloc16FromRouterId(router->GetNextHop()); + } + else if (linkCost < Mle::kMaxRouteCost) + { + rval = Mle::Rloc16FromRouterId(destinationId); + } + +exit: + return rval; +} + +uint8_t RouterTable::GetRouteCost(uint16_t aRloc16) const +{ + uint8_t rval = Mle::kMaxRouteCost; + const Router *router; + + router = FindRouterByRloc16(aRloc16); + VerifyOrExit(router != nullptr && FindNextHopOf(*router) != nullptr); + + rval = router->GetCost(); + +exit: + return rval; +} + void RouterTable::UpdateRouterIdSet(uint8_t aRouterIdSequence, const Mle::RouterIdSet &aRouterIdSet) { bool shouldAdd = false; @@ -408,6 +549,151 @@ exit: return; } +void RouterTable::UpdateRoutes(const Mle::RouteTlv &aRouteTlv, uint8_t aRouterId) +{ + Router *neighbor; + bool resetAdvInterval = false; + bool changed = false; + + neighbor = FindRouterById(aRouterId); + VerifyOrExit(neighbor != nullptr); + + // update link quality out to neighbor + changed = UpdateLinkQualityOut(aRouteTlv, *neighbor, resetAdvInterval); + + // update routes + for (uint8_t routerId = 0, routeCount = 0; routerId <= Mle::kMaxRouterId; routerId++) + { + Router *router; + Router *nextHop; + uint8_t cost; + + if (!aRouteTlv.IsRouterIdSet(routerId)) + { + continue; + } + + router = FindRouterById(routerId); + + if (router == nullptr || router->GetRloc16() == Get().GetRloc16() || router == neighbor) + { + routeCount++; + continue; + } + + nextHop = FindNextHopOf(*router); + + cost = aRouteTlv.GetRouteCost(routeCount); + + if (cost == 0) + { + cost = Mle::kMaxRouteCost; + } + + if (nextHop == nullptr || nextHop == neighbor) + { + // router has no next hop or next hop is neighbor (sender) + + if (cost + GetLinkCost(*neighbor) < Mle::kMaxRouteCost) + { + if (nextHop == nullptr && GetLinkCost(*router) >= Mle::kMaxRouteCost) + { + resetAdvInterval = true; + } + + if (router->GetNextHop() != aRouterId) + { + router->SetNextHop(aRouterId); + changed = true; + } + + if (router->GetCost() != cost) + { + router->SetCost(cost); + changed = true; + } + } + else if (nextHop == neighbor) + { + if (GetLinkCost(*router) >= Mle::kMaxRouteCost) + { + resetAdvInterval = true; + } + + router->SetNextHop(Mle::kInvalidRouterId); + router->SetCost(0); + router->SetLastHeard(TimerMilli::GetNow()); + changed = true; + } + } + else + { + uint8_t curCost = router->GetCost() + GetLinkCost(*nextHop); + uint8_t newCost = cost + GetLinkCost(*neighbor); + + if (newCost < curCost) + { + router->SetNextHop(aRouterId); + router->SetCost(cost); + changed = true; + } + } + + routeCount++; + } + + if (resetAdvInterval) + { + Get().ResetAdvertiseInterval(); + } + + if (changed) + { + LogRouteTable(); + } + +exit: + return; +} + +bool RouterTable::UpdateLinkQualityOut(const Mle::RouteTlv &aRouteTlv, Router &aNeighbor, bool &aResetAdvInterval) +{ + bool changed = false; + LinkQuality linkQuality; + uint8_t myRouterId; + uint8_t myRouteCount; + uint8_t oldLinkCost; + Router *nextHop; + + myRouterId = Mle::RouterIdFromRloc16(Get().GetRloc16()); + VerifyOrExit(aRouteTlv.IsRouterIdSet(myRouterId)); + + myRouteCount = 0; + for (uint8_t routerId = 0; routerId < myRouterId; routerId++) + { + myRouteCount += aRouteTlv.IsRouterIdSet(routerId); + } + + linkQuality = aRouteTlv.GetLinkQualityIn(myRouteCount); + VerifyOrExit(aNeighbor.GetLinkQualityOut() != linkQuality); + + oldLinkCost = GetLinkCost(aNeighbor); + + aNeighbor.SetLinkQualityOut(linkQuality); + nextHop = FindNextHopOf(aNeighbor); + + // reset MLE advertisement timer if neighbor route cost changed to or from infinite + if (nextHop == nullptr && (oldLinkCost >= Mle::kMaxRouteCost) != (GetLinkCost(aNeighbor) >= Mle::kMaxRouteCost)) + { + aResetAdvInterval = true; + } + + changed = true; + +exit: + return changed; +} + void RouterTable::FillRouteTlv(Mle::RouteTlv &aRouteTlv, const Neighbor *aNeighbor) const { uint8_t routerIdSequence = mRouterIdSequence; diff --git a/src/core/thread/router_table.hpp b/src/core/thread/router_table.hpp index f67678564..8797582f8 100644 --- a/src/core/thread/router_table.hpp +++ b/src/core/thread/router_table.hpp @@ -144,6 +144,36 @@ public: */ uint8_t GetLinkCost(const Router &aRouter) const; + /** + * This method returns the link cost to the given Router. + * + * @param[in] aRouterId The Router ID. + * + * @returns The link cost to the Router. + * + */ + uint8_t GetLinkCost(uint8_t aRouterId) const; + + /** + * This method returns the minimum mesh path cost to the given RLOC16 + * + * @param[in] aDestRloc16 The RLOC16 of destination + * + * @returns The minimum mesh path cost to @p aDestRloc16 (via direct link or forwarding). + * + */ + uint8_t GetPathCost(uint16_t aDestRloc16) const; + + /** + * This method returns the next hop towards an RLOC16 destination. + * + * @param[in] aDestination The RLOC16 of the destination. + * + * @returns A RLOC16 of the next hop if a route is known, kInvalidRloc16 otherwise. + * + */ + uint16_t GetNextHop(uint16_t aDestination) const; + /** * This method finds the router for a given Router ID. * @@ -286,6 +316,15 @@ public: */ void UpdateRouterIdSet(uint8_t aRouterIdSequence, const Mle::RouterIdSet &aRouterIdSet); + /** + * This method updates the routes based on a received `RouteTlv` from a neighboring router. + * + * @param[in] aRouteTlv The received `RouteTlv` + * @param[in] aRouterId The router ID of neighboring router from which @p aRouteTlv is received. + * + */ + void UpdateRoutes(const Mle::RouteTlv &aRouteTlv, uint8_t aRouterId); + /** * This method gets the allocated Router ID set. * @@ -371,6 +410,9 @@ private: return AsNonConst(AsConst(this)->FindRouter(aMatcher)); } + bool UpdateLinkQualityOut(const Mle::RouteTlv &aRouteTlv, Router &aNeighbor, bool &aResetAdvInterval); + uint8_t GetRouteCost(uint16_t aRloc16) const; + class RouterIdMap { public: