mirror of
https://github.com/espressif/openthread.git
synced 2026-07-29 23:27:46 +00:00
[routing-manager] add support for tracking peer BRs (#10445)
This commit adds a new feature to the `RoutingManager` to enable tracking information about peer Thread Border Routers that are connected to the same Thread network. When enabled, the `RoutingManager` will maintain a record of advertised RIO/PIO prefixes discovered from received Router Advertisement (RA) messages of peer BRs. When disabled (the existing behavior), such entries are not tracked. When tracked, these entries are marked to be disregarded and are not considered in any decision-making processes, such as selecting favored on-link prefixes or determining routes to publish in the Thread Network Data. They are primarily intended for debugging and telemetry (information gathering) purposes.
This commit is contained in:
@@ -1159,6 +1159,7 @@ void RoutingManager::RxRaTracker::ProcessPrefixInfoOption(const PrefixInfoOption
|
||||
{
|
||||
Ip6::Prefix prefix;
|
||||
Entry<OnLinkPrefix> *entry;
|
||||
bool disregard;
|
||||
|
||||
VerifyOrExit(aPio.IsValid());
|
||||
aPio.GetPrefix(prefix);
|
||||
@@ -1169,7 +1170,15 @@ void RoutingManager::RxRaTracker::ProcessPrefixInfoOption(const PrefixInfoOption
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
VerifyOrExit(prefix != Get<RoutingManager>().mOnLinkPrefixManager.GetLocalPrefix());
|
||||
// Disregard the PIO prefix if it matches our local on-link prefix,
|
||||
// as this indicates it's likely from a peer Border Router connected
|
||||
// to the same Thread mesh.
|
||||
|
||||
disregard = (prefix == Get<RoutingManager>().mOnLinkPrefixManager.GetLocalPrefix());
|
||||
|
||||
#if !OPENTHREAD_CONFIG_BORDER_ROUTING_TRACK_PEER_BR_INFO_ENABLE
|
||||
VerifyOrExit(!disregard);
|
||||
#endif
|
||||
|
||||
LogPrefixInfoOption(prefix, aPio.GetValidLifetime(), aPio.GetPreferredLifetime());
|
||||
|
||||
@@ -1198,6 +1207,8 @@ void RoutingManager::RxRaTracker::ProcessPrefixInfoOption(const PrefixInfoOption
|
||||
entry->AdoptValidAndPreferredLifetimesFrom(newPrefix);
|
||||
}
|
||||
|
||||
entry->SetDisregardFlag(disregard);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
@@ -1206,16 +1217,16 @@ void RoutingManager::RxRaTracker::ProcessRouteInfoOption(const RouteInfoOption &
|
||||
{
|
||||
Ip6::Prefix prefix;
|
||||
Entry<RoutePrefix> *entry;
|
||||
bool disregard;
|
||||
|
||||
VerifyOrExit(aRio.IsValid());
|
||||
aRio.GetPrefix(prefix);
|
||||
|
||||
VerifyOrExit(!prefix.IsLinkLocal() && !prefix.IsMulticast());
|
||||
|
||||
VerifyOrExit(Get<RoutingManager>().mOmrPrefixManager.GetLocalPrefix().GetPrefix() != prefix);
|
||||
|
||||
// Disregard our own advertised OMR prefixes and those currently
|
||||
// present in the Thread Network Data.
|
||||
// present in the Thread Network Data. This implies it is likely
|
||||
// from a peer Thread BR connected to the same Thread mesh.
|
||||
//
|
||||
// There should be eventual parity between the `RioAdvertiser`
|
||||
// prefixes and the OMR prefixes in Network Data, but temporary
|
||||
@@ -1223,8 +1234,13 @@ void RoutingManager::RxRaTracker::ProcessRouteInfoOption(const RouteInfoOption &
|
||||
// required to update Network Data (registering with leader). So
|
||||
// both checks are necessary.
|
||||
|
||||
VerifyOrExit(!Get<RoutingManager>().mRioAdvertiser.HasAdvertised(prefix));
|
||||
VerifyOrExit(!Get<NetworkData::Leader>().ContainsOmrPrefix(prefix));
|
||||
disregard = (Get<RoutingManager>().mOmrPrefixManager.GetLocalPrefix().GetPrefix() == prefix) ||
|
||||
Get<RoutingManager>().mRioAdvertiser.HasAdvertised(prefix) ||
|
||||
Get<NetworkData::Leader>().ContainsOmrPrefix(prefix);
|
||||
|
||||
#if !OPENTHREAD_CONFIG_BORDER_ROUTING_TRACK_PEER_BR_INFO_ENABLE
|
||||
VerifyOrExit(!disregard);
|
||||
#endif
|
||||
|
||||
LogRouteInfoOption(prefix, aRio.GetRouteLifetime(), aRio.GetPreference());
|
||||
|
||||
@@ -1250,6 +1266,8 @@ void RoutingManager::RxRaTracker::ProcessRouteInfoOption(const RouteInfoOption &
|
||||
entry->SetFrom(aRio);
|
||||
}
|
||||
|
||||
entry->SetDisregardFlag(disregard);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
@@ -1319,14 +1337,29 @@ template <class PrefixType> void RoutingManager::RxRaTracker::Entry<PrefixType>:
|
||||
void RoutingManager::RxRaTracker::HandleLocalOnLinkPrefixChanged(void)
|
||||
{
|
||||
const Ip6::Prefix &prefix = Get<RoutingManager>().mOnLinkPrefixManager.GetLocalPrefix();
|
||||
bool didRemove = false;
|
||||
bool didChange = false;
|
||||
|
||||
// When `TRACK_PEER_BR_INFO_ENABLE` is enabled, we mark
|
||||
// to disregard any on-link prefix entries matching the new
|
||||
// local on-link prefix. Otherwise, we can remove and free
|
||||
// them.
|
||||
|
||||
for (Router &router : mRouters)
|
||||
{
|
||||
didRemove |= router.mOnLinkPrefixes.RemoveAndFreeAllMatching(prefix);
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_TRACK_PEER_BR_INFO_ENABLE
|
||||
OnLinkPrefix *entry = router.mOnLinkPrefixes.FindMatching(prefix);
|
||||
|
||||
if ((entry != nullptr) && !entry->ShouldDisregard())
|
||||
{
|
||||
entry->SetDisregardFlag(true);
|
||||
didChange = true;
|
||||
}
|
||||
#else
|
||||
didChange |= router.mOnLinkPrefixes.RemoveAndFreeAllMatching(prefix);
|
||||
#endif
|
||||
}
|
||||
|
||||
VerifyOrExit(didRemove);
|
||||
VerifyOrExit(didChange);
|
||||
|
||||
Evaluate();
|
||||
|
||||
@@ -1338,7 +1371,7 @@ void RoutingManager::RxRaTracker::HandleNetDataChange(void)
|
||||
{
|
||||
NetworkData::Iterator iterator = NetworkData::kIteratorInit;
|
||||
NetworkData::OnMeshPrefixConfig prefixConfig;
|
||||
bool didRemove = false;
|
||||
bool didChange = false;
|
||||
|
||||
while (Get<NetworkData::Leader>().GetNextOnMeshPrefix(iterator, prefixConfig) == kErrorNone)
|
||||
{
|
||||
@@ -1349,11 +1382,21 @@ void RoutingManager::RxRaTracker::HandleNetDataChange(void)
|
||||
|
||||
for (Router &router : mRouters)
|
||||
{
|
||||
didRemove |= router.mRoutePrefixes.RemoveAndFreeAllMatching(prefixConfig.GetPrefix());
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_TRACK_PEER_BR_INFO_ENABLE
|
||||
RoutePrefix *entry = router.mRoutePrefixes.FindMatching(prefixConfig.GetPrefix());
|
||||
|
||||
if ((entry != nullptr) && !entry->ShouldDisregard())
|
||||
{
|
||||
entry->SetDisregardFlag(true);
|
||||
didChange = true;
|
||||
}
|
||||
#else
|
||||
didChange |= router.mRoutePrefixes.RemoveAndFreeAllMatching(prefixConfig.GetPrefix());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (didRemove)
|
||||
if (didChange)
|
||||
{
|
||||
Evaluate();
|
||||
}
|
||||
@@ -1395,13 +1438,13 @@ void RoutingManager::RxRaTracker::Evaluate(void)
|
||||
{
|
||||
DecisionFactors oldFactors = mDecisionFactors;
|
||||
TimeMilli now = TimerMilli::GetNow();
|
||||
NextFireTime routerTimeout(now);
|
||||
NextFireTime routerTimeoutTime(now);
|
||||
NextFireTime entryExpireTime(now);
|
||||
NextFireTime staleTime(now);
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Remove expired prefix entries in routers and then remove any
|
||||
// router that has with no prefix entries or flags.
|
||||
// router that has no prefix entries or flags.
|
||||
|
||||
mRouters.RemoveAndFreeAllMatching(Router::EmptyChecker(now));
|
||||
|
||||
@@ -1413,18 +1456,24 @@ void RoutingManager::RxRaTracker::Evaluate(void)
|
||||
|
||||
for (Router &router : mRouters)
|
||||
{
|
||||
router.mAllEntriesDisregarded = true;
|
||||
|
||||
mDecisionFactors.UpdateFlagsFrom(router);
|
||||
|
||||
for (OnLinkPrefix &entry : router.mOnLinkPrefixes)
|
||||
{
|
||||
mDecisionFactors.UpdateFrom(entry);
|
||||
entry.SetStaleTimeCalculated(false);
|
||||
|
||||
router.mAllEntriesDisregarded &= entry.ShouldDisregard();
|
||||
}
|
||||
|
||||
for (RoutePrefix &entry : router.mRoutePrefixes)
|
||||
{
|
||||
mDecisionFactors.UpdateFrom(entry);
|
||||
entry.SetStaleTimeCalculated(false);
|
||||
|
||||
router.mAllEntriesDisregarded &= entry.ShouldDisregard();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1446,11 +1495,12 @@ void RoutingManager::RxRaTracker::Evaluate(void)
|
||||
// their entries, `DetermineStaleTimeFor()` will consider all
|
||||
// matching entries and mark "StaleTimeCalculated" flag on them.
|
||||
|
||||
for (const Router &router : mRouters)
|
||||
for (Router &router : mRouters)
|
||||
{
|
||||
if (router.ShouldCheckReachability())
|
||||
{
|
||||
routerTimeout.UpdateIfEarlier(router.mTimeout);
|
||||
router.DetermineReachabilityTimeout();
|
||||
routerTimeoutTime.UpdateIfEarlier(router.mTimeoutTime);
|
||||
}
|
||||
|
||||
for (const OnLinkPrefix &entry : router.mOnLinkPrefixes)
|
||||
@@ -1486,7 +1536,7 @@ void RoutingManager::RxRaTracker::Evaluate(void)
|
||||
staleTime.UpdateIfEarlier(CalculateExpirationTime(mLocalRaHeaderUpdateTime, interval));
|
||||
}
|
||||
|
||||
mRouterTimer.FireAt(routerTimeout);
|
||||
mRouterTimer.FireAt(routerTimeoutTime);
|
||||
mExpirationTimer.FireAt(entryExpireTime);
|
||||
mStaleTimer.FireAt(staleTime);
|
||||
}
|
||||
@@ -1590,7 +1640,7 @@ void RoutingManager::RxRaTracker::HandleRouterTimer(void)
|
||||
|
||||
for (Router &router : mRouters)
|
||||
{
|
||||
if (!router.ShouldCheckReachability() || (router.mTimeout > now))
|
||||
if (!router.ShouldCheckReachability() || (router.mTimeoutTime > now))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -1599,8 +1649,8 @@ void RoutingManager::RxRaTracker::HandleRouterTimer(void)
|
||||
|
||||
if (router.IsReachable())
|
||||
{
|
||||
router.mTimeout = now + ((router.mNsProbeCount < Router::kMaxNsProbes) ? Router::kNsProbeRetryInterval
|
||||
: Router::kNsProbeTimeout);
|
||||
router.mTimeoutTime = now + ((router.mNsProbeCount < Router::kMaxNsProbes) ? Router::kNsProbeRetryInterval
|
||||
: Router::kNsProbeTimeout);
|
||||
SendNeighborSolicitToRouter(router);
|
||||
}
|
||||
else
|
||||
@@ -1817,7 +1867,27 @@ void RoutingManager::RxRaTracker::Router::ResetReachabilityState(void)
|
||||
|
||||
mNsProbeCount = 0;
|
||||
mLastUpdateTime = TimerMilli::GetNow();
|
||||
mTimeout = mLastUpdateTime + Random::NonCrypto::AddJitter(kReachableTimeout, kJitter);
|
||||
mTimeoutTime = mLastUpdateTime + Random::NonCrypto::AddJitter(kReachableInterval, kJitter);
|
||||
}
|
||||
|
||||
void RoutingManager::RxRaTracker::Router::DetermineReachabilityTimeout(void)
|
||||
{
|
||||
uint32_t interval;
|
||||
|
||||
VerifyOrExit(ShouldCheckReachability());
|
||||
VerifyOrExit(mNsProbeCount == 0);
|
||||
|
||||
// If all of the router's prefix entries are marked as
|
||||
// disregarded (excluded from any decisions), it indicates that
|
||||
// this router is likely a peer BR connected to the same Thread
|
||||
// mesh. We use a longer reachability check interval for such
|
||||
// peer BRs.
|
||||
|
||||
interval = mAllEntriesDisregarded ? kPeerBrReachableInterval : kReachableInterval;
|
||||
mTimeoutTime = mLastUpdateTime + Random::NonCrypto::AddJitter(interval, kJitter);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
bool RoutingManager::RxRaTracker::Router::Matches(const EmptyChecker &aChecker)
|
||||
@@ -1886,6 +1956,8 @@ exit:
|
||||
|
||||
void RoutingManager::RxRaTracker::DecisionFactors::UpdateFrom(const OnLinkPrefix &aOnLinkPrefix)
|
||||
{
|
||||
VerifyOrExit(!aOnLinkPrefix.ShouldDisregard());
|
||||
|
||||
if (aOnLinkPrefix.GetPrefix().IsUniqueLocal())
|
||||
{
|
||||
mHasUlaOnLink = true;
|
||||
@@ -1903,10 +1975,15 @@ void RoutingManager::RxRaTracker::DecisionFactors::UpdateFrom(const OnLinkPrefix
|
||||
|
||||
void RoutingManager::RxRaTracker::DecisionFactors::UpdateFrom(const RoutePrefix &aRoutePrefix)
|
||||
{
|
||||
VerifyOrExit(!aRoutePrefix.ShouldDisregard());
|
||||
|
||||
if (!mHasNonUlaRoute)
|
||||
{
|
||||
mHasNonUlaRoute = !aRoutePrefix.GetPrefix().IsUniqueLocal();
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -677,12 +677,16 @@ private:
|
||||
void SetStaleTimeCalculated(bool aFlag) { mStaleTimeCalculated = aFlag; }
|
||||
bool IsStaleTimeCalculated(void) const { return mStaleTimeCalculated; }
|
||||
|
||||
void SetDisregardFlag(bool aFlag) { mDisregard = aFlag; }
|
||||
bool ShouldDisregard(void) const { return mDisregard; }
|
||||
|
||||
protected:
|
||||
LifetimedPrefix(void) = default;
|
||||
|
||||
TimeMilli CalculateExpirationTime(uint32_t aLifetime) const;
|
||||
|
||||
Ip6::Prefix mPrefix;
|
||||
bool mDisregard : 1;
|
||||
bool mStaleTimeCalculated : 1;
|
||||
uint32_t mValidLifetime;
|
||||
TimeMilli mLastUpdateTime;
|
||||
@@ -808,9 +812,15 @@ private:
|
||||
|
||||
struct Router : public Clearable<Router>
|
||||
{
|
||||
// The timeout (in msec) for router to be considered reachable
|
||||
// before starting the Neighbor Solicitation (NS) probes.
|
||||
static constexpr uint32_t kReachableTimeout = OPENTHREAD_CONFIG_BORDER_ROUTING_ROUTER_ACTIVE_CHECK_TIMEOUT;
|
||||
// Reachability timeout intervals before starting Neighbor
|
||||
// Solicitation (NS) probes. Generally 60 seconds (± 2
|
||||
// seconds jitter) is used. For peer BRs a longer timeout
|
||||
// of 200 seconds (3 min and 20 seconds) is used. This is
|
||||
// selected to be longer than regular RA beacon interval
|
||||
// of 3 minutes (± 15 seconds jitter).
|
||||
|
||||
static constexpr uint32_t kReachableInterval = OPENTHREAD_CONFIG_BORDER_ROUTING_ROUTER_ACTIVE_CHECK_TIMEOUT;
|
||||
static constexpr uint32_t kPeerBrReachableInterval = Time::kOneSecondInMsec * 200;
|
||||
|
||||
static constexpr uint8_t kMaxNsProbes = 5; // Max number of NS probe attempts.
|
||||
static constexpr uint32_t kNsProbeRetryInterval = 1000; // In msec. Time between NS probe attempts.
|
||||
@@ -824,6 +834,7 @@ private:
|
||||
bool IsReachable(void) const { return mNsProbeCount <= kMaxNsProbes; }
|
||||
bool ShouldCheckReachability(void) const;
|
||||
void ResetReachabilityState(void);
|
||||
void DetermineReachabilityTimeout(void);
|
||||
bool Matches(const Ip6::Address &aAddress) const { return aAddress == mAddress; }
|
||||
bool Matches(const EmptyChecker &aChecker);
|
||||
void CopyInfoTo(RouterEntry &aEntry, TimeMilli aNow) const;
|
||||
@@ -835,12 +846,13 @@ private:
|
||||
OnLinkPrefixList mOnLinkPrefixes;
|
||||
RoutePrefixList mRoutePrefixes;
|
||||
TimeMilli mLastUpdateTime;
|
||||
TimeMilli mTimeout;
|
||||
TimeMilli mTimeoutTime;
|
||||
uint8_t mNsProbeCount;
|
||||
bool mManagedAddressConfigFlag : 1;
|
||||
bool mOtherConfigFlag : 1;
|
||||
bool mStubRouterFlag : 1;
|
||||
bool mIsLocalDevice : 1;
|
||||
bool mAllEntriesDisregarded : 1;
|
||||
};
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
@@ -71,6 +71,23 @@
|
||||
#define OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_BORDER_ROUTING_TRACK_PEER_BR_INFO_ENABLE
|
||||
*
|
||||
* Define to 1 to allow the Routing Manager to track information (e.g., advertised prefixes) about peer Thread
|
||||
* Border Routers that are connected to the same Thread network.
|
||||
*
|
||||
* When enabled, the Routing Manager will maintain a record of advertised RIO/PIO prefixes discovered from received
|
||||
* Router Advertisements of peer BRs. These entries are disregarded in decision-making (e.g., selecting favored
|
||||
* on-link prefix or determining which route to publish in the Thread Network Data).
|
||||
*
|
||||
* It is recommended to enable this feature alongside `OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE`.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_BORDER_ROUTING_TRACK_PEER_BR_INFO_ENABLE
|
||||
#define OPENTHREAD_CONFIG_BORDER_ROUTING_TRACK_PEER_BR_INFO_ENABLE OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_ROUTERS
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user