diff --git a/include/openthread/border_routing.h b/include/openthread/border_routing.h index 4801d869e..79be8e167 100644 --- a/include/openthread/border_routing.h +++ b/include/openthread/border_routing.h @@ -141,23 +141,27 @@ otError otBorderRoutingInit(otInstance *aInstance, uint32_t aInfraIfIndex, bool otError otBorderRoutingSetEnabled(otInstance *aInstance, bool aEnabled); /** - * This function gets the preference used when advertising Route Info Options (e.g., for discovered OMR prefixes) in - * Router Advertisement messages sent over the infrastructure link. + * This function gets the current preference used when advertising Route Info Options (RIO) in Router Advertisement + * messages sent over the infrastructure link. * - * @param[in] aInstance A pointer to an OpenThread instance. + * The RIO preference is determined as follows: * - * @returns The OMR prefix advertisement preference. + * - If explicitly set by user by calling `otBorderRoutingSetRouteInfoOptionPreference()`, the given preference is + * used. + * - Otherwise, it is determined based on device's current role: Medium preference when in router/leader role and + * low preference when in child role. + * + * @returns The current Route Info Option preference. * */ otRoutePreference otBorderRoutingGetRouteInfoOptionPreference(otInstance *aInstance); /** - * This function sets the preference to use when advertising Route Info Options in Router Advertisement messages sent - * over the infrastructure link, for example for discovered OMR prefixes. + * This function explicitly sets the preference to use when advertising Route Info Options (RIO) in Router + * Advertisement messages sent over the infrastructure link. * - * By default BR will use `medium` preference level, but this function allows the default value to be changed. As an - * example, it can be set to `low` preference in the case where device is a temporary BR (a mobile BR or a - * battery-powered BR) to indicate that other BRs (if any) should be preferred over this BR on the infrastructure link. + * After a call to this function, BR will use the given preference for all its advertised RIOs. The preference can be + * cleared by calling `otBorderRoutingClearRouteInfoOptionPreference()`. * * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aPreference The route preference to use. @@ -165,6 +169,17 @@ otRoutePreference otBorderRoutingGetRouteInfoOptionPreference(otInstance *aInsta */ void otBorderRoutingSetRouteInfoOptionPreference(otInstance *aInstance, otRoutePreference aPreference); +/** + * This function clears a previously set preference value for advertised Route Info Options. + * + * After a call to this function, BR will use device's role to determine the RIO preference: Medium preference when + * in router/leader role and low preference when in child role. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + */ +void otBorderRoutingClearRouteInfoOptionPreference(otInstance *aInstance); + /** * Gets the local Off-Mesh-Routable (OMR) Prefix, for example `fdfc:1ff5:1512:5622::/64`. * diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 1a809bc19..ced184f73 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (272) +#define OPENTHREAD_API_VERSION (273) /** * @addtogroup api-instance diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index fea81b9ac..2524ad0ab 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -652,28 +652,48 @@ template <> otError Interpreter::Process(Arg aArgs[]) OutputLine(" prf:%s", PreferenceToString(preference)); } #endif // OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE - /** - * @cli br rioprf (high,med,low) - * @code - * br rioprf - * med - * Done - * @endcode - * @code - * br rioprf low - * Done - * @endcode - * @cparam br rioprf [@ca{high}|@ca{med}|@ca{low}] - * @par api_copy - * #otBorderRoutingSetRouteInfoOptionPreference - * - */ else if (aArgs[0] == "rioprf") { + /** + * @cli br rioprf + * @code + * br rioprf + * med + * Done + * @endcode + * @par api_copy + * #otBorderRoutingGetRouteInfoOptionPreference + * + */ if (aArgs[1].IsEmpty()) { OutputLine("%s", PreferenceToString(otBorderRoutingGetRouteInfoOptionPreference(GetInstancePtr()))); } + /** + * @cli br rioprf clear + * @code + * br rioprf clear + * Done + * @endcode + * @par api_copy + * #otBorderRoutingClearRouteInfoOptionPreference + * + */ + else if (aArgs[1] == "clear") + { + otBorderRoutingClearRouteInfoOptionPreference(GetInstancePtr()); + } + /** + * @cli br rioprf (high,med,low) + * @code + * br rioprf low + * Done + * @endcode + * @cparam br rioprf [@ca{high}|@ca{med}|@ca{low}] + * @par api_copy + * #otBorderRoutingSetRouteInfoOptionPreference + * + */ else { otRoutePreference preference; diff --git a/src/core/api/border_routing_api.cpp b/src/core/api/border_routing_api.cpp index fb5e08075..baa29c71b 100644 --- a/src/core/api/border_routing_api.cpp +++ b/src/core/api/border_routing_api.cpp @@ -64,6 +64,11 @@ void otBorderRoutingSetRouteInfoOptionPreference(otInstance *aInstance, otRouteP static_cast(aPreference)); } +void otBorderRoutingClearRouteInfoOptionPreference(otInstance *aInstance) +{ + AsCoreType(aInstance).Get().ClearRouteInfoOptionPreference(); +} + otError otBorderRoutingGetOmrPrefix(otInstance *aInstance, otIp6Prefix *aPrefix) { return AsCoreType(aInstance).Get().GetOmrPrefix(AsCoreType(aPrefix)); diff --git a/src/core/border_router/routing_manager.cpp b/src/core/border_router/routing_manager.cpp index 8c61f6f05..e94d42a10 100644 --- a/src/core/border_router/routing_manager.cpp +++ b/src/core/border_router/routing_manager.cpp @@ -68,7 +68,8 @@ RoutingManager::RoutingManager(Instance &aInstance) , mIsEnabled(false) , mInfraIf(aInstance) , mLocalOmrPrefix(aInstance) - , mRouteInfoOptionPreference(NetworkData::kRoutePreferenceMedium) + , mRioPreference(NetworkData::kRoutePreferenceLow) + , mUserSetRioPreference(false) , mOnLinkPrefixManager(aInstance) , mDiscoveredPrefixTable(aInstance) #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE @@ -122,9 +123,36 @@ exit: void RoutingManager::SetRouteInfoOptionPreference(RoutePreference aPreference) { - VerifyOrExit(mRouteInfoOptionPreference != aPreference); + LogInfo("User explicitly set RIO Preference to %s", RoutePreferenceToString(aPreference)); + mUserSetRioPreference = true; + UpdateRioPreference(aPreference); +} - mRouteInfoOptionPreference = aPreference; +void RoutingManager::ClearRouteInfoOptionPreference(void) +{ + VerifyOrExit(mUserSetRioPreference); + + LogInfo("User cleared explicitly set RIO Preference"); + mUserSetRioPreference = false; + SetRioPreferenceBasedOnRole(); + +exit: + return; +} + +void RoutingManager::SetRioPreferenceBasedOnRole(void) +{ + UpdateRioPreference(Get().IsRouterOrLeader() ? NetworkData::kRoutePreferenceMedium + : NetworkData::kRoutePreferenceLow); +} + +void RoutingManager::UpdateRioPreference(RoutePreference aPreference) +{ + VerifyOrExit(mRioPreference != aPreference); + + LogInfo("RIO Preference changed: %s -> %s", RoutePreferenceToString(mRioPreference), + RoutePreferenceToString(aPreference)); + mRioPreference = aPreference; VerifyOrExit(mIsRunning); ScheduleRoutingPolicyEvaluation(kAfterRandomDelay); @@ -347,6 +375,11 @@ exit: void RoutingManager::HandleNotifierEvents(Events aEvents) { + if (aEvents.Contains(kEventThreadRoleChanged) && !mUserSetRioPreference) + { + SetRioPreferenceBasedOnRole(); + } + VerifyOrExit(IsInitialized() && IsEnabled()); if (aEvents.Contains(kEventThreadRoleChanged)) @@ -664,7 +697,7 @@ void RoutingManager::SendRouterAdvertisement(RouterAdvTxMode aRaTxMode) { if (prefix.GetLength() != 0) { - SuccessOrAssert(raMsg.AppendRouteInfoOption(prefix, /* aRouteLifetime */ 0, mRouteInfoOptionPreference)); + SuccessOrAssert(raMsg.AppendRouteInfoOption(prefix, /* aRouteLifetime */ 0, mRioPreference)); LogInfo("RouterAdvert: Added RIO for %s (lifetime=0)", prefix.ToString().AsCString()); } } @@ -738,7 +771,7 @@ void RoutingManager::SendRouterAdvertisement(RouterAdvTxMode aRaTxMode) for (const OnMeshPrefix &prefix : mAdvertisedPrefixes) { - SuccessOrAssert(raMsg.AppendRouteInfoOption(prefix, kDefaultOmrPrefixLifetime, mRouteInfoOptionPreference)); + SuccessOrAssert(raMsg.AppendRouteInfoOption(prefix, kDefaultOmrPrefixLifetime, mRioPreference)); LogInfo("RouterAdvert: Added RIO for %s (lifetime=%lu)", prefix.ToString().AsCString(), ToUlong(kDefaultOmrPrefixLifetime)); } diff --git a/src/core/border_router/routing_manager.hpp b/src/core/border_router/routing_manager.hpp index 30137ba4d..a8b39d615 100644 --- a/src/core/border_router/routing_manager.hpp +++ b/src/core/border_router/routing_manager.hpp @@ -150,28 +150,41 @@ public: void RequestStop(void) { Stop(); } /** - * This method gets the preference used when advertising Route Info Options (e.g., for discovered OMR prefixes) in - * Router Advertisement messages sent over the infrastructure link. + * This method gets the current preference used when advertising Route Info Options (RIO) in Router Advertisement + * messages sent over the infrastructure link. * - * @returns The Route Info Option preference. + * The RIO preference is determined as follows: + * + * - If explicitly set by user by calling `SetRouteInfoOptionPreference()`, the given preference is used. + * - Otherwise, it is determined based on device's role: Medium preference when in router/leader role and low + * preference when in child role. + * + * @returns The current Route Info Option preference. * */ - RoutePreference GetRouteInfoOptionPreference(void) const { return mRouteInfoOptionPreference; } + RoutePreference GetRouteInfoOptionPreference(void) const { return mRioPreference; } /** - * This method sets the preference to use when advertising Route Info Options (e.g., for discovered OMR prefixes) - * in Router Advertisement messages sent over the infrastructure link. + * This method explicitly sets the preference to use when advertising Route Info Options (RIO) in Router + * Advertisement messages sent over the infrastructure link. * - * By default BR will use 'medium' preference level but this method allows the default value to be changed. As an - * example, it can be set to 'low' preference in the case where device is a temporary BR (a mobile BR or a - * battery-powered BR) to indicate that other BRs (if any) should be preferred over this BR on the infrastructure - * link. + * After a call to this method, BR will use the given preference for all its advertised RIOs. The preference can be + * cleared by calling `ClearRouteInfoOptionPreference`()`. * * @param[in] aPreference The route preference to use. * */ void SetRouteInfoOptionPreference(RoutePreference aPreference); + /** + * This method clears a previously set preference value for advertised Route Info Options. + * + * After a call to this method, BR will use device role to determine the RIO preference: Medium preference when + * in router/leader role and low preference when in child role. + * + */ + void ClearRouteInfoOptionPreference(void); + /** * This method returns the local off-mesh-routable (OMR) prefix. * @@ -838,6 +851,8 @@ private: void HandleNotifierEvents(Events aEvents); bool IsInitialized(void) const { return mInfraIf.IsInitialized(); } bool IsEnabled(void) const { return mIsEnabled; } + void SetRioPreferenceBasedOnRole(void); + void UpdateRioPreference(RoutePreference aPreference); Error LoadOrGenerateRandomBrUlaPrefix(void); void EvaluateRoutingPolicy(void); @@ -890,7 +905,8 @@ private: // were advertised as RIO in the last sent RA message. OnMeshPrefixArray mAdvertisedPrefixes; - RoutePreference mRouteInfoOptionPreference; + RoutePreference mRioPreference; + bool mUserSetRioPreference; OnLinkPrefixManager mOnLinkPrefixManager; diff --git a/src/core/thread/network_data_types.cpp b/src/core/thread/network_data_types.cpp index b0cd1ac8b..5085782db 100644 --- a/src/core/thread/network_data_types.cpp +++ b/src/core/thread/network_data_types.cpp @@ -39,6 +39,25 @@ namespace ot { namespace NetworkData { +const char *RoutePreferenceToString(RoutePreference aPreference) +{ + const char *str = "low"; + + switch (aPreference) + { + case kRoutePreferenceHigh: + str = "high"; + break; + case kRoutePreferenceMedium: + str = "med"; + break; + case kRoutePreferenceLow: + break; + } + + return str; +} + #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE static bool IsPrefixValid(Instance &aInstance, const Ip6::Prefix &aPrefix) diff --git a/src/core/thread/network_data_types.hpp b/src/core/thread/network_data_types.hpp index 354efaebd..0907612f9 100644 --- a/src/core/thread/network_data_types.hpp +++ b/src/core/thread/network_data_types.hpp @@ -160,6 +160,16 @@ inline RoutePreference RoutePreferenceFromValue(uint8_t aValue) return kRoutePreferences[aValue & kMask]; } +/** + * This function converts a router preference to a human-readable string. + * + * @param[in] aPreference The preference to convert + * + * @returns The string representation of @p aPreference. + * + */ +const char *RoutePreferenceToString(RoutePreference aPreference); + /** * This class represents an On-mesh Prefix (Border Router) configuration. *