mirror of
https://github.com/espressif/openthread.git
synced 2026-08-16 23:57:46 +00:00
[mle] use increasing timeout for child role restoration (#11895)
This change updates the `PrevRoleRestorer` logic to use an increasing timeout when a non-sleepy device sends `Child Update Request` messages to restore its previous child role. The timeout starts at 4 seconds and doubles with each subsequent retransmission. This strategy is designed to handle scenarios where the parent may also be restarting, such as after a network-wide power outage, by allowing more time for the parent to recover. Over four attempts, the device waits a total of 29 seconds (4 + 8 + 16 + 1) before abandoning the restoration process. Sleepy devices continue to use a short and fixed 1-second timeout between retransmissions. Additionally, if the restoring child receives a Child Update Request from its former parent, it switches back to the shorter 1-second timeout to expedite the restoration process and allow at least two more Child Update attempts.
This commit is contained in:
+70
-2
@@ -2231,6 +2231,7 @@ void Mle::HandleChildUpdateRequestOnChild(RxInfo &aRxInfo)
|
||||
// message (`canTrustMessage` will be `false`).
|
||||
|
||||
VerifyOrExit(mPrevRoleRestorer.IsRestoringChildRole());
|
||||
mPrevRoleRestorer.HandleChildUpdateRequest(aRxInfo);
|
||||
}
|
||||
|
||||
SuccessOrExit(error = Tlv::Find<SourceAddressTlv>(aRxInfo.mMessage, sourceAddress));
|
||||
@@ -4203,6 +4204,8 @@ Mle::PrevRoleRestorer::PrevRoleRestorer(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mState(kIdle)
|
||||
, mAttempts(0)
|
||||
, mUseIncreasingTimeout(false)
|
||||
, mCurTimeout(0)
|
||||
, mTimer(aInstance)
|
||||
{
|
||||
}
|
||||
@@ -4242,9 +4245,38 @@ Error Mle::PrevRoleRestorer::Start(void)
|
||||
|
||||
VerifyOrExit(Get<Mle>().mLastSavedRole == kRoleChild);
|
||||
VerifyOrExit(Get<Mle>().mParent.IsStateValidOrRestoring());
|
||||
|
||||
// Try to restore the previous child role by sending up to
|
||||
// `kChildUpdateAttempts` Child Update Requests to the former
|
||||
// parent.
|
||||
//
|
||||
// A non-sleepy child uses an increasing timeout (starting at
|
||||
// `kChildUpdateStartTimeout` and doubling) to give a potentially
|
||||
// restarting parent more time to recover. The total wait time is
|
||||
// 29 seconds (4+8+16+1). A sleepy child uses a fixed short
|
||||
// timeout of one seconds(`kChildUpdateMinTimeout`).
|
||||
//
|
||||
// Receiving an MLE message from the parent triggers a switch to
|
||||
// the short timeout and guarantees at least two more attempts
|
||||
// (`kExtraChildUpdatesAfterRxFromParent`).
|
||||
|
||||
SetState(kRestoringChildRole);
|
||||
|
||||
GenerateRandomChallenge();
|
||||
mAttempts = kMaxChildUpdatesToRestoreRole;
|
||||
|
||||
mAttempts = kChildUpdateAttempts;
|
||||
|
||||
if (!Get<Mle>().IsRxOnWhenIdle())
|
||||
{
|
||||
mUseIncreasingTimeout = false;
|
||||
mCurTimeout = kChildUpdateMinTimeout;
|
||||
}
|
||||
else
|
||||
{
|
||||
mUseIncreasingTimeout = true;
|
||||
mCurTimeout = kChildUpdateStartTimeout;
|
||||
}
|
||||
|
||||
mTimer.Start(Get<Mle>().GenerateRandomDelay(kMaxStartDelay));
|
||||
error = kErrorNone;
|
||||
|
||||
@@ -4305,12 +4337,48 @@ exit:
|
||||
|
||||
void Mle::PrevRoleRestorer::SendChildUpdate(void)
|
||||
{
|
||||
mTimer.Start(Random::NonCrypto::AddJitter(kChildUpdateRetxDelay, kRetxJitter));
|
||||
if (mAttempts == 0)
|
||||
{
|
||||
mTimer.Start(kChildUpdateMinTimeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
mTimer.Start(Random::NonCrypto::AddJitter(mCurTimeout, kChildUpdateRetxJitter));
|
||||
|
||||
if (mUseIncreasingTimeout)
|
||||
{
|
||||
mCurTimeout += mCurTimeout;
|
||||
}
|
||||
}
|
||||
|
||||
LogDebg("Sending Child Update Request to restore child role, remaining attempts: %u", mAttempts);
|
||||
IgnoreError(Get<Mle>().SendChildUpdateRequestToParent(kToRestoreChildRole));
|
||||
}
|
||||
|
||||
void Mle::PrevRoleRestorer::CheckIfMessageIsFromParent(RxInfo &aRxInfo)
|
||||
{
|
||||
VerifyOrExit(IsRestoringChildRole());
|
||||
VerifyOrExit(aRxInfo.mNeighbor == &Get<Mle>().GetParent());
|
||||
|
||||
VerifyOrExit(mUseIncreasingTimeout);
|
||||
|
||||
LogInfo("Received msg from former parent, speeding up child role restoration");
|
||||
|
||||
mUseIncreasingTimeout = false;
|
||||
mCurTimeout = kChildUpdateMinTimeout;
|
||||
|
||||
if (mAttempts <= kExtraChildUpdatesAfterRxFromParent)
|
||||
{
|
||||
mAttempts = kExtraChildUpdatesAfterRxFromParent;
|
||||
LogInfo("Allow extra Child Update attempts %u", mAttempts);
|
||||
}
|
||||
|
||||
mTimer.FireAtIfEarlier(TimerMilli::GetNow() + Random::NonCrypto::AddJitter(mCurTimeout, kChildUpdateRetxJitter));
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
|
||||
void Mle::PrevRoleRestorer::DetermineMaxLinkRequestAttempts(void)
|
||||
|
||||
+13
-5
@@ -1843,15 +1843,20 @@ private:
|
||||
bool IsRestoringChildRole(void) const { return mState == kRestoringChildRole; }
|
||||
bool IsRestoringRouterOrLeaderRole(void) const { return mState == kRestoringRouterOrLeaderRole; }
|
||||
void HandleTimer(void);
|
||||
void HandleChildUpdateRequest(RxInfo &aRxInfo) { CheckIfMessageIsFromParent(aRxInfo); }
|
||||
|
||||
void GenerateRandomChallenge(void) { mChallenge.GenerateRandom(); }
|
||||
const TxChallenge &GetChallenge(void) const { return mChallenge; }
|
||||
|
||||
private:
|
||||
static constexpr uint32_t kMaxStartDelay = 25;
|
||||
static constexpr uint8_t kMaxChildUpdatesToRestoreRole = kMaxChildKeepAliveAttempts;
|
||||
static constexpr uint32_t kChildUpdateRetxDelay = kUnicastRetxDelay; /// 1000 msec
|
||||
static constexpr uint16_t kRetxJitter = 5;
|
||||
static constexpr uint32_t kMaxStartDelay = 25; // in msec
|
||||
|
||||
// Restoring Child Role (sending "child update request").
|
||||
static constexpr uint8_t kChildUpdateAttempts = 4;
|
||||
static constexpr uint8_t kExtraChildUpdatesAfterRxFromParent = 2;
|
||||
static constexpr uint16_t kChildUpdateMinTimeout = 1000; // in ms
|
||||
static constexpr uint16_t kChildUpdateStartTimeout = 4000; // in ms
|
||||
static constexpr uint16_t kChildUpdateRetxJitter = 25; // in ms
|
||||
|
||||
enum State : uint8_t
|
||||
{
|
||||
@@ -1862,6 +1867,7 @@ private:
|
||||
|
||||
void SetState(State aState);
|
||||
void SendChildUpdate(void);
|
||||
void CheckIfMessageIsFromParent(RxInfo &aRxInfo);
|
||||
#if OPENTHREAD_FTD
|
||||
void DetermineMaxLinkRequestAttempts(void);
|
||||
void SendMulticastLinkRequest(void);
|
||||
@@ -1870,7 +1876,9 @@ private:
|
||||
using DelayTimer = TimerMilliIn<Mle, &Mle::HandleRoleRestorerTimer>;
|
||||
|
||||
State mState;
|
||||
uint8_t mAttempts;
|
||||
uint8_t mAttempts : 7;
|
||||
bool mUseIncreasingTimeout : 1;
|
||||
uint16_t mCurTimeout;
|
||||
DelayTimer mTimer;
|
||||
TxChallenge mChallenge;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user