[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.
This commit is contained in:
Abtin Keshavarzian
2026-05-28 07:25:40 -07:00
committed by GitHub
parent 290919b178
commit eac46963bb
5 changed files with 94 additions and 120 deletions
+31 -23
View File
@@ -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<const Ip6AddrEntry &>(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<Mle::Mle>().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
+27 -62
View File
@@ -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<Ip6::Address, kNumIp6Addresses> 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<Ip6AddrEntry, kNumIp6Addresses> 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:
+4 -13
View File
@@ -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<Mlr::Manager>().UpdateProxiedSubscriptions(aChild, oldMlrRegisteredAddresses);
Get<Mlr::Manager>().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<Mlr::Manager>().UpdateProxiedSubscriptions(aChild, Mlr::Manager::ChildAddressArray());
Get<Mlr::Manager>().UpdateChildRegistrations(aChild);
#endif
mNeighborTable.Signal(NeighborTable::kChildAdded, aChild);
+22 -15
View File
@@ -82,7 +82,7 @@ void Manager::EnterState(State aState)
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
for (Child &child : Get<ChildTable>().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<ChildTable>().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<ChildTable>().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);
}
}
}
+10 -7
View File
@@ -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<Ip6::Address, kMaxChildAddresses> 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