[border-router] move RsSender to RxRaTracker (#12015)

This change moves the `RsSender` class from `RoutingManager` to
`RxRaTracker`.

The `RxRaTracker` is responsible for tracking received Router
Advertisements (RAs). Since sending Router Solicitations (RS) is the
mechanism to discover routers and solicit RAs, it is more appropriate
for `RxRaTracker` to own the `RsSender`.

This improves the separation of concerns by centralizing the logic for
both sending RS messages and processing the resulting RAs within the
`RxRaTracker` class. The `RoutingManager` is now decoupled from the
details of the RS transmission process.

The `IsRsTxInProgress()` method is also moved to `RxRaTracker` and its
Doxygen documentation is improved to provide more detail on the RS
transmission process.
This commit is contained in:
Abtin Keshavarzian
2025-10-10 12:58:46 -07:00
committed by GitHub
parent e07ed85620
commit 5180438303
4 changed files with 179 additions and 162 deletions
+1 -118
View File
@@ -69,7 +69,6 @@ RoutingManager::RoutingManager(Instance &aInstance)
#if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
, mPdPrefixManager(aInstance)
#endif
, mRsSender(aInstance)
, mRoutingPolicyTimer(aInstance)
{
mBrUlaPrefix.Clear();
@@ -310,7 +309,6 @@ void RoutingManager::Start(void)
mOnLinkPrefixManager.Start();
mOmrPrefixManager.Start();
mRoutePublisher.Start();
mRsSender.Start();
#if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
mPdPrefixManager.Start();
#endif
@@ -345,8 +343,6 @@ void RoutingManager::Stop(void)
mTxRaInfo.mTxCount = 0;
mRsSender.Stop();
mRoutingPolicyTimer.Stop();
mRoutePublisher.Stop();
@@ -656,21 +652,6 @@ bool RoutingManager::IsValidBrUlaPrefix(const Ip6::Prefix &aBrUlaPrefix)
return aBrUlaPrefix.mLength == kBrUlaPrefixLength && aBrUlaPrefix.mPrefix.mFields.m8[0] == 0xfd;
}
void RoutingManager::HandleRsSenderFinished(TimeMilli aStartTime)
{
// 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.
Get<RxRaTracker>().RemoveOrDeprecateOldEntries(aStartTime);
ScheduleRoutingPolicyEvaluation(kImmediately);
}
void RoutingManager::HandleRouterSolicit(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress)
{
OT_UNUSED_VARIABLE(aPacket);
@@ -1527,7 +1508,7 @@ exit:
void RoutingManager::OnLinkPrefixManager::Evaluate(void)
{
VerifyOrExit(!Get<RoutingManager>().mRsSender.IsInProgress());
VerifyOrExit(!Get<RxRaTracker>().IsRsTxInProgress());
SetAilPrefix(Get<RxRaTracker>().GetFavoredOnLinkPrefix());
@@ -2719,104 +2700,6 @@ void RoutingManager::TxRaInfo::CalculateHash(const RouterAdvert::RxMessage &aRaM
sha256.Finish(aHash);
}
//---------------------------------------------------------------------------------------------------------------------
// RsSender
RoutingManager::RsSender::RsSender(Instance &aInstance)
: InstanceLocator(aInstance)
, mTxCount(0)
, mTimer(aInstance)
{
}
void RoutingManager::RsSender::Start(void)
{
uint32_t delay;
VerifyOrExit(!IsInProgress());
delay = Random::NonCrypto::GetUint32InRange(0, kMaxStartDelay);
LogInfo("RsSender: Starting - will send first RS in %lu msec", ToUlong(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;
RouterSolicitHeader rsHdr;
TxMessage rsMsg;
InfraIf::LinkLayerAddress linkAddr;
InfraIf::Icmp6Packet packet;
Error error;
SuccessOrExit(error = rsMsg.Append(rsHdr));
if (Get<InfraIf>().GetLinkLayerAddress(linkAddr) == kErrorNone)
{
SuccessOrExit(error = rsMsg.AppendLinkLayerOption(linkAddr, Option::kSourceLinkLayerAddr));
}
rsMsg.GetAsPacket(packet);
destAddress.SetToLinkLocalAllRoutersMulticast();
error = Get<RoutingManager>().mInfraIf.Send(packet, destAddress);
if (error == kErrorNone)
{
Get<Ip6::Ip6>().GetBorderRoutingCounters().mRsTxSuccess++;
}
else
{
Get<Ip6::Ip6>().GetBorderRoutingCounters().mRsTxFailure++;
}
exit:
return error;
}
void RoutingManager::RsSender::HandleTimer(void)
{
Error error;
uint32_t delay;
if (mTxCount >= kMaxTxCount)
{
LogInfo("RsSender: Finished sending RS msgs and waiting for RAs");
Get<RoutingManager>().HandleRsSenderFinished(mStartTime);
ExitNow();
}
error = SendRs();
if (error == kErrorNone)
{
mTxCount++;
delay = (mTxCount == kMaxTxCount) ? kWaitOnLastAttempt : kTxInterval;
LogInfo("RsSender: Sent RS %u/%u", mTxCount, kMaxTxCount);
}
else
{
LogCrit("RsSender: Failed to send RS %u/%u: %s", mTxCount + 1, kMaxTxCount, ErrorToString(error));
// Note that `mTxCount` is intentionally not incremented
// if the tx fails.
delay = kRetryDelay;
}
mTimer.Start(delay);
exit:
return;
}
//---------------------------------------------------------------------------------------------------------------------
// PdPrefixManager
@@ -1021,44 +1021,6 @@ private:
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void HandleRsSenderTimer(void) { mRsSender.HandleTimer(); }
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);
void HandleTimer(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);
using RsTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleRsSenderTimer>;
uint8_t mTxCount;
RsTimer mTimer;
TimeMilli mStartTime;
};
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
void HandlePdPrefixManagerTimer(void) { mPdPrefixManager.HandleTimer(); }
@@ -1149,7 +1111,6 @@ private:
void EvaluateRoutingPolicy(void);
bool IsInitialPolicyEvaluationDone(void) const;
void ScheduleRoutingPolicyEvaluation(ScheduleMode aMode);
void HandleRsSenderFinished(TimeMilli aStartTime);
void SendRouterAdvertisement(RouterAdvTxMode aRaTxMode);
void HandleRouterAdvertisement(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress);
@@ -1205,7 +1166,6 @@ private:
#endif
TxRaInfo mTxRaInfo;
RsSender mRsSender;
Heap::Data mExtraRaOptions;
RoutingPolicyTimer mRoutingPolicyTimer;
+123 -3
View File
@@ -48,6 +48,7 @@ RegisterLogModule("BorderRouting");
RxRaTracker::RxRaTracker(Instance &aInstance)
: InstanceLocator(aInstance)
, mRsSender(aInstance)
, mExpirationTimer(aInstance)
, mStaleTimer(aInstance)
, mRouterTimer(aInstance)
@@ -58,7 +59,11 @@ RxRaTracker::RxRaTracker(Instance &aInstance)
mLocalRaHeader.Clear();
}
void RxRaTracker::Start(void) { HandleNetDataChange(); }
void RxRaTracker::Start(void)
{
mRsSender.Start();
HandleNetDataChange();
}
void RxRaTracker::Stop(void)
{
@@ -71,6 +76,23 @@ void RxRaTracker::Stop(void)
mStaleTimer.Stop();
mRouterTimer.Stop();
mRdnssAddrTimer.Stop();
mRsSender.Stop();
}
void RxRaTracker::HandleRsSenderFinished(TimeMilli aStartTime)
{
// 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.
RemoveOrDeprecateOldEntries(aStartTime);
Get<RoutingManager>().ScheduleRoutingPolicyEvaluation(RoutingManager::kImmediately);
}
void RxRaTracker::ProcessRouterAdvertMessage(const RouterAdvert::RxMessage &aRaMessage,
@@ -804,7 +826,7 @@ void RxRaTracker::HandleStaleTimer(void)
VerifyOrExit(Get<RoutingManager>().IsRunning());
LogInfo("Stale timer expired");
Get<RoutingManager>().mRsSender.Start();
mRsSender.Start();
exit:
return;
@@ -894,7 +916,7 @@ void RxRaTracker::SendNeighborSolicitToRouter(const Router &aRouter)
TxMessage nsMsg;
InfraIf::LinkLayerAddress linkAddr;
VerifyOrExit(!Get<RoutingManager>().mRsSender.IsInProgress());
VerifyOrExit(!mRsSender.IsInProgress());
nsHdr.SetTargetAddress(aRouter.mAddress);
SuccessOrExit(nsMsg.Append(nsHdr));
@@ -1448,6 +1470,104 @@ exit:
return;
}
//---------------------------------------------------------------------------------------------------------------------
// RxRaTracker::RsSender
RxRaTracker::RsSender::RsSender(Instance &aInstance)
: InstanceLocator(aInstance)
, mTxCount(0)
, mTimer(aInstance)
{
}
void RxRaTracker::RsSender::Start(void)
{
uint32_t delay;
VerifyOrExit(!IsInProgress());
delay = Random::NonCrypto::GetUint32InRange(0, kMaxStartDelay);
LogInfo("RsSender: Starting - will send first RS in %lu msec", ToUlong(delay));
mTxCount = 0;
mStartTime = TimerMilli::GetNow();
mTimer.Start(delay);
exit:
return;
}
void RxRaTracker::RsSender::Stop(void) { mTimer.Stop(); }
Error RxRaTracker::RsSender::SendRs(void)
{
Ip6::Address destAddress;
RouterSolicitHeader rsHdr;
TxMessage rsMsg;
InfraIf::LinkLayerAddress linkAddr;
InfraIf::Icmp6Packet packet;
Error error;
SuccessOrExit(error = rsMsg.Append(rsHdr));
if (Get<InfraIf>().GetLinkLayerAddress(linkAddr) == kErrorNone)
{
SuccessOrExit(error = rsMsg.AppendLinkLayerOption(linkAddr, Option::kSourceLinkLayerAddr));
}
rsMsg.GetAsPacket(packet);
destAddress.SetToLinkLocalAllRoutersMulticast();
error = Get<RoutingManager>().mInfraIf.Send(packet, destAddress);
if (error == kErrorNone)
{
Get<Ip6::Ip6>().GetBorderRoutingCounters().mRsTxSuccess++;
}
else
{
Get<Ip6::Ip6>().GetBorderRoutingCounters().mRsTxFailure++;
}
exit:
return error;
}
void RxRaTracker::RsSender::HandleTimer(void)
{
Error error;
uint32_t delay;
if (mTxCount >= kMaxTxCount)
{
LogInfo("RsSender: Finished sending RS msgs and waiting for RAs");
Get<RxRaTracker>().HandleRsSenderFinished(mStartTime);
ExitNow();
}
error = SendRs();
if (error == kErrorNone)
{
mTxCount++;
delay = (mTxCount == kMaxTxCount) ? kWaitOnLastAttempt : kTxInterval;
LogInfo("RsSender: Sent RS %u/%u", mTxCount, kMaxTxCount);
}
else
{
LogCrit("RsSender: Failed to send RS %u/%u: %s", mTxCount + 1, kMaxTxCount, ErrorToString(error));
// Note that `mTxCount` is intentionally not incremented
// if the tx fails.
delay = kRetryDelay;
}
mTimer.Start(delay);
exit:
return;
}
} // namespace BorderRouter
} // namespace ot
+55 -1
View File
@@ -103,6 +103,20 @@ public:
*/
void Stop(void);
/**
* Indicates whether the Router Solicitation (RS) transmission process is in progress.
*
* Upon `Start()`, the device performs the RS transmission process to discover routers on the infrastructure
* interface. The device sends three Router Solicitation (RS) messages every four seconds, starting with a random
* delay of up to one second for the first RS transmission. After sending the final RS message, the device waits
* one second before concluding the RS transmission process, at which point `IsRsTxInProgress()` returns `FALSE`.
* The RS transmission process is also performed if the stale timer for any discovered prefix expires.
*
* @retval TRUE If the Router Solicitation transmission process is in progress.
* @retval FALSE If the Router Solicitation transmission process is not in progress.
*/
bool IsRsTxInProgress(void) const { return mRsSender.IsInProgress(); }
/**
* Processes a received Router Advertisement (RA) message.
*
@@ -278,7 +292,6 @@ public:
bool IsAddressReachableThroughExplicitRoute(const Ip6::Address &aAddress) const;
// Callbacks notifying of changes
void RemoveOrDeprecateOldEntries(TimeMilli aTimeThreshold);
void HandleLocalOnLinkPrefixChanged(void);
private:
@@ -482,11 +495,51 @@ private:
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void HandleRsSenderTimer(void) { mRsSender.HandleTimer(); }
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 `RxRaTracker`.
explicit RsSender(Instance &aInstance);
bool IsInProgress(void) const { return mTimer.IsRunning(); }
void Start(void);
void Stop(void);
void HandleTimer(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);
using RsTimer = TimerMilliIn<RxRaTracker, &RxRaTracker::HandleRsSenderTimer>;
uint8_t mTxCount;
RsTimer mTimer;
TimeMilli mStartTime;
};
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void HandleRsSenderFinished(TimeMilli aStartTime);
void ProcessRaHeader(const RouterAdvert::Header &aRaHeader, Router &aRouter, RouterAdvOrigin aRaOrigin);
void ProcessPrefixInfoOption(const PrefixInfoOption &aPio, Router &aRouter);
void ProcessRouteInfoOption(const RouteInfoOption &aRio, Router &aRouter);
void ProcessRecursiveDnsServerOption(const RecursiveDnsServerOption &aRdnss, Router &aRouter);
void UpdateIfAddresses(const Ip6::Address &aAddress);
void RemoveOrDeprecateOldEntries(TimeMilli aTimeThreshold);
void Evaluate(void);
void DetermineStaleTimeFor(const OnLinkPrefix &aPrefix, NextFireTime &aStaleTime);
void DetermineStaleTimeFor(const RoutePrefix &aPrefix, NextFireTime &aStaleTime);
@@ -524,6 +577,7 @@ private:
using IfAddressList = OwningList<Entry<IfAddress>>;
using RdnssCallback = Callback<RdnssAddrCallback>;
RsSender mRsSender;
DecisionFactors mDecisionFactors;
RouterList mRouters;
IfAddressList mIfAddresses;