From 144de2096022d9ec294c9afe469a29380eb198b3 Mon Sep 17 00:00:00 2001 From: "Zhibin (Ryan) Wen" Date: Tue, 24 Mar 2026 15:32:27 +0800 Subject: [PATCH 1/2] feat(openthread): make esp_netif glue optional Signed-off-by: Zhibin (Ryan) Wen --- components/openthread/Kconfig | 13 ++++++++-- .../openthread-core-esp32x-ftd-config.h | 25 +++++++++++-------- .../openthread-core-esp32x-mtd-config.h | 25 +++++++++++-------- components/openthread/src/esp_openthread.cpp | 4 +-- .../src/esp_openthread_netif_glue.c | 2 -- .../src/port/esp_openthread_state.c | 2 ++ components/openthread/srcs_ftd_mtd.cmake | 6 +++++ 7 files changed, 51 insertions(+), 26 deletions(-) diff --git a/components/openthread/Kconfig b/components/openthread/Kconfig index bc0300874be..a6e7597bc96 100644 --- a/components/openthread/Kconfig +++ b/components/openthread/Kconfig @@ -243,7 +243,7 @@ menu "OpenThread" config OPENTHREAD_BORDER_ROUTER bool "Enable Border Router" - depends on OPENTHREAD_FTD + depends on OPENTHREAD_FTD && OPENTHREAD_PLATFORM_NETIF default n help Select this option to enable border router features in OpenThread. @@ -293,7 +293,7 @@ menu "OpenThread" config OPENTHREAD_DNS64_CLIENT bool "Enable DNS64 Client" - depends on LWIP_IPV4 + depends on LWIP_IPV4 && OPENTHREAD_PLATFORM_NETIF select LWIP_HOOK_DNS_EXTERNAL_RESOLVE_SELECT_CUSTOM default n help @@ -502,6 +502,15 @@ menu "OpenThread" failure. endmenu + config OPENTHREAD_PLATFORM_NETIF + bool "Enable esp_netif/lwIP glue" + depends on OPENTHREAD_FTD || OPENTHREAD_MTD + default y + help + Enable the default ESP-IDF OpenThread integration which creates an + OpenThread esp_netif, attaches the esp_netif glue, and enables + lwIP-specific DNS/netif handling. + endmenu menu "Thread Log" diff --git a/components/openthread/private_include/openthread-core-esp32x-ftd-config.h b/components/openthread/private_include/openthread-core-esp32x-ftd-config.h index 6b722ba10e6..1512054f133 100644 --- a/components/openthread/private_include/openthread-core-esp32x-ftd-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-ftd-config.h @@ -454,6 +454,21 @@ #endif #define OPENTHREAD_CONFIG_PARENT_SEARCH_RSS_MARGIN CONFIG_OPENTHREAD_PARENT_SEARCH_RSS_MARGIN +/** + * @def OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE + * + * Define to 1 to enable platform NETIF support. + * + */ +#ifdef OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE +#error `OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE` is redefined. +#endif +#ifdef CONFIG_OPENTHREAD_PLATFORM_NETIF +#ifndef OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE +#define OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE 1 +#endif +#endif + /*----The following options set fixed default values but can be overridden by the user header file.----*/ #if CONFIG_OPENTHREAD_BORDER_ROUTER @@ -703,16 +718,6 @@ #define OPENTHREAD_CONFIG_COAP_API_ENABLE 1 #endif -/** - * @def OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE - * - * Define to 1 to enable platform NETIF support. - * - */ -#ifndef OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE -#define OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE 1 -#endif - /** * @def OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE * diff --git a/components/openthread/private_include/openthread-core-esp32x-mtd-config.h b/components/openthread/private_include/openthread-core-esp32x-mtd-config.h index e6e9af61b20..f5cb2b02cc3 100644 --- a/components/openthread/private_include/openthread-core-esp32x-mtd-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-mtd-config.h @@ -245,6 +245,21 @@ #endif #define OPENTHREAD_CONFIG_MAC_MAX_CSMA_BACKOFFS_DIRECT CONFIG_OPENTHREAD_MAC_MAX_CSMA_BACKOFFS_DIRECT +/** + * @def OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE + * + * Define to 1 to enable platform NETIF support. + * + */ +#ifdef OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE +#error `OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE` is redefined. +#endif +#ifdef CONFIG_OPENTHREAD_PLATFORM_NETIF +#ifndef OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE +#define OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE 1 +#endif +#endif + /*----The following options set fixed default values but can be overridden by the user header file.----*/ /** @@ -257,16 +272,6 @@ #define OPENTHREAD_CONFIG_COAP_API_ENABLE 1 #endif -/** - * @def OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE - * - * Define to 1 to enable platform NETIF support. - * - */ -#ifndef OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE -#define OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE 1 -#endif - /** * @def OPENTHREAD_CONFIG_PLATFORM_ASSERT_MANAGEMENT * diff --git a/components/openthread/src/esp_openthread.cpp b/components/openthread/src/esp_openthread.cpp index 22802fc3e23..d0793dd4399 100644 --- a/components/openthread/src/esp_openthread.cpp +++ b/components/openthread/src/esp_openthread.cpp @@ -239,7 +239,7 @@ static void ot_task_worker(void *aContext) // Initialize the OpenThread stack ESP_ERROR_CHECK(esp_openthread_init(&(config->platform_config))); -#if CONFIG_OPENTHREAD_FTD || CONFIG_OPENTHREAD_MTD +#if CONFIG_OPENTHREAD_PLATFORM_NETIF esp_netif_t *openthread_netif = esp_netif_new(&(config->netif_config)); assert(openthread_netif != NULL); ESP_ERROR_CHECK(esp_netif_attach(openthread_netif, esp_openthread_netif_glue_init(&(config->platform_config)))); @@ -270,7 +270,7 @@ static void ot_task_worker(void *aContext) // esp_openthread_cli_console_command_unregister is not provided on idf 5.2 -#if CONFIG_OPENTHREAD_FTD || CONFIG_OPENTHREAD_MTD +#if CONFIG_OPENTHREAD_PLATFORM_NETIF // Clean up esp_openthread_netif_glue_deinit(); esp_netif_destroy(openthread_netif); diff --git a/components/openthread/src/esp_openthread_netif_glue.c b/components/openthread/src/esp_openthread_netif_glue.c index c49a2604073..3af3cfd850a 100644 --- a/components/openthread/src/esp_openthread_netif_glue.c +++ b/components/openthread/src/esp_openthread_netif_glue.c @@ -46,8 +46,6 @@ static esp_openthread_netif_glue_t s_openthread_netif_glue = { .event_fd = -1, }; -ESP_EVENT_DEFINE_BASE(OPENTHREAD_EVENT); - static QueueHandle_t s_packet_queue; static esp_netif_t *s_openthread_netif; static const char *netif_glue_workflow = "netif_glue"; diff --git a/components/openthread/src/port/esp_openthread_state.c b/components/openthread/src/port/esp_openthread_state.c index c3724773bd2..d106d397782 100644 --- a/components/openthread/src/port/esp_openthread_state.c +++ b/components/openthread/src/port/esp_openthread_state.c @@ -21,6 +21,8 @@ #define TAG "OT_STATE" +ESP_EVENT_DEFINE_BASE(OPENTHREAD_EVENT); + #if CONFIG_OPENTHREAD_BORDER_ROUTER static void handle_ot_border_router_state_changed(otInstance* instance) { diff --git a/components/openthread/srcs_ftd_mtd.cmake b/components/openthread/srcs_ftd_mtd.cmake index d486b03718f..90a9c0c1ecf 100644 --- a/components/openthread/srcs_ftd_mtd.cmake +++ b/components/openthread/srcs_ftd_mtd.cmake @@ -105,6 +105,12 @@ if(NOT CONFIG_OPENTHREAD_DNS64_CLIENT) "src/esp_openthread_dns64.c") endif() +if(NOT CONFIG_OPENTHREAD_PLATFORM_NETIF) + list(APPEND exclude_srcs + "src/esp_openthread_lwip_netif.c" + "src/esp_openthread_netif_glue.c") +endif() + if(NOT CONFIG_FREERTOS_USE_TICKLESS_IDLE) list(APPEND exclude_srcs "src/port/esp_openthread_sleep.c") From 7c4bae2183d975f21153912013683175a42843c8 Mon Sep 17 00:00:00 2001 From: "Zhibin (Ryan) Wen" Date: Tue, 24 Mar 2026 19:58:04 +0800 Subject: [PATCH 2/2] feat(openthread): add test support for esp_netif glue disabled scenario Signed-off-by: Zhibin (Ryan) Wen --- components/openthread/src/esp_openthread.cpp | 1 + examples/openthread/ot_ci_function.py | 7 ++- examples/openthread/ot_cli/main/esp_ot_cli.c | 4 ++ .../sdkconfig.ci.cli_disable_platform_netif | 2 + .../ot_examples_common/Kconfig.projbuild | 7 ++- examples/openthread/pytest_otbr.py | 60 +++++++++++++++++++ 6 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 examples/openthread/ot_cli/sdkconfig.ci.cli_disable_platform_netif diff --git a/components/openthread/src/esp_openthread.cpp b/components/openthread/src/esp_openthread.cpp index d0793dd4399..04b6bee4b2b 100644 --- a/components/openthread/src/esp_openthread.cpp +++ b/components/openthread/src/esp_openthread.cpp @@ -181,6 +181,7 @@ esp_err_t esp_openthread_mainloop_exit(void) esp_err_t esp_openthread_launch_mainloop(void) { + ESP_LOGI(OT_PLAT_LOG_TAG, "OpenThread enter mainloop"); esp_openthread_mainloop_context_t mainloop; otInstance *instance = esp_openthread_get_instance(); esp_err_t error = ESP_OK; diff --git a/examples/openthread/ot_ci_function.py b/examples/openthread/ot_ci_function.py index d4a55198603..54e057215d0 100644 --- a/examples/openthread/ot_ci_function.py +++ b/examples/openthread/ot_ci_function.py @@ -188,7 +188,7 @@ def getDataset(dut: IdfDut) -> str: def init_thread(dut: IdfDut) -> None: - dut.expect('OpenThread attached to netif', timeout=10) + dut.expect('OpenThread enter mainloop', timeout=10) wait(dut, 3) reset_thread(dut) @@ -201,7 +201,7 @@ def stop_thread(dut: IdfDut) -> None: def reset_thread(dut: IdfDut) -> None: execute_command(dut, 'factoryreset') - dut.expect('OpenThread attached to netif', timeout=20) + dut.expect('OpenThread enter mainloop', timeout=20) wait(dut, 3) clean_buffer(dut) @@ -463,7 +463,8 @@ def check_ipmaddr(dut: IdfDut) -> bool: def thread_is_joined_group(dut: IdfDut) -> bool: - command = 'mcast join ' + thread_ipv6_group + should_use_mcast = dut.app.sdkconfig.get('OPENTHREAD_PLATFORM_NETIF') is True + command = ('mcast join ' if should_use_mcast else 'ipmaddr add ') + thread_ipv6_group execute_command(dut, command) dut.expect('Done', timeout=5) order = 0 diff --git a/examples/openthread/ot_cli/main/esp_ot_cli.c b/examples/openthread/ot_cli/main/esp_ot_cli.c index 44a7d1abe80..0d49da7ef59 100644 --- a/examples/openthread/ot_cli/main/esp_ot_cli.c +++ b/examples/openthread/ot_cli/main/esp_ot_cli.c @@ -53,7 +53,9 @@ void app_main(void) ESP_ERROR_CHECK(nvs_flash_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); +#if CONFIG_OPENTHREAD_PLATFORM_NETIF ESP_ERROR_CHECK(esp_netif_init()); +#endif ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config)); #if CONFIG_OPENTHREAD_CLI @@ -62,7 +64,9 @@ void app_main(void) #endif static esp_openthread_config_t config = { +#if CONFIG_OPENTHREAD_PLATFORM_NETIF .netif_config = ESP_NETIF_DEFAULT_OPENTHREAD(), +#endif .platform_config = { .radio_config = ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG(), .host_config = ESP_OPENTHREAD_DEFAULT_HOST_CONFIG(), diff --git a/examples/openthread/ot_cli/sdkconfig.ci.cli_disable_platform_netif b/examples/openthread/ot_cli/sdkconfig.ci.cli_disable_platform_netif new file mode 100644 index 00000000000..6d7624ee6c9 --- /dev/null +++ b/examples/openthread/ot_cli/sdkconfig.ci.cli_disable_platform_netif @@ -0,0 +1,2 @@ +CONFIG_OPENTHREAD_PLATFORM_NETIF=n +CONFIG_OPENTHREAD_CLI_ESP_EXTENSION=n diff --git a/examples/openthread/ot_common_components/ot_examples_common/Kconfig.projbuild b/examples/openthread/ot_common_components/ot_examples_common/Kconfig.projbuild index 0bca5c29871..6123273f4a0 100644 --- a/examples/openthread/ot_common_components/ot_examples_common/Kconfig.projbuild +++ b/examples/openthread/ot_common_components/ot_examples_common/Kconfig.projbuild @@ -12,7 +12,12 @@ menu "Config for OpenThread Examples" menu "External Console Commands" config OPENTHREAD_IPERF_CMD_ENABLE bool "Enable iperf command" - depends on OPENTHREAD_FTD || OPENTHREAD_MTD + # TODO: Make this option depend on LWIP_ENABLE in the future. + # Currently, LWIP_ENABLE cannot be set to `n` because the OpenThread component makes MbedTLS a hard + # dependency. + # This is a known limitation of the ESP-IDF (<6) build system (component requirements are expanded + # before configuration is loaded). + depends on OPENTHREAD_PLATFORM_NETIF default y help If enabled, iperf will be registered and available as a console command. diff --git a/examples/openthread/pytest_otbr.py b/examples/openthread/pytest_otbr.py index c4fc9417a17..25459dd225b 100644 --- a/examples/openthread/pytest_otbr.py +++ b/examples/openthread/pytest_otbr.py @@ -123,6 +123,16 @@ PORT_MAPPING = { f'{ESPPORT3}|{ESPPORT1}|{ESPPORT2}', id='c6-h2-s3' ), + pytest.param( + 'rcp_uart|cli_disable_platform_netif|br', + 3, + f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}' + f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}' + f'|{os.path.join(os.path.dirname(__file__), "ot_br")}', + 'esp32c6|esp32h2|esp32s3', + f'{ESPPORT3}|{ESPPORT1}|{ESPPORT2}', + id='c6-h2_disable_platform_netif-s3', + ), pytest.param( 'rcp_spi|cli|br_spi', 3, @@ -207,6 +217,16 @@ def formBasicWiFiThreadNetwork(br:IdfDut, cli:IdfDut) -> None: f'{ESPPORT3}|{ESPPORT1}|{ESPPORT2}', id='c6-h2-s3' ), + pytest.param( + 'rcp_uart|cli_disable_platform_netif|br', + 3, + f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}' + f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}' + f'|{os.path.join(os.path.dirname(__file__), "ot_br")}', + 'esp32c6|esp32h2|esp32s3', + f'{ESPPORT3}|{ESPPORT1}|{ESPPORT2}', + id='c6-h2_disable_platform_netif-s3', + ), ], indirect=True, ) @@ -268,6 +288,16 @@ def test_Bidirectional_IPv6_connectivity(Init_interface:bool, dut: Tuple[IdfDut, f'{ESPPORT3}|{ESPPORT1}|{ESPPORT2}', id='c6-h2-s3' ), + pytest.param( + 'rcp_uart|cli_disable_platform_netif|br', + 3, + f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}' + f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}' + f'|{os.path.join(os.path.dirname(__file__), "ot_br")}', + 'esp32c6|esp32h2|esp32s3', + f'{ESPPORT3}|{ESPPORT1}|{ESPPORT2}', + id='c6-h2_disable_platform_netif-s3', + ), ], indirect=True, ) @@ -322,6 +352,16 @@ def test_multicast_forwarding_A(Init_interface:bool, dut: Tuple[IdfDut, IdfDut, f'{ESPPORT3}|{ESPPORT1}|{ESPPORT2}', id='c6-h2-s3' ), + pytest.param( + 'rcp_uart|cli_disable_platform_netif|br', + 3, + f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}' + f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}' + f'|{os.path.join(os.path.dirname(__file__), "ot_br")}', + 'esp32c6|esp32h2|esp32s3', + f'{ESPPORT3}|{ESPPORT1}|{ESPPORT2}', + id='c6-h2_disable_platform_netif-s3', + ), ], indirect=True, ) @@ -377,6 +417,16 @@ def test_multicast_forwarding_B(Init_interface:bool, dut: Tuple[IdfDut, IdfDut, f'{ESPPORT3}|{ESPPORT1}|{ESPPORT2}', id='c6-h2-s3' ), + pytest.param( + 'rcp_uart|cli_disable_platform_netif|br', + 3, + f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}' + f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}' + f'|{os.path.join(os.path.dirname(__file__), "ot_br")}', + 'esp32c6|esp32h2|esp32s3', + f'{ESPPORT3}|{ESPPORT1}|{ESPPORT2}', + id='c6-h2_disable_platform_netif-s3', + ), ], indirect=True, ) @@ -437,6 +487,16 @@ def test_service_discovery_of_Thread_device(Init_interface:bool, Init_avahi:bool f'{ESPPORT3}|{ESPPORT1}|{ESPPORT2}', id='c6-h2-s3' ), + pytest.param( + 'rcp_uart|cli_disable_platform_netif|br', + 3, + f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}' + f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}' + f'|{os.path.join(os.path.dirname(__file__), "ot_br")}', + 'esp32c6|esp32h2|esp32s3', + f'{ESPPORT3}|{ESPPORT1}|{ESPPORT2}', + id='c6-h2_disable_platform_netif-s3', + ), ], indirect=True, )