From d6221f4d326c07f328bb4fc194ef17f1f3d28174 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 1 May 2023 18:30:14 -0700 Subject: [PATCH] [routing-manager] `RoutePublisher` and new route publishing model (#8986) This commit updates the `RoutingManager` module to implement a new model for publishing routes. The new model replaces the previous model, which explicitly published all discovered routes and on-link prefixes (from processing Router Advertisements on AIL) as external routes in the Network Data. The new model simplifies this logic by publishing either a `fc00::/7` (ULA) route or a `::/0` (default) route in the Network Data, depending on the set of discovered routes and on-link prefixes, and the currently favored OMR prefix. This commit adds the `RoutePublisher` class, a nested sub-component of the `RoutingManager` class. The `RoutePublisher` class is responsible for determining the route prefix to publish and its preference. The preference of the published route is determined based on the current role of the Border Router (BR): low preference if the BR is a child, and medium preference if the BR is acting as a router. This commit also updates `test_routing_manager` unit test validating the new behavior. --- src/core/border_router/routing_manager.cpp | 510 ++++++++------- src/core/border_router/routing_manager.hpp | 96 ++- src/core/thread/network_data_publisher.cpp | 28 +- src/core/thread/network_data_publisher.hpp | 31 + .../border_router/test_manual_maddress.py | 3 +- .../test_multi_border_routers.py | 4 - .../test_multi_thread_networks.py | 8 +- .../border_router/test_on_link_prefix.py | 27 +- .../test_single_border_router.py | 10 +- tests/unit/test_routing_manager.cpp | 593 ++++++++++-------- 10 files changed, 753 insertions(+), 557 deletions(-) diff --git a/src/core/border_router/routing_manager.cpp b/src/core/border_router/routing_manager.cpp index 8563c1fb4..be0d6a4ec 100644 --- a/src/core/border_router/routing_manager.cpp +++ b/src/core/border_router/routing_manager.cpp @@ -72,6 +72,7 @@ RoutingManager::RoutingManager(Instance &aInstance) , mUserSetRioPreference(false) , mOnLinkPrefixManager(aInstance) , mDiscoveredPrefixTable(aInstance) + , mRoutePublisher(aInstance) #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE , mNat64PrefixManager(aInstance) #endif @@ -308,6 +309,8 @@ void RoutingManager::Start(void) mIsRunning = true; UpdateDiscoveredPrefixTableOnNetDataChange(); mOnLinkPrefixManager.Start(); + DetermineFavoredOmrPrefix(); + mRoutePublisher.Start(); mRsSender.Start(); #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE mNat64PrefixManager.Start(); @@ -341,6 +344,8 @@ void RoutingManager::Stop(void) mRoutingPolicyTimer.Stop(); + mRoutePublisher.Stop(); + LogInfo("Border Routing manager stopped"); mIsRunning = false; @@ -407,6 +412,7 @@ void RoutingManager::HandleNotifierEvents(Events aEvents) if (aEvents.Contains(kEventThreadRoleChanged) && !mUserSetRioPreference) { SetRioPreferenceBasedOnRole(); + mRoutePublisher.HandleRoleChanged(); } VerifyOrExit(IsInitialized() && IsEnabled()); @@ -436,7 +442,6 @@ void RoutingManager::UpdateDiscoveredPrefixTableOnNetDataChange(void) { NetworkData::Iterator iterator = NetworkData::kIteratorInit; NetworkData::OnMeshPrefixConfig prefixConfig; - bool foundDefRouteOmrPrefix = false; // Remove all OMR prefixes in Network Data from the // discovered prefix table. Also check if we have @@ -450,33 +455,16 @@ void RoutingManager::UpdateDiscoveredPrefixTableOnNetDataChange(void) } mDiscoveredPrefixTable.RemoveRoutePrefix(prefixConfig.GetPrefix()); - - if (prefixConfig.mDefaultRoute) - { - foundDefRouteOmrPrefix = true; - } } - - // If we find an OMR prefix with default route flag, it indicates - // that this prefix can be used with default route (routable beyond - // infra link). - // - // `DiscoveredPrefixTable` will always track which routers provide - // default route when processing received RA messages, but only - // if we see an OMR prefix with default route flag, we allow it - // to publish the discovered default route (as ::/0 external - // route) in Network Data. - - mDiscoveredPrefixTable.SetAllowDefaultRouteInNetData(foundDefRouteOmrPrefix); } -void RoutingManager::EvaluateOmrPrefix(void) +void RoutingManager::DetermineFavoredOmrPrefix(void) { + // Determine the favored OMR prefix present in Network Data. + NetworkData::Iterator iterator = NetworkData::kIteratorInit; NetworkData::OnMeshPrefixConfig onMeshPrefixConfig; - OT_ASSERT(mIsRunning); - mFavoredOmrPrefix.Clear(); while (Get().GetNextOnMeshPrefix(iterator, onMeshPrefixConfig) == kErrorNone) @@ -491,6 +479,13 @@ void RoutingManager::EvaluateOmrPrefix(void) mFavoredOmrPrefix.SetFrom(onMeshPrefixConfig); } } +} + +void RoutingManager::EvaluateOmrPrefix(void) +{ + OT_ASSERT(mIsRunning); + + DetermineFavoredOmrPrefix(); // Decide if we need to add or remove our local OMR prefix. @@ -520,69 +515,6 @@ exit: return; } -void RoutingManager::EvaluatePublishingPrefix(const Ip6::Prefix &aPrefix) -{ - // This method evaluates whether to publish or unpublish a given - // `aPrefix` as an external route in the Network Data. It makes a - // collective decision by checking with different sub-components to - // see whether or not each wants this prefix published and if so - // at what preference level and flags. - // - // Before calling this method, the sub-components need to make sure - // to update their internal state such that their `ShouldPublish()` - // provides the correct info. - - bool shouldPublish = false; - NetworkData::ExternalRouteConfig routeConfig; - - routeConfig.Clear(); - routeConfig.SetPrefix(aPrefix); - routeConfig.mPreference = NetworkData::kRoutePreferenceLow; - routeConfig.mStable = true; - - VerifyOrExit(mIsRunning); - - // The order of checks is important. The Discovered Prefix Table is - // first followed by Local On Link Prefix manager and finally NAT64 - // prefix manager. - - shouldPublish = mDiscoveredPrefixTable.ShouldPublish(routeConfig); - - if (mOnLinkPrefixManager.ShouldPublish(routeConfig)) - { - shouldPublish = true; - } - -#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE - if (mNat64PrefixManager.ShouldPublish(routeConfig)) - { - shouldPublish = true; - } -#endif - - if (shouldPublish) - { - SuccessOrAssert(Get().PublishExternalRoute( - routeConfig, NetworkData::Publisher::kFromRoutingManager)); - } - else - { - UnpublishExternalRoute(aPrefix); - } - -exit: - return; -} - -void RoutingManager::UnpublishExternalRoute(const Ip6::Prefix &aPrefix) -{ - VerifyOrExit(mIsRunning); - IgnoreError(Get().UnpublishPrefix(aPrefix)); - -exit: - return; -} - // This method evaluate the routing policy depends on prefix and route // information on Thread Network and infra link. As a result, this // method May send RA messages on infra link and publish/unpublish @@ -595,6 +527,7 @@ void RoutingManager::EvaluateRoutingPolicy(void) mOnLinkPrefixManager.Evaluate(); EvaluateOmrPrefix(); + mRoutePublisher.Evaluate(); #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE mNat64PrefixManager.Evaluate(); #endif @@ -1090,6 +1023,7 @@ void RoutingManager::HandleDiscoveredPrefixTableChanged(void) ResetDiscoveredPrefixStaleTimer(); mOnLinkPrefixManager.HandleDiscoveredPrefixTableChanged(); + mRoutePublisher.Evaluate(); exit: return; @@ -1113,15 +1047,19 @@ bool RoutingManager::NetworkDataContainsOmrPrefix(const Ip6::Prefix &aPrefix) co return contains; } -bool RoutingManager::NetworkDataContainsExternalRoute(const Ip6::Prefix &aPrefix) const +bool RoutingManager::NetworkDataContainsUlaRoute(void) const { + // Determine whether leader Network Data contains a route + // prefix which is either the ULA prefix `fc00::/7` or + // a sub-prefix of it (e.g., default route). + NetworkData::Iterator iterator = NetworkData::kIteratorInit; NetworkData::ExternalRouteConfig routeConfig; bool contains = false; while (Get().GetNextExternalRoute(iterator, routeConfig) == kErrorNone) { - if (routeConfig.mStable && routeConfig.GetPrefix() == aPrefix) + if (routeConfig.mStable && RoutePublisher::GetUlaPrefix().ContainsPrefix(routeConfig.GetPrefix())) { contains = true; break; @@ -1223,7 +1161,6 @@ RoutingManager::DiscoveredPrefixTable::DiscoveredPrefixTable(Instance &aInstance , mEntryTimer(aInstance) , mRouterTimer(aInstance) , mSignalTask(aInstance) - , mAllowDefaultRouteInNetData(false) { } @@ -1311,7 +1248,6 @@ void RoutingManager::DiscoveredPrefixTable::ProcessDefaultRoute(const Ip6::Nd::R } mEntryTimer.FireAtIfEarlier(entry->GetExpireTime()); - Get().EvaluatePublishingPrefix(entry->GetPrefix()); SignalTableChanged(); @@ -1358,7 +1294,6 @@ void RoutingManager::DiscoveredPrefixTable::ProcessPrefixInfoOption(const Ip6::N } mEntryTimer.FireAtIfEarlier(entry->GetExpireTime()); - Get().EvaluatePublishingPrefix(entry->GetPrefix()); SignalTableChanged(); @@ -1402,7 +1337,6 @@ void RoutingManager::DiscoveredPrefixTable::ProcessRouteInfoOption(const Ip6::Nd } mEntryTimer.FireAtIfEarlier(entry->GetExpireTime()); - Get().EvaluatePublishingPrefix(entry->GetPrefix()); SignalTableChanged(); @@ -1410,21 +1344,35 @@ exit: return; } -void RoutingManager::DiscoveredPrefixTable::SetAllowDefaultRouteInNetData(bool aAllow) +bool RoutingManager::DiscoveredPrefixTable::Contains(const Entry::Checker &aChecker) const { - Ip6::Prefix prefix; + bool contains = false; - VerifyOrExit(aAllow != mAllowDefaultRouteInNetData); + for (const Router &router : mRouters) + { + if (router.mEntries.ContainsMatching(aChecker)) + { + contains = true; + break; + } + } - LogInfo("Allow default route in netdata: %s -> %s", ToYesNo(mAllowDefaultRouteInNetData), ToYesNo(aAllow)); + return contains; +} - mAllowDefaultRouteInNetData = aAllow; +bool RoutingManager::DiscoveredPrefixTable::ContainsDefaultOrNonUlaRoutePrefix(void) const +{ + return Contains(Entry::Checker(Entry::Checker::kIsNotUla, Entry::kTypeRoute)); +} - prefix.Clear(); - Get().EvaluatePublishingPrefix(prefix); +bool RoutingManager::DiscoveredPrefixTable::ContainsNonUlaOnLinkPrefix(void) const +{ + return Contains(Entry::Checker(Entry::Checker::kIsNotUla, Entry::kTypeOnLink)); +} -exit: - return; +bool RoutingManager::DiscoveredPrefixTable::ContainsUlaOnLinkPrefix(void) const +{ + return Contains(Entry::Checker(Entry::Checker::kIsUla, Entry::kTypeOnLink)); } void RoutingManager::DiscoveredPrefixTable::FindFavoredOnLinkPrefix(Ip6::Prefix &aPrefix) const @@ -1452,32 +1400,6 @@ void RoutingManager::DiscoveredPrefixTable::FindFavoredOnLinkPrefix(Ip6::Prefix } } -bool RoutingManager::DiscoveredPrefixTable::ContainsOnLinkPrefix(const Ip6::Prefix &aPrefix) const -{ - return ContainsPrefix(Entry::Matcher(aPrefix, Entry::kTypeOnLink)); -} - -bool RoutingManager::DiscoveredPrefixTable::ContainsRoutePrefix(const Ip6::Prefix &aPrefix) const -{ - return ContainsPrefix(Entry::Matcher(aPrefix, Entry::kTypeRoute)); -} - -bool RoutingManager::DiscoveredPrefixTable::ContainsPrefix(const Entry::Matcher &aMatcher) const -{ - bool contains = false; - - for (const Router &router : mRouters) - { - if (router.mEntries.ContainsMatching(aMatcher)) - { - contains = true; - break; - } - } - - return contains; -} - void RoutingManager::DiscoveredPrefixTable::RemoveOnLinkPrefix(const Ip6::Prefix &aPrefix) { RemovePrefix(Entry::Matcher(aPrefix, Entry::kTypeOnLink)); @@ -1504,8 +1426,6 @@ void RoutingManager::DiscoveredPrefixTable::RemovePrefix(const Entry::Matcher &a FreeEntries(removedEntries); RemoveRoutersWithNoEntries(); - Get().EvaluatePublishingPrefix(aMatcher.mPrefix); - SignalTableChanged(); exit: @@ -1523,7 +1443,6 @@ void RoutingManager::DiscoveredPrefixTable::RemoveAllEntries(void) while ((entry = router.mEntries.Pop()) != nullptr) { - Get().UnpublishExternalRoute(entry->GetPrefix()); FreeEntry(*entry); SignalTableChanged(); } @@ -1672,29 +1591,6 @@ const RoutingManager::DiscoveredPrefixTable::Entry *RoutingManager::DiscoveredPr return favoredEntry; } -bool RoutingManager::DiscoveredPrefixTable::ShouldPublish(NetworkData::ExternalRouteConfig &aRouteConfig) const -{ - bool shouldPublish = false; - const Entry *favoredEntry; - - if (aRouteConfig.GetPrefix().GetLength() == 0) - { - // If the change is to default route ::/0 prefix, make sure we - // are allowed to publish default route in Network Data. - - VerifyOrExit(mAllowDefaultRouteInNetData); - } - - favoredEntry = FindFavoredEntryToPublish(aRouteConfig.GetPrefix()); - VerifyOrExit(favoredEntry != nullptr); - - shouldPublish = true; - aRouteConfig.mPreference = favoredEntry->GetPreference(); - -exit: - return shouldPublish; -} - void RoutingManager::DiscoveredPrefixTable::HandleEntryTimer(void) { RemoveExpiredEntries(); } void RoutingManager::DiscoveredPrefixTable::RemoveExpiredEntries(void) @@ -1710,14 +1606,6 @@ void RoutingManager::DiscoveredPrefixTable::RemoveExpiredEntries(void) RemoveRoutersWithNoEntries(); - // Determine if we need to publish/unpublish any prefixes in - // the Network Data. - - for (const Entry &expiredEntry : expiredEntries) - { - Get().EvaluatePublishingPrefix(expiredEntry.GetPrefix()); - } - if (!expiredEntries.IsEmpty()) { SignalTableChanged(); @@ -1927,6 +1815,11 @@ bool RoutingManager::DiscoveredPrefixTable::Entry::Matches(const Matcher &aMatch return (mType == aMatcher.mType) && (mPrefix == aMatcher.mPrefix); } +bool RoutingManager::DiscoveredPrefixTable::Entry::Matches(const Checker &aChecker) const +{ + return (mType == aChecker.mType) && (mPrefix.IsUniqueLocal() == (aChecker.mMode == Checker::kIsUla)); +} + bool RoutingManager::DiscoveredPrefixTable::Entry::Matches(const ExpirationChecker &aChecker) const { return GetExpireTime() <= aChecker.mNow; @@ -2006,6 +1899,15 @@ uint32_t RoutingManager::DiscoveredPrefixTable::Entry::CalculateExpireDelay(uint //--------------------------------------------------------------------------------------------------------------------- // OmrPrefix +bool RoutingManager::OmrPrefix::IsInfrastructureDerived(void) const +{ + // Indicate whether the OMR prefix is infrastructure-derived which + // can be identified as a valid OMR prefix with preference of + // medium or higher. + + return !IsEmpty() && (mPreference >= NetworkData::kRoutePreferenceMedium); +} + void RoutingManager::OmrPrefix::SetFrom(const NetworkData::OnMeshPrefixConfig &aOnMeshPrefixConfig) { mPrefix = aOnMeshPrefixConfig.GetPrefix(); @@ -2228,25 +2130,12 @@ exit: return; } -void RoutingManager::OnLinkPrefixManager::Start(void) -{ - Get().EvaluatePublishingPrefix(mLocalPrefix); - - for (const OldPrefix &oldPrefix : mOldLocalPrefixes) - { - Get().EvaluatePublishingPrefix(oldPrefix.mPrefix); - } -} +void RoutingManager::OnLinkPrefixManager::Start(void) {} void RoutingManager::OnLinkPrefixManager::Stop(void) { mFavoredDiscoveredPrefix.Clear(); - for (const OldPrefix &oldPrefix : mOldLocalPrefixes) - { - Get().UnpublishExternalRoute(oldPrefix.mPrefix); - } - switch (mState) { case kIdle: @@ -2255,7 +2144,6 @@ void RoutingManager::OnLinkPrefixManager::Stop(void) case kPublishing: case kAdvertising: case kDeprecating: - Get().UnpublishExternalRoute(mLocalPrefix); mState = kDeprecating; break; } @@ -2360,16 +2248,15 @@ void RoutingManager::OnLinkPrefixManager::PublishAndAdvertise(void) mState = kPublishing; ResetExpireTime(TimerMilli::GetNow()); - LogInfo("Publishing local on-link prefix %s in netdata", mLocalPrefix.ToString().AsCString()); - Get().EvaluatePublishingPrefix(mLocalPrefix); + // We wait for the ULA `fc00::/7` route or a sub-prefix of it (e.g., + // default route) to be added in Network Data before + // starting to advertise the local on-link prefix in RAs. + // However, if it is already present in Network Data (e.g., + // added by another BR on the same Thread mesh), we can + // immediately start advertising it. - // We wait for the prefix to be added in Network Data before - // starting to advertise it in RAs. However, if it is already - // present in Network Data (e.g., added by another BR on the same - // Thread mesh), we can immediately start advertising it. - - if (Get().NetworkDataContainsExternalRoute(mLocalPrefix)) + if (Get().NetworkDataContainsUlaRoute()) { EnterAdvertisingState(); } @@ -2401,31 +2288,14 @@ void RoutingManager::OnLinkPrefixManager::Deprecate(void) } } -bool RoutingManager::OnLinkPrefixManager::ShouldPublish(NetworkData::ExternalRouteConfig &aRouteConfig) const +bool RoutingManager::OnLinkPrefixManager::ShouldPublishUlaRoute(void) const { - bool shouldPublish = false; + // Determine whether or not we should publish ULA prefix. We need + // to publish if we are in any of `kPublishing`, `kAdvertising`, + // or `kDeprecating` states, or if there is at least one old local + // prefix being deprecated. - if (aRouteConfig.GetPrefix() == mLocalPrefix) - { - switch (mState) - { - case kIdle: - break; - case kPublishing: - case kAdvertising: - case kDeprecating: - shouldPublish = true; - aRouteConfig.mPreference = NetworkData::kRoutePreferenceMedium; - break; - } - } - else if (mOldLocalPrefixes.ContainsMatching(aRouteConfig.GetPrefix())) - { - shouldPublish = true; - aRouteConfig.mPreference = NetworkData::kRoutePreferenceMedium; - } - - return shouldPublish; + return (mState != kIdle) || !mOldLocalPrefixes.IsEmpty(); } void RoutingManager::OnLinkPrefixManager::ResetExpireTime(TimeMilli aNow) @@ -2515,7 +2385,7 @@ void RoutingManager::OnLinkPrefixManager::HandleNetDataChange(void) { VerifyOrExit(mState == kPublishing); - if (Get().NetworkDataContainsExternalRoute(mLocalPrefix)) + if (Get().NetworkDataContainsUlaRoute()) { EnterAdvertisingState(); Get().ScheduleRoutingPolicyEvaluation(kAfterRandomDelay); @@ -2528,7 +2398,7 @@ exit: void RoutingManager::OnLinkPrefixManager::HandleExtPanIdChange(void) { // If the current local prefix is being advertised or deprecated, - // we save it in `mOldLocalPrefixes` and keep deprecating it . It will + // we save it in `mOldLocalPrefixes` and keep deprecating it. It will // be included in emitted RAs as PIO with zero preferred lifetime. // It will still be present in Network Data until its expire time // so to allow Thread nodes to continue to communicate with `InfraIf` @@ -2544,10 +2414,7 @@ void RoutingManager::OnLinkPrefixManager::HandleExtPanIdChange(void) switch (oldState) { case kIdle: - break; - case kPublishing: - Get().EvaluatePublishingPrefix(oldPrefix); break; case kAdvertising: @@ -2558,6 +2425,7 @@ void RoutingManager::OnLinkPrefixManager::HandleExtPanIdChange(void) if (Get().mIsRunning) { + Get().mRoutePublisher.Evaluate(); Get().ScheduleRoutingPolicyEvaluation(kAfterRandomDelay); } @@ -2606,13 +2474,6 @@ void RoutingManager::OnLinkPrefixManager::DeprecateOldPrefix(const Ip6::Prefix & SavePrefix(aPrefix, aExpireTime); - Get().EvaluatePublishingPrefix(aPrefix); - - if (removedPrefix.GetLength() != 0) - { - Get().EvaluatePublishingPrefix(removedPrefix); - } - exit: return; } @@ -2644,7 +2505,6 @@ void RoutingManager::OnLinkPrefixManager::HandleTimer(void) LogInfo("Local on-link prefix %s expired", mLocalPrefix.ToString().AsCString()); IgnoreError(Get().RemoveBrOnLinkPrefix(mLocalPrefix)); mState = kIdle; - Get().EvaluatePublishingPrefix(mLocalPrefix); } else { @@ -2670,14 +2530,14 @@ void RoutingManager::OnLinkPrefixManager::HandleTimer(void) LogInfo("Old local on-link prefix %s expired", prefix.ToString().AsCString()); IgnoreError(Get().RemoveBrOnLinkPrefix(prefix)); mOldLocalPrefixes.RemoveMatching(prefix); - - Get().EvaluatePublishingPrefix(prefix); } if (nextExpireTime != now.GetDistantFuture()) { mTimer.FireAtIfEarlier(nextExpireTime); } + + Get().mRoutePublisher.Evaluate(); } //--------------------------------------------------------------------------------------------------------------------- @@ -2716,6 +2576,188 @@ void RoutingManager::OnMeshPrefixArray::MarkAsDeleted(const OnMeshPrefix &aPrefi } } +//--------------------------------------------------------------------------------------------------------------------- +// RoutePublisher + +const otIp6Prefix RoutingManager::RoutePublisher::kUlaPrefix = { + {{{0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + 7, +}; + +RoutingManager::RoutePublisher::RoutePublisher(Instance &aInstance) + : InstanceLocator(aInstance) + , mState(kDoNotPublish) + , mPreference(NetworkData::kRoutePreferenceMedium) + , mUserSetPreference(false) +{ +} + +void RoutingManager::RoutePublisher::Evaluate(void) +{ + State newState = kDoNotPublish; + + VerifyOrExit(Get().IsRunning()); + + if (Get().mFavoredOmrPrefix.IsInfrastructureDerived() && + Get().mDiscoveredPrefixTable.ContainsDefaultOrNonUlaRoutePrefix()) + { + newState = kPublishDefault; + } + else if (Get().mDiscoveredPrefixTable.ContainsNonUlaOnLinkPrefix()) + { + newState = kPublishDefault; + } + else if (Get().mDiscoveredPrefixTable.ContainsUlaOnLinkPrefix() || + Get().mOnLinkPrefixManager.ShouldPublishUlaRoute()) + { + newState = kPublishUla; + } + +exit: + if (newState != mState) + { + LogInfo("RoutePublisher state: %s -> %s", StateToString(mState), StateToString(newState)); + UpdatePublishedRoute(newState); + } +} + +void RoutingManager::RoutePublisher::DeterminePrefixFor(State aState, Ip6::Prefix &aPrefix) const +{ + aPrefix.Clear(); + + switch (aState) + { + case kDoNotPublish: + case kPublishDefault: + // `Clear()` will set the prefix `::/0`. + break; + case kPublishUla: + aPrefix = GetUlaPrefix(); + break; + } +} + +void RoutingManager::RoutePublisher::UpdatePublishedRoute(State aNewState) +{ + // Updates the published route entry in Network Data, transitioning + // from current `mState` to new `aNewState`. This method can be used + // when there is no change to `mState` but a change to `mPreference`. + + Ip6::Prefix oldPrefix; + NetworkData::ExternalRouteConfig routeConfig; + + DeterminePrefixFor(mState, oldPrefix); + + if (aNewState == kDoNotPublish) + { + VerifyOrExit(mState != kDoNotPublish); + IgnoreError(Get().UnpublishPrefix(oldPrefix)); + ExitNow(); + } + + routeConfig.Clear(); + routeConfig.mPreference = mPreference; + routeConfig.mStable = true; + DeterminePrefixFor(aNewState, routeConfig.GetPrefix()); + + // If we were not publishing a route prefix before, publish the new + // `routeConfig`. Otherwise, use `ReplacePublishedExternalRoute()` to + // replace the previously published prefix entry. This ensures that we do + // not have a situation where the previous route is removed while the new + // one is not yet added in the Network Data. + + if (mState == kDoNotPublish) + { + SuccessOrAssert(Get().PublishExternalRoute( + routeConfig, NetworkData::Publisher::kFromRoutingManager)); + } + else + { + SuccessOrAssert(Get().ReplacePublishedExternalRoute( + oldPrefix, routeConfig, NetworkData::Publisher::kFromRoutingManager)); + } + +exit: + mState = aNewState; +} + +void RoutingManager::RoutePublisher::Unpublish(void) +{ + // Unpublish the previously published route based on `mState` + // and update `mState`. + + Ip6::Prefix prefix; + + VerifyOrExit(mState != kDoNotPublish); + DeterminePrefixFor(mState, prefix); + IgnoreError(Get().UnpublishPrefix(prefix)); + mState = kDoNotPublish; + +exit: + return; +} + +void RoutingManager::RoutePublisher::SetPreference(RoutePreference aPreference) +{ + LogInfo("User explicitly set published route preference to %s", RoutePreferenceToString(aPreference)); + mUserSetPreference = true; + UpdatePreference(aPreference); +} + +void RoutingManager::RoutePublisher::ClearPreference(void) +{ + VerifyOrExit(mUserSetPreference); + + LogInfo("User cleared explicitly set published route preference - set based on role"); + mUserSetPreference = false; + SetPreferenceBasedOnRole(); + +exit: + return; +} + +void RoutingManager::RoutePublisher::SetPreferenceBasedOnRole(void) +{ + UpdatePreference(Get().IsRouterOrLeader() ? NetworkData::kRoutePreferenceMedium + : NetworkData::kRoutePreferenceLow); +} + +void RoutingManager::RoutePublisher::HandleRoleChanged(void) +{ + if (!mUserSetPreference) + { + SetPreferenceBasedOnRole(); + } +} + +void RoutingManager::RoutePublisher::UpdatePreference(RoutePreference aPreference) +{ + VerifyOrExit(mPreference != aPreference); + + LogInfo("Published route preference changed: %s -> %s", RoutePreferenceToString(mPreference), + RoutePreferenceToString(aPreference)); + mPreference = aPreference; + UpdatePublishedRoute(mState); + +exit: + return; +} + +const char *RoutingManager::RoutePublisher::StateToString(State aState) +{ + static const char *const kStateStrings[] = { + "none", // (0) kDoNotPublish + "def-route", // (1) kPublishDefault + "ula", // (2) kPublishUla + }; + + static_assert(0 == kDoNotPublish, "kDoNotPublish value is incorrect"); + static_assert(1 == kPublishDefault, "kPublishDefault value is incorrect"); + static_assert(2 == kPublishUla, "kPublishUla value is incorrect"); + + return kStateStrings[aState]; +} + #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE //--------------------------------------------------------------------------------------------------------------------- @@ -2768,7 +2810,7 @@ void RoutingManager::Nat64PrefixManager::Stop(void) if (mPublishedPrefix.IsValidNat64()) { - Get().UnpublishExternalRoute(mPublishedPrefix); + IgnoreError(Get().UnpublishPrefix(mPublishedPrefix)); } mPublishedPrefix.Clear(); @@ -2843,18 +2885,15 @@ void RoutingManager::Nat64PrefixManager::Evaluate(void) if (mPublishedPrefix.IsValidNat64() && (!shouldPublish || (prefix != mPublishedPrefix))) { - Ip6::Prefix prevPrefix; - - prevPrefix = mPublishedPrefix; + IgnoreError(Get().UnpublishPrefix(mPublishedPrefix)); mPublishedPrefix.Clear(); - Get().EvaluatePublishingPrefix(prevPrefix); } if (shouldPublish && ((prefix != mPublishedPrefix) || (preference != mPublishedPreference))) { mPublishedPrefix = prefix; mPublishedPreference = preference; - Get().EvaluatePublishingPrefix(mPublishedPrefix); + Publish(); } #if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE @@ -2874,19 +2913,18 @@ exit: return; } -bool RoutingManager::Nat64PrefixManager::ShouldPublish(NetworkData::ExternalRouteConfig &aRouteConfig) const +void RoutingManager::Nat64PrefixManager::Publish(void) { - bool shouldPublish = false; + NetworkData::ExternalRouteConfig routeConfig; - VerifyOrExit(mPublishedPrefix.IsValidNat64()); - VerifyOrExit(mPublishedPrefix == aRouteConfig.GetPrefix()); + routeConfig.Clear(); + routeConfig.SetPrefix(mPublishedPrefix); + routeConfig.mPreference = mPublishedPreference; + routeConfig.mStable = true; + routeConfig.mNat64 = true; - shouldPublish = true; - aRouteConfig.mPreference = mPublishedPreference; - aRouteConfig.mNat64 = true; - -exit: - return shouldPublish; + SuccessOrAssert( + Get().PublishExternalRoute(routeConfig, NetworkData::Publisher::kFromRoutingManager)); } void RoutingManager::Nat64PrefixManager::HandleTimer(void) diff --git a/src/core/border_router/routing_manager.hpp b/src/core/border_router/routing_manager.hpp index 1e365f2c5..5e3fe9d3c 100644 --- a/src/core/border_router/routing_manager.hpp +++ b/src/core/border_router/routing_manager.hpp @@ -92,14 +92,12 @@ public: * This is used by `NetworkData::Publisher` to reserve entries for use by `RoutingManager`. * * The number of published entries accounts for: - * - Max number of discovered prefix entries, - * - One entry for local on-link prefixes, - * - Max number of old (deprecating) local on-link prefixes, + * - Route prefix `fc00::/7` or `::/0` * - One entry for NAT64 published prefix. + * - One extra entry for transitions. * */ - static constexpr uint16_t kMaxPublishedPrefixes = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_PREFIXES + 1 + - OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_OLD_ON_LINK_PREFIXES + 1; + static constexpr uint16_t kMaxPublishedPrefixes = 3; /** * This enumeration represents the states of `RoutingManager`. @@ -501,17 +499,15 @@ private: const Ip6::Address &aSrcAddress); void ProcessNeighborAdvertMessage(const Ip6::Nd::NeighborAdvertMessage &aNaMessage); - void SetAllowDefaultRouteInNetData(bool aAllow); + bool ContainsDefaultOrNonUlaRoutePrefix(void) const; + bool ContainsNonUlaOnLinkPrefix(void) const; + bool ContainsUlaOnLinkPrefix(void) const; void FindFavoredOnLinkPrefix(Ip6::Prefix &aPrefix) const; - bool ContainsOnLinkPrefix(const Ip6::Prefix &aPrefix) const; + void RemoveOnLinkPrefix(const Ip6::Prefix &aPrefix); - - bool ContainsRoutePrefix(const Ip6::Prefix &aPrefix) const; void RemoveRoutePrefix(const Ip6::Prefix &aPrefix); - bool ShouldPublish(NetworkData::ExternalRouteConfig &aRouteConfig) const; - void RemoveAllEntries(void); void RemoveOrDeprecateOldEntries(TimeMilli aTimeThreshold); @@ -548,7 +544,26 @@ private: } const Ip6::Prefix &mPrefix; - bool mType; + Type mType; + }; + + struct Checker + { + enum Mode : uint8_t + { + kIsUla, + kIsNotUla, + }; + + Checker(Mode aMode, Type aType) + : mMode(aMode) + , mType(aType) + + { + } + + Mode mMode; + Type mType; }; struct ExpirationChecker @@ -566,6 +581,7 @@ private: void SetFrom(const Ip6::Nd::RouteInfoOption &aRio); Type GetType(void) const { return mType; } bool IsOnLinkPrefix(void) const { return (mType == kTypeOnLink); } + bool IsRoutePrefix(void) const { return (mType == kTypeRoute); } const Ip6::Prefix &GetPrefix(void) const { return mPrefix; } const TimeMilli &GetLastUpdateTime(void) const { return mLastUpdateTime; } uint32_t GetValidLifetime(void) const { return mValidLifetime; } @@ -575,6 +591,7 @@ private: RoutePreference GetPreference(void) const; bool operator==(const Entry &aOther) const; bool Matches(const Matcher &aMatcher) const; + bool Matches(const Checker &aChecker) const; bool Matches(const ExpirationChecker &aChecker) const; // Methods to use when `IsOnLinkPrefix()` @@ -642,7 +659,7 @@ private: void ProcessDefaultRoute(const Ip6::Nd::RouterAdvertMessage::Header &aRaHeader, Router &aRouter); void ProcessPrefixInfoOption(const Ip6::Nd::PrefixInfoOption &aPio, Router &aRouter); void ProcessRouteInfoOption(const Ip6::Nd::RouteInfoOption &aRio, Router &aRouter); - bool ContainsPrefix(const Entry::Matcher &aMatcher) const; + bool Contains(const Entry::Checker &aChecker) const; void RemovePrefix(const Entry::Matcher &aMatcher); void RemoveOrDeprecateEntriesFromInactiveRouters(void); void RemoveRoutersWithNoEntries(void); @@ -665,7 +682,6 @@ private: EntryTimer mEntryTimer; RouterTimer mRouterTimer; SignalTask mSignalTask; - bool mAllowDefaultRouteInNetData; }; class LocalOmrPrefix; @@ -676,6 +692,7 @@ private: OmrPrefix(void) { Clear(); } bool IsEmpty(void) const { return (mPrefix.GetLength() == 0); } + bool IsInfrastructureDerived(void) const; void SetFrom(const NetworkData::OnMeshPrefixConfig &aOnMeshPrefixConfig); void SetFrom(const LocalOmrPrefix &aLocalOmrPrefix); const Ip6::Prefix &GetPrefix(void) const { return mPrefix; } @@ -723,7 +740,7 @@ private: const Ip6::Prefix &GetFavoredDiscoveredPrefix(void) const { return mFavoredDiscoveredPrefix; } bool IsInitalEvaluationDone(void) const; void HandleDiscoveredPrefixTableChanged(void); - bool ShouldPublish(NetworkData::ExternalRouteConfig &aRouteConfig) const; + bool ShouldPublishUlaRoute(void) const; void AppendAsPiosTo(Ip6::Nd::RouterAdvertMessage &aRaMessage); bool IsPublishingOrAdvertising(void) const; void HandleNetDataChange(void); @@ -803,12 +820,12 @@ private: const Ip6::Prefix &GetLocalPrefix(void) const { return mLocalPrefix; } const Ip6::Prefix &GetFavoredPrefix(RoutePreference &aPreference) const; void Evaluate(void); - bool ShouldPublish(NetworkData::ExternalRouteConfig &aRouteConfig) const; void HandleDiscoverDone(const Ip6::Prefix &aPrefix); void HandleTimer(void); private: void Discover(void); + void Publish(void); using Nat64Timer = TimerMilliIn; @@ -822,6 +839,46 @@ private: }; #endif // OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE + class RoutePublisher : public InstanceLocator // Manages the routes that are published in net data + { + public: + explicit RoutePublisher(Instance &aInstance); + + void Start(void) { Evaluate(); } + void Stop(void) { Unpublish(); } + void Evaluate(void); + + RoutePreference GetPreference(void) const { return mPreference; } + void SetPreference(RoutePreference aPreference); + void ClearPreference(void); + + void HandleRoleChanged(void); + + static const Ip6::Prefix &GetUlaPrefix(void) { return AsCoreType(&kUlaPrefix); } + + private: + static const otIp6Prefix kUlaPrefix; + + enum State : uint8_t + { + kDoNotPublish, // Do not publish any routes in network data. + kPublishDefault, // Publish "::/0" route in network data. + kPublishUla, // Publish "fc00::/7" route in network data. + }; + + void DeterminePrefixFor(State aState, Ip6::Prefix &aPrefix) const; + void UpdatePublishedRoute(State aNewState); + void Unpublish(void); + void SetPreferenceBasedOnRole(void); + void UpdatePreference(RoutePreference aPreference); + + static const char *StateToString(State aState); + + State mState; + RoutePreference mPreference; + bool mUserSetPreference; + }; + struct RaInfo { // Tracks info about emitted RA messages: Number of RAs sent, @@ -895,9 +952,8 @@ private: void EvaluateRoutingPolicy(void); bool IsInitalPolicyEvaluationDone(void) const; void ScheduleRoutingPolicyEvaluation(ScheduleMode aMode); + void DetermineFavoredOmrPrefix(void); void EvaluateOmrPrefix(void); - void EvaluatePublishingPrefix(const Ip6::Prefix &aPrefix); - void UnpublishExternalRoute(const Ip6::Prefix &aPrefix); void HandleRsSenderFinished(TimeMilli aStartTime); void SendRouterAdvertisement(RouterAdvTxMode aRaTxMode); @@ -910,7 +966,7 @@ private: bool ShouldProcessRouteInfoOption(const Ip6::Nd::RouteInfoOption &aRio, const Ip6::Prefix &aPrefix); void UpdateDiscoveredPrefixTableOnNetDataChange(void); bool NetworkDataContainsOmrPrefix(const Ip6::Prefix &aPrefix) const; - bool NetworkDataContainsExternalRoute(const Ip6::Prefix &aPrefix) const; + bool NetworkDataContainsUlaRoute(void) const; void UpdateRouterAdvertHeader(const Ip6::Nd::RouterAdvertMessage *aRouterAdvertMessage); bool IsReceivedRouterAdvertFromManager(const Ip6::Nd::RouterAdvertMessage &aRaMessage) const; void ResetDiscoveredPrefixStaleTimer(void); @@ -949,6 +1005,8 @@ private: DiscoveredPrefixTable mDiscoveredPrefixTable; + RoutePublisher mRoutePublisher; + #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE Nat64PrefixManager mNat64PrefixManager; #endif diff --git a/src/core/thread/network_data_publisher.cpp b/src/core/thread/network_data_publisher.cpp index 22c31d9e5..056765cb9 100644 --- a/src/core/thread/network_data_publisher.cpp +++ b/src/core/thread/network_data_publisher.cpp @@ -95,6 +95,13 @@ exit: } Error Publisher::PublishExternalRoute(const ExternalRouteConfig &aConfig, Requester aRequester) +{ + return ReplacePublishedExternalRoute(aConfig.GetPrefix(), aConfig, aRequester); +} + +Error Publisher::ReplacePublishedExternalRoute(const Ip6::Prefix &aPrefix, + const ExternalRouteConfig &aConfig, + Requester aRequester) { Error error = kErrorNone; PrefixEntry *entry; @@ -102,7 +109,7 @@ Error Publisher::PublishExternalRoute(const ExternalRouteConfig &aConfig, Reques VerifyOrExit(aConfig.IsValid(GetInstance()), error = kErrorInvalidArgs); VerifyOrExit(aConfig.mStable, error = kErrorInvalidArgs); - entry = FindOrAllocatePrefixEntry(aConfig.GetPrefix(), aRequester); + entry = FindOrAllocatePrefixEntry(aPrefix, aRequester); VerifyOrExit(entry != nullptr, error = kErrorNoBufs); entry->Publish(aConfig, aRequester); @@ -806,23 +813,24 @@ void Publisher::PrefixEntry::Publish(const Ip6::Prefix &aPrefix, if (GetState() != kNoEntry) { - // If this is an existing entry, first we check that there is - // a change in either type or flags. We remove the old entry - // from Network Data if it was added. If the only change is - // to flags (e.g., change to the preference level) and the - // entry was previously added in Network Data, we re-add it - // with the new flags. This ensures that changes to flags are - // immediately reflected in the Network Data. + // If this is an existing entry, check if there is a change in + // type, flags, or the prefix itself. If not, everything is + // as before. If something is different, first, remove the + // old entry from Network Data if it was added. Then, re-add + // the new prefix/flags (replacing the old entry). This + // ensures the changes are immediately reflected in the + // Network Data. State oldState = GetState(); - VerifyOrExit((mType != aNewType) || (mFlags != aNewFlags)); + VerifyOrExit((mType != aNewType) || (mFlags != aNewFlags) || (mPrefix != aPrefix)); Remove(/* aNextState */ kNoEntry); if ((mType == aNewType) && ((oldState == kAdded) || (oldState == kRemoving))) { - mFlags = aNewFlags; + mPrefix = aPrefix; + mFlags = aNewFlags; Add(); } } diff --git a/src/core/thread/network_data_publisher.hpp b/src/core/thread/network_data_publisher.hpp index d042311e7..025462d5a 100644 --- a/src/core/thread/network_data_publisher.hpp +++ b/src/core/thread/network_data_publisher.hpp @@ -266,6 +266,37 @@ public: */ Error PublishExternalRoute(const ExternalRouteConfig &aConfig, Requester aRequester); + /** + * This method replaces a previously published external route. + * + * Only stable entries can be published (i.e.,`aConfig.mStable` MUST be `true`). + * + * If there is no previously published external route matching @p aPrefix, this method behaves similarly to + * `PublishExternalRoute()`, i.e., it will start the process of publishing @a aConfig as an external route in the + * Thread Network Data. + * + * If there is a previously published route entry matching @p aPrefix, it will be replaced with the new prefix from + * @p aConfig. In particular, if the @p aPrefix was already added in the Network Data, the change to the new prefix + * in @p aConfig is immediately reflected in the Network Data (i.e., @p aPrefix is removed and the new prefix is + * added in the same Network Data registration request to leader). This ensures that route entries in the Network + * Data are not abruptly removed and the transition from @p aPrefix to new prefix is smooth. + * + * @param[in] aPrefix The previously published external route prefix to replace. + * @param[in] aConfig The external route config to publish. + * @param[in] aRequester The requester (`kFromUser` or `kFromRoutingManager` module). + * + * @retval kErrorNone The external route is published successfully. + * @retval kErrorInvalidArgs The @p aConfig is not valid (bad prefix, invalid flag combinations, or not stable). + * @retval kErrorNoBufs Could not allocate an entry for the new request. Publisher supports a limited number + * of entries (shared between on-mesh prefix and external route) determined by config + * `OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES`. + * + * + */ + Error ReplacePublishedExternalRoute(const Ip6::Prefix &aPrefix, + const ExternalRouteConfig &aConfig, + Requester aRequester); + /** * This method indicates whether or not currently a published prefix entry (on-mesh or external route) is added to * the Thread Network Data. diff --git a/tests/scripts/thread-cert/border_router/test_manual_maddress.py b/tests/scripts/thread-cert/border_router/test_manual_maddress.py index 1bbe19007..536d3adca 100644 --- a/tests/scripts/thread-cert/border_router/test_manual_maddress.py +++ b/tests/scripts/thread-cert/border_router/test_manual_maddress.py @@ -108,8 +108,7 @@ class ManualMulticastAddressConfig(thread_cert.TestCase): # packet back to Host. # TD receives the MPL packet containing an encapsulated ping packet to # MA1, sent by Host, and unicasts a ping response packet back to Host. - pkts.filter_eth_src(vars['TD_ETH']) \ - .filter_ipv6_dst(_pkt.ipv6.src) \ + pkts.filter_ipv6_dst(_pkt.ipv6.src) \ .filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier) \ .must_next() diff --git a/tests/scripts/thread-cert/border_router/test_multi_border_routers.py b/tests/scripts/thread-cert/border_router/test_multi_border_routers.py index 2e5855b59..ab354d171 100755 --- a/tests/scripts/thread-cert/border_router/test_multi_border_routers.py +++ b/tests/scripts/thread-cert/border_router/test_multi_border_routers.py @@ -147,8 +147,6 @@ class MultiBorderRouters(thread_cert.TestCase): self.assertEqual(len(router2.get_netdata_non_nat64_prefixes()), 2) br1_on_link_prefix = br1.get_br_on_link_prefix() - self.assertEqual(br1_on_link_prefix, br1.get_netdata_non_nat64_prefixes()[0]) - self.assertEqual(br1_on_link_prefix, br1.get_netdata_non_nat64_prefixes()[0]) self.assertEqual(len(br1.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1) self.assertEqual(len(router1.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1) @@ -200,8 +198,6 @@ class MultiBorderRouters(thread_cert.TestCase): self.assertEqual(len(router2.get_netdata_non_nat64_prefixes()), 1) br2_on_link_prefix = br2.get_br_on_link_prefix() - self.assertEqual(set(map(IPv6Network, br2.get_netdata_non_nat64_prefixes())), - set(map(IPv6Network, [br1_on_link_prefix, br2_on_link_prefix]))) self.assertEqual(len(br1.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1) self.assertEqual(len(router1.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1) diff --git a/tests/scripts/thread-cert/border_router/test_multi_thread_networks.py b/tests/scripts/thread-cert/border_router/test_multi_thread_networks.py index d7ebc8066..bc2bb38a8 100755 --- a/tests/scripts/thread-cert/border_router/test_multi_thread_networks.py +++ b/tests/scripts/thread-cert/border_router/test_multi_thread_networks.py @@ -130,10 +130,10 @@ class MultiThreadNetworks(thread_cert.TestCase): # Each BR should independently register an external route for the on-link prefix # and OMR prefix in another Thread Network. - self.assertTrue(len(br1.get_netdata_non_nat64_prefixes()) == 2) - self.assertTrue(len(router1.get_netdata_non_nat64_prefixes()) == 2) - self.assertTrue(len(br2.get_netdata_non_nat64_prefixes()) == 2) - self.assertTrue(len(router2.get_netdata_non_nat64_prefixes()) == 2) + self.assertTrue(len(br1.get_netdata_non_nat64_prefixes()) == 1) + self.assertTrue(len(router1.get_netdata_non_nat64_prefixes()) == 1) + self.assertTrue(len(br2.get_netdata_non_nat64_prefixes()) == 1) + self.assertTrue(len(router2.get_netdata_non_nat64_prefixes()) == 1) br1_external_routes = br1.get_routes() br2_external_routes = br2.get_routes() diff --git a/tests/scripts/thread-cert/border_router/test_on_link_prefix.py b/tests/scripts/thread-cert/border_router/test_on_link_prefix.py index 4ff831ac4..406723623 100755 --- a/tests/scripts/thread-cert/border_router/test_on_link_prefix.py +++ b/tests/scripts/thread-cert/border_router/test_on_link_prefix.py @@ -127,10 +127,8 @@ class MultiThreadNetworks(thread_cert.TestCase): logging.info("HOST addrs: %r", host.get_addrs()) self.assertEqual(len(br1.get_netdata_non_nat64_prefixes()), 1) - on_link_prefix = br1.get_netdata_non_nat64_prefixes()[0] - self.assertEqual(IPv6Network(on_link_prefix), IPv6Network(ON_LINK_PREFIX)) - host_on_link_addr = host.get_matched_ula_addresses(on_link_prefix)[0] + host_on_link_addr = host.get_matched_ula_addresses(ON_LINK_PREFIX)[0] self.assertTrue(router1.ping(host_on_link_addr)) self.assertTrue( host.ping(router1.get_ip6_address(config.ADDRESS_TYPE.OMR)[0], backbone=True, interface=host_on_link_addr)) @@ -164,18 +162,16 @@ class MultiThreadNetworks(thread_cert.TestCase): br2_omr_prefix = br2.get_br_omr_prefix() self.assertNotEqual(br1_omr_prefix, br2_omr_prefix) - # Verify that the Border Routers starts advertsing new on-link prefix + # Verify that the Border Routers starts advertising new on-link prefix # but don't remove the external routes for the radvd on-link prefix # immediately, because the SLAAC addresses are still valid. - self.assertEqual(len(br1.get_netdata_non_nat64_prefixes()), 3) - self.assertEqual(len(router1.get_netdata_non_nat64_prefixes()), 3) - self.assertEqual(len(br2.get_netdata_non_nat64_prefixes()), 2) - self.assertEqual(len(router2.get_netdata_non_nat64_prefixes()), 2) - on_link_prefixes = list( - set(br1.get_netdata_non_nat64_prefixes()).intersection(br2.get_netdata_non_nat64_prefixes())) - self.assertEqual(len(on_link_prefixes), 1) - self.assertEqual(IPv6Network(on_link_prefixes[0]), IPv6Network(br2.get_br_on_link_prefix())) + self.assertEqual(len(br1.get_netdata_non_nat64_prefixes()), 1) + self.assertEqual(len(router1.get_netdata_non_nat64_prefixes()), 1) + self.assertEqual(len(br2.get_netdata_non_nat64_prefixes()), 1) + self.assertEqual(len(router2.get_netdata_non_nat64_prefixes()), 1) + + br2_on_link_prefix = br2.get_br_on_link_prefix() router1_omr_addr = router1.get_ip6_address(config.ADDRESS_TYPE.OMR)[0] router2_omr_addr = router2.get_ip6_address(config.ADDRESS_TYPE.OMR)[0] @@ -184,7 +180,7 @@ class MultiThreadNetworks(thread_cert.TestCase): # and preferred Border Router on-link prefix can be reached by Thread # devices in network of Border Router 1. for host_on_link_addr in [ - host.get_matched_ula_addresses(on_link_prefixes[0])[0], + host.get_matched_ula_addresses(br2_on_link_prefix)[0], host.get_matched_ula_addresses(ON_LINK_PREFIX)[0] ]: self.assertTrue(router1.ping(host_on_link_addr)) @@ -192,11 +188,6 @@ class MultiThreadNetworks(thread_cert.TestCase): host_on_link_addr = host.get_matched_ula_addresses(ON_LINK_PREFIX)[0] - # Make sure that addresses of the deprecated radvd `ON_LINK_PREFIX` - # can't be reached by Thread devices in network of Border Router 2. - self.assertFalse(router2.ping(host_on_link_addr)) - self.assertFalse(host.ping(router2_omr_addr, backbone=True, interface=host_on_link_addr)) - # Wait 30 seconds for the radvd `ON_LINK_PREFIX` to be invalidated # and make sure that Thread devices in both networks can't reach # the on-link address. diff --git a/tests/scripts/thread-cert/border_router/test_single_border_router.py b/tests/scripts/thread-cert/border_router/test_single_border_router.py index 1028629df..a660345fc 100755 --- a/tests/scripts/thread-cert/border_router/test_single_border_router.py +++ b/tests/scripts/thread-cert/border_router/test_single_border_router.py @@ -177,8 +177,6 @@ class SingleBorderRouter(thread_cert.TestCase): # The same local OMR and on-link prefix should be re-register. self.assertEqual(br.get_netdata_omr_prefixes(), [omr_prefix]) self.assertEqual(router.get_netdata_omr_prefixes(), [omr_prefix]) - self.assertEqual(br.get_netdata_non_nat64_prefixes(), [on_link_prefix]) - self.assertEqual(router.get_netdata_non_nat64_prefixes(), [on_link_prefix]) self.assertEqual(len(br.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1) self.assertEqual(len(router.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1) @@ -231,8 +229,6 @@ class SingleBorderRouter(thread_cert.TestCase): # The same local OMR and on-link prefix should be re-registered. self.assertEqual(br.get_netdata_omr_prefixes(), [omr_prefix]) self.assertEqual(router.get_netdata_omr_prefixes(), [omr_prefix]) - self.assertEqual(br.get_netdata_non_nat64_prefixes(), [on_link_prefix]) - self.assertEqual(router.get_netdata_non_nat64_prefixes(), [on_link_prefix]) self.assertEqual(len(br.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1) self.assertEqual(len(router.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1) @@ -285,8 +281,6 @@ class SingleBorderRouter(thread_cert.TestCase): # The same local OMR and on-link prefix should be re-registered. self.assertEqual(br.get_netdata_omr_prefixes(), [omr_prefix]) self.assertEqual(router.get_netdata_omr_prefixes(), [omr_prefix]) - self.assertEqual(br.get_netdata_non_nat64_prefixes(), [on_link_prefix]) - self.assertEqual(router.get_netdata_non_nat64_prefixes(), [on_link_prefix]) self.assertEqual(len(br.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1) self.assertEqual(len(router.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1) @@ -320,8 +314,8 @@ class SingleBorderRouter(thread_cert.TestCase): br.start_radvd_service(prefix=config.ONLINK_GUA_PREFIX, slaac=True) self.simulator.go(5) - self.assertEqual(len(br.get_netdata_non_nat64_prefixes()), 2) - self.assertEqual(len(router.get_netdata_non_nat64_prefixes()), 2) + self.assertEqual(len(br.get_netdata_non_nat64_prefixes()), 1) + self.assertEqual(len(router.get_netdata_non_nat64_prefixes()), 1) self.assertTrue(router.ping(host.get_ip6_address(config.ADDRESS_TYPE.ONLINK_GUA)[0])) self.assertTrue(router.ping(host.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA)[0])) diff --git a/tests/unit/test_routing_manager.cpp b/tests/unit/test_routing_manager.cpp index a463c1328..9692b4ae8 100644 --- a/tests/unit/test_routing_manager.cpp +++ b/tests/unit/test_routing_manager.cpp @@ -550,60 +550,43 @@ void VerifyNoOmrPrefixInNetData(void) using NetworkData::RoutePreference; -struct ExternalRoute +enum ExternalRouteMode : uint8_t { - ExternalRoute(const Ip6::Prefix &aPrefix, RoutePreference aPreference) - : mPrefix(aPrefix) - , mPreference(aPreference) - { - } - - const Ip6::Prefix &mPrefix; - RoutePreference mPreference; + kNoRoute, + kDefaultRoute, + kUlaRoute, }; -template void VerifyExternalRoutesInNetData(const ExternalRoute (&aExternRoutes)[kLength]) +void VerifyExternalRouteInNetData(ExternalRouteMode aMode) { - otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT; - NetworkData::ExternalRouteConfig routeConfig; - uint16_t counter; + Error error; + otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT; + otExternalRouteConfig routeConfig; - Log("VerifyExternalRoutesInNetData()"); + error = otNetDataGetNextRoute(sInstance, &iterator, &routeConfig); - counter = 0; - - while (otNetDataGetNextRoute(sInstance, &iterator, &routeConfig) == kErrorNone) + switch (aMode) { - bool didFind = false; + case kNoRoute: + Log("VerifyExternalRouteInNetData(kNoRoute)"); + VerifyOrQuit(error != kErrorNone); + break; - counter++; + case kDefaultRoute: + Log("VerifyExternalRouteInNetData(kDefaultRoute)"); + VerifyOrQuit(error == kErrorNone); + VerifyOrQuit(routeConfig.mPrefix.mLength == 0); + VerifyOrQuit(otNetDataGetNextRoute(sInstance, &iterator, &routeConfig) != kErrorNone); + break; - Log(" prefix:%s, prf:%s", routeConfig.GetPrefix().ToString().AsCString(), - PreferenceToString(routeConfig.mPreference)); - - for (const ExternalRoute &externalRoute : aExternRoutes) - { - if (externalRoute.mPrefix == routeConfig.GetPrefix()) - { - VerifyOrQuit(static_cast(routeConfig.mPreference) == externalRoute.mPreference); - didFind = true; - break; - } - } - - VerifyOrQuit(didFind); + case kUlaRoute: + Log("VerifyExternalRouteInNetData(kUlaRoute)"); + VerifyOrQuit(error == kErrorNone); + VerifyOrQuit(routeConfig.mPrefix.mLength == 7); + VerifyOrQuit(routeConfig.mPrefix.mPrefix.mFields.m8[0] == 0xfc); + VerifyOrQuit(otNetDataGetNextRoute(sInstance, &iterator, &routeConfig) != kErrorNone); + break; } - - VerifyOrQuit(counter == kLength); -} - -void VerifyNoExternalRouteInNetData(void) -{ - otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT; - NetworkData::ExternalRouteConfig routeConfig; - - Log("VerifyNoExternalRouteInNetData()"); - VerifyOrQuit(otNetDataGetNextRoute(sInstance, &iterator, &routeConfig) != kErrorNone); } struct Pio @@ -749,6 +732,11 @@ template void VerifyPrefixTable(const OnLinkPrefix VerifyPrefixTable(aOnLinkPrefixes, kNumOnLinkPrefixes, nullptr, 0); } +template void VerifyPrefixTable(const RoutePrefix (&aRoutePrefixes)[kNumRoutePrefixes]) +{ + VerifyPrefixTable(nullptr, 0, aRoutePrefixes, kNumRoutePrefixes); +} + void VerifyPrefixTable(const OnLinkPrefix *aOnLinkPrefixes, uint16_t aNumOnLinkPrefixes, const RoutePrefix *aRoutePrefixes, @@ -820,6 +808,8 @@ void VerifyPrefixTable(const OnLinkPrefix *aOnLinkPrefixes, VerifyOrQuit(routePrefixCount == aNumRoutePrefixes); } +void VerifyPrefixTableIsEmpty(void) { VerifyPrefixTable(nullptr, 0, nullptr, 0); } + void InitTest(bool aEnablBorderRouting = false, bool aAfterReset = false) { //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -917,7 +907,7 @@ void TestSamePrefixesFromMultipleRouters(void) // Check Network Data to include the local OMR and on-link prefix. VerifyOmrPrefixInNetData(localOmr); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Send an RA from router A with a new on-link (PIO) and route prefix (RIO). @@ -945,9 +935,7 @@ void TestSamePrefixesFromMultipleRouters(void) // Check Network Data to include new prefixes from router A. VerifyOmrPrefixInNetData(localOmr); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium), - ExternalRoute(routePrefix, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kDefaultRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Send the same RA again from router A with the on-link (PIO) and route prefix (RIO). @@ -982,14 +970,7 @@ void TestSamePrefixesFromMultipleRouters(void) // Check Network Data. VerifyOmrPrefixInNetData(localOmr); - - // We expect to see 3 entries, our local on link and new prefixes - // from router A and B. The `routePrefix` now should have high - // preference. - - VerifyExternalRoutesInNetData({ExternalRoute(routePrefix, NetworkData::kRoutePreferenceHigh), - ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kDefaultRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Send an RA from router B removing the route prefix. @@ -1006,11 +987,9 @@ void TestSamePrefixesFromMultipleRouters(void) {RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA)}); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check Network Data, all prefixes should be again at medium preference. + // Check Network Data. - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium), - ExternalRoute(routePrefix, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kDefaultRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1060,7 +1039,7 @@ void TestOmrSelection(void) // Check Network Data to include the local OMR and on-link prefix. VerifyOmrPrefixInNetData(localOmr); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Add a new OMR prefix directly into net data. The new prefix should @@ -1098,8 +1077,7 @@ void TestOmrSelection(void) // is removed. VerifyOmrPrefixInNetData(omrPrefix); - - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Remove the OMR prefix previously added in net data. @@ -1126,8 +1104,7 @@ void TestOmrSelection(void) // added again. VerifyOmrPrefixInNetData(localOmr); - - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1139,12 +1116,9 @@ void TestDefaultRoute(void) { Ip6::Prefix localOnLink; Ip6::Prefix localOmr; - Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64); - Ip6::Prefix routePrefix = PrefixFromString("2000:1234:5678::", 64); Ip6::Prefix omrPrefix = PrefixFromString("2000:0000:1111:4444::", 64); Ip6::Prefix defaultRoute = PrefixFromString("::", 0); Ip6::Address routerAddressA = AddressFromString("fd00::aaaa"); - Ip6::Address routerAddressB = AddressFromString("fd00::bbbb"); NetworkData::OnMeshPrefixConfig prefixConfig; Log("--------------------------------------------------------------------------------------------"); @@ -1153,53 +1127,60 @@ void TestDefaultRoute(void) InitTest(); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Start Routing Manager + // Start Routing Manager. Check emitted RS and RA messages. + + sRsEmitted = false; + sRaValidated = false; + sExpectedPio = kPioAdvertisingLocalOnLink; + sExpectedRios.Clear(); SuccessOrQuit(sInstance->Get().SetEnabled(true)); SuccessOrQuit(sInstance->Get().GetOnLinkPrefix(localOnLink)); SuccessOrQuit(sInstance->Get().GetOmrPrefix(localOmr)); - AdvanceTime(500); - Log("Local on-link prefix is %s", localOnLink.ToString().AsCString()); Log("Local OMR prefix is %s", localOmr.ToString().AsCString()); + sExpectedRios.Add(localOmr); + + AdvanceTime(30000); + + VerifyOrQuit(sRsEmitted); + VerifyOrQuit(sRaValidated); + VerifyOrQuit(sExpectedRios.SawAll()); + Log("Received RA was validated"); + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Send an RA from router A and B adding an onlink prefix - // and routePrefix from A, and a default route from B. + // Check Network Data to include the local OMR and ULA prefix. - SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)}, - {Rio(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium)}); + VerifyOmrPrefixInNetData(localOmr); + VerifyExternalRouteInNetData(kUlaRoute); - SendRouterAdvert(routerAddressB, DefaultRoute(kValidLitime, NetworkData::kRoutePreferenceLow)); + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Send RA from router A advertising a default route. - sRsEmitted = false; - sRaValidated = false; - sExpectedPio = kNoPio; - sExpectedRios.Clear(); + SendRouterAdvert(routerAddressA, DefaultRoute(kValidLitime, NetworkData::kRoutePreferenceLow)); AdvanceTime(10000); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check the discovered prefix table and ensure info from router B - // is now included in the table. + // Check the discovered prefix table and ensure default route + // from router A is in the table. - VerifyPrefixTable({OnLinkPrefix(onLinkPrefix, kValidLitime, kPreferredLifetime, routerAddressA)}, - {RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA), - RoutePrefix(defaultRoute, kValidLitime, NetworkData::kRoutePreferenceLow, routerAddressB)}); + VerifyPrefixTable({RoutePrefix(defaultRoute, kValidLitime, NetworkData::kRoutePreferenceLow, routerAddressA)}); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check Network Data. We should not see default route in - // Network Data yet (since there is no OMR prefix with default - // route flag). + // Network Data yet since there is no infrastructure-derived + // OMR prefix (with preference medium or higher). - VerifyExternalRoutesInNetData({ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium), - ExternalRoute(routePrefix, NetworkData::kRoutePreferenceMedium)}); + VerifyOmrPrefixInNetData(localOmr); + VerifyExternalRouteInNetData(kUlaRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Add an OMR prefix directly into Network Data with default route - // flag. + // Add an OMR prefix directly into Network Data with + // preference medium (infrastructure-derived). prefixConfig.Clear(); prefixConfig.mPrefix = omrPrefix; @@ -1207,7 +1188,7 @@ void TestDefaultRoute(void) prefixConfig.mSlaac = true; prefixConfig.mPreferred = true; prefixConfig.mOnMesh = true; - prefixConfig.mDefaultRoute = true; + prefixConfig.mDefaultRoute = false; prefixConfig.mPreference = NetworkData::kRoutePreferenceMedium; SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig)); @@ -1216,42 +1197,14 @@ void TestDefaultRoute(void) AdvanceTime(10000); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check Network Data. We should now see default route from - // router B. + // Check Network Data. Now that we have an infrastructure-derived + // OMR prefix, the default route should be published. - VerifyExternalRoutesInNetData({ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium), - ExternalRoute(routePrefix, NetworkData::kRoutePreferenceMedium), - ExternalRoute(defaultRoute, NetworkData::kRoutePreferenceLow)}); + VerifyOmrPrefixInNetData(omrPrefix); + VerifyExternalRouteInNetData(kDefaultRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Send an RA from router B adding a default route - // now also as ::/0 prefix RIO with a high preference. - - SendRouterAdvert(routerAddressB, {Rio(defaultRoute, kValidLitime, NetworkData::kRoutePreferenceHigh)}, - DefaultRoute(kValidLitime, NetworkData::kRoutePreferenceLow)); - - AdvanceTime(10000); - - //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check the discovered prefix table and ensure default route - // entry from router B is now correctly updated to use high - // preference (RIO overrides the default route info from header). - - VerifyPrefixTable({OnLinkPrefix(onLinkPrefix, kValidLitime, kPreferredLifetime, routerAddressA)}, - {RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA), - RoutePrefix(defaultRoute, kValidLitime, NetworkData::kRoutePreferenceHigh, routerAddressB)}); - - //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check Network Data. We should now see default route from - // router B included with high preference. - - VerifyExternalRoutesInNetData({ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium), - ExternalRoute(routePrefix, NetworkData::kRoutePreferenceMedium), - ExternalRoute(defaultRoute, NetworkData::kRoutePreferenceHigh)}); - - //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Remove the OMR prefix previously added with default route - // flag. + // Remove the OMR prefix from Network Data. SuccessOrQuit(otBorderRouterRemoveOnMeshPrefix(sInstance, &omrPrefix)); SuccessOrQuit(otBorderRouterRegister(sInstance)); @@ -1259,14 +1212,136 @@ void TestDefaultRoute(void) AdvanceTime(10000); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check Network Data. The default route ::/0 should be now - // removed since the OMR prefix with default route is removed. + // Check Network Data. We should again go back to ULA prefix. The + // default route advertised by router A should be still present in + // the discovered prefix table. - VerifyExternalRoutesInNetData({ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium), - ExternalRoute(routePrefix, NetworkData::kRoutePreferenceMedium)}); + VerifyOmrPrefixInNetData(localOmr); + VerifyExternalRouteInNetData(kUlaRoute); + + VerifyPrefixTable({RoutePrefix(defaultRoute, kValidLitime, NetworkData::kRoutePreferenceLow, routerAddressA)}); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Re-add the OMR prefix with default route flag. + // Add the OMR prefix again. + + SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig)); + SuccessOrQuit(otBorderRouterRegister(sInstance)); + + AdvanceTime(10000); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check Network Data. Again the default route should be published. + + VerifyOmrPrefixInNetData(omrPrefix); + VerifyExternalRouteInNetData(kDefaultRoute); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Send RA from router A removing the default route. + + SendRouterAdvert(routerAddressA, DefaultRoute(0, NetworkData::kRoutePreferenceLow)); + + AdvanceTime(10000); + + VerifyPrefixTableIsEmpty(); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check Network Data. Now that router A no longer advertised + // a default-route, we should go back to publishing ULA route. + + VerifyOmrPrefixInNetData(omrPrefix); + VerifyExternalRouteInNetData(kUlaRoute); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Send RA from router A again advertising a default route. + + SendRouterAdvert(routerAddressA, DefaultRoute(kValidLitime, NetworkData::kRoutePreferenceLow)); + + AdvanceTime(10000); + + VerifyPrefixTable({RoutePrefix(defaultRoute, kValidLitime, NetworkData::kRoutePreferenceLow, routerAddressA)}); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check Network Data. We should see default route published. + + VerifyOmrPrefixInNetData(omrPrefix); + VerifyExternalRouteInNetData(kDefaultRoute); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + Log("End of TestDefaultRoute"); + + FinalizeTest(); +} + +void TestAdvNonUlaRoute(void) +{ + Ip6::Prefix localOnLink; + Ip6::Prefix localOmr; + Ip6::Prefix omrPrefix = PrefixFromString("2000:0000:1111:4444::", 64); + Ip6::Prefix routePrefix = PrefixFromString("2000:1234:5678::", 64); + Ip6::Address routerAddressA = AddressFromString("fd00::aaaa"); + NetworkData::OnMeshPrefixConfig prefixConfig; + + Log("--------------------------------------------------------------------------------------------"); + Log("TestAdvNonUlaRoute"); + + InitTest(); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Start Routing Manager. Check emitted RS and RA messages. + + sRsEmitted = false; + sRaValidated = false; + sExpectedPio = kPioAdvertisingLocalOnLink; + sExpectedRios.Clear(); + + SuccessOrQuit(sInstance->Get().SetEnabled(true)); + + SuccessOrQuit(sInstance->Get().GetOnLinkPrefix(localOnLink)); + SuccessOrQuit(sInstance->Get().GetOmrPrefix(localOmr)); + + Log("Local on-link prefix is %s", localOnLink.ToString().AsCString()); + Log("Local OMR prefix is %s", localOmr.ToString().AsCString()); + + sExpectedRios.Add(localOmr); + + AdvanceTime(30000); + + VerifyOrQuit(sRsEmitted); + VerifyOrQuit(sRaValidated); + VerifyOrQuit(sExpectedRios.SawAll()); + Log("Received RA was validated"); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check Network Data to include the local OMR and ULA prefix. + + VerifyOmrPrefixInNetData(localOmr); + VerifyExternalRouteInNetData(kUlaRoute); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Send RA from router A advertising a non-ULA. + + SendRouterAdvert(routerAddressA, {Rio(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium)}); + + AdvanceTime(10000); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check the discovered prefix table and ensure the non-ULA + // from router A is in the table. + + VerifyPrefixTable({RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA)}); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check Network Data. We should not see default route in + // Network Data yet since there is no infrastructure-derived + // OMR prefix (with preference medium or higher). + + VerifyOmrPrefixInNetData(localOmr); + VerifyExternalRouteInNetData(kUlaRoute); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Add an OMR prefix directly into Network Data with + // preference medium (infrastructure-derived). prefixConfig.Clear(); prefixConfig.mPrefix = omrPrefix; @@ -1274,7 +1349,7 @@ void TestDefaultRoute(void) prefixConfig.mSlaac = true; prefixConfig.mPreferred = true; prefixConfig.mOnMesh = true; - prefixConfig.mDefaultRoute = true; + prefixConfig.mDefaultRoute = false; prefixConfig.mPreference = NetworkData::kRoutePreferenceMedium; SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig)); @@ -1283,38 +1358,78 @@ void TestDefaultRoute(void) AdvanceTime(10000); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check Network Data. We should again see the default route from - // router B included with high preference. + // Check Network Data. Now that we have an infrastructure-derived + // OMR prefix, the default route should be published. - VerifyExternalRoutesInNetData({ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium), - ExternalRoute(routePrefix, NetworkData::kRoutePreferenceMedium), - ExternalRoute(defaultRoute, NetworkData::kRoutePreferenceHigh)}); + VerifyOmrPrefixInNetData(omrPrefix); + VerifyExternalRouteInNetData(kDefaultRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Send an RA from router B removing default route - // in both header and in RIO. + // Remove the OMR prefix from Network Data. + + SuccessOrQuit(otBorderRouterRemoveOnMeshPrefix(sInstance, &omrPrefix)); + SuccessOrQuit(otBorderRouterRegister(sInstance)); - SendRouterAdvert(routerAddressB, {Rio(defaultRoute, 0, NetworkData::kRoutePreferenceHigh)}, - DefaultRoute(0, NetworkData::kRoutePreferenceMedium)); AdvanceTime(10000); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check the discovered prefix table and ensure default route - // entry from router B is no longer present. + // Check Network Data. We should again go back to ULA prefix. The + // non-ULA route advertised by router A should be still present in + // the discovered prefix table. - VerifyPrefixTable({OnLinkPrefix(onLinkPrefix, kValidLitime, kPreferredLifetime, routerAddressA)}, - {RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA)}); + VerifyOmrPrefixInNetData(localOmr); + VerifyExternalRouteInNetData(kUlaRoute); + + VerifyPrefixTable({RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA)}); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check Network Data. The default route ::/0 should be now - // removed since router B stopped advertising it. + // Add the OMR prefix again. - VerifyExternalRoutesInNetData({ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium), - ExternalRoute(routePrefix, NetworkData::kRoutePreferenceMedium)}); + SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig)); + SuccessOrQuit(otBorderRouterRegister(sInstance)); + + AdvanceTime(10000); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check Network Data. Again the default route should be published. + + VerifyOmrPrefixInNetData(omrPrefix); + VerifyExternalRouteInNetData(kDefaultRoute); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Send RA from router A removing the route. + + SendRouterAdvert(routerAddressA, {Rio(routePrefix, 0, NetworkData::kRoutePreferenceMedium)}); + + AdvanceTime(10000); + + VerifyPrefixTableIsEmpty(); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check Network Data. Now that router A no longer advertised + // the route, we should go back to publishing the ULA route. + + VerifyOmrPrefixInNetData(omrPrefix); + VerifyExternalRouteInNetData(kUlaRoute); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Send RA from router A again advertising the route again. + + SendRouterAdvert(routerAddressA, {Rio(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium)}); + + AdvanceTime(10000); + + VerifyPrefixTable({RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA)}); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check Network Data. We should see default route published. + + VerifyOmrPrefixInNetData(omrPrefix); + VerifyExternalRouteInNetData(kDefaultRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Log("End of TestDefaultRoute"); + Log("End of TestAdvNonUlaRoute"); FinalizeTest(); } @@ -1325,7 +1440,7 @@ void TestLocalOnLinkPrefixDeprecation(void) Ip6::Prefix localOnLink; Ip6::Prefix localOmr; - Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64); + Ip6::Prefix onLinkPrefix = PrefixFromString("fd00:abba:baba::", 64); Ip6::Address routerAddressA = AddressFromString("fd00::aaaa"); uint32_t localOnLinkLifetime; @@ -1363,7 +1478,7 @@ void TestLocalOnLinkPrefixDeprecation(void) // Check Network Data to include the local OMR and on-link prefix. VerifyOmrPrefixInNetData(localOmr); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Send an RA from router A with a new on-link (PIO) which is preferred over @@ -1391,8 +1506,7 @@ void TestLocalOnLinkPrefixDeprecation(void) // along with the deprecating local on-link prefix. VerifyOmrPrefixInNetData(localOmr); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Wait for local on-link prefix to expire @@ -1407,8 +1521,7 @@ void TestLocalOnLinkPrefixDeprecation(void) // see the deprecating local on-link prefix. VerifyOmrPrefixInNetData(localOmr); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); // Keep checking the emitted RAs and make sure on-link prefix // is included with smaller lifetime every time. @@ -1443,11 +1556,10 @@ void TestLocalOnLinkPrefixDeprecation(void) Log("On-link prefix is now expired"); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check Network Data and make sure the the expired local on-link prefix - // is removed. + // Check Network Data. VerifyOmrPrefixInNetData(localOmr); - VerifyExternalRoutesInNetData({ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1498,7 +1610,7 @@ void TestDomainPrefixAsOmr(void) // Check Network Data to include the local OMR and on-link prefix. VerifyOmrPrefixInNetData(localOmr); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Add a domain prefix directly into net data. The new prefix should @@ -1567,7 +1679,7 @@ void TestDomainPrefixAsOmr(void) // is removed. VerifyOmrPrefixInNetData(domainPrefix); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Remove the domain prefix from net data. @@ -1594,7 +1706,7 @@ void TestDomainPrefixAsOmr(void) // added again. VerifyOmrPrefixInNetData(localOmr); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1690,12 +1802,10 @@ void TestExtPanIdChange(void) oldPrefixLifetime = sDeprecatingPrefixes[0].mLifetime; //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Validate the Network Data to contain both the current and old - // local on-link prefixes. + // Validate Network Data. VerifyOmrPrefixInNetData(localOmr); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(oldLocalOnLink, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Stop BR and validate that a final RA is emitted deprecating @@ -1717,7 +1827,7 @@ void TestExtPanIdChange(void) VerifyOrQuit(!sRaValidated); VerifyNoOmrPrefixInNetData(); - VerifyNoExternalRouteInNetData(); + VerifyExternalRouteInNetData(kNoRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Start BR again and validate old prefix will continue to @@ -1740,11 +1850,9 @@ void TestExtPanIdChange(void) while (oldPrefixLifetime > 2 * kMaxRaTxInterval) { - // Ensure Network Data entries remain as before. Mainly we still - // see the deprecating local on-link prefix. + // Ensure Network Data entries remain as before. - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(oldLocalOnLink, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); // Keep checking the emitted RAs and make sure the prefix // is included with smaller lifetime every time. @@ -1766,18 +1874,17 @@ void TestExtPanIdChange(void) sRaValidated = false; - AdvanceTime(2 * kMaxRaTxInterval * 1000); + AdvanceTime(3 * kMaxRaTxInterval * 1000); VerifyOrQuit(sRaValidated); VerifyOrQuit(sDeprecatingPrefixes.IsEmpty()); Log("Old on-link prefix is now expired"); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Validate the Network Data now only contains the current local - // on-link prefix. + // Validate the Network Data. VerifyOmrPrefixInNetData(localOmr); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = // Check behavior when ext PAN ID changes while the local on-link is being @@ -1827,12 +1934,10 @@ void TestExtPanIdChange(void) VerifyOrQuit(sDeprecatingPrefixes[0].mPrefix == oldLocalOnLink); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Validate that Network Data contains the old local on-link - // prefix along with entry from router A. + // Validate that Network Data. VerifyOmrPrefixInNetData(localOmr); - VerifyExternalRoutesInNetData({ExternalRoute(oldLocalOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kDefaultRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Wait for old local on-link prefix to expire. @@ -1843,11 +1948,9 @@ void TestExtPanIdChange(void) SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)}); - // Ensure Network Data entries remain as before. Mainly we still - // see the deprecating old local on-link prefix. + // Ensure Network Data entries remain as before. - VerifyExternalRoutesInNetData({ExternalRoute(oldLocalOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kDefaultRoute); // Keep checking the emitted RAs and make sure the prefix // is included with smaller lifetime every time. @@ -1868,19 +1971,24 @@ void TestExtPanIdChange(void) // longer be seen in the emitted RA message. SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)}); + sRaValidated = false; - AdvanceTime(2 * kMaxRaTxInterval * 1000); + AdvanceTime(kMaxRaTxInterval * 1000); + SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)}); + AdvanceTime(kMaxRaTxInterval * 1000); + SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)}); + AdvanceTime(kMaxRaTxInterval * 1000); VerifyOrQuit(sRaValidated); VerifyOrQuit(sDeprecatingPrefixes.IsEmpty()); Log("Old on-link prefix is now expired"); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Validate the Network Data to now only contains entry from router A. + // Validate the Network Data. VerifyOmrPrefixInNetData(localOmr); - VerifyExternalRoutesInNetData({ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kDefaultRoute); //= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = // Check behavior when ext PAN ID changes while the local on-link is not @@ -1906,10 +2014,10 @@ void TestExtPanIdChange(void) VerifyOrQuit(sDeprecatingPrefixes.IsEmpty()); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Validate the Network Data to now only contains entry from router A. + // Validate the Network Data. VerifyOmrPrefixInNetData(localOmr); - VerifyExternalRoutesInNetData({ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kDefaultRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Remove the on-link prefix PIO being advertised by router A @@ -1926,11 +2034,11 @@ void TestExtPanIdChange(void) //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Wait for longer than valid lifetime of PIO entry from router A. - // Validate that it is unpublished from network data. + // Validate that default route is unpublished from network data. AdvanceTime(2000 * 1000); VerifyOmrPrefixInNetData(localOmr); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = // Multiple PAN ID changes and multiple deprecating old prefixes. @@ -1949,8 +2057,7 @@ void TestExtPanIdChange(void) VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 1); VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[0])); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(oldPrefixes[0], NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Change the prefix again. We should see two deprecating prefixes. @@ -1970,9 +2077,7 @@ void TestExtPanIdChange(void) VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[0])); VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[1])); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(oldPrefixes[0], NetworkData::kRoutePreferenceMedium), - ExternalRoute(oldPrefixes[1], NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Wait for 15 minutes and then change ext PAN ID again. @@ -1996,10 +2101,7 @@ void TestExtPanIdChange(void) VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[1])); VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[2])); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(oldPrefixes[0], NetworkData::kRoutePreferenceMedium), - ExternalRoute(oldPrefixes[1], NetworkData::kRoutePreferenceMedium), - ExternalRoute(oldPrefixes[2], NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Change ext PAN ID back to previous value of `kExtPanId1`. @@ -2023,10 +2125,7 @@ void TestExtPanIdChange(void) VerifyOrQuit(oldPrefixes[2] == localOnLink); VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[3])); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(oldPrefixes[0], NetworkData::kRoutePreferenceMedium), - ExternalRoute(oldPrefixes[1], NetworkData::kRoutePreferenceMedium), - ExternalRoute(oldPrefixes[3], NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Stop BR and validate the final emitted RA to contain @@ -2045,7 +2144,7 @@ void TestExtPanIdChange(void) VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[3])); VerifyNoOmrPrefixInNetData(); - VerifyNoExternalRouteInNetData(); + VerifyExternalRouteInNetData(kNoRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Wait for 15 minutes while BR stays disabled and validate @@ -2058,7 +2157,7 @@ void TestExtPanIdChange(void) VerifyOrQuit(!sRaValidated); VerifyNoOmrPrefixInNetData(); - VerifyNoExternalRouteInNetData(); + VerifyExternalRouteInNetData(kNoRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Start BR again, and check that we only see the last deprecating prefix @@ -2076,8 +2175,7 @@ void TestExtPanIdChange(void) VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 1); VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[3])); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(oldPrefixes[3], NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = // Validate the oldest prefix is removed when we have too many @@ -2112,10 +2210,7 @@ void TestExtPanIdChange(void) VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[2])); VerifyOrQuit(!sDeprecatingPrefixes.ContainsMatching(oldLocalOnLink)); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(oldPrefixes[0], NetworkData::kRoutePreferenceMedium), - ExternalRoute(oldPrefixes[1], NetworkData::kRoutePreferenceMedium), - ExternalRoute(oldPrefixes[2], NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2317,7 +2412,7 @@ void TestConflictingPrefix(void) // Check Network Data to include the local OMR and on-link prefix. VerifyOmrPrefixInNetData(localOmr); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Send an RA from router A with our local on-link prefix as RIO. @@ -2333,10 +2428,10 @@ void TestConflictingPrefix(void) VerifyOrQuit(sRaValidated); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check Network Data to still include the local OMR and on-link prefix. + // Check Network Data to still include the local OMR and ULA prefix. VerifyOmrPrefixInNetData(localOmr); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Send an RA from router A removing local on-link prefix as RIO. @@ -2344,11 +2439,11 @@ void TestConflictingPrefix(void) SendRouterAdvert(routerAddressA, {Rio(localOnLink, 0, NetworkData::kRoutePreferenceMedium)}); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Verify that on-link prefix is still included in Network Data and + // Verify that ULA prefix is still included in Network Data and // the change by router A did not cause it to be unpublished. AdvanceTime(10000); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check that the local on-link prefix is still being advertised. @@ -2357,7 +2452,7 @@ void TestConflictingPrefix(void) AdvanceTime(610000); VerifyOrQuit(sRaValidated); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Send RA from router B advertising an on-link prefix. This @@ -2377,12 +2472,11 @@ void TestConflictingPrefix(void) Log("On-link prefix is deprecating, remaining lifetime:%d", sOnLinkLifetime); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check Network Data to include the new on-link prefix from router B and - // the deprecating local on-link prefix. + // Check Network Data to include the default route now due + // the new on-link prefix from router B. VerifyOmrPrefixInNetData(localOmr); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kDefaultRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Send an RA from router A again adding local on-link prefix as RIO. @@ -2400,8 +2494,7 @@ void TestConflictingPrefix(void) //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check Network Data remains unchanged. - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kDefaultRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Send an RA from router A removing the previous RIO. @@ -2409,12 +2502,10 @@ void TestConflictingPrefix(void) SendRouterAdvert(routerAddressA, {Rio(localOnLink, 0, NetworkData::kRoutePreferenceMedium)}); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check Network Data remains unchanged and still contains - // the deprecating local on-link prefix. + // Check Network Data remains unchanged. AdvanceTime(60000); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kDefaultRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Send RA from router B removing its on-link prefix. @@ -2431,10 +2522,9 @@ void TestConflictingPrefix(void) VerifyOrQuit(sRaValidated); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check Network Data still contains both prefixes. + // Check Network Data to remain unchanged. - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kDefaultRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Change the extended PAN ID. @@ -2456,12 +2546,10 @@ void TestConflictingPrefix(void) oldLocalOnLink.ToString().AsCString()); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check Network Data contains old and new local on-link prefix - // and deprecating prefix from router B. + // Check Network Data contains default route due to the + // deprecating on-link prefix from router B. - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(oldLocalOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kDefaultRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Send an RA from router A again adding the old local on-link prefix @@ -2473,9 +2561,7 @@ void TestConflictingPrefix(void) // Check Network Data remains unchanged. AdvanceTime(10000); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(oldLocalOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kDefaultRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Send an RA from router A removing the previous RIO. @@ -2486,9 +2572,7 @@ void TestConflictingPrefix(void) // Check Network Data remains unchanged. AdvanceTime(10000); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(oldLocalOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kDefaultRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2537,10 +2621,10 @@ void TestSavedOnLinkPrefixes(void) VerifyOrQuit(sExpectedRios.SawAll()); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check Network Data to include the local OMR and on-link prefix. + // Check Network Data to include the local OMR and ULA prefix. VerifyOmrPrefixInNetData(localOmr); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Disable the instance and re-enable it. @@ -2562,10 +2646,10 @@ void TestSavedOnLinkPrefixes(void) VerifyOrQuit(sExpectedRios.SawAll()); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check Network Data to include the local OMR and on-link prefix. + // Check Network Data to include the local OMR and ULA prefix. VerifyOmrPrefixInNetData(localOmr); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Send RA from router A advertising an on-link prefix. @@ -2598,10 +2682,10 @@ void TestSavedOnLinkPrefixes(void) VerifyOrQuit(sExpectedRios.SawAll()); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check Network Data to include the local OMR and on-link prefix. + // Check Network Data to include the local OMR and ULA prefix. VerifyOmrPrefixInNetData(localOmr); - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kUlaRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2659,12 +2743,10 @@ void TestSavedOnLinkPrefixes(void) VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 1); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check the saved prefixes are in netdata and being - // deprecated. + // Check Network Data to now use default route due to the + // on-link prefix from router A. - VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(oldLocalOnLink, NetworkData::kRoutePreferenceMedium), - ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kDefaultRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Wait for more than 1800 seconds to let the deprecating @@ -2676,7 +2758,7 @@ void TestSavedOnLinkPrefixes(void) AdvanceTime(10 * 1000); } - VerifyExternalRoutesInNetData({ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kDefaultRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Disable the instance and re-enable it and restart Routing Manager. @@ -2703,11 +2785,9 @@ void TestSavedOnLinkPrefixes(void) VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 0); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Check that previously saved on-link prefixes are no longer - // seen in Network Data (indicating that they were removed from - // `Settings`). + // Check Network Data still contains the default route. - VerifyExternalRoutesInNetData({ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium)}); + VerifyExternalRouteInNetData(kDefaultRoute); //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2931,6 +3011,7 @@ int main(void) TestSamePrefixesFromMultipleRouters(); TestOmrSelection(); TestDefaultRoute(); + TestAdvNonUlaRoute(); TestLocalOnLinkPrefixDeprecation(); #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE TestDomainPrefixAsOmr();