[mle] use DelayedSender to delay & aggregate Child Update Requests (#10853)

This commit refines the Child Update Request mechanism within the MLE
module. The `DelayedSender` class is now used to schedule these
requests, enabling the aggregation of multiple updates into a single
transmission.

The previous implementation, which relied on
`mMessageTransmissionTimer` and a state variable, has been replaced
with the `DelayedSender` mechanism. This change aligns the Child
Update Request process with the scheduling of other MLE messages,
ensuring consistency.

Additionally, the `mMessageTransmissionTimer` is now exclusively
dedicated to retransmission handling, simplifying the logic and
improving code readability. The introduction of two boolean
variables, `mWaitingForChildUpdateResponse` and
`mWaitingForDataResponse`, further streamlines retransmission
handling by clearly tracking the waiting state for specific
responses.
This commit is contained in:
Abtin Keshavarzian
2024-11-11 08:02:00 -08:00
committed by Jonathan Hui
parent 169ac65e93
commit bf6d74d098
2 changed files with 71 additions and 88 deletions
+47 -54
View File
@@ -53,15 +53,15 @@ Mle::Mle(Instance &aInstance)
, mReceivedResponseFromParent(false)
, mDetachingGracefully(false)
, mInitiallyAttachedAsSleepy(false)
, mWaitingForChildUpdateResponse(false)
, mWaitingForDataResponse(false)
, mRole(kRoleDisabled)
, mLastSavedRole(kRoleDisabled)
, mDeviceMode(DeviceMode::kModeRxOnWhenIdle)
, mAttachState(kAttachStateIdle)
, mReattachState(kReattachStop)
, mAttachMode(kAnyPartition)
, mDataRequestState(kDataRequestNone)
, mAddressRegistrationMode(kAppendAllAddresses)
, mChildUpdateRequestState(kChildUpdateRequestNone)
, mParentRequestCounter(0)
, mChildUpdateAttempts(0)
, mDataRequestAttempts(0)
@@ -134,11 +134,7 @@ exit:
void Mle::ScheduleChildUpdateRequest(void)
{
if (mChildUpdateRequestState != kChildUpdateRequestPending)
{
mChildUpdateRequestState = kChildUpdateRequestPending;
ScheduleMessageTransmissionTimer();
}
mDelayedSender.ScheduleChildUpdateRequestToParent(kChildUpdateRequestDelay);
}
Error Mle::Disable(void)
@@ -685,12 +681,13 @@ void Mle::SetStateDetached(void)
SetRole(kRoleDetached);
SetAttachState(kAttachStateIdle);
mAttachTimer.Stop();
mDelayedSender.RemoveScheduledChildUpdateRequestToParent();
mMessageTransmissionTimer.Stop();
mChildUpdateRequestState = kChildUpdateRequestNone;
mChildUpdateAttempts = 0;
mDataRequestState = kDataRequestNone;
mDataRequestAttempts = 0;
mInitiallyAttachedAsSleepy = false;
mWaitingForChildUpdateResponse = false;
mChildUpdateAttempts = 0;
mWaitingForDataResponse = false;
mDataRequestAttempts = 0;
mInitiallyAttachedAsSleepy = false;
Get<MeshForwarder>().SetRxOnWhenIdle(true);
Get<Mac::Mac>().SetBeaconEnabled(false);
#if OPENTHREAD_FTD
@@ -1752,9 +1749,9 @@ Error Mle::SendDataRequest(const Ip6::Address &aDestination)
if (IsChild() && !IsRxOnWhenIdle())
{
mDataRequestState = kDataRequestActive;
mWaitingForDataResponse = true;
if (mChildUpdateRequestState == kChildUpdateRequestNone)
if (!mWaitingForChildUpdateResponse)
{
ScheduleMessageTransmissionTimer();
}
@@ -1813,15 +1810,8 @@ void Mle::ScheduleMessageTransmissionTimer(void)
{
uint32_t interval = 0;
switch (mChildUpdateRequestState)
if (mWaitingForChildUpdateResponse)
{
case kChildUpdateRequestNone:
break;
case kChildUpdateRequestPending:
ExitNow(interval = kChildUpdateRequestPendingDelay);
case kChildUpdateRequestActive:
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
if (Get<Mac::Mac>().IsCslEnabled())
{
@@ -1834,12 +1824,8 @@ void Mle::ScheduleMessageTransmissionTimer(void)
}
}
switch (mDataRequestState)
if (mWaitingForDataResponse)
{
case kDataRequestNone:
break;
case kDataRequestActive:
ExitNow(interval = kUnicastRetxDelay);
}
@@ -1863,15 +1849,13 @@ void Mle::HandleMessageTransmissionTimer(void)
{
// The `mMessageTransmissionTimer` is used for:
//
// - Delaying kEvent notification triggered "Child Update Request" transmission (to allow aggregation),
// - Retransmission of "Child Update Request",
// - Retransmission of "Data Request" on a child,
// - Sending periodic keep-alive "Child Update Request" messages on a non-sleepy (rx-on) child.
switch (mChildUpdateRequestState)
if (!mWaitingForChildUpdateResponse)
{
case kChildUpdateRequestNone:
if (mDataRequestState == kDataRequestActive)
if (mWaitingForDataResponse)
{
Ip6::Address destination;
@@ -1889,22 +1873,6 @@ void Mle::HandleMessageTransmissionTimer(void)
// Keep-alive "Child Update Request" only on a non-sleepy child
VerifyOrExit(IsChild() && IsRxOnWhenIdle());
break;
case kChildUpdateRequestPending:
if (Get<Notifier>().IsPending())
{
// Add another delay to ensures the Child Update Request is sent
// only after all pending changes are incorporated.
ScheduleMessageTransmissionTimer();
ExitNow();
}
mChildUpdateAttempts = 0;
break;
case kChildUpdateRequestActive:
break;
}
VerifyOrExit(mChildUpdateAttempts < kMaxChildKeepAliveAttempts, IgnoreError(BecomeDetached()));
@@ -1938,7 +1906,8 @@ Error Mle::SendChildUpdateRequestToParent(ChildUpdateRequestMode aMode)
{
// Enable MLE retransmissions on all Child Update Request
// messages, except when actively detaching.
mChildUpdateRequestState = kChildUpdateRequestActive;
mWaitingForChildUpdateResponse = true;
mDelayedSender.RemoveScheduledChildUpdateRequestToParent();
ScheduleMessageTransmissionTimer();
}
@@ -2743,7 +2712,7 @@ void Mle::HandleDataResponse(RxInfo &aRxInfo)
error = HandleLeaderData(aRxInfo);
if (mDataRequestState == kDataRequestNone && !IsRxOnWhenIdle())
if (!mWaitingForDataResponse && !IsRxOnWhenIdle())
{
// Stop fast data poll request by MLE since we received
// the response.
@@ -2903,8 +2872,8 @@ exit:
}
else if (error == kErrorNone)
{
mDataRequestAttempts = 0;
mDataRequestState = kDataRequestNone;
mDataRequestAttempts = 0;
mWaitingForDataResponse = false;
// Here the `mMessageTransmissionTimer` is intentionally not canceled
// so that when it fires from its callback a "Child Update" is sent
@@ -3560,10 +3529,10 @@ exit:
if (error == kErrorNone)
{
if (mChildUpdateRequestState == kChildUpdateRequestActive)
if (mWaitingForChildUpdateResponse)
{
mChildUpdateAttempts = 0;
mChildUpdateRequestState = kChildUpdateRequestNone;
mChildUpdateAttempts = 0;
mWaitingForChildUpdateResponse = false;
ScheduleMessageTransmissionTimer();
}
}
@@ -4331,6 +4300,26 @@ exit:
return;
}
void Mle::DelayedSender::ScheduleChildUpdateRequestToParent(uint16_t aDelay)
{
Ip6::Address destination;
destination.SetToLinkLocalAddress(Get<Mle>().mParent.GetExtAddress());
VerifyOrExit(!HasMatchingSchedule(kTypeChildUpdateRequestAsChild, destination));
AddSchedule(kTypeChildUpdateRequestAsChild, destination, aDelay, nullptr, 0);
exit:
return;
}
void Mle::DelayedSender::RemoveScheduledChildUpdateRequestToParent(void)
{
Ip6::Address destination;
destination.SetToLinkLocalAddress(Get<Mle>().mParent.GetExtAddress());
RemoveMatchingSchedules(kTypeChildUpdateRequestAsChild, destination);
}
#if OPENTHREAD_FTD
void Mle::DelayedSender::ScheduleParentResponse(const ParentResponseInfo &aInfo, uint16_t aDelay)
@@ -4449,6 +4438,10 @@ void Mle::DelayedSender::Execute(const Schedule &aSchedule)
IgnoreError(Get<Mle>().SendDataRequest(header.mDestination));
break;
case kTypeChildUpdateRequestAsChild:
IgnoreError(Get<Mle>().SendChildUpdateRequestToParent());
break;
#if OPENTHREAD_FTD
case kTypeParentResponse:
{
+24 -34
View File
@@ -731,25 +731,25 @@ private:
// Constants
// All time intervals are in milliseconds
static constexpr uint32_t kParentRequestRouterTimeout = 750; // Wait time after tx of Parent Req to routers
static constexpr uint32_t kParentRequestReedTimeout = 1250; // Wait timer after tx of Parent Req to REEDs
static constexpr uint32_t kParentRequestDuplicateMargin = 50; // Margin to detect duplicate received Parent Req
static constexpr uint32_t kChildIdResponseTimeout = 1250; // Wait time to receive Child ID Response
static constexpr uint32_t kAttachStartJitter = 50; // Max jitter time added to start of attach
static constexpr uint32_t kAnnounceProcessTimeout = 250; // Delay after Announce rx before processing
static constexpr uint32_t kAnnounceTimeout = 1400; // Total timeout for sending Announce messages
static constexpr uint16_t kMinAnnounceDelay = 80; // Min delay between Announcement messages
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 kChildUpdateRequestPendingDelay = 100; // Delay for aggregating Child Update Req
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
static constexpr uint32_t kDetachGracefullyTimeout = 1000; // Timeout for graceful detach
static constexpr uint32_t kUnicastRetxDelay = 1000; // Base delay for MLE unicast retx
static constexpr uint32_t kMulticastRetxDelay = 5000; // Base delay for MLE multicast retx
static constexpr uint32_t kMulticastRetxDelayMin = kMulticastRetxDelay * 9 / 10; // 0.9 * base delay
static constexpr uint32_t kMulticastRetxDelayMax = kMulticastRetxDelay * 11 / 10; // 1.1 * base delay
static constexpr uint32_t kParentRequestRouterTimeout = 750; // Wait time after tx of Parent Req to routers
static constexpr uint32_t kParentRequestReedTimeout = 1250; // Wait timer after tx of Parent Req to REEDs
static constexpr uint32_t kParentRequestDuplicateMargin = 50; // Margin to detect duplicate received Parent Req
static constexpr uint32_t kChildIdResponseTimeout = 1250; // Wait time to receive Child ID Response
static constexpr uint32_t kAttachStartJitter = 50; // Max jitter time added to start of attach
static constexpr uint32_t kAnnounceProcessTimeout = 250; // Delay after Announce rx before processing
static constexpr uint32_t kAnnounceTimeout = 1400; // Total timeout for sending Announce messages
static constexpr uint16_t kMinAnnounceDelay = 80; // Min delay between Announcement messages
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 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
static constexpr uint32_t kDetachGracefullyTimeout = 1000; // Timeout for graceful detach
static constexpr uint32_t kUnicastRetxDelay = 1000; // Base delay for MLE unicast retx
static constexpr uint32_t kMulticastRetxDelay = 5000; // Base delay for MLE multicast retx
static constexpr uint32_t kMulticastRetxDelayMin = kMulticastRetxDelay * 9 / 10; // 0.9 * base delay
static constexpr uint32_t kMulticastRetxDelayMax = kMulticastRetxDelay * 11 / 10; // 1.1 * base delay
static constexpr uint32_t kAnnounceBackoffForPendingDataset = 60000; // Max delay left to block Announce processing.
static constexpr uint8_t kMaxTxCount = 3; // Max tx count for MLE message
@@ -859,13 +859,6 @@ private:
kToRoutersAndReeds, // Parent Request to all routers and REEDs.
};
enum ChildUpdateRequestState : uint8_t
{
kChildUpdateRequestNone, // No pending or active Child Update Request.
kChildUpdateRequestPending, // Pending Child Update Request due to relative OT_CHANGED event.
kChildUpdateRequestActive, // Child Update Request has been sent and Child Update Response is expected.
};
enum ChildUpdateRequestMode : uint8_t // Used in `SendChildUpdateRequest()`
{
kNormalChildUpdateRequest, // Normal Child Update Request.
@@ -873,12 +866,6 @@ private:
kAppendZeroTimeout, // Use zero timeout when appending Timeout TLV (used for graceful detach).
};
enum DataRequestState : uint8_t
{
kDataRequestNone, // Not waiting for a Data Response.
kDataRequestActive, // Data Request has been sent, Data Response is expected.
};
enum SecuritySuite : uint8_t
{
k154Security = 0, // Security suite value indicating that MLE message is not secured.
@@ -1108,6 +1095,7 @@ private:
void Stop(void);
void ScheduleDataRequest(const Ip6::Address &aDestination, uint16_t aDelay);
void ScheduleChildUpdateRequestToParent(uint16_t aDelay);
#if OPENTHREAD_FTD
void ScheduleParentResponse(const ParentResponseInfo &aInfo, uint16_t aDelay);
void ScheduleMulticastDataResponse(uint16_t aDelay);
@@ -1116,6 +1104,8 @@ private:
const DiscoveryResponseInfo &aInfo,
uint16_t aDelay);
#endif
void RemoveScheduledChildUpdateRequestToParent(void);
void HandleTimer(void);
const MessageQueue &GetQueue(void) const { return mSchedules; }
@@ -1398,6 +1388,8 @@ private:
bool mReceivedResponseFromParent : 1;
bool mDetachingGracefully : 1;
bool mInitiallyAttachedAsSleepy : 1;
bool mWaitingForChildUpdateResponse : 1;
bool mWaitingForDataResponse : 1;
DeviceRole mRole;
DeviceRole mLastSavedRole;
@@ -1405,9 +1397,7 @@ private:
AttachState mAttachState;
ReattachState mReattachState;
AttachMode mAttachMode;
DataRequestState mDataRequestState;
AddressRegistrationMode mAddressRegistrationMode;
ChildUpdateRequestState mChildUpdateRequestState;
uint8_t mParentRequestCounter;
uint8_t mChildUpdateAttempts;