From 144d480ca9aa69d477eb1e01ce8b02eb9e5664b6 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 13 Dec 2022 23:07:45 -0800 Subject: [PATCH] [router-table] simplify tracking of routers and allocated IDs (#8483) This commit simplifies how `RouterTable` tracks the allocated Router IDs and the `Router` entries. A new class `RouterIdMap` is added which tracks the currently allocated Router IDs. For allocated IDs, it also tracks the index of the `Router` entry in `mRouters` array. For unallocated IDs, it tracks the remaining reuse delay time in seconds (using the same underlying `uint8_t` per Router ID). This new class makes it easier to find a `Router` by its ID. With this change, we no longer need to keep the `mRouters` array sorted based on Router ID (this was used when populating `RouteTlv`). This commit also changes the `mRouters` to use `Array` which will then tracks its length and also simplify range-based `for` iteration over `RouterTable` entries. --- src/core/common/array.hpp | 36 ++++ src/core/radio/trel_link.cpp | 2 +- src/core/thread/key_manager.cpp | 2 +- src/core/thread/mle_router.cpp | 12 +- src/core/thread/router_table.cpp | 346 +++++++++++++------------------ src/core/thread/router_table.hpp | 129 +++++------- src/core/thread/thread_tlvs.hpp | 8 + 7 files changed, 252 insertions(+), 283 deletions(-) diff --git a/src/core/common/array.hpp b/src/core/common/array.hpp index f4c6ee81c..4a65073f1 100644 --- a/src/core/common/array.hpp +++ b/src/core/common/array.hpp @@ -39,6 +39,7 @@ #include "common/code_utils.hpp" #include "common/const_cast.hpp" #include "common/error.hpp" +#include "common/locator.hpp" #include "common/numeric_limits.hpp" #include "common/type_traits.hpp" @@ -146,6 +147,24 @@ public: */ Array(const Array &aOtherArray) { *this = aOtherArray; } + /** + * This constructor initializes the array as empty and initializes its elements by calling `Init(Instance &)` + * method on every element. + * + * This constructor uses method `Init(Instance &aInstance)` on `Type`. + * + * @param[in] aInstance The OpenThread instance. + * + */ + explicit Array(Instance &aInstance) + : mLength(0) + { + for (Type &element : mElements) + { + element.Init(aInstance); + } + } + /** * This method clears the array. * @@ -558,6 +577,23 @@ public: return *this; } + /** + * This method indicates whether a given entry pointer is from the array buffer. + * + * This method does not check the current length of array and only checks that @p aEntry is pointing to an address + * contained within underlying C array buffer. + * + * @param[in] aEntry A pointer to an entry to check. + * + * @retval TRUE The @p aEntry is from the array. + * @retval FALSE The @p aEntry is not from the array. + * + */ + bool IsInArrayBuffer(const Type *aEntry) const + { + return (&mElements[0] <= aEntry) && (aEntry < GetArrayEnd(mElements)); + } + // The following methods are intended to support range-based `for` // loop iteration over the array elements and should not be used // directly. diff --git a/src/core/radio/trel_link.cpp b/src/core/radio/trel_link.cpp index 45f1d609e..9a12a9b37 100644 --- a/src/core/radio/trel_link.cpp +++ b/src/core/radio/trel_link.cpp @@ -265,7 +265,7 @@ void Link::HandleTimer(void) HandleTimer(child); } - for (Router &router : Get().Iterate()) + for (Router &router : Get()) { HandleTimer(router); } diff --git a/src/core/thread/key_manager.cpp b/src/core/thread/key_manager.cpp index 888a99c79..168899997 100644 --- a/src/core/thread/key_manager.cpp +++ b/src/core/thread/key_manager.cpp @@ -238,7 +238,7 @@ void KeyManager::ResetFrameCounters(void) #if OPENTHREAD_FTD // reset router frame counters - for (Router &router : Get().Iterate()) + for (Router &router : Get()) { router.SetKeySequence(0); router.GetLinkFrameCounters().Reset(); diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 028fc2477..b7cd90aae 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -1755,7 +1755,7 @@ bool MleRouter::HasNeighborWithGoodLinkQuality(void) const ExitNow(); } - for (Router &router : Get().Iterate()) + for (const Router &router : Get()) { if (!router.IsStateValid()) { @@ -1935,7 +1935,7 @@ void MleRouter::HandleTimeTick(void) } // update router state - for (Router &router : Get().Iterate()) + for (Router &router : Get()) { uint32_t age; @@ -3978,7 +3978,7 @@ void MleRouter::SendAddressSolicitResponse(const Coap::Message &aRequest, routerMaskTlv.Init(); routerMaskTlv.SetIdSequence(mRouterTable.GetRouterIdSequence()); - routerMaskTlv.SetAssignedRouterIdMask(mRouterTable.GetRouterIdSet()); + mRouterTable.GetRouterIdSet(routerMaskTlv.GetAssignedRouterIdMask()); SuccessOrExit(routerMaskTlv.AppendTo(*message)); } @@ -4107,7 +4107,7 @@ void MleRouter::FillConnectivityTlv(ConnectivityTlv &aTlv) aTlv.SetActiveRouters(mRouterTable.GetActiveRouterCount()); - for (Router &router : Get().Iterate()) + for (const Router &router : Get()) { if (router.GetRloc16() == GetRloc16()) { @@ -4150,7 +4150,7 @@ bool MleRouter::HasMinDowngradeNeighborRouters(void) { uint8_t routerCount = 0; - for (Router &router : Get().Iterate()) + for (const Router &router : Get()) { if (!router.IsStateValid()) { @@ -4172,7 +4172,7 @@ bool MleRouter::HasOneNeighborWithComparableConnectivity(const RouteTlv &aRouteT bool rval = true; // process local neighbor routers - for (Router &router : Get().Iterate()) + for (const Router &router : Get()) { LinkQuality localLinkQuality; LinkQuality peerLinkQuality; diff --git a/src/core/thread/router_table.cpp b/src/core/thread/router_table.cpp index e9beb4e36..3bc92e028 100644 --- a/src/core/thread/router_table.cpp +++ b/src/core/thread/router_table.cpp @@ -44,58 +44,24 @@ namespace ot { RegisterLogModule("RouterTable"); -RouterTable::Iterator::Iterator(Instance &aInstance) - : InstanceLocator(aInstance) - , ItemPtrIterator(Get().GetFirstEntry()) -{ -} - -void RouterTable::Iterator::Advance(void) { mItem = Get().GetNextEntry(mItem); } - RouterTable::RouterTable(Instance &aInstance) : InstanceLocator(aInstance) + , mRouters(aInstance) , mRouterIdSequenceLastUpdated(0) , mRouterIdSequence(Random::NonCrypto::GetUint8()) - , mActiveRouterCount(0) #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE , mMinRouterId(0) , mMaxRouterId(Mle::kMaxRouterId) #endif { - for (Router &router : mRouters) - { - router.Init(aInstance); - } - Clear(); } -const Router *RouterTable::GetFirstEntry(void) const -{ - const Router *router = &mRouters[0]; - VerifyOrExit(router->GetRloc16() != 0xffff, router = nullptr); - -exit: - return router; -} - -const Router *RouterTable::GetNextEntry(const Router *aRouter) const -{ - VerifyOrExit(aRouter != nullptr); - aRouter++; - VerifyOrExit(aRouter < &mRouters[Mle::kMaxRouters], aRouter = nullptr); - VerifyOrExit(aRouter->GetRloc16() != 0xffff, aRouter = nullptr); - -exit: - return aRouter; -} - void RouterTable::Clear(void) { ClearNeighbors(); - mAllocatedRouterIds.Clear(); - memset(mRouterIdReuseDelay, 0, sizeof(mRouterIdReuseDelay)); - UpdateAllocation(); + mRouterIdMap.Clear(); + mRouters.Clear(); } void RouterTable::ClearNeighbors(void) @@ -111,89 +77,40 @@ void RouterTable::ClearNeighbors(void) } } -bool RouterTable::IsAllocated(uint8_t aRouterId) const { return mAllocatedRouterIds.Contains(aRouterId); } - -void RouterTable::UpdateAllocation(void) +Router *RouterTable::AddRouter(uint8_t aRouterId) { - uint8_t indexMap[Mle::kMaxRouterId + 1]; + // Add a new `Router` entry to `mRouters` array with given + // `aRouterId` and update the `mRouterIdMap`. - mActiveRouterCount = 0; + Router *router = mRouters.PushBack(); - // build index map - for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++) + VerifyOrExit(router != nullptr); + + router->Clear(); + router->SetRloc16(Mle::Rloc16FromRouterId(aRouterId)); + router->SetNextHop(Mle::kInvalidRouterId); + + mRouterIdMap.SetIndex(aRouterId, mRouters.IndexOf(*router)); + +exit: + return router; +} + +void RouterTable::RemoveRouter(Router &aRouter) +{ + // Remove an existing `aRouter` entry from `mRouters` and update the + // `mRouterIdMap`. + + mRouterIdMap.Release(aRouter.GetRouterId()); + mRouters.Remove(aRouter); + + // Removing `aRouter` from `mRouters` array will replace it with + // the last entry in the array (if not already the last entry) so + // we update the index in `mRouteIdMap` for the moved entry. + + if (IsAllocated(aRouter.GetRouterId())) { - if (IsAllocated(routerId) && mActiveRouterCount < Mle::kMaxRouters) - { - indexMap[routerId] = mActiveRouterCount++; - } - else - { - indexMap[routerId] = Mle::kInvalidRouterId; - } - } - - // shift entries forward - for (int index = Mle::kMaxRouters - 2; index >= 0; index--) - { - uint8_t routerId = mRouters[index].GetRouterId(); - uint8_t newIndex; - - if (routerId > Mle::kMaxRouterId || indexMap[routerId] == Mle::kInvalidRouterId) - { - continue; - } - - newIndex = indexMap[routerId]; - - if (newIndex > index) - { - mRouters[newIndex] = mRouters[index]; - } - } - - // shift entries backward - for (uint8_t index = 1; index < Mle::kMaxRouters; index++) - { - uint8_t routerId = mRouters[index].GetRouterId(); - uint8_t newIndex; - - if (routerId > Mle::kMaxRouterId || indexMap[routerId] == Mle::kInvalidRouterId) - { - continue; - } - - newIndex = indexMap[routerId]; - - if (newIndex < index) - { - mRouters[newIndex] = mRouters[index]; - } - } - - // fix replaced entries - for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++) - { - uint8_t index = indexMap[routerId]; - - if (index != Mle::kInvalidRouterId) - { - Router &router = mRouters[index]; - - if (router.GetRouterId() != routerId) - { - router.Clear(); - router.SetRloc16(Mle::Rloc16FromRouterId(routerId)); - router.SetNextHop(Mle::kInvalidRouterId); - } - } - } - - // clear unused entries - for (uint8_t index = mActiveRouterCount; index < Mle::kMaxRouters; index++) - { - Router &router = mRouters[index]; - router.Clear(); - router.SetRloc16(0xffff); + mRouterIdMap.SetIndex(aRouter.GetRouterId(), mRouters.IndexOf((aRouter))); } } @@ -203,7 +120,7 @@ Router *RouterTable::Allocate(void) uint8_t numAvailable = 0; uint8_t selectedRouterId = Mle::kInvalidRouterId; - VerifyOrExit(mActiveRouterCount < Mle::kMaxRouters); + VerifyOrExit(!mRouters.IsFull()); // count available router ids #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE @@ -212,7 +129,7 @@ Router *RouterTable::Allocate(void) for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++) #endif { - if (!IsAllocated(routerId) && mRouterIdReuseDelay[routerId] == 0) + if (mRouterIdMap.CanAllocate(routerId)) { numAvailable++; @@ -239,16 +156,14 @@ exit: Router *RouterTable::Allocate(uint8_t aRouterId) { - Router *rval = nullptr; + Router *router = nullptr; - VerifyOrExit(aRouterId <= Mle::kMaxRouterId && mActiveRouterCount < Mle::kMaxRouters && !IsAllocated(aRouterId) && - mRouterIdReuseDelay[aRouterId] == 0); + VerifyOrExit(aRouterId <= Mle::kMaxRouterId && mRouterIdMap.CanAllocate(aRouterId)); - mAllocatedRouterIds.Add(aRouterId); - UpdateAllocation(); + router = AddRouter(aRouterId); + VerifyOrExit(router != nullptr); - rval = FindRouterById(aRouterId); - rval->SetLastHeard(TimerMilli::GetNow()); + router->SetLastHeard(TimerMilli::GetNow()); mRouterIdSequence++; mRouterIdSequenceLastUpdated = TimerMilli::GetNow(); @@ -257,38 +172,34 @@ Router *RouterTable::Allocate(uint8_t aRouterId) LogNote("Allocate router id %d", aRouterId); exit: - return rval; + return router; } Error RouterTable::Release(uint8_t aRouterId) { - Error error = kErrorNone; - uint16_t rloc16 = Mle::Rloc16FromRouterId(aRouterId); - Router *router; + Error error = kErrorNone; + Router *router; OT_ASSERT(aRouterId <= Mle::kMaxRouterId); VerifyOrExit(Get().IsLeader(), error = kErrorInvalidState); - VerifyOrExit(IsAllocated(aRouterId), error = kErrorNotFound); - router = FindNeighbor(rloc16); + router = FindRouterById(aRouterId); + VerifyOrExit(router != nullptr, error = kErrorNotFound); - if (router != nullptr) + if (router->IsStateValid()) { Get().Signal(NeighborTable::kRouterRemoved, *router); } - mAllocatedRouterIds.Remove(aRouterId); - UpdateAllocation(); + RemoveRouter(*router); - mRouterIdReuseDelay[aRouterId] = Mle::kRouterIdReuseDelay; - - for (router = GetFirstEntry(); router != nullptr; router = GetNextEntry(router)) + for (Router &otherRouter : mRouters) { - if (router->GetNextHop() == aRouterId) + if (otherRouter.GetNextHop() == aRouterId) { - router->SetNextHop(Mle::kInvalidRouterId); - router->SetCost(0); + otherRouter.SetNextHop(Mle::kInvalidRouterId); + otherRouter.SetCost(0); } } @@ -296,7 +207,8 @@ Error RouterTable::Release(uint8_t aRouterId) mRouterIdSequenceLastUpdated = TimerMilli::GetNow(); Get().Remove(aRouterId); - Get().RemoveBorderRouter(rloc16, NetworkData::Leader::kMatchModeRouterId); + Get().RemoveBorderRouter(Mle::Rloc16FromRouterId(aRouterId), + NetworkData::Leader::kMatchModeRouterId); Get().ResetAdvertiseInterval(); LogNote("Release router id %d", aRouterId); @@ -313,14 +225,14 @@ void RouterTable::RemoveRouterLink(Router &aRouter) aRouter.SetLastHeard(TimerMilli::GetNow()); } - for (Router *cur = GetFirstEntry(); cur != nullptr; cur = GetNextEntry(cur)) + for (Router &router : mRouters) { - if (cur->GetNextHop() == aRouter.GetRouterId()) + if (router.GetNextHop() == aRouter.GetRouterId()) { - cur->SetNextHop(Mle::kInvalidRouterId); - cur->SetCost(0); + router.SetNextHop(Mle::kInvalidRouterId); + router.SetCost(0); - if (GetLinkCost(*cur) >= Mle::kMaxRouteCost) + if (GetLinkCost(router) >= Mle::kMaxRouteCost) { Get().ResetAdvertiseInterval(); } @@ -338,17 +250,7 @@ void RouterTable::RemoveRouterLink(Router &aRouter) const Router *RouterTable::FindRouter(const Router::AddressMatcher &aMatcher) const { - const Router *router; - - for (router = GetFirstEntry(); router != nullptr; router = GetNextEntry(router)) - { - if (router->Matches(aMatcher)) - { - break; - } - } - - return router; + return mRouters.FindMatching(aMatcher); } Router *RouterTable::FindNeighbor(uint16_t aRloc16) @@ -375,13 +277,11 @@ Router *RouterTable::FindNeighbor(const Mac::Address &aMacAddress) const Router *RouterTable::FindRouterById(uint8_t aRouterId) const { const Router *router = nullptr; - uint16_t rloc16; - // Skip if invalid router id is passed. - VerifyOrExit(aRouterId < Mle::kInvalidRouterId); + VerifyOrExit(aRouterId <= Mle::kMaxRouterId); - rloc16 = Mle::Rloc16FromRouterId(aRouterId); - router = FindRouter(Router::AddressMatcher(rloc16, Router::kInStateAny)); + VerifyOrExit(IsAllocated(aRouterId)); + router = &mRouters[mRouterIdMap.GetIndex(aRouterId)]; exit: return router; @@ -429,16 +329,16 @@ Router *RouterTable::GetLeader(void) { return FindRouterById(Get uint32_t RouterTable::GetLeaderAge(void) const { - return (mActiveRouterCount > 0) ? Time::MsecToSec(TimerMilli::GetNow() - mRouterIdSequenceLastUpdated) : 0xffffffff; + return (!mRouters.IsEmpty()) ? Time::MsecToSec(TimerMilli::GetNow() - mRouterIdSequenceLastUpdated) : 0xffffffff; } uint8_t RouterTable::GetNeighborCount(void) const { uint8_t count = 0; - for (const Router *router = GetFirstEntry(); router != nullptr; router = GetNextEntry(router)) + for (const Router &router : mRouters) { - if (router->IsStateValid()) + if (router.IsStateValid()) { count++; } @@ -461,28 +361,48 @@ exit: void RouterTable::UpdateRouterIdSet(uint8_t aRouterIdSequence, const Mle::RouterIdSet &aRouterIdSet) { + bool shouldAdd = false; + mRouterIdSequence = aRouterIdSequence; mRouterIdSequenceLastUpdated = TimerMilli::GetNow(); - VerifyOrExit(mAllocatedRouterIds != aRouterIdSet); + // Remove all previously allocated routers that are now removed in + // new `aRouterIdSet`. for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++) { - // If was allocated but removed in new Router Id Set - if (IsAllocated(routerId) && !aRouterIdSet.Contains(routerId)) + if (IsAllocated(routerId) == aRouterIdSet.Contains(routerId)) + { + continue; + } + + if (IsAllocated(routerId)) { Router *router = FindRouterById(routerId); OT_ASSERT(router != nullptr); router->SetNextHop(Mle::kInvalidRouterId); RemoveRouterLink(*router); + RemoveRouter(*router); + } + else + { + shouldAdd = true; + } + } - mAllocatedRouterIds.Remove(routerId); + VerifyOrExit(shouldAdd); + + // Now add all new routers in `aRouterIdSet`. + + for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++) + { + if (!IsAllocated(routerId) && aRouterIdSet.Contains(routerId)) + { + AddRouter(routerId); } } - mAllocatedRouterIds = aRouterIdSet; - UpdateAllocation(); Get().ResetAdvertiseInterval(); exit: @@ -492,15 +412,17 @@ exit: void RouterTable::FillRouteTlv(Mle::RouteTlv &aRouteTlv, const Neighbor *aNeighbor) const { uint8_t routerIdSequence = mRouterIdSequence; - Mle::RouterIdSet routerIdSet = mAllocatedRouterIds; - uint8_t routerCount; + Mle::RouterIdSet routerIdSet; + uint8_t routerIndex; + + mRouterIdMap.GetAsRouterIdSet(routerIdSet); if ((aNeighbor != nullptr) && Mle::IsActiveRouter(aNeighbor->GetRloc16())) { // Sending a Link Accept message that may require truncation // of Route64 TLV. - routerCount = mActiveRouterCount; + uint8_t routerCount = mRouters.GetLength(); if (routerCount > Mle::kLinkAcceptMaxRouters) { @@ -536,18 +458,23 @@ void RouterTable::FillRouteTlv(Mle::RouteTlv &aRouteTlv, const Neighbor *aNeighb aRouteTlv.SetRouterIdSequence(routerIdSequence); aRouteTlv.SetRouterIdMask(routerIdSet); - routerCount = 0; + routerIndex = 0; - for (const Router *router = GetFirstEntry(); router != nullptr; router = GetNextEntry(router)) + for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++) { - if (!routerIdSet.Contains(router->GetRouterId())) + const Router *router; + + if (!routerIdSet.Contains(routerId)) { continue; } + router = FindRouterById(routerId); + OT_ASSERT(router != nullptr); + if (router->GetRloc16() == Get().GetRloc16()) { - aRouteTlv.SetRouteData(routerCount, kLinkQuality0, kLinkQuality0, 1); + aRouteTlv.SetRouteData(routerIndex, kLinkQuality0, kLinkQuality0, 1); } else { @@ -574,36 +501,30 @@ void RouterTable::FillRouteTlv(Mle::RouteTlv &aRouteTlv, const Neighbor *aNeighb routeCost = 0; } - aRouteTlv.SetRouteData(routerCount, router->GetLinkQualityIn(), router->GetLinkQualityOut(), routeCost); + aRouteTlv.SetRouteData(routerIndex, router->GetLinkQualityIn(), router->GetLinkQualityOut(), routeCost); } - routerCount++; + routerIndex++; } - aRouteTlv.SetRouteDataLength(routerCount); + aRouteTlv.SetRouteDataLength(routerIndex); } void RouterTable::HandleTimeTick(void) { - Mle::MleRouter &mle = Get(); + mRouterIdMap.HandleTimeTick(); - if (mle.IsLeader()) + VerifyOrExit(Get().IsLeader()); + + // Update router id sequence + if (GetLeaderAge() >= Mle::kRouterIdSequencePeriod) { - // update router id sequence - if (GetLeaderAge() >= Mle::kRouterIdSequencePeriod) - { - mRouterIdSequence++; - mRouterIdSequenceLastUpdated = TimerMilli::GetNow(); - } - - for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++) - { - if (mRouterIdReuseDelay[routerId] > 0) - { - mRouterIdReuseDelay[routerId]--; - } - } + mRouterIdSequence++; + mRouterIdSequenceLastUpdated = TimerMilli::GetNow(); } + +exit: + return; } #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE @@ -627,14 +548,41 @@ exit: } #endif +void RouterTable::RouterIdMap::GetAsRouterIdSet(Mle::RouterIdSet &aRouterIdSet) const +{ + aRouterIdSet.Clear(); + + for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++) + { + if (IsAllocated(routerId)) + { + aRouterIdSet.Add(routerId); + } + } +} + +void RouterTable::RouterIdMap::HandleTimeTick(void) +{ + for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++) + { + // If Router ID is not allocated the `mIndexes` tracks the + // remaining reuse delay time in seconds. + + if (!IsAllocated(routerId) && (mIndexes[routerId] > 0)) + { + mIndexes[routerId]--; + } + } +} + #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) -void RouterTable::LogRouteTable(void) +void RouterTable::LogRouteTable(void) const { static constexpr uint16_t kStringSize = 128; LogInfo("Route table"); - for (Router &router : Iterate()) + for (const Router &router : mRouters) { String string; diff --git a/src/core/thread/router_table.hpp b/src/core/thread/router_table.hpp index 4f5cf293b..44f30f802 100644 --- a/src/core/thread/router_table.hpp +++ b/src/core/thread/router_table.hpp @@ -33,6 +33,7 @@ #if OPENTHREAD_FTD +#include "common/array.hpp" #include "common/const_cast.hpp" #include "common/encoding.hpp" #include "common/iterator_utils.hpp" @@ -49,41 +50,8 @@ namespace ot { class RouterTable : public InstanceLocator, private NonCopyable { friend class NeighborTable; - class IteratorBuilder; public: - /** - * This class represents an iterator for iterating through entries in the router table. - * - */ - class Iterator : public InstanceLocator, public ItemPtrIterator - { - friend class ItemPtrIterator; - friend class IteratorBuilder; - - public: - /** - * This constructor initializes an `Iterator` instance to start from beginning of the router table. - * - * @param[in] aInstance A reference to the OpenThread instance. - * - */ - explicit Iterator(Instance &aInstance); - - private: - enum IteratorType : uint8_t - { - kEndIterator, - }; - - Iterator(Instance &aInstance, IteratorType) - : InstanceLocator(aInstance) - { - } - - void Advance(void); - }; - /** * Constructor. * @@ -148,7 +116,7 @@ public: * @returns The number of active routers in the Thread network. * */ - uint8_t GetActiveRouterCount(void) const { return mActiveRouterCount; } + uint8_t GetActiveRouterCount(void) const { return mRouters.GetLength(); } /** * This method returns the leader in the Thread network. @@ -258,8 +226,7 @@ public: */ bool Contains(const Neighbor &aNeighbor) const { - return mRouters <= &static_cast(aNeighbor) && - &static_cast(aNeighbor) < mRouters + Mle::kMaxRouters; + return mRouters.IsInArrayBuffer(&static_cast(aNeighbor)); } /** @@ -308,7 +275,7 @@ public: * @retval FALSE if @p aRouterId is not allocated. * */ - bool IsAllocated(uint8_t aRouterId) const; + bool IsAllocated(uint8_t aRouterId) const { return mRouterIdMap.IsAllocated(aRouterId); } /** * This method updates the Router ID allocation set. @@ -325,7 +292,7 @@ public: * @returns The allocated Router ID set. * */ - const Mle::RouterIdSet &GetRouterIdSet(void) const { return mAllocatedRouterIds; } + void GetRouterIdSet(Mle::RouterIdSet &aRouterIdSet) const { return mRouterIdMap.GetAsRouterIdSet(aRouterIdSet); } /** * This method fills a Route TLV. @@ -346,18 +313,6 @@ public: */ void HandleTimeTick(void); - /** - * This method enables range-based `for` loop iteration over all Router entries in the Router table. - * - * This method should be used as follows: - * - * for (Router &router : Get().Iterate()) { ... } - * - * @returns An `IteratorBuilder` instance. - * - */ - IteratorBuilder Iterate(void) { return IteratorBuilder(GetInstance()); } - #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE void GetRouterIdRange(uint8_t &aMinRouterId, uint8_t &aMaxRouterId) const; @@ -369,30 +324,23 @@ public: * This method logs the route table. * */ - void LogRouteTable(void); + void LogRouteTable(void) const; #else - void LogRouteTable(void) {} + void LogRouteTable(void) const {} #endif + // The following methods are intended to support range-based `for` + // loop iteration over the router and should not be used + // directly. + + Router *begin(void) { return mRouters.begin(); } + Router *end(void) { return mRouters.end(); } + const Router *begin(void) const { return mRouters.begin(); } + const Router *end(void) const { return mRouters.end(); } + private: - class IteratorBuilder : public InstanceLocator - { - public: - explicit IteratorBuilder(Instance &aInstance) - : InstanceLocator(aInstance) - { - } - - Iterator begin(void) { return Iterator(GetInstance()); } - Iterator end(void) { return Iterator(GetInstance(), Iterator::kEndIterator); } - }; - - void UpdateAllocation(void); - const Router *GetFirstEntry(void) const; - const Router *GetNextEntry(const Router *aRouter) const; - Router *GetFirstEntry(void) { return AsNonConst(AsConst(this)->GetFirstEntry()); } - Router *GetNextEntry(Router *aRouter) { return AsNonConst(AsConst(this)->GetNextEntry(aRouter)); } - + Router *AddRouter(uint8_t aRouterId); + void RemoveRouter(Router &aRouter); Router *FindNeighbor(uint16_t aRloc16); Router *FindNeighbor(const Mac::ExtAddress &aExtAddress); Router *FindNeighbor(const Mac::Address &aMacAddress); @@ -402,12 +350,41 @@ private: return AsNonConst(AsConst(this)->FindRouter(aMatcher)); } - Router mRouters[Mle::kMaxRouters]; - Mle::RouterIdSet mAllocatedRouterIds; - uint8_t mRouterIdReuseDelay[Mle::kMaxRouterId + 1]; - TimeMilli mRouterIdSequenceLastUpdated; - uint8_t mRouterIdSequence; - uint8_t mActiveRouterCount; + class RouterIdMap + { + public: + // The `RouterIdMap` tracks which Router IDs are allocated. + // For allocated IDs, tracks the index of the `Router` entry + // in `mRouters` array. For unallocated IDs, tracks the + // remaining reuse delay time (in seconds). + + RouterIdMap(void) { Clear(); } + void Clear(void) { memset(mIndexes, 0, sizeof(mIndexes)); } + bool IsAllocated(uint8_t aRouterId) const { return (mIndexes[aRouterId] & kAllocatedFlag); } + uint8_t GetIndex(uint8_t aRouterId) const { return (mIndexes[aRouterId] & kIndexMask); } + void SetIndex(uint8_t aRouterId, uint8_t aIndex) { mIndexes[aRouterId] = kAllocatedFlag | aIndex; } + bool CanAllocate(uint8_t aRouterId) const { return (mIndexes[aRouterId] == 0); } + void Release(uint8_t aRouterId) { mIndexes[aRouterId] = Mle::kRouterIdReuseDelay; } + void GetAsRouterIdSet(Mle::RouterIdSet &aRouterIdSet) const; + void HandleTimeTick(void); + + private: + // The high bit in `mIndexes[aRouterId]` indicates whether or + // not the router ID is allocated. The lower 7 bits give either + // the index in `mRouter` array or remaining reuse delay time. + + static constexpr uint8_t kAllocatedFlag = 1 << 7; + static constexpr uint8_t kIndexMask = 0x7f; + + static_assert(Mle::kRouterIdReuseDelay <= kIndexMask, "Mle::kRouterIdReuseDelay does not fit in 7 bits"); + + uint8_t mIndexes[Mle::kMaxRouterId + 1]; + }; + + Array mRouters; + RouterIdMap mRouterIdMap; + TimeMilli mRouterIdSequenceLastUpdated; + uint8_t mRouterIdSequence; #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE uint8_t mMinRouterId; uint8_t mMaxRouterId; diff --git a/src/core/thread/thread_tlvs.hpp b/src/core/thread/thread_tlvs.hpp index 5319da287..4527aac39 100644 --- a/src/core/thread/thread_tlvs.hpp +++ b/src/core/thread/thread_tlvs.hpp @@ -249,6 +249,14 @@ public: */ const Mle::RouterIdSet &GetAssignedRouterIdMask(void) const { return mAssignedRouterIdMask; } + /** + * This method gets the Assigned Router ID Mask. + * + * @returns The Assigned Router ID Mask. + * + */ + Mle::RouterIdSet &GetAssignedRouterIdMask(void) { return mAssignedRouterIdMask; } + /** * This method sets the Assigned Router ID Mask. *