From 0132362815ebd5b4535b6c84057f85ad8a673cd5 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Thu, 30 Jun 2022 09:49:27 -0700 Subject: [PATCH] [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. --- src/core/thread/mle_router.cpp | 8 +++--- src/core/thread/mle_router.hpp | 2 +- src/core/thread/mle_types.hpp | 12 +++++++++ src/core/thread/network_data_leader.cpp | 3 +-- src/core/thread/network_data_leader_ftd.cpp | 29 +++++++++++++++++++-- src/core/thread/network_data_leader_ftd.hpp | 13 +++++++-- 6 files changed, 56 insertions(+), 11 deletions(-) diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index f21cef38a..91a73e979 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -269,7 +269,7 @@ Error MleRouter::BecomeLeader(void) Get().Reset(); Get().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().Restore()); IgnoreError(Get().Restore()); @@ -421,7 +421,7 @@ void MleRouter::SetStateLeader(uint16_t aRloc16) mPreviousPartitionIdRouter = mLeaderData.GetPartitionId(); Get().RegisterReceiver(TimeTicker::kMleRouter); - Get().Start(); + Get().Start(aStartMode); Get().StartLeader(); Get().StartLeader(); Get().AddResource(mAddressSolicit); @@ -938,7 +938,7 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest) if (mLeaderData.GetLeaderRouterId() == RouterIdFromRloc16(GetRloc16())) { - SetStateLeader(GetRloc16()); + SetStateLeader(GetRloc16(), kRestoringLeaderRoleAfterReset); } else { diff --git a/src/core/thread/mle_router.hpp b/src/core/thread/mle_router.hpp index 6493c512b..87af6de57 100644 --- a/src/core/thread/mle_router.hpp +++ b/src/core/thread/mle_router.hpp @@ -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); diff --git a/src/core/thread/mle_types.hpp b/src/core/thread/mle_types.hpp index 0dfdf9348..fbc92a63e 100644 --- a/src/core/thread/mle_types.hpp +++ b/src/core/thread/mle_types.hpp @@ -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 /* diff --git a/src/core/thread/network_data_leader.cpp b/src/core/thread/network_data_leader.cpp index 8c2884201..0207c390f 100644 --- a/src/core/thread/network_data_leader.cpp +++ b/src/core/thread/network_data_leader.cpp @@ -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().IsLeader()) { - Get().UpdateContextsAfterReset(); + Get().HandleNetworkDataRestoredAfterReset(); } #endif diff --git a/src/core/thread/network_data_leader_ftd.cpp b/src/core/thread/network_data_leader_ftd.cpp index 770c2413b..dac504d76 100644 --- a/src/core/thread/network_data_leader_ftd.cpp +++ b/src/core/thread/network_data_leader_ftd.cpp @@ -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().AddResource(mServerData); Get().AddResource(mCommissioningDataGet); Get().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(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()) != nullptr) { const ContextTlv *context = prefix->FindSubTlv(); @@ -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().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) diff --git a/src/core/thread/network_data_leader_ftd.hpp b/src/core/thread/network_data_leader_ftd.hpp index c1f57644d..1ca969f67 100644 --- a/src/core/thread/network_data_leader_ftd.hpp +++ b/src/core/thread/network_data_leader_ftd.hpp @@ -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;