Skip to content

Commit 01d3944

Browse files
[mle] Consolidate role transition management in RoleTransitioner
This commit introduces the `RoleTransitioner` class (renamed from `RouterRoleTransition`) to centralize the management of state related to router role allowed, up/downgrade thresholds, and the address solicit state without introducing functional changes, to support future changes related to configuring these parameters. This commit is intended to not change any functionality, though some expected enhancements have been added in several TODO comments. The following state and logic are moved from the `Mle` class into the `RoleTransitioner`: - Increased scope of the state tracked by the `RoleTransitioner` class for all operations directly related to determining the transition state or timing for FTDs. This includes logic on values that can be passed with simple parameters to check functions, but excludes `InstanceLocator` operations, so that the class can remain focused on determining the role transition state. - `Signal...` methods of the `RoleTransitioner` class have been defined to clarify events affecting state transitions. - Named transition conditions on thresholds to `MayUpgrade()`, `MayBeginDowngradeTimer()`, and `MayCompleteTimedDowngrade()` to clarify that additional conditions may apply where called and to be more descriptive of the use of each threshold. - Renamed `WillBecomeRouterSoon()` -> `MayBecomeRouterSoon()` to match other related name changes and indicate that a pending upgrade may fail to take effect. - This also includes the downgrade blocking state (`mDowngradeBlocked`). - Includes adding an extra delay in the Leader role when starting a downgrade timer due to the router role no longer allowed. - Caches separate states affecting the `mRouterRoleAllowed` state, also detecting if a downgrade timer should be started based on - Some related switch cases have been replaced by short if-else blocks where it has a measurable improvement on codespace for the size-check build.
1 parent 8e6469d commit 01d3944

6 files changed

Lines changed: 343 additions & 265 deletions

File tree

src/core/api/thread_ftd_api.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ otError otThreadSetMaxChildIpAddresses(otInstance *aInstance, uint8_t aMaxIpAddr
6363

6464
bool otThreadIsRouterEligible(otInstance *aInstance)
6565
{
66+
// The value returned by the API is based on all factors affecting the Router-role-allowed status.
6667
return AsCoreType(aInstance).Get<Mle::Mle>().IsRouterRoleAllowed();
6768
}
6869

src/core/thread/dua_manager.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ void DuaManager::HandleNotifierEvents(Events aEvents)
319319
// Wait for link establishment with neighboring routers.
320320
UpdateRegistrationDelay(kNewRouterRegistrationDelay);
321321
}
322-
else if (Get<Mle::Mle>().WillBecomeRouterSoon())
322+
else if (Get<Mle::Mle>().MayBecomeRouterSoon())
323323
{
324324
// Will check again in case the device decides to stay REED when jitter timeout expires.
325325
UpdateRegistrationDelay(Get<Mle::Mle>().GetRouterRoleTransitionTimeout() + kNewRouterRegistrationDelay + 1);
@@ -432,7 +432,7 @@ void DuaManager::PerformNextRegistration(void)
432432
// Only send DUA.req when necessary
433433
#if OPENTHREAD_CONFIG_DUA_ENABLE
434434
#if OPENTHREAD_FTD
435-
if (!Get<Mle::Mle>().IsRouterOrLeader() && Get<Mle::Mle>().WillBecomeRouterSoon())
435+
if (!Get<Mle::Mle>().IsRouterOrLeader() && Get<Mle::Mle>().MayBecomeRouterSoon())
436436
{
437437
UpdateRegistrationDelay(Get<Mle::Mle>().GetRouterRoleTransitionTimeout() + kNewRouterRegistrationDelay + 1);
438438
ExitNow();

src/core/thread/mle.cpp

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,6 @@ Mle::Mle(Instance &aInstance)
8080
, mWedAttachTimer(aInstance)
8181
#endif
8282
#if OPENTHREAD_FTD
83-
, mAddressSolicitPending(false)
84-
, mAddressSolicitRejected(false)
8583
, mNetworkIdTimeout(kNetworkIdTimeout)
8684
, mPreviousPartitionRouterIdSequence(0)
8785
, mPreviousPartitionIdTimeout(0)
@@ -99,7 +97,6 @@ Mle::Mle(Instance &aInstance)
9997
, mAdvertiseTrickleTimer(aInstance, Mle::HandleAdvertiseTrickleTimer)
10098
, mChildTable(aInstance)
10199
, mRouterTable(aInstance)
102-
, mRoleTransitioner(aInstance)
103100
#endif // OPENTHREAD_FTD
104101
#if OPENTHREAD_CONFIG_P2P_ENABLE
105102
, mP2p(aInstance)
@@ -294,6 +291,10 @@ void Mle::SetRole(DeviceRole aRole)
294291

295292
SuccessOrExit(Get<Notifier>().Update(mRole, aRole, kEventThreadRoleChanged));
296293

294+
#if OPENTHREAD_FTD
295+
mRoleTransitioner.SignalRoleChanged();
296+
#endif
297+
297298
LogNote("Role %s -> %s", RoleToString(oldRole), RoleToString(mRole));
298299

299300
if ((oldRole == kRoleDetached) && IsAttached())
@@ -446,10 +447,6 @@ void Mle::Restore(void)
446447
// non-volatile settings after boot.
447448
mHasRestored = true;
448449

449-
#if OPENTHREAD_FTD
450-
mRoleTransitioner.UpdateRouterRoleAllowed(RoleTransitioner::kReasonMleInit);
451-
#endif
452-
453450
exit:
454451
return;
455452
}
@@ -598,7 +595,7 @@ void Mle::SetStateDetached(void)
598595
Get<MeshForwarder>().SetRxOnWhenIdle(true);
599596
Get<Mac::Mac>().SetBeaconEnabled(false);
600597
#if OPENTHREAD_FTD
601-
mRoleTransitioner.SetDowngradeBlocked(false);
598+
mRoleTransitioner.SignalDowngradeBlocked(false);
602599
ClearAlternateRloc16();
603600
HandleDetachStart();
604601
#endif
@@ -719,7 +716,7 @@ Error Mle::SetDeviceMode(DeviceMode aDeviceMode)
719716
ClearAlternateRloc16();
720717
}
721718

