[routing-manager] add RsSender nested class (#8124)

This commit adds `RsSender` class in `RoutingManager` which contains
the logic related to the transmission of Router Solicitation
(RS) messages to discover other routers. This class encapsulates all
variables, constants, and methods related to the RS transmission
mechanism(number of RS messages in a cycle, time intervals, etc).
This commit is contained in:
Abtin Keshavarzian
2022-09-12 13:00:48 -07:00
committed by GitHub
parent 865727adc8
commit 1861291a62
2 changed files with 138 additions and 115 deletions
+101 -96
View File
@@ -74,9 +74,8 @@ RoutingManager::RoutingManager(Instance &aInstance)
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
, mInfraIfNat64PrefixStaleTimer(aInstance, HandleInfraIfNat64PrefixStaleTimer)
#endif
, mRsSender(aInstance)
, mDiscoveredPrefixStaleTimer(aInstance, HandleDiscoveredPrefixStaleTimer)
, mRouterSolicitTimer(aInstance, HandleRouterSolicitTimer)
, mRouterSolicitCount(0)
, mRoutingPolicyTimer(aInstance, HandleRoutingPolicyTimer)
{
mFavoredDiscoveredOnLinkPrefix.Clear();
@@ -296,7 +295,7 @@ void RoutingManager::Start(void)
mIsRunning = true;
UpdateDiscoveredPrefixTableOnNetDataChange();
mLocalOnLinkPrefix.Start();
StartRouterSolicitationDelay();
mRsSender.Start();
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
mInfraIfNat64PrefixStaleTimer.Start(0);
#endif
@@ -332,8 +331,7 @@ void RoutingManager::Stop(void)
mRaInfo.mTxCount = 0;
mRouterSolicitTimer.Stop();
mRouterSolicitCount = 0;
mRsSender.Stop();
mRoutingPolicyTimer.Stop();
@@ -521,7 +519,7 @@ exit:
void RoutingManager::EvaluateOnLinkPrefix(void)
{
VerifyOrExit(!IsRouterSolicitationInProgress());
VerifyOrExit(!mRsSender.IsInProgress());
mDiscoveredPrefixTable.FindFavoredOnLinkPrefix(mFavoredDiscoveredOnLinkPrefix);
@@ -675,46 +673,6 @@ void RoutingManager::ScheduleRoutingPolicyEvaluation(ScheduleMode aMode)
mRoutingPolicyTimer.FireAtIfEarlier(evaluateTime);
}
// starts sending Router Solicitations in random delay
// between 0 and kMaxRtrSolicitationDelay.
void RoutingManager::StartRouterSolicitationDelay(void)
{
uint32_t randomDelay;
VerifyOrExit(!IsRouterSolicitationInProgress());
OT_ASSERT(mRouterSolicitCount == 0);
static_assert(kMaxRtrSolicitationDelay > 0, "invalid maximum Router Solicitation delay");
randomDelay = Random::NonCrypto::GetUint32InRange(0, Time::SecToMsec(kMaxRtrSolicitationDelay));
LogInfo("Start Router Solicitation, scheduled in %u milliseconds", randomDelay);
mTimeRouterSolicitStart = TimerMilli::GetNow();
mRouterSolicitTimer.Start(randomDelay);
exit:
return;
}
bool RoutingManager::IsRouterSolicitationInProgress(void) const
{
return mRouterSolicitTimer.IsRunning() || mRouterSolicitCount > 0;
}
Error RoutingManager::SendRouterSolicitation(void)
{
Ip6::Address destAddress;
Ip6::Nd::RouterSolicitMessage routerSolicit;
InfraIf::Icmp6Packet packet;
OT_ASSERT(IsInitialized());
packet.InitFrom(routerSolicit);
destAddress.SetToLinkLocalAllRoutersMulticast();
return mInfraIf.Send(packet, destAddress);
}
void RoutingManager::SendRouterAdvertisement(RouterAdvTxMode aRaTxMode)
{
// RA message max length is derived to accommodate:
@@ -973,61 +931,25 @@ bool RoutingManager::IsValidOnLinkPrefix(const Ip6::Prefix &aOnLinkPrefix)
!aOnLinkPrefix.IsMulticast();
}
void RoutingManager::HandleRouterSolicitTimer(Timer &aTimer)
void RoutingManager::HandleRsSenderFinished(TimeMilli aStartTime)
{
aTimer.Get<RoutingManager>().HandleRouterSolicitTimer();
}
// This is a callback from `RsSender` and is invoked when it
// finishes a cycle of sending Router Solicitations. `aStartTime`
// specifies the start time of the RS transmission cycle.
//
// We remove or deprecate old entries in discovered table that are
// not refreshed during Router Solicitation. We also invalidate
// the learned RA header if it is not refreshed during Router
// Solicitation.
void RoutingManager::HandleRouterSolicitTimer(void)
{
LogInfo("Router solicitation times out");
mDiscoveredPrefixTable.RemoveOrDeprecateOldEntries(aStartTime);
if (mRouterSolicitCount < kMaxRtrSolicitations)
if (mRaInfo.mHeaderUpdateTime <= aStartTime)
{
uint32_t nextSolicitationDelay;
Error error;
error = SendRouterSolicitation();
if (error == kErrorNone)
{
LogDebg("Successfully sent %uth Router Solicitation", mRouterSolicitCount);
++mRouterSolicitCount;
nextSolicitationDelay =
(mRouterSolicitCount == kMaxRtrSolicitations) ? kMaxRtrSolicitationDelay : kRtrSolicitationInterval;
}
else
{
LogCrit("Failed to send %uth Router Solicitation: %s", mRouterSolicitCount, ErrorToString(error));
// It's unexpected that RS will fail and we will retry sending RS messages in 60 seconds.
// Notice that `mRouterSolicitCount` is not incremented for failed RS and thus we will
// not start configuring on-link prefixes before `kMaxRtrSolicitations` successful RS
// messages have been sent.
nextSolicitationDelay = kRtrSolicitationRetryDelay;
mRouterSolicitCount = 0;
}
LogDebg("Router solicitation timer scheduled in %u seconds", nextSolicitationDelay);
mRouterSolicitTimer.Start(Time::SecToMsec(nextSolicitationDelay));
UpdateRouterAdvertHeader(/* aRouterAdvertMessage */ nullptr);
}
else
{
// Remove route prefixes and deprecate on-link prefixes that
// are not refreshed during Router Solicitation.
mDiscoveredPrefixTable.RemoveOrDeprecateOldEntries(mTimeRouterSolicitStart);
// Invalidate the learned RA message if it is not refreshed during Router Solicitation.
if (mRaInfo.mHeaderUpdateTime <= mTimeRouterSolicitStart)
{
UpdateRouterAdvertHeader(/* aRouterAdvertMessage */ nullptr);
}
mRouterSolicitCount = 0;
// Re-evaluate our routing policy and send Router Advertisement if necessary.
ScheduleRoutingPolicyEvaluation(kImmediately);
}
ScheduleRoutingPolicyEvaluation(kImmediately);
}
void RoutingManager::HandleDiscoveredPrefixStaleTimer(Timer &aTimer)
@@ -1038,7 +960,7 @@ void RoutingManager::HandleDiscoveredPrefixStaleTimer(Timer &aTimer)
void RoutingManager::HandleDiscoveredPrefixStaleTimer(void)
{
LogInfo("Stale On-Link or OMR Prefixes or RA messages are detected");
StartRouterSolicitationDelay();
mRsSender.Start();
}
void RoutingManager::HandleRoutingPolicyTimer(Timer &aTimer)
@@ -2312,6 +2234,89 @@ void RoutingManager::OnMeshPrefixArray::MarkAsDeleted(const OnMeshPrefix &aPrefi
}
}
//---------------------------------------------------------------------------------------------------------------------
// RsSender
RoutingManager::RsSender::RsSender(Instance &aInstance)
: InstanceLocator(aInstance)
, mTxCount(0)
, mTimer(aInstance, HandleTimer)
{
}
void RoutingManager::RsSender::Start(void)
{
uint32_t delay;
VerifyOrExit(!IsInProgress());
delay = Random::NonCrypto::GetUint32InRange(0, kMaxStartDelay);
LogInfo("Scheduled Router Solicitation in %u milliseconds", delay);
mTxCount = 0;
mStartTime = TimerMilli::GetNow();
mTimer.Start(delay);
exit:
return;
}
void RoutingManager::RsSender::Stop(void)
{
mTimer.Stop();
}
Error RoutingManager::RsSender::SendRs(void)
{
Ip6::Address destAddress;
Ip6::Nd::RouterSolicitMessage routerSolicit;
InfraIf::Icmp6Packet packet;
packet.InitFrom(routerSolicit);
destAddress.SetToLinkLocalAllRoutersMulticast();
return Get<RoutingManager>().mInfraIf.Send(packet, destAddress);
}
void RoutingManager::RsSender::HandleTimer(Timer &aTimer)
{
aTimer.Get<RoutingManager>().mRsSender.HandleTimer();
}
void RoutingManager::RsSender::HandleTimer(void)
{
Error error;
uint32_t delay;
if (mTxCount >= kMaxTxCount)
{
Get<RoutingManager>().HandleRsSenderFinished(mStartTime);
ExitNow();
}
error = SendRs();
if (error == kErrorNone)
{
mTxCount++;
LogInfo("Successfully sent RS %d/%d", mTxCount, kMaxTxCount);
delay = (mTxCount == kMaxTxCount) ? kWaitOnLastAttempt : kTxInterval;
}
else
{
LogCrit("Failed to send RS %d, error:%s", mTxCount + 1, ErrorToString(error));
// Note that `mTxCount` is intentionally not incremented
// if the tx fails.
delay = kRetryDelay;
}
mTimer.Start(delay);
exit:
return;
}
} // namespace BorderRouter
} // namespace ot
+37 -19
View File
@@ -322,9 +322,6 @@ private:
// The maximum number of initial Router Advertisements.
static constexpr uint32_t kMaxInitRtrAdvertisements = 3;
// The maximum number of Router Solicitations before sending Router Advertisements.
static constexpr uint32_t kMaxRtrSolicitations = 3;
static constexpr uint32_t kDefaultOmrPrefixLifetime = 1800; // The default OMR prefix valid lifetime. In sec.
static constexpr uint32_t kDefaultOnLinkPrefixLifetime = 1800; // The default on-link prefix valid lifetime. In sec.
static constexpr uint32_t kDefaultNat64PrefixLifetime = 300; // The default NAT64 prefix valid lifetime. In sec.
@@ -332,13 +329,9 @@ private:
static constexpr uint32_t kMinRtrAdvInterval = kMaxRtrAdvInterval / 3; // Min RA Interval. In sec.
static constexpr uint32_t kMaxInitRtrAdvInterval = 16; // Max Initial RA Interval. In sec.
static constexpr uint32_t kRaReplyJitter = 500; // Jitter for sending RA after rx RS. In msec.
static constexpr uint32_t kRtrSolicitationInterval = 4; // Interval between RSs. In sec.
static constexpr uint32_t kMaxRtrSolicitationDelay = 1; // Max delay for initial solicitation. In sec.
static constexpr uint32_t kPolicyEvaluationMinDelay = 2000; // Min delay for policy evaluation. In msec.
static constexpr uint32_t kPolicyEvaluationMaxDelay = 4000; // Max delay for policy evaluation. In msec.
static constexpr uint32_t kRtrSolicitationRetryDelay =
kRtrSolicitationInterval; // The delay before retrying failed RS tx. In Sec.
static constexpr uint32_t kMinDelayBetweenRtrAdvs = 3000; // Min delay (msec) between consecutive RAs.
static constexpr uint32_t kMinDelayBetweenRtrAdvs = 3000; // Min delay (msec) between consecutive RAs.
// The STALE_RA_TIME in seconds. The Routing Manager will consider the prefixes
// and learned RA parameters STALE when they are not refreshed in STALE_RA_TIME
@@ -651,6 +644,39 @@ private:
TimeMilli mLastTxTime;
};
class RsSender : public InstanceLocator
{
public:
// This class implements tx of Router Solicitation (RS)
// messages to discover other routers. `Start()` schedules
// a cycle of RS transmissions of `kMaxTxCount` separated
// by `kTxInterval`. At the end of cycle the callback
// `HandleRsSenderFinished()` is invoked to inform end of
// the cycle to `RoutingManager`.
explicit RsSender(Instance &aInstance);
bool IsInProgress(void) const { return mTimer.IsRunning(); }
void Start(void);
void Stop(void);
private:
// All time intervals are in msec.
static constexpr uint32_t kMaxStartDelay = 1000; // Max random delay to send the first RS.
static constexpr uint32_t kTxInterval = 4000; // Interval between RS tx.
static constexpr uint32_t kRetryDelay = kTxInterval; // Interval to wait to retry a failed RS tx.
static constexpr uint32_t kWaitOnLastAttempt = 1000; // Wait interval after last RS tx.
static constexpr uint8_t kMaxTxCount = 3; // Number of RS tx in one cycle.
Error SendRs(void);
static void HandleTimer(Timer &aTimer);
void HandleTimer(void);
uint8_t mTxCount;
TimerMilli mTimer;
TimeMilli mStartTime;
};
void EvaluateState(void);
void Start(void);
void Stop(void);
@@ -672,13 +698,9 @@ private:
void EvaluateOmrPrefix(void);
Error PublishExternalRoute(const Ip6::Prefix &aPrefix, RoutePreference aRoutePreference, bool aNat64 = false);
void UnpublishExternalRoute(const Ip6::Prefix &aPrefix);
void StartRouterSolicitationDelay(void);
Error SendRouterSolicitation(void);
void HandleRsSenderFinished(TimeMilli aStartTime);
void SendRouterAdvertisement(RouterAdvTxMode aRaTxMode);
bool IsRouterSolicitationInProgress(void) const;
static void HandleRouterSolicitTimer(Timer &aTimer);
void HandleRouterSolicitTimer(void);
static void HandleDiscoveredPrefixInvalidTimer(Timer &aTimer);
void HandleDiscoveredPrefixInvalidTimer(void);
static void HandleDiscoveredPrefixStaleTimer(Timer &aTimer);
@@ -748,14 +770,10 @@ private:
TimerMilli mInfraIfNat64PrefixStaleTimer;
#endif
RaInfo mRaInfo;
RaInfo mRaInfo;
RsSender mRsSender;
TimerMilli mDiscoveredPrefixStaleTimer;
TimerMilli mRouterSolicitTimer;
TimeMilli mTimeRouterSolicitStart;
uint8_t mRouterSolicitCount;
TimerMilli mRoutingPolicyTimer;
};