[mle] introduce "gradual router link establishment" on FTD children (#11025)

This commit introduces a "gradual router link establishment" mechanism
for FTD children. An FTD child device communicates through its parent
but can establish links with other neighboring routers to receive
multicast messages (forwarded MPL) from them, improving multicast
reliability.

An FTD child tries to establish links with the first
`ChildRouterLinks` routers quickly (sending an MLE Link Request to
initiate the link upon receiving advertisements from a neighboring
router). The `ChildRouterLinks` is configurable through an OT
configuration option (specifying the default value) and at run-time
using the `otThreadSetChildRouterLinks()` API.

After the first `ChildRouterLinks`, the "gradual router link
establishment" mechanism allows `kExtraChildRouterLinks` additional
router links to be established slowly over a longer time. Gradual
router link establishment uses the following conditions:

- The link quality to the router must be 2 or better.
- It is always skipped in the first 5 minutes
  (`kWaitDurationAfterAttach`) after the device attaches.
- The child randomly decides whether to perform/skip this (with a 5%
  probability).
- If the child decides to send a Link Request, a longer random delay
  window is used ([1.5-10] seconds).

Even in a dense network, if 500 FTD children receive the
advertisement, with a 5% selection probability, on average, 25 nodes
will try to send a Link Request randomly spread over a 1.5-10 second
window.

With a 5% probability, on average, it takes 20 trials (20 advertisement
receptions) for an FTD child to send a Link Request. Advertisements
are, on average, ~32 seconds apart, so a child will try to establish
a link in approximately 10 minutes (20 * 32 = 640 seconds).
This commit is contained in:
Abtin Keshavarzian
2025-01-09 10:17:22 -08:00
committed by GitHub
parent 5ddcb44a96
commit a877341b3b
3 changed files with 100 additions and 9 deletions
+26
View File
@@ -226,11 +226,37 @@
* @def OPENTHREAD_CONFIG_MLE_CHILD_ROUTER_LINKS
*
* Specifies the desired number of router links that a REED / FED attempts to maintain.
*
* This is default value used on an FTD child. This parameter can also be changed at run-time using the public APIs
* `otThreadGetChildRouterLinks/otThreadSetChildRouterLinks()`.
*/
#ifndef OPENTHREAD_CONFIG_MLE_CHILD_ROUTER_LINKS
#define OPENTHREAD_CONFIG_MLE_CHILD_ROUTER_LINKS 3
#endif
/**
* @def OPENTHREAD_CONFIG_MLE_EXTRA_CHILD_ROUTER_LINKS_GRADUAL
*
* Specifies the extra router links in addition to those specified by `otThreadSetChildRouterLinks()` that an FTD child
* can try to establish gradually over a longer span of time.
*
* A child device communicates through its parent but can establish links with other neighboring routers so that it can
* receive multicast messages (forwarded MPL) from other routers, thus improving multicast reliability.
*
* An FTD child tries to establish links with the first `CHILD_ROUTER_LINK` routers as quickly as possible
* (sending MLE Link Request to initiate link upon receiving advertisements from a neighboring router).
*
* After that, the FTD child uses the "gradual router link establishment" mechanism to establish router links with
* `OPENTHREAD_CONFIG_MLE_EXTRA_CHILD_ROUTER_LINKS_GRADUAL` additional routers. This is done slowly and over a longer
* span of time.
*
* This parameter can be set to zero to disable "gradual router link establishment" fully. Alternatively, it can be set
* to the maximum router count of 32 to allow the FTD child to establish links with all neighboring routers.
*/
#ifndef OPENTHREAD_CONFIG_MLE_EXTRA_CHILD_ROUTER_LINKS_GRADUAL
#define OPENTHREAD_CONFIG_MLE_EXTRA_CHILD_ROUTER_LINKS_GRADUAL 32
#endif
/**
* @def OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE
*
+63 -9
View File
@@ -1298,15 +1298,7 @@ Error MleRouter::HandleAdvertisementOnFtd(RxInfo &aRxInfo, uint16_t aSourceAddre
router = mRouterTable.FindRouterById(routerId);
VerifyOrExit(router != nullptr);
if (!router->IsStateValid() && !router->IsStateLinkRequest() &&
(mRouterTable.GetNeighborCount(kLinkQuality1) < mChildRouterLinks))
{
InitNeighbor(*router, aRxInfo);
router->SetState(Neighbor::kStateLinkRequest);
delay = Random::NonCrypto::GetUint32InRange(kMinLinkRequestDelayOnChild, kMaxLinkRequestDelayOnChild);
mDelayedSender.ScheduleLinkRequest(*router, delay);
ExitNow(error = kErrorNoRoute);
}
EstablishRouterLinkOnFtdChild(*router, aRxInfo, linkMargin);
}
#if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE
@@ -1372,6 +1364,68 @@ exit:
return error;
}
void MleRouter::EstablishRouterLinkOnFtdChild(Router &aRouter, RxInfo &aRxInfo, uint8_t aLinkMargin)
{
// Decide on an FTD child whether to establish a link with a
// router upon receiving an advertisement from it.
uint8_t neighborCount;
uint32_t minDelay;
uint32_t maxDelay;
VerifyOrExit(!aRouter.IsStateValid() && !aRouter.IsStateLinkRequest());
// The first `mChildRouterLinks` are established quickly. After that,
// the "gradual router link establishment" mechanism is used, which
// allows `kExtraChildRouterLinks` additional router links to be
// established, but it is done slowly and over a longer span of time.
//
// Gradual router link establishment conditions:
// - The maximum `neighborCount` limit is not yet reached.
// - We see Link Quality 2 or better.
// - Always skipped in the first 5 minutes
// (`kWaitDurationAfterAttach`) after the device attaches.
// - The child randomly decides whether to perform/skip this (with a 5%
// probability, `kProbabilityPercentage`).
// - If the child decides to send Link Request, a longer random delay
// window is used, [1.5-10] seconds.
//
// Even in a dense network, if the advertisement is received by 500 FTD
// children with a 5% selection probability, on average, 25 nodes will
// try to send a Link Request, which will be randomly spread over a
// [1.5-10] second window.
//
// With a 5% probability, on average, it takes 20 trials (20 advertisement
// receptions for an FTD child to send a Link Request). Advertisements
// are, on average, ~32 seconds apart, so, on average, a child will try
// to establish a link in `20 * 32 = 640` seconds (~10 minutes).
neighborCount = mRouterTable.GetNeighborCount(kLinkQuality1);
if (neighborCount < mChildRouterLinks)
{
minDelay = kMinLinkRequestDelayOnChild;
maxDelay = kMaxLinkRequestDelayOnChild;
}
else
{
VerifyOrExit(neighborCount < mChildRouterLinks + GradualChildRouterLink::kExtraChildRouterLinks);
VerifyOrExit(LinkQualityForLinkMargin(aLinkMargin) >= kLinkQuality2);
VerifyOrExit(GetCurrentAttachDuration() > GradualChildRouterLink::kWaitDurationAfterAttach);
VerifyOrExit(Random::NonCrypto::GetUint8InRange(0, 100) < GradualChildRouterLink::kProbabilityPercentage);
minDelay = GradualChildRouterLink::kMinLinkRequestDelay;
maxDelay = GradualChildRouterLink::kMaxLinkRequestDelay;
}
InitNeighbor(aRouter, aRxInfo);
aRouter.SetState(Neighbor::kStateLinkRequest);
mDelayedSender.ScheduleLinkRequest(aRouter, Random::NonCrypto::GetUint32InRange(minDelay, maxDelay));
exit:
return;
}
void MleRouter::HandleParentRequest(RxInfo &aRxInfo)
{
Error error = kErrorNone;
+11
View File
@@ -517,6 +517,16 @@ private:
static constexpr uint8_t kChildRouterLinks = OPENTHREAD_CONFIG_MLE_CHILD_ROUTER_LINKS;
static constexpr uint8_t kMaxChildIpAddresses = OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD;
// Constants for gradual router link establishment (on FTD child)
struct GradualChildRouterLink
{
static constexpr uint8_t kExtraChildRouterLinks = OPENTHREAD_CONFIG_MLE_EXTRA_CHILD_ROUTER_LINKS_GRADUAL;
static constexpr uint32_t kWaitDurationAfterAttach = 300; // in seconds (5 minutes)
static constexpr uint32_t kMinLinkRequestDelay = 1500; // in msec
static constexpr uint32_t kMaxLinkRequestDelay = 10000; // in msec
static constexpr uint32_t kProbabilityPercentage = 5; // in percent
};
static constexpr uint8_t kMinCriticalChildrenCount = 6;
static constexpr uint16_t kChildSupervisionDefaultIntervalForOlderVersion =
@@ -595,6 +605,7 @@ private:
void HandleDataRequest(RxInfo &aRxInfo);
void HandleNetworkDataUpdateRouter(void);
void HandleDiscoveryRequest(RxInfo &aRxInfo);
void EstablishRouterLinkOnFtdChild(Router &aRouter, RxInfo &aRxInfo, uint8_t aLinkMargin);
Error ProcessRouteTlv(const RouteTlv &aRouteTlv, RxInfo &aRxInfo);
Error ReadAndProcessRouteTlvOnFtdChild(RxInfo &aRxInfo, uint8_t aParentId);
void StopAdvertiseTrickleTimer(void);