722-
mRoleTransitioner.UpdateRouterRoleAllowed(RoleTransitioner::kReasonDeviceModeChanged);
719+
mRoleTransitioner.SignalFtdModeChanged(IsFullThreadDevice(), mRole);
723720
#endif
724721

725722
if (IsAttached())
@@ -1044,7 +1041,7 @@ void Mle::HandleNotifierEvents(Events aEvents)
10441041
#if OPENTHREAD_FTD
10451042
if (aEvents.Contains(kEventSecurityPolicyChanged))
10461043
{
1047-
mRoleTransitioner.UpdateRouterRoleAllowed(RoleTransitioner::kReasonSecurityPolicyChanged);
1044+
HandleRouterRoleAllowedFromSecurityPolicy();
10481045
}
10491046

10501047
if (mRoleTransitioner.IsDowngradeBlocked() && aEvents.Contains(kEventThreadChildRemoved))
@@ -1060,7 +1057,7 @@ void Mle::HandleNotifierEvents(Events aEvents)
10601057
}
10611058
}
10621059

1063-
mRoleTransitioner.SetDowngradeBlocked(shouldBlock);
1060+
mRoleTransitioner.SignalDowngradeBlocked(shouldBlock);
10641061
}
10651062
#endif
10661063

src/core/thread/mle.hpp

Lines changed: 89 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -771,7 +771,7 @@ class Mle : public InstanceLocator, private NonCopyable
771771
* @retval kErrorNone Successfully set the router-eligible configuration.
772772
* @retval kErrorNotCapable The device is not capable of becoming a router.
773773
*/
774-
Error SetRouterEligible(bool aEligible) { return mRoleTransitioner.SetRouterEligible(aEligible); }
774+
Error SetRouterEligible(bool aEligible);
775775

776776
/**
777777
* Indicates whether the router role is currently allowed.
@@ -1022,7 +1022,7 @@ class Mle : public InstanceLocator, private NonCopyable
10221022
* @retval TRUE If the REED is going to become a Router soon.
10231023
* @retval FALSE If the REED is not going to become a Router soon.
10241024
*/
1025-
bool WillBecomeRouterSoon(void) const { return mRoleTransitioner.WillBecomeRouterSoon(); }
1025+
bool MayBecomeRouterSoon(void) const { return IsChild() && mRoleTransitioner.MayBecomeRouterSoon(); }
10261026

