[mle-router] add RouterRoleTransition nested class (#9490)

This commit adds `RouterRoleTransition` nested class to `MleRouter`.
This class tracks the timeout and jitter intervals for router role
transitions, i.e., device upgrading to router role from REED or
downgrading from router to REED. It provides helper methods like
`IsPending()` and `StartTimeout()` to check if role transition
is pending or to start the timeout countdown. These methods help to
simplify the code and make it more readable.
This commit is contained in:
Abtin Keshavarzian
2023-10-06 12:09:48 -07:00
committed by GitHub
parent 4f6b4923aa
commit 50e20c8958
7 changed files with 87 additions and 65 deletions
+1 -1
View File
@@ -222,7 +222,7 @@ uint8_t otThreadGetRouterSelectionJitter(otInstance *aInstance)
void otThreadSetRouterSelectionJitter(otInstance *aInstance, uint8_t aRouterJitter)
{
IgnoreError(AsCoreType(aInstance).Get<Mle::MleRouter>().SetRouterSelectionJitter(aRouterJitter));
AsCoreType(aInstance).Get<Mle::MleRouter>().SetRouterSelectionJitter(aRouterJitter);
}
otError otThreadGetChildInfoById(otInstance *aInstance, uint16_t aChildId, otChildInfo *aChildInfo)
+4 -3
View File
@@ -289,9 +289,10 @@ exit:
void Local::HandleTimeTick(void)
{
// Delay registration when `GetRouterSelectionJitterTimeout()` is non-zero,
// which indicates device may soon switch its role (e.g., REED to router).
VerifyOrExit(Get<Mle::MleRouter>().GetRouterSelectionJitterTimeout() == 0);
// Delay registration while router role transition is pending
// (i.e., device may soon switch from REED to router role).
VerifyOrExit(!Get<Mle::MleRouter>().IsRouterRoleTransitionPending());
if (mRegistrationTimeout > 0)
{
+1 -1
View File
@@ -334,7 +334,7 @@ void DuaManager::HandleNotifierEvents(Events aEvents)
else if (mle.IsExpectedToBecomeRouterSoon())
{
// Will check again in case the device decides to stay REED when jitter timeout expires.
UpdateRegistrationDelay(mle.GetRouterSelectionJitterTimeout() + kNewRouterRegistrationDelay + 1);
UpdateRegistrationDelay(mle.GetRouterRoleTransitionTimeout() + kNewRouterRegistrationDelay + 1);
}
#endif
}
+1 -1
View File
@@ -770,7 +770,7 @@ void Mle::InformPreviousChannel(void)
VerifyOrExit(IsChild() || IsRouter());
#if OPENTHREAD_FTD
VerifyOrExit(!IsFullThreadDevice() || IsRouter() || Get<MleRouter>().GetRouterSelectionJitterTimeout() == 0);
VerifyOrExit(!IsFullThreadDevice() || IsRouter() || !Get<MleRouter>().IsRouterRoleTransitionPending());
#endif
mAlternatePanId = Mac::kPanIdBroadcast;
+42 -49
View File
@@ -82,8 +82,6 @@ MleRouter::MleRouter(Instance &aInstance)
, mPreviousPartitionId(0)
, mPreviousPartitionRouterIdSequence(0)
, mPreviousPartitionIdTimeout(0)
, mRouterSelectionJitter(kRouterSelectionJitter)
, mRouterSelectionJitterTimeout(0)
, mChildRouterLinks(kChildRouterLinks)
, mParentPriority(kParentPriorityUnspecified)
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
@@ -193,16 +191,13 @@ void MleRouter::HandleSecurityPolicyChanged(void)
VerifyOrExit(IsRouterOrLeader() && !IsRouterEligible());
// `mRouterSelectionJitterTimeout` is non-zero if we are already
// waiting to downgrade.
VerifyOrExit(!mRouterRoleTransition.IsPending());
VerifyOrExit(mRouterSelectionJitterTimeout == 0);
mRouterSelectionJitterTimeout = 1 + Random::NonCrypto::GetUint8InRange(0, mRouterSelectionJitter);
mRouterRoleTransition.StartTimeout();
if (IsLeader())
{
mRouterSelectionJitterTimeout += kLeaderDowngradeExtraDelay;
mRouterRoleTransition.IncreaseTimeout(kLeaderDowngradeExtraDelay);
}
exit:
@@ -229,7 +224,7 @@ Error MleRouter::BecomeRouter(ThreadStatusTlv::Status aStatus)
LogInfo("Attempt to become router");
Get<MeshForwarder>().SetRxOnWhenIdle(true);
mRouterSelectionJitterTimeout = 0;
mRouterRoleTransition.StopTimeout();
switch (mRole)
{
@@ -329,7 +324,7 @@ void MleRouter::HandleChildStart(AttachMode aMode)
{
mAddressSolicitRejected = false;
mRouterSelectionJitterTimeout = 1 + Random::NonCrypto::GetUint8InRange(0, mRouterSelectionJitter);
mRouterRoleTransition.StartTimeout();
StopLeader();
Get<TimeTicker>().RegisterReceiver(TimeTicker::kMleRouter);
@@ -1072,18 +1067,6 @@ exit:
return error;
}
Error MleRouter::SetRouterSelectionJitter(uint8_t aRouterJitter)
{
Error error = kErrorNone;
VerifyOrExit(aRouterJitter > 0, error = kErrorInvalidArgs);
mRouterSelectionJitter = aRouterJitter;
exit:
return error;
}
Error MleRouter::ProcessRouteTlv(const RouteTlv &aRouteTlv, RxInfo &aRxInfo)
{
// This method processes `aRouteTlv` read from an MLE message.
@@ -1292,9 +1275,9 @@ Error MleRouter::HandleAdvertisement(RxInfo &aRxInfo, uint16_t aSourceAddress, c
ExitNow(error = kErrorDetached);
}
if ((mRouterSelectionJitterTimeout == 0) && (mRouterTable.GetActiveRouterCount() < mRouterUpgradeThreshold))
if (!mRouterRoleTransition.IsPending() && (mRouterTable.GetActiveRouterCount() < mRouterUpgradeThreshold))
{
mRouterSelectionJitterTimeout = 1 + Random::NonCrypto::GetUint8InRange(0, mRouterSelectionJitter);
mRouterRoleTransition.StartTimeout();
}
mRouterTable.UpdateRoutesOnFed(routeTlv, routerId);
@@ -1323,12 +1306,9 @@ Error MleRouter::HandleAdvertisement(RxInfo &aRxInfo, uint16_t aSourceAddress, c
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Update routers as a router or leader.
if (IsRouter())
if (IsRouter() && ShouldDowngrade(routerId, routeTlv))
{
if (ShouldDowngrade(routerId, routeTlv))
{
mRouterSelectionJitterTimeout = 1 + Random::NonCrypto::GetUint8InRange(0, mRouterSelectionJitter);
}
mRouterRoleTransition.StartTimeout();
}
router = mRouterTable.FindRouterById(routerId);
@@ -1514,7 +1494,7 @@ exit:
void MleRouter::HandleTimeTick(void)
{
bool routerStateUpdate = false;
bool roleTransitionTimeoutExpired = false;
VerifyOrExit(IsFullThreadDevice(), Get<TimeTicker>().UnregisterReceiver(TimeTicker::kMleRouter));
@@ -1528,15 +1508,7 @@ void MleRouter::HandleTimeTick(void)
mPreviousPartitionIdTimeout--;
}
if (mRouterSelectionJitterTimeout > 0)
{
mRouterSelectionJitterTimeout--;
if (mRouterSelectionJitterTimeout == 0)
{
routerStateUpdate = true;
}
}
roleTransitionTimeoutExpired = mRouterRoleTransition.HandleTimeTick();
switch (mRole)
{
@@ -1550,11 +1522,10 @@ void MleRouter::HandleTimeTick(void)
break;
case kRoleChild:
if (routerStateUpdate)
if (roleTransitionTimeoutExpired)
{
if (mRouterTable.GetActiveRouterCount() < mRouterUpgradeThreshold && HasNeighborWithGoodLinkQuality())
{
// upgrade to Router
IgnoreError(BecomeRouter(ThreadStatusTlv::kTooFewRouters));
}
else
@@ -1576,7 +1547,6 @@ void MleRouter::HandleTimeTick(void)
OT_FALL_THROUGH;
case kRoleRouter:
// verify path to leader
LogDebg("network id timeout = %lu", ToUlong(mRouterTable.GetLeaderAge()));
if ((mRouterTable.GetActiveRouterCount() > 0) && (mRouterTable.GetLeaderAge() >= mNetworkIdTimeout))
@@ -1585,7 +1555,7 @@ void MleRouter::HandleTimeTick(void)
Attach(kSamePartition);
}
if (routerStateUpdate && mRouterTable.GetActiveRouterCount() > mRouterDowngradeThreshold)
if (roleTransitionTimeoutExpired && mRouterTable.GetActiveRouterCount() > mRouterDowngradeThreshold)
{
LogNote("Downgrade to REED");
Attach(kDowngradeToReed);
@@ -1594,7 +1564,7 @@ void MleRouter::HandleTimeTick(void)
OT_FALL_THROUGH;
case kRoleLeader:
if (routerStateUpdate && !IsRouterEligible())
if (roleTransitionTimeoutExpired && !IsRouterEligible())
{
LogInfo("No longer router eligible");
IgnoreError(BecomeDetached());
@@ -3573,7 +3543,7 @@ bool MleRouter::IsExpectedToBecomeRouterSoon(void) const
static constexpr uint8_t kMaxDelay = 10;
return IsRouterEligible() && IsChild() && !mAddressSolicitRejected &&
((GetRouterSelectionJitterTimeout() != 0 && GetRouterSelectionJitterTimeout() <= kMaxDelay) ||
((mRouterRoleTransition.IsPending() && mRouterRoleTransition.GetTimeout() <= kMaxDelay) ||
mAddressSolicitPending);
}
@@ -3826,10 +3796,7 @@ bool MleRouter::ShouldDowngrade(uint8_t aNeighborId, const RouteTlv &aRouteTlv)
VerifyOrExit(IsRouter());
VerifyOrExit(mRouterTable.IsAllocated(aNeighborId));
// `mRouterSelectionJitterTimeout` is non-zero if we are already
// waiting to downgrade.
VerifyOrExit(mRouterSelectionJitterTimeout == 0);
VerifyOrExit(!mRouterRoleTransition.IsPending());
VerifyOrExit(activeRouterCount > mRouterDowngradeThreshold);
@@ -4037,6 +4004,32 @@ exit:
}
#endif // OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
//----------------------------------------------------------------------------------------------------------------------
// RouterRoleTransition
MleRouter::RouterRoleTransition::RouterRoleTransition(void)
: mTimeout(0)
, mJitter(kRouterSelectionJitter)
{
}
void MleRouter::RouterRoleTransition::StartTimeout(void)
{
mTimeout = 1 + Random::NonCrypto::GetUint8InRange(0, mJitter);
}
bool MleRouter::RouterRoleTransition::HandleTimeTick(void)
{
bool expired = false;
VerifyOrExit(mTimeout > 0);
mTimeout--;
expired = (mTimeout == 0);
exit:
return expired;
}
} // namespace Mle
} // namespace ot
+37 -9
View File
@@ -265,26 +265,36 @@ public:
/**
* Returns the ROUTER_SELECTION_JITTER value.
*
* @returns The ROUTER_SELECTION_JITTER value.
* @returns The ROUTER_SELECTION_JITTER value in seconds.
*
*/
uint8_t GetRouterSelectionJitter(void) const { return mRouterSelectionJitter; }
uint8_t GetRouterSelectionJitter(void) const { return mRouterRoleTransition.GetJitter(); }
/**
* Sets the ROUTER_SELECTION_JITTER value.
*
* @returns The ROUTER_SELECTION_JITTER value.
* @param[in] aRouterJitter The router selection jitter value (in seconds).
*
*/
Error SetRouterSelectionJitter(uint8_t aRouterJitter);
void SetRouterSelectionJitter(uint8_t aRouterJitter) { mRouterRoleTransition.SetJitter(aRouterJitter); }
/**
* Returns the current router selection jitter timeout value.
* Indicates whether or not router role transition (upgrade from REED or downgrade to REED) is pending.
*
* @returns The current router selection jitter timeout value.
* @retval TRUE Router role transition is pending.
* @retval FALSE Router role transition is not pending
*
*/
uint8_t GetRouterSelectionJitterTimeout(void) const { return mRouterSelectionJitterTimeout; }
bool IsRouterRoleTransitionPending(void) const { return mRouterRoleTransition.IsPending(); }
/**
* Returns the current timeout delay in seconds till router role transition (upgrade from REED or downgrade to
* REED).
*
* @returns The timeout in seconds till router role transition, or zero if not pending role transition.
*
*/
uint8_t GetRouterRoleTransitionTimeout(void) const { return mRouterRoleTransition.GetTimeout(); }
/**
* Returns the ROUTER_UPGRADE_THRESHOLD value.
@@ -616,6 +626,25 @@ private:
static constexpr int8_t kParentPriorityLow = -1;
static constexpr int8_t kParentPriorityUnspecified = -2;
class RouterRoleTransition
{
public:
RouterRoleTransition(void);
bool IsPending(void) const { return (mTimeout != 0); }
void StartTimeout(void);
void StopTimeout(void) { mTimeout = 0; }
void IncreaseTimeout(uint8_t aIncrement) { mTimeout += aIncrement; }
uint8_t GetTimeout(void) const { return mTimeout; }
bool HandleTimeTick(void);
uint8_t GetJitter(void) const { return mJitter; }
void SetJitter(uint8_t aJitter) { mJitter = aJitter; }
private:
uint8_t mTimeout;
uint8_t mJitter;
};
void HandleDetachStart(void);
void HandleChildStart(AttachMode aMode);
void HandleSecurityPolicyChanged(void);
@@ -727,8 +756,7 @@ private:
uint8_t mPreviousPartitionRouterIdSequence; ///< The router ID sequence when last attached
uint8_t mPreviousPartitionIdTimeout; ///< The partition ID timeout when last attached
uint8_t mRouterSelectionJitter; ///< The variable to save the assigned jitter value.
uint8_t mRouterSelectionJitterTimeout; ///< The Timeout prior to request/release Router ID.
RouterRoleTransition mRouterRoleTransition;
uint8_t mChildRouterLinks;
+1 -1
View File
@@ -108,7 +108,7 @@ exit:
break;
#if OPENTHREAD_FTD
case kErrorInvalidState:
mTimer.Start(Time::SecToMsec(Get<Mle::MleRouter>().GetRouterSelectionJitterTimeout() + 1));
mTimer.Start(Time::SecToMsec(Get<Mle::MleRouter>().GetRouterRoleTransitionTimeout() + 1));
break;
#endif
case kErrorNotFound: