Skip to content

Commit

Permalink
[routing-manager] simplify state management in PdPrefixManager (ope…
Browse files Browse the repository at this point in the history
…nthread#11250)

This commit simplifies state tracking and updates within
`PdPrefixManager`. Previously, three boolean flags (`mEnabled`,
`mStarted`, and `mPaused`) and a `GetState()` method were used to
represent the state as a `Dhcp6PdState`.

This commit replaces the boolean flags with a single `mState`
variable of type `Dhcp6PdState`.  New `UpdateState()` and `SetState()`
methods handle all state transitions, ensuring PD prefix withdrawal
(OMR prefix removal from Network Data) and state change signaling.
  • Loading branch information
abtink authored Feb 18, 2025
1 parent 2c64402 commit a6432f7
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 69 deletions.
99 changes: 41 additions & 58 deletions src/core/border_router/routing_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3946,9 +3946,7 @@ void RoutingManager::RsSender::HandleTimer(void)

RoutingManager::PdPrefixManager::PdPrefixManager(Instance &aInstance)
: InstanceLocator(aInstance)
, mEnabled(false)
, mIsStarted(false)
, mIsPaused(false)
, mState(kDhcp6PdStateDisabled)
, mNumPlatformPioProcessed(0)
, mNumPlatformRaReceived(0)
, mLastPlatformRaTime(0)
Expand All @@ -3958,83 +3956,68 @@ RoutingManager::PdPrefixManager::PdPrefixManager(Instance &aInstance)

void RoutingManager::PdPrefixManager::SetEnabled(bool aEnabled)
{
State oldState = GetState();

VerifyOrExit(mEnabled != aEnabled);
mEnabled = aEnabled;
EvaluateStateChange(oldState);

exit:
return;
}

void RoutingManager::PdPrefixManager::StartStop(bool aStart)
{
State oldState = GetState();

VerifyOrExit(aStart != mIsStarted);
mIsStarted = aStart;
EvaluateStateChange(oldState);
if (aEnabled)
{
VerifyOrExit(mState == kDhcp6PdStateDisabled);
UpdateState();
}
else
{
SetState(kDhcp6PdStateDisabled);
}

exit:
return;
}

void RoutingManager::PdPrefixManager::PauseResume(bool aPause)
void RoutingManager::PdPrefixManager::Evaluate(void)
{
State oldState = GetState();

VerifyOrExit(aPause != mIsPaused);
mIsPaused = aPause;
EvaluateStateChange(oldState);
VerifyOrExit(mState != kDhcp6PdStateDisabled);
UpdateState();

exit:
return;
}

RoutingManager::PdPrefixManager::State RoutingManager::PdPrefixManager::GetState(void) const
void RoutingManager::PdPrefixManager::UpdateState(void)
{
State state = kDhcp6PdStateDisabled;

if (mEnabled)
if (!Get<RoutingManager>().IsRunning())
{
state = mIsStarted ? (mIsPaused ? kDhcp6PdStateIdle : kDhcp6PdStateRunning) : kDhcp6PdStateStopped;
SetState(kDhcp6PdStateStopped);
}
else
{
const FavoredOmrPrefix &favoredOmrPrefix = Get<RoutingManager>().mOmrPrefixManager.GetFavoredPrefix();

return state;
}

void RoutingManager::PdPrefixManager::Evaluate(void)
{
const FavoredOmrPrefix &favoredPrefix = Get<RoutingManager>().mOmrPrefixManager.GetFavoredPrefix();
bool shouldPause = favoredPrefix.IsInfrastructureDerived() && (favoredPrefix.GetPrefix() != mPrefix.GetPrefix());
// We request a PD prefix (enter `kDhcp6PdStateRunning`),
// unless we see a favored infrastructure-derived OMR prefix
// which differs from our prefix. In this case, we can
// withdraw our prefix and enter `kDhcp6PdStateIdle`.

PauseResume(/* aPause */ shouldPause);
if (favoredOmrPrefix.IsInfrastructureDerived() && (favoredOmrPrefix.GetPrefix() != mPrefix.GetPrefix()))
{
SetState(kDhcp6PdStateIdle);
}
else
{
SetState(kDhcp6PdStateRunning);
}
}
}

void RoutingManager::PdPrefixManager::EvaluateStateChange(Dhcp6PdState aOldState)
void RoutingManager::PdPrefixManager::SetState(State aState)
{
State newState = GetState();
VerifyOrExit(aState != mState);

VerifyOrExit(aOldState != newState);
LogInfo("PdPrefixManager: %s -> %s", StateToString(aOldState), StateToString(newState));
LogInfo("PdPrefixManager: %s -> %s", StateToString(mState), StateToString(aState));
mState = aState;

switch (newState)
if (mState != kDhcp6PdStateRunning)
{
case kDhcp6PdStateDisabled:
case kDhcp6PdStateStopped:
case kDhcp6PdStateIdle:
WithdrawPrefix();
break;
case kDhcp6PdStateRunning:
break;
}

// When the prefix is replaced, there will be a short period when the old prefix is still in the netdata, and PD
// manager will refuse to request the prefix.
// TODO: Either update the comment for the state callback or add a random delay when notifing the upper layer for
// state change.
mStateCallback.InvokeIfSet(MapEnum(newState));
mStateCallback.InvokeIfSet(MapEnum(mState));

exit:
return;
Expand All @@ -4044,7 +4027,7 @@ Error RoutingManager::PdPrefixManager::GetPrefixInfo(PrefixTableEntry &aInfo) co
{
Error error = kErrorNone;

VerifyOrExit(IsRunning() && HasPrefix(), error = kErrorNotFound);
VerifyOrExit(HasPrefix(), error = kErrorNotFound);

aInfo.mPrefix = mPrefix.GetPrefix();
aInfo.mValidLifetime = mPrefix.GetValidLifetime();
Expand All @@ -4059,7 +4042,7 @@ Error RoutingManager::PdPrefixManager::GetProcessedRaInfo(PdProcessedRaInfo &aPd
{
Error error = kErrorNone;

VerifyOrExit(IsRunning() && HasPrefix(), error = kErrorNotFound);
VerifyOrExit(HasPrefix(), error = kErrorNotFound);

aPdProcessedRaInfo.mNumPlatformRaReceived = mNumPlatformRaReceived;
aPdProcessedRaInfo.mNumPlatformPioProcessed = mNumPlatformPioProcessed;
Expand Down Expand Up @@ -4119,7 +4102,7 @@ void RoutingManager::PdPrefixManager::Process(const InfraIf::Icmp6Packet *aRaPac
PdPrefix favoredPrefix;
PdPrefix prefix;

VerifyOrExit(mEnabled, error = kErrorInvalidState);
VerifyOrExit(mState != kDhcp6PdStateDisabled, error = kErrorInvalidState);

if (aRaPacket != nullptr)
{
Expand Down
17 changes: 6 additions & 11 deletions src/core/border_router/routing_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1471,12 +1471,11 @@ class RoutingManager : public InstanceLocator
explicit PdPrefixManager(Instance &aInstance);

void SetEnabled(bool aEnabled);
void Start(void) { StartStop(/* aStart= */ true); }
void Stop(void) { StartStop(/* aStart= */ false); }
bool IsRunning(void) const { return GetState() == kDhcp6PdStateRunning; }
void Start(void) { Evaluate(); }
void Stop(void) { Evaluate(); }
bool HasPrefix(void) const { return !mPrefix.IsEmpty(); }
const Ip6::Prefix &GetPrefix(void) const { return mPrefix.GetPrefix(); }
State GetState(void) const;
State GetState(void) const { return mState; }

void ProcessRa(const uint8_t *aRouterAdvert, uint16_t aLength);
void ProcessPrefix(const PrefixTableEntry &aPrefixTableEntry);
Expand All @@ -1496,22 +1495,18 @@ class RoutingManager : public InstanceLocator
bool IsFavoredOver(const PdPrefix &aOther) const;
};

void UpdateState(void);
void SetState(State aState);
void Process(const InfraIf::Icmp6Packet *aRaPacket, const PrefixTableEntry *aPrefixTableEntry);
void ProcessPdPrefix(PdPrefix &aPrefix, PdPrefix &aFavoredPrefix);
void EvaluateStateChange(State aOldState);
void WithdrawPrefix(void);
void StartStop(bool aStart);
void PauseResume(bool aPause);

static const char *StateToString(State aState);

using PrefixTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandlePdPrefixManagerTimer>;
using StateCallback = Callback<PdCallback>;

bool mEnabled; // Whether PdPrefixManager is enabled. (guards the overall PdPrefixManager functions)
bool mIsStarted; // Whether PdPrefixManager is started. (monitoring prefixes)
bool mIsPaused; // Whether PdPrefixManager is paused. (when there is another BR advertising another prefix)

State mState;
uint32_t mNumPlatformPioProcessed;
uint32_t mNumPlatformRaReceived;
TimeMilli mLastPlatformRaTime;
Expand Down

0 comments on commit a6432f7

Please sign in to comment.