Skip to content

Commit

Permalink
[mle] add DelayedSender class to manage delayed msg tx (openthread#…
Browse files Browse the repository at this point in the history
…10733)

This commit introduces the `DelayedSender` nested class within `Mle`
to handle delayed MLE message transmissions, such as delayed
responses. Existing methods related to delayed message handling have
been refactored into this new class.
  • Loading branch information
abtink authored Sep 25, 2024
1 parent 3913e0d commit b42be4c
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 120 deletions.
213 changes: 113 additions & 100 deletions src/core/thread/mle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,12 @@ Mle::Mle(Instance &aInstance)
#endif
, mAlternateTimestamp(0)
, mNeighborTable(aInstance)
, mDelayedSender(aInstance)
, mSocket(aInstance, *this)
#if OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE
, mParentSearch(aInstance)
#endif
, mAttachTimer(aInstance)
, mDelayedResponseTimer(aInstance)
, mMessageTransmissionTimer(aInstance)
, mDetachGracefullyTimer(aInstance)
{
Expand Down Expand Up @@ -1563,88 +1563,6 @@ uint32_t Mle::Reattach(void)
return delay;
}

void Mle::HandleDelayedResponseTimer(void)
{
NextFireTime nextSendTime;

for (Message &message : mDelayedResponses)
{
DelayedResponseMetadata metadata;

metadata.ReadFrom(message);

if (nextSendTime.GetNow() < metadata.mSendTime)
{
nextSendTime.UpdateIfEarlier(metadata.mSendTime);
}
else
{
mDelayedResponses.Dequeue(message);
SendDelayedResponse(static_cast<TxMessage &>(message), metadata);
}
}

mDelayedResponseTimer.FireAt(nextSendTime);
}

void Mle::SendDelayedResponse(TxMessage &aMessage, const DelayedResponseMetadata &aMetadata)
{
Error error = kErrorNone;

aMetadata.RemoveFrom(aMessage);

if (aMessage.GetSubType() == Message::kSubTypeMleDataRequest)
{
SuccessOrExit(error = aMessage.AppendActiveAndPendingTimestampTlvs());
}

SuccessOrExit(error = aMessage.SendTo(aMetadata.mDestination));

Log(kMessageSend, kTypeGenericDelayed, aMetadata.mDestination);

if (!IsRxOnWhenIdle())
{
// Start fast poll mode, assuming enqueued msg is MLE Data Request.
// Note: Finer-grade check may be required when deciding whether or
// not to enter fast poll mode for other type of delayed message.

Get<DataPollSender>().SendFastPolls(DataPollSender::kDefaultFastPolls);
}

exit:
if (error != kErrorNone)
{
aMessage.Free();
}
}

void Mle::RemoveDelayedDataResponseMessage(void)
{
RemoveDelayedMessage(Message::kSubTypeMleDataResponse, kTypeDataResponse, nullptr);
}

void Mle::RemoveDelayedDataRequestMessage(const Ip6::Address &aDestination)
{
RemoveDelayedMessage(Message::kSubTypeMleDataRequest, kTypeDataRequest, &aDestination);
}

void Mle::RemoveDelayedMessage(Message::SubType aSubType, MessageType aMessageType, const Ip6::Address *aDestination)
{
for (Message &message : mDelayedResponses)
{
DelayedResponseMetadata metadata;

metadata.ReadFrom(message);

if ((message.GetSubType() == aSubType) &&
((aDestination == nullptr) || (metadata.mDestination == *aDestination)))
{
mDelayedResponses.DequeueAndFree(message);
Log(kMessageRemoveDelayed, aMessageType, metadata.mDestination);
}
}
}

