From 51c62a29d0ce170e8c85e65f9f8deade0d7c575e Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Mon, 12 Mar 2018 18:27:07 +0000 Subject: [PATCH] [network-data] optimize network data update via MLE (#2612) This commit reduces stack usage when receiving/updating network data via MLE by copying the network data directly out of the message and skipping the TLV read. --- src/core/thread/mle.cpp | 23 +++++++++++----------- src/core/thread/mle_tlvs.hpp | 9 --------- src/core/thread/network_data_leader.cpp | 26 ++++++++++++++++++------- src/core/thread/network_data_leader.hpp | 17 +++++++++------- tests/unit/test_lowpan.cpp | 10 +++++++++- 5 files changed, 49 insertions(+), 36 deletions(-) diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 45b7214e3..d64a7c7d5 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -2554,9 +2554,9 @@ otError Mle::HandleLeaderData(const Message &aMessage, const Ip6::MessageInfo &a ThreadNetif & netif = GetNetif(); otError error = OT_ERROR_NONE; LeaderDataTlv leaderData; - NetworkDataTlv networkData; ActiveTimestampTlv activeTimestamp; PendingTimestampTlv pendingTimestamp; + uint16_t networkDataOffset = 0; uint16_t activeDatasetOffset = 0; uint16_t pendingDatasetOffset = 0; bool dataRequest = false; @@ -2638,13 +2638,12 @@ otError Mle::HandleLeaderData(const Message &aMessage, const Ip6::MessageInfo &a pendingTimestamp.SetLength(0); } - if (Tlv::GetTlv(aMessage, Tlv::kNetworkData, sizeof(networkData), networkData) == OT_ERROR_NONE) + if (Tlv::GetOffset(aMessage, Tlv::kNetworkData, networkDataOffset) == OT_ERROR_NONE) { - VerifyOrExit(networkData.IsValid(), error = OT_ERROR_PARSE); - - netif.GetNetworkDataLeader().SetNetworkData(leaderData.GetDataVersion(), leaderData.GetStableDataVersion(), - (mDeviceMode & ModeTlv::kModeFullNetworkData) == 0, - networkData.GetNetworkData(), networkData.GetLength()); + error = netif.GetNetworkDataLeader().SetNetworkData( + leaderData.GetDataVersion(), leaderData.GetStableDataVersion(), + (mDeviceMode & ModeTlv::kModeFullNetworkData) == 0, aMessage, networkDataOffset); + SuccessOrExit(error); } else { @@ -2912,11 +2911,11 @@ otError Mle::HandleChildIdResponse(const Message &aMessage, const Ip6::MessageIn LeaderDataTlv leaderData; SourceAddressTlv sourceAddress; Address16Tlv shortAddress; - NetworkDataTlv networkData; RouteTlv route; ActiveTimestampTlv activeTimestamp; PendingTimestampTlv pendingTimestamp; Tlv tlv; + uint16_t networkDataOffset; uint16_t offset; // Source Address @@ -2936,7 +2935,8 @@ otError Mle::HandleChildIdResponse(const Message &aMessage, const Ip6::MessageIn VerifyOrExit(shortAddress.IsValid(), error = OT_ERROR_PARSE); // Network Data - SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kNetworkData, sizeof(networkData), networkData)); + error = Tlv::GetOffset(aMessage, Tlv::kNetworkData, networkDataOffset); + SuccessOrExit(error); // Active Timestamp if (Tlv::GetTlv(aMessage, Tlv::kActiveTimestamp, sizeof(activeTimestamp), activeTimestamp) == OT_ERROR_NONE) @@ -3003,8 +3003,8 @@ otError Mle::HandleChildIdResponse(const Message &aMessage, const Ip6::MessageIn mParent.SetRloc16(sourceAddress.GetRloc16()); netif.GetNetworkDataLeader().SetNetworkData(leaderData.GetDataVersion(), leaderData.GetStableDataVersion(), - (mDeviceMode & ModeTlv::kModeFullNetworkData) == 0, - networkData.GetNetworkData(), networkData.GetLength()); + (mDeviceMode & ModeTlv::kModeFullNetworkData) == 0, aMessage, + networkDataOffset); netif.GetActiveDataset().ApplyConfiguration(); @@ -3029,7 +3029,6 @@ otError Mle::HandleChildUpdateRequest(const Message &aMessage, const Ip6::Messag Mac::ExtAddress srcAddr; SourceAddressTlv sourceAddress; LeaderDataTlv leaderData; - NetworkDataTlv networkData; ChallengeTlv challenge; StatusTlv status; TlvRequestTlv tlvRequest; diff --git a/src/core/thread/mle_tlvs.hpp b/src/core/thread/mle_tlvs.hpp index caaa41a8d..fc8062209 100644 --- a/src/core/thread/mle_tlvs.hpp +++ b/src/core/thread/mle_tlvs.hpp @@ -864,15 +864,6 @@ public: SetLength(sizeof(*this) - sizeof(Tlv)); } - /** - * This method indicates whether or not the TLV appears to be well-formed. - * - * @retval TRUE If the TLV appears to be well-formed. - * @retval FALSE If the TLV does not appear to be well-formed. - * - */ - bool IsValid(void) const { return GetLength() < sizeof(*this) - sizeof(Tlv); } - /** * This method returns a pointer to the Network Data. * diff --git a/src/core/thread/network_data_leader.cpp b/src/core/thread/network_data_leader.cpp index 6414fb212..21555d765 100644 --- a/src/core/thread/network_data_leader.cpp +++ b/src/core/thread/network_data_leader.cpp @@ -404,16 +404,25 @@ otError LeaderBase::DefaultRouteLookup(PrefixTlv &aPrefix, uint16_t *aRloc16) return error; } -void LeaderBase::SetNetworkData(uint8_t aVersion, - uint8_t aStableVersion, - bool aStable, - const uint8_t *aData, - uint8_t aDataLength) +otError LeaderBase::SetNetworkData(uint8_t aVersion, + uint8_t aStableVersion, + bool aStable, + const Message &aMessage, + uint16_t aMessageOffset) { + otError error = OT_ERROR_NONE; + Mle::Tlv tlv; + uint16_t length; + + length = aMessage.Read(aMessageOffset, sizeof(tlv), &tlv); + VerifyOrExit(length == sizeof(tlv), error = OT_ERROR_PARSE); + + length = aMessage.Read(aMessageOffset + sizeof(tlv), tlv.GetLength(), mTlvs); + VerifyOrExit(length == tlv.GetLength(), error = OT_ERROR_PARSE); + + mLength = tlv.GetLength(); mVersion = aVersion; mStableVersion = aStableVersion; - memcpy(mTlvs, aData, aDataLength); - mLength = aDataLength; if (aStable) { @@ -423,6 +432,9 @@ void LeaderBase::SetNetworkData(uint8_t aVersion, otDumpDebgNetData(GetInstance(), "set network data", mTlvs, mLength); GetNotifier().SetFlags(OT_CHANGED_THREAD_NETDATA); + +exit: + return error; } otError LeaderBase::SetCommissioningData(const uint8_t *aValue, uint8_t aValueLength) diff --git a/src/core/thread/network_data_leader.hpp b/src/core/thread/network_data_leader.hpp index 556ef1dd0..7a8976ff3 100644 --- a/src/core/thread/network_data_leader.hpp +++ b/src/core/thread/network_data_leader.hpp @@ -153,15 +153,18 @@ public: * @param[in] aVersion The Version value. * @param[in] aStableVersion The Stable Version value. * @param[in] aStableOnly TRUE if storing only the stable data, FALSE otherwise. - * @param[in] aData A pointer to the Network Data. - * @param[in] aDataLength The length of the Network Data in bytes. + * @param[in] aMessage A reference to the MLE message. + * @param[in] aMessageOffset The offset in @p aMessage for the Network Data TLV. + * + * @retval OT_ERROR_NONE Successfully set the network data. + * @retval OT_ERROR_PARSE Network Data TLV in @p aMessage is not valid. * */ - void SetNetworkData(uint8_t aVersion, - uint8_t aStableVersion, - bool aStableOnly, - const uint8_t *aData, - uint8_t aDataLength); + otError SetNetworkData(uint8_t aVersion, + uint8_t aStableVersion, + bool aStableOnly, + const Message &aMessage, + uint16_t aMessageOffset); /** * This method sends a Server Data Notification message to the Leader indicating an invalid RLOC16. diff --git a/tests/unit/test_lowpan.cpp b/tests/unit/test_lowpan.cpp index ebad97c4f..daba82e09 100644 --- a/tests/unit/test_lowpan.cpp +++ b/tests/unit/test_lowpan.cpp @@ -114,6 +114,9 @@ static void Init() // Emulate global prefixes with contextes. uint8_t mockNetworkData[] = { + 0x0c, // MLE Network Data Type + 0x20, // MLE Network Data Length + // Prefix 2001:2:0:1::/64 0x03, 0x0e, // Prefix TLV 0x00, 0x40, 0x20, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x07, 0x02, // 6LoWPAN Context ID TLV @@ -125,7 +128,12 @@ static void Init() 0x02, 0x40 // Context ID = 2, C = FALSE }; - sThreadNetif->GetNetworkDataLeader().SetNetworkData(0, 0, true, mockNetworkData, sizeof(mockNetworkData)); + Message *message = sInstance->GetMessagePool().New(Message::kTypeIp6, 0); + VerifyOrQuit(message != NULL, "6lo: Ip6::NewMessage failed"); + + SuccessOrQuit(message->Append(mockNetworkData, sizeof(mockNetworkData)), "6lo: Message::Append failed"); + + sThreadNetif->GetNetworkDataLeader().SetNetworkData(0, 0, true, *message, 0); } /**