[mle] improve router and leader post reset link request timings and attempts (#12022)

In order to facilitate a well-staged post reset process for a larger
size link, it is important to consider the timing of devices returning
to the link.

With the changes in this PR, that timing will be as follows:
1. The leader and routers will begin sending link request messages in
   an attempt to reattach to the previous partition.
2. Both the leader and routers will have 4 attempts to reconnect,
   afterwords falling back to attach any.
3. The leader here is given a 2s retry window (jittered 10% either
   way), for a worst-case (tightest timing vs routers) of 4x2.2s =
   8.8s before starting attachment.
4. The routers here are given the normal 5s multicast retx delay with
   the same 10% jitter, resulting in a tightest timing (shortest) of
   4x4.5s = 18s
5. For this analysis, the jitter during the attach process is ignored
   because it will not be particularly significant, so we assume both
   flow through a nominal failed attachment of 2x0.75s (routers) +
   4x1.25s (reeds) = 6.5s
6. This means that the previous leader will start the new partition
   around 15.3s after starting.
7. The former routers would fall back to starting a new partition on
   their own at 24.5s after reset.

This timing leaves 9.2s of leeway (greater than the length of the full
attachment process) for the routers to get parent responses from the
old leader which has started the new partition and attach instead of
starting their own partitions.

This also leaves sufficient time between the router attachment and
children timing out of their role restoration process to attach to
their former parents.

Additionally, 4 attempts should be more than sufficient with this
timing to successfully reattach to a partition that did not also
reset. If a link request sent in this period is not accepted, then the
old partition can be safely assumed to be gone, or removed links to
the reset device.

Routers with children and the leader will also benefit in
single-device reset cases here because they are able to rejoin more
quickly. Only routers with very few/no children are slowed down in
re-attachment by 5s.
This commit is contained in:
Tom Rebbert
2026-03-24 11:57:33 -05:00
committed by GitHub
parent 683086776f
commit 42ac624019
5 changed files with 28 additions and 29 deletions
+10 -14
View File
@@ -4236,7 +4236,7 @@ Error Mle::PrevRoleRestorer::Start(void)
Get<MeshForwarder>().SetRxOnWhenIdle(true);
SetState(kRestoringRouterOrLeaderRole);
DetermineMaxLinkRequestAttempts();
mAttempts = kRestoreLinkRequestAttempts;
mTimer.Start(Get<Mle>().GenerateRandomDelay(kMaxStartDelay));
error = kErrorNone;
#endif
@@ -4381,23 +4381,19 @@ exit:
#if OPENTHREAD_FTD
void Mle::PrevRoleRestorer::DetermineMaxLinkRequestAttempts(void)
{
mAttempts = kMaxCriticalTxCount;
if ((Get<Mle>().mLastSavedRole == kRoleRouter) &&
(Get<Mle>().mChildTable.GetNumChildren(Child::kInStateValidOrRestoring) < kMinCriticalChildrenCount))
{
mAttempts = kMaxTxCount;
}
}
void Mle::PrevRoleRestorer::SendMulticastLinkRequest(void)
{
uint32_t delay;
uint32_t retxDelayMin = kMulticastRetxDelayMin;
uint32_t retxDelayMax = kMulticastRetxDelayMax;
delay = (mAttempts == 0) ? kLinkRequestTimeout
: Random::NonCrypto::GetUint32InRange(kMulticastRetxDelayMin, kMulticastRetxDelayMax);
if (Get<Mle>().mLastSavedRole == kRoleLeader)
{
retxDelayMin = kLeaderRetxDelayMin;
retxDelayMax = kLeaderRetxDelayMax;
}
delay = (mAttempts == 0) ? kLinkRequestTimeout : Random::NonCrypto::GetUint32InRange(retxDelayMin, retxDelayMax);
mTimer.Start(delay);
+3 -1
View File
@@ -1857,6 +1857,9 @@ private:
static constexpr uint16_t kChildUpdateMinTimeout = 1000; // in ms
static constexpr uint16_t kChildUpdateStartTimeout = 4000; // in ms
static constexpr uint16_t kChildUpdateRetxJitter = 25; // in ms
static constexpr uint8_t kRestoreLinkRequestAttempts = 4;
static constexpr uint32_t kLeaderRetxDelayMin = kLinkRequestTimeout * 9 / 10; // 0.9 * base delay
static constexpr uint32_t kLeaderRetxDelayMax = kLinkRequestTimeout * 11 / 10; // 1.1 * base delay
enum State : uint8_t
{
@@ -1869,7 +1872,6 @@ private:
void SendChildUpdate(void);
void CheckIfMessageIsFromParent(RxInfo &aRxInfo);
#if OPENTHREAD_FTD
void DetermineMaxLinkRequestAttempts(void);
void SendMulticastLinkRequest(void);
#endif
+9 -8
View File
@@ -122,9 +122,10 @@ SECURITY_POLICY = [672, 'onrc']
LEADER_STARTUP_DELAY = 12
ROUTER_STARTUP_DELAY = 10
# See logic of RouterRoleRestorer
# ((kMaxTxCount=6) - 1) * 1.1 * (kMulticastRetxDelay=5) + 2 + ROUTER_STARTUP_DELAY
ROUTER_RESTORE_DELAY = 40
LEADER_REBOOT_DELAY = 40
# (MLE_MAX_RESTORING_TRANSMISSION_COUNT - 1) * 1.1 * (kMulticastRetxDelay=5s) + 2s + ROUTER_STARTUP_DELAY
ROUTER_RESTORE_DELAY = 29
# (MLE_MAX_RESTORING_TRANSMISSION_COUNT - 1) * 1.1 * (kLinkRequestTimeout=2s) + 2s + LEADER_STARTUP_DELAY
LEADER_REBOOT_DELAY = 21
ED_STARTUP_DELAY = 5
BORDER_ROUTER_STARTUP_DELAY = 20
MAX_NEIGHBOR_AGE = 100
@@ -153,11 +154,11 @@ PACKET_VERIFICATION_NONE = 0
PACKET_VERIFICATION_DEFAULT = 1
PACKET_VERIFICATION_TREL = 2
# After leader reset it may retransmit link request 6 times with max 5.5s interval
LEADER_RESET_DELAY = 41
# After router reset it may retransmit link request 3 times with max 5.5s interval
ROUTER_RESET_DELAY = 23
MLE_MAX_CRITICAL_TRANSMISSION_COUNT = 6
# After leader reset it may retransmit link request 4 times with max 2.2s interval
LEADER_RESET_DELAY = 17
# After router reset it may retransmit link request 4 times with max 5.5s interval
ROUTER_RESET_DELAY = 30
MLE_MAX_RESTORING_TRANSMISSION_COUNT = 4
MLE_MAX_TRANSMISSION_COUNT = 3
@@ -43,7 +43,7 @@ DUT_ROUTER1 = 2
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to show that when the Leader is rebooted, it sends MLE_MAX_CRITICAL_TRANSMISSION_COUNT MLE link request packets if no response is received.
# The purpose of this test case is to show that when the Leader is rebooted, it sends MLE_MAX_RESTORING_TRANSMISSION_COUNT MLE link request packets if no response is received.
#
# Test Topology:
# -------------
@@ -129,12 +129,12 @@ class Test_LeaderRebootMultipleLinkRequest(thread_cert.TestCase):
filter_wpan_src64(ROUTER).\
must_next()
# The Leader MUST send MLE_MAX_CRITICAL_TRANSMISSION_COUNT multicast Link Request
# The Leader MUST send MLE_MAX_RESTORING_TRANSMISSION_COUNT multicast Link Request
# The following TLVs MUST be present in the Link Request:
# - Challenge TLV
# - Version TLV
# - TLV Request TLV: Address16 TLV, Route64 TLV
for i in range(0, config.MLE_MAX_CRITICAL_TRANSMISSION_COUNT):
for i in range(0, config.MLE_MAX_RESTORING_TRANSMISSION_COUNT):
pkts.filter_wpan_src64(LEADER).\
filter_LLARMA().\
filter_mle_cmd(MLE_LINK_REQUEST).\
@@ -49,7 +49,7 @@ MED6 = 8
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to show that when a router with > 5 children is rebooted, it sends MLE_MAX_CRITICAL_TRANSMISSION_COUNT MLE link request packets if no response is received.
# The purpose of this test case is to show that when a router is rebooted, it sends MLE_MAX_RESTORING_TRANSMISSION_COUNT MLE link request packets if no response is received.
#
# Test Topology:
# -------------
@@ -150,12 +150,12 @@ class Test_LeaderRebootMultipleLinkRequest(thread_cert.TestCase):
filter_mle_advertisement('Router').\
must_next()
# The router MUST send MLE_MAX_CRITICAL_TRANSMISSION_COUNT multicast Link Request
# The router MUST send MLE_MAX_RESTORING_TRANSMISSION_COUNT multicast Link Request
# The following TLVs MUST be present in the Link Request:
# - Challenge TLV
# - Version TLV
# - TLV Request TLV: Address16 TLV, Route64 TLV
for i in range(0, config.MLE_MAX_CRITICAL_TRANSMISSION_COUNT):
for i in range(0, config.MLE_MAX_RESTORING_TRANSMISSION_COUNT):
pkts.filter_wpan_src64(ROUTER).\
filter_LLARMA().\
filter_mle_cmd(MLE_LINK_REQUEST).\