10271027
/**
10281028
* Removes a link to a neighbor.
@@ -1179,14 +1179,14 @@ class Mle : public InstanceLocator, private NonCopyable
11791179
*
11801180
* @param[in] aEnabled TRUE if the device was commissioned using CCM, FALSE otherwise.
11811181
*/
1182-
void SetCcmEnabled(bool aEnabled) { mRoleTransitioner.SetCcmEnabled(aEnabled); }
1182+
void SetCcmEnabled(bool aEnabled);
11831183

11841184
/**
11851185
* Sets whether the Security Policy TLV version-threshold for routing (VR field) is enabled.
11861186
*
11871187
* @param[in] aEnabled TRUE to enable Security Policy TLV version-threshold for routing, FALSE otherwise.
11881188
*/
1189-
void SetThreadVersionCheckEnabled(bool aEnabled) { mRoleTransitioner.SetThreadVersionCheckEnabled(aEnabled); }
1189+
void SetThreadVersionCheckEnabled(bool aEnabled);
11901190

11911191
/**
11921192
* Gets the current Interval Max value used by Advertisement trickle timer.
@@ -1344,12 +1344,8 @@ class Mle : public InstanceLocator, private NonCopyable
13441344
static constexpr uint32_t kMaxLeaderToRouterTimeout = 90000; // (in msec)
13451345
static constexpr uint8_t kMinDowngradeNeighbors = 7;
13461346
static constexpr uint8_t kNetworkIdTimeout = 120; // (in sec)
1347-
static constexpr uint8_t kRouterSelectionJitter = 120; // (in sec)
1348-
static constexpr uint8_t kRouterDowngradeThreshold = 23;
1349-
static constexpr uint8_t kRouterUpgradeThreshold = 16;
13501347
static constexpr uint16_t kDiscoveryMaxJitter = 250; // Max jitter delay Discovery Responses (in msec).
13511348
static constexpr uint16_t kUnsolicitedDataResponseJitter = 500; // Max delay for unsol Data Response (in msec).
1352-
static constexpr uint8_t kLeaderDowngradeExtraDelay = 10; // Extra delay to downgrade leader (in sec).
13531349
static constexpr uint8_t kDefaultLeaderWeight = 64;
13541350
static constexpr uint8_t kAlternateRloc16Timeout = 8; // Time to use alternate RLOC16 (in sec).
13551351

@@ -2204,58 +2200,97 @@ class Mle : public InstanceLocator, private NonCopyable
22042200

22052201
#if OPENTHREAD_FTD
22062202

2207-
class RoleTransitioner : public InstanceLocator
2203+
class RoleTransitioner
22082204
{
2209-
// Manages the router role upgrade/downgrade transitions
2210-
22112205
public:
2212-
enum UpdateRouterRoleAllowedReason : uint8_t // Used in `UpdateRouterRoleAllowed()`
2213-
{
2214-
kReasonMleInit,
2215-
kReasonDeviceModeChanged,
2216-
kReasonConfigParameterChanged,
2217-
kReasonSecurityPolicyChanged,
2218-
};
2206+
explicit RoleTransitioner(void);
22192207

2220-
explicit RoleTransitioner(Instance &aInstance);
2208+
bool IsAddressSolicitPending(void) const { return mAddressSolicitState == kAddressSolicitStatePending; }
2209+
bool IsRouterRoleAllowed(void) const { return mRouterRoleAllowed; }
2210+
bool IsTransitionPending(void) const { return (mTimeout != 0); }
2211+
bool IsDowngradeBlocked(void) const { return mDowngradeBlocked; }
2212+
2213+
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
2214+
bool IsCcmEnabled(void) const { return mCcmEnabled; }
2215+
bool IsThreadVersionCheckEnabled(void) const { return mThreadVersionCheckEnabled; }
2216+
#endif
22212217

2222-
bool IsRouterRoleAllowed(void) const { return mRouterRoleAllowed; }
2223-
void UpdateRouterRoleAllowed(UpdateRouterRoleAllowedReason aReason);
2224-
Error SetRouterEligible(bool aEligible);
2218+
bool MayBeginDowngradeTimer(uint8_t aRouterCount, uint16_t aValidChildren) const;
2219+
bool MayCompleteTimedDowngrade(uint8_t aRouterCount) const;
2220+
bool MayUpgrade(uint8_t aRouterCount) const;
2221+
bool MayBecomeRouterSoon(void) const;
2222+
2223+
uint8_t GetTimeout(void) const { return mTimeout; }
22252224
uint8_t GetJitter(void) const { return mJitter; }
2226-
void SetJitter(uint8_t aJitter) { mJitter = aJitter; }
22272225
uint8_t GetUpgradeThreshold(void) const { return mUpgradeThreshold; }
2228-
void SetUpgradeThreshold(uint8_t aThreshold) { mUpgradeThreshold = aThreshold; }
22292226
uint8_t GetDowngradeThreshold(void) const { return mDowngradeThreshold; }
2230-
void SetDowngradeThreshold(uint8_t aThreshold) { mDowngradeThreshold = aThreshold; }
2231-
bool IsDowngradeBlocked(void) const { return mDowngradeBlocked; }
2232-
void SetDowngradeBlocked(bool aBlocked) { mDowngradeBlocked = aBlocked; }
2233-
bool IsTransitionPending(void) const { return (mTimeout != 0); }
2234-
bool WillBecomeRouterSoon(void) const;
2235-
void StartTimeout(void);
2236-
void StopTimeout(void) { mTimeout = 0; }
2237-
void IncreaseTimeout(uint8_t aIncrement) { mTimeout += aIncrement; }
2238-
uint8_t GetTimeout(void) const { return mTimeout; }
2239-
bool IsRouterCountBelowUpgradeThreshold(void) const;
2240-
void HandleTimeTick(void);
2241-
void DecideWhetherToUpgrade(void);
2242-
void DecideWhetherToDowngrade(uint8_t aNeighborId, const RouteTlv &aRouteTlv);
2227+
2228+
void SetJitter(uint8_t aJitter) { mJitter = aJitter; }
2229+
void SetUpgradeThreshold(uint8_t aThreshold) { mUpgradeThreshold = aThreshold; }
2230+
void SetDowngradeThreshold(uint8_t aThreshold) { mDowngradeThreshold = aThreshold; }
2231+
2232+
bool HandleTimeTick(void);
2233+
void StartRouterUpgradeIfConditionsAllow(uint8_t aRouterCount);
2234+
2235+
// ------------------
2236+
// Transition signals
2237+
void SignalAddressSolicitFinished(void);
2238+
void SignalAddressSolicitPending(void) { mAddressSolicitState = kAddressSolicitStatePending; }
2239+
void SignalAddressSolicitRejected(void) { mAddressSolicitState = kAddressSolicitStateRejected; }
2240+
void SignalBecomingRouter(void) { StopTimer(); }
2241+
void SignalBeginTimedLeaderDowngrade(void);
2242+
void SignalBeginTimedRouterDowngrade(void);
2243+
void SignalChildUpgradeStart(void);
2244+
void SignalDowngradeAborted(void);
2245+
void SignalDowngradeBlocked(bool aShouldBlock);
2246+
void SignalRoleChanged(void);
2247+
2248+
// -----------------------------------------------------------------
2249+
// State transition signals affecting the Router role allowed status
2250+
void SignalFtdModeChanged(bool aIsFtdMode, DeviceRole aRole);
2251+
void SignalRouterEligible(bool aEligible, DeviceRole aRole);
2252+
void SignalRouterRoleAllowedBySecurityPolicy(bool aAllowed, DeviceRole aRole);
2253+
22432254
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
2244-
void SetCcmEnabled(bool aEnabled);
2245-
void SetThreadVersionCheckEnabled(bool aEnabled);
2255+
void SetCcmEnabled(bool aCcmEnabled) { mCcmEnabled = aCcmEnabled; }
2256+
void SetThreadVersionCheckEnabled(bool aThreadVersionCheckEnabled)
2257+
{
2258+
mThreadVersionCheckEnabled = aThreadVersionCheckEnabled;
2259+
}
22462260
#endif
22472261

22482262
private:
2249-
bool DetermineIfRouterRoleAllowed(void) const;
2250-
bool NeighborHasComparableConnectivity(uint8_t aNeighborId, const RouteTlv &aRouteTlv) const;
2263+
enum AddressSolicitState : uint8_t
2264+
{
2265+
kAddressSolicitStateIdle,
2266+
kAddressSolicitStatePending,
2267+
kAddressSolicitStateRejected,
2268+
};
2269+
2270+
void BeginTimer(void);
2271+
void StopTimer(void);
2272+
void SignalRouterRoleAllowedUpdate(DeviceRole aRole);
2273+
2274+
static constexpr uint8_t kLeaderDowngradeExtraDelay = 10; ///< Extra delay to downgrade leader (in sec).
2275+
static constexpr uint8_t kMaxDelayToTransitionSoon = 10; ///< Time window considered "soon" (in sec).
2276+
static constexpr uint8_t kRouterSelectionJitterDefault = 120; ///< Timeout jitter (in sec).
22512277

2252-
bool mRouterEligible : 1;
2253-
bool mRouterRoleAllowed : 1;
2254-
bool mDowngradeBlocked : 1;
2278+
static constexpr uint8_t kRouterDowngradeThresholdDefault = 23; ///< Default downgrade threshold
2279+
static constexpr uint8_t kRouterUpgradeThresholdDefault = 16; ///< Default upgrade threshold
2280+
2281+
// Router Role Allowed statuses
2282+
bool mRouterRoleAllowed : 1; ///< Cached state of the router role allowed status
2283+
bool mRouterEligible : 1; ///< Router Eligible configuration affecting the role allowed status
2284+
bool mUsingFtdMode : 1; ///< FTD mode
2285+
bool mRouterRoleAllowedBySecurityPolicy : 1; ///< Cached state of the security policy router role allowed status
2286+
bool mDowngradeBlocked : 1; ///< Router role blocked from downgrading
22552287
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
2256-
bool mCcmEnabled : 1;
2257-
bool mThreadVersionCheckEnabled : 1;
2288+
bool mCcmEnabled : 1; ///< Whether to allow the security policy CCM commissioned check
2289+
bool mThreadVersionCheckEnabled : 1; ///< Whether to allow the security policy version check
22582290
#endif
2291+
2292+
AddressSolicitState mAddressSolicitState;
2293+
22592294
uint8_t mTimeout;
22602295
uint8_t mJitter;
22612296
uint8_t mUpgradeThreshold;
@@ -2446,6 +2481,8 @@ class Mle : public InstanceLocator, private NonCopyable
24462481
void ClearAlternateRloc16(void);
24472482
uint8_t SelectLeaderId(void) const;
24482483
uint32_t SelectPartitionId(void) const;
2484+
void HandleRouterRoleAllowedFromSecurityPolicy(void);
2485+
void HandleRoleAllowedChangedFromConfig(void);
24492486
void DetermineConnectivity(Connectivity &aConnectivity) const;
24502487
void HandleDetachStart(void);
24512488
void HandleChildStart(void);
@@ -2493,6 +2530,8 @@ class Mle : public InstanceLocator, private NonCopyable
24932530
void SetChildStateToValid(Child &aChild);
24942531
bool HasChildren(void);
24952532
void RemoveChildren(void);
2533+
void CheckOrBeginRouterDowngrade(uint8_t aNeighborId, const RouteTlv &aRouteTlv);
2534+
bool NeighborHasComparableConnectivity(const RouteTlv &aRouteTlv, uint8_t aNeighborId) const;
24962535
void HandleAdvertiseTrickleTimer(void);
24972536
void HandleTimeTick(void);
24982537
void HandleRouterTableEvent(RouterTable::Events aEvents);
@@ -2571,13 +2610,13 @@ class Mle : public InstanceLocator, private NonCopyable
25712610

25722611
#if OPENTHREAD_FTD
25732612

2574-
bool mAddressSolicitPending : 1;
2575-
bool mAddressSolicitRejected : 1;
2613+
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
2614+
bool mCcmEnabled : 1;
2615+
bool mThreadVersionCheckEnabled : 1;
2616+
#endif
25762617
uint8_t mRouterId;
25772618
uint8_t mPreviousRouterId;
25782619
uint8_t mNetworkIdTimeout;
2579-
uint8_t mRouterUpgradeThreshold;
2580-
uint8_t mRouterDowngradeThreshold;
25812620
uint8_t mLeaderWeight;
25822621
uint8_t mPreviousPartitionRouterIdSequence;
25832622
uint8_t mPreviousPartitionIdTimeout;

0 commit comments

Comments
 (0)