void Mle::SendParentRequest(ParentRequestType aType)
{
Error error = kErrorNone;
Expand Down Expand Up @@ -1821,7 +1739,7 @@ Error Mle::SendDataRequest(const Ip6::Address &aDestination, const uint8_t *aTlv
Error error = kErrorNone;
TxMessage *message;

RemoveDelayedDataRequestMessage(aDestination);
mDelayedSender.RemoveDataRequestMessage(aDestination);

VerifyOrExit((message = NewMleMessage(kCommandDataRequest)) != nullptr, error = kErrorNoBufs);
SuccessOrExit(error = message->AppendTlvRequestTlv(aTlvs, aTlvsLength));
Expand Down Expand Up @@ -4386,17 +4304,124 @@ void Mle::TlvList::AddElementsFrom(const TlvList &aTlvList)
}

//---------------------------------------------------------------------------------------------------------------------
// DelayedResponseMetadata
// DelayedSender

void Mle::DelayedResponseMetadata::ReadFrom(const Message &aMessage)
Mle::DelayedSender::DelayedSender(Instance &aInstance)
: InstanceLocator(aInstance)
, mTimer(aInstance)
{
}

Error Mle::DelayedSender::SendMessage(TxMessage &aMessage, const Ip6::Address &aDestination, uint16_t aDelay)
{
Error error = kErrorNone;
Metadata metadata;

metadata.mSendTime = TimerMilli::GetNow() + aDelay;
metadata.mDestination = aDestination;

SuccessOrExit(error = metadata.AppendTo(aMessage));
mQueue.Enqueue(aMessage);

mTimer.FireAtIfEarlier(metadata.mSendTime);

exit:
return error;
}

void Mle::DelayedSender::HandleTimer(void)
{
NextFireTime nextSendTime;

for (Message &message : mQueue)
{
Metadata metadata;

metadata.ReadFrom(message);

if (nextSendTime.GetNow() < metadata.mSendTime)
{
nextSendTime.UpdateIfEarlier(metadata.mSendTime);
}
else
{
mQueue.Dequeue(message);
Send(static_cast<TxMessage &>(message), metadata);
}
}

mTimer.FireAt(nextSendTime);
}

void Mle::DelayedSender::Send(TxMessage &aMessage, const Metadata &aMetadata)
{
Error error = kErrorNone;

aMetadata.RemoveFrom(aMessage);

if (aMessage.GetSubType() == Message::kSubTypeMleDataRequest)
{
SuccessOrExit(error = aMessage.AppendActiveAndPendingTimestampTlvs());
}

SuccessOrExit(error = aMessage.SendTo(aMetadata.mDestination));

Log(kMessageSend, kTypeGenericDelayed, aMetadata.mDestination);

if (!Get<Mle>().IsRxOnWhenIdle())
{
// Start fast poll mode, assuming enqueued msg is MLE Data Request.
// Note: Finer-grade check may be required when deciding whether or
// not to enter fast poll mode for other type of delayed message.

Get<DataPollSender>().SendFastPolls(DataPollSender::kDefaultFastPolls);
}

exit:
if (error != kErrorNone)
{
aMessage.Free();
}
}

void Mle::DelayedSender::RemoveDataResponseMessage(void)
{
RemoveMessage(Message::kSubTypeMleDataResponse, kTypeDataResponse, nullptr);
}

void Mle::DelayedSender::RemoveDataRequestMessage(const Ip6::Address &aDestination)
{
RemoveMessage(Message::kSubTypeMleDataRequest, kTypeDataRequest, &aDestination);
}

void Mle::DelayedSender::RemoveMessage(Message::SubType aSubType,
MessageType aMessageType,
const Ip6::Address *aDestination)
{
for (Message &message : mQueue)
{
Metadata metadata;

metadata.ReadFrom(message);

if ((message.GetSubType() == aSubType) &&
((aDestination == nullptr) || (metadata.mDestination == *aDestination)))
{
mQueue.DequeueAndFree(message);
Log(kMessageRemoveDelayed, aMessageType, metadata.mDestination);
}
}
}

void Mle::DelayedSender::Metadata::ReadFrom(const Message &aMessage)
{
uint16_t length = aMessage.GetLength();

OT_ASSERT(length >= sizeof(*this));
IgnoreError(aMessage.Read(length - sizeof(*this), *this));
}

void Mle::DelayedResponseMetadata::RemoveFrom(Message &aMessage) const { aMessage.RemoveFooter(sizeof(*this)); }
void Mle::DelayedSender::Metadata::RemoveFrom(Message &aMessage) const { aMessage.RemoveFooter(sizeof(*this)); }

//---------------------------------------------------------------------------------------------------------------------
// TxMessage
Expand Down Expand Up @@ -4852,19 +4877,7 @@ Error Mle::TxMessage::SendTo(const Ip6::Address &aDestination)

Error Mle::TxMessage::SendAfterDelay(const Ip6::Address &aDestination, uint16_t aDelay)
{
Error error = kErrorNone;
DelayedResponseMetadata metadata;

metadata.mSendTime = TimerMilli::GetNow() + aDelay;
metadata.mDestination = aDestination;

SuccessOrExit(error = metadata.AppendTo(*this));
Get<Mle>().mDelayedResponses.Enqueue(*this);

Get<Mle>().mDelayedResponseTimer.FireAtIfEarlier(metadata.mSendTime);

exit:
return error;
return Get<Mle>().mDelayedSender.SendMessage(*this, aDestination, aDelay);
}

#if OPENTHREAD_FTD
Expand Down
51 changes: 32 additions & 19 deletions src/core/thread/mle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -586,12 +586,7 @@ class Mle : public InstanceLocator, private NonCopyable
*
* @returns A reference to the send queue.
*/
const MessageQueue &GetMessageQueue(void) const { return mDelayedResponses; }

/**
* Frees multicast MLE Data Response from Delayed Message Queue if any.
*/
void RemoveDelayedDataResponseMessage(void);
const MessageQueue &GetMessageQueue(void) const { return mDelayedSender.GetQueue(); }

/**
* Gets the MLE counters.
Expand Down Expand Up @@ -1093,14 +1088,38 @@ class Mle : public InstanceLocator, private NonCopyable

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

struct DelayedResponseMetadata
void HandleDelayedSenderTimer(void) { mDelayedSender.HandleTimer(); }

class DelayedSender : public InstanceLocator
{
Error AppendTo(Message &aMessage) const { return aMessage.Append(*this); }
void ReadFrom(const Message &aMessage);
void RemoveFrom(Message &aMessage) const;
public:
explicit DelayedSender(Instance &aInstance);

Error SendMessage(TxMessage &aMessage, const Ip6::Address &aDestination, uint16_t aDelay);
void RemoveDataRequestMessage(const Ip6::Address &aDestination);
void RemoveDataResponseMessage(void);
void HandleTimer(void);

const MessageQueue &GetQueue(void) const { return mQueue; }

private:
struct Metadata
{
Error AppendTo(Message &aMessage) const { return aMessage.Append(*this); }
void ReadFrom(const Message &aMessage);
void RemoveFrom(Message &aMessage) const;

Ip6::Address mDestination;
TimeMilli mSendTime;
};

void Send(TxMessage &aMessage, const Metadata &aMetadata);
void RemoveMessage(Message::SubType aSubType, MessageType aMessageType, const Ip6::Address *aDestination);

using DelayTimer = TimerMilliIn<Mle, &Mle::HandleDelayedSenderTimer>;

Ip6::Address mDestination; // IPv6 address of the message destination.
TimeMilli mSendTime; // Time when the message shall be sent.
MessageQueue mQueue;
DelayTimer mTimer;
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Expand Down Expand Up @@ -1223,7 +1242,6 @@ class Mle : public InstanceLocator, private NonCopyable
void ClearParentCandidate(void) { mParentCandidate.Clear(); }
Error SendDataRequest(const Ip6::Address &aDestination);
void HandleNotifierEvents(Events aEvents);
void SendDelayedResponse(TxMessage &aMessage, const DelayedResponseMetadata &aMetadata);
void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
void ReestablishLinkWithNeighbor(Neighbor &aNeighbor);
void HandleDetachGracefullyTimer(void);
Expand All @@ -1243,7 +1261,6 @@ class Mle : public InstanceLocator, private NonCopyable
bool IsAnnounceAttach(void) const { return mAlternatePanId != Mac::kPanIdBroadcast; }
void ScheduleMessageTransmissionTimer(void);
void HandleAttachTimer(void);
void HandleDelayedResponseTimer(void);
void HandleMessageTransmissionTimer(void);
void ProcessKeySequence(RxInfo &aRxInfo);
void HandleAdvertisement(RxInfo &aRxInfo);
Expand Down Expand Up @@ -1280,8 +1297,6 @@ class Mle : public InstanceLocator, private NonCopyable
const Ip6::MessageInfo &aMessageInfo,
uint16_t aCmdOffset,
const SecurityHeader &aHeader);
void RemoveDelayedMessage(Message::SubType aSubType, MessageType aMessageType, const Ip6::Address *aDestination);
void RemoveDelayedDataRequestMessage(const Ip6::Address &aDestination);

#if OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH
void InformPreviousParent(void);
Expand Down Expand Up @@ -1352,7 +1367,6 @@ class Mle : public InstanceLocator, private NonCopyable

using DetachGracefullyTimer = TimerMilliIn<Mle, &Mle::HandleDetachGracefullyTimer>;
using AttachTimer = TimerMilliIn<Mle, &Mle::HandleAttachTimer>;
using DelayTimer = TimerMilliIn<Mle, &Mle::HandleDelayedResponseTimer>;
using MsgTxTimer = TimerMilliIn<Mle, &Mle::HandleMessageTransmissionTimer>;
using MleSocket = Ip6::Udp::SocketIn<Mle, &Mle::HandleUdpReceive>;

Expand Down Expand Up @@ -1402,7 +1416,7 @@ class Mle : public InstanceLocator, private NonCopyable
LeaderData mLeaderData;
Parent mParent;
NeighborTable mNeighborTable;
MessageQueue mDelayedResponses;
DelayedSender mDelayedSender;
TxChallenge mParentRequestChallenge;
ParentCandidate mParentCandidate;
MleSocket mSocket;
Expand All @@ -1418,7 +1432,6 @@ class Mle : public InstanceLocator, private NonCopyable
Callback<otThreadParentResponseCallback> mParentResponseCallback;
#endif
AttachTimer mAttachTimer;
DelayTimer mDelayedResponseTimer;
MsgTxTimer mMessageTransmissionTimer;
DetachGracefullyTimer mDetachGracefullyTimer;
Ip6::NetworkPrefix mMeshLocalPrefix;
Expand Down
2 changes: 1 addition & 1 deletion src/core/thread/mle_router.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3116,7 +3116,7 @@ void MleRouter::SendDataResponse(const Ip6::Address &aDestination,
{
Get<MeshForwarder>().RemoveDataResponseMessages();

RemoveDelayedDataResponseMessage();
mDelayedSender.RemoveDataResponseMessage();

SuccessOrExit(error = message->SendAfterDelay(aDestination, aDelay));
Log(kMessageDelay, kTypeDataResponse, aDestination);
Expand Down

0 comments on commit b42be4c

Please sign in to comment.