From c28496dbd84ce033d09ac78b6bffaebac4303eb0 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 8 Aug 2022 09:24:10 -0700 Subject: [PATCH] [routing-manager] add `LocalOnLinkPrefix` class (#7989) This commit simplifies `RoutingManager` by adding a nested class `LocalOnLinkPrefix` which encapsulates the local on-link prefix related info and functionality. It tracks the state of the prefix, i.e. whether we are advertising, deprecating or not including it. It provides a method to append it as a PIO in an RA message and uses a timer to keep track of the prefix's lifetime (since the last time it was advertised in an RA message). This commit also updated the `test_routing_manager` unit test to add `TestLocalOnLinkPrefixDeprecation()` checking the deprecation and expiration of local on-link prefix. --- src/core/border_router/routing_manager.cpp | 292 +++++++++++++-------- src/core/border_router/routing_manager.hpp | 47 +++- tests/unit/test_routing_manager.cpp | 138 ++++++++++ 3 files changed, 357 insertions(+), 120 deletions(-) diff --git a/src/core/border_router/routing_manager.cpp b/src/core/border_router/routing_manager.cpp index c7f213ff4..e32bef077 100644 --- a/src/core/border_router/routing_manager.cpp +++ b/src/core/border_router/routing_manager.cpp @@ -66,8 +66,7 @@ RoutingManager::RoutingManager(Instance &aInstance) , mInfraIf(aInstance) , mLocalOmrPrefix(aInstance) , mRouteInfoOptionPreference(NetworkData::kRoutePreferenceMedium) - , mIsAdvertisingLocalOnLinkPrefix(false) - , mOnLinkPrefixDeprecateTimer(aInstance, HandleOnLinkPrefixDeprecateTimer) + , mLocalOnLinkPrefix(aInstance) , mIsAdvertisingLocalNat64Prefix(false) , mDiscoveredPrefixTable(aInstance) , mTimeRouterAdvMessageLastUpdate(TimerMilli::GetNow()) @@ -82,9 +81,6 @@ RoutingManager::RoutingManager(Instance &aInstance) mFavoredDiscoveredOnLinkPrefix.Clear(); mBrUlaPrefix.Clear(); - - mLocalOnLinkPrefix.Clear(); - mLocalNat64Prefix.Clear(); } @@ -99,7 +95,7 @@ Error RoutingManager::Init(uint32_t aInfraIfIndex, bool aInfraIfIsRunning) #if OPENTHREAD_CONFIG_BORDER_ROUTING_NAT64_ENABLE GenerateNat64Prefix(); #endif - GenerateOnLinkPrefix(); + mLocalOnLinkPrefix.Generate(); error = mInfraIf.HandleStateChanged(mInfraIf.GetIfIndex(), aInfraIfIsRunning); @@ -168,7 +164,7 @@ Error RoutingManager::GetOnLinkPrefix(Ip6::Prefix &aPrefix) Error error = kErrorNone; VerifyOrExit(IsInitialized(), error = kErrorInvalidState); - aPrefix = mLocalOnLinkPrefix; + aPrefix = mLocalOnLinkPrefix.GetPrefix(); exit: return error; @@ -232,20 +228,6 @@ void RoutingManager::GenerateNat64Prefix(void) } #endif -void RoutingManager::GenerateOnLinkPrefix(void) -{ - MeshCoP::ExtendedPanId extPanId = Get().GetExtPanId(); - - mLocalOnLinkPrefix.mPrefix.mFields.m8[0] = 0xfd; - // Global ID: 40 most significant bits of Extended PAN ID - memcpy(mLocalOnLinkPrefix.mPrefix.mFields.m8 + 1, extPanId.m8, 5); - // Subnet ID: 16 least significant bits of Extended PAN ID - memcpy(mLocalOnLinkPrefix.mPrefix.mFields.m8 + 6, extPanId.m8 + 6, 2); - mLocalOnLinkPrefix.SetLength(kOnLinkPrefixLength); - - LogNote("Local on-link prefix: %s", mLocalOnLinkPrefix.ToString().AsCString()); -} - void RoutingManager::EvaluateState(void) { if (mIsEnabled && Get().IsAttached() && mInfraIf.IsRunning()) @@ -266,6 +248,7 @@ void RoutingManager::Start(void) mIsRunning = true; UpdateDiscoveredPrefixTableOnNetDataChange(); + mLocalOnLinkPrefix.Start(); StartRouterSolicitationDelay(); } } @@ -279,14 +262,7 @@ void RoutingManager::Stop(void) mFavoredDiscoveredOnLinkPrefix.Clear(); - if (mIsAdvertisingLocalOnLinkPrefix) - { - UnpublishExternalRoute(mLocalOnLinkPrefix); - - // Start deprecating the local on-link prefix to send a PIO - // with zero preferred lifetime in `SendRouterAdvertisement`. - DeprecateOnLinkPrefix(); - } + mLocalOnLinkPrefix.Stop(); #if OPENTHREAD_CONFIG_BORDER_ROUTING_NAT64_ENABLE if (mIsAdvertisingLocalNat64Prefix) @@ -298,7 +274,6 @@ void RoutingManager::Stop(void) SendRouterAdvertisement(kInvalidateAllPrevPrefixes); mAdvertisedPrefixes.Clear(); - mOnLinkPrefixDeprecateTimer.Stop(); mDiscoveredPrefixTable.RemoveAllEntries(); mDiscoveredPrefixStaleTimer.Stop(); @@ -359,15 +334,7 @@ void RoutingManager::HandleNotifierEvents(Events aEvents) if (aEvents.Contains(kEventThreadExtPanIdChanged)) { - if (mIsAdvertisingLocalOnLinkPrefix) - { - UnpublishExternalRoute(mLocalOnLinkPrefix); - // TODO: consider deprecating/invalidating existing - // on-link prefix - mIsAdvertisingLocalOnLinkPrefix = false; - } - - GenerateOnLinkPrefix(); + mLocalOnLinkPrefix.HandleExtPanIdChange(); if (mIsRunning) { @@ -511,14 +478,7 @@ void RoutingManager::EvaluateOnLinkPrefix(void) // We need to advertise our local on-link prefix since there is // no discovered on-link prefix. - mOnLinkPrefixDeprecateTimer.Stop(); - VerifyOrExit(!mIsAdvertisingLocalOnLinkPrefix); - - SuccessOrExit(PublishExternalRoute(mLocalOnLinkPrefix, NetworkData::kRoutePreferenceMedium)); - - mIsAdvertisingLocalOnLinkPrefix = true; - LogInfo("Start advertising on-link prefix %s on %s", mLocalOnLinkPrefix.ToString().AsCString(), - mInfraIf.ToString().AsCString()); + SuccessOrExit(mLocalOnLinkPrefix.Advertise()); // We remove the local on-link prefix from discovered prefix // table, in case it was previously discovered and included in @@ -530,12 +490,11 @@ void RoutingManager::EvaluateOnLinkPrefix(void) // not allow the local on-link prefix to be added in the prefix // table while we are advertising it. - mDiscoveredPrefixTable.RemoveOnLinkPrefix(mLocalOnLinkPrefix, DiscoveredPrefixTable::kKeepInNetData); + mDiscoveredPrefixTable.RemoveOnLinkPrefix(mLocalOnLinkPrefix.GetPrefix(), + DiscoveredPrefixTable::kKeepInNetData); } - else + else if (mLocalOnLinkPrefix.IsAdvertising()) { - VerifyOrExit(mIsAdvertisingLocalOnLinkPrefix); - // When an application-specific on-link prefix is received and // it is larger than the local prefix, we will not remove the // advertised local prefix. In this case, there will be two @@ -543,11 +502,11 @@ void RoutingManager::EvaluateOnLinkPrefix(void) // converge to the same smallest/favored on-link prefix and the // application-specific prefix is not used. - if (!(mLocalOnLinkPrefix < mFavoredDiscoveredOnLinkPrefix)) + if (!(mLocalOmrPrefix.GetPrefix() < mFavoredDiscoveredOnLinkPrefix)) { LogInfo("EvaluateOnLinkPrefix: There is already favored on-link prefix %s on %s", mFavoredDiscoveredOnLinkPrefix.ToString().AsCString(), mInfraIf.ToString().AsCString()); - DeprecateOnLinkPrefix(); + mLocalOnLinkPrefix.Deprecate(); } } @@ -555,34 +514,6 @@ exit: return; } -void RoutingManager::HandleOnLinkPrefixDeprecateTimer(Timer &aTimer) -{ - aTimer.Get().HandleOnLinkPrefixDeprecateTimer(); -} - -void RoutingManager::HandleOnLinkPrefixDeprecateTimer(void) -{ - OT_ASSERT(!mIsAdvertisingLocalOnLinkPrefix); - - LogInfo("Local on-link prefix %s expired", mLocalOnLinkPrefix.ToString().AsCString()); - - if (!mDiscoveredPrefixTable.ContainsOnLinkPrefix(mLocalOnLinkPrefix)) - { - UnpublishExternalRoute(mLocalOnLinkPrefix); - } -} - -void RoutingManager::DeprecateOnLinkPrefix(void) -{ - OT_ASSERT(mIsAdvertisingLocalOnLinkPrefix); - - mIsAdvertisingLocalOnLinkPrefix = false; - - LogInfo("Deprecate local on-link prefix %s", mLocalOnLinkPrefix.ToString().AsCString()); - mOnLinkPrefixDeprecateTimer.StartAt(mTimeAdvertisedOnLinkPrefix, - TimeMilli::SecToMsec(kDefaultOnLinkPrefixLifetime)); -} - #if OPENTHREAD_CONFIG_BORDER_ROUTING_NAT64_ENABLE void RoutingManager::EvaluateNat64Prefix(void) { @@ -747,30 +678,10 @@ void RoutingManager::SendRouterAdvertisement(RouterAdvTxMode aRaTxMode) NetworkData::Iterator iterator; NetworkData::OnMeshPrefixConfig prefixConfig; - // Append PIO for local on-link prefix. Ensure it is either being + // Append PIO for local on-link prefix if is either being // advertised or deprecated. - if (mIsAdvertisingLocalOnLinkPrefix || mOnLinkPrefixDeprecateTimer.IsRunning()) - { - uint32_t validLifetime = kDefaultOnLinkPrefixLifetime; - uint32_t preferredLifetime = kDefaultOnLinkPrefixLifetime; - - if (mOnLinkPrefixDeprecateTimer.IsRunning()) - { - validLifetime = TimeMilli::MsecToSec(mOnLinkPrefixDeprecateTimer.GetFireTime() - TimerMilli::GetNow()); - preferredLifetime = 0; - } - - SuccessOrAssert(raMsg.AppendPrefixInfoOption(mLocalOnLinkPrefix, validLifetime, preferredLifetime)); - - if (mIsAdvertisingLocalOnLinkPrefix) - { - mTimeAdvertisedOnLinkPrefix = TimerMilli::GetNow(); - } - - LogInfo("RouterAdvert: Added PIO for %s (valid=%u, preferred=%u)", mLocalOnLinkPrefix.ToString().AsCString(), - validLifetime, preferredLifetime); - } + mLocalOnLinkPrefix.AppendAsPioTo(raMsg); // Determine which previously advertised prefixes need to be // invalidated. Under `kInvalidateAllPrevPrefixes` mode we need @@ -931,7 +842,7 @@ bool RoutingManager::IsReceivedRouterAdvertFromManager(const Ip6::Nd::RouterAdve VerifyOrExit(pio.IsValid()); pio.GetPrefix(prefix); - VerifyOrExit(prefix == mLocalOnLinkPrefix); + VerifyOrExit(prefix == mLocalOnLinkPrefix.GetPrefix()); break; } @@ -1127,9 +1038,9 @@ bool RoutingManager::ShouldProcessPrefixInfoOption(const Ip6::Nd::PrefixInfoOpti ExitNow(); } - if (mIsAdvertisingLocalOnLinkPrefix) + if (mLocalOnLinkPrefix.IsAdvertising()) { - VerifyOrExit(aPrefix != mLocalOnLinkPrefix); + VerifyOrExit(aPrefix != mLocalOnLinkPrefix.GetPrefix()); } shouldProcess = true; @@ -2125,6 +2036,175 @@ exit: return; } +//--------------------------------------------------------------------------------------------------------------------- +// LocalOnLinkPrefix + +RoutingManager::LocalOnLinkPrefix::LocalOnLinkPrefix(Instance &aInstance) + : InstanceLocator(aInstance) + , mState(kIdle) + , mTimer(aInstance, HandleTimer) +{ + mPrefix.Clear(); +} + +void RoutingManager::LocalOnLinkPrefix::Generate(void) +{ + MeshCoP::ExtendedPanId extPanId = Get().GetExtPanId(); + + mPrefix.mPrefix.mFields.m8[0] = 0xfd; + // Global ID: 40 most significant bits of Extended PAN ID + memcpy(mPrefix.mPrefix.mFields.m8 + 1, extPanId.m8, 5); + // Subnet ID: 16 least significant bits of Extended PAN ID + memcpy(mPrefix.mPrefix.mFields.m8 + 6, extPanId.m8 + 6, 2); + mPrefix.SetLength(kOnLinkPrefixLength); + + LogNote("Local on-link prefix: %s", mPrefix.ToString().AsCString()); +} + +void RoutingManager::LocalOnLinkPrefix::Start(void) +{ + mState = kIdle; +} + +void RoutingManager::LocalOnLinkPrefix::Stop(void) +{ + VerifyOrExit(mState != kIdle); + + Get().UnpublishExternalRoute(mPrefix); + mState = kDeprecating; + + // Start deprecating the local on-link prefix to send a PIO + // with zero preferred lifetime in the next call to + // `SendRouterAdvertisement()`. + +exit: + return; +} + +Error RoutingManager::LocalOnLinkPrefix::Advertise(void) +{ + // Start advertising the local on-link prefix if not already. This + // will also publish it in the Network Data as an external route + // entry. + + Error error = kErrorNone; + + VerifyOrExit(mState != kAdvertising); + + mTimer.Stop(); + + SuccessOrExit(error = Get().PublishExternalRoute(mPrefix, NetworkData::kRoutePreferenceMedium)); + + mState = kAdvertising; + LogInfo("Start advertising on-link prefix %s", mPrefix.ToString().AsCString()); + +exit: + return error; +} + +void RoutingManager::LocalOnLinkPrefix::Deprecate(void) +{ + // Deprecate the local on-link prefix if it was being advertised + // before. While depreciating the prefix, we wait for the lifetime + // timer to expire before unpublishing the prefix from the Network + // Data. We also continue to include it as a PIO in the RA message + // with zero preferred lifetime and the remaining valid lifetime + // until the timer expires. + + VerifyOrExit(mState == kAdvertising); + + mState = kDeprecating; + LogInfo("Deprecate local on-link prefix %s", mPrefix.ToString().AsCString()); + +exit: + return; +} + +void RoutingManager::LocalOnLinkPrefix::AppendAsPioTo(Ip6::Nd::RouterAdvertMessage &aRaMessage) +{ + // Append the local on-link prefix to the `aRaMessage` as a PIO + // only if it is being advertised or deprecated. + // + // If in `kAdvertising` state, we restart the lifetime timer. + // If in `kDeprecating` state, we include it as PIO with zero + // preferred lifetime and the remaining valid lifetime which + // is tracked by the timer. + + uint32_t validLifetime = kDefaultOnLinkPrefixLifetime; + uint32_t preferredLifetime = kDefaultOnLinkPrefixLifetime; + TimeMilli now; + + switch (mState) + { + case kAdvertising: + mTimer.Start(TimeMilli::SecToMsec(kDefaultOnLinkPrefixLifetime)); + break; + + case kDeprecating: + now = TimerMilli::GetNow(); + VerifyOrExit(mTimer.IsRunning() && (mTimer.GetFireTime() > now)); + validLifetime = TimeMilli::MsecToSec(mTimer.GetFireTime() - now); + preferredLifetime = 0; + break; + + case kIdle: + ExitNow(); + } + + SuccessOrAssert(aRaMessage.AppendPrefixInfoOption(mPrefix, validLifetime, preferredLifetime)); + + LogInfo("RouterAdvert: Added PIO for %s (valid=%u, preferred=%u)", mPrefix.ToString().AsCString(), validLifetime, + preferredLifetime); + +exit: + return; +} + +void RoutingManager::LocalOnLinkPrefix::HandleExtPanIdChange(void) +{ + switch (mState) + { + case kIdle: + break; + + case kAdvertising: + Get().UnpublishExternalRoute(mPrefix); + + // TODO: consider deprecating/invalidating the existing + // on-link prefix. + break; + + case kDeprecating: + mTimer.Stop(); + break; + } + + mState = kIdle; + Generate(); +} + +void RoutingManager::LocalOnLinkPrefix::HandleTimer(Timer &aTimer) +{ + aTimer.Get().mLocalOnLinkPrefix.HandleTimer(); +} + +void RoutingManager::LocalOnLinkPrefix::HandleTimer(void) +{ + VerifyOrExit(mState == kDeprecating); + + LogInfo("Local on-link prefix %s expired", mPrefix.ToString().AsCString()); + + if (!Get().mDiscoveredPrefixTable.ContainsOnLinkPrefix(mPrefix)) + { + Get().UnpublishExternalRoute(mPrefix); + } + + mState = kIdle; + +exit: + return; +} + //--------------------------------------------------------------------------------------------------------------------- // OnMeshPrefixArray diff --git a/src/core/border_router/routing_manager.hpp b/src/core/border_router/routing_manager.hpp index fcc07c448..c08cc4528 100644 --- a/src/core/border_router/routing_manager.hpp +++ b/src/core/border_router/routing_manager.hpp @@ -515,7 +515,7 @@ private: RoutePreference mPreference; }; - class LocalOmrPrefix : InstanceLocator + class LocalOmrPrefix : public InstanceLocator { public: explicit LocalOmrPrefix(Instance &aInstance); @@ -531,6 +531,37 @@ private: bool mIsAddedInNetData; }; + class LocalOnLinkPrefix : public InstanceLocator + { + public: + explicit LocalOnLinkPrefix(Instance &aInstance); + + void Generate(void); + void Start(void); + void Stop(void); + Error Advertise(void); + void Deprecate(void); + void AppendAsPioTo(Ip6::Nd::RouterAdvertMessage &aRaMessage); + const Ip6::Prefix &GetPrefix(void) const { return mPrefix; } + bool IsAdvertising(void) const { return (mState == kAdvertising); } + void HandleExtPanIdChange(void); + + private: + enum State : uint8_t + { + kIdle, + kAdvertising, + kDeprecating, + }; + + static void HandleTimer(Timer &aTimer); + void HandleTimer(void); + + Ip6::Prefix mPrefix; + State mState; + TimerMilli mTimer; + }; + typedef Ip6::Prefix OnMeshPrefix; class OnMeshPrefixArray : public Array @@ -547,7 +578,6 @@ private: bool IsInitialized(void) const { return mInfraIf.IsInitialized(); } bool IsEnabled(void) const { return mIsEnabled; } Error LoadOrGenerateRandomBrUlaPrefix(void); - void GenerateOnLinkPrefix(void); void EvaluateOnLinkPrefix(void); @@ -574,8 +604,6 @@ private: static void HandleDiscoveredPrefixStaleTimer(Timer &aTimer); void HandleDiscoveredPrefixStaleTimer(void); static void HandleRoutingPolicyTimer(Timer &aTimer); - void HandleOnLinkPrefixDeprecateTimer(void); - static void HandleOnLinkPrefixDeprecateTimer(Timer &aTimer); void DeprecateOnLinkPrefix(void); void HandleRouterSolicit(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress); @@ -619,16 +647,7 @@ private: // Prefix length of zero indicates there is none. Ip6::Prefix mFavoredDiscoveredOnLinkPrefix; - // The on-link prefix loaded from local persistent storage or - // randomly generated if non is found in persistent storage. - Ip6::Prefix mLocalOnLinkPrefix; - - bool mIsAdvertisingLocalOnLinkPrefix; - - // The last time when the on-link prefix is advertised with - // non-zero preferred lifetime. - TimeMilli mTimeAdvertisedOnLinkPrefix; - TimerMilli mOnLinkPrefixDeprecateTimer; + LocalOnLinkPrefix mLocalOnLinkPrefix; // The NAT64 prefix allocated from the /48 BR ULA prefix. Ip6::Prefix mLocalNat64Prefix; diff --git a/tests/unit/test_routing_manager.cpp b/tests/unit/test_routing_manager.cpp index 5725e1308..d58885e7e 100644 --- a/tests/unit/test_routing_manager.cpp +++ b/tests/unit/test_routing_manager.cpp @@ -81,6 +81,7 @@ bool sRsEmitted; // Indicates if an RS message was emitted by BR. bool sRaValidated; // Indicates if an RA was emitted by BR and successfully validated. bool sSawExpectedRio; // Indicates if the emitted RA by BR contained an RIO with `sExpectedRioPrefix` ExpectedPio sExpectedPio; // Expected PIO in the emitted RA by BR (MUST be seen in RA to set `sRaValidated`). +uint32_t sOnLinkLifetime; // Valid lifetime for local on-link prefix from the last processed RA. Ip6::Prefix sExpectedRioPrefix; // Expected RIO prefix to see in RA (MUST be seen to set `sSawExpectedRio`). //---------------------------------------------------------------------------------------------------------------------- @@ -245,6 +246,8 @@ void ValidateRouterAdvert(const Icmp6Packet &aPacket) VerifyOrQuit(pio.GetPreferredLifetime() == 0, "On link prefix is not deprecated"); } + sOnLinkLifetime = pio.GetValidLifetime(); + break; } @@ -1105,6 +1108,140 @@ void TestDefaultRoute(void) testFreeInstance(sInstance); } +void TestLocalOnLinkPrefixDeprecation(void) +{ + static constexpr uint32_t kMaxRaTxInterval = 601; // In seconds + + Ip6::Prefix localOnLink; + Ip6::Prefix localOmr; + Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64); + Ip6::Address routerAddressA = AddressFromString("fd00::aaaa"); + uint32_t localOnLinkLifetime; + + Log("--------------------------------------------------------------------------------------------"); + Log("TestLocalOnLinkPrefixDeprecation"); + + InitTest(); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Start Routing Manager. Check emitted RS and RA messages. + + 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()); + + sRsEmitted = false; + sRaValidated = false; + sSawExpectedRio = false; + sExpectedPio = kPioAdvertisingLocalOnLink; + sExpectedRioPrefix = localOmr; + + AdvanceTime(30000); + + VerifyOrQuit(sRsEmitted); + VerifyOrQuit(sRaValidated); + VerifyOrQuit(sSawExpectedRio); + Log("Local on-link prefix is being advertised, lifetime: %d", sOnLinkLifetime); + localOnLinkLifetime = sOnLinkLifetime; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check Network Data to include the local OMR and on-link prefix. + + VerifyOmrPrefixInNetData(localOmr); + VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium)}); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Send an RA from router A with a new on-link (PIO) which is preferred over + // the local on-link prefix. + + SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)}); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check that the local on-link prefix is now deprecating in the new RA. + + sRaValidated = false; + sSawExpectedRio = false; + sExpectedPio = kPioDeprecatingLocalOnLink; + + AdvanceTime(10000); + VerifyOrQuit(sRaValidated); + VerifyOrQuit(sSawExpectedRio); + Log("On-link prefix is deprecating, remaining lifetime:%d", sOnLinkLifetime); + VerifyOrQuit(sOnLinkLifetime < localOnLinkLifetime); + localOnLinkLifetime = sOnLinkLifetime; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check Network Data. We must see the new on-link prefix from router A + // along with the deprecating local on-link prefix. + + VerifyOmrPrefixInNetData(localOmr); + VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium), + ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium)}); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Wait for local on-link prefix to expire + + while (localOnLinkLifetime > kMaxRaTxInterval) + { + // Send same RA from router A to keep the on-link prefix alive. + + SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)}); + + // Ensure Network Data entries remain as before. Mainly we still + // see the deprecating local on-link prefix. + + VerifyOmrPrefixInNetData(localOmr); + VerifyExternalRoutesInNetData({ExternalRoute(localOnLink, NetworkData::kRoutePreferenceMedium), + ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium)}); + + // Keep checking the emitted RAs and make sure on-link prefix + // is included with smaller lifetime every time. + + sRaValidated = false; + sSawExpectedRio = false; + sExpectedPio = kPioDeprecatingLocalOnLink; + + AdvanceTime(kMaxRaTxInterval * 1000); + + VerifyOrQuit(sRaValidated); + VerifyOrQuit(sSawExpectedRio); + Log("On-link prefix is deprecating, remaining lifetime:%d", sOnLinkLifetime); + VerifyOrQuit(sOnLinkLifetime < localOnLinkLifetime); + localOnLinkLifetime = sOnLinkLifetime; + } + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // The local on-link prefix must be expired and should no + // longer be seen in the emitted RA message. + + sRaValidated = false; + sSawExpectedRio = false; + sExpectedPio = kNoPio; + + AdvanceTime(kMaxRaTxInterval * 1000); + + VerifyOrQuit(sRaValidated); + VerifyOrQuit(sSawExpectedRio); + Log("On-link prefix is now expired"); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Check Network Data and make sure the the expired local on-link prefix + // is removed. + + VerifyOmrPrefixInNetData(localOmr); + VerifyExternalRoutesInNetData({ExternalRoute(onLinkPrefix, NetworkData::kRoutePreferenceMedium)}); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + Log("End of TestLocalOnLinkPrefixDeprecation"); + + testFreeInstance(sInstance); +} + #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE int main(void) @@ -1113,6 +1250,7 @@ int main(void) TestSamePrefixesFromMultipleRouters(); TestOmrSelection(); TestDefaultRoute(); + TestLocalOnLinkPrefixDeprecation(); printf("All tests passed\n"); #else printf("BORDER_ROUTING feature is not enabled\n");