From 7b9b396dd516ff0e339cfc9420c660a4b820bb5b Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 1 Jul 2024 08:12:42 -0700 Subject: [PATCH] [routing-manager] add `OnLinkPrefix::IsFavoredOver()` (#10452) This commit adds the `OnLinkPrefix::IsFavoredOver()` method to determine if an on-link prefix is eligible to be considered as a favored prefix, and if so, is favored over another prefix. A numerically smaller prefix is considered favored. Additionally, a new test case is added to `test_routing_manager` to validate the selection of favored on-link prefixes, including the the requirement of a minimum preferred lifetime of 1800 seconds for a prefix to be considered eligible. --- src/core/border_router/routing_manager.cpp | 31 +++-- src/core/border_router/routing_manager.hpp | 5 +- tests/unit/test_routing_manager.cpp | 129 +++++++++++++++++++++ 3 files changed, 154 insertions(+), 11 deletions(-) diff --git a/src/core/border_router/routing_manager.cpp b/src/core/border_router/routing_manager.cpp index 07b2c6379..36f9541bd 100644 --- a/src/core/border_router/routing_manager.cpp +++ b/src/core/border_router/routing_manager.cpp @@ -927,6 +927,27 @@ void RoutingManager::OnLinkPrefix::CopyInfoTo(PrefixTableEntry &aEntry, TimeMill aEntry.mPreferredLifetime = GetPreferredLifetime(); } +bool RoutingManager::OnLinkPrefix::IsFavoredOver(const Ip6::Prefix &aPrefix) const +{ + bool isFavored = false; + + // Validate that the `OnLinkPrefix` is eligible to be considered a + // favored on-link prefix. It must not be deprecated and have a + // preferred lifetime exceeding a minimum (1800 seconds). + + VerifyOrExit(!IsDeprecated()); + VerifyOrExit(GetPreferredLifetime() >= kFavoredMinPreferredLifetime); + + // Numerically smaller prefix is favored (unless `aPrefix` is empty). + + VerifyOrExit(aPrefix.GetLength() != 0, isFavored = true); + + isFavored = GetPrefix() < aPrefix; + +exit: + return isFavored; +} + //--------------------------------------------------------------------------------------------------------------------- // RoutePrefix @@ -1874,18 +1895,10 @@ void RoutingManager::RxRaTracker::DecisionFactors::UpdateFrom(const OnLinkPrefix mHasNonUlaOnLink = true; } - // Determine favored on-link prefix - - VerifyOrExit(!aOnLinkPrefix.IsDeprecated()); - VerifyOrExit(aOnLinkPrefix.GetPreferredLifetime() >= kFavoredOnLinkPrefixMinPreferredLifetime); - - if ((mFavoredOnLinkPrefix.GetLength() == 0) || (aOnLinkPrefix.GetPrefix() < mFavoredOnLinkPrefix)) + if (aOnLinkPrefix.IsFavoredOver(mFavoredOnLinkPrefix)) { mFavoredOnLinkPrefix = aOnLinkPrefix.GetPrefix(); } - -exit: - return; } void RoutingManager::RxRaTracker::DecisionFactors::UpdateFrom(const RoutePrefix &aRoutePrefix) diff --git a/src/core/border_router/routing_manager.hpp b/src/core/border_router/routing_manager.hpp index dec8ccc5e..5c036a58f 100644 --- a/src/core/border_router/routing_manager.hpp +++ b/src/core/border_router/routing_manager.hpp @@ -702,8 +702,11 @@ private: TimeMilli GetStaleTime(void) const; void AdoptValidAndPreferredLifetimesFrom(const OnLinkPrefix &aPrefix); void CopyInfoTo(PrefixTableEntry &aEntry, TimeMilli aNow) const; + bool IsFavoredOver(const Ip6::Prefix &aPrefix) const; private: + static constexpr uint32_t kFavoredMinPreferredLifetime = 1800; // In sec. + uint32_t mPreferredLifetime; }; @@ -782,8 +785,6 @@ private: void HandleRouterTimer(void); private: - static constexpr uint32_t kFavoredOnLinkPrefixMinPreferredLifetime = 1800; // In sec. - //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template diff --git a/tests/unit/test_routing_manager.cpp b/tests/unit/test_routing_manager.cpp index c156a6e32..dd983cd0c 100644 --- a/tests/unit/test_routing_manager.cpp +++ b/tests/unit/test_routing_manager.cpp @@ -1168,6 +1168,16 @@ void VerifyDiscoveredRouters(const InfraRouter *aRouters, uint16_t aNumRouters) void VerifyDiscoveredRoutersIsEmpty(void) { VerifyDiscoveredRouters(nullptr, 0); } +void VerifyFavoredOnLinkPrefix(const Ip6::Prefix &aPrefix) +{ + Ip6::Prefix favoredPrefix; + + Log("VerifyFavoredOnLinkPrefix(%s)", aPrefix.ToString().AsCString()); + + SuccessOrQuit(sInstance->Get().GetFavoredOnLinkPrefix(favoredPrefix)); + VerifyOrQuit(favoredPrefix == aPrefix); +} + void InitTest(bool aEnablBorderRouting = false, bool aAfterReset = false) { uint32_t delay = 10000; @@ -1846,6 +1856,124 @@ void TestAdvNonUlaRoute(void) FinalizeTest(); } +void TestFavoredOnLinkPrefix(void) +{ + Ip6::Prefix localOnLink; + Ip6::Prefix localOmr; + Ip6::Prefix onLinkPrefixA = PrefixFromString("2000:abba:baba:aaaa::", 64); + Ip6::Prefix onLinkPrefixB = PrefixFromString("2000:abba:baba:bbbb::", 64); + Ip6::Address routerAddressA = AddressFromString("fd00::aaaa"); + Ip6::Address routerAddressB = AddressFromString("fd00::bbbb"); + uint16_t heapAllocations; + + Log("--------------------------------------------------------------------------------------------"); + Log("TestFavoredOnLinkPrefix"); + + InitTest(); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Start Routing Manager. Check emitted RS and RA messages. + + sRsEmitted = false; + sRaValidated = false; + sExpectedPio = kPioAdvertisingLocalOnLink; + sExpectedRios.Clear(); + + heapAllocations = sHeapAllocatedPtrs.GetLength(); + 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"); + + VerifyFavoredOnLinkPrefix(localOnLink); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Advertise on-link prefix B from router B + + SendRouterAdvert(routerAddressB, {Pio(onLinkPrefixB, kValidLitime, kPreferredLifetime)}); + + AdvanceTime(10 * 1000); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check the discovered prefix table and ensure on-link prefix B is + // now the favored on-link prefix + + VerifyPrefixTable({OnLinkPrefix(onLinkPrefixB, kValidLitime, kPreferredLifetime, routerAddressB)}); + VerifyFavoredOnLinkPrefix(onLinkPrefixB); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Advertise on-link prefix A from router A with a short + // preferred lifetime (less than 1800 which is the threshold for it + // to be considered a valid favored on-link prefix). + + SendRouterAdvert(routerAddressA, {Pio(onLinkPrefixA, kValidLitime, 1799)}); + + AdvanceTime(10 * 1000); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check the discovered prefix table and ensure on-link prefix B is + // still the favored on-link prefix. + + VerifyPrefixTable({OnLinkPrefix(onLinkPrefixB, kValidLitime, kPreferredLifetime, routerAddressB), + OnLinkPrefix(onLinkPrefixA, kValidLitime, 1799, routerAddressA)}); + + VerifyFavoredOnLinkPrefix(onLinkPrefixB); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Advertise on-link prefix A from router A with a long + // preferred lifetime now. + + SendRouterAdvert(routerAddressA, {Pio(onLinkPrefixA, kValidLitime, kPreferredLifetime)}); + + AdvanceTime(10 * 1000); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check the discovered prefix table and ensure that now on-link + // prefix A (which is numerically smaller) is considered as + // favored on-link prefix. + + VerifyPrefixTable({OnLinkPrefix(onLinkPrefixB, kValidLitime, kPreferredLifetime, routerAddressB), + OnLinkPrefix(onLinkPrefixA, kValidLitime, kPreferredLifetime, routerAddressA)}); + + VerifyFavoredOnLinkPrefix(onLinkPrefixA); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Deprecate on-link prefix A from router A + + SendRouterAdvert(routerAddressA, {Pio(onLinkPrefixA, kValidLitime, 0)}); + + AdvanceTime(10 * 1000); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check the discovered prefix table and ensure that now on-link + // prefix B is again the favored on-link prefix. + + VerifyPrefixTable({OnLinkPrefix(onLinkPrefixB, kValidLitime, kPreferredLifetime, routerAddressB), + OnLinkPrefix(onLinkPrefixA, kValidLitime, 0, routerAddressA)}); + + VerifyFavoredOnLinkPrefix(onLinkPrefixB); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + SuccessOrQuit(sInstance->Get().SetEnabled(false)); + VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength()); + + Log("End of TestFavoredOnLinkPrefix"); + FinalizeTest(); +} + void TestLocalOnLinkPrefixDeprecation(void) { static constexpr uint32_t kMaxRaTxInterval = 196; // In seconds @@ -4187,6 +4315,7 @@ int main(void) ot::TestOmrSelection(); ot::TestDefaultRoute(); ot::TestAdvNonUlaRoute(); + ot::TestFavoredOnLinkPrefix(); ot::TestLocalOnLinkPrefixDeprecation(); #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE ot::TestDomainPrefixAsOmr();