[mesh-forwarder] finalize message direct tx on drop or eviction (#9682)

This commit adds `FinalizeMessageDirectTx()`, which clears the
`DirectTx` flag on a given message, updates the IPv6 counter, and
signals other modules about the transmission status(particularly for
`MleDiscoverRequest` and `MleChildIdRequest` messages so their
internal state can be updated).

This commit ensures `FinalizeMessageDirectTx()` is called in various
scenarios:
- Successful message delivery (all fragments reach destination).
- Any fragment transmission failure (frame tx failure)
- Message drop due to address query failure or malformed message.
- Message drop by queue management.
- Message eviction to prioritize higher-priority messages.

This commit also updates `DiscoverScanner` to stop an ongoing discover
scan if the "MLE Discover Request" message transmission fails with error
other than CSMA error. This is necessary because the `DiscoverScanner`
reuses the same `Message` instance for tx on different scan channels.
If the `Message` is freed (e.g., evicted), the `Message` cannot be
reused.

Finally, this commit renames `RemoveMessage()` to `EvictMessage()` to
clarify the purpose and usage of this method.
This commit is contained in:
Abtin Keshavarzian
2023-12-05 13:22:29 -08:00
committed by GitHub
parent 3754174c54
commit 001b01ee32
6 changed files with 67 additions and 36 deletions
+23 -10
View File
@@ -205,7 +205,7 @@ Mac::TxFrame *DiscoverScanner::PrepareDiscoveryRequestFrame(Mac::TxFrame &aFrame
return frame;
}
void DiscoverScanner::HandleDiscoveryRequestFrameTxDone(Message &aMessage)
void DiscoverScanner::HandleDiscoveryRequestFrameTxDone(Message &aMessage, Error aError)
{
switch (mState)
{
@@ -213,15 +213,28 @@ void DiscoverScanner::HandleDiscoveryRequestFrameTxDone(Message &aMessage)
break;
case kStateScanning:
// Mark the Discovery Request message for direct tx to ensure it
// is not dequeued and freed by `MeshForwarder` and is ready for
// the next scan channel. Also pause message tx on `MeshForwarder`
// while listening to receive Discovery Responses.
aMessage.SetDirectTransmission();
aMessage.SetTimestampToNow();
Get<MeshForwarder>().PauseMessageTransmissions();
mTimer.Start(kDefaultScanDuration);
break;
if ((aError == kErrorNone) || (aError == kErrorChannelAccessFailure))
{
// Mark the Discovery Request message for direct tx to ensure it
// is not dequeued and freed by `MeshForwarder` and is ready for
// the next scan channel. Also pause message tx on `MeshForwarder`
// while listening to receive Discovery Responses.
aMessage.SetDirectTransmission();
aMessage.SetTimestampToNow();
Get<MeshForwarder>().PauseMessageTransmissions();
mTimer.Start(kDefaultScanDuration);
break;
}
// If we encounter other error failures (e.g., `kErrorDrop` due
// to queue management dropping the message or if message being
// evicted), `aMessage` may be immediately freed. This prevents
// us from reusing it to request a scan on the next scan channel.
// As a result, we stop the scan operation in such cases.
mState = kStateScanDone;
OT_FALL_THROUGH;
case kStateScanDone:
HandleDiscoverComplete();
+1 -1
View File
@@ -165,7 +165,7 @@ private:
// Methods used by `MeshForwarder`
Mac::TxFrame *PrepareDiscoveryRequestFrame(Mac::TxFrame &aFrame);
void HandleDiscoveryRequestFrameTxDone(Message &aMessage);
void HandleDiscoveryRequestFrameTxDone(Message &aMessage, Error aError);
void Stop(void) { HandleDiscoverComplete(); }
// Methods used from `Mle`
+37 -22
View File
@@ -202,7 +202,7 @@ void MeshForwarder::PrepareEmptyFrame(Mac::TxFrame &aFrame, const Mac::Address &
aFrame.SetPayloadLength(0);
}
void MeshForwarder::RemoveMessage(Message &aMessage)
void MeshForwarder::EvictMessage(Message &aMessage)
{
PriorityQueue *queue = aMessage.GetPriorityQueue();
@@ -217,6 +217,8 @@ void MeshForwarder::RemoveMessage(Message &aMessage)
}
#endif
FinalizeMessageDirectTx(aMessage, kErrorNoBufs);
if (mSendMessage == &aMessage)
{
mSendMessage = nullptr;
@@ -387,7 +389,7 @@ exit:
mTxQueueStats.UpdateFor(aMessage);
#endif
LogMessage(kMessageQueueMgmtDrop, aMessage);
aMessage.ClearDirectTransmission();
FinalizeMessageDirectTx(aMessage, kErrorDrop);
RemoveMessageIfNoPendingTx(aMessage);
}
@@ -518,7 +520,7 @@ void MeshForwarder::ApplyDirectTxQueueLimit(Message &aMessage)
#endif
LogMessage(kMessageFullQueueDrop, aMessage);
aMessage.ClearDirectTransmission();
FinalizeMessageDirectTx(aMessage, kErrorDrop);
RemoveMessageIfNoPendingTx(aMessage);
exit:
@@ -642,6 +644,7 @@ Message *MeshForwarder::PrepareNextDirectTransmission(void)
mTxQueueStats.UpdateFor(*curMessage);
#endif
LogMessage(kMessageDrop, *curMessage, error);
FinalizeMessageDirectTx(*curMessage, error);
mSendQueue.DequeueAndFree(*curMessage);
continue;
}
@@ -1261,9 +1264,6 @@ void MeshForwarder::UpdateSendMessage(Error aFrameTxError, Mac::Address &aMacDes
txError = aFrameTxError;
mSendMessage->ClearDirectTransmission();
mSendMessage->SetOffset(0);
if (aNeighbor != nullptr)
{
aNeighbor->GetLinkInfo().AddMessageTxStatus(mSendMessage->GetTxSuccess());
@@ -1289,39 +1289,54 @@ void MeshForwarder::UpdateSendMessage(Error aFrameTxError, Mac::Address &aMacDes
#endif
LogMessage(kMessageTransmit, *mSendMessage, txError, &aMacDest);
FinalizeMessageDirectTx(*mSendMessage, txError);
RemoveMessageIfNoPendingTx(*mSendMessage);
if (mSendMessage->GetType() == Message::kTypeIp6)
exit:
mScheduleTransmissionTask.Post();
}
void MeshForwarder::FinalizeMessageDirectTx(Message &aMessage, Error aError)
{
// Finalizes the direct transmission of `aMessage`. This can be
// triggered by successful delivery (all fragments reaching the
// destination), failure of any fragment, queue management
// dropping the message, or eviction of message to accommodate
// higher priority messages.
VerifyOrExit(aMessage.IsDirectTransmission());
aMessage.ClearDirectTransmission();
aMessage.SetOffset(0);
if (aError != kErrorNone)
{
if (mSendMessage->GetTxSuccess())
{
mIpCounters.mTxSuccess++;
}
else
{
mIpCounters.mTxFailure++;
}
aMessage.SetTxSuccess(false);
}
switch (mSendMessage->GetSubType())
if (aMessage.GetType() == Message::kTypeIp6)
{
aMessage.GetTxSuccess() ? mIpCounters.mTxSuccess++ : mIpCounters.mTxFailure++;
}
switch (aMessage.GetSubType())
{
case Message::kSubTypeMleDiscoverRequest:
// Note that `HandleDiscoveryRequestFrameTxDone()` may update
// `mSendMessage` and mark it again for direct transmission.
Get<Mle::DiscoverScanner>().HandleDiscoveryRequestFrameTxDone(*mSendMessage);
// `aMessage` and mark it again for direct transmission.
Get<Mle::DiscoverScanner>().HandleDiscoveryRequestFrameTxDone(aMessage, aError);
break;
case Message::kSubTypeMleChildIdRequest:
Get<Mle::Mle>().HandleChildIdRequestTxDone(*mSendMessage);
Get<Mle::Mle>().HandleChildIdRequestTxDone(aMessage);
break;
default:
break;
}
RemoveMessageIfNoPendingTx(*mSendMessage);
exit:
mScheduleTransmissionTask.Post();
return;
}
bool MeshForwarder::RemoveMessageIfNoPendingTx(Message &aMessage)
+2 -1
View File
@@ -552,7 +552,7 @@ private:
Message::Priority aPriority);
Error HandleDatagram(Message &aMessage, const ThreadLinkInfo &aLinkInfo, const Mac::Address &aMacSource);
void ClearReassemblyList(void);
void RemoveMessage(Message &aMessage);
void EvictMessage(Message &aMessage);
void HandleDiscoverComplete(void);
void HandleReceivedFrame(Mac::RxFrame &aFrame);
@@ -564,6 +564,7 @@ private:
void UpdateNeighborLinkFailures(Neighbor &aNeighbor, Error aError, bool aAllowNeighborRemove, uint8_t aFailLimit);
void HandleSentFrame(Mac::TxFrame &aFrame, Error aError);
void UpdateSendMessage(Error aFrameTxError, Mac::Address &aMacDest, Neighbor *aNeighbor);
void FinalizeMessageDirectTx(Message &aMessage, Error aError);
bool RemoveMessageIfNoPendingTx(Message &aMessage);
void HandleTimeTick(void);
+3 -1
View File
@@ -165,6 +165,7 @@ void MeshForwarder::HandleResolved(const Ip6::Address &aEid, Error aError)
if (aError != kErrorNone)
{
LogMessage(kMessageDrop, message, kErrorAddressQuery);
FinalizeMessageDirectTx(message, kErrorAddressQuery);
mSendQueue.DequeueAndFree(message);
continue;
}
@@ -259,7 +260,7 @@ Error MeshForwarder::EvictMessage(Message::Priority aPriority)
exit:
if ((error == kErrorNone) && (evict != nullptr))
{
RemoveMessage(*evict);
EvictMessage(*evict);
}
return error;
@@ -342,6 +343,7 @@ void MeshForwarder::RemoveDataResponseMessages(void)
}
LogMessage(kMessageDrop, message);
FinalizeMessageDirectTx(message, kErrorDrop);
mSendQueue.DequeueAndFree(message);
}
}
+1 -1
View File
@@ -68,7 +68,7 @@ Error MeshForwarder::EvictMessage(Message::Priority aPriority)
if (message->GetPriority() < static_cast<uint8_t>(aPriority))
{
RemoveMessage(*message);
EvictMessage(*message);
ExitNow(error = kErrorNone);
}