diff --git a/src/core/border_router/routing_manager.cpp b/src/core/border_router/routing_manager.cpp index b3ec00fe4..07b2c6379 100644 --- a/src/core/border_router/routing_manager.cpp +++ b/src/core/border_router/routing_manager.cpp @@ -594,7 +594,7 @@ void RoutingManager::SendRouterAdvertisement(RouterAdvTxMode aRaTxMode) header.SetToDefault(); } - mRxRaTracker.DetermineAndSetFlags(header); + mRxRaTracker.SetHeaderFlagsOn(header); SuccessOrExit(error = raMsg.AppendHeader(header)); @@ -980,12 +980,11 @@ void RoutingManager::RxRaTracker::Stop(void) { mRouters.Free(); mLocalRaHeader.Clear(); + mDecisionFactors.Clear(); mExpirationTimer.Stop(); mStaleTimer.Stop(); mRouterTimer.Stop(); - - SignalTableChanged(); } void RoutingManager::RxRaTracker::ProcessRouterAdvertMessage(const RouterAdvert::RxMessage &aRaMessage, @@ -1048,9 +1047,9 @@ void RoutingManager::RxRaTracker::ProcessRouterAdvertMessage(const RouterAdvert: router->mIsLocalDevice = (aRaOrigin == kThisBrOtherEntity); - UpdateRouterOnRx(*router); + router->ResetReachabilityState(); - RemoveRoutersWithNoEntriesOrFlags(); + Evaluate(); exit: return; @@ -1070,13 +1069,11 @@ void RoutingManager::RxRaTracker::ProcessRaHeader(const RouterAdvert::Header &aR if (aRouter.mManagedAddressConfigFlag != managedFlag) { aRouter.mManagedAddressConfigFlag = managedFlag; - SignalTableChanged(); } if (aRouter.mOtherConfigFlag != otherFlag) { aRouter.mOtherConfigFlag = otherFlag; - SignalTableChanged(); } if (aRaOrigin == kThisBrOtherEntity) @@ -1104,7 +1101,6 @@ void RoutingManager::RxRaTracker::ProcessRaHeader(const RouterAdvert::Header &aR if (mLocalRaHeader != oldHeader) { - SignalTableChanged(); Get().ScheduleRoutingPolicyEvaluation(kAfterRandomDelay); } } @@ -1134,10 +1130,6 @@ void RoutingManager::RxRaTracker::ProcessRaHeader(const RouterAdvert::Header &aR entry->SetFrom(aRaHeader); } - mExpirationTimer.FireAtIfEarlier(entry->GetExpireTime()); - - SignalTableChanged(); - exit: return; } @@ -1185,10 +1177,6 @@ void RoutingManager::RxRaTracker::ProcessPrefixInfoOption(const PrefixInfoOption entry->AdoptValidAndPreferredLifetimesFrom(newPrefix); } - mExpirationTimer.FireAtIfEarlier(entry->GetExpireTime()); - - SignalTableChanged(); - exit: return; } @@ -1241,10 +1229,6 @@ void RoutingManager::RxRaTracker::ProcessRouteInfoOption(const RouteInfoOption & entry->SetFrom(aRio); } - mExpirationTimer.FireAtIfEarlier(entry->GetExpireTime()); - - SignalTableChanged(); - exit: return; } @@ -1311,73 +1295,6 @@ template void RoutingManager::RxRaTracker::Entry: #endif // !OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE -bool RoutingManager::RxRaTracker::ContainsDefaultOrNonUlaRoutePrefix(void) const -{ - bool contains = false; - - for (const Router &router : mRouters) - { - if (router.mRoutePrefixes.ContainsMatching(RoutePrefix::kIsNotUla)) - { - contains = true; - break; - } - } - - return contains; -} - -bool RoutingManager::RxRaTracker::ContainsOnLinkPrefix(OnLinkPrefix::UlaChecker aUlaChecker) const -{ - bool contains = false; - - for (const Router &router : mRouters) - { - if (router.mOnLinkPrefixes.ContainsMatching(aUlaChecker)) - { - contains = true; - break; - } - } - - return contains; -} - -bool RoutingManager::RxRaTracker::ContainsNonUlaOnLinkPrefix(void) const -{ - return ContainsOnLinkPrefix(OnLinkPrefix::kIsNotUla); -} - -bool RoutingManager::RxRaTracker::ContainsUlaOnLinkPrefix(void) const -{ - return ContainsOnLinkPrefix(OnLinkPrefix::kIsUla); -} - -void RoutingManager::RxRaTracker::FindFavoredOnLinkPrefix(Ip6::Prefix &aPrefix) const -{ - // Find the smallest preferred on-link prefix entry in the table - // and return it in `aPrefix`. If there is none, `aPrefix` is - // cleared (prefix length is set to zero). - - aPrefix.Clear(); - - for (const Router &router : mRouters) - { - for (const OnLinkPrefix &entry : router.mOnLinkPrefixes) - { - if (entry.IsDeprecated() || (entry.GetPreferredLifetime() < kFavoredOnLinkPrefixMinPreferredLifetime)) - { - continue; - } - - if ((aPrefix.GetLength() == 0) || (entry.GetPrefix() < aPrefix)) - { - aPrefix = entry.GetPrefix(); - } - } - } -} - void RoutingManager::RxRaTracker::HandleLocalOnLinkPrefixChanged(void) { const Ip6::Prefix &prefix = Get().mOnLinkPrefixManager.GetLocalPrefix(); @@ -1390,9 +1307,7 @@ void RoutingManager::RxRaTracker::HandleLocalOnLinkPrefixChanged(void) VerifyOrExit(didRemove); - RemoveRoutersWithNoEntriesOrFlags(); - - SignalTableChanged(); + Evaluate(); exit: return; @@ -1419,8 +1334,7 @@ void RoutingManager::RxRaTracker::HandleNetDataChange(void) if (didRemove) { - RemoveRoutersWithNoEntriesOrFlags(); - SignalTableChanged(); + Evaluate(); } } @@ -1436,7 +1350,6 @@ void RoutingManager::RxRaTracker::RemoveOrDeprecateOldEntries(TimeMilli aTimeThr if (entry.GetLastUpdateTime() <= aTimeThreshold) { entry.ClearPreferredLifetime(); - SignalTableChanged(); } } @@ -1445,7 +1358,6 @@ void RoutingManager::RxRaTracker::RemoveOrDeprecateOldEntries(TimeMilli aTimeThr if (entry.GetLastUpdateTime() <= aTimeThreshold) { entry.ClearValidLifetime(); - SignalTableChanged(); } } } @@ -1453,18 +1365,55 @@ void RoutingManager::RxRaTracker::RemoveOrDeprecateOldEntries(TimeMilli aTimeThr if (mLocalRaHeader.IsValid() && (mLocalRaHeaderUpdateTime <= aTimeThreshold)) { mLocalRaHeader.Clear(); - SignalTableChanged(); } - RemoveExpiredEntries(); + Evaluate(); } -void RoutingManager::RxRaTracker::ScheduleAllTimers(void) +void RoutingManager::RxRaTracker::Evaluate(void) { - TimeMilli now = TimerMilli::GetNow(); - NextFireTime routerTimeout(now); - NextFireTime entryExpireTime(now); - NextFireTime staleTime(now); + DecisionFactors oldFactors = mDecisionFactors; + TimeMilli now = TimerMilli::GetNow(); + NextFireTime routerTimeout(now); + NextFireTime entryExpireTime(now); + NextFireTime staleTime(now); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Remove expired prefix entries in routers and then remove any + // router that has with no prefix entries or flags. + + mRouters.RemoveAndFreeAllMatching(Router::EmptyChecker(now)); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Determine decision factors (favored on-link prefix, has any + // ULA/non-ULA on-link/route prefix, M/O flags). + + mDecisionFactors.Clear(); + + for (Router &router : mRouters) + { + mDecisionFactors.UpdateFlagsFrom(router); + + for (OnLinkPrefix &entry : router.mOnLinkPrefixes) + { + mDecisionFactors.UpdateFrom(entry); + entry.SetStaleTimeCalculated(false); + } + + for (RoutePrefix &entry : router.mRoutePrefixes) + { + mDecisionFactors.UpdateFrom(entry); + entry.SetStaleTimeCalculated(false); + } + } + + if (oldFactors != mDecisionFactors) + { + mSignalTask.Post(); + } + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Schedule timers // If multiple routers advertise the same on-link or route prefix, // the stale time for the prefix is determined by the latest stale @@ -1476,19 +1425,6 @@ void RoutingManager::RxRaTracker::ScheduleAllTimers(void) // their entries, `DetermineStaleTimeFor()` will consider all // matching entries and mark "StaleTimeCalculated" flag on them. - for (Router &router : mRouters) - { - for (OnLinkPrefix &entry : router.mOnLinkPrefixes) - { - entry.SetStaleTimeCalculated(false); - } - - for (RoutePrefix &entry : router.mRoutePrefixes) - { - entry.SetStaleTimeCalculated(false); - } - } - for (const Router &router : mRouters) { if (router.ShouldCheckReachability()) @@ -1604,43 +1540,9 @@ exit: return; } -void RoutingManager::RxRaTracker::RemoveRoutersWithNoEntriesOrFlags(void) -{ - mRouters.RemoveAndFreeAllMatching(Router::kContainsNoEntriesOrFlags); -} +void RoutingManager::RxRaTracker::HandleExpirationTimer(void) { Evaluate(); } -void RoutingManager::RxRaTracker::HandleExpirationTimer(void) { RemoveExpiredEntries(); } - -void RoutingManager::RxRaTracker::RemoveExpiredEntries(void) -{ - TimeMilli now = TimerMilli::GetNow(); - bool didRemove = false; - - for (Router &router : mRouters) - { - LifetimedPrefix::ExpirationChecker expirationChecker(now); - - didRemove |= router.mOnLinkPrefixes.RemoveAndFreeAllMatching(expirationChecker); - didRemove |= router.mRoutePrefixes.RemoveAndFreeAllMatching(expirationChecker); - } - - RemoveRoutersWithNoEntriesOrFlags(); - - if (didRemove) - { - SignalTableChanged(); - } - - ScheduleAllTimers(); -} - -void RoutingManager::RxRaTracker::SignalTableChanged(void) { mSignalTask.Post(); } - -void RoutingManager::RxRaTracker::HandleSignalTask(void) -{ - ScheduleAllTimers(); - Get().HandleRaPrefixTableChanged(); -} +void RoutingManager::RxRaTracker::HandleSignalTask(void) { Get().HandleRaPrefixTableChanged(); } void RoutingManager::RxRaTracker::ProcessNeighborAdvertMessage(const NeighborAdvertMessage &aNaMessage) { @@ -1653,22 +1555,14 @@ void RoutingManager::RxRaTracker::ProcessNeighborAdvertMessage(const NeighborAdv LogInfo("Received NA from router %s", router->mAddress.ToString().AsCString()); - UpdateRouterOnRx(*router); + router->ResetReachabilityState(); + + Evaluate(); exit: return; } -void RoutingManager::RxRaTracker::UpdateRouterOnRx(Router &aRouter) -{ - aRouter.mNsProbeCount = 0; - aRouter.mLastUpdateTime = TimerMilli::GetNow(); - - aRouter.mTimeout = - aRouter.mLastUpdateTime + Random::NonCrypto::AddJitter(Router::kReachableTimeout, Router::kJitter); - mRouterTimer.FireAtIfEarlier(aRouter.mTimeout); -} - void RoutingManager::RxRaTracker::HandleRouterTimer(void) { TimeMilli now = TimerMilli::GetNow(); @@ -1701,21 +1595,17 @@ void RoutingManager::RxRaTracker::HandleRouterTimer(void) if (!entry.IsDeprecated()) { entry.ClearPreferredLifetime(); - SignalTableChanged(); } } for (RoutePrefix &entry : router.mRoutePrefixes) { entry.ClearValidLifetime(); - SignalTableChanged(); } } } - RemoveExpiredEntries(); - - ScheduleAllTimers(); + Evaluate(); } void RoutingManager::RxRaTracker::SendNeighborSolicitToRouter(const Router &aRouter) @@ -1737,39 +1627,16 @@ exit: return; } -void RoutingManager::RxRaTracker::DetermineAndSetFlags(RouterAdvert::Header &aHeader) const +void RoutingManager::RxRaTracker::SetHeaderFlagsOn(RouterAdvert::Header &aHeader) const { - // Determine the `M` and `O` flags to include in the RA message - // header to be emitted. - // - // If any discovered router on infrastructure which is not itself a - // stub router (e.g., another Thread BR) includes the `M` or `O` - // flag, we also include the same flag. - // - // If a router has failed to respond to max number of NS probe - // attempts, we consider it as offline and ignore its flags. - - for (const Router &router : mRouters) + if (mDecisionFactors.mHeaderManagedAddressConfigFlag) { - if (router.mStubRouterFlag) - { - continue; - } + aHeader.SetManagedAddressConfigFlag(); + } - if (!router.IsReachable()) - { - continue; - } - - if (router.mManagedAddressConfigFlag) - { - aHeader.SetManagedAddressConfigFlag(); - } - - if (router.mOtherConfigFlag) - { - aHeader.SetOtherConfigFlag(); - } + if (mDecisionFactors.mHeaderOtherConfigFlag) + { + aHeader.SetOtherConfigFlag(); } } @@ -1923,19 +1790,31 @@ bool RoutingManager::RxRaTracker::Router::ShouldCheckReachability(void) const return IsReachable() && !mIsLocalDevice; } -bool RoutingManager::RxRaTracker::Router::Matches(EmptyChecker aChecker) const +void RoutingManager::RxRaTracker::Router::ResetReachabilityState(void) { - // Checks whether or not a `Router` instance has any useful info. An - // entry can be removed if it does not advertise M or O flags and + // Called when an RA or NA is received and processed. + + mNsProbeCount = 0; + mLastUpdateTime = TimerMilli::GetNow(); + mTimeout = mLastUpdateTime + Random::NonCrypto::AddJitter(kReachableTimeout, kJitter); +} + +bool RoutingManager::RxRaTracker::Router::Matches(const EmptyChecker &aChecker) +{ + // First removes all expired on-link or router prefixes. Then + // checks whether or not the router has any useful info. + + bool hasFlags = false; + + mOnLinkPrefixes.RemoveAndFreeAllMatching(aChecker); + mRoutePrefixes.RemoveAndFreeAllMatching(aChecker); + + // Router can be removed if it does not advertise M or O flags and // also does not have any advertised prefix entries (RIO/PIO). If // the router already failed to respond to max NS probe attempts, // we consider it as offline and therefore do not consider its // flags anymore. - OT_UNUSED_VARIABLE(aChecker); - - bool hasFlags = false; - if (IsReachable()) { hasFlags = (mManagedAddressConfigFlag || mOtherConfigFlag); @@ -1955,6 +1834,68 @@ void RoutingManager::RxRaTracker::Router::CopyInfoTo(RouterEntry &aEntry, TimeMi aEntry.mIsReachable = IsReachable(); } +//--------------------------------------------------------------------------------------------------------------------- +// RxRaTracker::DecisionFactors + +void RoutingManager::RxRaTracker::DecisionFactors::UpdateFlagsFrom(const Router &aRouter) +{ + // Determine the `M` and `O` flags to include in the RA message + // header to be emitted. + // + // If any discovered router on infrastructure which is not itself a + // stub router (e.g., another Thread BR) includes the `M` or `O` + // flag, we also include the same flag. + + VerifyOrExit(!aRouter.mStubRouterFlag); + VerifyOrExit(aRouter.IsReachable()); + + if (aRouter.mManagedAddressConfigFlag) + { + mHeaderManagedAddressConfigFlag = true; + } + + if (aRouter.mOtherConfigFlag) + { + mHeaderOtherConfigFlag = true; + } + +exit: + return; +} + +void RoutingManager::RxRaTracker::DecisionFactors::UpdateFrom(const OnLinkPrefix &aOnLinkPrefix) +{ + if (aOnLinkPrefix.GetPrefix().IsUniqueLocal()) + { + mHasUlaOnLink = true; + } + else + { + mHasNonUlaOnLink = true; + } + + // Determine favored on-link prefix + + VerifyOrExit(!aOnLinkPrefix.IsDeprecated()); + VerifyOrExit(aOnLinkPrefix.GetPreferredLifetime() >= kFavoredOnLinkPrefixMinPreferredLifetime); + + if ((mFavoredOnLinkPrefix.GetLength() == 0) || (aOnLinkPrefix.GetPrefix() < mFavoredOnLinkPrefix)) + { + mFavoredOnLinkPrefix = aOnLinkPrefix.GetPrefix(); + } + +exit: + return; +} + +void RoutingManager::RxRaTracker::DecisionFactors::UpdateFrom(const RoutePrefix &aRoutePrefix) +{ + if (!mHasNonUlaRoute) + { + mHasNonUlaRoute = !aRoutePrefix.GetPrefix().IsUniqueLocal(); + } +} + //--------------------------------------------------------------------------------------------------------------------- // FavoredOmrPrefix @@ -2379,7 +2320,7 @@ void RoutingManager::OnLinkPrefixManager::Evaluate(void) { VerifyOrExit(!Get().mRsSender.IsInProgress()); - Get().mRxRaTracker.FindFavoredOnLinkPrefix(mFavoredDiscoveredPrefix); + mFavoredDiscoveredPrefix = Get().mRxRaTracker.GetFavoredOnLinkPrefix(); if ((mFavoredDiscoveredPrefix.GetLength() == 0) || (mFavoredDiscoveredPrefix == mLocalPrefix)) { @@ -2431,11 +2372,7 @@ void RoutingManager::OnLinkPrefixManager::HandleRaPrefixTableChanged(void) // prefix has changed, we trigger a re-evaluation of the routing // policy. - Ip6::Prefix newFavoredPrefix; - - Get().mRxRaTracker.FindFavoredOnLinkPrefix(newFavoredPrefix); - - if (newFavoredPrefix != mFavoredDiscoveredPrefix) + if (Get().mRxRaTracker.GetFavoredOnLinkPrefix() != mFavoredDiscoveredPrefix) { Get().ScheduleRoutingPolicyEvaluation(kAfterRandomDelay); } diff --git a/src/core/border_router/routing_manager.hpp b/src/core/border_router/routing_manager.hpp index 16286658b..dec8ccc5e 100644 --- a/src/core/border_router/routing_manager.hpp +++ b/src/core/border_router/routing_manager.hpp @@ -54,6 +54,7 @@ #include "border_router/infra_if.hpp" #include "common/array.hpp" #include "common/callback.hpp" +#include "common/equatable.hpp" #include "common/error.hpp" #include "common/heap_allocatable.hpp" #include "common/heap_array.hpp" @@ -658,12 +659,6 @@ private: // base class for `OnLinkPrefix` or `RoutePrefix`. public: - enum UlaChecker : bool - { - kIsNotUla = false, - kIsUla = true, - }; - struct ExpirationChecker { explicit ExpirationChecker(TimeMilli aNow) { mNow = aNow; } @@ -677,7 +672,6 @@ private: TimeMilli GetExpireTime(void) const { return CalculateExpirationTime(mValidLifetime); } bool Matches(const Ip6::Prefix &aPrefix) const { return (mPrefix == aPrefix); } - bool Matches(const UlaChecker &aIsUla) const { return (mPrefix.IsUniqueLocal() == aIsUla); } bool Matches(const ExpirationChecker &aChecker) const { return (GetExpireTime() <= aChecker.mNow); } void SetStaleTimeCalculated(bool aFlag) { mStaleTimeCalculated = aFlag; } @@ -761,25 +755,27 @@ private: RouterAdvOrigin aRaOrigin); void ProcessNeighborAdvertMessage(const NeighborAdvertMessage &aNaMessage); - bool ContainsDefaultOrNonUlaRoutePrefix(void) const; - bool ContainsNonUlaOnLinkPrefix(void) const; - bool ContainsUlaOnLinkPrefix(void) const; + // Decision factors + bool ContainsDefaultOrNonUlaRoutePrefix(void) const { return mDecisionFactors.mHasNonUlaRoute; } + bool ContainsNonUlaOnLinkPrefix(void) const { return mDecisionFactors.mHasNonUlaOnLink; } + bool ContainsUlaOnLinkPrefix(void) const { return mDecisionFactors.mHasUlaOnLink; } - void FindFavoredOnLinkPrefix(Ip6::Prefix &aPrefix) const; - - void HandleLocalOnLinkPrefixChanged(void); - void HandleNetDataChange(void); - - void RemoveOrDeprecateOldEntries(TimeMilli aTimeThreshold); + const Ip6::Prefix &GetFavoredOnLinkPrefix(void) const { return mDecisionFactors.mFavoredOnLinkPrefix; } + void SetHeaderFlagsOn(RouterAdvert::Header &aHeader) const; const RouterAdvert::Header &GetLocalRaHeaderToMirror(void) const { return mLocalRaHeader; } - void DetermineAndSetFlags(RouterAdvert::Header &aHeader) const; - + // Iterating over discovered items void InitIterator(PrefixTableIterator &aIterator) const; Error GetNextEntry(PrefixTableIterator &aIterator, PrefixTableEntry &aEntry) const; Error GetNextRouter(PrefixTableIterator &aIterator, RouterEntry &aEntry) const; + // Callbacks notifying of changes + void RemoveOrDeprecateOldEntries(TimeMilli aTimeThreshold); + void HandleLocalOnLinkPrefixChanged(void); + void HandleNetDataChange(void); + + // Tasklet or timer callbacks void HandleSignalTask(void); void HandleExpirationTimer(void); void HandleStaleTimer(void); @@ -822,15 +818,13 @@ private: static_assert(kMaxNsProbes < 255, "kMaxNsProbes MUST not be 255"); - enum EmptyChecker : uint8_t - { - kContainsNoEntriesOrFlags - }; + typedef LifetimedPrefix::ExpirationChecker EmptyChecker; bool IsReachable(void) const { return mNsProbeCount <= kMaxNsProbes; } bool ShouldCheckReachability(void) const; + void ResetReachabilityState(void); bool Matches(const Ip6::Address &aAddress) const { return aAddress == mAddress; } - bool Matches(EmptyChecker aChecker) const; + bool Matches(const EmptyChecker &aChecker); void CopyInfoTo(RouterEntry &aEntry, TimeMilli aNow) const; using OnLinkPrefixList = OwningList>; @@ -911,18 +905,32 @@ private: //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + struct DecisionFactors : public Clearable, public Equatable + { + DecisionFactors(void) { Clear(); } + + bool HasFavoredOnLink(void) const { return (mFavoredOnLinkPrefix.GetLength() != 0); } + void UpdateFlagsFrom(const Router &aRouter); + void UpdateFrom(const OnLinkPrefix &aOnLinkPrefix); + void UpdateFrom(const RoutePrefix &aRoutePrefix); + + Ip6::Prefix mFavoredOnLinkPrefix; + bool mHasNonUlaRoute : 1; + bool mHasNonUlaOnLink : 1; + bool mHasUlaOnLink : 1; + bool mHeaderManagedAddressConfigFlag : 1; + bool mHeaderOtherConfigFlag : 1; + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + void ProcessRaHeader(const RouterAdvert::Header &aRaHeader, Router &aRouter, RouterAdvOrigin aRaOrigin); void ProcessPrefixInfoOption(const PrefixInfoOption &aPio, Router &aRouter); void ProcessRouteInfoOption(const RouteInfoOption &aRio, Router &aRouter); void ProcessRaFlagsExtOption(const RaFlagsExtOption &aFlagsOption, Router &aRouter); - bool ContainsOnLinkPrefix(OnLinkPrefix::UlaChecker aUlaChecker) const; - void RemoveRoutersWithNoEntriesOrFlags(void); - void RemoveExpiredEntries(void); - void SignalTableChanged(void); - void ScheduleAllTimers(void); + void Evaluate(void); void DetermineStaleTimeFor(const OnLinkPrefix &aPrefix, NextFireTime &aStaleTime); void DetermineStaleTimeFor(const RoutePrefix &aPrefix, NextFireTime &aStaleTime); - void UpdateRouterOnRx(Router &aRouter); void SendNeighborSolicitToRouter(const Router &aRouter); #if OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE template Entry *AllocateEntry(void) { return Entry::Allocate(); } @@ -936,6 +944,7 @@ private: using RouterTimer = TimerMilliIn; using RouterList = OwningList>; + DecisionFactors mDecisionFactors; RouterList mRouters; ExpirationTimer mExpirationTimer; StaleTimer mStaleTimer; @@ -943,6 +952,7 @@ private: SignalTask mSignalTask; RouterAdvert::Header mLocalRaHeader; TimeMilli mLocalRaHeaderUpdateTime; + #if !OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE Pool mEntryPool; Pool, kMaxRouters> mRouterPool;