From a0c332b2a2c4a4acef823550aa2281c5d990c08f Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 17 Mar 2026 17:24:47 -0700 Subject: [PATCH] [ip6] add `otIp6Init()` to configure external address pools (#12603) This commit introduces the `OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE` configuration and the `otIp6Init()` API. When enabled, this feature allows the OpenThread stack to use externally provided memory buffers for its external unicast and multicast address pools. By decoupling the pool sizes from build-time configurations (`OPENTHREAD_CONFIG_IP6_MAX_EXT_UCAST_ADDRS` and `OPENTHREAD_CONFIG_IP6_MAX_EXT_MCAST_ADDRS`), the OpenThread stack can be compiled as a generic library without hardcoding the address pool sizes. It delegates the memory allocation and configuration to the application layer at run-time. When the feature is enabled, `otIp6Init()` must be invoked to initialize the `Netif` address pools before calling `otIp6SetEnabled()`. --- etc/cmake/options.cmake | 1 + include/openthread/instance.h | 2 +- include/openthread/ip6.h | 51 +++++++++++++++- src/cli/cli.cpp | 61 +++++++++++++++++++ src/cli/cli.hpp | 5 ++ src/cli/cli_config.h | 13 ++++ src/core/api/ip6_api.cpp | 20 +++++- src/core/config/ip6.h | 22 +++++++ src/core/net/netif.cpp | 23 +++++++ src/core/net/netif.hpp | 42 ++++++++++++- .../openthread-core-toranj-config-posix.h | 4 ++ ...openthread-core-toranj-config-simulation.h | 2 + 12 files changed, 237 insertions(+), 9 deletions(-) diff --git a/etc/cmake/options.cmake b/etc/cmake/options.cmake index 09325a55e..576365496 100644 --- a/etc/cmake/options.cmake +++ b/etc/cmake/options.cmake @@ -218,6 +218,7 @@ ot_option(OT_EXTERNAL_HEAP OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE "external heap ot_option(OT_FIREWALL OPENTHREAD_POSIX_CONFIG_FIREWALL_ENABLE "firewall") ot_option(OT_HISTORY_TRACKER OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE "history tracker") ot_option(OT_IP6_FRAGM OPENTHREAD_CONFIG_IP6_FRAGMENTATION_ENABLE "ipv6 fragmentation") +ot_option(OT_IP6_INIT_ADDR_POOL OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE "IPv6 init address pool") ot_option(OT_JAM_DETECTION OPENTHREAD_CONFIG_JAM_DETECTION_ENABLE "jam detection") ot_option(OT_JOINER OPENTHREAD_CONFIG_JOINER_ENABLE "joiner") ot_option(OT_LINK_METRICS_INITIATOR OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE "link metrics initiator") diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 0747e1027..1b9ee3389 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -52,7 +52,7 @@ extern "C" { * * @note This number versions both OpenThread platform and user APIs. */ -#define OPENTHREAD_API_VERSION (581) +#define OPENTHREAD_API_VERSION (582) /** * @addtogroup api-instance diff --git a/include/openthread/ip6.h b/include/openthread/ip6.h index f6a9d3ed5..0d9be5f3c 100644 --- a/include/openthread/ip6.h +++ b/include/openthread/ip6.h @@ -264,17 +264,59 @@ enum OT_IP6_PROTO_DST_OPTS = 60, ///< Destination Options for IPv6 }; +/** + * Initializes the IPv6 interface and its external address pools. + * + * Requires `OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE`. + * + * It provides the memory buffers for the external unicast and multicast address pools and must be called before + * enabling the IPv6 interface. + * + * The provided memory buffers MUST persist and remain valid as long as the OpenThread instance is initialized. + * OpenThread will use these provided buffers to manage the pools of externally added unicast and multicast + * addresses (i.e., those added via `otIp6AddUnicastAddress()` and `otIp6SubscribeMulticastAddress()`). + * + * This function can only be called once. Subsequent calls will return `OT_ERROR_ALREADY`. + * + * The `OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE` feature and this function allow the external unicast/multicast + * address pools to be configured at run-time after OpenThread instance initialization, rather than build-time. + * When this feature is disabled, the build-time configs `OPENTHREAD_CONFIG_IP6_MAX_EXT_UCAST_ADDRS` and + * `OPENTHREAD_CONFIG_IP6_MAX_EXT_MCAST_ADDRS` specify the pool sizes used by the OpenThread stack. + * + * This feature allows the OpenThread stack to be compiled as a library without specifying the address pool sizes. + * It delegates the configuration of the pools to the next layer, allowing the OpenThread stack to be integrated into + * various projects without requiring a new OpenThread stack configuration to be built. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aUnicastAddrPool A pointer to an array of `otNetifAddress`. + * @param[in] aUnicastAddrPoolSize The number of entries in @p aUnicastAddrPool. + * @param[in] aMulticastAddrPool A pointer to an array of `otNetifMulticastAddress`. + * @param[in] aMulticastAddrPoolSize The number of entries in @p aMulticastAddrPool. + * + * @retval OT_ERROR_NONE Successfully initialized the IPv6 interface. + * @retval OT_ERROR_ALREADY The IPv6 interface is already initialized. + */ +otError otIp6Init(otInstance *aInstance, + otNetifAddress *aUnicastAddrPool, + uint16_t aUnicastAddrPoolSize, + otNetifMulticastAddress *aMulticastAddrPool, + uint16_t aMulticastAddrPoolSize); + /** * Brings the IPv6 interface up or down. * * Call this to enable or disable IPv6 communication. * + * When `OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE` is enabled, `otIp6Init()` MUST be called prior to calling + * this function. If it is not, this function will return `OT_ERROR_INVALID_STATE`. + * * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aEnabled TRUE to enable IPv6, FALSE otherwise. * * @retval OT_ERROR_NONE Successfully brought the IPv6 interface up/down. * @retval OT_ERROR_INVALID_STATE IPv6 interface is not available since device is operating in raw-link mode - * (applicable only when `OPENTHREAD_CONFIG_LINK_RAW_ENABLE` feature is enabled). + * (applicable only when `OPENTHREAD_CONFIG_LINK_RAW_ENABLE` feature is enabled), + * or not initialized under `OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE`. */ otError otIp6SetEnabled(otInstance *aInstance, bool aEnabled); @@ -292,7 +334,8 @@ bool otIp6IsEnabled(otInstance *aInstance); * Adds a Network Interface Address to the Thread interface. * * The passed-in instance @p aAddress is copied by the Thread interface. The Thread interface only - * supports a fixed number of externally added unicast addresses. See `OPENTHREAD_CONFIG_IP6_MAX_EXT_UCAST_ADDRS`. + * supports a fixed number of externally added unicast addresses. See `OPENTHREAD_CONFIG_IP6_MAX_EXT_UCAST_ADDRS` + * and `OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE`. * * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aAddress A pointer to a Network Interface Address. @@ -339,7 +382,9 @@ bool otIp6HasUnicastAddress(otInstance *aInstance, const otIp6Address *aAddress) * Subscribes the Thread interface to a Network Interface Multicast Address. * * The passed in instance @p aAddress will be copied by the Thread interface. The Thread interface only - * supports a fixed number of externally added multicast addresses. See `OPENTHREAD_CONFIG_IP6_MAX_EXT_MCAST_ADDRS`. + * supports a fixed number of externally added multicast addresses. See `OPENTHREAD_CONFIG_IP6_MAX_EXT_MCAST_ADDRS` + * and `OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE`. + * * * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aAddress A pointer to an IP Address. diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index f099b2540..223a2aa1f 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -3316,6 +3317,12 @@ template <> otError Interpreter::Process(Arg aArgs[]) { SuccessOrExit(error = otIp6SetEnabled(GetInstancePtr(), false)); } +#if OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE && OPENTHREAD_CONFIG_CLI_IFCONFIG_INIT_ENABLE + else if (aArgs[0] == "init") + { + error = ProcessIfconfigInit(aArgs + 1); + } +#endif else { ExitNow(error = OT_ERROR_INVALID_ARGS); @@ -3325,6 +3332,60 @@ exit: return error; } +#if OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE && OPENTHREAD_CONFIG_CLI_IFCONFIG_INIT_ENABLE + +otError Interpreter::ProcessIfconfigInit(Arg aArgs[]) +{ + /** + * @cli ifconfig init + * @code + * ifconfig init 5 6 + * Done + * @endcode + * @cparam ifconfig @ca{unicast-addr-pool-size} @ca{multicast-addr-pool-size} + * @par + * This command is intended for testing purposes only and requires `OPENTHREAD_CONFIG_CLI_IFCONFIG_INIT_ENABLE` + * and `OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE`. + * @par api_copy + * #otIp6Init + */ + + otError error; + uint16_t unicastPoolSize; + uint16_t multicastPoolSize; + otNetifAddress *unicastPool = nullptr; + otNetifMulticastAddress *multicastPool = nullptr; + + SuccessOrExit(error = aArgs[0].ParseAsUint16(unicastPoolSize)); + SuccessOrExit(error = aArgs[1].ParseAsUint16(multicastPoolSize)); + VerifyOrExit(aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS); + + if (unicastPoolSize > 0) + { + unicastPool = static_cast(otHeapCAlloc(unicastPoolSize, sizeof(otNetifAddress))); + VerifyOrExit(unicastPool != nullptr, error = OT_ERROR_NO_BUFS); + } + + if (multicastPoolSize > 0) + { + multicastPool = + static_cast(otHeapCAlloc(multicastPoolSize, sizeof(otNetifMulticastAddress))); + VerifyOrExit(multicastPool != nullptr, error = OT_ERROR_NO_BUFS); + } + + SuccessOrExit(error = otIp6Init(GetInstancePtr(), unicastPool, unicastPoolSize, multicastPool, multicastPoolSize)); + unicastPool = nullptr; + multicastPool = nullptr; + +exit: + otHeapFree(unicastPool); + otHeapFree(multicastPool); + + return error; +} + +#endif // OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE && OPENTHREAD_CONFIG_CLI_IFCONFIG_INIT_ENABLE + template <> otError Interpreter::Process(Arg aArgs[]) { /** diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index 1beb7332e..0ec85fbbb 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -228,6 +228,11 @@ private: #if OPENTHREAD_FTD void OutputEidCacheEntry(const otCacheEntryInfo &aEntry); #endif + +#if OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE && OPENTHREAD_CONFIG_CLI_IFCONFIG_INIT_ENABLE + otError ProcessIfconfigInit(Arg aArgs[]); +#endif + #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE static void HandleLocateResult(void *aContext, otError aError, diff --git a/src/cli/cli_config.h b/src/cli/cli_config.h index 159ec4bba..f5d9e3f06 100644 --- a/src/cli/cli_config.h +++ b/src/cli/cli_config.h @@ -69,6 +69,19 @@ #define OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE 1 #endif +/** + * @def OPENTHREAD_CONFIG_CLI_IFCONFIG_INIT_ENABLE + * + * Indicates whether or not the CLI `ifconfig init` command to be supported. + * + * This is applicable when `OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE` is used. + * + * The `ifconfig init` is intended for testing purposes only. + */ +#ifndef OPENTHREAD_CONFIG_CLI_IFCONFIG_INIT_ENABLE +#define OPENTHREAD_CONFIG_CLI_IFCONFIG_INIT_ENABLE 0 +#endif + /** * @def OPENTHREAD_CONFIG_CLI_TCP_ENABLE * diff --git a/src/core/api/ip6_api.cpp b/src/core/api/ip6_api.cpp index 7e05a6cb1..1e9adcc1b 100644 --- a/src/core/api/ip6_api.cpp +++ b/src/core/api/ip6_api.cpp @@ -37,11 +37,27 @@ using namespace ot; +#if OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE +otError otIp6Init(otInstance *aInstance, + otNetifAddress *aUnicastAddrPool, + uint16_t aUnicastAddrPoolSize, + otNetifMulticastAddress *aMulticastAddrPool, + uint16_t aMulticastAddrPoolSize) +{ + return AsCoreType(aInstance).Get().Init(AsCoreTypePtr(aUnicastAddrPool), aUnicastAddrPoolSize, + AsCoreTypePtr(aMulticastAddrPool), aMulticastAddrPoolSize); +} +#endif + otError otIp6SetEnabled(otInstance *aInstance, bool aEnabled) { Error error = kErrorNone; Instance &instance = AsCoreType(aInstance); +#if OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE + VerifyOrExit(instance.Get().IsInitialized(), error = kErrorInvalidState); +#endif + #if OPENTHREAD_CONFIG_LINK_RAW_ENABLE VerifyOrExit(!instance.Get().IsEnabled(), error = kErrorInvalidState); #endif @@ -55,9 +71,9 @@ otError otIp6SetEnabled(otInstance *aInstance, bool aEnabled) instance.Get().Down(); } -#if OPENTHREAD_CONFIG_LINK_RAW_ENABLE + ExitNow(); + exit: -#endif return error; } diff --git a/src/core/config/ip6.h b/src/core/config/ip6.h index 6a158ee8f..eb8a54d36 100644 --- a/src/core/config/ip6.h +++ b/src/core/config/ip6.h @@ -46,10 +46,30 @@ #include "config/border_routing.h" #include "config/misc.h" +/** + * @def OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE + * + * Define as 1 to enable feature to require Thread Network interface initialization which allows configuring + * the external unicast/multicast address pool used by the OpenThread stack. + * + * This feature allows the OpenThread stack to be compiled as a library without specifying the address pool sizes. + * It delegates the configuration of the pools to the next layer, making it run-time configurable after OpenThread + * instance initialization. This allows the OpenThread stack to be integrated into various projects without requiring a + * new OpenThread stack configuration to be built. + * + * When this feature is enabled, the configs `OPENTHREAD_CONFIG_IP6_MAX_EXT_UCAST_ADDRS` and + * `OPENTHREAD_CONFIG_IP6_MAX_EXT_MCAST_ADDRS` are no longer applicable or used. + */ +#ifndef OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE +#define OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE 0 +#endif + /** * @def OPENTHREAD_CONFIG_IP6_MAX_EXT_UCAST_ADDRS * * The maximum number of supported IPv6 addresses allows to be externally added. + * + * If `OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE` is enabled, this config is not used. */ #ifndef OPENTHREAD_CONFIG_IP6_MAX_EXT_UCAST_ADDRS #define OPENTHREAD_CONFIG_IP6_MAX_EXT_UCAST_ADDRS 4 @@ -59,6 +79,8 @@ * @def OPENTHREAD_CONFIG_IP6_MAX_EXT_MCAST_ADDRS * * The maximum number of supported IPv6 multicast addresses allows to be externally added. + * + * If `OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE` is enabled, this config is not used. */ #ifndef OPENTHREAD_CONFIG_IP6_MAX_EXT_MCAST_ADDRS #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE diff --git a/src/core/net/netif.cpp b/src/core/net/netif.cpp index d17567a41..c4a9f5313 100644 --- a/src/core/net/netif.cpp +++ b/src/core/net/netif.cpp @@ -89,9 +89,32 @@ const otNetifMulticastAddress Netif::kLinkLocalAllRoutersMulticastAddress = { Netif::Netif(Instance &aInstance) : InstanceLocator(aInstance) +#if OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE + , mInitialized(false) +#endif { } +#if OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE + +Error Netif::Init(UnicastAddress *aUnicastAddrPool, + uint16_t aUnicastAddrPoolSize, + MulticastAddress *aMulticastAddrPool, + uint16_t aMulticastAddrPoolSize) +{ + Error error = kErrorNone; + + VerifyOrExit(!mInitialized, error = kErrorAlready); + mInitialized = true; + SuccessOrExit(error = mExtUnicastAddressPool.Init(aUnicastAddrPool, aUnicastAddrPoolSize)); + SuccessOrExit(error = mExtMulticastAddressPool.Init(aMulticastAddrPool, aMulticastAddrPoolSize)); + +exit: + return error; +} + +#endif // OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE + bool Netif::IsMulticastSubscribed(const Address &aAddress) const { return mMulticastAddresses.ContainsMatching(aAddress); diff --git a/src/core/net/netif.hpp b/src/core/net/netif.hpp index 1bde35b73..d65e10eaf 100644 --- a/src/core/net/netif.hpp +++ b/src/core/net/netif.hpp @@ -326,6 +326,37 @@ public: */ explicit Netif(Instance &aInstance); +#if OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE + + /** + * Initializes the network interface with external address pools. + * + * It provides the memory buffers to be used for the external unicast and multicast address pools. The provided + * pool memory buffers MUST persist and remain valid as long as the OpenThread instance is initialized. + * + * @param[in] aUnicastAddrPool A pointer to an array of `UnicastAddress` entries. + * @param[in] aUnicastAddrPoolSize The number of entries in @p aUnicastAddrPool. + * @param[in] aMulticastAddrPool A pointer to an array of `MulticastAddress` entries. + * @param[in] aMulticastAddrPoolSize The number of entries in @p aMulticastAddrPool. + * + * @retval kErrorNone Successfully initialized the network interface. + * @retval kErrorAlready The network interface is already initialized. + */ + Error Init(UnicastAddress *aUnicastAddrPool, + uint16_t aUnicastAddrPoolSize, + MulticastAddress *aMulticastAddrPool, + uint16_t aMulticastAddrPoolSize); + + /** + * Indicates whether or not the network interface is initialized. + * + * @retval TRUE If the network interface is initialized. + * @retval FALSE If the network interface is not initialized. + */ + bool IsInitialized(void) const { return mInitialized; } + +#endif // OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE + /** * Registers a callback to notify internal IPv6 address changes. * @@ -582,13 +613,18 @@ private: const MulticastAddress *aStart, const MulticastAddress *aEnd); - LinkedList mUnicastAddresses; - LinkedList mMulticastAddresses; - + LinkedList mUnicastAddresses; + LinkedList mMulticastAddresses; Callback mAddressCallback; +#if OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE + ConfigPool mExtUnicastAddressPool; + ConfigPool mExtMulticastAddressPool; + bool mInitialized; +#else Pool mExtUnicastAddressPool; Pool mExtMulticastAddressPool; +#endif static const otNetifMulticastAddress kRealmLocalAllMplForwardersMulticastAddress; static const otNetifMulticastAddress kLinkLocalAllNodesMulticastAddress; diff --git a/tests/toranj/openthread-core-toranj-config-posix.h b/tests/toranj/openthread-core-toranj-config-posix.h index 7324a9556..f7c67682f 100644 --- a/tests/toranj/openthread-core-toranj-config-posix.h +++ b/tests/toranj/openthread-core-toranj-config-posix.h @@ -38,6 +38,10 @@ #define OPENTHREAD_CONFIG_PLATFORM_INFO "POSIX-toranj" +#define OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE 1 + +#define OPENTHREAD_CONFIG_CLI_IFCONFIG_INIT_ENABLE 1 + #define OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE 1 #define OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE 1 diff --git a/tests/toranj/openthread-core-toranj-config-simulation.h b/tests/toranj/openthread-core-toranj-config-simulation.h index 9e08676fa..b85ab97af 100644 --- a/tests/toranj/openthread-core-toranj-config-simulation.h +++ b/tests/toranj/openthread-core-toranj-config-simulation.h @@ -43,6 +43,8 @@ #define OPENTHREAD_CONFIG_PLATFORM_INFO "SIMULATION-toranj" #endif +#define OPENTHREAD_CONFIG_IP6_INIT_EXT_ADDR_POOL_ENABLE 0 + #define OPENTHREAD_CONFIG_HISTORY_TRACKER_SERVER_ENABLE 1 #define OPENTHREAD_CONFIG_HISTORY_TRACKER_CLIENT_ENABLE 1