Skip to content

Commit

Permalink
[mle] enhance MTD child IPv6 address registration (openthread#10743)
Browse files Browse the repository at this point in the history
This commit improves how MTD children register their IPv6 addresses
with their parent. The `Slaac` class now tracks the Lowpan Context
ID (from Network Data) for each SLAAC address. If the Context ID
associated with an existing SLAAC address changes (due to Network
Data updates), the `Slaac` module notifies the `Mle` to schedule
a "Child Update Request" transmission (if the device is an MTD
child). This ensures that the MTD child re-registers its addresses,
resolving any previous registration failures caused by incorrect or
outdated context ID compression.

This commit also adds `test-035-context-id-change-addr-reg.py`
to validate the newly added behavior.
  • Loading branch information
abtink authored Sep 25, 2024
1 parent 3a57996 commit 3913e0d
Show file tree
Hide file tree
Showing 7 changed files with 284 additions and 13 deletions.
33 changes: 20 additions & 13 deletions src/core/thread/mle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,11 @@ Error Mle::Enable(void)

void Mle::ScheduleChildUpdateRequest(void)
{
mChildUpdateRequestState = kChildUpdateRequestPending;
ScheduleMessageTransmissionTimer();
if (mChildUpdateRequestState != kChildUpdateRequestPending)
{
mChildUpdateRequestState = kChildUpdateRequestPending;
ScheduleMessageTransmissionTimer();
}
}

Error Mle::Disable(void)
Expand Down Expand Up @@ -1055,21 +1058,29 @@ void Mle::InitNeighbor(Neighbor &aNeighbor, const RxInfo &aRxInfo)
aNeighbor.SetLastHeard(TimerMilli::GetNow());
}

void Mle::ScheduleChildUpdateRequestIfMtdChild(void)
{
if (IsChild() && !IsFullThreadDevice())
{
ScheduleChildUpdateRequest();
}
}

void Mle::HandleNotifierEvents(Events aEvents)
{
VerifyOrExit(!IsDisabled());

if (aEvents.Contains(kEventThreadRoleChanged))
{
if (IsChild() && !IsFullThreadDevice() && mAddressRegistrationMode == kAppendMeshLocalOnly)
if (mAddressRegistrationMode == kAppendMeshLocalOnly)
{
// If only mesh-local address was registered in the "Child
// ID Request" message, after device is attached, trigger a
// "Child Update Request" to register the remaining
// addresses.

mAddressRegistrationMode = kAppendAllAddresses;
ScheduleChildUpdateRequest();
ScheduleChildUpdateRequestIfMtdChild();
}
}

Expand All @@ -1083,10 +1094,7 @@ void Mle::HandleNotifierEvents(Events aEvents)
Get<Notifier>().Signal(kEventThreadMeshLocalAddrChanged);
}

if (IsChild() && !IsFullThreadDevice())
{
ScheduleChildUpdateRequest();
}
ScheduleChildUpdateRequestIfMtdChild();
}

if (aEvents.ContainsAny(kEventIp6MulticastSubscribed | kEventIp6MulticastUnsubscribed))
Expand All @@ -1097,15 +1105,14 @@ void Mle::HandleNotifierEvents(Events aEvents)
// parent of 1.2 or higher version as it could depend on its
// parent to perform Multicast Listener Report.

if (IsChild() && !IsFullThreadDevice() &&
(!IsRxOnWhenIdle()
if (!IsRxOnWhenIdle()
#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
|| !GetParent().IsThreadVersion1p1()
|| !GetParent().IsThreadVersion1p1()
#endif
))
)

{
ScheduleChildUpdateRequest();
ScheduleChildUpdateRequestIfMtdChild();
}
}

Expand Down
9 changes: 9 additions & 0 deletions src/core/thread/mle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,15 @@ class Mle : public InstanceLocator, private NonCopyable
return (&aAddress == &mLinkLocalAllThreadNodes) || (&aAddress == &mRealmLocalAllThreadNodes);
}

/**
* Schedules a "Child Update Request" transmission if the device is an MTD child.
*
* For example, the `Slaac` class, which manages SLAAC addresses, calls this method to notify `Mle` that an
* existing SLAAC address's Context ID has changed. This can occur due to Network Data updates where the same
* on-mesh prefix receives a new Context ID.
*/
void ScheduleChildUpdateRequestIfMtdChild(void);

#if OPENTHREAD_CONFIG_DYNAMIC_STORE_FRAME_AHEAD_COUNTER_ENABLE
/**
* Sets the store frame counter ahead.
Expand Down
30 changes: 30 additions & 0 deletions src/core/utils/slaac_address.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,15 @@ void Slaac::RemoveOrDeprecateAddresses(void)
{
RemoveAddress(slaacAddr);
}

if (UpdateContextIdFor(slaacAddr))
{
// If the Context ID of an existing address changes,
// notify MLE so an MTD child can re-register its
// addresses with the parent.

Get<Mle::Mle>().ScheduleChildUpdateRequestIfMtdChild();
}
}
else if (!slaacAddr.IsDeprecating())
{
Expand Down Expand Up @@ -341,6 +350,9 @@ void Slaac::AddAddressFor(const NetworkData::OnMeshPrefixConfig &aConfig)

IgnoreError(GenerateIid(*newAddress, dadCounter));

newAddress->SetContextId(SlaacAddress::kInvalidContextId);
UpdateContextIdFor(*newAddress);

LogAddress(kAdding, *newAddress);

Get<ThreadNetif>().AddUnicastAddress(*newAddress);
Expand All @@ -349,6 +361,24 @@ void Slaac::AddAddressFor(const NetworkData::OnMeshPrefixConfig &aConfig)
return;
}

bool Slaac::UpdateContextIdFor(SlaacAddress &aSlaacAddress)
{
bool didChange = false;
Lowpan::Context context;

if (Get<NetworkData::Leader>().GetContext(aSlaacAddress.GetAddress(), context) != kErrorNone)
{
context.mContextId = SlaacAddress::kInvalidContextId;
}

VerifyOrExit(context.mContextId != aSlaacAddress.GetContextId());
aSlaacAddress.SetContextId(context.mContextId);
didChange = true;

exit:
return didChange;
}

void Slaac::HandleTimer(void)
{
NextFireTime nextTime;
Expand Down
6 changes: 6 additions & 0 deletions src/core/utils/slaac_address.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,12 @@ class Slaac : public InstanceLocator, private NonCopyable
class SlaacAddress : public Ip6::Netif::UnicastAddress
{
public:
static constexpr uint8_t kInvalidContextId = 0;

bool IsInUse(void) const { return mValid; }
void MarkAsNotInUse(void) { mValid = false; }
uint8_t GetContextId(void) const { return mContextId; }
void SetContextId(uint8_t aContextId) { mContextId = aContextId; }
uint8_t GetDomainId(void) const { return mDomainId; }
void SetDomainId(uint8_t aDomainId) { mDomainId = aDomainId; }
bool IsDeprecating(void) const { return (mExpirationTime.GetValue() != kNotDeprecated); };
Expand All @@ -188,6 +192,7 @@ class Slaac : public InstanceLocator, private NonCopyable
private:
static constexpr uint32_t kNotDeprecated = 0; // Special `mExpirationTime` value to indicate not deprecated.

uint8_t mContextId;
uint8_t mDomainId;
TimeMilli mExpirationTime;
};
Expand All @@ -200,6 +205,7 @@ class Slaac : public InstanceLocator, private NonCopyable
void DeprecateAddress(SlaacAddress &aAddress);
void RemoveAddress(SlaacAddress &aAddress);
void AddAddressFor(const NetworkData::OnMeshPrefixConfig &aConfig);
bool UpdateContextIdFor(SlaacAddress &aSlaacAddress);
void HandleTimer(void);
void GetIidSecretKey(IidSecretKey &aKey) const;
void HandleNotifierEvents(Events aEvents);
Expand Down
9 changes: 9 additions & 0 deletions tests/toranj/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,12 @@ def get_pollperiod(self):
def set_pollperiod(self, period):
self._cli_no_output('pollperiod', period)

def get_child_timeout(self):
return self._cli_single_output('childtimeout')

def set_child_timeout(self, timeout):
self._cli_no_output('childtimeout', timeout)

def get_partition_id(self):
return self._cli_single_output('partitionid')

Expand All @@ -368,6 +374,9 @@ def get_parent_info(self):
def get_child_table(self):
return Node.parse_table(self.cli('child table'))

def get_child_ip(self):
return self.cli('childip')

def get_neighbor_table(self):
return Node.parse_table(self.cli('neighbor table'))

Expand Down
Loading

0 comments on commit 3913e0d

Please sign in to comment.