diff --git a/src/core/border_router/routing_manager.cpp b/src/core/border_router/routing_manager.cpp index fe219832b..b35c3fcc9 100644 --- a/src/core/border_router/routing_manager.cpp +++ b/src/core/border_router/routing_manager.cpp @@ -556,21 +556,13 @@ Error RoutingManager::PublishExternalRoute(const Ip6::Prefix &aPrefix, RoutePref LogWarn("Failed to publish external route %s: %s", aPrefix.ToString().AsCString(), ErrorToString(error)); } - return (error == kErrorAlready) ? kErrorNone : error; + return error; } void RoutingManager::UnpublishExternalRoute(const Ip6::Prefix &aPrefix) { - Error error = kErrorNone; - VerifyOrExit(mIsRunning); - - error = Get().UnpublishPrefix(aPrefix); - - if (error != kErrorNone) - { - LogWarn("Failed to unpublish route %s: %s", aPrefix.ToString().AsCString(), ErrorToString(error)); - } + IgnoreError(Get().UnpublishPrefix(aPrefix)); exit: return; @@ -1234,27 +1226,47 @@ void RoutingManager::DiscoveredPrefixTable::ProcessRouterAdvertMessage(const Ip6 { // Process a received RA message and update the prefix table. - OT_UNUSED_VARIABLE(aSrcAddress); + Router *router = mRouters.FindMatching(aSrcAddress); + + if (router == nullptr) + { + router = mRouters.PushBack(); + + if (router == nullptr) + { + LogWarn("Received RA from too many routers, ignore RA from %s", aSrcAddress.ToString().AsCString()); + ExitNow(); + } + + router->mAddress = aSrcAddress; + router->mEntries.Clear(); + } for (const Ip6::Nd::Option &option : aRaMessage) { switch (option.GetType()) { case Ip6::Nd::Option::kTypePrefixInfo: - ProcessPrefixInfoOption(static_cast(option)); + ProcessPrefixInfoOption(static_cast(option), *router); break; case Ip6::Nd::Option::kTypeRouteInfo: - ProcessRouteInfoOption(static_cast(option)); + ProcessRouteInfoOption(static_cast(option), *router); break; default: break; } } + + RemoveRoutersWithNoEntries(); + +exit: + return; } -void RoutingManager::DiscoveredPrefixTable::ProcessPrefixInfoOption(const Ip6::Nd::PrefixInfoOption &aPio) +void RoutingManager::DiscoveredPrefixTable::ProcessPrefixInfoOption(const Ip6::Nd::PrefixInfoOption &aPio, + Router & aRouter) { Ip6::Prefix prefix; Entry * entry; @@ -1266,21 +1278,22 @@ void RoutingManager::DiscoveredPrefixTable::ProcessPrefixInfoOption(const Ip6::N LogInfo("Processing PIO (%s, %u seconds)", prefix.ToString().AsCString(), aPio.GetValidLifetime()); - entry = mEntries.FindMatching(Entry::Matcher(prefix, Entry::kTypeOnLink)); + entry = aRouter.mEntries.FindMatching(Entry::Matcher(prefix, Entry::kTypeOnLink)); if (entry == nullptr) { VerifyOrExit(aPio.GetValidLifetime() != 0); - if (mEntries.IsFull()) + entry = AllocateEntry(); + + if (entry == nullptr) { LogWarn("Discovered too many prefixes, ignore on-link prefix %s", prefix.ToString().AsCString()); ExitNow(); } - SuccessOrExit(Get().PublishExternalRoute(prefix, NetworkData::kRoutePreferenceMedium)); - entry = mEntries.PushBack(); entry->InitFrom(aPio); + aRouter.mEntries.Push(*entry); } else { @@ -1290,6 +1303,7 @@ void RoutingManager::DiscoveredPrefixTable::ProcessPrefixInfoOption(const Ip6::N entry->AdoptValidAndPreferredLiftimesFrom(newEntry); } + UpdateNetworkDataOnChangeTo(*entry); mTimer.FireAtIfEarlier(entry->GetExpireTime()); SignalTableChanged(); @@ -1297,7 +1311,8 @@ exit: return; } -void RoutingManager::DiscoveredPrefixTable::ProcessRouteInfoOption(const Ip6::Nd::RouteInfoOption &aRio) +void RoutingManager::DiscoveredPrefixTable::ProcessRouteInfoOption(const Ip6::Nd::RouteInfoOption &aRio, + Router & aRouter) { Ip6::Prefix prefix; Entry * entry; @@ -1309,32 +1324,29 @@ void RoutingManager::DiscoveredPrefixTable::ProcessRouteInfoOption(const Ip6::Nd LogInfo("Processing RIO (%s, %u seconds)", prefix.ToString().AsCString(), aRio.GetRouteLifetime()); - entry = mEntries.FindMatching(Entry::Matcher(prefix, Entry::kTypeRoute)); - - if (aRio.GetRouteLifetime() == 0) - { - VerifyOrExit(entry != nullptr); - - Get().UnpublishExternalRoute(entry->GetPrefix()); - mEntries.Remove(*entry); - - ExitNow(); - } + entry = aRouter.mEntries.FindMatching(Entry::Matcher(prefix, Entry::kTypeRoute)); if (entry == nullptr) { - if (mEntries.IsFull()) + VerifyOrExit(aRio.GetRouteLifetime() != 0); + + entry = AllocateEntry(); + + if (entry == nullptr) { - LogWarn("Discovered too many prefixes, ignore new prefix %s", prefix.ToString().AsCString()); + LogWarn("Discovered too many prefixes, ignore route prefix %s", prefix.ToString().AsCString()); ExitNow(); } - SuccessOrExit(Get().PublishExternalRoute(prefix, aRio.GetPreference())); - entry = mEntries.PushBack(); + entry->InitFrom(aRio); + aRouter.mEntries.Push(*entry); + } + else + { + entry->InitFrom(aRio); } - entry->InitFrom(aRio); - + UpdateNetworkDataOnChangeTo(*entry); mTimer.FireAtIfEarlier(entry->GetExpireTime()); SignalTableChanged(); @@ -1350,59 +1362,83 @@ void RoutingManager::DiscoveredPrefixTable::FindFavoredOnLinkPrefix(Ip6::Prefix aPrefix.Clear(); - for (const Entry &entry : mEntries) + for (const Router &router : mRouters) { - if (!entry.IsOnLinkPrefix() || entry.IsDeprecated()) + for (const Entry &entry : router.mEntries) { - continue; - } + if (!entry.IsOnLinkPrefix() || entry.IsDeprecated()) + { + continue; + } - if ((aPrefix.GetLength() == 0) || (entry.GetPrefix() < aPrefix)) - { - aPrefix = entry.GetPrefix(); + if ((aPrefix.GetLength() == 0) || (entry.GetPrefix() < aPrefix)) + { + aPrefix = entry.GetPrefix(); + } } } } bool RoutingManager::DiscoveredPrefixTable::ContainsOnLinkPrefix(const Ip6::Prefix &aPrefix) const { - return mEntries.ContainsMatching(Entry::Matcher(aPrefix, Entry::kTypeOnLink)); + return ContainsPrefix(Entry::Matcher(aPrefix, Entry::kTypeOnLink)); } bool RoutingManager::DiscoveredPrefixTable::ContainsRoutePrefix(const Ip6::Prefix &aPrefix) const { - return mEntries.ContainsMatching(Entry::Matcher(aPrefix, Entry::kTypeRoute)); + return ContainsPrefix(Entry::Matcher(aPrefix, Entry::kTypeRoute)); +} + +bool RoutingManager::DiscoveredPrefixTable::ContainsPrefix(const Entry::Matcher &aMatcher) const +{ + bool contains = false; + + for (const Router &router : mRouters) + { + if (router.mEntries.ContainsMatching(aMatcher)) + { + contains = true; + break; + } + } + + return contains; } void RoutingManager::DiscoveredPrefixTable::RemoveOnLinkPrefix(const Ip6::Prefix &aPrefix, NetDataMode aNetDataMode) { - RemovePrefix(aPrefix, Entry::kTypeOnLink, aNetDataMode); + RemovePrefix(Entry::Matcher(aPrefix, Entry::kTypeOnLink), aNetDataMode); } void RoutingManager::DiscoveredPrefixTable::RemoveRoutePrefix(const Ip6::Prefix &aPrefix, NetDataMode aNetDataMode) { - RemovePrefix(aPrefix, Entry::kTypeRoute, aNetDataMode); + RemovePrefix(Entry::Matcher(aPrefix, Entry::kTypeRoute), aNetDataMode); } -void RoutingManager::DiscoveredPrefixTable::RemovePrefix(const Ip6::Prefix &aPrefix, - Entry::Type aType, - NetDataMode aNetDataMode) +void RoutingManager::DiscoveredPrefixTable::RemovePrefix(const Entry::Matcher &aMatcher, NetDataMode aNetDataMode) { - // Remove a prefix of given type from the table if there is any. + // Removes all entries matching a given prefix from the table. // `aNetDataMode` specifies behavior when a match is found and // removed. It indicates whether or not to unpublish it from // Network Data. - Entry *entry = mEntries.FindMatching(Entry::Matcher(aPrefix, aType)); + LinkedList removedEntries; - VerifyOrExit(entry != nullptr); + for (Router &router : mRouters) + { + router.mEntries.RemoveAllMatching(aMatcher, removedEntries); + } + + VerifyOrExit(!removedEntries.IsEmpty()); if (aNetDataMode == kUnpublishFromNetData) { - Get().UnpublishExternalRoute(aPrefix); + UnpublishEntry(*removedEntries.GetHead()); } - mEntries.Remove(*entry); + FreeEntries(removedEntries); + RemoveRoutersWithNoEntries(); + SignalTableChanged(); exit: @@ -1414,14 +1450,19 @@ void RoutingManager::DiscoveredPrefixTable::RemoveAllEntries(void) // Remove all entries from the table and unpublish them // from Network Data. - Entry *entry; - - while ((entry = mEntries.PopBack()) != nullptr) + for (Router &router : mRouters) { - Get().UnpublishExternalRoute(entry->GetPrefix()); - SignalTableChanged(); + Entry *entry; + + while ((entry = router.mEntries.Pop()) != nullptr) + { + UnpublishEntry(*entry); + FreeEntry(*entry); + SignalTableChanged(); + } } + RemoveRoutersWithNoEntries(); mTimer.Stop(); } @@ -1430,20 +1471,23 @@ void RoutingManager::DiscoveredPrefixTable::RemoveOrDeprecateOldEntries(TimeMill // Remove route prefix entries and deprecate on-link entries in // the table that are old (not updated since `aTimeThreshold`). - for (Entry &entry : mEntries) + for (Router &router : mRouters) { - if (entry.GetLastUpdateTime() <= aTimeThreshold) + for (Entry &entry : router.mEntries) { - if (entry.IsOnLinkPrefix()) + if (entry.GetLastUpdateTime() <= aTimeThreshold) { - entry.ClearPreferredLifetime(); - } - else - { - entry.ClearValidLifetime(); - } + if (entry.IsOnLinkPrefix()) + { + entry.ClearPreferredLifetime(); + } + else + { + entry.ClearValidLifetime(); + } - SignalTableChanged(); + SignalTableChanged(); + } } } @@ -1460,25 +1504,99 @@ TimeMilli RoutingManager::DiscoveredPrefixTable::CalculateNextStaleTime(TimeMill // prefixes become stale (the latest stale time) but for route // prefixes we consider the earliest stale time. - for (const Entry &entry : mEntries) + for (const Router &router : mRouters) { - TimeMilli entryStaleTime = OT_MAX(aNow, entry.GetStaleTime()); - - if (entry.IsOnLinkPrefix() && !entry.IsDeprecated()) + for (const Entry &entry : router.mEntries) { - onLinkStaleTime = OT_MAX(onLinkStaleTime, entryStaleTime); - foundOnLink = true; - } + TimeMilli entryStaleTime = OT_MAX(aNow, entry.GetStaleTime()); - if (!entry.IsOnLinkPrefix()) - { - routeStaleTime = OT_MIN(routeStaleTime, entryStaleTime); + if (entry.IsOnLinkPrefix() && !entry.IsDeprecated()) + { + onLinkStaleTime = OT_MAX(onLinkStaleTime, entryStaleTime); + foundOnLink = true; + } + + if (!entry.IsOnLinkPrefix()) + { + routeStaleTime = OT_MIN(routeStaleTime, entryStaleTime); + } } } return foundOnLink ? OT_MIN(onLinkStaleTime, routeStaleTime) : routeStaleTime; } +void RoutingManager::DiscoveredPrefixTable::RemoveRoutersWithNoEntries(void) +{ + mRouters.RemoveAllMatching(Router::kContainsNoEntries); +} + +void RoutingManager::DiscoveredPrefixTable::FreeEntries(LinkedList &aEntries) +{ + // Frees all entries in the given list `aEntries` (put them back + // in the entry pool). + + Entry *entry; + + while ((entry = aEntries.Pop()) != nullptr) + { + FreeEntry(*entry); + } +} + +RoutingManager::DiscoveredPrefixTable::Entry *RoutingManager::DiscoveredPrefixTable::FindFavoredEntryToPublish( + const Ip6::Prefix &aPrefix) +{ + // Finds the favored entry matching a given `aPrefix` in the table + // to publish in the Network Data. We can have multiple entries + // in the table matching the same `aPrefix` from different + // routers and potentially with different preference values. We + // select the one with the highest preference as the favored + // entry to publish. + + Entry *favoredEntry = nullptr; + + for (Router &router : mRouters) + { + for (Entry &entry : router.mEntries) + { + if (entry.GetPrefix() != aPrefix) + { + continue; + } + + if ((favoredEntry == nullptr) || (entry.GetPreference() > favoredEntry->GetPreference())) + { + favoredEntry = &entry; + } + } + } + + return favoredEntry; +} + +void RoutingManager::DiscoveredPrefixTable::UpdateNetworkDataOnChangeTo(Entry &aEntry) +{ + // Updates Network Data when there is a change to `aEntry` which + // can be a newly added entry or an existing entry that is + // modified due to processing of a received RA message. + + Entry *favoredEntry = FindFavoredEntryToPublish(aEntry.GetPrefix()); + + OT_ASSERT(favoredEntry != nullptr); + PublishEntry(*favoredEntry); +} + +void RoutingManager::DiscoveredPrefixTable::PublishEntry(const Entry &aEntry) +{ + IgnoreError(Get().PublishExternalRoute(aEntry.GetPrefix(), aEntry.GetPreference())); +} + +void RoutingManager::DiscoveredPrefixTable::UnpublishEntry(const Entry &aEntry) +{ + Get().UnpublishExternalRoute(aEntry.GetPrefix()); +} + void RoutingManager::DiscoveredPrefixTable::HandleTimer(Timer &aTimer) { aTimer.Get().mDiscoveredPrefixTable.HandleTimer(); @@ -1491,28 +1609,48 @@ void RoutingManager::DiscoveredPrefixTable::HandleTimer(void) void RoutingManager::DiscoveredPrefixTable::RemoveExpiredEntries(void) { - TimeMilli now = TimerMilli::GetNow(); - TimeMilli nextExpireTime = now.GetDistantFuture(); + TimeMilli now = TimerMilli::GetNow(); + TimeMilli nextExpireTime = now.GetDistantFuture(); + LinkedList expiredEntries; - for (EntryArray::IndexType index = 0; index < mEntries.GetLength();) + for (Router &router : mRouters) { - Entry &entry = mEntries[index]; + router.mEntries.RemoveAllMatching(Entry::ExpirationChecker(now), expiredEntries); + } - if (entry.GetExpireTime() <= now) + RemoveRoutersWithNoEntries(); + + // Determine if we need to publish/unpublish any prefixes in + // the Network Data. + + for (const Entry &expiredEntry : expiredEntries) + { + Entry *favoredEntry = FindFavoredEntryToPublish(expiredEntry.GetPrefix()); + + if (favoredEntry == nullptr) { - Get().UnpublishExternalRoute(entry.GetPrefix()); - - // Remove the prefix from the array (which replaces it with - // last entry in the array). So in this case, we do not - // increment the `index`. - - mEntries.Remove(entry); - SignalTableChanged(); + UnpublishEntry(expiredEntry); } else + { + PublishEntry(*favoredEntry); + } + } + + if (!expiredEntries.IsEmpty()) + { + SignalTableChanged(); + } + + FreeEntries(expiredEntries); + + // Determine the next expire time and schedule timer. + + for (const Router &router : mRouters) + { + for (const Entry &entry : router.mEntries) { nextExpireTime = OT_MIN(nextExpireTime, entry.GetExpireTime()); - index++; } } @@ -1539,20 +1677,20 @@ void RoutingManager::DiscoveredPrefixTable::Entry::InitFrom(const Ip6::Nd::Prefi { Clear(); aPio.GetPrefix(mPrefix); - mType = kTypeOnLink; - mValidLifetime = aPio.GetValidLifetime(); - mPreferredLifetime = aPio.GetPreferredLifetime(); - mLastUpdateTime = TimerMilli::GetNow(); + mType = kTypeOnLink; + mValidLifetime = aPio.GetValidLifetime(); + mShared.mPreferredLifetime = aPio.GetPreferredLifetime(); + mLastUpdateTime = TimerMilli::GetNow(); } void RoutingManager::DiscoveredPrefixTable::Entry::InitFrom(const Ip6::Nd::RouteInfoOption &aRio) { Clear(); aRio.GetPrefix(mPrefix); - mType = kTypeRoute; - mValidLifetime = aRio.GetRouteLifetime(); - mRoutePreference = aRio.GetPreference(); - mLastUpdateTime = TimerMilli::GetNow(); + mType = kTypeRoute; + mValidLifetime = aRio.GetRouteLifetime(); + mShared.mRoutePreference = aRio.GetPreference(); + mLastUpdateTime = TimerMilli::GetNow(); } bool RoutingManager::DiscoveredPrefixTable::Entry::operator==(const Entry &aOther) const @@ -1565,6 +1703,11 @@ bool RoutingManager::DiscoveredPrefixTable::Entry::Matches(const Matcher &aMatch return (mType == aMatcher.mType) && (mPrefix == aMatcher.mPrefix); } +bool RoutingManager::DiscoveredPrefixTable::Entry::Matches(const ExpirationChecker &aCheker) const +{ + return GetExpireTime() <= aCheker.mNow; +} + TimeMilli RoutingManager::DiscoveredPrefixTable::Entry::GetExpireTime(void) const { return mLastUpdateTime + CalculateExpireDelay(mValidLifetime); @@ -1572,7 +1715,7 @@ TimeMilli RoutingManager::DiscoveredPrefixTable::Entry::GetExpireTime(void) cons TimeMilli RoutingManager::DiscoveredPrefixTable::Entry::GetStaleTime(void) const { - uint32_t delay = OT_MIN(kRtrAdvStaleTime, IsOnLinkPrefix() ? mPreferredLifetime : mValidLifetime); + uint32_t delay = OT_MIN(kRtrAdvStaleTime, IsOnLinkPrefix() ? GetPreferredLifetime() : mValidLifetime); return mLastUpdateTime + TimeMilli::SecToMsec(delay); } @@ -1581,7 +1724,15 @@ bool RoutingManager::DiscoveredPrefixTable::Entry::IsDeprecated(void) const { OT_ASSERT(IsOnLinkPrefix()); - return mLastUpdateTime + TimeMilli::SecToMsec(mPreferredLifetime) <= TimerMilli::GetNow(); + return mLastUpdateTime + TimeMilli::SecToMsec(GetPreferredLifetime()) <= TimerMilli::GetNow(); +} + +RoutingManager::RoutePreference RoutingManager::DiscoveredPrefixTable::Entry::GetPreference(void) const +{ + // Returns the preference level to use when we publish + // the prefix entry in Network Data. + + return IsOnLinkPrefix() ? NetworkData::kRoutePreferenceMedium : GetRoutePreference(); } void RoutingManager::DiscoveredPrefixTable::Entry::AdoptValidAndPreferredLiftimesFrom(const Entry &aEntry) @@ -1608,8 +1759,8 @@ void RoutingManager::DiscoveredPrefixTable::Entry::AdoptValidAndPreferredLiftime mValidLifetime = kTwoHoursInSeconds; } - mPreferredLifetime = aEntry.GetPreferredLifetime(); - mLastUpdateTime = aEntry.GetLastUpdateTime(); + mShared.mPreferredLifetime = aEntry.GetPreferredLifetime(); + mLastUpdateTime = aEntry.GetLastUpdateTime(); } uint32_t RoutingManager::DiscoveredPrefixTable::Entry::CalculateExpireDelay(uint32_t aValidLifetime) diff --git a/src/core/border_router/routing_manager.hpp b/src/core/border_router/routing_manager.hpp index 870c8d4da..f888b6954 100644 --- a/src/core/border_router/routing_manager.hpp +++ b/src/core/border_router/routing_manager.hpp @@ -52,8 +52,10 @@ #include "border_router/infra_if.hpp" #include "common/array.hpp" #include "common/error.hpp" +#include "common/linked_list.hpp" #include "common/locator.hpp" #include "common/notifier.hpp" +#include "common/pool.hpp" #include "common/string.hpp" #include "common/timer.hpp" #include "net/ip6.hpp" @@ -200,9 +202,6 @@ private: // The maximum number of the OMR prefixes to advertise. static constexpr uint8_t kMaxOmrPrefixNum = OPENTHREAD_CONFIG_IP6_SLAAC_NUM_ADDRESSES; - // The maximum number of prefixes to discover on the infra link. - static constexpr uint8_t kMaxDiscoveredPrefixNum = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_PREFIXES; - static constexpr uint8_t kOmrPrefixLength = OT_IP6_PREFIX_BITSIZE; // The length of an OMR prefix. In bits. static constexpr uint8_t kOnLinkPrefixLength = OT_IP6_PREFIX_BITSIZE; // The length of an On-link prefix. In bits. static constexpr uint8_t kBrUlaPrefixLength = 48; // The length of a BR ULA prefix. In bits. @@ -289,10 +288,13 @@ private: TimeMilli CalculateNextStaleTime(TimeMilli aNow) const; private: - static constexpr uint8_t kMaxEntries = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_PREFIXES; + static constexpr uint16_t kMaxRouters = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_ROUTERS; + static constexpr uint16_t kMaxEntries = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_PREFIXES; - struct Entry : private Clearable, public Unequatable + class Entry : public LinkedListEntry, public Unequatable, private Clearable { + friend class LinkedListEntry; + public: enum Type : uint8_t { @@ -312,8 +314,19 @@ private: bool mType; }; + struct ExpirationChecker + { + explicit ExpirationChecker(TimeMilli aNow) + : mNow(aNow) + { + } + + TimeMilli mNow; + }; + void InitFrom(const Ip6::Nd::PrefixInfoOption &aPio); void InitFrom(const Ip6::Nd::RouteInfoOption &aRio); + Type GetType(void) const { return mType; } bool IsOnLinkPrefix(void) const { return (mType == kTypeOnLink); } const Ip6::Prefix &GetPrefix(void) const { return mPrefix; } const TimeMilli & GetLastUpdateTime(void) const { return mLastUpdateTime; } @@ -321,44 +334,71 @@ private: void ClearValidLifetime(void) { mValidLifetime = 0; } TimeMilli GetExpireTime(void) const; TimeMilli GetStaleTime(void) const; + RoutePreference GetPreference(void) const; bool operator==(const Entry &aOther) const; bool Matches(const Matcher &aMatcher) const; + bool Matches(const ExpirationChecker &aCheker) const; // Methods to use when `IsOnLinkPrefix()` - uint32_t GetPreferredLifetime(void) const { return mPreferredLifetime; } - void ClearPreferredLifetime(void) { mPreferredLifetime = 0; } + uint32_t GetPreferredLifetime(void) const { return mShared.mPreferredLifetime; } + void ClearPreferredLifetime(void) { mShared.mPreferredLifetime = 0; } bool IsDeprecated(void) const; void AdoptValidAndPreferredLiftimesFrom(const Entry &aEntry); // Method to use when `!IsOnlinkPrefix()` - RoutePreference GetRoutePreference(void) const { return mRoutePreference; } + RoutePreference GetRoutePreference(void) const { return mShared.mRoutePreference; } private: static uint32_t CalculateExpireDelay(uint32_t aValidLifetime); - Ip6::Prefix mPrefix; - TimeMilli mLastUpdateTime; - uint32_t mValidLifetime; - uint32_t mPreferredLifetime; // Applicable when prefix is on-link. - RoutePreference mRoutePreference; // Applicable when prefix is not on-link - Type mType; + Entry * mNext; + Ip6::Prefix mPrefix; + Type mType; + TimeMilli mLastUpdateTime; + uint32_t mValidLifetime; + union + { + uint32_t mPreferredLifetime; // Applicable when prefix is on-link. + RoutePreference mRoutePreference; // Applicable when prefix is not on-link + } mShared; }; - typedef Array EntryArray; + struct Router + { + enum EmptyChecker : uint8_t + { + kContainsNoEntries + }; - void RemovePrefix(const Ip6::Prefix &aPrefix, Entry::Type aType, NetDataMode aNetDataMode); + bool Matches(const Ip6::Address &aAddress) const { return aAddress == mAddress; } + bool Matches(EmptyChecker) const { return mEntries.IsEmpty(); } - void ProcessPrefixInfoOption(const Ip6::Nd::PrefixInfoOption &aPio); - void ProcessRouteInfoOption(const Ip6::Nd::RouteInfoOption &aRio); + Ip6::Address mAddress; + LinkedList mEntries; + }; + + void ProcessPrefixInfoOption(const Ip6::Nd::PrefixInfoOption &aPio, Router &aRouter); + void ProcessRouteInfoOption(const Ip6::Nd::RouteInfoOption &aRio, Router &aRouter); + bool ContainsPrefix(const Entry::Matcher &aMatcher) const; + void RemovePrefix(const Entry::Matcher &aMatcher, NetDataMode aNetDataMode); + void RemoveRoutersWithNoEntries(void); + Entry * AllocateEntry(void) { return mEntryPool.Allocate(); } + void FreeEntry(Entry &aEntry) { mEntryPool.Free(aEntry); } + void FreeEntries(LinkedList &aEntries); + void UpdateNetworkDataOnChangeTo(Entry &aEntry); + Entry * FindFavoredEntryToPublish(const Ip6::Prefix &aPrefix); + void PublishEntry(const Entry &aEntry); + void UnpublishEntry(const Entry &aEntry); static void HandleTimer(Timer &aTimer); void HandleTimer(void); void RemoveExpiredEntries(void); void SignalTableChanged(void); static void HandleSignalTask(Tasklet &aTasklet); - EntryArray mEntries; - TimerMilli mTimer; - Tasklet mSignalTask; + Array mRouters; + Pool mEntryPool; + TimerMilli mTimer; + Tasklet mSignalTask; }; class OmrPrefix // An OMR Prefix diff --git a/src/core/config/border_router.h b/src/core/config/border_router.h index ef5a3a1e3..b917a0284 100644 --- a/src/core/config/border_router.h +++ b/src/core/config/border_router.h @@ -91,6 +91,16 @@ #define OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE 0 #endif +/** + * @def OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_ROUTERS + * + * Specifies maximum number of routers (on infra link) to track by routing manager. + * + */ +#ifndef OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_ROUTERS +#define OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_ROUTERS 16 +#endif + /** * @def OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_PREFIXES * @@ -98,7 +108,7 @@ * */ #ifndef OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_PREFIXES -#define OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_PREFIXES 8 +#define OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_PREFIXES 64 #endif /**