[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:
Abtin Keshavarzian
2023-07-01 07:50:01 -07:00
committed by GitHub
parent 3d5cb364f2
commit 422f673c7c
15 changed files with 602 additions and 56 deletions
+2 -2
View File
@@ -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
+38
View File
@@ -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`.
*
+33 -39
View File
@@ -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_*`
+36
View File
@@ -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
```
+81
View File
@@ -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"),
};
+17
View File
@@ -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));
+38 -5
View File
@@ -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);
+42 -1
View File
@@ -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
+1
View File
@@ -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++)
+1
View File
@@ -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
View File
@@ -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;
+1
View File
@@ -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);
+24
View File
@@ -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
+263
View File
@@ -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))
+1
View File
@@ -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