Skip to content

Commit 7169561

Browse files
authored
[mle] update DelayedSender to keep the tx schedule (openthread#10846)
This commit updates how `Mle::DelayedSender` sends MLE messages after a delay. Previously, a delayed message was fully prepared and placed in a queue, waiting for its delay duration to expire. In the new model, a delayed message is prepared when the requested delay time expires and the message transmission time is reached. The message is constructed right before transmission. This ensures that the delayed message includes the most up-to-date information and simplifies the methods that prepare and send different types of MLE messages. `DelayedSender` now keeps track of the message type and the specific information required to construct the message later. For example, for a delayed Parent Response to a Parent Request, the extended address and the `RxChallenge` of the child are saved. This new model makes it easier to implement the desired behavior when similar messages are already scheduled to the same destination. For example: - For Data Request, if one is already scheduled, a new request can be skipped, as the earlier Data Request will be valid. - For Parent Response, Link Accept, and Data Response, a new schedule request replaces an earlier one. - For Discovery Response, multiple schedules are allowed.
1 parent e6a6b9f commit 7169561

File tree

5 files changed

+372
-217
lines changed

5 files changed

+372
-217
lines changed

src/core/thread/mle.cpp

Lines changed: 172 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ void Mle::Stop(StopMode aMode)
217217

218218
VerifyOrExit(!IsDisabled());
219219

220+
mDelayedSender.Stop();
220221
Get<KeyManager>().Stop();
221222
SetStateDetached();
222223
Get<ThreadNetif>().UnsubscribeMulticast(mRealmLocalAllThreadNodes);
@@ -1737,22 +1738,17 @@ Error Mle::SendChildIdRequest(void)
17371738
}
17381739

17391740
Error Mle::SendDataRequest(const Ip6::Address &aDestination)
1740-
{
1741-
return SendDataRequestAfterDelay(aDestination, /* aDelay */ 0);
1742-
}
1743-
1744-
Error Mle::SendDataRequestAfterDelay(const Ip6::Address &aDestination, uint16_t aDelay)
17451741
{
17461742
static const uint8_t kTlvs[] = {Tlv::kNetworkData, Tlv::kRoute};
17471743

1748-
Error error;
1744+
Error error = kErrorNone;
17491745

1750-
mDelayedSender.RemoveDataRequestMessage(aDestination);
1746+
VerifyOrExit(IsAttached());
17511747

17521748
// Based on `mRequestRouteTlv` include both Network Data and Route
17531749
// TLVs or only Network Data TLV.
17541750

1755-
error = SendDataRequest(aDestination, kTlvs, mRequestRouteTlv ? 2 : 1, aDelay);
1751+
error = SendDataRequest(aDestination, kTlvs, mRequestRouteTlv ? 2 : 1);
17561752

17571753
if (IsChild() && !IsRxOnWhenIdle())
17581754
{
@@ -1764,6 +1760,7 @@ Error Mle::SendDataRequestAfterDelay(const Ip6::Address &aDestination, uint16_t
17641760
}
17651761
}
17661762

1763+
exit:
17671764
return error;
17681765
}
17691766

