[mesh-forwarder] collision avoidance delay mechanism (#7512)

This commit adds a new feature in `MeshForwarder` to add wait delay
after a successful frame tx to a neighbor which is expected to
forward the frame. This wait time applies before the next direct tx
to any neighbor on an FTD. This mechanism is intended to help prevent
self-interference when messages are sent to a destination that is
at least 2-hops away. This commit adds new OT build configs to
enable/disable this behavior and specify the wait interval
(default is set to 8 msec).
This commit is contained in:
Abtin Keshavarzian
2022-04-19 11:05:24 -07:00
committed by GitHub
parent 1e9f6ebd95
commit 5c8a9cb5bc
4 changed files with 86 additions and 1 deletions
+26
View File
@@ -119,6 +119,32 @@
#define OPENTHREAD_CONFIG_MAC_RETX_DELAY_MAX_BACKOFF_EXPONENT 5
#endif
/**
* @def OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE
*
* Define as 1 to enable collision avoidance delay feature, which adds a delay wait time after a successful frame tx
* to a neighbor which is expected to forward the frame. This delay is applied before the next direct frame tx (towards
* any neighbor) on an FTD.
*
* The delay interval is specified by `OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_INTERVAL` (in milliseconds).
*
*/
#ifndef OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE
#define OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE 1
#endif
/**
* @def OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_INTERVAL
*
* Specifies the collision avoidance delay interval in milliseconds. This is added after a successful frame tx to a
* neighbor that is expected to forward the frame (when `OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE` is
* enabled).
*
*/
#ifndef OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_INTERVAL
#define OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_INTERVAL 8
#endif
/**
* @def OPENTHREAD_CONFIG_MAC_RETRY_SUCCESS_HISTOGRAM_ENABLE
*
+39
View File
@@ -101,6 +101,10 @@ MeshForwarder::MeshForwarder(Instance &aInstance)
, mEnabled(false)
, mTxPaused(false)
, mSendBusy(false)
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE
, mDelayNextTx(false)
, mTxDelayTimer(aInstance, HandleTxDelayTimer)
#endif
, mScheduleTransmissionTask(aInstance, MeshForwarder::ScheduleTransmissionTask)
#if OPENTHREAD_FTD
, mIndirectSender(aInstance)
@@ -145,6 +149,11 @@ void MeshForwarder::Stop(void)
mFragmentPriorityList.Clear();
#endif
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE
mTxDelayTimer.Stop();
mDelayNextTx = false;
#endif
mEnabled = false;
mSendMessage = nullptr;
Get<Mac::Mac>().SetRxOnWhenIdle(false);
@@ -237,6 +246,20 @@ void MeshForwarder::ResumeMessageTransmissions(void)
}
}
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE
void MeshForwarder::HandleTxDelayTimer(Timer &aTimer)
{
aTimer.Get<MeshForwarder>().HandleTxDelayTimer();
}
void MeshForwarder::HandleTxDelayTimer(void)
{
mDelayNextTx = false;
mScheduleTransmissionTask.Post();
LogDebg("Tx delay timer expired");
}
#endif
void MeshForwarder::ScheduleTransmissionTask(Tasklet &aTasklet)
{
aTasklet.Get<MeshForwarder>().ScheduleTransmissionTask();
@@ -246,6 +269,10 @@ void MeshForwarder::ScheduleTransmissionTask(void)
{
VerifyOrExit(!mSendBusy && !mTxPaused);
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE
VerifyOrExit(!mDelayNextTx);
#endif
mSendMessage = PrepareNextDirectTransmission();
VerifyOrExit(mSendMessage != nullptr);
@@ -996,6 +1023,18 @@ void MeshForwarder::HandleSentFrame(Mac::TxFrame &aFrame, Error aError)
VerifyOrExit(mEnabled);
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE
if (mDelayNextTx && (aError == kErrorNone))
{
mTxDelayTimer.Start(kTxDelayInterval);
LogDebg("Start tx delay timer for %u msec", kTxDelayInterval);
}
else
{
mDelayNextTx = false;
}
#endif
if (!aFrame.IsEmpty())
{
IgnoreError(aFrame.GetDstAddr(macDest));
+11 -1
View File
@@ -334,6 +334,8 @@ private:
static constexpr uint8_t kMeshHeaderFrameMtu = OT_RADIO_FRAME_MAX_SIZE; // Max MTU with a Mesh Header frame.
static constexpr uint8_t kMeshHeaderFrameFcsSize = sizeof(uint16_t); // Frame FCS size for Mesh Header frame.
static constexpr uint32_t kTxDelayInterval = OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_INTERVAL; // In msec
enum MessageAction : uint8_t
{
kMessageReceive, // Indicates that the message was received.
@@ -503,11 +505,15 @@ private:
void PauseMessageTransmissions(void) { mTxPaused = true; }
void ResumeMessageTransmissions(void);
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE
static void HandleTxDelayTimer(Timer &aTimer);
void HandleTxDelayTimer(void);
#endif
void LogMessage(MessageAction aAction,
const Message & aMessage,
Error aError = kErrorNone,
const Mac::Address *aAddress = nullptr);
void LogFrame(const char *aActionText, const Mac::Frame &aFrame, Error aError);
void LogFragmentFrameDrop(Error aError,
uint16_t aFrameLength,
@@ -585,6 +591,10 @@ private:
bool mEnabled : 1;
bool mTxPaused : 1;
bool mSendBusy : 1;
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE
bool mDelayNextTx : 1;
TimerMilli mTxDelayTimer;
#endif
Tasklet mScheduleTransmissionTask;
+10
View File
@@ -403,6 +403,13 @@ Error MeshForwarder::UpdateMeshRoute(Message &aMessage)
mMeshDest = meshHeader.GetDestination();
mMeshSource = meshHeader.GetSource();
#if OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE
if (mMacDest.GetShort() != mMeshDest)
{
mDelayNextTx = true;
}
#endif
exit:
return error;
}
@@ -616,6 +623,9 @@ Error MeshForwarder::UpdateIp6RouteFtd(Ip6::Header &ip6Header, Message &aMessage
// destination is not neighbor
mMacSource.SetShort(mMeshSource);
mAddMeshHeader = true;
#if OPENTHREAD_CONFIG_MAC_COLLISION_AVOIDANCE_DELAY_ENABLE
mDelayNextTx = true;
#endif
}
exit: