[router-table] move cost calc and related methods to RouterTable (#8623)

This commit moves existing methods for cost and next hop calculation
and updating router table entries to `RouterTable` class from
`MleRouter`.
This commit is contained in:
Abtin Keshavarzian
2023-01-09 09:50:08 -08:00
committed by GitHub
parent bf5576c93b
commit b5fafccdef
4 changed files with 337 additions and 313 deletions
+7 -289
View File
@@ -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<RouterTable>().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<ChildTable>().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<uint8_t>(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());
}
}
+2 -24
View File
@@ -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,
+286
View File
@@ -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<Mle::Mle>().GetRloc16())
{
// Destination is this device, return cost as zero.
// This is also valid when device is a child.
ExitNow(cost = 0);
}
if (Get<Mle::MleRouter>().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<Mle::Mle>().GetParent().GetRloc16());
cost = CostForLinkQuality(Get<Mle::Mle>().GetParent().GetLinkQualityIn());
ExitNow();
}
destRouterId = Mle::RouterIdFromRloc16(aDestRloc16);
if (destRouterId == Mle::RouterIdFromRloc16(Get<Mle::Mle>().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<ChildTable>().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<uint8_t>(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<Mle::Mle>().IsChild())
{
const Router &parent = Get<Mle::Mle>().GetParent();
VerifyOrExit(parent.IsStateValid());
ExitNow(rval = parent.GetRloc16());
}
// The frame is destined to a child
if (destinationId == Mle::RouterIdFromRloc16(Get<Mle::Mle>().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<Mle::Mle>().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<Mle::MleRouter>().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<Mle::Mle>().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;
+42
View File
@@ -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: