[border-routing] fix stale prefixes checking timer (#7241)

Current implementation will reschedule the Stale Timer when discovered
on-link or OMR prefixes or RA messages are updated, but it has a few
issues:

1. It's counting the maximum stale time of all on-link prefixes so
    that we will schedule Router Solicitation when all on-link
    prefixes become stale. But it failed to filter out OMR prefixes in
    the `mDiscoveredPrefixes` list. This results in incorrect stale
    time calculation.

2. A deprecated on-link-prefix is not removed from
    `mDiscoveredPrefixes` directly but the preferred lifetime is set
    to zero. We are not filtering out deprecated on-link prefixes when
    calculating stale time and this results in zero stale timer delay
    if there are no non-deprecated on-link prefixes.

This commit fixes those issues by having a dedicated
`ResetDiscoveredPrefixStaleTimer` to reschedule the stale timer with
following rules whenever discovered prefixes or learnt RA messages are
updated:

1. If BR learns RA header from Host daemons, it should send RS when
   the RA header is stale.

2. If BR discovered any on-link prefix, it should send RS when all
   on-link prefixes are stale.

3. If BR discovered any OMR prefix, it should send RS when the first
   OMR prefix is stale.

`ResetDiscoveredPrefixStaleTimer` is supposed to correctly calculate
stale timer timeout whenever it's called.
This commit is contained in:
Simon Lin
2021-12-26 23:15:02 -08:00
committed by GitHub
parent d47dea0b6f
commit 2129daaf21
2 changed files with 77 additions and 14 deletions
+75 -14
View File
@@ -65,6 +65,7 @@ RoutingManager::RoutingManager(Instance &aInstance)
, mIsAdvertisingLocalOnLinkPrefix(false)
, mOnLinkPrefixDeprecateTimer(aInstance, HandleOnLinkPrefixDeprecateTimer)
, mTimeRouterAdvMessageLastUpdate(TimerMilli::GetNow())
, mLearntRouterAdvMessageFromHost(false)
, mDiscoveredPrefixInvalidTimer(aInstance, HandleDiscoveredPrefixInvalidTimer)
, mDiscoveredPrefixStaleTimer(aInstance, HandleDiscoveredPrefixStaleTimer)
, mRouterAdvertisementTimer(aInstance, HandleRouterAdvertisementTimer)
@@ -917,6 +918,9 @@ void RoutingManager::HandleRouterSolicitTimer(void)
// Re-evaluate our routing policy and send Router Advertisement if necessary.
EvaluateRoutingPolicy();
// Reset prefix stale timer because `mDiscoveredPrefixes` may change.
ResetDiscoveredPrefixStaleTimer();
}
}
@@ -927,7 +931,7 @@ void RoutingManager::HandleDiscoveredPrefixStaleTimer(Timer &aTimer)
void RoutingManager::HandleDiscoveredPrefixStaleTimer(void)
{
otLogInfoBr("All on-link prefixes are stale");
otLogInfoBr("Stale On-Link or OMR Prefixes or RA messages are detected");
StartRouterSolicitationDelay();
}
@@ -1072,7 +1076,6 @@ bool RoutingManager::UpdateDiscoveredOnLinkPrefix(const RouterAdv::PrefixInfoOpt
{
Ip6::Prefix prefix = aPio.GetPrefix();
bool needReevaluate = false;
TimeMilli staleTime;
ExternalPrefix onLinkPrefix;
ExternalPrefix *existingPrefix = nullptr;
@@ -1093,16 +1096,12 @@ bool RoutingManager::UpdateDiscoveredOnLinkPrefix(const RouterAdv::PrefixInfoOpt
onLinkPrefix.mPreferredLifetime = aPio.GetPreferredLifetime();
onLinkPrefix.mTimeLastUpdate = TimerMilli::GetNow();
staleTime = TimerMilli::GetNow();
for (ExternalPrefix &externalPrefix : mDiscoveredPrefixes)
{
if (externalPrefix == onLinkPrefix)
{
existingPrefix = &externalPrefix;
}
staleTime = OT_MAX(staleTime, externalPrefix.GetStaleTime());
}
if (existingPrefix == nullptr)
@@ -1158,8 +1157,7 @@ bool RoutingManager::UpdateDiscoveredOnLinkPrefix(const RouterAdv::PrefixInfoOpt
}
mDiscoveredPrefixInvalidTimer.FireAtIfEarlier(existingPrefix->GetExpireTime());
staleTime = OT_MAX(staleTime, existingPrefix->GetStaleTime());
mDiscoveredPrefixStaleTimer.FireAtIfEarlier(staleTime);
ResetDiscoveredPrefixStaleTimer();
exit:
return needReevaluate;
@@ -1213,8 +1211,6 @@ void RoutingManager::UpdateDiscoveredOmrPrefix(const RouterAdv::RouteInfoOption
{
existingPrefix = &externalPrefix;
}
mDiscoveredPrefixStaleTimer.FireAtIfEarlier(externalPrefix.GetStaleTime());
}
if (existingPrefix == nullptr)
@@ -1239,7 +1235,7 @@ void RoutingManager::UpdateDiscoveredOmrPrefix(const RouterAdv::RouteInfoOption
*existingPrefix = omrPrefix;
mDiscoveredPrefixInvalidTimer.FireAtIfEarlier(existingPrefix->GetExpireTime());
mDiscoveredPrefixStaleTimer.FireAtIfEarlier(existingPrefix->GetStaleTime());
ResetDiscoveredPrefixStaleTimer();
exit:
return;
@@ -1325,17 +1321,82 @@ bool RoutingManager::UpdateRouterAdvMessage(const RouterAdv::RouterAdvMessage *a
if (aRouterAdvMessage == nullptr || aRouterAdvMessage->GetRouterLifetime() == 0)
{
mRouterAdvMessage.SetToDefault();
mLearntRouterAdvMessageFromHost = false;
}
else
{
mRouterAdvMessage = *aRouterAdvMessage;
mDiscoveredPrefixStaleTimer.FireAtIfEarlier(mTimeRouterAdvMessageLastUpdate +
Time::SecToMsec(kRtrAdvStaleTime));
mRouterAdvMessage = *aRouterAdvMessage;
mLearntRouterAdvMessageFromHost = true;
}
ResetDiscoveredPrefixStaleTimer();
return (mRouterAdvMessage != oldRouterAdvMessage);
}
void RoutingManager::ResetDiscoveredPrefixStaleTimer(void)
{
TimeMilli now = TimerMilli::GetNow();
TimeMilli nextStaleTime = now.GetDistantFuture();
TimeMilli maxOnlinkPrefixStaleTime = now;
bool requireCheckStaleOnlinkPrefix = false;
OT_ASSERT(mIsRunning);
// The stale timer triggers sending RS to check the state of On-Link/OMR prefixes and host RA messages.
// The rules for calculating the next stale time:
// 1. If BR learns RA header from Host daemons, it should send RS when the RA header is stale.
// 2. If BR discovered any on-link prefix, it should send RS when all on-link prefixes are stale.
// 3. If BR discovered any OMR prefix, it should send RS when the first OMR prefix is stale.
// Check for stale Router Advertisement Message if learnt from Host.
if (mLearntRouterAdvMessageFromHost)
{
TimeMilli routerAdvMessageStaleTime = mTimeRouterAdvMessageLastUpdate + Time::SecToMsec(kRtrAdvStaleTime);
nextStaleTime = OT_MIN(nextStaleTime, routerAdvMessageStaleTime);
}
for (ExternalPrefix &externalPrefix : mDiscoveredPrefixes)
{
TimeMilli prefixStaleTime = externalPrefix.GetStaleTime();
if (externalPrefix.mIsOnLinkPrefix)
{
if (!externalPrefix.IsDeprecated())
{
// Check for least recent stale On-Link Prefixes if BR is not advertising local On-Link Prefix.
maxOnlinkPrefixStaleTime = OT_MAX(maxOnlinkPrefixStaleTime, prefixStaleTime);
requireCheckStaleOnlinkPrefix = true;
}
}
else
{
// Check for most recent stale OMR Prefixes
nextStaleTime = OT_MIN(nextStaleTime, prefixStaleTime);
}
}
if (requireCheckStaleOnlinkPrefix)
{
nextStaleTime = OT_MIN(nextStaleTime, maxOnlinkPrefixStaleTime);
}
if (nextStaleTime == now.GetDistantFuture())
{
if (mDiscoveredPrefixStaleTimer.IsRunning())
{
otLogDebgBr("Prefix stale timer stopped");
}
mDiscoveredPrefixStaleTimer.Stop();
}
else
{
mDiscoveredPrefixStaleTimer.FireAt(nextStaleTime);
otLogDebgBr("Prefix stale timer scheduled in %lu ms", nextStaleTime - now);
}
}
} // namespace BorderRouter
} // namespace ot
@@ -315,6 +315,7 @@ private:
void InvalidateAllDiscoveredPrefixes(void);
bool NetworkDataContainsOmrPrefix(const Ip6::Prefix &aPrefix) const;
bool UpdateRouterAdvMessage(const RouterAdv::RouterAdvMessage *aRouterAdvMessage);
void ResetDiscoveredPrefixStaleTimer(void);
static bool IsValidOmrPrefix(const NetworkData::OnMeshPrefixConfig &aOnMeshPrefixConfig);
static bool IsValidOmrPrefix(const Ip6::Prefix &aOmrPrefix);
@@ -370,6 +371,7 @@ private:
// and updated with RA messages initiated from infra interface.
RouterAdv::RouterAdvMessage mRouterAdvMessage;
TimeMilli mTimeRouterAdvMessageLastUpdate;
bool mLearntRouterAdvMessageFromHost;
TimerMilli mDiscoveredPrefixInvalidTimer;
TimerMilli mDiscoveredPrefixStaleTimer;