mirror of
https://github.com/espressif/openthread.git
synced 2026-08-04 01:47:47 +00:00
[routing-manager] determine route preference from parent link quality (#9080)
This commit updates how `RoutePublisher` determines the published route preference: - Medium preference is used on a border router (BR) acting as a router or a BR acting as an end-device (ED) connected to a parent with link quality 3. - An ED BR with lower link quality publishes its route with low preference. For ED BRs, the preference is updated if the parent's link quality changes. However, to avoid frequent preference changes due to link variability, the following rules are used: - If the link quality goes to 1 or 2, the route preference is immediately changed to low. - On transition to link quality 3, we wait for 5 minutes before changing the preference to medium. - If the ED BR switches parents, the link quality to the new parent is used to determine preference. It also adds new APIs and related CLI commands to allow users to get and manually set the published route preference. A new test script `test-021-br-route-prf.py` is added to validate the selection of route preference by BR. This commit also adds a new mechanism to detect when the link quality to the parent changes and signal it using a newly added `Notifier` event.
This commit is contained in:
@@ -49,13 +49,13 @@ otError otPlatInfraIfSendIcmp6Nd(uint32_t aInfraIfIndex,
|
||||
OT_UNUSED_VARIABLE(aBuffer);
|
||||
OT_UNUSED_VARIABLE(aBufferLength);
|
||||
|
||||
return OT_ERROR_FAILED;
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
otError otPlatInfraIfDiscoverNat64Prefix(uint32_t aInfraIfIndex)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInfraIfIndex);
|
||||
|
||||
return OT_ERROR_FAILED;
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -213,6 +213,44 @@ void otBorderRoutingSetRouteInfoOptionPreference(otInstance *aInstance, otRouteP
|
||||
*/
|
||||
void otBorderRoutingClearRouteInfoOptionPreference(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* Gets the current preference used for published routes in Network Data.
|
||||
*
|
||||
* The preference is determined as follows:
|
||||
*
|
||||
* - If explicitly set by user by calling `otBorderRoutingSetRoutePreference()`, the given preference is used.
|
||||
* - Otherwise, it is determined automatically by `RoutingManager` based on the device's role and link quality.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
*
|
||||
* @returns The current published route preference.
|
||||
*
|
||||
*/
|
||||
otRoutePreference otBorderRoutingGetRoutePreference(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* Explicitly sets the preference of published routes in Network Data.
|
||||
*
|
||||
* After a call to this function, BR will use the given preference. The preference can be cleared by calling
|
||||
* `otBorderRoutingClearRoutePreference()`.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aPreference The route preference to use.
|
||||
*
|
||||
*/
|
||||
void otBorderRoutingSetRoutePreference(otInstance *aInstance, otRoutePreference aPreference);
|
||||
|
||||
/**
|
||||
* Clears a previously set preference value for published routes in Network Data.
|
||||
*
|
||||
* After a call to this function, BR will determine the preference automatically based on the device's role and
|
||||
* link quality (to the parent when acting as end-device).
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
*
|
||||
*/
|
||||
void otBorderRoutingClearRoutePreference(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* Gets the local Off-Mesh-Routable (OMR) Prefix, for example `fdfc:1ff5:1512:5622::/64`.
|
||||
*
|
||||
|
||||
@@ -53,7 +53,7 @@ extern "C" {
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (336)
|
||||
#define OPENTHREAD_API_VERSION (337)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
@@ -171,44 +171,38 @@ uint64_t otInstanceGetUptime(otInstance *aInstance);
|
||||
*/
|
||||
void otInstanceGetUptimeAsString(otInstance *aInstance, char *aBuffer, uint16_t aSize);
|
||||
|
||||
/**
|
||||
* Defines flags that are passed as part of `otStateChangedCallback`.
|
||||
*
|
||||
*/
|
||||
enum
|
||||
{
|
||||
OT_CHANGED_IP6_ADDRESS_ADDED = 1 << 0, ///< IPv6 address was added
|
||||
OT_CHANGED_IP6_ADDRESS_REMOVED = 1 << 1, ///< IPv6 address was removed
|
||||
OT_CHANGED_THREAD_ROLE = 1 << 2, ///< Role (disabled, detached, child, router, leader) changed
|
||||
OT_CHANGED_THREAD_LL_ADDR = 1 << 3, ///< The link-local address changed
|
||||
OT_CHANGED_THREAD_ML_ADDR = 1 << 4, ///< The mesh-local address changed
|
||||
OT_CHANGED_THREAD_RLOC_ADDED = 1 << 5, ///< RLOC was added
|
||||
OT_CHANGED_THREAD_RLOC_REMOVED = 1 << 6, ///< RLOC was removed
|
||||
OT_CHANGED_THREAD_PARTITION_ID = 1 << 7, ///< Partition ID changed
|
||||
OT_CHANGED_THREAD_KEY_SEQUENCE_COUNTER = 1 << 8, ///< Thread Key Sequence changed
|
||||
OT_CHANGED_THREAD_NETDATA = 1 << 9, ///< Thread Network Data changed
|
||||
OT_CHANGED_THREAD_CHILD_ADDED = 1 << 10, ///< Child was added
|
||||
OT_CHANGED_THREAD_CHILD_REMOVED = 1 << 11, ///< Child was removed
|
||||
OT_CHANGED_IP6_MULTICAST_SUBSCRIBED = 1 << 12, ///< Subscribed to a IPv6 multicast address
|
||||
OT_CHANGED_IP6_MULTICAST_UNSUBSCRIBED = 1 << 13, ///< Unsubscribed from a IPv6 multicast address
|
||||
OT_CHANGED_THREAD_CHANNEL = 1 << 14, ///< Thread network channel changed
|
||||
OT_CHANGED_THREAD_PANID = 1 << 15, ///< Thread network PAN Id changed
|
||||
OT_CHANGED_THREAD_NETWORK_NAME = 1 << 16, ///< Thread network name changed
|
||||
OT_CHANGED_THREAD_EXT_PANID = 1 << 17, ///< Thread network extended PAN ID changed
|
||||
OT_CHANGED_NETWORK_KEY = 1 << 18, ///< Network key changed
|
||||
OT_CHANGED_PSKC = 1 << 19, ///< PSKc changed
|
||||
OT_CHANGED_SECURITY_POLICY = 1 << 20, ///< Security Policy changed
|
||||
OT_CHANGED_CHANNEL_MANAGER_NEW_CHANNEL = 1 << 21, ///< Channel Manager new pending Thread channel changed
|
||||
OT_CHANGED_SUPPORTED_CHANNEL_MASK = 1 << 22, ///< Supported channel mask changed
|
||||
OT_CHANGED_COMMISSIONER_STATE = 1 << 23, ///< Commissioner state changed
|
||||
OT_CHANGED_THREAD_NETIF_STATE = 1 << 24, ///< Thread network interface state changed
|
||||
OT_CHANGED_THREAD_BACKBONE_ROUTER_STATE = 1 << 25, ///< Backbone Router state changed
|
||||
OT_CHANGED_THREAD_BACKBONE_ROUTER_LOCAL = 1 << 26, ///< Local Backbone Router configuration changed
|
||||
OT_CHANGED_JOINER_STATE = 1 << 27, ///< Joiner state changed
|
||||
OT_CHANGED_ACTIVE_DATASET = 1 << 28, ///< Active Operational Dataset changed
|
||||
OT_CHANGED_PENDING_DATASET = 1 << 29, ///< Pending Operational Dataset changed
|
||||
OT_CHANGED_NAT64_TRANSLATOR_STATE = 1 << 30, ///< The state of NAT64 translator changed
|
||||
};
|
||||
#define OT_CHANGED_IP6_ADDRESS_ADDED (1U << 0) ///< IPv6 address was added
|
||||
#define OT_CHANGED_IP6_ADDRESS_REMOVED (1U << 1) ///< IPv6 address was removed
|
||||
#define OT_CHANGED_THREAD_ROLE (1U << 2) ///< Role (disabled, detached, child, router, leader) changed
|
||||
#define OT_CHANGED_THREAD_LL_ADDR (1U << 3) ///< The link-local address changed
|
||||
#define OT_CHANGED_THREAD_ML_ADDR (1U << 4) ///< The mesh-local address changed
|
||||
#define OT_CHANGED_THREAD_RLOC_ADDED (1U << 5) ///< RLOC was added
|
||||
#define OT_CHANGED_THREAD_RLOC_REMOVED (1U << 6) ///< RLOC was removed
|
||||
#define OT_CHANGED_THREAD_PARTITION_ID (1U << 7) ///< Partition ID changed
|
||||
#define OT_CHANGED_THREAD_KEY_SEQUENCE_COUNTER (1U << 8) ///< Thread Key Sequence changed
|
||||
#define OT_CHANGED_THREAD_NETDATA (1U << 9) ///< Thread Network Data changed
|
||||
#define OT_CHANGED_THREAD_CHILD_ADDED (1U << 10) ///< Child was added
|
||||
#define OT_CHANGED_THREAD_CHILD_REMOVED (1U << 11) ///< Child was removed
|
||||
#define OT_CHANGED_IP6_MULTICAST_SUBSCRIBED (1U << 12) ///< Subscribed to a IPv6 multicast address
|
||||
#define OT_CHANGED_IP6_MULTICAST_UNSUBSCRIBED (1U << 13) ///< Unsubscribed from a IPv6 multicast address
|
||||
#define OT_CHANGED_THREAD_CHANNEL (1U << 14) ///< Thread network channel changed
|
||||
#define OT_CHANGED_THREAD_PANID (1U << 15) ///< Thread network PAN Id changed
|
||||
#define OT_CHANGED_THREAD_NETWORK_NAME (1U << 16) ///< Thread network name changed
|
||||
#define OT_CHANGED_THREAD_EXT_PANID (1U << 17) ///< Thread network extended PAN ID changed
|
||||
#define OT_CHANGED_NETWORK_KEY (1U << 18) ///< Network key changed
|
||||
#define OT_CHANGED_PSKC (1U << 19) ///< PSKc changed
|
||||
#define OT_CHANGED_SECURITY_POLICY (1U << 20) ///< Security Policy changed
|
||||
#define OT_CHANGED_CHANNEL_MANAGER_NEW_CHANNEL (1U << 21) ///< Channel Manager new pending Thread channel changed
|
||||
#define OT_CHANGED_SUPPORTED_CHANNEL_MASK (1U << 22) ///< Supported channel mask changed
|
||||
#define OT_CHANGED_COMMISSIONER_STATE (1U << 23) ///< Commissioner state changed
|
||||
#define OT_CHANGED_THREAD_NETIF_STATE (1U << 24) ///< Thread network interface state changed
|
||||
#define OT_CHANGED_THREAD_BACKBONE_ROUTER_STATE (1U << 25) ///< Backbone Router state changed
|
||||
#define OT_CHANGED_THREAD_BACKBONE_ROUTER_LOCAL (1U << 26) ///< Local Backbone Router configuration changed
|
||||
#define OT_CHANGED_JOINER_STATE (1U << 27) ///< Joiner state changed
|
||||
#define OT_CHANGED_ACTIVE_DATASET (1U << 28) ///< Active Operational Dataset changed
|
||||
#define OT_CHANGED_PENDING_DATASET (1U << 29) ///< Pending Operational Dataset changed
|
||||
#define OT_CHANGED_NAT64_TRANSLATOR_STATE (1U << 30) ///< The state of NAT64 translator changed
|
||||
#define OT_CHANGED_PARENT_LINK_QUALITY (1U << 31) ///< Parent link quality changed
|
||||
|
||||
/**
|
||||
* Represents a bit-field indicating specific state/configuration that has changed. See `OT_CHANGED_*`
|
||||
|
||||
@@ -13,6 +13,7 @@ Usage : `br [command] ...`
|
||||
- [onlinkprefix](#onlinkprefix)
|
||||
- [prefixtable](#prefixtable)
|
||||
- [rioprf](#rioprf)
|
||||
- [routeprf](#routeprf)
|
||||
- [state](#state)
|
||||
|
||||
## Command Details
|
||||
@@ -32,6 +33,7 @@ omrprefix
|
||||
onlinkprefix
|
||||
prefixtable
|
||||
rioprf
|
||||
routeprf
|
||||
state
|
||||
Done
|
||||
```
|
||||
@@ -206,3 +208,37 @@ Clear a previously set preference value for advertising Route Info Options (e.g.
|
||||
> br rioprf clear
|
||||
Done
|
||||
```
|
||||
|
||||
### routeprf
|
||||
|
||||
Usage: `br routeprf`
|
||||
|
||||
Get the preference used for publishing routes in Thread Network Data. This may be the automatically determined route preference, or an administratively set fixed route preference - if applicable.
|
||||
|
||||
```bash
|
||||
> br routeprf
|
||||
med
|
||||
Done
|
||||
```
|
||||
|
||||
### routeprf \<prf\>
|
||||
|
||||
Usage: `br routeprf high|med|low`
|
||||
|
||||
Set the preference (which may be 'high', 'med', or 'low') to use publishing routes in Thread Network Data. Setting a preference value overrides the automatic route preference determination. It is used only for an explicit administrative configuration of a Border Router.
|
||||
|
||||
```bash
|
||||
> br routeprf low
|
||||
Done
|
||||
```
|
||||
|
||||
### routeprf clear
|
||||
|
||||
Usage: `br routeprf clear`
|
||||
|
||||
Clear a previously set preference value for publishing routes in Thread Network Data. When cleared BR will automatically determine the route preference based on device's role and link quality to parent (when acting as end-device).
|
||||
|
||||
```bash
|
||||
> br routeprf clear
|
||||
Done
|
||||
```
|
||||
|
||||
@@ -44,6 +44,32 @@
|
||||
namespace ot {
|
||||
namespace Cli {
|
||||
|
||||
/**
|
||||
* @cli br init
|
||||
* @code
|
||||
* br init 2 1
|
||||
* Done
|
||||
* @endcode
|
||||
* @cparam br init @ca{infrastructure-network-index} @ca{is-running}
|
||||
* @par
|
||||
* Initializes the Border Routing Manager.
|
||||
* @sa otBorderRoutingInit
|
||||
*/
|
||||
template <> otError Br::Process<Cmd("init")>(Arg aArgs[])
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint32_t ifIndex;
|
||||
bool isRunning;
|
||||
|
||||
SuccessOrExit(error = aArgs[0].ParseAsUint32(ifIndex));
|
||||
SuccessOrExit(error = aArgs[1].ParseAsBool(isRunning));
|
||||
VerifyOrExit(aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
error = otBorderRoutingInit(GetInstancePtr(), ifIndex, isRunning);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* @cli br enable
|
||||
* @code
|
||||
@@ -452,6 +478,59 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
template <> otError Br::Process<Cmd("routeprf")>(Arg aArgs[])
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
/**
|
||||
* @cli br routeprf
|
||||
* @code
|
||||
* br routeprf
|
||||
* med
|
||||
* Done
|
||||
* @endcode
|
||||
* @par api_copy
|
||||
* #otBorderRoutingGetRoutePreference
|
||||
*/
|
||||
if (aArgs[0].IsEmpty())
|
||||
{
|
||||
OutputLine("%s", Interpreter::PreferenceToString(otBorderRoutingGetRoutePreference(GetInstancePtr())));
|
||||
}
|
||||
/**
|
||||
* @cli br routeprf clear
|
||||
* @code
|
||||
* br routeprf clear
|
||||
* Done
|
||||
* @endcode
|
||||
* @par api_copy
|
||||
* #otBorderRoutingClearRoutePreference
|
||||
*/
|
||||
else if (aArgs[0] == "clear")
|
||||
{
|
||||
otBorderRoutingClearRoutePreference(GetInstancePtr());
|
||||
}
|
||||
/**
|
||||
* @cli br routeprf (high,med,low)
|
||||
* @code
|
||||
* br routeprf low
|
||||
* Done
|
||||
* @endcode
|
||||
* @cparam br routeprf [@ca{high}|@ca{med}|@ca{low}]
|
||||
* @par api_copy
|
||||
* #otBorderRoutingSetRoutePreference
|
||||
*/
|
||||
else
|
||||
{
|
||||
otRoutePreference preference;
|
||||
|
||||
SuccessOrExit(error = Interpreter::ParsePreference(aArgs[0], preference));
|
||||
otBorderRoutingSetRoutePreference(GetInstancePtr(), preference);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE
|
||||
|
||||
/**
|
||||
@@ -499,6 +578,7 @@ otError Br::Process(Arg aArgs[])
|
||||
#endif
|
||||
CmdEntry("disable"),
|
||||
CmdEntry("enable"),
|
||||
CmdEntry("init"),
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
CmdEntry("nat64prefix"),
|
||||
#endif
|
||||
@@ -506,6 +586,7 @@ otError Br::Process(Arg aArgs[])
|
||||
CmdEntry("onlinkprefix"),
|
||||
CmdEntry("prefixtable"),
|
||||
CmdEntry("rioprf"),
|
||||
CmdEntry("routeprf"),
|
||||
CmdEntry("state"),
|
||||
};
|
||||
|
||||
|
||||
@@ -75,6 +75,23 @@ void otBorderRoutingClearRouteInfoOptionPreference(otInstance *aInstance)
|
||||
AsCoreType(aInstance).Get<BorderRouter::RoutingManager>().ClearRouteInfoOptionPreference();
|
||||
}
|
||||
|
||||
otRoutePreference otBorderRoutingGetRoutePreference(otInstance *aInstance)
|
||||
{
|
||||
return static_cast<otRoutePreference>(
|
||||
AsCoreType(aInstance).Get<BorderRouter::RoutingManager>().GetRoutePreference());
|
||||
}
|
||||
|
||||
void otBorderRoutingSetRoutePreference(otInstance *aInstance, otRoutePreference aPreference)
|
||||
{
|
||||
AsCoreType(aInstance).Get<BorderRouter::RoutingManager>().SetRoutePreference(
|
||||
static_cast<NetworkData::RoutePreference>(aPreference));
|
||||
}
|
||||
|
||||
void otBorderRoutingClearRoutePreference(otInstance *aInstance)
|
||||
{
|
||||
AsCoreType(aInstance).Get<BorderRouter::RoutingManager>().ClearRoutePreference();
|
||||
}
|
||||
|
||||
otError otBorderRoutingGetOmrPrefix(otInstance *aInstance, otIp6Prefix *aPrefix)
|
||||
{
|
||||
return AsCoreType(aInstance).Get<BorderRouter::RoutingManager>().GetOmrPrefix(AsCoreType(aPrefix));
|
||||
|
||||
@@ -433,9 +433,10 @@ void RoutingManager::HandleNotifierEvents(Events aEvents)
|
||||
if (aEvents.Contains(kEventThreadRoleChanged) && !mUserSetRioPreference)
|
||||
{
|
||||
SetRioPreferenceBasedOnRole();
|
||||
mRoutePublisher.HandleRoleChanged();
|
||||
}
|
||||
|
||||
mRoutePublisher.HandleNotifierEvents(aEvents);
|
||||
|
||||
VerifyOrExit(IsInitialized() && IsEnabled());
|
||||
|
||||
if (aEvents.Contains(kEventThreadRoleChanged))
|
||||
@@ -2725,6 +2726,7 @@ RoutingManager::RoutePublisher::RoutePublisher(Instance &aInstance)
|
||||
, mState(kDoNotPublish)
|
||||
, mPreference(NetworkData::kRoutePreferenceMedium)
|
||||
, mUserSetPreference(false)
|
||||
, mTimer(aInstance)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -2838,6 +2840,7 @@ void RoutingManager::RoutePublisher::SetPreference(RoutePreference aPreference)
|
||||
{
|
||||
LogInfo("User explicitly set published route preference to %s", RoutePreferenceToString(aPreference));
|
||||
mUserSetPreference = true;
|
||||
mTimer.Stop();
|
||||
UpdatePreference(aPreference);
|
||||
}
|
||||
|
||||
@@ -2855,18 +2858,48 @@ exit:
|
||||
|
||||
void RoutingManager::RoutePublisher::SetPreferenceBasedOnRole(void)
|
||||
{
|
||||
UpdatePreference(Get<Mle::Mle>().IsRouterOrLeader() ? NetworkData::kRoutePreferenceMedium
|
||||
: NetworkData::kRoutePreferenceLow);
|
||||
RoutePreference preference = NetworkData::kRoutePreferenceMedium;
|
||||
|
||||
if (Get<Mle::Mle>().IsChild() && (Get<Mle::Mle>().GetParent().GetTwoWayLinkQuality() != kLinkQuality3))
|
||||
{
|
||||
preference = NetworkData::kRoutePreferenceLow;
|
||||
}
|
||||
|
||||
UpdatePreference(preference);
|
||||
mTimer.Stop();
|
||||
}
|
||||
|
||||
void RoutingManager::RoutePublisher::HandleRoleChanged(void)
|
||||
void RoutingManager::RoutePublisher::HandleNotifierEvents(Events aEvents)
|
||||
{
|
||||
if (!mUserSetPreference)
|
||||
VerifyOrExit(!mUserSetPreference);
|
||||
|
||||
if (aEvents.Contains(kEventThreadRoleChanged))
|
||||
{
|
||||
SetPreferenceBasedOnRole();
|
||||
}
|
||||
|
||||
if (aEvents.Contains(kEventParentLinkQualityChanged))
|
||||
{
|
||||
VerifyOrExit(Get<Mle::Mle>().IsChild());
|
||||
|
||||
if (Get<Mle::Mle>().GetParent().GetTwoWayLinkQuality() == kLinkQuality3)
|
||||
{
|
||||
VerifyOrExit(!mTimer.IsRunning());
|
||||
mTimer.Start(kDelayBeforePrfUpdateOnLinkQuality3);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdatePreference(NetworkData::kRoutePreferenceLow);
|
||||
mTimer.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void RoutingManager::RoutePublisher::HandleTimer(void) { SetPreferenceBasedOnRole(); }
|
||||
|
||||
void RoutingManager::RoutePublisher::UpdatePreference(RoutePreference aPreference)
|
||||
{
|
||||
VerifyOrExit(mPreference != aPreference);
|
||||
|
||||
@@ -228,6 +228,39 @@ public:
|
||||
*/
|
||||
void ClearRouteInfoOptionPreference(void);
|
||||
|
||||
/**
|
||||
* Gets the current preference used for published routes in Network Data.
|
||||
*
|
||||
* The preference is determined as follows:
|
||||
*
|
||||
* - If explicitly set by user by calling `SetRoutePreference()`, the given preference is used.
|
||||
* - Otherwise, it is determined automatically by `RoutingManager` based on the device's role and link quality.
|
||||
*
|
||||
* @returns The current published route preference.
|
||||
*
|
||||
*/
|
||||
RoutePreference GetRoutePreference(void) const { return mRoutePublisher.GetPreference(); }
|
||||
|
||||
/**
|
||||
* Explicitly sets the preference of published routes in Network Data.
|
||||
*
|
||||
* After a call to this method, BR will use the given preference. The preference can be cleared by calling
|
||||
* `ClearRoutePreference`()`.
|
||||
*
|
||||
* @param[in] aPreference The route preference to use.
|
||||
*
|
||||
*/
|
||||
void SetRoutePreference(RoutePreference aPreference) { mRoutePublisher.SetPreference(aPreference); }
|
||||
|
||||
/**
|
||||
* Clears a previously set preference value for published routes in Network Data.
|
||||
*
|
||||
* After a call to this method, BR will determine the preference automatically based on the device's role and
|
||||
* link quality (to the parent when acting as end-device).
|
||||
*
|
||||
*/
|
||||
void ClearRoutePreference(void) { mRoutePublisher.ClearPreference(); }
|
||||
|
||||
/**
|
||||
* Returns the local generated off-mesh-routable (OMR) prefix.
|
||||
*
|
||||
@@ -941,6 +974,8 @@ private:
|
||||
};
|
||||
#endif // OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
|
||||
void HandleRoutePublisherTimer(void) { mRoutePublisher.HandleTimer(); }
|
||||
|
||||
class RoutePublisher : public InstanceLocator // Manages the routes that are published in net data
|
||||
{
|
||||
public:
|
||||
@@ -954,11 +989,14 @@ private:
|
||||
void SetPreference(RoutePreference aPreference);
|
||||
void ClearPreference(void);
|
||||
|
||||
void HandleRoleChanged(void);
|
||||
void HandleNotifierEvents(Events aEvents);
|
||||
void HandleTimer(void);
|
||||
|
||||
static const Ip6::Prefix &GetUlaPrefix(void) { return AsCoreType(&kUlaPrefix); }
|
||||
|
||||
private:
|
||||
static constexpr uint32_t kDelayBeforePrfUpdateOnLinkQuality3 = TimeMilli::SecToMsec(5 * 60);
|
||||
|
||||
static const otIp6Prefix kUlaPrefix;
|
||||
|
||||
enum State : uint8_t
|
||||
@@ -976,9 +1014,12 @@ private:
|
||||
|
||||
static const char *StateToString(State aState);
|
||||
|
||||
using DelayTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleRoutePublisherTimer>;
|
||||
|
||||
State mState;
|
||||
RoutePreference mPreference;
|
||||
bool mUserSetPreference;
|
||||
DelayTimer mTimer;
|
||||
};
|
||||
|
||||
struct RaInfo
|
||||
|
||||
@@ -272,6 +272,7 @@ const char *Notifier::EventToString(Event aEvent) const
|
||||
"ActDset", // kEventActiveDatasetChanged (1 << 28)
|
||||
"PndDset", // kEventPendingDatasetChanged (1 << 29)
|
||||
"Nat64", // kEventNat64TranslatorStateChanged (1 << 30)
|
||||
"ParentLq", // kEventParentLinkQualityChanged (1 << 31)
|
||||
};
|
||||
|
||||
for (uint8_t index = 0; index < GetArrayLength(kEventStrings); index++)
|
||||
|
||||
@@ -97,6 +97,7 @@ enum Event : uint32_t
|
||||
kEventActiveDatasetChanged = OT_CHANGED_ACTIVE_DATASET, ///< Active Dataset changed
|
||||
kEventPendingDatasetChanged = OT_CHANGED_PENDING_DATASET, ///< Pending Dataset changed
|
||||
kEventNat64TranslatorStateChanged = OT_CHANGED_NAT64_TRANSLATOR_STATE, ///< Nat64Translator state changed
|
||||
kEventParentLinkQualityChanged = OT_CHANGED_PARENT_LINK_QUALITY, ///< Parent link quality changed
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+24
-9
@@ -1298,11 +1298,8 @@ void Mac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError)
|
||||
|
||||
if ((aError == kErrorNone) && (neighbor != nullptr))
|
||||
{
|
||||
neighbor->GetLinkInfo().AddRss(aAckFrame->GetRssi());
|
||||
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
|
||||
neighbor->AggregateLinkMetrics(/* aSeriesId */ 0, aAckFrame->GetType(), aAckFrame->GetLqi(),
|
||||
aAckFrame->GetRssi());
|
||||
#endif
|
||||
UpdateNeighborLinkInfo(*neighbor, *aAckFrame);
|
||||
|
||||
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
|
||||
ProcessEnhAckProbing(*aAckFrame, *neighbor);
|
||||
#endif
|
||||
@@ -1863,10 +1860,7 @@ void Mac::HandleReceivedFrame(RxFrame *aFrame, Error aError)
|
||||
|
||||
if (neighbor != nullptr)
|
||||
{
|
||||
neighbor->GetLinkInfo().AddRss(aFrame->GetRssi());
|
||||
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
|
||||
neighbor->AggregateLinkMetrics(/* aSeriesId */ 0, aFrame->GetType(), aFrame->GetLqi(), aFrame->GetRssi());
|
||||
#endif
|
||||
UpdateNeighborLinkInfo(*neighbor, *aFrame);
|
||||
|
||||
if (aFrame->GetSecurityEnabled())
|
||||
{
|
||||
@@ -2030,6 +2024,27 @@ exit:
|
||||
}
|
||||
}
|
||||
|
||||
void Mac::UpdateNeighborLinkInfo(Neighbor &aNeighbor, const RxFrame &aRxFrame)
|
||||
{
|
||||
LinkQuality oldLinkQuality = aNeighbor.GetLinkInfo().GetLinkQuality();
|
||||
|
||||
aNeighbor.GetLinkInfo().AddRss(aRxFrame.GetRssi());
|
||||
|
||||
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
|
||||
aNeighbor.AggregateLinkMetrics(/* aSeriesId */ 0, aRxFrame.GetType(), aRxFrame.GetLqi(), aRxFrame.GetRssi());
|
||||
#endif
|
||||
|
||||
// Signal when `aNeighbor` is the current parent and its link
|
||||
// quality gets changed.
|
||||
|
||||
VerifyOrExit(Get<Mle::Mle>().IsChild() && (&aNeighbor == &Get<Mle::Mle>().GetParent()));
|
||||
VerifyOrExit(aNeighbor.GetLinkInfo().GetLinkQuality() != oldLinkQuality);
|
||||
Get<Notifier>().Signal(kEventParentLinkQualityChanged);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
bool Mac::HandleMacCommand(RxFrame &aFrame)
|
||||
{
|
||||
bool didHandle = false;
|
||||
|
||||
@@ -768,6 +768,7 @@ private:
|
||||
bool ShouldSendBeacon(void) const;
|
||||
bool IsJoinable(void) const;
|
||||
void BeginTransmit(void);
|
||||
void UpdateNeighborLinkInfo(Neighbor &aNeighbor, const RxFrame &aRxFrame);
|
||||
bool HandleMacCommand(RxFrame &aFrame);
|
||||
void HandleTimer(void);
|
||||
|
||||
|
||||
@@ -713,6 +713,30 @@ class Node(object):
|
||||
if (instance_name == service['instance'] and service_name == service['name']):
|
||||
return service
|
||||
|
||||
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# br
|
||||
|
||||
def br_init(self, if_inex, is_running):
|
||||
self._cli_no_output('br init', if_inex, is_running)
|
||||
|
||||
def br_enable(self):
|
||||
self._cli_no_output('br enable')
|
||||
|
||||
def br_disable(self):
|
||||
self._cli_no_output('br disable')
|
||||
|
||||
def br_get_state(self):
|
||||
return self._cli_single_output('br state')
|
||||
|
||||
def br_get_routeprf(self):
|
||||
return self._cli_single_output('br routeprf')
|
||||
|
||||
def br_set_routeprf(self, prf):
|
||||
self._cli_no_output('br routeprf', prf)
|
||||
|
||||
def br_clear_routeprf(self):
|
||||
self._cli_no_output('br routeprf clear')
|
||||
|
||||
# ------------------------------------------------------------------------------------------------------------------
|
||||
# Helper methods
|
||||
|
||||
|
||||
Executable
+263
@@ -0,0 +1,263 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2023, The OpenThread Authors.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. Neither the name of the copyright holder nor the
|
||||
# names of its contributors may be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
from cli import verify
|
||||
from cli import verify_within
|
||||
import cli
|
||||
import time
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------------
|
||||
# Test description: BR published route preference.
|
||||
#
|
||||
#
|
||||
|
||||
test_name = __file__[:-3] if __file__.endswith('.py') else __file__
|
||||
print('-' * 120)
|
||||
print('Starting \'{}\''.format(test_name))
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------------
|
||||
# Creating `cli.Node` instances
|
||||
|
||||
speedup = 40
|
||||
cli.Node.set_time_speedup_factor(speedup)
|
||||
|
||||
leader = cli.Node()
|
||||
br = cli.Node()
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------------
|
||||
# Form topology
|
||||
|
||||
leader.set_macfilter_lqi_to_node(br, 2)
|
||||
br.set_macfilter_lqi_to_node(leader, 2)
|
||||
|
||||
leader.form('br-route-prf')
|
||||
br.join(leader)
|
||||
|
||||
verify(leader.get_state() == 'leader')
|
||||
verify(br.get_state() == 'router')
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------------
|
||||
# Test Implementation
|
||||
|
||||
verify(br.br_get_state() == 'uninitialized')
|
||||
|
||||
br.br_init(1, 1)
|
||||
|
||||
verify(br.br_get_state() == 'disabled')
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Check the default route preference while BR is disabled
|
||||
|
||||
verify(br.br_get_routeprf() == 'med')
|
||||
|
||||
br.br_set_routeprf('low')
|
||||
verify(br.br_get_routeprf() == 'low')
|
||||
|
||||
br.br_set_routeprf('med')
|
||||
verify(br.br_get_routeprf() == 'med')
|
||||
|
||||
br.br_set_routeprf('high')
|
||||
verify(br.br_get_routeprf() == 'high')
|
||||
|
||||
br.br_clear_routeprf()
|
||||
verify(br.br_get_routeprf() == 'med')
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Enable BR and check the published route and its preference
|
||||
|
||||
br.br_enable()
|
||||
|
||||
|
||||
def check_published_route_1():
|
||||
verify(br.br_get_state() == 'running')
|
||||
routes = br.get_netdata_routes()
|
||||
verify(len(routes) == 1)
|
||||
verify(routes[0].startswith('fc00::/7 s med'))
|
||||
verify(br.br_get_routeprf() == 'med')
|
||||
|
||||
|
||||
verify_within(check_published_route_1, 5)
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Force `br` to become an end-device. Check that the published
|
||||
# route is now using `low` (since link quality to parent is
|
||||
# configured as 2)
|
||||
|
||||
br.set_router_eligible('disable')
|
||||
|
||||
parent_info = br.get_parent_info()
|
||||
verify(parent_info['Link Quality In'] == '2')
|
||||
|
||||
|
||||
def check_published_route_2():
|
||||
verify(br.get_state() == 'child')
|
||||
routes = br.get_netdata_routes()
|
||||
verify(len(routes) == 1)
|
||||
verify(routes[0].startswith('fc00::/7 s low'))
|
||||
verify(br.br_get_routeprf() == 'low')
|
||||
|
||||
|
||||
verify_within(check_published_route_2, 5)
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Manually set the route prf to 'high` and validated that network
|
||||
# data gets updated. Repeat setting route prf to `med`.
|
||||
|
||||
br.br_set_routeprf('high')
|
||||
|
||||
|
||||
def check_published_route_3():
|
||||
verify(br.get_state() == 'child')
|
||||
routes = br.get_netdata_routes()
|
||||
verify(len(routes) == 1)
|
||||
verify(routes[0].startswith('fc00::/7 s high'))
|
||||
verify(br.br_get_routeprf() == 'high')
|
||||
|
||||
|
||||
verify_within(check_published_route_3, 5)
|
||||
|
||||
br.br_set_routeprf('med')
|
||||
|
||||
|
||||
def check_published_route_4():
|
||||
verify(br.get_state() == 'child')
|
||||
routes = br.get_netdata_routes()
|
||||
verify(len(routes) == 1)
|
||||
verify(routes[0].startswith('fc00::/7 s med'))
|
||||
verify(br.br_get_routeprf() == 'med')
|
||||
|
||||
|
||||
verify_within(check_published_route_4, 5)
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Clear the manually set route prf and validate that we go back
|
||||
# to `low`.
|
||||
|
||||
br.br_clear_routeprf()
|
||||
verify(br.br_get_routeprf() == 'low')
|
||||
|
||||
|
||||
def check_published_route_5():
|
||||
verify(br.get_state() == 'child')
|
||||
routes = br.get_netdata_routes()
|
||||
verify(len(routes) == 1)
|
||||
verify(routes[0].startswith('fc00::/7 s low'))
|
||||
verify(br.br_get_routeprf() == 'low')
|
||||
|
||||
|
||||
verify_within(check_published_route_5, 5)
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Allow `br` to take `router` role, validate that the route
|
||||
# prf of `med` is used.
|
||||
|
||||
br.set_router_eligible('enable')
|
||||
|
||||
|
||||
def check_published_route_6():
|
||||
verify(br.get_state() == 'router')
|
||||
routes = br.get_netdata_routes()
|
||||
verify(len(routes) == 1)
|
||||
verify(routes[0].startswith('fc00::/7 s med'))
|
||||
verify(br.br_get_routeprf() == 'med')
|
||||
|
||||
|
||||
verify_within(check_published_route_6, 15)
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Update RSS MAC filter to use link quality 3 between `br` and
|
||||
# `leader`. Again force `br` to become `child` and validate
|
||||
# that now it still continues to use `med` prf.
|
||||
|
||||
leader.set_macfilter_lqi_to_node(br, 3)
|
||||
br.set_macfilter_lqi_to_node(leader, 3)
|
||||
|
||||
br.set_router_eligible('disable')
|
||||
|
||||
|
||||
def check_published_route_7():
|
||||
verify(br.get_state() == 'child')
|
||||
routes = br.get_netdata_routes()
|
||||
verify(len(routes) == 1)
|
||||
verify(routes[0].startswith('fc00::/7 s med'))
|
||||
verify(br.br_get_routeprf() == 'med')
|
||||
|
||||
|
||||
verify_within(check_published_route_7, 5)
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Update RSS MAC filter to use link quality 1 between `br` and
|
||||
# `leader`. Validate that route prf is updated quickly to `low`.
|
||||
|
||||
br.set_macfilter_lqi_to_node(leader, 1)
|
||||
br.ping(leader.get_mleid_ip_addr())
|
||||
parent_info = br.get_parent_info()
|
||||
verify(parent_info['Link Quality In'] == '1')
|
||||
|
||||
|
||||
def check_published_route_8():
|
||||
verify(br.get_state() == 'child')
|
||||
routes = br.get_netdata_routes()
|
||||
verify(len(routes) == 1)
|
||||
verify(routes[0].startswith('fc00::/7 s low'))
|
||||
verify(br.br_get_routeprf() == 'low')
|
||||
|
||||
|
||||
verify_within(check_published_route_8, 15)
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Update RSS MAC filter to go back to link quality 3.
|
||||
# Make sure the published route prf is not immediately
|
||||
# updated and only updated after ~5 minutes.
|
||||
|
||||
br.set_macfilter_lqi_to_node(leader, 3)
|
||||
br.ping(leader.get_mleid_ip_addr())
|
||||
parent_info = br.get_parent_info()
|
||||
verify(parent_info['Link Quality In'] == '3')
|
||||
|
||||
verify(br.br_get_routeprf() == 'low')
|
||||
|
||||
|
||||
def check_published_route_9():
|
||||
verify(br.get_state() == 'child')
|
||||
routes = br.get_netdata_routes()
|
||||
verify(len(routes) == 1)
|
||||
verify(routes[0].startswith('fc00::/7 s med'))
|
||||
verify(br.br_get_routeprf() == 'med')
|
||||
|
||||
|
||||
# Wait for 5 minutes
|
||||
|
||||
verify_within(check_published_route_9, (5 * 60 / speedup) + 5)
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------------
|
||||
# Test finished
|
||||
|
||||
cli.Node.finalize_all_nodes()
|
||||
|
||||
print('\'{}\' passed.'.format(test_name))
|
||||
@@ -185,6 +185,7 @@ if [ "$TORANJ_CLI" = 1 ]; then
|
||||
run cli/test-018-next-hop-and-path-cost.py
|
||||
run cli/test-019-netdata-context-id.py
|
||||
run cli/test-020-net-diag-vendor-info.py
|
||||
run cli/test-021-br-route-prf.py
|
||||
run cli/test-022-netdata-full.py
|
||||
run cli/test-400-srp-client-server.py
|
||||
run cli/test-601-channel-manager-channel-change.py
|
||||
|
||||
Reference in New Issue
Block a user