[mle] request "Route TLV" after quick re-attach as FED (#8956)

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.
This commit is contained in:
Abtin Keshavarzian
2023-05-02 23:15:33 -07:00
committed by GitHub
parent b9a318092c
commit 6f909a1d6a
5 changed files with 95 additions and 62 deletions
+1 -3
View File
@@ -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;
@@ -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;
+38 -9
View File
@@ -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)
@@ -1841,7 +1842,30 @@ exit:
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,
@@ -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++;
}
@@ -2741,8 +2763,6 @@ exit:
void Mle::HandleAdvertisement(RxInfo &aRxInfo)
{
static const uint8_t kTlvs[] = {Tlv::kNetworkData};
Error error = kErrorNone;
uint16_t sourceAddress;
LeaderData leaderData;
@@ -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;
@@ -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())
@@ -2989,8 +3013,6 @@ exit:
if (dataRequest)
{
static const uint8_t kTlvs[] = {Tlv::kNetworkData};
uint16_t delay;
if (aRxInfo.mMessageInfo.GetSockAddr().IsMulticast())
@@ -3005,7 +3027,7 @@ exit:
delay = 10;
}
IgnoreError(SendDataRequest(aRxInfo.mMessageInfo.GetPeerAddr(), kTlvs, delay));
IgnoreError(SendDataRequestAfterDelay(aRxInfo.mMessageInfo.GetPeerAddr(), delay));
}
else if (error == kErrorNone)
{
@@ -3584,6 +3606,13 @@ void Mle::HandleChildUpdateResponse(RxInfo &aRxInfo)
mRetrieveNewNetworkData = true;
#if OPENTHREAD_FTD
if (IsFullThreadDevice())
{
mRequestRouteTlv = true;
}
#endif
OT_FALL_THROUGH;
case kRoleChild:
+30 -45
View File
@@ -1525,49 +1525,32 @@ protected:
*/
Mac::ShortAddress GetNextHop(uint16_t aDestination) const;
/**
* This method generates an MLE Data Request message.
*
* @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);
#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 which request Link Metrics Report TLV.
*
* @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.
*
* @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);
}
Error SendDataRequestForLinkMetricsReport(const Ip6::Address &aDestination,
const LinkMetrics::LinkMetrics::QueryInfo &aQueryInfo);
#endif
/**
* This method generates an MLE Data Request message.
*
* @tparam kArrayLength The TLV array length.
*
* @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.
*
* @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);
}
/**
* This method generates an MLE Child Update Request message.
*
@@ -1769,20 +1752,21 @@ protected:
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.
@@ -1990,6 +1974,7 @@ private:
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,
+7 -4
View File
@@ -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;
@@ -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);
@@ -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)
@@ -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;
@@ -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);
+19 -1
View File
@@ -55,7 +55,7 @@ child2 = cli.Node()
# 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')
@@ -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