mirror of
https://github.com/espressif/openthread.git
synced 2026-08-26 04:09:52 +00:00
[mle] expedite recovery from temporary router link quality mismatch (#10906)
This commit adds a mechanism to expedite recovery from temporary router link quality mismatches. If a received `RouteTlv` (from a received Advertisement) indicates that the neighboring router claims no link to us by setting its `GetLinkQualityOut()` towards us as `0`, and our two-way link quality to this router is at least Link Quality 2, we schedule a unicast MLE Advertisement to be sent to this neighbor. This advertisement is sent after a randomly selected delay within a one-second window using `Mle::DelayedSender`. This helps with link recovery on the neighboring router, which otherwise may take longer due to reliance on the next trickle timer-triggered Advertisement transmission, which can be up to 32 seconds later and, being multicast, may be missed.
This commit is contained in:
@@ -4574,6 +4574,15 @@ void Mle::DelayedSender::ScheduleParentResponse(const ParentResponseInfo &aInfo,
|
||||
AddSchedule(kTypeParentResponse, destination, aDelay, &aInfo, sizeof(aInfo));
|
||||
}
|
||||
|
||||
void Mle::DelayedSender::ScheduleAdvertisement(const Ip6::Address &aDestination, uint16_t aDelay)
|
||||
{
|
||||
VerifyOrExit(!HasMatchingSchedule(kTypeAdvertisement, aDestination));
|
||||
AddSchedule(kTypeAdvertisement, aDestination, aDelay, nullptr, 0);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Mle::DelayedSender::ScheduleMulticastDataResponse(uint16_t aDelay)
|
||||
{
|
||||
Ip6::Address destination;
|
||||
@@ -4717,6 +4726,10 @@ void Mle::DelayedSender::Execute(const Schedule &aSchedule)
|
||||
break;
|
||||
}
|
||||
|
||||
case kTypeAdvertisement:
|
||||
Get<MleRouter>().SendAdvertisement(header.mDestination);
|
||||
break;
|
||||
|
||||
case kTypeDataResponse:
|
||||
Get<MleRouter>().SendMulticastDataResponse();
|
||||
break;
|
||||
|
||||
@@ -1139,6 +1139,7 @@ private:
|
||||
void ScheduleChildUpdateRequestToParent(uint16_t aDelay);
|
||||
#if OPENTHREAD_FTD
|
||||
void ScheduleParentResponse(const ParentResponseInfo &aInfo, uint16_t aDelay);
|
||||
void ScheduleAdvertisement(const Ip6::Address &aDestination, uint16_t aDelay);
|
||||
void ScheduleMulticastDataResponse(uint16_t aDelay);
|
||||
void ScheduleLinkRequest(const Router &aRouter, uint16_t aDelay);
|
||||
void ScheduleLinkAccept(const LinkAcceptInfo &aInfo, uint16_t aDelay);
|
||||
|
||||
@@ -486,7 +486,7 @@ void MleRouter::HandleAdvertiseTrickleTimer(void)
|
||||
{
|
||||
VerifyOrExit(IsRouterEligible(), mAdvertiseTrickleTimer.Stop());
|
||||
|
||||
SendAdvertisement();
|
||||
SendMulticastAdvertisement();
|
||||
|
||||
exit:
|
||||
return;
|
||||
@@ -534,11 +534,27 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void MleRouter::SendAdvertisement(void)
|
||||
void MleRouter::SendMulticastAdvertisement(void)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
Ip6::Address destination;
|
||||
TxMessage *message = nullptr;
|
||||
|
||||
destination.SetToLinkLocalAllNodesMulticast();
|
||||
SendAdvertisement(destination);
|
||||
}
|
||||
|
||||
void MleRouter::ScheduleUnicastAdvertisementTo(const Router &aRouter)
|
||||
{
|
||||
Ip6::Address destination;
|
||||
|
||||
destination.SetToLinkLocalAddress(aRouter.GetExtAddress());
|
||||
mDelayedSender.ScheduleAdvertisement(destination,
|
||||
Random::NonCrypto::GetUint32InRange(0, kMaxUnicastAdvertisementDelay));
|
||||
}
|
||||
|
||||
void MleRouter::SendAdvertisement(const Ip6::Address &aDestination)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
TxMessage *message = nullptr;
|
||||
|
||||
// Suppress MLE Advertisements when trying to attach to a better
|
||||
// partition. Without this, a candidate parent might incorrectly
|
||||
@@ -574,10 +590,9 @@ void MleRouter::SendAdvertisement(void)
|
||||
OT_ASSERT(false);
|
||||
}
|
||||
|
||||
destination.SetToLinkLocalAllNodesMulticast();
|
||||
SuccessOrExit(error = message->SendTo(destination));
|
||||
SuccessOrExit(error = message->SendTo(aDestination));
|
||||
|
||||
Log(kMessageSend, kTypeAdvertisement, destination);
|
||||
Log(kMessageSend, kTypeAdvertisement, aDestination);
|
||||
|
||||
exit:
|
||||
FreeMessageOnError(message, error);
|
||||
@@ -1604,7 +1619,7 @@ void MleRouter::HandleTimeTick(void)
|
||||
|
||||
if (!mAdvertiseTrickleTimer.IsRunning())
|
||||
{
|
||||
SendAdvertisement();
|
||||
SendMulticastAdvertisement();
|
||||
|
||||
mAdvertiseTrickleTimer.Start(TrickleTimer::kModePlainTimer, kReedAdvIntervalMin, kReedAdvIntervalMax);
|
||||
}
|
||||
@@ -3464,7 +3479,7 @@ void MleRouter::HandleAddressSolicitResponse(Coap::Message *aMessage,
|
||||
// up the dissemination of the new Router ID to other routers.
|
||||
// This can also help with quicker link establishment with our
|
||||
// former parent and other routers.
|
||||
SendAdvertisement();
|
||||
SendMulticastAdvertisement();
|
||||
|
||||
for (Child &child : Get<ChildTable>().Iterate(Child::kInStateChildIdRequest))
|
||||
{
|
||||
|
||||
@@ -362,6 +362,14 @@ public:
|
||||
*/
|
||||
void FillConnectivityTlv(ConnectivityTlv &aTlv);
|
||||
|
||||
/**
|
||||
* Schedule tx of MLE Advertisement message (unicast) to the given neighboring router after a random delay.
|
||||
*
|
||||
* @param[in] aRouter The router to send the Advertisement to.
|
||||
*
|
||||
*/
|
||||
void ScheduleUnicastAdvertisementTo(const Router &aRouter);
|
||||
|
||||
#if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
|
||||
/**
|
||||
* Sets steering data out of band
|
||||
@@ -494,6 +502,7 @@ private:
|
||||
static constexpr uint32_t kAdvIntervalMaxLogRoutes = 5000;
|
||||
#endif
|
||||
|
||||
static constexpr uint32_t kMaxUnicastAdvertisementDelay = 1000; // Max random delay for unciast Adv tx
|
||||
static constexpr uint32_t kMaxNeighborAge = 100000; // Max neighbor age (in msec)
|
||||
static constexpr uint32_t kMaxLeaderToRouterTimeout = 90000; // (in msec)
|
||||
static constexpr uint8_t kMinDowngradeNeighbors = 7;
|
||||
@@ -616,7 +625,8 @@ private:
|
||||
const Router *aRouter,
|
||||
const Ip6::MessageInfo &aMessageInfo);
|
||||
void SendAddressRelease(void);
|
||||
void SendAdvertisement(void);
|
||||
void SendMulticastAdvertisement(void);
|
||||
void SendAdvertisement(const Ip6::Address &aDestination);
|
||||
void SendLinkRequest(Router *aRouter);
|
||||
Error SendLinkAccept(const LinkAcceptInfo &aInfo);
|
||||
void SendParentResponse(const ParentResponseInfo &aInfo);
|
||||
|
||||
@@ -596,6 +596,25 @@ void RouterTable::UpdateRoutes(const Mle::RouteTlv &aRouteTlv, uint8_t aNeighbor
|
||||
neighbor->SetLinkQualityOut(linkQuality);
|
||||
SignalTableChanged();
|
||||
}
|
||||
|
||||
// If the `aRouteTlv` indicates that the neighboring
|
||||
// router claims to have no link to us (by setting its
|
||||
// `GetLinkQualityOut()` towards us as `kLinkQuality0`),
|
||||
// and we have previously established a link with it, and
|
||||
// our two-way link quality to this router is at least
|
||||
// `kLinkQuality2`, we schedule a unicast Advertisement to
|
||||
// be sent to this neighbor. This helps expedite recovery
|
||||
// from any temporary router link quality mismatch.
|
||||
// Otherwise, the neighboring router will continue to
|
||||
// advertise that it has no link to us until our next
|
||||
// trickle timer-triggered Advertisement transmission
|
||||
// (which can be up to 32 seconds later).
|
||||
|
||||
if (neighbor->IsStateValid() && (aRouteTlv.GetLinkQualityOut(index) == kLinkQuality0) &&
|
||||
(neighbor->GetTwoWayLinkQuality() >= kLinkQuality2))
|
||||
{
|
||||
Get<Mle::MleRouter>().ScheduleUnicastAdvertisementTo(*neighbor);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user