[netdata] wait for sync before accepting new data on leader restart (#7838)

This commit adds a new mechanism related to Network Data recovery on
leader after restart. We determine whether device is starting normally
as leader or restoring its role as leader after restart. In the
latter case, we do not allow the device to accept any new Network Data
registrations until it has successfully recovered the Network Data
(received MLE Data Response).

This change help address situation where Network Data entries
registered with leader before it syncs and restores the Network Data
can be removed and then take a while to be re-registered.
This commit is contained in:
Abtin Keshavarzian
2022-06-30 09:49:27 -07:00
committed by GitHub
parent 3b0a876b24
commit 0132362815
6 changed files with 56 additions and 11 deletions
+4 -4
View File
@@ -269,7 +269,7 @@ Error MleRouter::BecomeLeader(void)
Get<NetworkData::Leader>().Reset();
Get<MeshCoP::Leader>().SetEmptyCommissionerData();
SetStateLeader(Rloc16FromRouterId(leaderId));
SetStateLeader(Rloc16FromRouterId(leaderId), kStartingAsLeader);
exit:
return error;
@@ -401,7 +401,7 @@ void MleRouter::SetStateRouter(uint16_t aRloc16)
}
}
void MleRouter::SetStateLeader(uint16_t aRloc16)
void MleRouter::SetStateLeader(uint16_t aRloc16, LeaderStartMode aStartMode)
{
IgnoreError(Get<MeshCoP::ActiveDatasetManager>().Restore());
IgnoreError(Get<MeshCoP::PendingDatasetManager>().Restore());
@@ -421,7 +421,7 @@ void MleRouter::SetStateLeader(uint16_t aRloc16)
mPreviousPartitionIdRouter = mLeaderData.GetPartitionId();
Get<TimeTicker>().RegisterReceiver(TimeTicker::kMleRouter);
Get<NetworkData::Leader>().Start();
Get<NetworkData::Leader>().Start(aStartMode);
Get<MeshCoP::ActiveDatasetManager>().StartLeader();
Get<MeshCoP::PendingDatasetManager>().StartLeader();
Get<Tmf::Agent>().AddResource(mAddressSolicit);
@@ -938,7 +938,7 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest)
if (mLeaderData.GetLeaderRouterId() == RouterIdFromRloc16(GetRloc16()))
{
SetStateLeader(GetRloc16());
SetStateLeader(GetRloc16(), kRestoringLeaderRoleAfterReset);
}
else
{
+1 -1
View File
@@ -635,7 +635,7 @@ private:
const Message * aRequestMessage = nullptr);
Error SendDiscoveryResponse(const Ip6::Address &aDestination, const Message &aDiscoverRequestMessage);
void SetStateRouter(uint16_t aRloc16);
void SetStateLeader(uint16_t aRloc16);
void SetStateLeader(uint16_t aRloc16, LeaderStartMode aStartMode);
void StopLeader(void);
void SynchronizeChildNetworkData(void);
Error UpdateChildAddresses(const Message &aMessage, uint16_t aOffset, Child &aChild);
+12
View File
@@ -218,6 +218,18 @@ constexpr uint16_t kAloc16NeighborDiscoveryAgentEnd = 0xfc4e;
constexpr uint8_t kServiceMinId = 0x00; ///< Minimal Service ID.
constexpr uint8_t kServiceMaxId = 0x0f; ///< Maximal Service ID.
/**
* This enumeration specifies the leader role start mode.
*
* The start mode indicates whether device is starting normally as leader or restoring its role after reset.
*
*/
enum LeaderStartMode : uint8_t
{
kStartingAsLeader, ///< Starting as leader normally.
kRestoringLeaderRoleAfterReset, ///< Restoring leader role after reset.
};
#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
/*
+1 -2
View File
@@ -394,10 +394,9 @@ Error LeaderBase::SetNetworkData(uint8_t aVersion,
}
#if OPENTHREAD_FTD
// Synchronize internal 6LoWPAN Context ID Set with recently obtained Network Data.
if (Get<Mle::MleRouter>().IsLeader())
{
Get<Leader>().UpdateContextsAfterReset();
Get<Leader>().HandleNetworkDataRestoredAfterReset();
}
#endif
+27 -2
View File
@@ -60,6 +60,7 @@ RegisterLogModule("NetworkData");
Leader::Leader(Instance &aInstance)
: LeaderBase(aInstance)
, mWaitingForNetDataSync(false)
, mTimer(aInstance, Leader::HandleTimer)
, mServerData(UriPath::kServerData, &Leader::HandleServerData, this)
, mCommissioningDataGet(UriPath::kCommissionerGet, &Leader::HandleCommissioningGet, this)
@@ -77,8 +78,15 @@ void Leader::Reset(void)
mContextIdReuseDelay = kContextIdReuseDelay;
}
void Leader::Start(void)
void Leader::Start(Mle::LeaderStartMode aStartMode)
{
mWaitingForNetDataSync = (aStartMode == Mle::kRestoringLeaderRoleAfterReset);
if (mWaitingForNetDataSync)
{
mTimer.Start(kMaxNetDataSyncWait);
}
Get<Tmf::Agent>().AddResource(mServerData);
Get<Tmf::Agent>().AddResource(mCommissioningDataGet);
Get<Tmf::Agent>().AddResource(mCommissioningDataSet);
@@ -146,6 +154,8 @@ void Leader::HandleServerData(Coap::Message &aMessage, const Ip6::MessageInfo &a
LogInfo("Received network data registration");
VerifyOrExit(!mWaitingForNetDataSync);
VerifyOrExit(aMessageInfo.GetPeerAddr().GetIid().IsRoutingLocator());
switch (Tlv::Find<ThreadRloc16Tlv>(aMessage, rloc16))
@@ -1296,11 +1306,16 @@ void Leader::RemoveContext(PrefixTlv &aPrefix, uint8_t aContextId)
}
}
void Leader::UpdateContextsAfterReset(void)
void Leader::HandleNetworkDataRestoredAfterReset(void)
{
const PrefixTlv *prefix;
TlvIterator tlvIterator(GetTlvsStart(), GetTlvsEnd());
mWaitingForNetDataSync = false;
// Synchronize internal 6LoWPAN Context ID Set with the
// recently obtained Network Data.
while ((prefix = tlvIterator.Iterate<PrefixTlv>()) != nullptr)
{
const ContextTlv *context = prefix->FindSubTlv<ContextTlv>();
@@ -1332,6 +1347,13 @@ void Leader::HandleTimer(void)
{
bool contextsWaiting = false;
if (mWaitingForNetDataSync)
{
LogInfo("Timed out waiting for netdata on restoring leader role after reset");
IgnoreError(Get<Mle::MleRouter>().BecomeDetached());
ExitNow();
}
for (uint8_t i = 0; i < kNumContextIds; i++)
{
if (mContextLastUsed[i].GetValue() == 0)
@@ -1353,6 +1375,9 @@ void Leader::HandleTimer(void)
{
mTimer.Start(kStateUpdatePeriod);
}
exit:
return;
}
Error Leader::RemoveStaleChildEntries(Coap::ResponseHandler aHandler, void *aContext)
+11 -2
View File
@@ -95,8 +95,15 @@ public:
/**
* This method starts the Leader services.
*
* The start mode indicates whether device is starting normally as leader or restoring its role as leader after
* reset. In the latter case, we do not accept any new registrations (`HandleServerData()`) and wait for
* `HandleNetworkDataRestoredAfterReset()` to indicate that the leader has successfully recovered the Network Data
* before allowing new Network Data registrations.
*
* @param[in] aStartMode The start mode.
*
*/
void Start(void);
void Start(Mle::LeaderStartMode aStartMode);
/**
* This method stops the Leader services.
@@ -149,7 +156,7 @@ public:
* Note that this method should be called only by the Leader once after reset.
*
*/
void UpdateContextsAfterReset(void);
void HandleNetworkDataRestoredAfterReset(void);
/**
* This method scans network data for given Service ID and returns pointer to the respective TLV, if present.
@@ -305,7 +312,9 @@ private:
static constexpr uint8_t kNumContextIds = 15; // Maximum Context ID
static constexpr uint32_t kContextIdReuseDelay = 48 * 60 * 60; // in seconds
static constexpr uint32_t kStateUpdatePeriod = 60 * 1000; // State update period in milliseconds
static constexpr uint32_t kMaxNetDataSyncWait = 60 * 1000; // Maximum time to wait for netdata sync.
bool mWaitingForNetDataSync;
uint16_t mContextUsed;
TimeMilli mContextLastUsed[kNumContextIds];
uint32_t mContextIdReuseDelay;