]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: read the minimum and maximum MTU of the interface, and adjust requested...
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 6 Jun 2021 05:46:58 +0000 (14:46 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 8 Jun 2021 19:59:23 +0000 (04:59 +0900)
src/network/networkd-link.c
src/network/networkd-link.h
src/network/networkd-setlink.c

index 56eacdd0a19cf8d8fe508aaad0458323092df935..71feb057eb6e69219fd0efed370340eadceab2f8 100644 (file)
@@ -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;
 
index aa30019a13da342f472c3d2ea3991fdaee6b4d50..647c60e6847c5e06fcc483fcee0ca941e0c8317e 100644 (file)
@@ -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;
index a66033b2a7325ca45d455f8bf472a70fa34a3ba7..6207bcf23b344378faf8abb6ccedcbb30d8e7dbf 100644 (file)
@@ -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)