mirror of
https://github.com/espressif/openthread.git
synced 2026-08-01 08:37:47 +00:00
[mle] consolidate role transition management in RoleTransitioner (#12983)
This commit introduces the `RoleTransitioner` class (renamed from `RouterRoleTransition`) to centralize the management of router role eligibility, thresholds, and transitions. The following state and logic are moved from the `Mle` class into the `RoleTransitioner`: - Router role eligibility and allowance state (`mRouterEligible`, `mRouterRoleAllowed`). - Upgrade and downgrade thresholds. - Downgrade blocking state (`mDowngradeBlocked`). - Transition decision logic (`DecideWhetherToUpgrade()`, `DecideWhetherToDowngrade()`). - The transition jitter timer and its management. By consolidating these responsibilities, the complexity of the main `Mle` class is reduced, and the role transition process is more explicitly managed within its own sub-component.
This commit is contained in:
+10
-16
@@ -80,18 +80,9 @@ Mle::Mle(Instance &aInstance)
|
||||
, mWedAttachTimer(aInstance)
|
||||
#endif
|
||||
#if OPENTHREAD_FTD
|
||||
, mRouterEligible(true)
|
||||
, mRouterRoleAllowed(true)
|
||||
, mBlockDowngrade(false)
|
||||
, mAddressSolicitPending(false)
|
||||
, mAddressSolicitRejected(false)
|
||||
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
|
||||
, mCcmEnabled(false)
|
||||
, mThreadVersionCheckEnabled(true)
|
||||
#endif
|
||||
, mNetworkIdTimeout(kNetworkIdTimeout)
|
||||
, mRouterUpgradeThreshold(kRouterUpgradeThreshold)
|
||||
, mRouterDowngradeThreshold(kRouterDowngradeThreshold)
|
||||
, mPreviousPartitionRouterIdSequence(0)
|
||||
, mPreviousPartitionIdTimeout(0)
|
||||
, mChildRouterLinks(kChildRouterLinks)
|
||||
@@ -108,6 +99,7 @@ Mle::Mle(Instance &aInstance)
|
||||
, mAdvertiseTrickleTimer(aInstance, Mle::HandleAdvertiseTrickleTimer)
|
||||
, mChildTable(aInstance)
|
||||
, mRouterTable(aInstance)
|
||||
, mRoleTransitioner(aInstance)
|
||||
#endif // OPENTHREAD_FTD
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
, mP2p(aInstance)
|
||||
@@ -455,7 +447,7 @@ void Mle::Restore(void)
|
||||
mHasRestored = true;
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
UpdateRouterRoleAllowed(kReasonMleInit);
|
||||
mRoleTransitioner.UpdateRouterRoleAllowed(RoleTransitioner::kReasonMleInit);
|
||||
#endif
|
||||
|
||||
exit:
|
||||
@@ -606,7 +598,7 @@ void Mle::SetStateDetached(void)
|
||||
Get<MeshForwarder>().SetRxOnWhenIdle(true);
|
||||
Get<Mac::Mac>().SetBeaconEnabled(false);
|
||||
#if OPENTHREAD_FTD
|
||||
mBlockDowngrade = false;
|
||||
mRoleTransitioner.SetDowngradeBlocked(false);
|
||||
ClearAlternateRloc16();
|
||||
HandleDetachStart();
|
||||
#endif
|
||||
@@ -727,7 +719,7 @@ Error Mle::SetDeviceMode(DeviceMode aDeviceMode)
|
||||
ClearAlternateRloc16();
|
||||
}
|
||||
|
||||
UpdateRouterRoleAllowed(kReasonDeviceModeChanged);
|
||||
mRoleTransitioner.UpdateRouterRoleAllowed(RoleTransitioner::kReasonDeviceModeChanged);
|
||||
#endif
|
||||
|
||||
if (IsAttached())
|
||||
@@ -1052,21 +1044,23 @@ void Mle::HandleNotifierEvents(Events aEvents)
|
||||
#if OPENTHREAD_FTD
|
||||
if (aEvents.Contains(kEventSecurityPolicyChanged))
|
||||
{
|
||||
UpdateRouterRoleAllowed(kReasonSecurityPolicyChanged);
|
||||
mRoleTransitioner.UpdateRouterRoleAllowed(RoleTransitioner::kReasonSecurityPolicyChanged);
|
||||
}
|
||||
|
||||
if (mBlockDowngrade && aEvents.Contains(kEventThreadChildRemoved))
|
||||
if (mRoleTransitioner.IsDowngradeBlocked() && aEvents.Contains(kEventThreadChildRemoved))
|
||||
{
|
||||
mBlockDowngrade = false;
|
||||
bool shouldBlock = false;
|
||||
|
||||
for (const Child &child : Get<ChildTable>().Iterate(Child::kInStateValid))
|
||||
{
|
||||
if (child.IsBlockingParentDowngrade())
|
||||
{
|
||||
mBlockDowngrade = true;
|
||||
shouldBlock = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mRoleTransitioner.SetDowngradeBlocked(shouldBlock);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+64
-46
@@ -771,7 +771,7 @@ public:
|
||||
* @retval kErrorNone Successfully set the router-eligible configuration.
|
||||
* @retval kErrorNotCapable The device is not capable of becoming a router.
|
||||
*/
|
||||
Error SetRouterEligible(bool aEligible);
|
||||
Error SetRouterEligible(bool aEligible) { return mRoleTransitioner.SetRouterEligible(aEligible); }
|
||||
|
||||
/**
|
||||
* Indicates whether the router role is currently allowed.
|
||||
@@ -782,7 +782,7 @@ public:
|
||||
* @retval TRUE If the router role is allowed.
|
||||
* @retval FALSE If the router role is not allowed.
|
||||
*/
|
||||
bool IsRouterRoleAllowed(void) const { return mRouterRoleAllowed; }
|
||||
bool IsRouterRoleAllowed(void) const { return mRoleTransitioner.IsRouterRoleAllowed(); }
|
||||
|
||||
/**
|
||||
* Indicates whether a node is the only router on the network.
|
||||
@@ -928,14 +928,14 @@ public:
|
||||
*
|
||||
* @returns The ROUTER_SELECTION_JITTER value in seconds.
|
||||
*/
|
||||
uint8_t GetRouterSelectionJitter(void) const { return mRouterRoleTransition.GetJitter(); }
|
||||
uint8_t GetRouterSelectionJitter(void) const { return mRoleTransitioner.GetJitter(); }
|
||||
|
||||
/**
|
||||
* Sets the ROUTER_SELECTION_JITTER value.
|
||||
*
|
||||
* @param[in] aRouterJitter The router selection jitter value (in seconds).
|
||||
*/
|
||||
void SetRouterSelectionJitter(uint8_t aRouterJitter) { mRouterRoleTransition.SetJitter(aRouterJitter); }
|
||||
void SetRouterSelectionJitter(uint8_t aRouterJitter) { mRoleTransitioner.SetJitter(aRouterJitter); }
|
||||
|
||||
/**
|
||||
* Indicates whether or not router role transition (upgrade from REED or downgrade to REED) is pending.
|
||||
@@ -943,7 +943,7 @@ public:
|
||||
* @retval TRUE Router role transition is pending.
|
||||
* @retval FALSE Router role transition is not pending
|
||||
*/
|
||||
bool IsRouterRoleTransitionPending(void) const { return mRouterRoleTransition.IsPending(); }
|
||||
bool IsRouterRoleTransitionPending(void) const { return mRoleTransitioner.IsTransitionPending(); }
|
||||
|
||||
/**
|
||||
* Returns the current timeout delay in seconds till router role transition (upgrade from REED or downgrade to
|
||||
@@ -951,35 +951,35 @@ public:
|
||||
*
|
||||
* @returns The timeout in seconds till router role transition, or zero if not pending role transition.
|
||||
*/
|
||||
uint8_t GetRouterRoleTransitionTimeout(void) const { return mRouterRoleTransition.GetTimeout(); }
|
||||
uint8_t GetRouterRoleTransitionTimeout(void) const { return mRoleTransitioner.GetTimeout(); }
|
||||
|
||||
/**
|
||||
* Returns the ROUTER_UPGRADE_THRESHOLD value.
|
||||
*
|
||||
* @returns The ROUTER_UPGRADE_THRESHOLD value.
|
||||
*/
|
||||
uint8_t GetRouterUpgradeThreshold(void) const { return mRouterUpgradeThreshold; }
|
||||
uint8_t GetRouterUpgradeThreshold(void) const { return mRoleTransitioner.GetUpgradeThreshold(); }
|
||||
|
||||
/**
|
||||
* Sets the ROUTER_UPGRADE_THRESHOLD value.
|
||||
*
|
||||
* @param[in] aThreshold The ROUTER_UPGRADE_THRESHOLD value.
|
||||
*/
|
||||
void SetRouterUpgradeThreshold(uint8_t aThreshold) { mRouterUpgradeThreshold = aThreshold; }
|
||||
void SetRouterUpgradeThreshold(uint8_t aThreshold) { mRoleTransitioner.SetUpgradeThreshold(aThreshold); }
|
||||
|
||||
/**
|
||||
* Returns the ROUTER_DOWNGRADE_THRESHOLD value.
|
||||
*
|
||||
* @returns The ROUTER_DOWNGRADE_THRESHOLD value.
|
||||
*/
|
||||
uint8_t GetRouterDowngradeThreshold(void) const { return mRouterDowngradeThreshold; }
|
||||
uint8_t GetRouterDowngradeThreshold(void) const { return mRoleTransitioner.GetDowngradeThreshold(); }
|
||||
|
||||
/**
|
||||
* Sets the ROUTER_DOWNGRADE_THRESHOLD value.
|
||||
*
|
||||
* @param[in] aThreshold The ROUTER_DOWNGRADE_THRESHOLD value.
|
||||
*/
|
||||
void SetRouterDowngradeThreshold(uint8_t aThreshold) { mRouterDowngradeThreshold = aThreshold; }
|
||||
void SetRouterDowngradeThreshold(uint8_t aThreshold) { mRoleTransitioner.SetDowngradeThreshold(aThreshold); }
|
||||
|
||||
/**
|
||||
* Indicates whether or not downgrading from router role to REED is blocked.
|
||||
@@ -997,7 +997,7 @@ public:
|
||||
* @retval TRUE The device is blocked from downgrading.
|
||||
* @retval FALSE The device is not blocked from downgrading.
|
||||
*/
|
||||
bool IsDowngradeBlocked(void) const { return mBlockDowngrade; }
|
||||
bool IsDowngradeBlocked(void) const { return mRoleTransitioner.IsDowngradeBlocked(); }
|
||||
|
||||
/**
|
||||
* Returns the MLE_CHILD_ROUTER_LINKS value.
|
||||
@@ -1022,7 +1022,7 @@ public:
|
||||
* @retval TRUE If the REED is going to become a Router soon.
|
||||
* @retval FALSE If the REED is not going to become a Router soon.
|
||||
*/
|
||||
bool WillBecomeRouterSoon(void) const;
|
||||
bool WillBecomeRouterSoon(void) const { return mRoleTransitioner.WillBecomeRouterSoon(); }
|
||||
|
||||
/**
|
||||
* Removes a link to a neighbor.
|
||||
@@ -1179,14 +1179,14 @@ public:
|
||||
*
|
||||
* @param[in] aEnabled TRUE if the device was commissioned using CCM, FALSE otherwise.
|
||||
*/
|
||||
void SetCcmEnabled(bool aEnabled);
|
||||
void SetCcmEnabled(bool aEnabled) { mRoleTransitioner.SetCcmEnabled(aEnabled); }
|
||||
|
||||
/**
|
||||
* Sets whether the Security Policy TLV version-threshold for routing (VR field) is enabled.
|
||||
*
|
||||
* @param[in] aEnabled TRUE to enable Security Policy TLV version-threshold for routing, FALSE otherwise.
|
||||
*/
|
||||
void SetThreadVersionCheckEnabled(bool aEnabled);
|
||||
void SetThreadVersionCheckEnabled(bool aEnabled) { mRoleTransitioner.SetThreadVersionCheckEnabled(aEnabled); }
|
||||
|
||||
/**
|
||||
* Gets the current Interval Max value used by Advertisement trickle timer.
|
||||
@@ -1473,16 +1473,6 @@ private:
|
||||
kAddrSolicitUnrecognizedReason = 6,
|
||||
};
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
enum UpdateRouterRoleAllowedReason : uint8_t // Used in `UpdateRouterRoleAllowed()`
|
||||
{
|
||||
kReasonMleInit,
|
||||
kReasonDeviceModeChanged,
|
||||
kReasonConfigParameterChanged,
|
||||
kReasonSecurityPolicyChanged,
|
||||
};
|
||||
#endif
|
||||
|
||||
enum MessageAction : uint8_t
|
||||
{
|
||||
kMessageSend,
|
||||
@@ -2216,26 +2206,65 @@ private:
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
|
||||
class RouterRoleTransition
|
||||
class RoleTransitioner : public InstanceLocator
|
||||
{
|
||||
public:
|
||||
RouterRoleTransition(void);
|
||||
// Manages the router role upgrade/downgrade transitions
|
||||
|
||||
bool IsPending(void) const { return (mTimeout != 0); }
|
||||
public:
|
||||
enum UpdateRouterRoleAllowedReason : uint8_t // Used in `UpdateRouterRoleAllowed()`
|
||||
{
|
||||
kReasonMleInit,
|
||||
kReasonDeviceModeChanged,
|
||||
kReasonConfigParameterChanged,
|
||||
kReasonSecurityPolicyChanged,
|
||||
};
|
||||
|
||||
explicit RoleTransitioner(Instance &aInstance);
|
||||
|
||||
bool IsRouterRoleAllowed(void) const { return mRouterRoleAllowed; }
|
||||
void UpdateRouterRoleAllowed(UpdateRouterRoleAllowedReason aReason);
|
||||
Error SetRouterEligible(bool aEligible);
|
||||
uint8_t GetJitter(void) const { return mJitter; }
|
||||
void SetJitter(uint8_t aJitter) { mJitter = aJitter; }
|
||||
uint8_t GetUpgradeThreshold(void) const { return mUpgradeThreshold; }
|
||||
void SetUpgradeThreshold(uint8_t aThreshold) { mUpgradeThreshold = aThreshold; }
|
||||
uint8_t GetDowngradeThreshold(void) const { return mDowngradeThreshold; }
|
||||
void SetDowngradeThreshold(uint8_t aThreshold) { mDowngradeThreshold = aThreshold; }
|
||||
bool IsDowngradeBlocked(void) const { return mDowngradeBlocked; }
|
||||
void SetDowngradeBlocked(bool aBlocked) { mDowngradeBlocked = aBlocked; }
|
||||
bool IsTransitionPending(void) const { return (mTimeout != 0); }
|
||||
bool WillBecomeRouterSoon(void) const;
|
||||
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; }
|
||||
bool IsRouterCountBelowUpgradeThreshold(void) const;
|
||||
void HandleTimeTick(void);
|
||||
void DecideWhetherToUpgrade(void);
|
||||
void DecideWhetherToDowngrade(uint8_t aNeighborId, const RouteTlv &aRouteTlv);
|
||||
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
|
||||
void SetCcmEnabled(bool aEnabled);
|
||||
void SetThreadVersionCheckEnabled(bool aEnabled);
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool DetermineIfRouterRoleAllowed(void) const;
|
||||
bool NeighborHasComparableConnectivity(uint8_t aNeighborId, const RouteTlv &aRouteTlv) const;
|
||||
|
||||
bool mRouterEligible : 1;
|
||||
bool mRouterRoleAllowed : 1;
|
||||
bool mDowngradeBlocked : 1;
|
||||
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
|
||||
bool mCcmEnabled : 1;
|
||||
bool mThreadVersionCheckEnabled : 1;
|
||||
#endif
|
||||
uint8_t mTimeout;
|
||||
uint8_t mJitter;
|
||||
uint8_t mUpgradeThreshold;
|
||||
uint8_t mDowngradeThreshold;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // OPENTHREAD_FTD
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
#if OPENTHREAD_CONFIG_P2P_ENABLE
|
||||
@@ -2419,8 +2448,6 @@ private:
|
||||
void ClearAlternateRloc16(void);
|
||||
uint8_t SelectLeaderId(void) const;
|
||||
uint32_t SelectPartitionId(void) const;
|
||||
bool DetermineIfRouterRoleAllowed(void) const;
|
||||
void UpdateRouterRoleAllowed(UpdateRouterRoleAllowedReason aReason);
|
||||
void DetermineConnectivity(Connectivity &aConnectivity) const;
|
||||
void HandleDetachStart(void);
|
||||
void HandleChildStart(void);
|
||||
@@ -2468,8 +2495,6 @@ private:
|
||||
void SetChildStateToValid(Child &aChild);
|
||||
bool HasChildren(void);
|
||||
void RemoveChildren(void);
|
||||
bool ShouldDowngrade(uint8_t aNeighborId, const RouteTlv &aRouteTlv) const;
|
||||
bool NeighborHasComparableConnectivity(const RouteTlv &aRouteTlv, uint8_t aNeighborId) const;
|
||||
void HandleAdvertiseTrickleTimer(void);
|
||||
void HandleTimeTick(void);
|
||||
void HandleRouterTableEvent(RouterTable::Events aEvents);
|
||||
@@ -2548,15 +2573,8 @@ private:
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
|
||||
bool mRouterEligible : 1;
|
||||
bool mRouterRoleAllowed : 1;
|
||||
bool mBlockDowngrade : 1;
|
||||
bool mAddressSolicitPending : 1;
|
||||
bool mAddressSolicitRejected : 1;
|
||||
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
|
||||
bool mCcmEnabled : 1;
|
||||
bool mThreadVersionCheckEnabled : 1;
|
||||
#endif
|
||||
bool mAddressSolicitPending : 1;
|
||||
bool mAddressSolicitRejected : 1;
|
||||
uint8_t mRouterId;
|
||||
uint8_t mPreviousRouterId;
|
||||
uint8_t mNetworkIdTimeout;
|
||||
@@ -2579,7 +2597,7 @@ private:
|
||||
TrickleTimer mAdvertiseTrickleTimer;
|
||||
ChildTable mChildTable;
|
||||
RouterTable mRouterTable;
|
||||
RouterRoleTransition mRouterRoleTransition;
|
||||
RoleTransitioner mRoleTransitioner;
|
||||
Ip6::Netif::UnicastAddress mLeaderAloc;
|
||||
#if OPENTHREAD_CONFIG_MLE_DEVICE_PROPERTY_LEADER_WEIGHT_ENABLE
|
||||
DeviceProperties mDeviceProperties;
|
||||
|
||||
+141
-116
@@ -76,12 +76,12 @@ void Mle::HandlePartitionChange(void)
|
||||
mRouterTable.Clear();
|
||||
}
|
||||
|
||||
bool Mle::DetermineIfRouterRoleAllowed(void) const
|
||||
bool Mle::RoleTransitioner::DetermineIfRouterRoleAllowed(void) const
|
||||
{
|
||||
bool allowed = false;
|
||||
const SecurityPolicy &secPolicy = Get<KeyManager>().GetSecurityPolicy();
|
||||
|
||||
VerifyOrExit(mRouterEligible && IsFullThreadDevice());
|
||||
VerifyOrExit(mRouterEligible && Get<Mle>().IsFullThreadDevice());
|
||||
|
||||
#if OPENTHREAD_CONFIG_THREAD_VERSION == OT_THREAD_VERSION_1_1
|
||||
VerifyOrExit(secPolicy.mRoutersEnabled);
|
||||
@@ -116,14 +116,14 @@ exit:
|
||||
return allowed;
|
||||
}
|
||||
|
||||
void Mle::UpdateRouterRoleAllowed(UpdateRouterRoleAllowedReason aReason)
|
||||
void Mle::RoleTransitioner::UpdateRouterRoleAllowed(UpdateRouterRoleAllowedReason aReason)
|
||||
{
|
||||
bool allowed = DetermineIfRouterRoleAllowed();
|
||||
|
||||
VerifyOrExit(allowed != mRouterRoleAllowed);
|
||||
mRouterRoleAllowed = allowed;
|
||||
|
||||
if (IsAttached())
|
||||
if (Get<Mle>().IsAttached())
|
||||
{
|
||||
Get<Mac::Mac>().SetBeaconEnabled(mRouterRoleAllowed);
|
||||
}
|
||||
@@ -131,12 +131,12 @@ void Mle::UpdateRouterRoleAllowed(UpdateRouterRoleAllowedReason aReason)
|
||||
// Take action based on the current role, the new `mRouterRoleAllowed`,
|
||||
// and the reason for the change.
|
||||
|
||||
if (IsChild() && mRouterRoleAllowed && (aReason == kReasonConfigParameterChanged))
|
||||
if (Get<Mle>().IsChild() && mRouterRoleAllowed && (aReason == kReasonConfigParameterChanged))
|
||||
{
|
||||
mRouterRoleTransition.StartTimeout();
|
||||
StartTimeout();
|
||||
}
|
||||
|
||||
if (IsRouterOrLeader())
|
||||
if (Get<Mle>().IsRouterOrLeader())
|
||||
{
|
||||
// If currently acting as router or leader, but the config or
|
||||
// security policy changes such that the router role is no
|
||||
@@ -157,16 +157,16 @@ void Mle::UpdateRouterRoleAllowed(UpdateRouterRoleAllowedReason aReason)
|
||||
break;
|
||||
|
||||
case kReasonConfigParameterChanged:
|
||||
IgnoreError(BecomeDetached());
|
||||
IgnoreError(Get<Mle>().BecomeDetached());
|
||||
break;
|
||||
|
||||
case kReasonSecurityPolicyChanged:
|
||||
VerifyOrExit(!mRouterRoleTransition.IsPending());
|
||||
mRouterRoleTransition.StartTimeout();
|
||||
VerifyOrExit(!IsTransitionPending());
|
||||
StartTimeout();
|
||||
|
||||
if (IsLeader())
|
||||
if (Get<Mle>().IsLeader())
|
||||
{
|
||||
mRouterRoleTransition.IncreaseTimeout(kLeaderDowngradeExtraDelay);
|
||||
IncreaseTimeout(kLeaderDowngradeExtraDelay);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -176,11 +176,11 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
Error Mle::SetRouterEligible(bool aEligible)
|
||||
Error Mle::RoleTransitioner::SetRouterEligible(bool aEligible)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
if (!IsFullThreadDevice())
|
||||
if (!Get<Mle>().IsFullThreadDevice())
|
||||
{
|
||||
VerifyOrExit(!aEligible, error = kErrorNotCapable);
|
||||
}
|
||||
@@ -195,13 +195,13 @@ exit:
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
|
||||
void Mle::SetCcmEnabled(bool aEnabled)
|
||||
void Mle::RoleTransitioner::SetCcmEnabled(bool aEnabled)
|
||||
{
|
||||
mCcmEnabled = aEnabled;
|
||||
UpdateRouterRoleAllowed(kReasonConfigParameterChanged);
|
||||
}
|
||||
|
||||
void Mle::SetThreadVersionCheckEnabled(bool aEnabled)
|
||||
void Mle::RoleTransitioner::SetThreadVersionCheckEnabled(bool aEnabled)
|
||||
{
|
||||
mThreadVersionCheckEnabled = aEnabled;
|
||||
UpdateRouterRoleAllowed(kReasonConfigParameterChanged);
|
||||
@@ -241,7 +241,7 @@ Error Mle::BecomeRouter(RouterUpgradeReason aReason)
|
||||
LogInfo("Attempt to become router, reason:%s", RouterUpgradeReasonToString(aReason));
|
||||
|
||||
Get<MeshForwarder>().SetRxOnWhenIdle(true);
|
||||
mRouterRoleTransition.StopTimeout();
|
||||
mRoleTransitioner.StopTimeout();
|
||||
|
||||
error = SendAddressSolicit(aReason);
|
||||
|
||||
@@ -341,7 +341,7 @@ void Mle::HandleChildStart(void)
|
||||
{
|
||||
mAddressSolicitRejected = false;
|
||||
|
||||
mRouterRoleTransition.StartTimeout();
|
||||
mRoleTransitioner.StartTimeout();
|
||||
|
||||
StopLeader();
|
||||
Get<TimeTicker>().RegisterReceiver(TimeTicker::kMle);
|
||||
@@ -409,7 +409,7 @@ void Mle::HandleChildStart(void)
|
||||
|
||||
exit:
|
||||
|
||||
if (mRouterTable.GetActiveRouterCount() >= mRouterUpgradeThreshold &&
|
||||
if (!mRoleTransitioner.IsRouterCountBelowUpgradeThreshold() &&
|
||||
(!IsRouterIdValid(mPreviousRouterId) || !HasChildren()))
|
||||
{
|
||||
SetRouterId(kInvalidRouterId);
|
||||
@@ -515,7 +515,7 @@ void Mle::HandleRouterTableEvent(RouterTable::Events aEvents)
|
||||
|
||||
if (aEvents & RouterTable::kEventRouterAdded)
|
||||
{
|
||||
mBlockDowngrade = false;
|
||||
mRoleTransitioner.SetDowngradeBlocked(false);
|
||||
}
|
||||
|
||||
if (IsRouterOrLeader() && mAdvertiseTrickleTimer.IsRunning())
|
||||
@@ -1305,12 +1305,9 @@ Error Mle::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddress, co
|
||||
ExitNow(error = kErrorDetached);
|
||||
}
|
||||
|
||||
if (!mRouterRoleTransition.IsPending() && (mRouterTable.GetActiveRouterCount() < mRouterUpgradeThreshold))
|
||||
{
|
||||
mRouterRoleTransition.StartTimeout();
|
||||
}
|
||||
|
||||
mRouterTable.UpdateRouterOnFtdChild(routeTlv, routerId);
|
||||
|
||||
mRoleTransitioner.DecideWhetherToUpgrade();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1331,12 +1328,12 @@ Error Mle::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddress, co
|
||||
}
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Update routers as a router or leader.
|
||||
// Inform `RoleTransitioner` to decide whether we need to downgrade
|
||||
|
||||
if (IsRouter() && ShouldDowngrade(routerId, routeTlv))
|
||||
{
|
||||
mRouterRoleTransition.StartTimeout();
|
||||
}
|
||||
mRoleTransitioner.DecideWhetherToDowngrade(routerId, routeTlv);
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Update routers as a router or leader.
|
||||
|
||||
router = mRouterTable.FindRouterById(routerId);
|
||||
VerifyOrExit(router != nullptr);
|
||||
@@ -1589,55 +1586,7 @@ void Mle::HandleTimeTick(void)
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Role transitions
|
||||
|
||||
if (mRouterRoleTransition.HandleTimeTick())
|
||||
{
|
||||
// `mRouterRoleTransition.HandleTimeTick()` returns `true`
|
||||
// if role transition timeout expires.
|
||||
|
||||
switch (mRole)
|
||||
{
|
||||
case kRoleDisabled:
|
||||
case kRoleDetached:
|
||||
break;
|
||||
|
||||
case kRoleChild:
|
||||
if (mRouterTable.GetActiveRouterCount() < mRouterUpgradeThreshold && HasNeighborWithGoodLinkQuality())
|
||||
{
|
||||
IgnoreError(BecomeRouter(kReasonTooFewRouters));
|
||||
}
|
||||
else
|
||||
{
|
||||
mAnnounceHandler.HandleRouterRoleTransitionAttemptDone();
|
||||
}
|
||||
|
||||
if (!mAdvertiseTrickleTimer.IsRunning())
|
||||
{
|
||||
SendMulticastAdvertisement();
|
||||
|
||||
mAdvertiseTrickleTimer.Start(TrickleTimer::kModePlainTimer, kReedAdvIntervalMin, kReedAdvIntervalMax);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case kRoleRouter:
|
||||
if (mRouterTable.GetActiveRouterCount() > mRouterDowngradeThreshold)
|
||||
{
|
||||
LogNote("Downgrade to REED");
|
||||
mAttacher.Attach(kDowngradeToReed);
|
||||
}
|
||||
|
||||
OT_FALL_THROUGH;
|
||||
|
||||
case kRoleLeader:
|
||||
if (!IsRouterRoleAllowed())
|
||||
{
|
||||
LogInfo("Router role no longer allowed");
|
||||
IgnoreError(BecomeDetached());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
mRoleTransitioner.HandleTimeTick();
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Check Leader's age
|
||||
@@ -3485,13 +3434,13 @@ void Mle::HandleAddressSolicitResponse(Coap::Msg *aMsg, Error aResult)
|
||||
// router from downgrading back to a REED to ensure this
|
||||
// child remains connected.
|
||||
//
|
||||
// The `mBlockDowngrade` is cleared in various situations:
|
||||
// The `DowngradeBlocked` is cleared in various situations:
|
||||
// - From `SetStateDetached()` (e.g. partition change).
|
||||
// - If a new router is added (new possible parent).
|
||||
// - If all children blocking downgrade are disconnected.
|
||||
|
||||
child.SetBlockParentDowngrade(true);
|
||||
mBlockDowngrade = true;
|
||||
mRoleTransitioner.SetDowngradeBlocked(true);
|
||||
}
|
||||
|
||||
exit:
|
||||
@@ -3508,18 +3457,18 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
bool Mle::WillBecomeRouterSoon(void) const
|
||||
bool Mle::RoleTransitioner::WillBecomeRouterSoon(void) const
|
||||
{
|
||||
static constexpr uint8_t kMaxDelay = 10;
|
||||
|
||||
bool willBecomeRouter = false;
|
||||
|
||||
VerifyOrExit(IsRouterRoleAllowed() && IsChild());
|
||||
VerifyOrExit(!mAddressSolicitRejected);
|
||||
VerifyOrExit(IsRouterRoleAllowed() && Get<Mle>().IsChild());
|
||||
VerifyOrExit(!Get<Mle>().mAddressSolicitRejected);
|
||||
|
||||
if (!mAddressSolicitPending)
|
||||
if (!Get<Mle>().mAddressSolicitPending)
|
||||
{
|
||||
VerifyOrExit(mRouterRoleTransition.IsPending() && mRouterRoleTransition.GetTimeout() <= kMaxDelay);
|
||||
VerifyOrExit(IsTransitionPending() && GetTimeout() <= kMaxDelay);
|
||||
}
|
||||
|
||||
willBecomeRouter = true;
|
||||
@@ -3597,7 +3546,7 @@ void Mle::ProcessAddressSolicit(AddrSolicitInfo &aInfo)
|
||||
switch (aInfo.mReason)
|
||||
{
|
||||
case kReasonTooFewRouters:
|
||||
VerifyOrExit(mRouterTable.GetActiveRouterCount() < mRouterUpgradeThreshold);
|
||||
VerifyOrExit(mRoleTransitioner.IsRouterCountBelowUpgradeThreshold());
|
||||
break;
|
||||
|
||||
case kReasonHaveChildIdRequest:
|
||||
@@ -3605,7 +3554,7 @@ void Mle::ProcessAddressSolicit(AddrSolicitInfo &aInfo)
|
||||
break;
|
||||
|
||||
case kReasonBorderRouterRequest:
|
||||
if ((mRouterTable.GetActiveRouterCount() >= mRouterUpgradeThreshold) &&
|
||||
if (!mRoleTransitioner.IsRouterCountBelowUpgradeThreshold() &&
|
||||
(Get<NetworkData::Leader>().CountBorderRouters(NetworkData::kRouterRoleOnly) >=
|
||||
kRouterUpgradeBorderRouterRequestThreshold))
|
||||
{
|
||||
@@ -3781,30 +3730,29 @@ void Mle::FillConnectivityTlvValue(ConnectivityTlvValue &aTlvValue) const
|
||||
aTlvValue.InitFrom(connectivity);
|
||||
}
|
||||
|
||||
bool Mle::ShouldDowngrade(uint8_t aNeighborId, const RouteTlv &aRouteTlv) const
|
||||
void Mle::RoleTransitioner::DecideWhetherToDowngrade(uint8_t aNeighborId, const RouteTlv &aRouteTlv)
|
||||
{
|
||||
// Determine whether all conditions are satisfied for the router
|
||||
// to downgrade after receiving info for a neighboring router
|
||||
// with Router ID `aNeighborId` along with its `aRouteTlv`.
|
||||
|
||||
bool shouldDowngrade = false;
|
||||
uint8_t activeRouterCount = mRouterTable.GetActiveRouterCount();
|
||||
uint8_t activeRouterCount = Get<RouterTable>().GetActiveRouterCount();
|
||||
uint8_t count;
|
||||
|
||||
VerifyOrExit(IsRouter());
|
||||
VerifyOrExit(mRouterTable.IsAllocated(aNeighborId));
|
||||
VerifyOrExit(!mBlockDowngrade);
|
||||
VerifyOrExit(Get<Mle>().IsRouter());
|
||||
VerifyOrExit(Get<RouterTable>().IsAllocated(aNeighborId));
|
||||
VerifyOrExit(!mDowngradeBlocked);
|
||||
|
||||
VerifyOrExit(!mRouterRoleTransition.IsPending());
|
||||
VerifyOrExit(!IsTransitionPending());
|
||||
|
||||
VerifyOrExit(activeRouterCount > mRouterDowngradeThreshold);
|
||||
VerifyOrExit(activeRouterCount > mDowngradeThreshold);
|
||||
|
||||
// Check that we have at least `kMinDowngradeNeighbors`
|
||||
// neighboring routers with two-way link quality of 2 or better.
|
||||
|
||||
count = 0;
|
||||
|
||||
for (const Router &router : mRouterTable)
|
||||
for (const Router &router : Get<RouterTable>())
|
||||
{
|
||||
if (!router.IsStateValid() || (router.GetTwoWayLinkQuality() < kLinkQuality2))
|
||||
{
|
||||
@@ -3823,28 +3771,29 @@ bool Mle::ShouldDowngrade(uint8_t aNeighborId, const RouteTlv &aRouteTlv) const
|
||||
|
||||
// Check that we have fewer children than three times the number
|
||||
// of excess routers (defined as the difference between number of
|
||||
// active routers and `mRouterDowngradeThreshold`).
|
||||
// active routers and `mDowngradeThreshold`).
|
||||
|
||||
count = activeRouterCount - mRouterDowngradeThreshold;
|
||||
VerifyOrExit(mChildTable.GetNumChildren(Child::kInStateValid) < count * 3);
|
||||
count = activeRouterCount - mDowngradeThreshold;
|
||||
VerifyOrExit(Get<ChildTable>().GetNumChildren(Child::kInStateValid) < count * 3);
|
||||
|
||||
// Check that the neighbor has as good or better-quality links to
|
||||
// same routers.
|
||||
|
||||
VerifyOrExit(NeighborHasComparableConnectivity(aRouteTlv, aNeighborId));
|
||||
VerifyOrExit(NeighborHasComparableConnectivity(aNeighborId, aRouteTlv));
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
|
||||
// Check if we are eligible to be router due to being a BR.
|
||||
VerifyOrExit(!Get<NetworkData::Notifier>().IsEligibleForRouterRoleUpgradeAsBorderRouter());
|
||||
#endif
|
||||
|
||||
shouldDowngrade = true;
|
||||
// All conditions are satisfied to start downgrade.
|
||||
StartTimeout();
|
||||
|
||||
exit:
|
||||
return shouldDowngrade;
|
||||
return;
|
||||
}
|
||||
|
||||
bool Mle::NeighborHasComparableConnectivity(const RouteTlv &aRouteTlv, uint8_t aNeighborId) const
|
||||
bool Mle::RoleTransitioner::NeighborHasComparableConnectivity(uint8_t aNeighborId, const RouteTlv &aRouteTlv) const
|
||||
{
|
||||
// Check whether the neighboring router with Router ID `aNeighborId`
|
||||
// (along with its `aRouteTlv`) has as good or better-quality links
|
||||
@@ -3860,12 +3809,12 @@ bool Mle::NeighborHasComparableConnectivity(const RouteTlv &aRouteTlv, uint8_t a
|
||||
LinkQuality localLinkQuality;
|
||||
LinkQuality peerLinkQuality;
|
||||
|
||||
if ((routerId == mRouterId) || (routerId == aNeighborId))
|
||||
if ((routerId == Get<Mle>().mRouterId) || (routerId == aNeighborId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
router = mRouterTable.FindRouterById(routerId);
|
||||
router = Get<RouterTable>().FindRouterById(routerId);
|
||||
|
||||
if ((router == nullptr) || !router->IsStateValid())
|
||||
{
|
||||
@@ -4017,26 +3966,102 @@ const char *Mle::RouterUpgradeReasonToString(uint8_t aReason)
|
||||
#endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// RouterRoleTransition
|
||||
// RoleTransitioner
|
||||
|
||||
Mle::RouterRoleTransition::RouterRoleTransition(void)
|
||||
: mTimeout(0)
|
||||
Mle::RoleTransitioner::RoleTransitioner(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mRouterEligible(true)
|
||||
, mRouterRoleAllowed(true)
|
||||
, mDowngradeBlocked(false)
|
||||
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
|
||||
, mCcmEnabled(false)
|
||||
, mThreadVersionCheckEnabled(true)
|
||||
#endif
|
||||
, mTimeout(0)
|
||||
, mJitter(kRouterSelectionJitter)
|
||||
, mUpgradeThreshold(kRouterUpgradeThreshold)
|
||||
, mDowngradeThreshold(kRouterDowngradeThreshold)
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
void Mle::RouterRoleTransition::StartTimeout(void) { mTimeout = 1 + Random::NonCrypto::GetUint8InRange(0, mJitter); }
|
||||
void Mle::RoleTransitioner::StartTimeout(void) { mTimeout = 1 + Random::NonCrypto::GetUint8InRange(0, mJitter); }
|
||||
|
||||
bool Mle::RouterRoleTransition::HandleTimeTick(void)
|
||||
bool Mle::RoleTransitioner::IsRouterCountBelowUpgradeThreshold(void) const
|
||||
{
|
||||
bool expired = false;
|
||||
return Get<RouterTable>().GetActiveRouterCount() < mUpgradeThreshold;
|
||||
}
|
||||
|
||||
VerifyOrExit(mTimeout > 0);
|
||||
mTimeout--;
|
||||
expired = (mTimeout == 0);
|
||||
void Mle::RoleTransitioner::DecideWhetherToUpgrade(void)
|
||||
{
|
||||
VerifyOrExit(Get<Mle>().IsChild());
|
||||
|
||||
VerifyOrExit(IsRouterRoleAllowed());
|
||||
|
||||
VerifyOrExit(!IsTransitionPending());
|
||||
VerifyOrExit(IsRouterCountBelowUpgradeThreshold());
|
||||
|
||||
StartTimeout();
|
||||
|
||||
exit:
|
||||
return expired;
|
||||
return;
|
||||
}
|
||||
|
||||
void Mle::RoleTransitioner::HandleTimeTick(void)
|
||||
{
|
||||
VerifyOrExit(mTimeout > 0);
|
||||
mTimeout--;
|
||||
|
||||
VerifyOrExit(mTimeout == 0);
|
||||
|
||||
// Timeout expired
|
||||
|
||||
switch (Get<Mle>().mRole)
|
||||
{
|
||||
case kRoleDisabled:
|
||||
case kRoleDetached:
|
||||
break;
|
||||
|
||||
case kRoleChild:
|
||||
if (IsRouterCountBelowUpgradeThreshold() && Get<Mle>().HasNeighborWithGoodLinkQuality())
|
||||
{
|
||||
IgnoreError(Get<Mle>().BecomeRouter(kReasonTooFewRouters));
|
||||
}
|
||||
else
|
||||
{
|
||||
Get<Mle>().mAnnounceHandler.HandleRouterRoleTransitionAttemptDone();
|
||||
}
|
||||
|
||||
if (!Get<Mle>().mAdvertiseTrickleTimer.IsRunning())
|
||||
{
|
||||
Get<Mle>().SendMulticastAdvertisement();
|
||||
Get<Mle>().mAdvertiseTrickleTimer.Start(TrickleTimer::kModePlainTimer, kReedAdvIntervalMin,
|
||||
kReedAdvIntervalMax);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case kRoleRouter:
|
||||
if (Get<RouterTable>().GetActiveRouterCount() > mDowngradeThreshold)
|
||||
{
|
||||
LogNote("Downgrade to REED");
|
||||
Get<Mle>().mAttacher.Attach(kDowngradeToReed);
|
||||
}
|
||||
|
||||
OT_FALL_THROUGH;
|
||||
|
||||
case kRoleLeader:
|
||||
if (!IsRouterRoleAllowed())
|
||||
{
|
||||
LogInfo("Router role no longer allowed");
|
||||
IgnoreError(Get<Mle>().BecomeDetached());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
} // namespace Mle
|
||||
|
||||
Reference in New Issue
Block a user