feat(esp_netif): Add support for initial MTU in netif config

Closes https://github.com/espressif/esp-idf/issues/15319
This commit is contained in:
David Cermak
2025-09-22 16:36:49 +02:00
parent fdd86721e7
commit 4c69bf826f
8 changed files with 105 additions and 23 deletions
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -52,7 +52,8 @@ extern "C" {
.if_key = "WIFI_STA_DEF", \
.if_desc = "sta", \
.route_prio = 100, \
.bridge_info = NULL \
.bridge_info = NULL, \
.mtu = 0 \
} \
#ifdef CONFIG_ESP_WIFI_SOFTAP_SUPPORT
@@ -66,7 +67,8 @@ extern "C" {
.if_key = "WIFI_AP_DEF", \
.if_desc = "ap", \
.route_prio = 10, \
.bridge_info = NULL \
.bridge_info = NULL, \
.mtu = 0 \
}
#endif
@@ -79,7 +81,8 @@ extern "C" {
.lost_ip_event = 0, \
.if_key = "WIFI_NAN_DEF", \
.if_desc = "nan", \
.route_prio = 10 \
.route_prio = 10, \
.mtu = 0 \
};
#define ESP_NETIF_INHERENT_DEFAULT_ETH() \
@@ -92,7 +95,8 @@ extern "C" {
.if_key = "ETH_DEF", \
.if_desc = "eth", \
.route_prio = 50, \
.bridge_info = NULL \
.bridge_info = NULL, \
.mtu = 0 \
}
#ifdef CONFIG_PPP_SUPPORT
@@ -106,7 +110,8 @@ extern "C" {
.if_key = "PPP_DEF", \
.if_desc = "ppp", \
.route_prio = 20, \
.bridge_info = NULL \
.bridge_info = NULL, \
.mtu = 0 \
}
#endif /* CONFIG_PPP_SUPPORT */
@@ -120,7 +125,8 @@ extern "C" {
.if_key = "BR0", \
.if_desc = "br0", \
.route_prio = 70, \
.bridge_info = NULL \
.bridge_info = NULL, \
.mtu = 0 \
}
#define ESP_NETIF_INHERENT_DEFAULT_BR_DHCPS() \
@@ -133,7 +139,8 @@ extern "C" {
.if_key = "BR1", \
.if_desc = "br1", \
.route_prio = 70, \
.bridge_info = NULL \
.bridge_info = NULL, \
.mtu = 0 \
}
/**
@@ -255,6 +255,7 @@ typedef struct esp_netif_inherent_config {
A higher value of route_prio indicates
a higher priority */
bridgeif_config_t *bridge_info; /*!< LwIP bridge configuration */
uint16_t mtu; /*!< Optional initial MTU (bytes). 0 = use stack default */
} esp_netif_inherent_config_t;
typedef struct esp_netif_config esp_netif_config_t;
@@ -488,13 +488,11 @@ esp_netif_t *esp_netif_get_handle_from_ifkey(const char *if_key)
// MTU control is not supported in loopback build.
esp_err_t esp_netif_set_mtu(esp_netif_t *esp_netif, uint16_t mtu)
{
ESP_LOGD(TAG, "%s esp_netif:%p mtu:%u", __func__, esp_netif, (unsigned)mtu);
return ESP_ERR_NOT_SUPPORTED;
}
esp_err_t esp_netif_get_mtu(esp_netif_t *esp_netif, uint16_t *mtu)
{
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif);
return ESP_ERR_NOT_SUPPORTED;
}
#endif /* CONFIG_ESP_NETIF_LOOPBACK */
+19 -3
View File
@@ -31,6 +31,7 @@
#include "lwip/priv/tcpip_priv.h"
#include "lwip/netif.h"
#include "lwip/etharp.h"
#include "lwip/prot/ip4.h"
#if CONFIG_ESP_NETIF_BRIDGE_EN
#include "netif/bridgeif.h"
#endif // CONFIG_ESP_NETIF_BRIDGE_EN
@@ -672,6 +673,9 @@ static err_t netif_mld_mac_filter_cb(struct netif *netif, const ip6_addr_t *grou
static esp_err_t esp_netif_init_configuration(esp_netif_t *esp_netif, const esp_netif_config_t *cfg)
{
#define MAX_MTU_SIZE 9000 /* lwip doesn't have a global maximum, 9000 is selected as a reasonable max MTU for most cases
it is possible to override this upper bound by runtime configuration esp_netif_set_mtu() */
// Basic esp_netif and lwip is a mandatory configuration and cannot be updated after esp_netif_new()
if (cfg == NULL || cfg->base == NULL || cfg->stack == NULL) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
@@ -703,6 +707,12 @@ static esp_err_t esp_netif_init_configuration(esp_netif_t *esp_netif, const esp_
if (cfg->base->route_prio) {
esp_netif->route_prio = cfg->base->route_prio;
}
// Store initial MTU preference (applied after netif_add()). 0 keeps stack default.
if (cfg->base->mtu >= IP_HLEN && cfg->base->mtu <= MAX_MTU_SIZE) {
esp_netif->configured_mtu = cfg->base->mtu;
} else {
esp_netif->configured_mtu = 0;
}
#if CONFIG_ESP_NETIF_BRIDGE_EN
// Setup bridge configuration if the interface is to be bridge
@@ -1001,6 +1011,10 @@ static esp_err_t esp_netif_lwip_add(esp_netif_t *esp_netif)
#if CONFIG_ESP_NETIF_BRIDGE_EN
}
#endif // CONFIG_ESP_NETIF_BRIDGE_EN
// Apply configured MTU (if provided) after netif has been added and initialized
if (esp_netif->configured_mtu) {
esp_netif->lwip_netif->mtu = esp_netif->configured_mtu;
}
if (esp_netif->driver_set_mac_filter) {
#if LWIP_IPV4 && LWIP_IGMP
netif_set_igmp_mac_filter(esp_netif->lwip_netif, netif_igmp_mac_filter_cb);
@@ -2701,9 +2715,6 @@ esp_err_t esp_netif_get_netif_impl_name(esp_netif_t *esp_netif, char* name)
static esp_err_t esp_netif_set_mtu_api(esp_netif_api_msg_t *msg)
{
esp_netif_t *esp_netif = msg->esp_netif;
if (esp_netif == NULL || esp_netif->lwip_netif == NULL || msg->data == NULL) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
uint16_t mtu = *(uint16_t *)msg->data;
esp_netif->lwip_netif->mtu = mtu;
return ESP_OK;
@@ -2715,6 +2726,11 @@ esp_err_t esp_netif_set_mtu(esp_netif_t *esp_netif, uint16_t mtu)
if (esp_netif == NULL || esp_netif->lwip_netif == NULL) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
/* Validate MTU is at least large enough for IP header */
if (mtu < IP_HLEN) {
ESP_LOGE(TAG, "MTU is too small, must be at least %d", IP_HLEN);
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
return esp_netif_lwip_ipc_call(esp_netif_set_mtu_api, esp_netif, &mtu);
}
@@ -123,6 +123,8 @@ struct esp_netif_obj {
#ifdef CONFIG_ESP_NETIF_SET_DNS_PER_DEFAULT_NETIF
ip_addr_t dns[DNS_MAX_SERVERS];
#endif
// initial MTU preference to apply after netif_add(); 0 means use stack default
uint16_t configured_mtu;
};
typedef enum esp_netif_set_default_state {
@@ -658,6 +658,48 @@ TEST(esp_netif, set_get_dnsserver)
}
}
TEST(esp_netif, initial_mtu_config_applied)
{
// Ensure TCP/IP stack is initialized
test_case_uses_tcpip();
// Minimal driver config to satisfy start-time sanity checks
esp_netif_driver_ifconfig_t driver_config = { .handle = (void*)1, .transmit = dummy_transmit };
// Case 1: explicit MTU configured
uint16_t mtu_out = 0;
esp_netif_inherent_config_t base1 = { .if_key = "mtu_if0" };
base1.mtu = 1400;
esp_netif_config_t cfg1 = {
.base = &base1,
.stack = ESP_NETIF_NETSTACK_DEFAULT_WIFI_STA,
.driver = &driver_config,
};
esp_netif_t *n1 = esp_netif_new(&cfg1);
TEST_ASSERT_NOT_NULL(n1);
esp_netif_action_start(n1, NULL, 0, NULL);
TEST_ASSERT_EQUAL(ESP_OK, esp_netif_get_mtu(n1, &mtu_out));
TEST_ASSERT_EQUAL_UINT16(1400, mtu_out);
esp_netif_destroy(n1);
// Case 2: default MTU (0 means use stack default, e.g., 1500)
esp_netif_inherent_config_t base2 = { .if_key = "mtu_if1" };
// base2.mtu intentionally left 0
esp_netif_config_t cfg2 = {
.base = &base2,
.stack = ESP_NETIF_NETSTACK_DEFAULT_WIFI_STA,
.driver = &driver_config,
};
esp_netif_t *n2 = esp_netif_new(&cfg2);
TEST_ASSERT_NOT_NULL(n2);
esp_netif_action_start(n2, NULL, 0, NULL);
TEST_ASSERT_EQUAL(ESP_OK, esp_netif_get_mtu(n2, &mtu_out));
TEST_ASSERT_EQUAL_UINT16(1500, mtu_out);
struct netif *netif = esp_netif_get_netif_impl(n2);
TEST_ASSERT_EQUAL_UINT16(1500, netif->mtu);
esp_netif_destroy(n2);
}
TEST_GROUP_RUNNER(esp_netif)
{
/**
@@ -686,6 +728,7 @@ TEST_GROUP_RUNNER(esp_netif)
RUN_TEST_CASE(esp_netif, dhcp_server_state_transitions_wifi_ap)
RUN_TEST_CASE(esp_netif, dhcp_server_state_transitions_mesh)
#endif
RUN_TEST_CASE(esp_netif, initial_mtu_config_applied)
RUN_TEST_CASE(esp_netif, route_priority)
RUN_TEST_CASE(esp_netif, set_get_dnsserver)
RUN_TEST_CASE(esp_netif, unified_netif_status_event)
+19 -7
View File
@@ -23,18 +23,30 @@ Notes:
3) Example output:
```
I (xxx) pmtu_probe: Connecting network...
I (xxx) pmtu_probe: Probing PMTU to host www.espressif.com (IPv4)
I (xxx) pmtu_probe: Search range payload=[0, 1472]
I (xxx) pmtu_probe: Best payload=1392 -> MTU=1420
I (xxx) pmtu_probe: Applying MTU 1420 to default netif
I (8236) example_common: Connected to example_netif_sta
I (8246) example_common: - IPv4 address: 192.168.0.35,
I (8276) pmtu_probe: Probing PMTU to host www.espressif.com (IPv4)
I (8276) pmtu_probe: Search range payload=[0, 1472]
I (8286) pmtu_probe: Trying payload once with size 736
I (8436) pmtu_probe: Trying payload once with size 1104
I (8586) pmtu_probe: Trying payload once with size 1288
I (8736) pmtu_probe: Trying payload once with size 1380
I (8886) pmtu_probe: Trying payload once with size 1426
I (9036) pmtu_probe: Trying payload once with size 1449
I (9186) pmtu_probe: Trying payload once with size 1461
I (9336) pmtu_probe: Trying payload once with size 1467
I (9486) pmtu_probe: Trying payload once with size 1470
I (9636) pmtu_probe: Trying payload once with size 1471
I (9786) pmtu_probe: Trying payload once with size 1472
I (9936) pmtu_probe: Best payload=1472 -> MTU=1500
I (9936) pmtu_probe: Applying MTU 1500 to default netif
I (9936) main_task: Returned from app_main()
```
## Implementation details
- Uses `esp_ping` (ping_sock) to attempt 1 echo per payload size and waits synchronously for success/timeout.
- Bounds the search using the current interface MTU when available, otherwise falls back to `1472`.
- Applies MTU via new API:
- Applies MTU via these API:
- `esp_netif_set_mtu(esp_netif_t *netif, uint16_t mtu)`
- `esp_netif_get_mtu(esp_netif_t *netif, uint16_t *mtu)`
@@ -47,8 +47,9 @@ static void on_ping_end(esp_ping_handle_t hdl, void *args)
}
}
static bool try_payload_once(const ip_addr_t *target, uint32_t payload)
static bool try_payload_once(const ip_addr_t *target, uint32_t payload_size)
{
ESP_LOGI(TAG, "Trying payload once with size %u", payload_size);
probe_ctx_t ctx = { .done = xSemaphoreCreateBinary(), .got_reply = false };
if (!ctx.done) {
return false;
@@ -58,7 +59,7 @@ static bool try_payload_once(const ip_addr_t *target, uint32_t payload)
cfg.count = 1;
cfg.timeout_ms = 1000; // 1s timeout
cfg.interval_ms = 100; // not used for count=1
cfg.data_size = payload;
cfg.data_size = payload_size;
esp_ping_callbacks_t cbs = {
.cb_args = &ctx,
.on_ping_success = on_ping_success,
@@ -106,7 +107,9 @@ static bool resolve_host(const char *host, ip_addr_t *out)
void app_main(void)
{
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_LOGI(TAG, "Connecting network...");
ESP_ERROR_CHECK(example_connect());
@@ -123,7 +126,7 @@ void app_main(void)
return;
}
ESP_LOGI(TAG, "Probing PMTU to host %s (IPv4)");
ESP_LOGI(TAG, "Probing PMTU to host %s (IPv4)", host);
uint16_t if_mtu = 0;
uint32_t lo = 0;