From fd402bfb177c4ad861a8337c38fbd96d1b98eb8d 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 12a5066d16..8e0d219e66 100644 --- a/components/openthread/Kconfig +++ b/components/openthread/Kconfig @@ -249,7 +249,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. @@ -299,7 +299,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 @@ -508,6 +508,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 82d474aff8..32a3a33795 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 f631a157d5..1d3997c7e1 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 311617f6a0..61f3ceae2d 100644 --- a/components/openthread/src/esp_openthread.cpp +++ b/components/openthread/src/esp_openthread.cpp @@ -253,7 +253,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)))); @@ -285,7 +285,7 @@ static void ot_task_worker(void *aContext) esp_openthread_cli_console_command_unregister(); #endif // CONFIG_OPENTHREAD_CLI -#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 35dd8db149..fc371d4849 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 c3724773bd..d106d39778 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 4d6c2fab63..bae3a44fa8 100644 --- a/components/openthread/srcs_ftd_mtd.cmake +++ b/components/openthread/srcs_ftd_mtd.cmake @@ -107,6 +107,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 49652ce314eb1d7e4a69ac95d91fafb5516307b6 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 | 11 ++-- 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 | 62 ++++++++++++++++++- 6 files changed, 80 insertions(+), 7 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 61f3ceae2d..3ca5d46527 100644 --- a/components/openthread/src/esp_openthread.cpp +++ b/components/openthread/src/esp_openthread.cpp @@ -182,6 +182,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 2773b85c31..cde15f9153 100644 --- a/examples/openthread/ot_ci_function.py +++ b/examples/openthread/ot_ci_function.py @@ -185,7 +185,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) @@ -198,16 +198,16 @@ 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) def hardreset_dut(dut: IdfDut) -> None: dut.serial.hard_reset() - dut.expect('OpenThread attached to netif', timeout=20) + dut.expect('OpenThread enter mainloop', timeout=20) execute_command(dut, 'factoryreset') - dut.expect('OpenThread attached to netif', timeout=20) + dut.expect('OpenThread enter mainloop', timeout=20) # get the mleid address of the thread @@ -461,7 +461,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 44a7d1abe8..0d49da7ef5 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 0000000000..6d7624ee6c --- /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 0bca5c2987..6123273f4a 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 38b4c7b5c2..4668b3593a 100644 --- a/examples/openthread/pytest_otbr.py +++ b/examples/openthread/pytest_otbr.py @@ -121,6 +121,16 @@ PORT_MAPPING = {'ESPPORT1': 'esp32h2', 'ESPPORT2': 'esp32s3', 'ESPPORT3': 'esp32 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, @@ -204,6 +214,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, ) @@ -264,6 +284,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, ) @@ -317,6 +347,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, ) @@ -371,6 +411,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, ) @@ -432,6 +482,16 @@ def test_service_discovery_of_Thread_device( 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, ) @@ -717,7 +777,7 @@ def test_ot_sleepy_device(dut: tuple[IdfDut, IdfDut]) -> None: finally: logging.info('Cleaning up...') ocf.execute_command(leader, 'factoryreset') - leader.expect('OpenThread attached to netif', timeout=20) + leader.expect('OpenThread enter mainloop', timeout=20) ocf.hardreset_dut(sleepy_device) time.sleep(3)