[routing-manager] adv local on-link prefix after added in net data (#8119)

This commit enhances `RoutingManager` so that when we decide to
advertise the local on-link prefix and publish it in Network Data as
an external route, we wait for it to be seen in the leader's Network
Data before including it in the emitted RA messages as PIO. If the
prefix is already present in Network Data (e.g., may have been added
by another BR on the same Thread mesh) we start advertising it
immediately. When publishing prefixes in Network Data, it may take a
short random time before the entry is registered with leader and the
updated Network Data is propagated to all Thread nodes. This change
delays the advertisement of the on-link prefix on the infra link side
till it is configured as an external route on the Thread side.
This commit is contained in:
Abtin Keshavarzian
2022-10-13 09:15:17 -07:00
committed by GitHub
parent f92364c977
commit f5e2a0f961
3 changed files with 126 additions and 24 deletions
+110 -19
View File
@@ -352,6 +352,7 @@ void RoutingManager::HandleNotifierEvents(Events aEvents)
if (mIsRunning && aEvents.Contains(kEventThreadNetdataChanged))
{
UpdateDiscoveredPrefixTableOnNetDataChange();
mLocalOnLinkPrefix.HandleNetDataChange();
ScheduleRoutingPolicyEvaluation(kAfterRandomDelay);
}
@@ -532,7 +533,7 @@ void RoutingManager::EvaluateOnLinkPrefix(void)
// and therefore is the same for all BRs on the same Thread
// mesh.
mLocalOnLinkPrefix.Advertise();
mLocalOnLinkPrefix.PublishAndAdvertise();
// We remove the local on-link prefix from discovered prefix
// table, in case it was previously discovered and included in
@@ -548,7 +549,7 @@ void RoutingManager::EvaluateOnLinkPrefix(void)
mFavoredDiscoveredOnLinkPrefix.Clear();
}
else if (mLocalOnLinkPrefix.IsAdvertising())
else if (mLocalOnLinkPrefix.IsPublishingOrAdvertising())
{
// When an application-specific on-link prefix is received and
// it is larger than the local prefix, we will not remove the
@@ -611,7 +612,7 @@ bool RoutingManager::IsInitalPolicyEvaluationDone(void) const
// and published in the Thread Network Data.
return mIsRunning && !mFavoredOmrPrefix.IsEmpty() &&
(mFavoredDiscoveredOnLinkPrefix.GetLength() != 0 || mLocalOnLinkPrefix.IsAdvertising());
(mFavoredDiscoveredOnLinkPrefix.GetLength() != 0 || mLocalOnLinkPrefix.IsPublishingOrAdvertising());
}
void RoutingManager::ScheduleRoutingPolicyEvaluation(ScheduleMode aMode)
@@ -994,7 +995,7 @@ bool RoutingManager::ShouldProcessPrefixInfoOption(const Ip6::Nd::PrefixInfoOpti
ExitNow();
}
if (mLocalOnLinkPrefix.IsAdvertising())
if (mLocalOnLinkPrefix.IsPublishingOrAdvertising())
{
VerifyOrExit(aPrefix != mLocalOnLinkPrefix.GetPrefix());
}
@@ -1077,18 +1078,36 @@ bool RoutingManager::NetworkDataContainsOmrPrefix(const Ip6::Prefix &aPrefix) co
{
NetworkData::Iterator iterator = NetworkData::kIteratorInit;
NetworkData::OnMeshPrefixConfig onMeshPrefixConfig;
bool contain = false;
bool contains = false;
while (Get<NetworkData::Leader>().GetNextOnMeshPrefix(iterator, onMeshPrefixConfig) == kErrorNone)
{
if (IsValidOmrPrefix(onMeshPrefixConfig) && onMeshPrefixConfig.GetPrefix() == aPrefix)
{
contain = true;
contains = true;
break;
}
}
return contain;
return contains;
}
bool RoutingManager::NetworkDataContainsExternalRoute(const Ip6::Prefix &aPrefix) const
{
NetworkData::Iterator iterator = NetworkData::kIteratorInit;
NetworkData::ExternalRouteConfig routeConfig;
bool contains = false;
while (Get<NetworkData::Leader>().GetNextExternalRoute(iterator, routeConfig) == kErrorNone)
{
if (routeConfig.mStable && routeConfig.GetPrefix() == aPrefix)
{
contains = true;
break;
}
}
return contains;
}
void RoutingManager::UpdateRouterAdvertHeader(const Ip6::Nd::RouterAdvertMessage *aRouterAdvertMessage)
@@ -1994,6 +2013,15 @@ void RoutingManager::LocalOnLinkPrefix::Stop(void)
Get<RoutingManager>().UnpublishExternalRoute(mPrefix);
if (mState == kPublishing)
{
// If we are waiting for prefix to be added in Network Data
// and not yet advertised it in any RA, there is no need to
// deprecate it and we can directly go to `kIdle` state.
mState = kIdle;
ExitNow();
}
mState = kDeprecating;
// Start deprecating the local on-link prefix to send a PIO
@@ -2004,20 +2032,37 @@ exit:
return;
}
void RoutingManager::LocalOnLinkPrefix::Advertise(void)
void RoutingManager::LocalOnLinkPrefix::PublishAndAdvertise(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.
// Start publishing and advertising the local on-link prefix if
// not already.
VerifyOrExit(mState != kAdvertising);
switch (mState)
{
case kIdle:
case kDeprecating:
break;
mState = kAdvertising;
mExpireTime = TimerMilli::GetNow() + TimeMilli::SecToMsec(kDefaultOnLinkPrefixLifetime);
LogInfo("Start advertising on-link prefix %s", mPrefix.ToString().AsCString());
case kPublishing:
case kAdvertising:
ExitNow();
}
mState = kPublishing;
LogInfo("Publishing local on-link prefix %s in netdata", mPrefix.ToString().AsCString());
Get<RoutingManager>().EvaluatePublishingPrefix(mPrefix);
// 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<RoutingManager>().NetworkDataContainsExternalRoute(mPrefix))
{
EnterAdvertisingState();
}
exit:
return;
}
@@ -2031,11 +2076,24 @@ void RoutingManager::LocalOnLinkPrefix::Deprecate(void)
// with zero preferred lifetime and the remaining valid lifetime
// until the timer expires.
VerifyOrExit(mState == kAdvertising);
switch (mState)
{
case kPublishing:
mState = kIdle;
Get<RoutingManager>().EvaluatePublishingPrefix(mPrefix);
mState = kIdle;
break;
mState = kDeprecating;
mTimer.FireAtIfEarlier(mExpireTime);
LogInfo("Deprecate local on-link prefix %s", mPrefix.ToString().AsCString());
case kAdvertising:
mState = kDeprecating;
mTimer.FireAtIfEarlier(mExpireTime);
LogInfo("Deprecate local on-link prefix %s", mPrefix.ToString().AsCString());
break;
case kIdle:
case kDeprecating:
ExitNow();
}
exit:
return;
@@ -2051,6 +2109,7 @@ bool RoutingManager::LocalOnLinkPrefix::ShouldPublish(NetworkData::ExternalRoute
{
case kIdle:
break;
case kPublishing:
case kAdvertising:
case kDeprecating:
shouldPublish = true;
@@ -2067,6 +2126,19 @@ bool RoutingManager::LocalOnLinkPrefix::ShouldPublish(NetworkData::ExternalRoute
return shouldPublish;
}
void RoutingManager::LocalOnLinkPrefix::EnterAdvertisingState(void)
{
mState = kAdvertising;
mExpireTime = TimerMilli::GetNow() + TimeMilli::SecToMsec(kDefaultOnLinkPrefixLifetime);
LogInfo("Start advertising local on-link prefix %s", mPrefix.ToString().AsCString());
}
bool RoutingManager::LocalOnLinkPrefix::IsPublishingOrAdvertising(void) const
{
return (mState == kPublishing) || (mState == kAdvertising);
}
void RoutingManager::LocalOnLinkPrefix::AppendAsPiosTo(Ip6::Nd::RouterAdvertMessage &aRaMessage)
{
AppendCurPrefix(aRaMessage);
@@ -2099,6 +2171,7 @@ void RoutingManager::LocalOnLinkPrefix::AppendCurPrefix(Ip6::Nd::RouterAdvertMes
break;
case kIdle:
case kPublishing:
ExitNow();
}
@@ -2127,6 +2200,20 @@ exit:
return;
}
void RoutingManager::LocalOnLinkPrefix::HandleNetDataChange(void)
{
VerifyOrExit(mState == kPublishing);
if (Get<RoutingManager>().NetworkDataContainsExternalRoute(mPrefix))
{
EnterAdvertisingState();
Get<RoutingManager>().ScheduleRoutingPolicyEvaluation(kAfterRandomDelay);
}
exit:
return;
}
void RoutingManager::LocalOnLinkPrefix::HandleExtPanIdChange(void)
{
// If the prefix is advertised or being deprecated we remember it
@@ -2141,6 +2228,10 @@ void RoutingManager::LocalOnLinkPrefix::HandleExtPanIdChange(void)
case kIdle:
break;
case kPublishing:
Get<RoutingManager>().UnpublishExternalRoute(mPrefix);
break;
case kAdvertising:
case kDeprecating:
if (mOldPrefix.GetLength() != 0)
+6 -2
View File
@@ -613,12 +613,13 @@ private:
void Generate(void);
void Start(void);
void Stop(void);
void Advertise(void);
void PublishAndAdvertise(void);
void Deprecate(void);
bool ShouldPublish(NetworkData::ExternalRouteConfig &aRouteConfig) const;
void AppendAsPiosTo(Ip6::Nd::RouterAdvertMessage &aRaMessage);
const Ip6::Prefix &GetPrefix(void) const { return mPrefix; }
bool IsAdvertising(void) const { return (mState == kAdvertising); }
bool IsPublishingOrAdvertising(void) const;
void HandleNetDataChange(void);
void HandleExtPanIdChange(void);
void HandleTimer(void);
@@ -626,10 +627,12 @@ private:
enum State : uint8_t
{
kIdle,
kPublishing,
kAdvertising,
kDeprecating,
};
void EnterAdvertisingState(void);
void AppendCurPrefix(Ip6::Nd::RouterAdvertMessage &aRaMessage);
void AppendOldPrefix(Ip6::Nd::RouterAdvertMessage &aRaMessage);
@@ -775,6 +778,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;
void UpdateRouterAdvertHeader(const Ip6::Nd::RouterAdvertMessage *aRouterAdvertMessage);
bool IsReceivedRouterAdvertFromManager(const Ip6::Nd::RouterAdvertMessage &aRaMessage) const;
void ResetDiscoveredPrefixStaleTimer(void);
+10 -3
View File
@@ -300,7 +300,7 @@ void ValidateRouterAdvert(const Icmp6Packet &aPacket)
break;
}
}
else
else if (sExpectOldOnLinkPio)
{
VerifyOrQuit(pio.GetPreferredLifetime() == 0, "Old on link prefix is not deprecated");
sOldOnLinkPrefix = prefix;
@@ -347,16 +347,23 @@ void ValidateRouterAdvert(const Icmp6Packet &aPacket)
break;
case kPioAdvertisingLocalOnLink:
case kPioDeprecatingLocalOnLink:
VerifyOrQuit(sawExpectedPio, "Did not see on-link prefix PIO in the RA");
// First emitted RAs may not yet have the expected PIO
// so we exit and not set `sRaValidated` to allow it
// to be checked for next received RA.
VerifyOrExit(sawExpectedPio);
break;
}
if (sExpectOldOnLinkPio)
{
VerifyOrQuit(sawExpecteOldPio, "Did not see old on-link prefix PIO in the RA");
VerifyOrExit(sawExpecteOldPio);
}
sRaValidated = true;
}
exit:
return;
}
void LogRouterAdvert(const Icmp6Packet &aPacket)