From 04feddc4586b1780c4108023a8e7dee7cb697700 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 11 Oct 2022 12:57:33 -0700 Subject: [PATCH] [netdata] update `Publisher` to reserve entries for `RoutingManager` (#8148) This commit updates `NetworkData::Publisher` to reserve a set of prefix entries for use by `RoutingManager` only. This allow us to simplify how `RoutingManager` publishes route prefixes in Network Data (assert on failure). In particular, this commit defines a new enum `Requester` which specifies the requester (`kFromUser` or `kFromRoutingManager`) associated with a published prefix. This is used by methods `PublishExternalRoute()`/`PublishOnMeshPrefix()`. When allocating new entries, we ensure that each requester is limited to its maximum number of entries. --- src/core/api/netdata_publisher_api.cpp | 6 ++- src/core/border_router/routing_manager.cpp | 29 ++++------ src/core/border_router/routing_manager.hpp | 34 ++++++++---- src/core/config/netdata_publisher.h | 9 +--- src/core/thread/network_data_publisher.cpp | 63 ++++++++++++++++------ src/core/thread/network_data_publisher.hpp | 56 ++++++++++++------- 6 files changed, 122 insertions(+), 75 deletions(-) diff --git a/src/core/api/netdata_publisher_api.cpp b/src/core/api/netdata_publisher_api.cpp index 559734be2..035243390 100644 --- a/src/core/api/netdata_publisher_api.cpp +++ b/src/core/api/netdata_publisher_api.cpp @@ -82,12 +82,14 @@ void otNetDataUnpublishDnsSrpService(otInstance *aInstance) otError otNetDataPublishOnMeshPrefix(otInstance *aInstance, const otBorderRouterConfig *aConfig) { - return AsCoreType(aInstance).Get().PublishOnMeshPrefix(AsCoreType(aConfig)); + return AsCoreType(aInstance).Get().PublishOnMeshPrefix(AsCoreType(aConfig), + NetworkData::Publisher::kFromUser); } otError otNetDataPublishExternalRoute(otInstance *aInstance, const otExternalRouteConfig *aConfig) { - return AsCoreType(aInstance).Get().PublishExternalRoute(AsCoreType(aConfig)); + return AsCoreType(aInstance).Get().PublishExternalRoute(AsCoreType(aConfig), + NetworkData::Publisher::kFromUser); } bool otNetDataIsPrefixAdded(otInstance *aInstance, const otIp6Prefix *aPrefix) diff --git a/src/core/border_router/routing_manager.cpp b/src/core/border_router/routing_manager.cpp index cff6c26d9..727e79609 100644 --- a/src/core/border_router/routing_manager.cpp +++ b/src/core/border_router/routing_manager.cpp @@ -458,9 +458,8 @@ exit: return; } -Error RoutingManager::PublishExternalRoute(const Ip6::Prefix &aPrefix, RoutePreference aRoutePreference, bool aNat64) +void RoutingManager::PublishExternalRoute(const Ip6::Prefix &aPrefix, RoutePreference aRoutePreference, bool aNat64) { - Error error; NetworkData::ExternalRouteConfig routeConfig; OT_ASSERT(mIsRunning); @@ -471,14 +470,8 @@ Error RoutingManager::PublishExternalRoute(const Ip6::Prefix &aPrefix, RoutePref routeConfig.mNat64 = aNat64; routeConfig.mPreference = aRoutePreference; - error = Get().PublishExternalRoute(routeConfig); - - if (error != kErrorNone) - { - LogWarn("Failed to publish external route %s: %s", aPrefix.ToString().AsCString(), ErrorToString(error)); - } - - return error; + SuccessOrAssert( + Get().PublishExternalRoute(routeConfig, NetworkData::Publisher::kFromRoutingManager)); } void RoutingManager::UnpublishExternalRoute(const Ip6::Prefix &aPrefix) @@ -507,7 +500,7 @@ void RoutingManager::EvaluateOnLinkPrefix(void) // and therefore is the same for all BRs on the same Thread // mesh. - SuccessOrExit(mLocalOnLinkPrefix.Advertise()); + mLocalOnLinkPrefix.Advertise(); // We remove the local on-link prefix from discovered prefix // table, in case it was previously discovered and included in @@ -1616,7 +1609,7 @@ exit: void RoutingManager::DiscoveredPrefixTable::PublishEntry(const Entry &aEntry) { - IgnoreError(Get().PublishExternalRoute(aEntry.GetPrefix(), aEntry.GetPreference())); + Get().PublishExternalRoute(aEntry.GetPrefix(), aEntry.GetPreference()); } void RoutingManager::DiscoveredPrefixTable::UnpublishEntry(const Entry &aEntry) @@ -2015,24 +2008,22 @@ exit: return; } -Error RoutingManager::LocalOnLinkPrefix::Advertise(void) +void RoutingManager::LocalOnLinkPrefix::Advertise(void) { // Start advertising the local on-link prefix if not already. This // will also publish it in the Network Data as an external route // entry. - Error error = kErrorNone; - VerifyOrExit(mState != kAdvertising); - SuccessOrExit(error = Get().PublishExternalRoute(mPrefix, NetworkData::kRoutePreferenceMedium)); + Get().PublishExternalRoute(mPrefix, NetworkData::kRoutePreferenceMedium); mState = kAdvertising; mExpireTime = TimerMilli::GetNow() + TimeMilli::SecToMsec(kDefaultOnLinkPrefixLifetime); LogInfo("Start advertising on-link prefix %s", mPrefix.ToString().AsCString()); exit: - return error; + return; } void RoutingManager::LocalOnLinkPrefix::Deprecate(void) @@ -2316,9 +2307,9 @@ void RoutingManager::Nat64PrefixManager::Evaluate(void) mPublishedPrefix.Clear(); } - if (shouldPublish && (prefix != mPublishedPrefix) && - (Get().PublishExternalRoute(prefix, preference, /* aNat64 */ true) == kErrorNone)) + if (shouldPublish && (prefix != mPublishedPrefix)) { + Get().PublishExternalRoute(prefix, preference, /* aNat64 */ true); mPublishedPrefix = prefix; } diff --git a/src/core/border_router/routing_manager.hpp b/src/core/border_router/routing_manager.hpp index ea5626ee3..c548e4129 100644 --- a/src/core/border_router/routing_manager.hpp +++ b/src/core/border_router/routing_manager.hpp @@ -85,6 +85,20 @@ public: typedef otBorderRoutingPrefixTableIterator PrefixTableIterator; ///< Prefix Table Iterator. typedef otBorderRoutingPrefixTableEntry PrefixTableEntry; ///< Prefix Table Entry. + /** + * This constant specifies the maximum number of route prefixes that may be published by `RoutingManager` + * in Thread Network Data. + * + * This is used by `NetworkData::Publisher` to reserve entries for use by `RoutingManager`. + * + * The number of published entries accounts for: + * - Max number of discovered prefix entries, + * - Two entries for local on-link prefixes (current prefix and old one deprecating on extended PAN ID change), + * - One entry for NAT64 published prefix. + * + */ + static constexpr uint16_t kMaxPublishedPrefixes = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_PREFIXES + 3; + /** * This constructor initializes the routing manager. * @@ -605,7 +619,7 @@ private: void Generate(void); void Start(void); void Stop(void); - Error Advertise(void); + void Advertise(void); void Deprecate(void); void AppendAsPiosTo(Ip6::Nd::RouterAdvertMessage &aRaMessage); const Ip6::Prefix &GetPrefix(void) const { return mPrefix; } @@ -747,15 +761,15 @@ private: bool IsEnabled(void) const { return mIsEnabled; } Error LoadOrGenerateRandomBrUlaPrefix(void); - void EvaluateOnLinkPrefix(void); - void EvaluateRoutingPolicy(void); - bool IsInitalPolicyEvaluationDone(void) const; - void ScheduleRoutingPolicyEvaluation(ScheduleMode aMode); - void EvaluateOmrPrefix(void); - Error PublishExternalRoute(const Ip6::Prefix &aPrefix, RoutePreference aRoutePreference, bool aNat64 = false); - void UnpublishExternalRoute(const Ip6::Prefix &aPrefix); - void HandleRsSenderFinished(TimeMilli aStartTime); - void SendRouterAdvertisement(RouterAdvTxMode aRaTxMode); + void EvaluateOnLinkPrefix(void); + void EvaluateRoutingPolicy(void); + bool IsInitalPolicyEvaluationDone(void) const; + void ScheduleRoutingPolicyEvaluation(ScheduleMode aMode); + void EvaluateOmrPrefix(void); + void PublishExternalRoute(const Ip6::Prefix &aPrefix, RoutePreference aRoutePreference, bool aNat64 = false); + void UnpublishExternalRoute(const Ip6::Prefix &aPrefix); + void HandleRsSenderFinished(TimeMilli aStartTime); + void SendRouterAdvertisement(RouterAdvTxMode aRaTxMode); void HandleDiscoveredPrefixStaleTimer(void); diff --git a/src/core/config/netdata_publisher.h b/src/core/config/netdata_publisher.h index 21fcdb56c..ee8fe583a 100644 --- a/src/core/config/netdata_publisher.h +++ b/src/core/config/netdata_publisher.h @@ -148,17 +148,12 @@ /** * @def OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES * - * Specifies maximum number of prefix (on-mesh prefix or external route) entries supported by Publisher. + * Specifies maximum number of prefix (on-mesh prefix or external route) entries reserved by Publisher for use by + * user (through OT public APIs). * */ #ifndef OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES - -#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE -#define OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES \ - (OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_PREFIXES + 5) -#else #define OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES 3 #endif -#endif #endif // CONFIG_NETDATA_PUBLISHER_H_ diff --git a/src/core/thread/network_data_publisher.cpp b/src/core/thread/network_data_publisher.cpp index 0b19446c7..4c79ef305 100644 --- a/src/core/thread/network_data_publisher.cpp +++ b/src/core/thread/network_data_publisher.cpp @@ -87,7 +87,7 @@ void Publisher::SetPrefixCallback(PrefixCallback aCallback, void *aContext) mPrefixCallbackContext = aContext; } -Error Publisher::PublishOnMeshPrefix(const OnMeshPrefixConfig &aConfig) +Error Publisher::PublishOnMeshPrefix(const OnMeshPrefixConfig &aConfig, Requester aRequester) { Error error = kErrorNone; PrefixEntry *entry; @@ -95,16 +95,16 @@ Error Publisher::PublishOnMeshPrefix(const OnMeshPrefixConfig &aConfig) VerifyOrExit(aConfig.IsValid(GetInstance()), error = kErrorInvalidArgs); VerifyOrExit(aConfig.mStable, error = kErrorInvalidArgs); - entry = FindOrAllocatePrefixEntry(aConfig.GetPrefix()); + entry = FindOrAllocatePrefixEntry(aConfig.GetPrefix(), aRequester); VerifyOrExit(entry != nullptr, error = kErrorNoBufs); - entry->Publish(aConfig); + entry->Publish(aConfig, aRequester); exit: return error; } -Error Publisher::PublishExternalRoute(const ExternalRouteConfig &aConfig) +Error Publisher::PublishExternalRoute(const ExternalRouteConfig &aConfig, Requester aRequester) { Error error = kErrorNone; PrefixEntry *entry; @@ -112,10 +112,10 @@ Error Publisher::PublishExternalRoute(const ExternalRouteConfig &aConfig) VerifyOrExit(aConfig.IsValid(GetInstance()), error = kErrorInvalidArgs); VerifyOrExit(aConfig.mStable, error = kErrorInvalidArgs); - entry = FindOrAllocatePrefixEntry(aConfig.GetPrefix()); + entry = FindOrAllocatePrefixEntry(aConfig.GetPrefix(), aRequester); VerifyOrExit(entry != nullptr, error = kErrorNoBufs); - entry->Publish(aConfig); + entry->Publish(aConfig, aRequester); exit: return error; @@ -149,24 +149,48 @@ exit: return error; } -Publisher::PrefixEntry *Publisher::FindOrAllocatePrefixEntry(const Ip6::Prefix &aPrefix) +Publisher::PrefixEntry *Publisher::FindOrAllocatePrefixEntry(const Ip6::Prefix &aPrefix, Requester aRequester) { // Returns a matching prefix entry if found, otherwise tries // to allocate a new entry. - PrefixEntry *prefixEntry = FindMatchingPrefixEntry(aPrefix); - - VerifyOrExit(prefixEntry == nullptr); + PrefixEntry *prefixEntry = nullptr; + uint16_t numEntries = 0; + uint8_t maxEntries = 0; for (PrefixEntry &entry : mPrefixEntries) { - if (!entry.IsInUse()) + if (entry.IsInUse()) + { + if (entry.GetRequester() == aRequester) + { + numEntries++; + } + + if (entry.Matches(aPrefix)) + { + prefixEntry = &entry; + ExitNow(); + } + } + else if (prefixEntry == nullptr) { prefixEntry = &entry; - ExitNow(); } } + switch (aRequester) + { + case kFromUser: + maxEntries = kMaxUserPrefixEntries; + break; + case kFromRoutingManager: + maxEntries = kMaxRoutingManagerPrefixEntries; + break; + } + + VerifyOrExit(numEntries < maxEntries, prefixEntry = nullptr); + exit: return prefixEntry; } @@ -786,22 +810,27 @@ Publisher::DnsSrpServiceEntry::Info::Info(Type aType, uint16_t aPortOrSeqNumber, //--------------------------------------------------------------------------------------------------------------------- // Publisher::PrefixEntry -void Publisher::PrefixEntry::Publish(const OnMeshPrefixConfig &aConfig) +void Publisher::PrefixEntry::Publish(const OnMeshPrefixConfig &aConfig, Requester aRequester) { LogInfo("Publishing OnMeshPrefix %s", aConfig.GetPrefix().ToString().AsCString()); - Publish(aConfig.GetPrefix(), aConfig.ConvertToTlvFlags(), kTypeOnMeshPrefix); + Publish(aConfig.GetPrefix(), aConfig.ConvertToTlvFlags(), kTypeOnMeshPrefix, aRequester); } -void Publisher::PrefixEntry::Publish(const ExternalRouteConfig &aConfig) +void Publisher::PrefixEntry::Publish(const ExternalRouteConfig &aConfig, Requester aRequester) { LogInfo("Publishing ExternalRoute %s", aConfig.GetPrefix().ToString().AsCString()); - Publish(aConfig.GetPrefix(), aConfig.ConvertToTlvFlags(), kTypeExternalRoute); + Publish(aConfig.GetPrefix(), aConfig.ConvertToTlvFlags(), kTypeExternalRoute, aRequester); } -void Publisher::PrefixEntry::Publish(const Ip6::Prefix &aPrefix, uint16_t aNewFlags, Type aNewType) +void Publisher::PrefixEntry::Publish(const Ip6::Prefix &aPrefix, + uint16_t aNewFlags, + Type aNewType, + Requester aRequester) { + mRequester = aRequester; + if (GetState() != kNoEntry) { // If this is an existing entry, first we check that there is diff --git a/src/core/thread/network_data_publisher.hpp b/src/core/thread/network_data_publisher.hpp index 3c5a9b59b..e0801b806 100644 --- a/src/core/thread/network_data_publisher.hpp +++ b/src/core/thread/network_data_publisher.hpp @@ -43,14 +43,9 @@ "or OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE" #endif -#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE && (OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES < \ - (OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_PREFIXES + 4)) -#error "OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES needs to support more entries when "\ - "OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE is enabled to accommodate for max on-link prefixes" -#endif - #include +#include "border_router/routing_manager.hpp" #include "common/clearable.hpp" #include "common/equatable.hpp" #include "common/error.hpp" @@ -87,6 +82,16 @@ public: kEventEntryRemoved = OT_NETDATA_PUBLISHER_EVENT_ENTRY_REMOVED, ///< Entry is removed from Network Data. }; + /** + * This enumeration represents the requester associated with a published prefix. + * + */ + enum Requester : uint8_t + { + kFromUser, ///< Requested by user (public OT API). + kFromRoutingManager, ///< Requested by `RoutingManager` module. + }; + /** * This constructor initializes `Publisher` object. * @@ -222,6 +227,7 @@ public: * same prefix with the same or higher preference. * * @param[in] aConfig The on-mesh prefix config to publish. + * @param[in] aRequester The requester (`kFromUser` or `kFromRoutingManager` module). * * @retval kErrorNone The on-mesh prefix is published successfully. * @retval kErrorInvalidArgs The @p aConfig is not valid (bad prefix, invalid flag combinations, or not stable). @@ -232,7 +238,7 @@ public: * * */ - Error PublishOnMeshPrefix(const OnMeshPrefixConfig &aConfig); + Error PublishOnMeshPrefix(const OnMeshPrefixConfig &aConfig, Requester aRequester); /** * This method requests an external route prefix to be published in the Thread Network Data. @@ -247,6 +253,7 @@ public: * same prefix with the same or higher preference. * * @param[in] aConfig The external route config to publish. + * @param[in] aRequester The requester (`kFromUser` or `kFromRoutingManager` module). * * @retval kErrorNone The external route is published successfully. * @retval kErrorInvalidArgs The @p aConfig is not valid (bad prefix, invalid flag combinations, or not stable). @@ -256,7 +263,7 @@ public: * * */ - Error PublishExternalRoute(const ExternalRouteConfig &aConfig); + Error PublishExternalRoute(const ExternalRouteConfig &aConfig, Requester aRequester); /** * This method indicates whether or not currently a published prefix entry (on-mesh or external route) is added to @@ -401,22 +408,30 @@ private: #endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE + // Max number of prefix (on-mesh or external route) entries. - static constexpr uint16_t kMaxPrefixEntries = OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES; + static constexpr uint16_t kMaxUserPrefixEntries = OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES; + +#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE + static constexpr uint16_t kMaxRoutingManagerPrefixEntries = BorderRouter::RoutingManager::kMaxPublishedPrefixes; +#else + static constexpr uint16_t kMaxRoutingManagerPrefixEntries = 0; +#endif class PrefixEntry : public Entry, private NonCopyable { friend class Entry; public: - void Init(Instance &aInstance) { Entry::Init(aInstance); } - bool IsInUse(void) const { return GetState() != kNoEntry; } - bool Matches(const Ip6::Prefix &aPrefix) const { return mPrefix == aPrefix; } - void Publish(const OnMeshPrefixConfig &aConfig); - void Publish(const ExternalRouteConfig &aConfig); - void Unpublish(void); - void HandleTimer(void) { Entry::HandleTimer(); } - void HandleNotifierEvents(Events aEvents); + void Init(Instance &aInstance) { Entry::Init(aInstance); } + bool IsInUse(void) const { return GetState() != kNoEntry; } + bool Matches(const Ip6::Prefix &aPrefix) const { return mPrefix == aPrefix; } + void Publish(const OnMeshPrefixConfig &aConfig, Requester aRequester); + void Publish(const ExternalRouteConfig &aConfig, Requester aRequester); + Requester GetRequester(void) const { return mRequester; } + void Unpublish(void); + void HandleTimer(void) { Entry::HandleTimer(); } + void HandleNotifierEvents(Events aEvents); private: static constexpr uint8_t kDesiredNumOnMeshPrefix = @@ -431,7 +446,7 @@ private: kTypeExternalRoute, }; - void Publish(const Ip6::Prefix &aPrefix, uint16_t aNewFlags, Type aNewType); + void Publish(const Ip6::Prefix &aPrefix, uint16_t aNewFlags, Type aNewType, Requester aRequester); void Add(void); Error AddOnMeshPrefix(void); Error AddExternalRoute(void); @@ -441,6 +456,7 @@ private: void CountExternalRouteEntries(uint8_t &aNumEntries, uint8_t &aNumPreferredEntries) const; Type mType; + Requester mRequester; Ip6::Prefix mPrefix; uint16_t mFlags; }; @@ -451,7 +467,7 @@ private: #endif #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE - PrefixEntry * FindOrAllocatePrefixEntry(const Ip6::Prefix &aPrefix); + PrefixEntry * FindOrAllocatePrefixEntry(const Ip6::Prefix &aPrefix, Requester aRequester); PrefixEntry * FindMatchingPrefixEntry(const Ip6::Prefix &aPrefix); const PrefixEntry *FindMatchingPrefixEntry(const Ip6::Prefix &aPrefix) const; bool IsAPrefixEntry(const Entry &aEntry) const; @@ -469,7 +485,7 @@ private: #endif #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE - PrefixEntry mPrefixEntries[kMaxPrefixEntries]; + PrefixEntry mPrefixEntries[kMaxUserPrefixEntries + kMaxRoutingManagerPrefixEntries]; PrefixCallback mPrefixCallback; void * mPrefixCallbackContext; #endif