@@ -1773,16 +1770,15 @@ Error Mle::SendDataRequestForLinkMetricsReport(const Ip6::Address
17731770
{
17741771
static const uint8_t kTlvs[] = {Tlv::kLinkMetricsReport};
17751772

1776-
return SendDataRequest(aDestination, kTlvs, sizeof(kTlvs), /* aDelay */ 0, &aQueryInfo);
1773+
return SendDataRequest(aDestination, kTlvs, sizeof(kTlvs), &aQueryInfo);
17771774
}
17781775

17791776
Error Mle::SendDataRequest(const Ip6::Address &aDestination,
17801777
const uint8_t *aTlvs,
17811778
uint8_t aTlvsLength,
1782-
uint16_t aDelay,
17831779
const LinkMetrics::Initiator::QueryInfo *aQueryInfo)
17841780
#else
1785-
Error Mle::SendDataRequest(const Ip6::Address &aDestination, const uint8_t *aTlvs, uint8_t aTlvsLength, uint16_t aDelay)
1781+
Error Mle::SendDataRequest(const Ip6::Address &aDestination, const uint8_t *aTlvs, uint8_t aTlvsLength)
17861782
#endif
17871783
{
17881784
Error error = kErrorNone;
@@ -1798,22 +1794,14 @@ Error Mle::SendDataRequest(const Ip6::Address &aDestination, const uint8_t *aTlv
17981794
}
17991795
#endif
18001796

1801-
if (aDelay)
1802-
{
1803-
SuccessOrExit(error = message->SendAfterDelay(aDestination, aDelay));
1804-
Log(kMessageDelay, kTypeDataRequest, aDestination);
1805-
}
1806-
else
1807-
{
1808-
SuccessOrExit(error = message->AppendActiveAndPendingTimestampTlvs());
1797+
SuccessOrExit(error = message->AppendActiveAndPendingTimestampTlvs());
18091798

1810-
SuccessOrExit(error = message->SendTo(aDestination));
1811-
Log(kMessageSend, kTypeDataRequest, aDestination);
1799+
SuccessOrExit(error = message->SendTo(aDestination));
1800+
Log(kMessageSend, kTypeDataRequest, aDestination);
18121801

1813-
if (!IsRxOnWhenIdle())
1814-
{
1815-
Get<DataPollSender>().SendFastPolls(DataPollSender::kDefaultFastPolls);
1816-
}
1802+
if (!IsRxOnWhenIdle())
1803+
{
1804+
Get<DataPollSender>().SendFastPolls(DataPollSender::kDefaultFastPolls);
18171805
}
18181806

18191807
exit:
@@ -2719,8 +2707,8 @@ void Mle::HandleAdvertisement(RxInfo &aRxInfo)
27192707

27202708
if (mRetrieveNewNetworkData || IsNetworkDataNewer(leaderData))
27212709
{
2722-
delay = Random::NonCrypto::GetUint16InRange(0, kMleMaxResponseDelay);
2723-
IgnoreError(SendDataRequestAfterDelay(aRxInfo.mMessageInfo.GetPeerAddr(), delay));
2710+
delay = 1 + Random::NonCrypto::GetUint16InRange(0, kMleMaxResponseDelay);
2711+
mDelayedSender.ScheduleDataRequest(aRxInfo.mMessageInfo.GetPeerAddr(), delay);
27242712
}
27252713

27262714
aRxInfo.mClass = RxInfo::kPeerMessage;
@@ -2901,7 +2889,7 @@ Error Mle::HandleLeaderData(RxInfo &aRxInfo)
29012889

29022890
if (aRxInfo.mMessageInfo.GetSockAddr().IsMulticast())
29032891
{
2904-
delay = Random::NonCrypto::GetUint16InRange(0, kMleMaxResponseDelay);
2892+
delay = 1 + Random::NonCrypto::GetUint16InRange(0, kMleMaxResponseDelay);
29052893
}
29062894
else
29072895
{
@@ -2911,7 +2899,7 @@ Error Mle::HandleLeaderData(RxInfo &aRxInfo)
29112899
delay = 10;
29122900
}
29132901

2914-
IgnoreError(SendDataRequestAfterDelay(aRxInfo.mMessageInfo.GetPeerAddr(), delay));
2902+
mDelayedSender.ScheduleDataRequest(aRxInfo.mMessageInfo.GetPeerAddr(), delay);
29152903
}
29162904
else if (error == kErrorNone)
29172905
{
@@ -4328,100 +4316,210 @@ Mle::DelayedSender::DelayedSender(Instance &aInstance)
43284316
{
43294317
}
43304318

4331-
Error Mle::DelayedSender::SendMessage(TxMessage &aMessage, const Ip6::Address &aDestination, uint16_t aDelay)
4319+
void Mle::DelayedSender::Stop(void)
4320+
{
4321+
mTimer.Stop();
4322+
mSchedules.DequeueAndFreeAll();
4323+
}
4324+
4325+
void Mle::DelayedSender::ScheduleDataRequest(const Ip6::Address &aDestination, uint16_t aDelay)
4326+
{
4327+
VerifyOrExit(!HasMatchingSchedule(kTypeDataRequest, aDestination));
4328+
AddSchedule(kTypeDataRequest, aDestination, aDelay, nullptr, 0);
4329+
4330+
exit:
4331+
return;
4332+
}
4333+
4334+
#if OPENTHREAD_FTD
4335+
4336+
void Mle::DelayedSender::ScheduleParentResponse(const ParentResponseInfo &aInfo, uint16_t aDelay)
4337+
{
4338+
Ip6::Address destination;
4339+
4340+
destination.SetToLinkLocalAddress(aInfo.mChildExtAddress);
4341+
4342+
RemoveMatchingSchedules(kTypeParentResponse, destination);
4343+
AddSchedule(kTypeParentResponse, destination, aDelay, &aInfo, sizeof(aInfo));
4344+
}
4345+
4346+
void Mle::DelayedSender::ScheduleMulticastDataResponse(uint16_t aDelay)
4347+
{
4348+
Ip6::Address destination;
4349+
4350+
destination.SetToLinkLocalAllNodesMulticast();
4351+
4352+
Get<MeshForwarder>().RemoveDataResponseMessages();
4353+
RemoveMatchingSchedules(kTypeDataResponse, destination);
4354+
AddSchedule(kTypeDataResponse, destination, aDelay, nullptr, 0);
4355+
}
4356+
4357+
void Mle::DelayedSender::ScheduleLinkAccept(const LinkAcceptInfo &aInfo, uint16_t aDelay)
4358+
{
4359+
Ip6::Address destination;
4360+
4361+
destination.SetToLinkLocalAddress(aInfo.mExtAddress);
4362+
4363+
RemoveMatchingSchedules(kTypeLinkAccept, destination);
4364+
AddSchedule(kTypeLinkAccept, destination, aDelay, &aInfo, sizeof(aInfo));
4365+
}
4366+
4367+
void Mle::DelayedSender::ScheduleDiscoveryResponse(const Ip6::Address &aDestination,
4368+
const DiscoveryResponseInfo &aInfo,
4369+
uint16_t aDelay)
4370+
{
4371+
AddSchedule(kTypeDiscoveryResponse, aDestination, aDelay, &aInfo, sizeof(aInfo));
4372+
}
4373+
4374+
#endif // OPENTHREAD_FTD
4375+
4376+
void Mle::DelayedSender::AddSchedule(MessageType aMessageType,
4377+
const Ip6::Address &aDestination,
4378+
uint16_t aDelay,
4379+
const void *aInfo,
4380+
uint16_t aInfoSize)
43324381
{
4333-
Error error = kErrorNone;
4334-
Metadata metadata;
4382+
Schedule *schedule = Get<MessagePool>().Allocate(Message::kTypeOther);
4383+
Header header;
43354384

4336-
metadata.mSendTime = TimerMilli::GetNow() + aDelay;
4337-
metadata.mDestination = aDestination;
4385+
VerifyOrExit(schedule != nullptr);
43384386

4339-
SuccessOrExit(error = metadata.AppendTo(aMessage));
4340-
mQueue.Enqueue(aMessage);
4387+
header.mSendTime = TimerMilli::GetNow() + aDelay;
4388+
header.mDestination = aDestination;
4389+
header.mMessageType = aMessageType;
4390+
SuccessOrExit(schedule->Append(header));
43414391

4342-
mTimer.FireAtIfEarlier(metadata.mSendTime);
4392+
if (aInfo != nullptr)
4393+
{
4394+
SuccessOrExit(schedule->AppendBytes(aInfo, aInfoSize));
4395+
}
4396+
4397+
mTimer.FireAtIfEarlier(header.mSendTime);
4398+
4399+
mSchedules.Enqueue(*schedule);
4400+
schedule = nullptr;
4401+
4402+
Log(kMessageDelay, aMessageType, aDestination);
43434403

43444404
exit:
4345-
return error;
4405+
FreeMessage(schedule);
43464406
}
43474407

43484408
void Mle::DelayedSender::HandleTimer(void)
43494409
{
43504410
NextFireTime nextSendTime;
4411+
MessageQueue schedulesToExecute;
43514412

4352-
for (Message &message : mQueue)
4413+
for (Schedule &schedule : mSchedules)
43534414
{
4354-
Metadata metadata;
4415+
Header header;
43554416

4356-
metadata.ReadFrom(message);
4417+
header.ReadFrom(schedule);
43574418

4358-
if (nextSendTime.GetNow() < metadata.mSendTime)
4419+
if (nextSendTime.GetNow() < header.mSendTime)
43594420
{
4360-
nextSendTime.UpdateIfEarlier(metadata.mSendTime);
4421+
nextSendTime.UpdateIfEarlier(header.mSendTime);
43614422
}
43624423
else
43634424
{
4364-
mQueue.Dequeue(message);
4365-
Send(static_cast<TxMessage &>(message), metadata);
4425+
mSchedules.Dequeue(schedule);
4426+
schedulesToExecute.Enqueue(schedule);
43664427
}
43674428
}
43684429

43694430
mTimer.FireAt(nextSendTime);
4431+
4432+
for (Schedule &schedule : schedulesToExecute)
4433+
{
4434+
Execute(schedule);
4435+
}
4436+
4437+
schedulesToExecute.DequeueAndFreeAll();
43704438
}
43714439

4372-
void Mle::DelayedSender::Send(TxMessage &aMessage, const Metadata &aMetadata)
4440+
void Mle::DelayedSender::Execute(const Schedule &aSchedule)
43734441
{
4374-
Error error = kErrorNone;
4442+
Header header;
43754443

4376-
aMetadata.RemoveFrom(aMessage);
4444+
header.ReadFrom(aSchedule);
43774445

4378-
if (aMessage.IsMleCommand(kCommandDataRequest))
4446+
switch (header.mMessageType)
43794447
{
4380-
SuccessOrExit(error = aMessage.AppendActiveAndPendingTimestampTlvs());
4381-
}
4448+
case kTypeDataRequest:
4449+
IgnoreError(Get<Mle>().SendDataRequest(header.mDestination));
4450+
break;
4451+
4452+
#if OPENTHREAD_FTD
4453+
case kTypeParentResponse:
4454+
{
4455+
ParentResponseInfo info;
43824456

4383-
SuccessOrExit(error = aMessage.SendTo(aMetadata.mDestination));
4457+
IgnoreError(aSchedule.Read(sizeof(Header), info));
4458+
Get<MleRouter>().SendParentResponse(info);
4459+
break;
4460+
}
43844461

4385-
Log(kMessageSend, kTypeGenericDelayed, aMetadata.mDestination);
4462+
case kTypeDataResponse:
4463+
Get<MleRouter>().SendMulticastDataResponse();
4464+
break;
43864465

4387-
if (!Get<Mle>().IsRxOnWhenIdle())
4466+
case kTypeLinkAccept:
43884467
{
4389-
// Start fast poll mode, assuming enqueued msg is MLE Data Request.
4390-
// Note: Finer-grade check may be required when deciding whether or
4391-
// not to enter fast poll mode for other type of delayed message.
4468+
LinkAcceptInfo info;
43924469

4393-
Get<DataPollSender>().SendFastPolls(DataPollSender::kDefaultFastPolls);
4470+
IgnoreError(aSchedule.Read(sizeof(Header), info));
4471+
IgnoreError(Get<MleRouter>().SendLinkAccept(info));
4472+
break;
43944473
}
43954474

4396-
exit:
4397-
if (error != kErrorNone)
4475+
case kTypeDiscoveryResponse:
43984476
{
4399-
aMessage.Free();
4477+
DiscoveryResponseInfo info;
4478+
4479+
IgnoreError(aSchedule.Read(sizeof(Header), info));
4480+
IgnoreError(Get<MleRouter>().SendDiscoveryResponse(header.mDestination, info));
4481+
break;
44004482
}
4401-
}
4483+
#endif // OPENTHREAD_FTD
44024484

4403-
void Mle::DelayedSender::RemoveDataResponseMessage(void)
4404-
{
4405-
RemoveMessage(kCommandDataResponse, kTypeDataResponse, nullptr);
4485+
default:
4486+
break;
4487+
}
44064488
}
44074489

4408-
void Mle::DelayedSender::RemoveDataRequestMessage(const Ip6::Address &aDestination)
4490+
bool Mle::DelayedSender::Match(const Schedule &aSchedule, MessageType aMessageType, const Ip6::Address &aDestination)
44094491
{
4410-
RemoveMessage(kCommandDataRequest, kTypeDataRequest, &aDestination);
4492+
Header header;
4493+
4494+
header.ReadFrom(aSchedule);
4495+
4496+
return (header.mMessageType == aMessageType) && (header.mDestination == aDestination);
44114497
}
44124498

4413-
void Mle::DelayedSender::RemoveMessage(Command aCommand, MessageType aMessageType, const Ip6::Address *aDestination)
4499+
bool Mle::DelayedSender::HasMatchingSchedule(MessageType aMessageType, const Ip6::Address &aDestination) const
44144500
{
4415-
for (Message &message : mQueue)
4501+
bool hasMatching = false;
4502+
4503+
for (const Schedule &schedule : mSchedules)
44164504
{
4417-
Metadata metadata;
4505+
if (Match(schedule, aMessageType, aDestination))
4506+
{
4507+
hasMatching = true;
4508+
break;
4509+
}
4510+
}
44184511

4419-
metadata.ReadFrom(message);
4512+
return hasMatching;
4513+
}
44204514

4421-
if (message.IsMleCommand(aCommand) && ((aDestination == nullptr) || (metadata.mDestination == *aDestination)))
4515+
void Mle::DelayedSender::RemoveMatchingSchedules(MessageType aMessageType, const Ip6::Address &aDestination)
4516+
{
4517+
for (Schedule &schedule : mSchedules)
4518+
{
4519+
if (Match(schedule, aMessageType, aDestination))
44224520
{
4423-
mQueue.DequeueAndFree(message);
4424-
Log(kMessageRemoveDelayed, aMessageType, metadata.mDestination);
4521+
mSchedules.DequeueAndFree(schedule);
4522+
Log(kMessageRemoveDelayed, aMessageType, aDestination);
44254523
}
44264524
}
44274525
}
@@ -4846,11 +4944,6 @@ Error Mle::TxMessage::SendTo(const Ip6::Address &aDestination)
48464944
return error;
48474945
}
48484946

4849-
Error Mle::TxMessage::SendAfterDelay(const Ip6::Address &aDestination, uint16_t aDelay)
4850-
{
4851-
return Get<Mle>().mDelayedSender.SendMessage(*this, aDestination, aDelay);
4852-
}
4853-
48544947
#if OPENTHREAD_FTD
48554948

48564949
Error Mle::TxMessage::AppendConnectivityTlv(void)

0 commit comments

Comments
 (0)