[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:
Abtin Keshavarzian
2024-07-03 11:21:04 -07:00
committed by GitHub
parent 5248408076
commit 41ded02814
3 changed files with 131 additions and 25 deletions
+98 -21
View File
@@ -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;
}
//---------------------------------------------------------------------------------------------------------------------
+16 -4
View File
@@ -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;
};
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+17
View File
@@ -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
*