From 77ea86302e8a03167d5f3ed710e4e50f8426a6b1 Mon Sep 17 00:00:00 2001 From: Rongli Sun Date: Tue, 31 Mar 2020 22:58:51 +0800 Subject: [PATCH] [cli] add `childip max` command (#4759) Thread 1.2 test harness requires the ability to set the number of IP address the parent could store per child to test the reaction of the Child DUT. The value intentionally may not conform to the Conformance Specification. Since it is only used for reference device, this commit wraps relevant APIs in the OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE macro. --- include/openthread/thread_ftd.h | 31 +++++++++++++++ src/cli/README.md | 22 +++++++++++ src/cli/cli.cpp | 67 ++++++++++++++++++++++----------- src/core/api/thread_ftd_api.cpp | 16 ++++++++ src/core/thread/mle_router.cpp | 49 ++++++++++++++++++++++-- src/core/thread/mle_router.hpp | 26 +++++++++++++ 6 files changed, 186 insertions(+), 25 deletions(-) diff --git a/include/openthread/thread_ftd.h b/include/openthread/thread_ftd.h index 3a59fe555..c27a9483c 100644 --- a/include/openthread/thread_ftd.h +++ b/include/openthread/thread_ftd.h @@ -578,6 +578,37 @@ int8_t otThreadGetParentPriority(otInstance *aInstance); */ otError otThreadSetParentPriority(otInstance *aInstance, int8_t aParentPriority); +/** + * This function gets the maximum number of IP addresses that each MTD child may register with this device as parent. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @returns The maximum number of IP addresses that each MTD child may register with this device as parent. + * + * @sa otThreadSetMaxChildIpAddresses + * + */ +uint8_t otThreadGetMaxChildIpAddresses(otInstance *aInstance); + +/** + * This function sets/restores the maximum number of IP addresses that each MTD child may register with this + * device as parent. + * + * @note This API requires `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE`, and is only used by Thread Test Harness + * to limit the address registrations of the reference parent in order to test the MTD DUT reaction. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aMaxIpAddresses The maximum number of IP addresses that each MTD child may register with this + * device as parent. 0 to clear the setting and restore the default. + * + * @retval OT_ERROR_NONE Successfully set/cleared the number. + * @retval OT_ERROR_INVALID_ARGS If exceeds the allowed maximum number. + * + * @sa otThreadGetMaxChildIpAddresses + * + */ +otError otThreadSetMaxChildIpAddresses(otInstance *aInstance, uint8_t aMaxIpAddresses); + /** * This enumeration defines the constants used in `otNeighborTableCallback` to indicate whether a child or router * neighbor is being added or removed. diff --git a/src/cli/README.md b/src/cli/README.md index b57e74f40..5dccb8482 100644 --- a/src/cli/README.md +++ b/src/cli/README.md @@ -333,6 +333,28 @@ Get the list of IP addresses stored for MTD children. Done ``` +### childip max + +Get the maximum number of IP addresses that each MTD child may register with this device as parent. + +```bash +> childip max +4 +Done +``` + +### childip max \ + +Set the maximum number of IP addresses that each MTD child may register with this device as parent. +0 to clear the setting and restore the default. + +`OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is required. + +```bash +> childip max 2 +Done +``` + ### childmax Get the Thread maximum number of allowed children. diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index c1115602c..e3746a33c 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -864,37 +864,62 @@ exit: void Interpreter::ProcessChildIp(uint8_t aArgsLength, char *aArgs[]) { - otError error = OT_ERROR_NONE; - uint16_t maxChildren; + OT_UNUSED_VARIABLE(aArgs); + otError error = OT_ERROR_NONE; - VerifyOrExit(aArgsLength == 0, error = OT_ERROR_INVALID_ARGS); - - maxChildren = otThreadGetMaxAllowedChildren(mInstance); - - for (uint16_t childIndex = 0; childIndex < maxChildren; childIndex++) + if (aArgsLength == 0) { - otChildIp6AddressIterator iterator = OT_CHILD_IP6_ADDRESS_ITERATOR_INIT; - otIp6Address ip6Address; - otChildInfo childInfo; + uint16_t maxChildren = otThreadGetMaxAllowedChildren(mInstance); - if ((otThreadGetChildInfoByIndex(mInstance, childIndex, &childInfo) != OT_ERROR_NONE) || - childInfo.mIsStateRestoring) + for (uint16_t childIndex = 0; childIndex < maxChildren; childIndex++) { - continue; - } + otChildIp6AddressIterator iterator = OT_CHILD_IP6_ADDRESS_ITERATOR_INIT; + otIp6Address ip6Address; + otChildInfo childInfo; - iterator = OT_CHILD_IP6_ADDRESS_ITERATOR_INIT; + if ((otThreadGetChildInfoByIndex(mInstance, childIndex, &childInfo) != OT_ERROR_NONE) || + childInfo.mIsStateRestoring) + { + continue; + } - while (otThreadGetChildNextIp6Address(mInstance, childIndex, &iterator, &ip6Address) == OT_ERROR_NONE) - { - mServer->OutputFormat("%04x: ", childInfo.mRloc16); - OutputIp6Address(ip6Address); - mServer->OutputFormat("\r\n"); + iterator = OT_CHILD_IP6_ADDRESS_ITERATOR_INIT; + + while (otThreadGetChildNextIp6Address(mInstance, childIndex, &iterator, &ip6Address) == OT_ERROR_NONE) + { + mServer->OutputFormat("%04x: ", childInfo.mRloc16); + OutputIp6Address(ip6Address); + mServer->OutputFormat("\r\n"); + } } } + else if (strcmp(aArgs[0], "max") == 0) + { + if (aArgsLength == 1) + { + mServer->OutputFormat("%d\r\n", otThreadGetMaxChildIpAddresses(mInstance)); + } +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + else if (aArgsLength == 2) + { + unsigned long value; + SuccessOrExit(error = ParseUnsignedLong(aArgs[1], value)); + SuccessOrExit(error = otThreadSetMaxChildIpAddresses(mInstance, static_cast(value))); + } +#endif + else + { + error = OT_ERROR_INVALID_ARGS; + } + } + else + { + error = OT_ERROR_INVALID_COMMAND; + } +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE exit: - OT_UNUSED_VARIABLE(aArgs); +#endif AppendResult(error); } diff --git a/src/core/api/thread_ftd_api.cpp b/src/core/api/thread_ftd_api.cpp index 3c4a79883..c102e84f3 100644 --- a/src/core/api/thread_ftd_api.cpp +++ b/src/core/api/thread_ftd_api.cpp @@ -58,6 +58,22 @@ otError otThreadSetMaxAllowedChildren(otInstance *aInstance, uint16_t aMaxChildr return instance.Get().SetMaxChildrenAllowed(aMaxChildren); } +uint8_t otThreadGetMaxChildIpAddresses(otInstance *aInstance) +{ + Instance &instance = *static_cast(aInstance); + + return instance.Get().GetMaxChildIpAddresses(); +} + +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE +otError otThreadSetMaxChildIpAddresses(otInstance *aInstance, uint8_t aMaxIpAddresses) +{ + Instance &instance = *static_cast(aInstance); + + return instance.Get().SetMaxChildIpAddresses(aMaxIpAddresses); +} +#endif + bool otThreadIsRouterEligible(otInstance *aInstance) { Instance &instance = *static_cast(aInstance); diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 90cfb4517..e4c5e9ce7 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -83,6 +83,9 @@ MleRouter::MleRouter(Instance &aInstance) #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE , mBackboneRouterRegistrationDelay(0) #endif +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + , mMaxChildIpAddresses(0) +#endif { mDeviceMode.Set(mDeviceMode.Get() | DeviceMode::kModeFullThreadDevice | DeviceMode::kModeFullNetworkData); @@ -1984,6 +1987,34 @@ exit: } } +uint8_t MleRouter::GetMaxChildIpAddresses(void) const +{ + uint8_t num = OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD; + +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + if (mMaxChildIpAddresses != 0) + { + num = mMaxChildIpAddresses; + } +#endif + + return num; +} + +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE +otError MleRouter::SetMaxChildIpAddresses(uint8_t aMaxIpAddresses) +{ + otError error = OT_ERROR_NONE; + + VerifyOrExit(aMaxIpAddresses <= OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD, error = OT_ERROR_INVALID_ARGS); + + mMaxChildIpAddresses = aMaxIpAddresses; + +exit: + return error; +} +#endif + otError MleRouter::UpdateChildAddresses(const Message &aMessage, uint16_t aOffset, Child &aChild) { otError error = OT_ERROR_NONE; @@ -2034,10 +2065,20 @@ otError MleRouter::UpdateChildAddresses(const Message &aMessage, uint16_t aOffse address = *entry.GetIp6Address(); } - // We try to accept/add as many IPv6 addresses as possible. - // "Child ID/Update Response" will indicate the accepted - // addresses. - error = aChild.AddIp6Address(address); +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + if (mMaxChildIpAddresses > 0 && storedCount >= mMaxChildIpAddresses) + { + // Skip remaining address registration entries but keep logging skipped addresses. + error = OT_ERROR_NO_BUFS; + } + else +#endif + { + // We try to accept/add as many IPv6 addresses as possible. + // "Child ID/Update Response" will indicate the accepted + // addresses. + error = aChild.AddIp6Address(address); + } if (error == OT_ERROR_NONE) { diff --git a/src/core/thread/mle_router.hpp b/src/core/thread/mle_router.hpp index 0fa17b6ad..a84ec5958 100644 --- a/src/core/thread/mle_router.hpp +++ b/src/core/thread/mle_router.hpp @@ -677,6 +677,29 @@ public: void SetBackboneRouterRegistrationDelay(uint8_t aDelay) { mBackboneRouterRegistrationDelay = aDelay; } #endif + /** + * This method gets the maximum number of IP addresses that each MTD child may register with this device as parent. + * + * @returns The maximum number of IP addresses that each MTD child may register with this device as parent. + * + */ + uint8_t GetMaxChildIpAddresses(void) const; + +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + /** + * This method sets/restores the maximum number of IP addresses that each MTD child may register with this + * device as parent. + * + * @param[in] aMaxIpAddresses The maximum number of IP addresses that each MTD child may register with this + * device as parent. 0 to clear the setting and restore the default. + * + * @retval OT_ERROR_NONE Successfully set/cleared the number. + * @retval OT_ERROR_INVALID_ARGS If exceeds the allowed maximum number. + * + */ + otError SetMaxChildIpAddresses(uint8_t aMaxIpAddresses); +#endif + private: enum { @@ -824,6 +847,9 @@ private: #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE uint8_t mBackboneRouterRegistrationDelay; ///< Delay before registering Backbone Router service. #endif +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + uint8_t mMaxChildIpAddresses; +#endif #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE MeshCoP::SteeringDataTlv mSteeringData;