From 717ba5fc90159a09d27d2893f12984ee647e11ab Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 6 Jun 2021 14:46:58 +0900 Subject: [PATCH] network: read the minimum and maximum MTU of the interface, and adjust requested MTU based on these values --- src/network/networkd-link.c | 28 +++++++++++++++++++++++----- src/network/networkd-link.h | 4 +++- src/network/networkd-setlink.c | 34 ++++++++++++++++++++++++++++------ 3 files changed, 54 insertions(+), 12 deletions(-) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 56eacdd0a19..71feb057eb6 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2012,7 +2012,7 @@ static int link_update_hardware_address(Link *link, sd_netlink_message *message) } static int link_update_mtu(Link *link, sd_netlink_message *message) { - uint32_t mtu; + uint32_t mtu, min_mtu = 0, max_mtu = UINT32_MAX; int r; assert(link); @@ -2024,16 +2024,34 @@ static int link_update_mtu(Link *link, sd_netlink_message *message) { if (r < 0) return log_link_debug_errno(link, r, "rtnl: failed to read MTU in RTM_NEWLINK message: %m"); - if (mtu == 0 || link->mtu == mtu) + r = sd_netlink_message_read_u32(message, IFLA_MIN_MTU, &min_mtu); + if (r < 0 && r != -ENODATA) + return log_link_debug_errno(link, r, "rtnl: failed to read minimum MTU in RTM_NEWLINK message: %m"); + + r = sd_netlink_message_read_u32(message, IFLA_MAX_MTU, &max_mtu); + if (r < 0 && r != -ENODATA) + return log_link_debug_errno(link, r, "rtnl: failed to read maximum MTU in RTM_NEWLINK message: %m"); + + if (mtu == 0) return 0; + if (max_mtu == 0) + max_mtu = UINT32_MAX; + + link->min_mtu = min_mtu; + link->max_mtu = max_mtu; + if (link->original_mtu == 0) { link->original_mtu = mtu; - log_link_debug(link, "Saved original MTU: %" PRIu32, link->original_mtu); + log_link_debug(link, "Saved original MTU %" PRIu32" (min: %"PRIu32", max: %"PRIu32")", + link->original_mtu, link->min_mtu, link->max_mtu); } - if (link->mtu != 0) - log_link_debug(link, "MTU is changed: %"PRIu32" → %"PRIu32, link->mtu, mtu); + if (link->mtu == mtu) + return 0; + + log_link_debug(link, "MTU is changed: %"PRIu32" → %"PRIu32" (min: %"PRIu32", max: %"PRIu32")", + link->mtu, mtu, link->min_mtu, link->max_mtu); link->mtu = mtu; diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index aa30019a13d..647c60e6847 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -58,6 +58,9 @@ typedef struct Link { struct ether_addr permanent_mac; struct in6_addr ipv6ll_address; uint32_t mtu; + uint32_t min_mtu; + uint32_t max_mtu; + uint32_t original_mtu; sd_device *sd_device; char *driver; @@ -114,7 +117,6 @@ typedef struct Link { Address *dhcp_address, *dhcp_address_old; Set *dhcp_routes, *dhcp_routes_old; char *lease_file; - uint32_t original_mtu; unsigned dhcp4_messages; sd_ipv4acd *dhcp_acd; bool dhcp4_route_failed:1; diff --git a/src/network/networkd-setlink.c b/src/network/networkd-setlink.c index a66033b2a73..6207bcf23b3 100644 --- a/src/network/networkd-setlink.c +++ b/src/network/networkd-setlink.c @@ -677,16 +677,38 @@ int link_request_to_set_master(Link *link) { int link_request_to_set_mtu(Link *link, uint32_t mtu) { Request *req = NULL; /* avoid false maybe-uninitialized warning */ + const char *origin; + uint32_t min_mtu; int r; assert(link); + assert(link->network); + + min_mtu = link->min_mtu; + origin = "the minimum MTU of the interface"; + if (link_ipv6_enabled(link)) { + /* IPv6 protocol requires a minimum MTU of IPV6_MTU_MIN(1280) bytes on the interface. Bump up + * MTU bytes to IPV6_MTU_MIN. */ + if (min_mtu < IPV6_MIN_MTU) { + min_mtu = IPV6_MIN_MTU; + origin = "the minimum IPv6 MTU"; + } + if (min_mtu < link->network->ipv6_mtu) { + min_mtu = link->network->ipv6_mtu; + origin = "the requested IPv6 MTU in IPv6MTUBytes="; + } + } + + if (mtu < min_mtu) { + log_link_warning(link, "Bumping the requested MTU %"PRIu32" to %s (%"PRIu32")", + mtu, origin, min_mtu); + mtu = min_mtu; + } - /* IPv6 protocol requires a minimum MTU of IPV6_MTU_MIN(1280) bytes on the interface. Bump up - * MTU bytes to IPV6_MTU_MIN. */ - if (mtu < IPV6_MIN_MTU && link_ipv6_enabled(link)) { - log_link_warning(link, "Bumping MTU to " STRINGIFY(IPV6_MIN_MTU) ", as IPv6 is enabled " - "and requires a minimum MTU of " STRINGIFY(IPV6_MIN_MTU) " bytes"); - mtu = IPV6_MIN_MTU; + if (mtu > link->max_mtu) { + log_link_warning(link, "Reducing the requested MTU %"PRIu32" to the interface's maximum MTU %"PRIu32".", + mtu, link->max_mtu); + mtu = link->max_mtu; } if (link->mtu == mtu) -- 2.47.3