From eac46963bb66bc46542a6776ae3c0dd2134eb8e5 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Thu, 28 May 2026 07:25:40 -0700 Subject: [PATCH] [mlr] simplify MLR state tracking on `Child` (#13166) This commit simplifies MLR state tracking for child devices. Previously, `Child::Ip6AddrEntry` inherited from `Ip6::Address` to encapsulate the MLR registration check using the `Child` reference. This introduced tight coupling between `Child` and `Ip6AddrEntry`. The logic is refactored by removing `Ip6AddrEntry`. Instead, `Child` now directly manages a `Child::Ip6AddressArray` and encapsulates the MLR state querying/updating through new methods: - `SetAddressMlrRegistrationState()` - `GetAllMlrRegisteredAddresses()` - `ClearAllAddressesMlrRegistrationState()` In `Mlr::Manager`, the redundant `ChildAddressArray` typedef and `kMaxChildAddresses` constant are removed, reusing the `Child::Ip6AddressArray`. The method `UpdateProxiedSubscriptions()` is renamed to the more intuitive `UpdateChildRegistrations()`, and overloaded to allow calling it without an old address list during initial child registration. --- src/core/thread/child.cpp | 54 +++++++++++--------- src/core/thread/child.hpp | 89 ++++++++++----------------------- src/core/thread/mle_ftd.cpp | 17 ++----- src/core/thread/mlr_manager.cpp | 37 ++++++++------ src/core/thread/mlr_manager.hpp | 17 ++++--- 5 files changed, 94 insertions(+), 120 deletions(-) diff --git a/src/core/thread/child.cpp b/src/core/thread/child.cpp index a3e049e1b..e6db7e416 100644 --- a/src/core/thread/child.cpp +++ b/src/core/thread/child.cpp @@ -71,24 +71,6 @@ void Child::Info::SetFrom(const Child &aChild) mConnectionTime = aChild.GetConnectionTime(); } -//--------------------------------------------------------------------------------------------------------------------- -// Child::Ip6AddrEntry - -#if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE - -bool Child::Ip6AddrEntry::IsMlrRegistered(const Child &aChild) const -{ - return aChild.mMlrRegisteredSet.Has(aChild.mIp6Addresses.IndexOf(*this)); -} - -// NOLINTNEXTLINE(readability-make-member-function-const) -void Child::Ip6AddrEntry::SetMlrRegistered(bool aRegistered, Child &aChild) -{ - aChild.mMlrRegisteredSet.Update(aChild.mIp6Addresses.IndexOf(*this), aRegistered); -} - -#endif // OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE - //--------------------------------------------------------------------------------------------------------------------- // Child @@ -182,7 +164,7 @@ Error Child::AddIp6Address(const Ip6::Address &aAddress) } VerifyOrExit(!mIp6Addresses.ContainsMatching(aAddress), error = kErrorAlready); - error = mIp6Addresses.PushBack(static_cast(aAddress)); + error = mIp6Addresses.PushBack(aAddress); exit: return error; @@ -191,7 +173,7 @@ exit: Error Child::RemoveIp6Address(const Ip6::Address &aAddress) { Error error = kErrorNotFound; - Ip6AddrEntry *entry; + Ip6::Address *entry; if (Get().IsMeshLocalAddress(aAddress)) { @@ -271,18 +253,44 @@ exit: bool Child::HasMlrRegisteredAddress(const Ip6::Address &aAddress) const { bool hasAddress = false; - const Ip6AddrEntry *entry; + const Ip6::Address *entry; entry = mIp6Addresses.FindMatching(aAddress); VerifyOrExit(entry != nullptr); - hasAddress = entry->IsMlrRegistered(*this); + hasAddress = mMlrRegisteredSet.Has(mIp6Addresses.IndexOf(*entry)); exit: return hasAddress; } -#endif +void Child::SetAddressMlrRegistrationState(const Ip6::Address &aAddress, bool aRegistered) +{ + Ip6::Address *entry; + + entry = mIp6Addresses.FindMatching(aAddress); + VerifyOrExit(entry != nullptr); + + mMlrRegisteredSet.Update(mIp6Addresses.IndexOf(*entry), aRegistered); + +exit: + return; +} + +void Child::GetAllMlrRegisteredAddresses(Ip6AddressArray &aAddressArray) const +{ + aAddressArray.Clear(); + + for (const Ip6::Address &entry : mIp6Addresses) + { + if (mMlrRegisteredSet.Has(mIp6Addresses.IndexOf(entry))) + { + IgnoreError(aAddressArray.PushBack(entry)); + } + } +} + +#endif // OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE #endif // OPENTHREAD_FTD diff --git a/src/core/thread/child.hpp b/src/core/thread/child.hpp index 26124ae28..f0d538225 100644 --- a/src/core/thread/child.hpp +++ b/src/core/thread/child.hpp @@ -60,6 +60,13 @@ public: */ static constexpr uint16_t kNumIp6Addresses = OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD - 1; + /** + * Represents an array of IPv6 addresses registered by an MTD child. + * + * This array does not include the mesh-local EID. + */ + typedef Array Ip6AddressArray; + /** * Represents the iterator for registered IPv6 address list of an MTD child. */ @@ -84,50 +91,6 @@ public: void SetFrom(const Child &aChild); }; - /** - * Represents an IPv6 address entry registered by an MTD child. - */ - class Ip6AddrEntry : public Ip6::Address - { - public: - /** - * Indicates whether the entry matches a given IPv6 address. - * - * @param[in] aAddress The IPv6 address. - * - * @retval TRUE The entry matches @p aAddress. - * @retval FALSE The entry does not match @p aAddress. - */ - bool Matches(const Ip6::Address &aAddress) const { return (*this == aAddress); } - -#if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE - /** - * Indicates whether the IPv6 address is registered via Multicast Listener Registration (MLR) on a given child. - * - * @param[in] aChild The child associated with the address. - * - * @retval TRUE If the address is MLR registered on @p aChild. - * @retval FALSE If the address is not MLR registered on @p aChild. - */ - bool IsMlrRegistered(const Child &aChild) const; - - /** - * Sets whether the IPv6 address is registered via Multicast Listener Registration (MLR) on a given child. - * - * @param[in] aRegistered TRUE if MLR registered, FALSE otherwise. - * @param[in] aChild The child associated with the address. - */ - void SetMlrRegistered(bool aRegistered, Child &aChild); -#endif - }; - - /** - * Represents an array of IPv6 address entries registered by an MTD child. - * - * This array does not include the mesh-local EID. - */ - typedef Array Ip6AddressArray; - /** * Initializes the `Child` object. * @@ -178,15 +141,6 @@ public: */ const Ip6AddressArray &GetIp6Addresses(void) const { return mIp6Addresses; } - /** - * Gets an array of registered IPv6 address entries by the child. - * - * The array does not include the mesh-local EID. The ML-EID can retrieved using `GetMeshLocalIp6Address()`. - * - * @returns The array of registered IPv6 addresses by the child. - */ - Ip6AddressArray &GetIp6Addresses(void) { return mIp6Addresses; } - /** * Iterates over all registered IPv6 addresses (using an iterator). * @@ -202,7 +156,7 @@ public: /** * Adds an IPv6 address to the list. * - * @param[in] aAddress A reference to IPv6 address to be added. + * @param[in] aAddress The IPv6 address to be added. * * @retval kErrorNone Successfully added the new address. * @retval kErrorAlready Address is already in the list. @@ -214,7 +168,7 @@ public: /** * Removes an IPv6 address from the list. * - * @param[in] aAddress A reference to IPv6 address to be removed. + * @param[in] aAddress The IPv6 address to be removed. * * @retval kErrorNone Successfully removed the address. * @retval kErrorNotFound Address was not found in the list. @@ -225,7 +179,7 @@ public: /** * Indicates whether an IPv6 address is in the list of IPv6 addresses of the child. * - * @param[in] aAddress A reference to IPv6 address. + * @param[in] aAddress The IPv6 address to check. * * @retval TRUE The address exists on the list. * @retval FALSE Address was not found in the list. @@ -353,10 +307,11 @@ public: void SetBlockParentDowngrade(bool aBlock) { mBlockParentDowngrade = aBlock; } #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE + /** - * Clears the Multicast Listener Registration (MLR) registered state on all IPv6 addresses of the child. + * Clears the Multicast Listener Registration (MLR) registration state of all IPv6 addresses of the child. */ - void ClearMlrRegisteredStateOnAllIp6Addresses(void) { mMlrRegisteredSet.Clear(); } + void ClearAllAddressesMlrRegistrationState(void) { mMlrRegisteredSet.Clear(); } /** * Indicates whether the child has a given IPv6 address that is MLR registered. @@ -369,12 +324,22 @@ public: bool HasMlrRegisteredAddress(const Ip6::Address &aAddress) const; /** - * Indicates whether the child has any IPv6 address that is MLR registered. + * Sets the MLR registered state of a given IPv6 address of the child. * - * @retval TRUE If the child has any MLR registered IPv6 address. - * @retval FALSE If the child does not have any MLR registered IPv6 address. + * If @p aAddress is not present on the list, calling this method does nothing. + * + * @param[in] aAddress The address. + * @param[in] aRegistered TRUE if MLR registered, FALSE otherwise. */ - bool HasAnyMlrRegisteredAddress(void) const { return !mMlrRegisteredSet.IsEmpty(); } + void SetAddressMlrRegistrationState(const Ip6::Address &aAddress, bool aRegistered); + + /** + * Gets all the MLR registered IPv6 addresses of the child. + * + * @param[out] aAddressArray A reference to an array to output the addresses. + */ + void GetAllMlrRegisteredAddresses(Ip6AddressArray &aAddressArray) const; + #endif // OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE private: diff --git a/src/core/thread/mle_ftd.cpp b/src/core/thread/mle_ftd.cpp index 7d277cae8..2b1c456db 100644 --- a/src/core/thread/mle_ftd.cpp +++ b/src/core/thread/mle_ftd.cpp @@ -1830,7 +1830,7 @@ Error Mle::ProcessAddressRegistrationTlv(RxInfo &aRxInfo, Child &aChild) Ip6::Address oldDua; #endif #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE - Mlr::Manager::ChildAddressArray oldMlrRegisteredAddresses; + Child::Ip6AddressArray oldMlrRegisteredAddresses; #endif OT_UNUSED_VARIABLE(storedCount); @@ -1845,16 +1845,7 @@ Error Mle::ProcessAddressRegistrationTlv(RxInfo &aRxInfo, Child &aChild) #endif #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE - if (aChild.HasAnyMlrRegisteredAddress()) - { - for (const Child::Ip6AddrEntry &addrEntry : aChild.GetIp6Addresses()) - { - if (addrEntry.IsMlrRegistered(aChild)) - { - IgnoreError(oldMlrRegisteredAddresses.PushBack(addrEntry)); - } - } - } + aChild.GetAllMlrRegisteredAddresses(oldMlrRegisteredAddresses); #endif aChild.ClearIp6Addresses(); @@ -1946,7 +1937,7 @@ Error Mle::ProcessAddressRegistrationTlv(RxInfo &aRxInfo, Child &aChild) #endif #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE - Get().UpdateProxiedSubscriptions(aChild, oldMlrRegisteredAddresses); + Get().UpdateChildRegistrations(aChild, oldMlrRegisteredAddresses); #endif if (count == 0) @@ -3812,7 +3803,7 @@ void Mle::SetChildStateToValid(Child &aChild) IgnoreError(mChildTable.StoreChild(aChild)); #if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE - Get().UpdateProxiedSubscriptions(aChild, Mlr::Manager::ChildAddressArray()); + Get().UpdateChildRegistrations(aChild); #endif mNeighborTable.Signal(NeighborTable::kChildAdded, aChild); diff --git a/src/core/thread/mlr_manager.cpp b/src/core/thread/mlr_manager.cpp index 72c9a28d8..f543070da 100644 --- a/src/core/thread/mlr_manager.cpp +++ b/src/core/thread/mlr_manager.cpp @@ -82,7 +82,7 @@ void Manager::EnterState(State aState) #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE for (Child &child : Get().Iterate(Child::kInStateValid)) { - child.ClearMlrRegisteredStateOnAllIp6Addresses(); + child.ClearAllAddressesMlrRegistrationState(); } #endif } @@ -256,29 +256,36 @@ bool Manager::IsAddressRegisteredByAnyChildExcept(const Ip6::Address &aAddress, return isRegistered; } -void Manager::UpdateProxiedSubscriptions(Child &aChild, const ChildAddressArray &aOldRegisteredAddresses) +void Manager::UpdateChildRegistrations(Child &aChild) +{ + Child::Ip6AddressArray emptyArray; + + UpdateChildRegistrations(aChild, emptyArray); +} + +void Manager::UpdateChildRegistrations(Child &aChild, const Child::Ip6AddressArray &aOldRegisteredAddresses) { bool hasUnregistered = false; VerifyOrExit(aChild.IsStateValid()); - for (Child::Ip6AddrEntry &addrEntry : aChild.GetIp6Addresses()) + for (const Ip6::Address &addr : aChild.GetIp6Addresses()) { bool isRegistered; - if (!addrEntry.IsMulticastLargerThanRealmLocal()) + if (!addr.IsMulticastLargerThanRealmLocal()) { continue; } - isRegistered = aOldRegisteredAddresses.Contains(addrEntry); + isRegistered = aOldRegisteredAddresses.ContainsMatching(addr); #if OPENTHREAD_CONFIG_MLR_ENABLE - isRegistered = isRegistered || IsAddressRegisteredByNetif(addrEntry); + isRegistered = isRegistered || IsAddressRegisteredByNetif(addr); #endif - isRegistered = isRegistered || IsAddressRegisteredByAnyChildExcept(addrEntry, &aChild); + isRegistered = isRegistered || IsAddressRegisteredByAnyChildExcept(addr, &aChild); - addrEntry.SetMlrRegistered(isRegistered, aChild); + aChild.SetAddressMlrRegistrationState(addr, isRegistered); if (!isRegistered) { @@ -347,11 +354,11 @@ void Manager::DetermineAddressesToRegister(AddressArray &aAddresses) const #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE for (const Child &child : Get().Iterate(Child::kInStateValid)) { - for (const Child::Ip6AddrEntry &addrEntry : child.GetIp6Addresses()) + for (const Ip6::Address &addr : child.GetIp6Addresses()) { - if (addrEntry.IsMulticastLargerThanRealmLocal() && !addrEntry.IsMlrRegistered(child)) + if (addr.IsMulticastLargerThanRealmLocal() && !child.HasMlrRegisteredAddress(addr)) { - SuccessOrExit(aAddresses.AddUnique(addrEntry)); + SuccessOrExit(aAddresses.AddUnique(addr)); } } } @@ -606,12 +613,12 @@ void Manager::ProcessResponse(Coap::Msg *aMsg, Error aResult) #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE for (Child &child : Get().Iterate(Child::kInStateValid)) { - for (Child::Ip6AddrEntry &addrEntry : child.GetIp6Addresses()) + for (const Ip6::Address &addr : child.GetIp6Addresses()) { - if (addrEntry.IsMulticastLargerThanRealmLocal() && !addrEntry.IsMlrRegistered(child) && - registeredAddresses.Contains(addrEntry)) + if (addr.IsMulticastLargerThanRealmLocal() && !child.HasMlrRegisteredAddress(addr) && + registeredAddresses.Contains(addr)) { - addrEntry.SetMlrRegistered(true, child); + child.SetAddressMlrRegistrationState(addr, true); } } } diff --git a/src/core/thread/mlr_manager.hpp b/src/core/thread/mlr_manager.hpp index 63eb90b9c..ffb2cf0a7 100644 --- a/src/core/thread/mlr_manager.hpp +++ b/src/core/thread/mlr_manager.hpp @@ -97,17 +97,20 @@ public: void HandleBackboneRouterPrimaryUpdate(BackboneRouter::PrimaryEvent aEvent); #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE - static constexpr uint16_t kMaxChildAddresses = OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD - 1; ///< Max MLR addresses - - typedef Array ChildAddressArray; ///< Registered MLR addresses array. + /** + * Updates the MLR registration status of a given child's addresses. + * + * @param[in] aChild The child to update. + */ + void UpdateChildRegistrations(Child &aChild); /** - * Updates the Multicast Subscription Table according to the Child information. + * Updates the MLR registration status of a given child's addresses. * - * @param[in] aChild A reference to the child information. - * @param[in] aOldRegisteredAddresses Array of the Child's previously registered IPv6 addresses. + * @param[in] aChild The child to update. + * @param[in] aOldRegisteredAddresses Child's previously registered addresses. */ - void UpdateProxiedSubscriptions(Child &aChild, const ChildAddressArray &aOldRegisteredAddresses); + void UpdateChildRegistrations(Child &aChild, const Child::Ip6AddressArray &aOldRegisteredAddresses); #endif #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE