Skip to content

Commit

Permalink
[mle] request "Route TLV" after quick re-attach as FED (openthread#8956)
Browse files Browse the repository at this point in the history
This commit allows an FED child to request Route TLV (in "TLV Request
TLV") in an MLE Data Request message. Parent will include the Route
TLV when requested by the child.

After successfully performing a quick re-attach upon reset, an FED
child requests Route TLV when sending MLE Data Request to its parent.
This is tracked by a newly added boolean `mRequestRouteTlv`, which is
set after quick re-attach and cleared when Route TLV is successfully
processed.

This commit also simplifies methods related to sending Data Request.
  • Loading branch information
abtink committed May 3, 2023
1 parent b9a3180 commit 6f909a1
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 57 deletions.
4 changes: 1 addition & 3 deletions src/core/thread/link_metrics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,6 @@ LinkMetrics::LinkMetrics(Instance &aInstance)

Error LinkMetrics::Query(const Ip6::Address &aDestination, uint8_t aSeriesId, const Metrics *aMetrics)
{
static const uint8_t kTlvs[] = {Mle::Tlv::kLinkMetricsReport};

Error error;
Neighbor *neighbor;
QueryInfo info;
Expand All @@ -79,7 +77,7 @@ Error LinkMetrics::Query(const Ip6::Address &aDestination, uint8_t aSeriesId, co
VerifyOrExit(info.mTypeIdCount == 0, error = kErrorInvalidArgs);
}

error = Get<Mle::MleRouter>().SendDataRequest(aDestination, kTlvs, sizeof(kTlvs), /* aDelay */ 0, info);
error = Get<Mle::MleRouter>().SendDataRequestForLinkMetricsReport(aDestination, info);

exit:
return error;
Expand Down
47 changes: 38 additions & 9 deletions src/core/thread/mle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ const otMeshLocalPrefix Mle::sMeshLocalPrefixInit = {
Mle::Mle(Instance &aInstance)
: InstanceLocator(aInstance)
, mRetrieveNewNetworkData(false)
, mRequestRouteTlv(false)
, mRole(kRoleDisabled)
, mNeighborTable(aInstance)
, mDeviceMode(DeviceMode::kModeRxOnWhenIdle)
Expand Down Expand Up @@ -1841,7 +1842,30 @@ Error Mle::SendChildIdRequest(void)
return error;
}

Error Mle::SendDataRequest(const Ip6::Address &aDestination)
{
return SendDataRequestAfterDelay(aDestination, /* aDelay */ 0);
}

Error Mle::SendDataRequestAfterDelay(const Ip6::Address &aDestination, uint16_t aDelay)
{
static const uint8_t kTlvs[] = {Tlv::kNetworkData, Tlv::kRoute};

// Based on `mRequestRouteTlv` include both Network Data and Route
// TLVs or only Network Data TLV.

return SendDataRequest(aDestination, kTlvs, mRequestRouteTlv ? 2 : 1, aDelay);
}

#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
Error Mle::SendDataRequestForLinkMetricsReport(const Ip6::Address &aDestination,
const LinkMetrics::LinkMetrics::QueryInfo &aQueryInfo)
{
static const uint8_t kTlvs[] = {Tlv::kLinkMetricsReport};

return SendDataRequest(aDestination, kTlvs, sizeof(kTlvs), /* aDelay */ 0, &aQueryInfo);
}

Error Mle::SendDataRequest(const Ip6::Address &aDestination,
const uint8_t *aTlvs,
uint8_t aTlvsLength,
Expand Down Expand Up @@ -1987,15 +2011,13 @@ void Mle::HandleMessageTransmissionTimer(void)
case kChildUpdateRequestNone:
if (mDataRequestState == kDataRequestActive)
{
static const uint8_t kTlvs[] = {Tlv::kNetworkData};

Ip6::Address destination;

VerifyOrExit(mDataRequestAttempts < kMaxChildKeepAliveAttempts, IgnoreError(BecomeDetached()));

destination.SetToLinkLocalAddress(mParent.GetExtAddress());

if (SendDataRequest(destination, kTlvs) == kErrorNone)
if (SendDataRequest(destination) == kErrorNone)
{
mDataRequestAttempts++;
}
Expand Down Expand Up @@ -2741,8 +2763,6 @@ void Mle::ReestablishLinkWithNeighbor(Neighbor &aNeighbor)

void Mle::HandleAdvertisement(RxInfo &aRxInfo)
{
static const uint8_t kTlvs[] = {Tlv::kNetworkData};

Error error = kErrorNone;
uint16_t sourceAddress;
LeaderData leaderData;
Expand Down Expand Up @@ -2796,7 +2816,7 @@ void Mle::HandleAdvertisement(RxInfo &aRxInfo)
if (mRetrieveNewNetworkData || IsNetworkDataNewer(leaderData))
{
delay = Random::NonCrypto::GetUint16InRange(0, kMleMaxResponseDelay);
IgnoreError(SendDataRequest(aRxInfo.mMessageInfo.GetPeerAddr(), kTlvs, delay));
IgnoreError(SendDataRequestAfterDelay(aRxInfo.mMessageInfo.GetPeerAddr(), delay));
}

aRxInfo.mClass = RxInfo::kPeerMessage;
Expand Down Expand Up @@ -2826,6 +2846,10 @@ void Mle::HandleDataResponse(RxInfo &aRxInfo)
}
#endif

#if OPENTHREAD_FTD
SuccessOrExit(error = Get<MleRouter>().ReadAndProcessRouteTlvOnFed(aRxInfo, mParent.GetRouterId()));
#endif

error = HandleLeaderData(aRxInfo);

if (mDataRequestState == kDataRequestNone && !IsRxOnWhenIdle())
Expand Down Expand Up @@ -2989,8 +3013,6 @@ Error Mle::HandleLeaderData(RxInfo &aRxInfo)

if (dataRequest)
{
static const uint8_t kTlvs[] = {Tlv::kNetworkData};

uint16_t delay;

if (aRxInfo.mMessageInfo.GetSockAddr().IsMulticast())
Expand All @@ -3005,7 +3027,7 @@ Error Mle::HandleLeaderData(RxInfo &aRxInfo)
delay = 10;
}

IgnoreError(SendDataRequest(aRxInfo.mMessageInfo.GetPeerAddr(), kTlvs, delay));
IgnoreError(SendDataRequestAfterDelay(aRxInfo.mMessageInfo.GetPeerAddr(), delay));
}
else if (error == kErrorNone)
{
Expand Down Expand Up @@ -3584,6 +3606,13 @@ void Mle::HandleChildUpdateResponse(RxInfo &aRxInfo)

mRetrieveNewNetworkData = true;

#if OPENTHREAD_FTD
if (IsFullThreadDevice())
{
mRequestRouteTlv = true;
}
#endif

OT_FALL_THROUGH;

case kRoleChild:
Expand Down
65 changes: 25 additions & 40 deletions src/core/thread/mle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1525,48 +1525,31 @@ class Mle : public InstanceLocator, private NonCopyable
*/
Mac::ShortAddress GetNextHop(uint16_t aDestination) const;

#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
/**
* This method generates an MLE Data Request message which includes a Link Metrics Query TLV.
* This method generates an MLE Data Request message.
*
* @param[in] aDestination A reference to the IPv6 address of the destination.
* @param[in] aTlvs A pointer to requested TLV types.
* @param[in] aTlvsLength The number of TLV types in @p aTlvs.
* @param[in] aDelay Delay in milliseconds before the Data Request message is sent.
* @param[in] aQueryInfo A Link Metrics query info.
* @param[in] aDestination The IPv6 destination address.
*
* @retval kErrorNone Successfully generated an MLE Data Request message.
* @retval kErrorNoBufs Insufficient buffers to generate the MLE Data Request message.
*
*/
Error SendDataRequest(const Ip6::Address &aDestination,
const uint8_t *aTlvs,
uint8_t aTlvsLength,
uint16_t aDelay,
const LinkMetrics::LinkMetrics::QueryInfo &aQueryInfo)
{
return SendDataRequest(aDestination, aTlvs, aTlvsLength, aDelay, &aQueryInfo);
}
#endif
Error SendDataRequest(const Ip6::Address &aDestination);

#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
/**
* This method generates an MLE Data Request message.
*
* @tparam kArrayLength The TLV array length.
* This method generates an MLE Data Request message which request Link Metrics Report TLV.
*
* @param[in] aDestination A reference to the IPv6 address of the destination.
* @param[in] aTlvs An array of requested TLVs.
* @param[in] aDelay Delay in milliseconds before the Data Request message is sent.
* @param[in] aQueryInfo A Link Metrics query info.
*
* @retval kErrorNone Successfully generated an MLE Data Request message.
* @retval kErrorNoBufs Insufficient buffers to generate the MLE Data Request message.
*
*/
template <uint8_t kArrayLength>
Error SendDataRequest(const Ip6::Address &aDestination, const uint8_t (&aTlvs)[kArrayLength], uint16_t aDelay = 0)
{
return SendDataRequest(aDestination, aTlvs, kArrayLength, aDelay);
}
Error SendDataRequestForLinkMetricsReport(const Ip6::Address &aDestination,
const LinkMetrics::LinkMetrics::QueryInfo &aQueryInfo);
#endif

/**
* This method generates an MLE Child Update Request message.
Expand Down Expand Up @@ -1769,20 +1752,21 @@ class Mle : public InstanceLocator, private NonCopyable

Ip6::Netif::UnicastAddress mLeaderAloc; ///< Leader anycast locator

LeaderData mLeaderData; ///< Last received Leader Data TLV.
bool mRetrieveNewNetworkData; ///< Indicating new Network Data is needed if set.
DeviceRole mRole; ///< Current Thread role.
Parent mParent; ///< Parent information.
NeighborTable mNeighborTable; ///< The neighbor table.
DeviceMode mDeviceMode; ///< Device mode setting.
AttachState mAttachState; ///< The attach state.
uint8_t mParentRequestCounter; ///< Number of parent requests while in `kAttachStateParentRequest`.
ReattachState mReattachState; ///< Reattach state
uint16_t mAttachCounter; ///< Attach attempt counter.
uint16_t mAnnounceDelay; ///< Delay in between sending Announce messages during attach.
AttachTimer mAttachTimer; ///< The timer for driving the attach process.
DelayTimer mDelayedResponseTimer; ///< The timer to delay MLE responses.
MsgTxTimer mMessageTransmissionTimer; ///< The timer for (re-)sending of MLE messages (e.g. Child Update).
LeaderData mLeaderData; ///< Last received Leader Data TLV.
bool mRetrieveNewNetworkData : 1; ///< Indicating new Network Data is needed if set.
bool mRequestRouteTlv : 1; ///< Request Route TLV when sending Data Request.
DeviceRole mRole; ///< Current Thread role.
Parent mParent; ///< Parent information.
NeighborTable mNeighborTable; ///< The neighbor table.
DeviceMode mDeviceMode; ///< Device mode setting.
AttachState mAttachState; ///< The attach state.
uint8_t mParentRequestCounter; ///< Number of parent requests while in `kAttachStateParentRequest`.
ReattachState mReattachState; ///< Reattach state
uint16_t mAttachCounter; ///< Attach attempt counter.
uint16_t mAnnounceDelay; ///< Delay in between sending Announce messages during attach.
AttachTimer mAttachTimer; ///< The timer for driving the attach process.
DelayTimer mDelayedResponseTimer; ///< The timer to delay MLE responses.
MsgTxTimer mMessageTransmissionTimer; ///< The timer for (re-)sending of MLE messages (e.g. Child Update).
#if OPENTHREAD_FTD
uint8_t mLinkRequestAttempts; ///< Number of remaining link requests to send after reset.
bool mWasLeader; ///< Indicating if device was leader before reset.
Expand Down Expand Up @@ -1990,6 +1974,7 @@ class Mle : public InstanceLocator, private NonCopyable
void HandleDetachGracefullyTimer(void);
bool IsDetachingGracefully(void) { return mDetachGracefullyTimer.IsRunning(); }
Error SendChildUpdateRequest(ChildUpdateRequestMode aMode);
Error SendDataRequestAfterDelay(const Ip6::Address &aDestination, uint16_t aDelay);

#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
Error SendDataRequest(const Ip6::Address &aDestination,
Expand Down
11 changes: 7 additions & 4 deletions src/core/thread/mle_router.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -808,8 +808,6 @@ void MleRouter::HandleLinkAcceptAndRequest(RxInfo &aRxInfo)

Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest)
{
static const uint8_t kDataRequestTlvs[] = {Tlv::kNetworkData};

Error error = kErrorNone;
Router *router;
Neighbor::State neighborState;
Expand Down Expand Up @@ -916,7 +914,7 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest)

mLinkRequestAttempts = 0; // completed router sync after reset, no more link request to retransmit
mRetrieveNewNetworkData = true;
IgnoreError(SendDataRequest(aRxInfo.mMessageInfo.GetPeerAddr(), kDataRequestTlvs));
IgnoreError(SendDataRequest(aRxInfo.mMessageInfo.GetPeerAddr()));

#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
Get<TimeSync>().HandleTimeSyncMessage(aRxInfo.mMessage);
Expand All @@ -939,7 +937,7 @@ Error MleRouter::HandleLinkAccept(RxInfo &aRxInfo, bool aRequest)
SerialNumber::IsGreater(leaderData.GetDataVersion(NetworkData::kFullSet),
Get<NetworkData::Leader>().GetVersion(NetworkData::kFullSet)))
{
IgnoreError(SendDataRequest(aRxInfo.mMessageInfo.GetPeerAddr(), kDataRequestTlvs));
IgnoreError(SendDataRequest(aRxInfo.mMessageInfo.GetPeerAddr()));
}

// Route (optional)
Expand Down Expand Up @@ -1085,6 +1083,7 @@ Error MleRouter::ReadAndProcessRouteTlvOnFed(RxInfo &aRxInfo, uint8_t aParentId)
case kErrorNone:
SuccessOrExit(error = ProcessRouteTlv(routeTlv, aRxInfo));
mRouterTable.UpdateRoutesOnFed(routeTlv, aParentId);
mRequestRouteTlv = false;
break;
case kErrorNotFound:
break;
Expand Down Expand Up @@ -3159,6 +3158,10 @@ void MleRouter::SendDataResponse(const Ip6::Address &aDestination,
SuccessOrExit(error = message->AppendPendingDatasetTlv());
break;

case Tlv::kRoute:
SuccessOrExit(error = message->AppendRouteTlv());
break;

#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
case Tlv::kLinkMetricsReport:
OT_ASSERT(aRequestMessage != nullptr);
Expand Down
20 changes: 19 additions & 1 deletion tests/toranj/cli/test-012-reset-recovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
# Form topology

leader.form('reset')
child1.join(leader, cli.JOIN_TYPE_END_DEVICE)
child1.join(leader, cli.JOIN_TYPE_REED)
child2.join(leader, cli.JOIN_TYPE_END_DEVICE)

verify(leader.get_state() == 'leader')
Expand Down Expand Up @@ -135,6 +135,24 @@ def check_leader_neighbor_table():

verify_within(check_leader_neighbor_table, 10)

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Reset `child` and make sure it re-attaches successfully.

del child1
child1 = cli.Node(index=3)
child1.set_router_eligible('disable')
child1.interface_up()
child1.thread_start()


def check_child1_state():
verify(child1.get_state() == 'child')
table = child1.get_router_table()
verify(len(table) == 2)


verify_within(check_child1_state, 10)

# -----------------------------------------------------------------------------------------------------------------------
# Test finished

Expand Down

0 comments on commit 6f909a1

Please sign in to comment.