mirror of
https://github.com/espressif/openthread.git
synced 2026-07-27 14:27:47 +00:00
[mle] Periodic Parent Search feature (#2330)
This commit implements a "Periodic Parent Search" feature in MLE. This feature is disabled by default and can be enabled through `OPENTHREAD_CONFIG_ENABLE_PERIODIC_PARENT_SEARCH` configuration option. When enabled, an end-device/child (while staying attached) will periodically search for a possible better parent and will switch if it finds a better one. The child will periodically check the average RSS value for the current parent, and only if it is below a specific threshold, a parent search is performed. Since the parent search process can be power consuming (child needs to stays in RX mode to collect parent response) and to limit its impact on battery-powered devices, after a parent search is triggered, the child will not trigger another one before a specified longer backoff interval. The check and backoff intervals along with the RSS threshold used to trigger the parent search can be set from a set of configuration options.
This commit is contained in:
committed by
Jonathan Hui
parent
0097c403bc
commit
fc170d85fd
@@ -970,6 +970,64 @@
|
||||
#define OPENTHREAD_CONFIG_INFORM_PREVIOUS_PARENT_ON_REATTACH 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_ENABLE_PERIODIC_PARENT_SEARCH
|
||||
*
|
||||
* Define as 1 to enable periodic parent search feature.
|
||||
*
|
||||
* When this feature is enabled an end-device/child (while staying attached) will periodically search for a possible
|
||||
* better parent and will switch parent if a better one is found.
|
||||
*
|
||||
* The child will periodically check the average RSS value for the current parent, and only if it is below a specific
|
||||
* threshold, a parent search is performed. The `OPENTHREAD_CONFIG_PARENT_SEARCH_CHECK_INTERVAL` specifies the the
|
||||
* check interval (in seconds) and `OPENTHREAD_CONFIG_PARENT_SEARCH_RSS_THRESHOLD` gives the RSS threshold.
|
||||
*
|
||||
* Since the parent search process can be power consuming (child needs to stays in RX mode to collect parent response)
|
||||
* and to limit its impact on battery-powered devices, after a parent search is triggered, the child will not trigger
|
||||
* another one before a specified backoff interval specified by `OPENTHREAD_CONFIG_PARENT_SEARCH_BACKOFF_INTERVAL`
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_ENABLE_PERIODIC_PARENT_SEARCH
|
||||
#define OPENTHREAD_CONFIG_ENABLE_PERIODIC_PARENT_SEARCH 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_PARENT_SEARCH_CHECK_INTERVAL
|
||||
*
|
||||
* Specifies the interval in seconds for a child to check the trigger condition to perform a parent search.
|
||||
*
|
||||
* Applicable only if periodic parent search feature is enabled (see `OPENTHREAD_CONFIG_ENABLE_PERIODIC_PARENT_SEARCH`).
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_PARENT_SEARCH_CHECK_INTERVAL
|
||||
#define OPENTHREAD_CONFIG_PARENT_SEARCH_CHECK_INTERVAL (9 * 60)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_PARENT_SEARCH_BACKOFF_INTERVAL
|
||||
*
|
||||
* Specifies the backoff interval in seconds for a child to not perform a parent search after triggering one.
|
||||
*
|
||||
* Applicable only if periodic parent search feature is enabled (see `OPENTHREAD_CONFIG_ENABLE_PERIODIC_PARENT_SEARCH`).
|
||||
*
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_PARENT_SEARCH_BACKOFF_INTERVAL
|
||||
#define OPENTHREAD_CONFIG_PARENT_SEARCH_BACKOFF_INTERVAL (10* 60 * 60)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_PARENT_SEARCH_RSS_THRESHOLD
|
||||
*
|
||||
* Specifies the RSS threshold used to trigger a parent search.
|
||||
*
|
||||
* Applicable only if periodic parent search feature is enabled (see `OPENTHREAD_CONFIG_ENABLE_PERIODIC_PARENT_SEARCH`).
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_PARENT_SEARCH_RSS_THRESHOLD
|
||||
#define OPENTHREAD_CONFIG_PARENT_SEARCH_RSS_THRESHOLD -65
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
|
||||
*
|
||||
|
||||
@@ -93,6 +93,13 @@ Mle::Mle(Instance &aInstance) :
|
||||
mEnableEui64Filtering(false),
|
||||
#if OPENTHREAD_CONFIG_INFORM_PREVIOUS_PARENT_ON_REATTACH
|
||||
mPreviousParentRloc(Mac::kShortAddrInvalid),
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_ENABLE_PERIODIC_PARENT_SEARCH
|
||||
mParentSearchIsInBackoff(false),
|
||||
mParentSearchBackoffWasCanceled(false),
|
||||
mParentSearchRecentlyDetached(false),
|
||||
mParentSearchBackoffCancelTime(0),
|
||||
mParentSearchTimer(aInstance, &Mle::HandleParentSearchTimer, this),
|
||||
#endif
|
||||
mAnnounceChannel(OT_RADIO_CHANNEL_MIN),
|
||||
mPreviousChannel(0),
|
||||
@@ -194,6 +201,10 @@ Mle::Mle(Instance &aInstance) :
|
||||
|
||||
mNetifCallback.Set(&Mle::HandleNetifStateChanged, this);
|
||||
GetNetif().RegisterCallback(mNetifCallback);
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_PERIODIC_PARENT_SEARCH
|
||||
StartParentSearchTimer();
|
||||
#endif
|
||||
}
|
||||
|
||||
otError Mle::Enable(void)
|
||||
@@ -501,6 +512,10 @@ otError Mle::BecomeDetached(void)
|
||||
netif.GetPendingDataset().HandleDetach();
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_PERIODIC_PARENT_SEARCH
|
||||
mParentSearchRecentlyDetached = true;
|
||||
#endif
|
||||
|
||||
SetStateDetached();
|
||||
mParent.SetState(Neighbor::kStateInvalid);
|
||||
SetRloc16(Mac::kShortAddrInvalid);
|
||||
@@ -636,6 +651,10 @@ otError Mle::SetStateChild(uint16_t aRloc16)
|
||||
netif.GetAnnounceBeginServer().SendAnnounce(1 << mPreviousChannel);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_PERIODIC_PARENT_SEARCH
|
||||
UpdateParentSearchState();
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_INFORM_PREVIOUS_PARENT_ON_REATTACH
|
||||
InformPreviousParent();
|
||||
mPreviousParentRloc = mParent.GetRloc16();
|
||||
@@ -3446,6 +3465,115 @@ exit:
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_INFORM_PREVIOUS_PARENT_ON_REATTACH
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_PERIODIC_PARENT_SEARCH
|
||||
void Mle::HandleParentSearchTimer(Timer &aTimer)
|
||||
{
|
||||
aTimer.GetOwner<Mle>().HandleParentSearchTimer();
|
||||
}
|
||||
|
||||
void Mle::HandleParentSearchTimer(void)
|
||||
{
|
||||
int8_t parentRss;
|
||||
|
||||
otLogInfoMle(GetInstance(), "PeriodicParentSearch: %s interval passed",
|
||||
mParentSearchIsInBackoff ? "Backoff" : "Check");
|
||||
|
||||
if (mParentSearchBackoffWasCanceled)
|
||||
{
|
||||
// Backoff can be canceled if the device switches to a new parent.
|
||||
// from `UpdateParentSearchState()`. We want to limit this to happen
|
||||
// only once within a backoff interval.
|
||||
|
||||
if (TimerMilli::GetNow() - mParentSearchBackoffCancelTime >= kParentSearchBackoffInterval)
|
||||
{
|
||||
mParentSearchBackoffWasCanceled = false;
|
||||
otLogInfoMle(GetInstance(), "PeriodicParentSearch: Backoff cancellation is allowed on parent switch");
|
||||
}
|
||||
}
|
||||
|
||||
mParentSearchIsInBackoff = false;
|
||||
|
||||
VerifyOrExit(mRole == OT_DEVICE_ROLE_CHILD);
|
||||
|
||||
parentRss = GetParent()->GetLinkInfo().GetAverageRss();
|
||||
otLogInfoMle(GetInstance(), "PeriodicParentSearch: Parent RSS %d", parentRss);
|
||||
VerifyOrExit(parentRss != OT_RADIO_RSSI_INVALID);
|
||||
|
||||
if (parentRss < kParentSearchRssThreadhold)
|
||||
{
|
||||
otLogInfoMle(GetInstance(), "PeriodicParentSearch: Parent RSS less than %d, searching for new parents",
|
||||
kParentSearchRssThreadhold);
|
||||
mParentSearchIsInBackoff = true;
|
||||
BecomeChild(kAttachAny);
|
||||
}
|
||||
|
||||
exit:
|
||||
StartParentSearchTimer();
|
||||
}
|
||||
|
||||
void Mle::StartParentSearchTimer(void)
|
||||
{
|
||||
uint32_t interval;
|
||||
|
||||
interval = (otPlatRandomGet() % kParentSearchJitterInterval);
|
||||
|
||||
if (mParentSearchIsInBackoff)
|
||||
{
|
||||
interval += kParentSearchBackoffInterval;
|
||||
}
|
||||
else
|
||||
{
|
||||
interval += kParentSearchCheckInterval;
|
||||
}
|
||||
|
||||
mParentSearchTimer.Start(interval);
|
||||
|
||||
otLogInfoMle(GetInstance(), "PeriodicParentSearch: (Re)starting timer for %s interval",
|
||||
mParentSearchIsInBackoff ? "backoff" : "check");
|
||||
|
||||
}
|
||||
|
||||
void Mle::UpdateParentSearchState(void)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_INFORM_PREVIOUS_PARENT_ON_REATTACH
|
||||
|
||||
// If we are in middle of backoff and backoff was not canceled
|
||||
// recently and we recently detached from a previous parent,
|
||||
// then we check if the new parent is different from the previous
|
||||
// one, and if so, we cancel the backoff mode and also remember
|
||||
// the backoff cancel time. This way the canceling of backoff
|
||||
// is allowed only once within a backoff window.
|
||||
//
|
||||
// The reason behind the canceling of the backoff is to handle
|
||||
// the scenario where a previous parent is not available for a
|
||||
// short duration (e.g., it is going through a software update)
|
||||
// and the child switches to a less desirable parent. With this
|
||||
// model the child will check for other parents sooner and have
|
||||
// the chance to switch back to the original (and possibly
|
||||
// preferred) parent more quickly.
|
||||
|
||||
if (mParentSearchIsInBackoff && !mParentSearchBackoffWasCanceled && mParentSearchRecentlyDetached)
|
||||
{
|
||||
if ((mPreviousParentRloc != Mac::kShortAddrInvalid) && (mPreviousParentRloc != mParent.GetRloc16()))
|
||||
{
|
||||
mParentSearchIsInBackoff = false;
|
||||
mParentSearchBackoffWasCanceled = true;
|
||||
mParentSearchBackoffCancelTime = TimerMilli::GetNow();
|
||||
otLogInfoMle(GetInstance(), "PeriodicParentSearch: Canceling backoff on switching to a new parent");
|
||||
}
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_INFORM_PREVIOUS_PARENT_ON_REATTACH
|
||||
|
||||
mParentSearchRecentlyDetached = false;
|
||||
|
||||
if (!mParentSearchIsInBackoff)
|
||||
{
|
||||
StartParentSearchTimer();
|
||||
}
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_PERIODIC_PARENT_SEARCH
|
||||
|
||||
void Mle::LogMleMessage(const char *aLogString, const Ip6::Address &aAddress) const
|
||||
{
|
||||
#if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && (OPENTHREAD_CONFIG_LOG_MLE == 1)
|
||||
|
||||
@@ -1405,6 +1405,17 @@ private:
|
||||
kMleHopLimit = 255,
|
||||
};
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_PERIODIC_PARENT_SEARCH
|
||||
enum
|
||||
{
|
||||
// All timer intervals are converted to milliseconds
|
||||
kParentSearchCheckInterval = (OPENTHREAD_CONFIG_PARENT_SEARCH_CHECK_INTERVAL * 1000u),
|
||||
kParentSearchBackoffInterval = (OPENTHREAD_CONFIG_PARENT_SEARCH_BACKOFF_INTERVAL * 1000u),
|
||||
kParentSearchJitterInterval = (15 * 1000u),
|
||||
kParentSearchRssThreadhold = OPENTHREAD_CONFIG_PARENT_SEARCH_RSS_THRESHOLD,
|
||||
};
|
||||
#endif
|
||||
|
||||
void GenerateNonce(const Mac::ExtAddress &aMacAddr, uint32_t aFrameCounter, uint8_t aSecurityLevel,
|
||||
uint8_t *aNonce);
|
||||
|
||||
@@ -1452,6 +1463,13 @@ private:
|
||||
otError InformPreviousParent(void);
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_PERIODIC_PARENT_SEARCH
|
||||
static void HandleParentSearchTimer(Timer &aTimer);
|
||||
void HandleParentSearchTimer(void);
|
||||
void StartParentSearchTimer(void);
|
||||
void UpdateParentSearchState(void);
|
||||
#endif
|
||||
|
||||
MessageQueue mDelayedResponses;
|
||||
|
||||
struct
|
||||
@@ -1492,6 +1510,14 @@ private:
|
||||
uint16_t mPreviousParentRloc;
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_PERIODIC_PARENT_SEARCH
|
||||
bool mParentSearchIsInBackoff : 1;
|
||||
bool mParentSearchBackoffWasCanceled : 1;
|
||||
bool mParentSearchRecentlyDetached : 1;
|
||||
uint32_t mParentSearchBackoffCancelTime;
|
||||
TimerMilli mParentSearchTimer;
|
||||
#endif
|
||||
|
||||
uint8_t mAnnounceChannel;
|
||||
uint8_t mPreviousChannel;
|
||||
uint16_t mPreviousPanId;
|
||||
|
||||
Reference in New Issue
Block a user