[mle] apply random delay when sending Link Request on advertisement reception (#10870)

This commit updates `DelayedSender` to allow scheduling of delayed MLE
Link Request messages. This is used to apply a random delay when
sending a Link Request after receiving an MLE Advertisement from a
neighbor.

Advertisement messages are multicast transmissions and can be received
by multiple nodes, potentially causing synchronized generation of
Link Requests. This change helps distribute the transmission time
over a random window (one second if the requester is a router, or
[1.5-3] seconds window if it is a child).

When a router timeout occurs (i.e., no advertisements are received
from a neighboring router for more than the maximum allowed age), the
device sends Link Requests to restore its link. This commit updates
this process to apply a random delay (over a one-second window) to
each Link Request transmission.

This aligns the implementation with the Thread specification and can
improve network behavior when a new router is added or abruptly
removed.
This commit is contained in:
Abtin Keshavarzian
2024-11-20 18:12:40 -08:00
committed by GitHub
parent f26e1bb852
commit ac12984358
3 changed files with 44 additions and 4 deletions
+31
View File
@@ -4540,6 +4540,21 @@ void Mle::DelayedSender::ScheduleMulticastDataResponse(uint16_t aDelay)
AddSchedule(kTypeDataResponse, destination, aDelay, nullptr, 0);
}
void Mle::DelayedSender::ScheduleLinkRequest(const Router &aRouter, uint16_t aDelay)
{
Ip6::Address destination;
uint16_t routerRloc16;
destination.SetToLinkLocalAddress(aRouter.GetExtAddress());
VerifyOrExit(!HasMatchingSchedule(kTypeLinkRequest, destination));
routerRloc16 = aRouter.GetRloc16();
AddSchedule(kTypeLinkRequest, destination, aDelay, &routerRloc16, sizeof(uint16_t));
exit:
return;
}
void Mle::DelayedSender::ScheduleLinkAccept(const LinkAcceptInfo &aInfo, uint16_t aDelay)
{
Ip6::Address destination;
@@ -4662,6 +4677,22 @@ void Mle::DelayedSender::Execute(const Schedule &aSchedule)
break;
}
case kTypeLinkRequest:
{
uint16_t rlco16;
Router *router;
IgnoreError(aSchedule.Read(sizeof(Header), rlco16));
router = Get<RouterTable>().FindRouterByRloc16(rlco16);
if (router != nullptr)
{
Get<MleRouter>().SendLinkRequest(router);
}
break;
}
case kTypeDiscoveryResponse:
{
DiscoveryResponseInfo info;
+4
View File
@@ -766,6 +766,9 @@ private:
static constexpr uint32_t kParentResponseMaxDelayRouters = 500; // Max response delay for Parent Req to routers
static constexpr uint32_t kParentResponseMaxDelayAll = 1000; // Max response delay for Parent Req to all
static constexpr uint32_t kChildUpdateRequestDelay = 100; // Delay for aggregating Child Update Req
static constexpr uint32_t kMaxLinkRequestDelayOnRouter = 1000; // Max delay to tx Link Request on Adv rx
static constexpr uint32_t kMinLinkRequestDelayOnChild = 1500; // Min delay to tx Link Request on Adv rx (child)
static constexpr uint32_t kMaxLinkRequestDelayOnChild = 3000; // Max delay to tx Link Request on Adv rx (child)
static constexpr uint32_t kMaxLinkAcceptDelay = 1000; // Max delay to tx Link Accept for multicast Req
static constexpr uint32_t kChildIdRequestTimeout = 5000; // Max delay to rx a Child ID Req after Parent Res
static constexpr uint32_t kLinkRequestTimeout = 2000; // Max delay to rx a Link Accept
@@ -1134,6 +1137,7 @@ private:
#if OPENTHREAD_FTD
void ScheduleParentResponse(const ParentResponseInfo &aInfo, uint16_t aDelay);
void ScheduleMulticastDataResponse(uint16_t aDelay);
void ScheduleLinkRequest(const Router &aRouter, uint16_t aDelay);
void ScheduleLinkAccept(const LinkAcceptInfo &aInfo, uint16_t aDelay);
void ScheduleDiscoveryResponse(const Ip6::Address &aDestination,
const DiscoveryResponseInfo &aInfo,
+9 -4
View File
@@ -1188,6 +1188,7 @@ Error MleRouter::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddre
RouteTlv routeTlv;
Router *router;
uint8_t routerId;
uint32_t delay;
switch (aRxInfo.mMessage.ReadRouteTlv(routeTlv))
{
@@ -1301,7 +1302,8 @@ Error MleRouter::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddre
{
InitNeighbor(*router, aRxInfo);
router->SetState(Neighbor::kStateLinkRequest);
SendLinkRequest(router);
delay = Random::NonCrypto::GetUint32InRange(kMinLinkRequestDelayOnChild, kMaxLinkRequestDelayOnChild);
mDelayedSender.ScheduleLinkRequest(*router, delay);
ExitNow(error = kErrorNoRoute);
}
}
@@ -1350,7 +1352,8 @@ Error MleRouter::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddre
{
InitNeighbor(*router, aRxInfo);
router->SetState(Neighbor::kStateLinkRequest);
SendLinkRequest(router);
delay = Random::NonCrypto::GetUint32InRange(0, kMaxLinkRequestDelayOnRouter);
mDelayedSender.ScheduleLinkRequest(*router, delay);
ExitNow(error = kErrorNoRoute);
}
@@ -1651,7 +1654,8 @@ void MleRouter::HandleTimeTick(void)
bool sendLinkRequest = true;
// Once router age expires, we send Link Request every
// time tick, up to `kMaxTxCount`. After the last
// time tick (second), up to `kMaxTxCount`. Each rx is
// randomly delayed (one second window). After the last
// attempt, we wait for the "Link Accept" timeout
// (~3 seconds), before the router is removed.
@@ -1666,7 +1670,8 @@ void MleRouter::HandleTimeTick(void)
if (sendLinkRequest)
{
SendLinkRequest(&router);
mDelayedSender.ScheduleLinkRequest(
router, Random::NonCrypto::GetUint32InRange(0, kMaxLinkRequestDelayOnRouter));
}
}