diff --git a/include/openthread/border_routing.h b/include/openthread/border_routing.h index 92534c087..29f22ddf8 100644 --- a/include/openthread/border_routing.h +++ b/include/openthread/border_routing.h @@ -160,6 +160,19 @@ typedef struct otPdProcessedRaInfo uint32_t mLastPlatformRaMsec; ///< The timestamp of last processed RA message. } otPdProcessedRaInfo; +/** + * Represents the configuration options related to the OMR prefix. + * + * This is used in `otBorderRoutingSetOmrConfig()` to offer manual administration options to explicitly configure + * the OMR prefix or to disable it. + */ +typedef enum +{ + OT_BORDER_ROUTING_OMR_CONFIG_AUTO, ///< BR auto-generates the local OMR prefix. + OT_BORDER_ROUTING_OMR_CONFIG_CUSTOM, ///< BR uses a given custom OMR prefix. + OT_BORDER_ROUTING_OMR_CONFIG_DISABLED, ///< BR does not add local/PD OMR prefix in Network Data. +} otBorderRoutingOmrConfig; + /** * Represents the state of Border Routing Manager. */ @@ -226,6 +239,56 @@ otError otBorderRoutingSetEnabled(otInstance *aInstance, bool aEnabled); */ otBorderRoutingState otBorderRoutingGetState(otInstance *aInstance); +/** + * Configures the OMR prefix handling in the Border Routing Manager. + * + * This function offers manual administration options to explicitly configure the OMR prefix or to disable it. + * + * By default, `OT_BORDER_ROUTING_OMR_CONFIG_AUTO` is used. In this mode, the Border Routing Manager automatically + * selects and manages the OMR prefix. This can involve auto-generating a local prefix or utilizing a prefix obtained + * through DHCPv6 PD (Prefix Delegation), if the feature is enabled. + * + * The `OT_BORDER_ROUTING_OMR_CONFIG_CUSTOM` option enables the use of a user-specified OMR prefix. When this option + * is selected, the @p aOmrPrefix and @p aPreference parameters are used to define the custom OMR prefix and its + * associated preference. These parameters are ignored for other configuration modes, and @p aOmrPrefix can be `NULL`. + * + * The `OT_BORDER_ROUTING_OMR_CONFIG_DISABLED` option disables the Border Routing Manager's management of the OMR + * prefix. The Routing Manager module itself will not add any local or DHCPv6 PD OMR prefixes to the Network Data. + * + * @param[in] aInstance A pointer to the OpenThread instance. + * @param[in] aConfig The desired OMR configuration. + * @param[in] aOmrPrefix A pointer to the custom OMR prefix. Required only when @p aConfig is + * `OT_BORDER_ROUTING_OMR_CONFIG_CUSTOM`. Otherwise, it can be `NULL`. + * @param[in] aPreference The preference associated with the custom OMR prefix. + * + * @retval OT_ERROR_NONE The OMR configuration was successfully set to @p aConfig. + * @retval OT_ERROR_INVALID_ARGS The provided custom OMR prefix (@p aOmrPrefix) is invalid. + */ +otError otBorderRoutingSetOmrConfig(otInstance *aInstance, + otBorderRoutingOmrConfig aConfig, + const otIp6Prefix *aOmrPrefix, + otRoutePreference aPreference); + +/** + * Gets the current OMR prefix configuration mode. + * + * This function retrieves the current OMR configuration and, if a custom OMR prefix is configured, the custom prefix + * and its associated preference. + * + * If the caller does not require the custom OMR prefix and preference, the @p aOmrPrefix and @p aPreference parameters + * can be set to `NULL`. + * + * @param[in] aInstance A pointer to the OpenThread instance. + * @param[out] aOmrPrefix A pointer to an `otIp6Prefix` to return the custom OMR prefix, if the configuration is + * `OT_BORDER_ROUTING_OMR_CONFIG_CUSTOM`. + * @param[out] aPreference A pointer to return the preference associated with the custom OMR prefix. + * + * @return The current OMR prefix configuration mode. + */ +otBorderRoutingOmrConfig otBorderRoutingGetOmrConfig(otInstance *aInstance, + otIp6Prefix *aOmrPrefix, + otRoutePreference *aPreference); + /** * Gets the current preference used when advertising Route Info Options (RIO) in Router Advertisement * messages sent over the infrastructure link. diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 4297df615..49501ca0d 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -52,7 +52,7 @@ extern "C" { * * @note This number versions both OpenThread platform and user APIs. */ -#define OPENTHREAD_API_VERSION (491) +#define OPENTHREAD_API_VERSION (492) /** * @addtogroup api-instance diff --git a/src/cli/README_BR.md b/src/cli/README_BR.md index 2b4e1385e..dcc9b1088 100644 --- a/src/cli/README_BR.md +++ b/src/cli/README_BR.md @@ -33,6 +33,7 @@ Print BR command help menu. counters disable enable +omrconfig omrprefix onlinkprefix pd @@ -117,6 +118,63 @@ RS TxFailed: 0 Done ``` +### omrconfig + +Usage: `br omrconfig` + +Get the current OMR prefix configuration mode. + +The possible modes are: + +- `auto`: BR auto-generates the local OMR prefix. +- `custom`: BR uses a given custom OMR prefix with its associated preference. +- `disabled`: BR does not add local/PD OMR prefix in Network Data. + +```bash +> br omrconfig +auto +Done +``` + +Usage: `br omrconfig auto` + +Set the current OMR prefix configuration mode to `auto`. + +``` +> br omrconfig auto +Done + +> br omrconfig +auto +Done +``` + +Usage: `br omrconfig custom [high|med|low]` + +Set the current OMR prefix configuration mode to `custom` + +``` +> br omrconfig custom fd00::/64 med +Done + +> br omrconfig +custom (fd00:0:0:0::/64, prf:med) +Done +``` + +Usage: `br omrconfig disable` + +Set the current OMR prefix configuration mode to `disabled` + +``` +> br omrconfig disable +Done + +> br omrconfig +disabled +Done +``` + ### omrprefix Usage: `br omrprefix [local|favored]` diff --git a/src/cli/cli_br.cpp b/src/cli/cli_br.cpp index 68108693b..5f0bfa494 100644 --- a/src/cli/cli_br.cpp +++ b/src/cli/cli_br.cpp @@ -174,6 +174,114 @@ exit: return error; } +template <> otError Br::Process(Arg aArgs[]) +{ + otError error = OT_ERROR_NONE; + otIp6Prefix customPrefix; + otRoutePreference preference; + otBorderRoutingOmrConfig omrConfig; + + /** + * @cli br omrconfig + * @code + * br omrconfig + * auto + * Done + * @endcode + * @code + * br omrconfig + * custom (fd00:0:0:0::/64, prf:med) + * Done + * @endcode + * @par + * Outputs current OMR prefix configuration mode. + * @sa otBorderRoutingGetOmrConfig + */ + if (aArgs[0].IsEmpty()) + { + omrConfig = otBorderRoutingGetOmrConfig(GetInstancePtr(), &customPrefix, &preference); + + switch (omrConfig) + { + case OT_BORDER_ROUTING_OMR_CONFIG_AUTO: + OutputLine("auto"); + break; + case OT_BORDER_ROUTING_OMR_CONFIG_CUSTOM: + OutputFormat("custom ("); + OutputIp6Prefix(customPrefix); + OutputLine(", prf:%s)", PreferenceToString(preference)); + break; + case OT_BORDER_ROUTING_OMR_CONFIG_DISABLED: + OutputLine("disabled"); + break; + } + } + else + { + ClearAllBytes(customPrefix); + preference = OT_ROUTE_PREFERENCE_MED; + + /** + * @cli br omrconfig auto + * @code + * br omrconfig auto + * Done + * @endcode + * @par + * Sets OMR prefix configuration mode to `auto` In this mode, the Border Routing Manager automatically + * selects and manages the OMR prefix. + */ + if (aArgs[0] == "auto") + { + omrConfig = OT_BORDER_ROUTING_OMR_CONFIG_AUTO; + VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS); + } + /** + * @cli br omrconfig custom + * @code + * br omrconfig custom fd00::/64 med + * Done + * @endcode + * @cparam br omrconfig custom @ca{prefix} [@ca{high}|@ca{med}|@ca{low}] + * @par + * Sets OMR prefix configuration mode to `custom`. In this mode, a custom OMR prefix and its associated + * preference are used. + */ + else if (aArgs[0] == "custom") + { + omrConfig = OT_BORDER_ROUTING_OMR_CONFIG_CUSTOM; + + SuccessOrExit(error = aArgs[1].ParseAsIp6Prefix(customPrefix)); + SuccessOrExit(error = Interpreter::ParsePreference(aArgs[2], preference)); + VerifyOrExit(aArgs[3].IsEmpty(), error = OT_ERROR_INVALID_ARGS); + } + /** + * @cli br omrconfig disable + * @code + * br omrconfig disable + * Done + * @endcode + * @cparam br omrconfig disable + * @par + * Sets OMR prefix configuration mode to `disable` which prevents the Border Routing Manager from adding any + * local or DHCPv6 PD OMR prefixes to the Network Data. + */ + else if (aArgs[0] == "disable") + { + omrConfig = OT_BORDER_ROUTING_OMR_CONFIG_DISABLED; + } + else + { + ExitNow(error = OT_ERROR_INVALID_ARGS); + } + + error = otBorderRoutingSetOmrConfig(GetInstancePtr(), omrConfig, &customPrefix, preference); + } + +exit: + return error; +} + /** * @cli br omrprefix * @code @@ -925,6 +1033,7 @@ otError Br::Process(Arg aArgs[]) #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE CmdEntry("nat64prefix"), #endif + CmdEntry("omrconfig"), CmdEntry("omrprefix"), CmdEntry("onlinkprefix"), #if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE diff --git a/src/core/api/border_routing_api.cpp b/src/core/api/border_routing_api.cpp index ce5bde85e..3f4ad0e9c 100644 --- a/src/core/api/border_routing_api.cpp +++ b/src/core/api/border_routing_api.cpp @@ -54,6 +54,34 @@ otBorderRoutingState otBorderRoutingGetState(otInstance *aInstance) return MapEnum(AsCoreType(aInstance).Get().GetState()); } +otError otBorderRoutingSetOmrConfig(otInstance *aInstance, + otBorderRoutingOmrConfig aConfig, + const otIp6Prefix *aOmrPrefix, + otRoutePreference aPreference) +{ + return AsCoreType(aInstance).Get().SetOmrConfig( + MapEnum(aConfig), AsCoreTypePtr(aOmrPrefix), + static_cast(aPreference)); +} + +otBorderRoutingOmrConfig otBorderRoutingGetOmrConfig(otInstance *aInstance, + otIp6Prefix *aOmrPrefix, + otRoutePreference *aPreference) +{ + BorderRouter::RoutingManager::RoutePreference preference; + BorderRouter::RoutingManager::OmrConfig omrConfig; + + omrConfig = + AsCoreType(aInstance).Get().GetOmrConfig(AsCoreTypePtr(aOmrPrefix), &preference); + + if (aPreference != nullptr) + { + *aPreference = static_cast(preference); + } + + return MapEnum(omrConfig); +} + otRoutePreference otBorderRoutingGetRouteInfoOptionPreference(otInstance *aInstance) { return static_cast( diff --git a/src/core/border_router/routing_manager.cpp b/src/core/border_router/routing_manager.cpp index faae82ec3..0526668c5 100644 --- a/src/core/border_router/routing_manager.cpp +++ b/src/core/border_router/routing_manager.cpp @@ -494,8 +494,7 @@ bool RoutingManager::IsInitialPolicyEvaluationDone(void) const // the emitted Router Advert message on infrastructure side // and published in the Thread Network Data. - return mIsRunning && !mOmrPrefixManager.GetFavoredPrefix().IsEmpty() && - mOnLinkPrefixManager.IsInitalEvaluationDone(); + return mIsRunning && mOmrPrefixManager.IsInitalEvaluationDone() && mOnLinkPrefixManager.IsInitalEvaluationDone(); } void RoutingManager::ScheduleRoutingPolicyEvaluation(ScheduleMode aMode) @@ -2382,12 +2381,6 @@ bool RoutingManager::FavoredOmrPrefix::IsInfrastructureDerived(void) const return !IsEmpty() && (mPreference >= NetworkData::kRoutePreferenceMedium); } -bool RoutingManager::FavoredOmrPrefix::operator==(const FavoredOmrPrefix &aOther) const -{ - return (mPreference == aOther.mPreference) && (mIsDomainPrefix == aOther.mIsDomainPrefix) && - (mPrefix == aOther.mPrefix); -} - void RoutingManager::FavoredOmrPrefix::SetFrom(const NetworkData::OnMeshPrefixConfig &aOnMeshPrefixConfig) { mPrefix = aOnMeshPrefixConfig.GetPrefix(); @@ -2426,6 +2419,7 @@ bool RoutingManager::FavoredOmrPrefix::IsFavoredOver(const NetworkData::OnMeshPr RoutingManager::OmrPrefixManager::OmrPrefixManager(Instance &aInstance) : InstanceLocator(aInstance) + , mConfig(kOmrConfigAuto) , mIsLocalAddedInNetData(false) , mDefaultRoute(false) { @@ -2454,6 +2448,69 @@ void RoutingManager::OmrPrefixManager::Stop(void) ClearFavoredPrefix(); } +bool RoutingManager::OmrPrefixManager::IsInitalEvaluationDone(void) const +{ + // This method indicates whether or not we are done with the + // initial policy evaluation of the OMR prefix, i.e., either + // we have discovered a favored OMR prefix (added by us or another BR) + // or if `OmrConfig` is set to disable OMR prefix management. + + return !mFavoredPrefix.IsEmpty() || (mConfig == kOmrConfigDisabled); +} + +RoutingManager::OmrConfig RoutingManager::OmrPrefixManager::GetConfig(Ip6::Prefix *aPrefix, + RoutePreference *aPreference) const +{ + if (mConfig == kOmrConfigCustom) + { + if (aPrefix != nullptr) + { + *aPrefix = mCustomPrefix.GetPrefix(); + } + + if (aPreference != nullptr) + { + *aPreference = mCustomPrefix.GetPreference(); + } + } + + return mConfig; +} + +Error RoutingManager::OmrPrefixManager::SetConfig(OmrConfig aConfig, + const Ip6::Prefix *aPrefix, + RoutePreference aPreference) +{ + Error error = kErrorNone; + OmrPrefix customPrefix; + + if (aConfig == kOmrConfigCustom) + { + VerifyOrExit((aPrefix != nullptr) && IsValidOmrPrefix(*aPrefix), error = kErrorInvalidArgs); + + customPrefix.mPrefix = *aPrefix; + customPrefix.mPreference = aPreference; + } + + VerifyOrExit((aConfig != mConfig) || (customPrefix != mCustomPrefix)); + + LogInfo("OMR config: %s -> %s", OmrConfigToString(mConfig), OmrConfigToString(aConfig)); + + if (aConfig == kOmrConfigCustom) + { + LogInfo("OMR custom prefix set to %s (prf:%s)", customPrefix.GetPrefix().ToString().AsCString(), + RoutePreferenceToString(customPrefix.GetPreference())); + } + + mConfig = aConfig; + mCustomPrefix = customPrefix; + + Get().ScheduleRoutingPolicyEvaluation(kImmediately); + +exit: + return error; +} + void RoutingManager::OmrPrefixManager::SetFavordPrefix(const OmrPrefix &aOmrPrefix) { FavoredOmrPrefix oldFavoredPrefix = mFavoredPrefix; @@ -2493,6 +2550,60 @@ void RoutingManager::OmrPrefixManager::DetermineFavoredPrefixInNetData(FavoredOm } } +void RoutingManager::OmrPrefixManager::UpdateLocalPrefix(void) +{ + // Determine the local prefix and remove any outdated previous + // local prefix which may have been added in the Network Data. + + switch (mConfig) + { + case kOmrConfigAuto: +#if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE + if (Get().mPdPrefixManager.HasPrefix()) + { + if (mLocalPrefix.GetPrefix() != Get().mPdPrefixManager.GetPrefix()) + { + RemoveLocalFromNetData(); + mLocalPrefix.mPrefix = Get().mPdPrefixManager.GetPrefix(); + mLocalPrefix.mPreference = PdPrefixManager::kPdRoutePreference; + mLocalPrefix.mIsDomainPrefix = false; + LogInfo("Setting local OMR prefix to PD prefix: %s", mLocalPrefix.GetPrefix().ToString().AsCString()); + } + } + else +#endif + if (mLocalPrefix.GetPrefix() != mGeneratedPrefix) + { + RemoveLocalFromNetData(); + mLocalPrefix.mPrefix = mGeneratedPrefix; + mLocalPrefix.mPreference = RoutePreference::kRoutePreferenceLow; + mLocalPrefix.mIsDomainPrefix = false; + LogInfo("Setting local OMR prefix to generated prefix: %s", + mLocalPrefix.GetPrefix().ToString().AsCString()); + } + + break; + + case kOmrConfigCustom: + if (mLocalPrefix != mCustomPrefix) + { + RemoveLocalFromNetData(); + mLocalPrefix = mCustomPrefix; + LogInfo("Setting local OMR prefix to custom prefix: %s", mLocalPrefix.GetPrefix().ToString().AsCString()); + } + + break; + + case kOmrConfigDisabled: + if (!mLocalPrefix.IsEmpty()) + { + RemoveLocalFromNetData(); + mLocalPrefix.Clear(); + } + break; + } +} + void RoutingManager::OmrPrefixManager::Evaluate(void) { FavoredOmrPrefix favoredPrefix; @@ -2501,32 +2612,16 @@ void RoutingManager::OmrPrefixManager::Evaluate(void) DetermineFavoredPrefixInNetData(favoredPrefix); - // Determine the local prefix and remove outdated prefix published by us. -#if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE - if (Get().mPdPrefixManager.HasPrefix()) - { - if (mLocalPrefix.GetPrefix() != Get().mPdPrefixManager.GetPrefix()) - { - RemoveLocalFromNetData(); - mLocalPrefix.mPrefix = Get().mPdPrefixManager.GetPrefix(); - mLocalPrefix.mPreference = PdPrefixManager::kPdRoutePreference; - mLocalPrefix.mIsDomainPrefix = false; - LogInfo("Setting local OMR prefix to PD prefix: %s", mLocalPrefix.GetPrefix().ToString().AsCString()); - } - } - else -#endif - if (mLocalPrefix.GetPrefix() != mGeneratedPrefix) - { - RemoveLocalFromNetData(); - mLocalPrefix.mPrefix = mGeneratedPrefix; - mLocalPrefix.mPreference = RoutePreference::kRoutePreferenceLow; - mLocalPrefix.mIsDomainPrefix = false; - LogInfo("Setting local OMR prefix to generated prefix: %s", mLocalPrefix.GetPrefix().ToString().AsCString()); - } + UpdateLocalPrefix(); // Decide if we need to add or remove our local OMR prefix. + if (mLocalPrefix.IsEmpty()) + { + SetFavordPrefix(favoredPrefix); + ExitNow(); + } + if (favoredPrefix.IsEmpty() || favoredPrefix.GetPreference() < mLocalPrefix.GetPreference()) { SuccessOrExit(AddLocalToNetData()); @@ -2624,7 +2719,6 @@ void RoutingManager::OmrPrefixManager::RemoveLocalFromNetData(void) if (error != kErrorNone) { LogWarn("Failed to remove %s from Thread Network Data: %s", LocalToString().AsCString(), ErrorToString(error)); - ExitNow(); } mIsLocalAddedInNetData = false; @@ -2687,6 +2781,25 @@ RoutingManager::OmrPrefixManager::InfoString RoutingManager::OmrPrefixManager::F return string; } +const char *RoutingManager::OmrPrefixManager::OmrConfigToString(OmrConfig aConfig) +{ + static const char *const kConfigStrings[] = { + "auto", // (0) kOmrConfigAuto + "custom", // (1) kOmrConfigCustom + "disabled", // (2) kOmrConfigDisabled + }; + + struct EnumCheck + { + InitEnumValidatorCounter(); + ValidateNextEnum(kOmrConfigAuto); + ValidateNextEnum(kOmrConfigCustom); + ValidateNextEnum(kOmrConfigDisabled); + }; + + return kConfigStrings[aConfig]; +} + //--------------------------------------------------------------------------------------------------------------------- // OnLinkPrefixManager diff --git a/src/core/border_router/routing_manager.hpp b/src/core/border_router/routing_manager.hpp index d96a3a07d..698c6e1cb 100644 --- a/src/core/border_router/routing_manager.hpp +++ b/src/core/border_router/routing_manager.hpp @@ -135,6 +135,16 @@ public: kStateRunning = OT_BORDER_ROUTING_STATE_RUNNING, ///< Initialized, enabled, and running. }; + /** + * Represents the admin configuration options related to the OMR prefix. + */ + enum OmrConfig : uint8_t + { + kOmrConfigAuto = OT_BORDER_ROUTING_OMR_CONFIG_AUTO, ///< BR auto-generates the local OMR prefix. + kOmrConfigCustom = OT_BORDER_ROUTING_OMR_CONFIG_CUSTOM, ///< BR uses a given custom OMR prefix. + kOmrConfigDisabled = OT_BORDER_ROUTING_OMR_CONFIG_DISABLED, ///< BR does not add local/PD OMR prefix in NetData. + }; + /** * This enumeration represents the states of DHCPv6 PD in `RoutingManager`. */ @@ -209,6 +219,39 @@ public: */ void RequestStop(void) { Stop(); } + /** + * Configures the OMR prefix handling in the Border Routing Manager. + * + * @param[in] aConfig The desired OMR configuration. + * @param[in] aOmrPrefix A pointer to the custom OMR prefix. Required only when @p aConfig is + * `kOmrConfigCustom`. Otherwise, it can be `nullptr`. + * @param[in] aPreference The preference associated with the custom OMR prefix. + * + * @retval kErrorNone The OMR configuration was successfully set to @p aConfig. + * @retval kErrorInvalidArgs The provided custom OMR prefix (@p aOmrPrefix) is invalid. + */ + Error SetOmrConfig(OmrConfig aConfig, const Ip6::Prefix *aOmrPrefix, RoutePreference aPreference) + { + return mOmrPrefixManager.SetConfig(aConfig, aOmrPrefix, aPreference); + } + + /** + * Gets the current OMR prefix configuration mode. + * + * If the caller does not require the custom OMR prefix and preference, the @p aOmrPrefix and @p aPreference + * parameters can be set to `nullptr`. + * + * @param[out] aOmrPrefix A pointer to an `otIp6Prefix` to return the custom OMR prefix, if the configuration + * is `kOmrConfigCustom`. + * @param[out] aPreference A pointer to return the preference associated with the custom OMR prefix. + * + * @return The current OMR prefix configuration mode. + */ + OmrConfig GetOmrConfig(Ip6::Prefix *aPrefix, RoutePreference *aPreference) const + { + return mOmrPrefixManager.GetConfig(aPrefix, aPreference); + } + /** * Gets the current preference used when advertising Route Info Options (RIO) in Router Advertisement * messages sent over the infrastructure link. @@ -1145,7 +1188,7 @@ private: class OmrPrefixManager; - class OmrPrefix : public Clearable + class OmrPrefix : public Clearable, public Equatable { friend class OmrPrefixManager; @@ -1165,13 +1208,12 @@ private: //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class FavoredOmrPrefix : public OmrPrefix, public Unequatable + class FavoredOmrPrefix : public OmrPrefix { friend class OmrPrefixManager; public: bool IsInfrastructureDerived(void) const; - bool operator==(const FavoredOmrPrefix &aOther) const; private: void SetFrom(const NetworkData::OnMeshPrefixConfig &aOnMeshPrefixConfig); @@ -1189,6 +1231,9 @@ private: void Init(const Ip6::Prefix &aBrUlaPrefix); void Start(void); void Stop(void); + bool IsInitalEvaluationDone(void) const; + OmrConfig GetConfig(Ip6::Prefix *aPrefix, RoutePreference *aPreference) const; + Error SetConfig(OmrConfig aConfig, const Ip6::Prefix *aPrefix, RoutePreference aPreference); void Evaluate(void); void UpdateDefaultRouteFlag(bool aDefaultRoute); bool ShouldAdvertiseLocalAsRio(void) const; @@ -1204,13 +1249,18 @@ private: void SetFavordPrefix(const OmrPrefix &aOmrPrefix); void ClearFavoredPrefix(void) { SetFavordPrefix(OmrPrefix()); } void DetermineFavoredPrefixInNetData(FavoredOmrPrefix &aFavoredPrefix); + void UpdateLocalPrefix(void); Error AddLocalToNetData(void); Error AddOrUpdateLocalInNetData(void); void RemoveLocalFromNetData(void); InfoString LocalToString(void) const; InfoString FavoredToString(const FavoredOmrPrefix &aFavoredPrefix) const; + static const char *OmrConfigToString(OmrConfig aConfig); + + OmrConfig mConfig; OmrPrefix mLocalPrefix; + OmrPrefix mCustomPrefix; Ip6::Prefix mGeneratedPrefix; FavoredOmrPrefix mFavoredPrefix; bool mIsLocalAddedInNetData; @@ -1714,6 +1764,7 @@ template <> void RoutingManager::RxRaTracker::EntryGet().SetEnabled(true)); + + omrConfig = sInstance->Get().GetOmrConfig(nullptr, nullptr); + VerifyOrQuit(omrConfig == kOmrConfigAuto); + + SuccessOrQuit(sInstance->Get().GetOmrPrefix(localOmr)); + + Log("Local OMR prefix is %s", localOmr.ToString().AsCString()); + + sExpectedRios.Add(localOmr); + + AdvanceTime(30000); + + VerifyOrQuit(sRsEmitted); + VerifyOrQuit(sRaValidated); + VerifyOrQuit(sExpectedRios.SawAll()); + VerifyOrQuit(sExpectedRios[0].mLifetime == kRioValidLifetime); + VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceMedium); + + VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false); + VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Update OMR config to disable it + + preference = NetworkData::kRoutePreferenceMedium; + SuccessOrQuit(sInstance->Get().SetOmrConfig(kOmrConfigDisabled, nullptr, preference)); + + omrConfig = sInstance->Get().GetOmrConfig(nullptr, nullptr); + VerifyOrQuit(omrConfig == kOmrConfigDisabled); + + AdvanceTime(100); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Make sure BR emits RA with the new OMR prefix now, and deprecates the old OMR prefix. + + sRaValidated = false; + sExpectedPio = kPioAdvertisingLocalOnLink; + sExpectedRios.Clear(); + sExpectedRios.Add(localOmr); + + AdvanceTime(20 * 1000); + + VerifyOrQuit(sRaValidated); + VerifyOrQuit(sExpectedRios.SawAll()); + VerifyOrQuit(sExpectedRios[0].mLifetime <= kRioDeprecatingLifetime); + VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceLow); + + // Check Network Data. We should now see no OMR prefix in the Network Data. + + VerifyNoOmrPrefixInNetData(); + VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet); + + SuccessOrQuit(sInstance->Get().GetFavoredOmrPrefix(prefix, preference)); + VerifyOrQuit(prefix.GetLength() == 0); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Update OMR config back `kOmrConfigAuto` mode. + + preference = NetworkData::kRoutePreferenceMedium; + SuccessOrQuit(sInstance->Get().SetOmrConfig(kOmrConfigAuto, nullptr, preference)); + + omrConfig = sInstance->Get().GetOmrConfig(nullptr, nullptr); + VerifyOrQuit(omrConfig == kOmrConfigAuto); + + AdvanceTime(100); + + sRaValidated = false; + sExpectedPio = kPioAdvertisingLocalOnLink; + sExpectedRios.Clear(); + sExpectedRios.Add(localOmr); + + AdvanceTime(30 * 1000); + + VerifyOrQuit(sRaValidated); + VerifyOrQuit(sExpectedRios.SawAll()); + VerifyOrQuit(sExpectedRios[0].mLifetime == kRioValidLifetime); + VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceMedium); + + VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false); + VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Update OMR config to `kOmrConfigCustom` mode to use a custom prefix + + preference = NetworkData::kRoutePreferenceMedium; + SuccessOrQuit( + sInstance->Get().SetOmrConfig(kOmrConfigCustom, &customPrefix, preference)); + + omrConfig = sInstance->Get().GetOmrConfig(&prefix, &preference); + VerifyOrQuit(omrConfig == kOmrConfigCustom); + VerifyOrQuit(prefix == customPrefix); + VerifyOrQuit(preference == NetworkData::kRoutePreferenceMedium); + + AdvanceTime(100); + + sRaValidated = false; + sExpectedPio = kPioAdvertisingLocalOnLink; + sExpectedRios.Clear(); + sExpectedRios.Add(customPrefix); + sExpectedRios.Add(localOmr); + + AdvanceTime(60 * 1000); + + VerifyOrQuit(sRaValidated); + VerifyOrQuit(sExpectedRios.SawAll()); + VerifyOrQuit(sExpectedRios[0].mLifetime == kRioValidLifetime); + VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceMedium); + VerifyOrQuit(sExpectedRios[1].mLifetime <= kRioDeprecatingLifetime); + VerifyOrQuit(sExpectedRios[1].mPreference == NetworkData::kRoutePreferenceLow); + + VerifyOmrPrefixInNetData(customPrefix, /* aDefaultRoute */ false, &preference); + VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Update the custom prefix preference value to high. + + preference = NetworkData::kRoutePreferenceHigh; + SuccessOrQuit( + sInstance->Get().SetOmrConfig(kOmrConfigCustom, &customPrefix, preference)); + + omrConfig = sInstance->Get().GetOmrConfig(&prefix, &preference); + VerifyOrQuit(omrConfig == kOmrConfigCustom); + VerifyOrQuit(prefix == customPrefix); + VerifyOrQuit(preference == NetworkData::kRoutePreferenceHigh); + + AdvanceTime(100); + + sRaValidated = false; + sExpectedPio = kPioAdvertisingLocalOnLink; + sExpectedRios.Clear(); + sExpectedRios.Add(customPrefix); + sExpectedRios.Add(localOmr); + + AdvanceTime(60 * 1000); + + VerifyOrQuit(sRaValidated); + VerifyOrQuit(sExpectedRios.SawAll()); + VerifyOrQuit(sExpectedRios[0].mLifetime == kRioValidLifetime); + VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceMedium); + VerifyOrQuit(sExpectedRios[1].mLifetime <= kRioDeprecatingLifetime); + VerifyOrQuit(sExpectedRios[1].mPreference == NetworkData::kRoutePreferenceLow); + + VerifyOmrPrefixInNetData(customPrefix, /* aDefaultRoute */ false, &preference); + VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Wait for previous local OMR to be fully deprecated and validate that is no + // longer seen in the emitted RA. + + AdvanceTime(350 * 1000); + + sRaValidated = false; + sExpectedPio = kPioAdvertisingLocalOnLink; + sExpectedRios.Add(customPrefix); + + AdvanceTime(200 * 1000); + + VerifyOrQuit(sRaValidated); + VerifyOrQuit(sExpectedRios.SawAll()); + + VerifyOmrPrefixInNetData(customPrefix, /* aDefaultRoute */ false, &preference); + + SuccessOrQuit(sInstance->Get().GetFavoredOmrPrefix(prefix, preference)); + VerifyOrQuit(prefix == customPrefix); + VerifyOrQuit(preference == NetworkData::kRoutePreferenceHigh); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Switch back to `kOmrConfigDiable` mode. Check that custom prefix is + // removed from Network Data and we see it deprecating in emitted RAs. + + SuccessOrQuit(sInstance->Get().SetOmrConfig(kOmrConfigDisabled, nullptr, preference)); + + omrConfig = sInstance->Get().GetOmrConfig(nullptr, nullptr); + VerifyOrQuit(omrConfig == kOmrConfigDisabled); + + AdvanceTime(100); + + sRaValidated = false; + sExpectedPio = kPioAdvertisingLocalOnLink; + sExpectedRios.Clear(); + sExpectedRios.Add(customPrefix); + + AdvanceTime(60 * 1000); + + VerifyOrQuit(sRaValidated); + VerifyOrQuit(sExpectedRios.SawAll()); + VerifyOrQuit(sExpectedRios[0].mLifetime <= kRioDeprecatingLifetime); + VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceLow); + + VerifyNoOmrPrefixInNetData(); + VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet); + + SuccessOrQuit(sInstance->Get().GetFavoredOmrPrefix(prefix, preference)); + VerifyOrQuit(prefix.GetLength() == 0); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Switch back to `kOmrConfigAuto` mode. + + SuccessOrQuit(sInstance->Get().SetOmrConfig(kOmrConfigAuto, nullptr, preference)); + + omrConfig = sInstance->Get().GetOmrConfig(nullptr, nullptr); + VerifyOrQuit(omrConfig == kOmrConfigAuto); + + AdvanceTime(100); + + sRaValidated = false; + sExpectedPio = kPioAdvertisingLocalOnLink; + sExpectedRios.Clear(); + sExpectedRios.Add(localOmr); + sExpectedRios.Add(customPrefix); + + AdvanceTime(60 * 1000); + + VerifyOrQuit(sRaValidated); + VerifyOrQuit(sExpectedRios.SawAll()); + VerifyOrQuit(sExpectedRios[0].mLifetime == kRioValidLifetime); + VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceMedium); + VerifyOrQuit(sExpectedRios[1].mLifetime <= kRioDeprecatingLifetime); + VerifyOrQuit(sExpectedRios[1].mPreference == NetworkData::kRoutePreferenceLow); + + preference = NetworkData::kRoutePreferenceLow; + VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false, &preference); + VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet); + + SuccessOrQuit(sInstance->Get().GetFavoredOmrPrefix(prefix, preference)); + VerifyOrQuit(prefix == localOmr); + VerifyOrQuit(preference == NetworkData::kRoutePreferenceLow); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + SuccessOrQuit(sInstance->Get().SetEnabled(false)); + VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength()); + + Log("End of TestOmrConfig"); + FinalizeTest(); +} + void TestDefaultRoute(void) { Ip6::Prefix localOnLink; @@ -4714,6 +4987,7 @@ int main(void) #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE ot::TestSamePrefixesFromMultipleRouters(); ot::TestOmrSelection(); + ot::TestOmrConfig(); ot::TestDefaultRoute(); ot::TestAdvNonUlaRoute(); ot::TestFavoredOnLinkPrefix();