[bbr] introduce BackboneRouter::Config core class (#13108)

This commit introduces a new core class `BackboneRouter::Config` that
inherits from the public `otBackboneRouterConfig` struct. This aligns
with the OpenThread architectural pattern of using core-internal
classes to wrap public API structures, providing a cleaner interface
and encapsulating logic.

Importantly, this commit ensures that the `MlrTimeout` is adjusted
and clamped to valid ranges before comparing the new configuration
with the existing one. This ensures that the state transition
(e.g., `kStateRefreshed`) correctly reflects the actual values
that will be used.

Other improvements:
- Added helper methods `IsPresent()`, `MarkAsAbsent()`, and getters
  for configuration fields.
- Moved `MlrTimeout` adjustment logic into `Config::AdjustMlrTimeout()`.
- Added `Config::Log()` to log configuration details, and updated
  `Leader` to log both old and new configurations when a Primary
  Backbone Router event occurs.
This commit is contained in:
Abtin Keshavarzian
2026-05-18 13:01:02 -07:00
committed by GitHub
parent 5c5c100fee
commit 56010e2f65
5 changed files with 127 additions and 48 deletions
+1 -1
View File
@@ -46,7 +46,7 @@ otError otBackboneRouterGetPrimary(otInstance *aInstance, otBackboneRouterConfig
{
AssertPointerIsNotNull(aConfig);
return AsCoreType(aInstance).Get<BackboneRouter::Leader>().GetConfig(*aConfig);
return AsCoreType(aInstance).Get<BackboneRouter::Leader>().GetConfig(AsCoreType(aConfig));
}
#endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
+2 -2
View File
@@ -57,14 +57,14 @@ void otBackboneRouterGetConfig(otInstance *aInstance, otBackboneRouterConfig *aC
{
AssertPointerIsNotNull(aConfig);
AsCoreType(aInstance).Get<BackboneRouter::Local>().GetConfig(*aConfig);
AsCoreType(aInstance).Get<BackboneRouter::Local>().GetConfig(AsCoreType(aConfig));
}
otError otBackboneRouterSetConfig(otInstance *aInstance, const otBackboneRouterConfig *aConfig)
{
AssertPointerIsNotNull(aConfig);
return AsCoreType(aInstance).Get<BackboneRouter::Local>().SetConfig(*aConfig);
return AsCoreType(aInstance).Get<BackboneRouter::Local>().SetConfig(AsCoreType(aConfig));
}
otError otBackboneRouterRegister(otInstance *aInstance)
+57 -38
View File
@@ -42,6 +42,43 @@ namespace BackboneRouter {
RegisterLogModule("BbrLeader");
//---------------------------------------------------------------------------------------------------------------------
// Config
void Config::AdjustMlrTimeout(void)
{
uint32_t origTimeout;
VerifyOrExit(IsPresent());
origTimeout = GetMlrTimeout();
mMlrTimeout = Clamp(mMlrTimeout, kMinMlrTimeout, kMaxMlrTimeout);
VerifyOrExit(mMlrTimeout != origTimeout);
LogNote("MLR timeout adjusted: %lu -> %lu", ToUlong(origTimeout), ToUlong(mMlrTimeout));
exit:
return;
}
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
void Config::Log(const char *aTitle) const
{
if (IsPresent())
{
LogInfo(" %s: 0x%04x seqno:%u delay:%u timeout:%lu", aTitle, mServer16, mSequenceNumber, mReregistrationDelay,
ToUlong(mMlrTimeout));
}
else
{
LogInfo(" %s: none", aTitle);
}
}
#endif
//---------------------------------------------------------------------------------------------------------------------
// Leader
Leader::Leader(Instance &aInstance)
: InstanceLocator(aInstance)
{
@@ -50,8 +87,7 @@ Leader::Leader(Instance &aInstance)
void Leader::Reset(void)
{
// Invalid server short address indicates no available Backbone Router service in the Thread Network.
mConfig.mServer16 = Mle::kInvalidRloc16;
mConfig.MarkAsAbsent();
// Domain Prefix Length 0 indicates no available Domain Prefix in the Thread network.
mDomainPrefix.SetLength(0);
@@ -82,19 +118,6 @@ exit:
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
void Leader::LogBackboneRouterPrimary(State aState, const Config &aConfig) const
{
OT_UNUSED_VARIABLE(aConfig);
LogInfo("PBBR state: %s", StateToString(aState));
if (aState != kStateRemoved && aState != kStateNone)
{
LogInfo("Rloc16:0x%4x, seqno:%u, delay:%u, timeout:%lu", aConfig.mServer16, aConfig.mSequenceNumber,
aConfig.mReregistrationDelay, ToUlong(aConfig.mMlrTimeout));
}
}
const char *Leader::StateToString(State aState)
{
#define StateMapList(_) \
@@ -135,18 +158,20 @@ void Leader::HandleNotifierEvents(Events aEvents)
void Leader::UpdateBackboneRouterPrimary(void)
{
Config config;
Config newConfig;
State state;
Get<NetworkData::Service::Manager>().GetBackboneRouterPrimary(config);
Get<NetworkData::Service::Manager>().GetBackboneRouterPrimary(newConfig);
if (config.mServer16 != mConfig.mServer16)
newConfig.AdjustMlrTimeout();
if (newConfig.GetServer16() != mConfig.GetServer16())
{
if (config.mServer16 == Mle::kInvalidRloc16)
if (!newConfig.IsPresent())
{
state = kStateRemoved;
}
else if (mConfig.mServer16 == Mle::kInvalidRloc16)
else if (!mConfig.IsPresent())
{
state = kStateAdded;
}
@@ -156,16 +181,17 @@ void Leader::UpdateBackboneRouterPrimary(void)
state = kStateToTriggerRereg;
}
}
else if (config.mServer16 == Mle::kInvalidRloc16)
else if (!newConfig.IsPresent())
{
// If no Primary all the time.
state = kStateNone;
}
else if (config.mSequenceNumber != mConfig.mSequenceNumber)
else if (newConfig.GetSequenceNumber() != mConfig.GetSequenceNumber())
{
state = kStateToTriggerRereg;
}
else if (config.mReregistrationDelay != mConfig.mReregistrationDelay || config.mMlrTimeout != mConfig.mMlrTimeout)
else if (newConfig.GetReregistrationDelay() != mConfig.GetReregistrationDelay() ||
newConfig.GetMlrTimeout() != mConfig.GetMlrTimeout())
{
state = kStateRefreshed;
}
@@ -174,22 +200,13 @@ void Leader::UpdateBackboneRouterPrimary(void)
state = kStateUnchanged;
}
// Restrain the range of MLR timeout to be always valid
if (config.mServer16 != Mle::kInvalidRloc16)
{
uint32_t origTimeout = config.mMlrTimeout;
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
LogInfo("PBBR event: %s", StateToString(state));
mConfig.Log("Old");
newConfig.Log("New");
#endif
config.mMlrTimeout = Clamp(config.mMlrTimeout, kMinMlrTimeout, kMaxMlrTimeout);
if (config.mMlrTimeout != origTimeout)
{
LogNote("Leader MLR Timeout is normalized from %lu to %lu", ToUlong(origTimeout),
ToUlong(config.mMlrTimeout));
}
}
mConfig = config;
LogBackboneRouterPrimary(state, mConfig);
mConfig = newConfig;
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
Get<BackboneRouter::Local>().HandleBackboneRouterPrimaryUpdate(state, mConfig);
@@ -202,6 +219,8 @@ void Leader::UpdateBackboneRouterPrimary(void)
#if OPENTHREAD_CONFIG_DUA_ENABLE || (OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE)
Get<DuaManager>().HandleBackboneRouterPrimaryUpdate(state, mConfig);
#endif
OT_UNUSED_VARIABLE(state);
}
void Leader::UpdateDomainPrefixConfig(void)
+66 -6
View File
@@ -48,14 +48,13 @@
#include "common/log.hpp"
#include "common/non_copyable.hpp"
#include "common/notifier.hpp"
#include "common/string.hpp"
#include "net/ip6_address.hpp"
namespace ot {
namespace BackboneRouter {
typedef otBackboneRouterConfig Config;
constexpr uint16_t kDefaultRegistrationDelay = 5; ///< Default registration delay (in sec).
constexpr uint32_t kDefaultMlrTimeout = 3600; ///< Default MLR Timeout (in sec).
constexpr uint32_t kMinMlrTimeout = 300; ///< Minimum MLR Timeout (in sec).
@@ -78,6 +77,69 @@ enum DomainPrefixEvent : uint8_t
kDomainPrefixRefreshed = OT_BACKBONE_ROUTER_DOMAIN_PREFIX_CHANGED, ///< Domain Prefix Changed.
};
class Leader;
/**
* Represents a Backbone Router configuration.
*/
class Config : public otBackboneRouterConfig
{
friend class Leader;
public:
/**
* Marks the configuration as absent.
*
* This is done by setting the Primary Backbone Router short address (`GetServer16()`) to `Mle::kInvalidRloc16`.
*/
void MarkAsAbsent(void) { mServer16 = Mle::kInvalidRloc16; }
/**
* Indicates whether the configuration is present (i.e., it is derived from a Primary Backbone Router).
*
* The presence state is tracked using the Primary Backbone Router short address (`GetServer16()`).
*
* @retval TRUE The configuration is present.
* @retval FALSE The configuration is not present.
*/
bool IsPresent(void) const { return mServer16 != Mle::kInvalidRloc16; }
/**
* Gets the Primary Backbone Router short address.
*
* @returns The Primary Backbone Router short address, or `Mle::kInvalidRloc16` if not present.
*/
uint16_t GetServer16(void) const { return mServer16; }
/**
* Gets the Reregistration Delay value.
*
* @returns The Reregistration Delay value (in seconds).
*/
uint16_t GetReregistrationDelay(void) const { return mReregistrationDelay; }
/**
* Gets the Multicast Listener Registration (MLR) Timeout value.
*
* @returns The MLR Timeout value (in seconds).
*/
uint32_t GetMlrTimeout(void) const { return mMlrTimeout; }
/**
* Gets the Sequence Number.
*
* @returns The Sequence Number.
*/
uint8_t GetSequenceNumber(void) const { return mSequenceNumber; }
private:
void AdjustMlrTimeout(void);
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
void Log(const char *aTitle) const;
#endif
};
/**
* Implements the basic Primary Backbone Router service operations.
*/
@@ -143,7 +205,7 @@ public:
* @retval TRUE If there is Primary Backbone Router.
* @retval FALSE If there is no Primary Backbone Router.
*/
bool HasPrimary(void) const { return mConfig.mServer16 != Mle::kInvalidRloc16; }
bool HasPrimary(void) const { return mConfig.IsPresent(); }
/**
* Gets the Domain Prefix in the Thread Network.
@@ -175,11 +237,8 @@ private:
void UpdateBackboneRouterPrimary(void);
void UpdateDomainPrefixConfig(void);
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
void LogBackboneRouterPrimary(State aState, const Config &aConfig) const;
static const char *StateToString(State aState);
static const char *DomainPrefixEventToString(DomainPrefixEvent aEvent);
#else
void LogBackboneRouterPrimary(State, const Config &) const {}
#endif
Config mConfig;
@@ -189,6 +248,7 @@ private:
} // namespace BackboneRouter
DefineMapEnum(otBackboneRouterDomainPrefixEvent, BackboneRouter::DomainPrefixEvent);
DefineCoreType(otBackboneRouterConfig, BackboneRouter::Config);
} // namespace ot
+1 -1
View File
@@ -382,7 +382,7 @@ void Manager::GetBackboneRouterPrimary(ot::BackboneRouter::Config &aConfig) cons
serviceData.InitFrom(bbrServiceNumber);
aConfig.mServer16 = Mle::kInvalidRloc16;
aConfig.MarkAsAbsent();
while ((serviceTlv = Get<Leader>().FindNextThreadService(serviceTlv, serviceData,
NetworkData::kServicePrefixMatch)) != nullptr)