diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 91434316c..8c081fe99 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (172) +#define OPENTHREAD_API_VERSION (173) /** * @addtogroup api-instance diff --git a/include/openthread/thread_ftd.h b/include/openthread/thread_ftd.h index 2f0375fd8..b6ad860f1 100644 --- a/include/openthread/thread_ftd.h +++ b/include/openthread/thread_ftd.h @@ -739,6 +739,38 @@ void otThreadRegisterNeighborTableCallback(otInstance *aInstance, otNeighborTabl */ void otThreadSetCcmEnabled(otInstance *aInstance, bool aEnabled); +/** + * This function gets the range of router IDs that are allowed to assign to nodes within the thread network. + * + * @note This API requires `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE`, and is only used for test purpose. All the + * router IDs in the range [aMinRouterId, aMaxRouterId] are allowed. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[out] aMinRouterId The minimum router ID. + * @param[out] aMaxRouterId The maximum router ID. + * + * @sa otThreadSetRouterIdRange + * + */ +void otThreadGetRouterIdRange(otInstance *aInstance, uint8_t *aMinRouterId, uint8_t *aMaxRouterId); + +/** + * This function sets the range of router IDs that are allowed to assign to nodes within the thread network. + * + * @note This API requires `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE`, and is only used for test purpose. All the + * router IDs in the range [aMinRouterId, aMaxRouterId] are allowed. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aMinRouterId The minimum router ID. + * @param[in] aMaxRouterId The maximum router ID. + * + * @retval OT_ERROR_NONE Successfully set the range. + * @retval OT_ERROR_INVALID_ARGS aMinRouterId > aMaxRouterId, or the range is not covered by [0, 62]. + * + * @sa otThreadGetRouterIdRange + * + */ +otError otThreadSetRouterIdRange(otInstance *aInstance, uint8_t aMinRouterId, uint8_t aMaxRouterId); /** * @} * diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 66d4c7739..ef7401cf1 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -3224,6 +3224,31 @@ otError Interpreter::ProcessParentPriority(Arg aArgs[]) } #endif +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE +otError Interpreter::ProcessRouterIdRange(Arg *aArgs) +{ + uint8_t minRouterId; + uint8_t maxRouterId; + otError error = OT_ERROR_NONE; + + if (aArgs[0].IsEmpty()) + { + otThreadGetRouterIdRange(GetInstancePtr(), &minRouterId, &maxRouterId); + OutputLine("%d %d", minRouterId, maxRouterId); + } + else + { + SuccessOrExit(error = aArgs[0].ParseAsUint8(minRouterId)); + SuccessOrExit(error = aArgs[1].ParseAsUint8(maxRouterId)); + VerifyOrExit(aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS); + SuccessOrExit(error = otThreadSetRouterIdRange(GetInstancePtr(), minRouterId, maxRouterId)); + } + +exit: + return error; +} +#endif + #if OPENTHREAD_CONFIG_PING_SENDER_ENABLE void Interpreter::HandlePingReply(const otPingSenderReply *aReply, void *aContext) diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index f35e3ac7b..cf6326ddb 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -564,6 +564,9 @@ private: #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE otError ProcessTrel(Arg aArgs[]); #endif +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + otError ProcessRouterIdRange(Arg *aArgs); +#endif #if OPENTHREAD_CONFIG_PING_SENDER_ENABLE static void HandlePingReply(const otPingSenderReply *aReply, void *aContext); @@ -830,6 +833,9 @@ private: {"router", &Interpreter::ProcessRouter}, {"routerdowngradethreshold", &Interpreter::ProcessRouterDowngradeThreshold}, {"routereligible", &Interpreter::ProcessRouterEligible}, +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + {"routeridrange", &Interpreter::ProcessRouterIdRange}, +#endif {"routerselectionjitter", &Interpreter::ProcessRouterSelectionJitter}, {"routerupgradethreshold", &Interpreter::ProcessRouterUpgradeThreshold}, #endif diff --git a/src/core/api/thread_ftd_api.cpp b/src/core/api/thread_ftd_api.cpp index d96c11f6c..a6a319804 100644 --- a/src/core/api/thread_ftd_api.cpp +++ b/src/core/api/thread_ftd_api.cpp @@ -370,4 +370,16 @@ void otThreadSetCcmEnabled(otInstance *aInstance, bool aEnabled) } #endif +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE +void otThreadGetRouterIdRange(otInstance *aInstance, uint8_t *aMinRouterId, uint8_t *aMaxRouterId) +{ + AsCoreType(aInstance).Get().GetRouterIdRange(*aMinRouterId, *aMaxRouterId); +} + +otError otThreadSetRouterIdRange(otInstance *aInstance, uint8_t aMinRouterId, uint8_t aMaxRouterId) +{ + return AsCoreType(aInstance).Get().SetRouterIdRange(aMinRouterId, aMaxRouterId); +} +#endif + #endif // OPENTHREAD_FTD diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index 3915b247e..cfe200415 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -214,6 +214,10 @@ Error MleRouter::BecomeLeader(void) Router * router; uint32_t partitionId; uint8_t leaderId; +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + uint8_t minRouterId; + uint8_t maxRouterId; +#endif VerifyOrExit(!Get().IsPartiallyComplete(), error = kErrorInvalidState); VerifyOrExit(!IsDisabled(), error = kErrorInvalidState); @@ -228,8 +232,20 @@ Error MleRouter::BecomeLeader(void) partitionId = Random::NonCrypto::GetUint32(); #endif - leaderId = IsRouterIdValid(mPreviousRouterId) ? mPreviousRouterId +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + mRouterTable.GetRouterIdRange(minRouterId, maxRouterId); + if (IsRouterIdValid(mPreviousRouterId) && minRouterId <= mPreviousRouterId && mPreviousRouterId <= maxRouterId) + { + leaderId = mPreviousRouterId; + } + else + { + leaderId = Random::NonCrypto::GetUint8InRange(minRouterId, maxRouterId + 1); + } +#else + leaderId = IsRouterIdValid(mPreviousRouterId) ? mPreviousRouterId : Random::NonCrypto::GetUint8InRange(0, kMaxRouterId + 1); +#endif SetLeaderData(partitionId, mLeaderWeight, leaderId); diff --git a/src/core/thread/router_table.cpp b/src/core/thread/router_table.cpp index 8f777d99b..7b8101734 100644 --- a/src/core/thread/router_table.cpp +++ b/src/core/thread/router_table.cpp @@ -58,6 +58,10 @@ RouterTable::RouterTable(Instance &aInstance) , mRouterIdSequenceLastUpdated(0) , mRouterIdSequence(Random::NonCrypto::GetUint8()) , mActiveRouterCount(0) +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + , mMinRouterId(0) + , mMaxRouterId(Mle::kMaxRouterId) +#endif { for (Router &router : mRouters) { @@ -204,7 +208,11 @@ Router *RouterTable::Allocate(void) uint8_t freeBit; // count available router ids +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + for (uint8_t routerId = mMinRouterId; routerId <= mMaxRouterId; routerId++) +#else for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++) +#endif { if (!IsAllocated(routerId) && mRouterIdReuseDelay[routerId] == 0) { @@ -218,7 +226,11 @@ Router *RouterTable::Allocate(void) freeBit = Random::NonCrypto::GetUint8InRange(0, numAvailable); // allocate router +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + for (uint8_t routerId = mMinRouterId; routerId <= mMaxRouterId; routerId++) +#else for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++) +#endif { if (IsAllocated(routerId) || mRouterIdReuseDelay[routerId] > 0) { @@ -529,6 +541,27 @@ void RouterTable::HandleTimeTick(void) } } +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE +void RouterTable::GetRouterIdRange(uint8_t &aMinRouterId, uint8_t &aMaxRouterId) const +{ + aMinRouterId = mMinRouterId; + aMaxRouterId = mMaxRouterId; +} + +Error RouterTable::SetRouterIdRange(uint8_t aMinRouterId, uint8_t aMaxRouterId) +{ + Error error = kErrorNone; + + VerifyOrExit(aMinRouterId <= aMaxRouterId, error = kErrorInvalidArgs); + VerifyOrExit(aMaxRouterId <= Mle::kMaxRouterId, error = kErrorInvalidArgs); + mMinRouterId = aMinRouterId; + mMaxRouterId = aMaxRouterId; + +exit: + return error; +} +#endif + } // namespace ot #endif // OPENTHREAD_FTD diff --git a/src/core/thread/router_table.hpp b/src/core/thread/router_table.hpp index 06a280c97..1542a211d 100644 --- a/src/core/thread/router_table.hpp +++ b/src/core/thread/router_table.hpp @@ -338,6 +338,12 @@ public: */ IteratorBuilder Iterate(void) { return IteratorBuilder(GetInstance()); } +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + void GetRouterIdRange(uint8_t &aMinRouterId, uint8_t &aMaxRouterId) const; + + Error SetRouterIdRange(uint8_t aMinRouterId, uint8_t aMaxRouterId); +#endif + private: class IteratorBuilder : public InstanceLocator { @@ -369,6 +375,10 @@ private: TimeMilli mRouterIdSequenceLastUpdated; uint8_t mRouterIdSequence; uint8_t mActiveRouterCount; +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + uint8_t mMinRouterId; + uint8_t mMaxRouterId; +#endif }; } // namespace ot diff --git a/tests/scripts/thread-cert/backbone/test_dua_routing.py b/tests/scripts/thread-cert/backbone/test_dua_routing.py index 11cd8e5e0..51b88fafc 100644 --- a/tests/scripts/thread-cert/backbone/test_dua_routing.py +++ b/tests/scripts/thread-cert/backbone/test_dua_routing.py @@ -70,6 +70,7 @@ class TestNdProxy(thread_cert.TestCase): 'is_otbr': True, 'version': '1.2', 'channel': CH1, + 'router_id_range': [0, 30], }, SBBR: { 'name': 'SBBR', @@ -93,6 +94,7 @@ class TestNdProxy(thread_cert.TestCase): 'is_otbr': True, 'version': '1.2', 'channel': CH2, + 'router_id_range': [31, 60], }, ROUTER2: { 'name': 'ROUTER2', diff --git a/tests/scripts/thread-cert/node.py b/tests/scripts/thread-cert/node.py index a13b314d7..ae4411df7 100755 --- a/tests/scripts/thread-cert/node.py +++ b/tests/scripts/thread-cert/node.py @@ -2954,6 +2954,17 @@ class NodeImpl: return rxtx_list + def set_router_id_range(self, min_router_id: int, max_router_id: int): + cmd = f'routeridrange {min_router_id} {max_router_id}' + self.send_command(cmd) + self._expect_command_output() + + def get_router_id_range(self): + cmd = 'routeridrange' + self.send_command(cmd) + line = self._expect_command_output()[0] + return [int(item) for item in line.split()] + class Node(NodeImpl, OtCli): pass diff --git a/tests/scripts/thread-cert/thread_cert.py b/tests/scripts/thread-cert/thread_cert.py index 0695e5f7a..355b44277 100755 --- a/tests/scripts/thread-cert/thread_cert.py +++ b/tests/scripts/thread-cert/thread_cert.py @@ -230,6 +230,9 @@ class TestCase(NcpSupportMixin, unittest.TestCase): if 'bbr_registration_jitter' in params: self.nodes[i].set_bbr_registration_jitter(params['bbr_registration_jitter']) + if 'router_id_range' in params: + self.nodes[i].set_router_id_range(params['router_id_range'][0], params['router_id_range'][1]) + # we have to add allowlist after nodes are all created for i, params in initial_topology.items(): allowlist = params['allowlist']