diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index c8eca66545..85685d6df7 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -261,7 +261,7 @@ static int dhcp_lease_lost(Link *link) { r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu); if (r >= 0 && link->original_mtu != mtu) { - r = link_set_mtu(link, link->original_mtu); + r = link_set_mtu(link, link->original_mtu, true); if (r < 0) { log_link_warning(link, "DHCP error: could not reset MTU"); @@ -451,7 +451,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { r = sd_dhcp_lease_get_mtu(lease, &mtu); if (r >= 0) { - r = link_set_mtu(link, mtu); + r = link_set_mtu(link, mtu, true); if (r < 0) log_link_error_errno(link, r, "Failed to set MTU to %" PRIu16 ": %m", mtu); } diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 22b639bad6..1738a0d944 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1427,7 +1427,7 @@ static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) return 1; } -int link_set_mtu(Link *link, uint32_t mtu) { +int link_set_mtu(Link *link, uint32_t mtu, bool force) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; int r; @@ -1435,7 +1435,10 @@ int link_set_mtu(Link *link, uint32_t mtu) { assert(link->manager); assert(link->manager->rtnl); - if (link->mtu == mtu || link->setting_mtu) + if (mtu == 0 || link->setting_mtu) + return 0; + + if (force ? link->mtu == mtu : link->mtu >= mtu) return 0; log_link_debug(link, "Setting MTU: %" PRIu32, mtu); @@ -3118,11 +3121,9 @@ static int link_configure(Link *link) { return r; } - if (link->network->mtu > 0) { - r = link_set_mtu(link, link->network->mtu); - if (r < 0) - return r; - } + r = link_set_mtu(link, link->network->mtu, link->network->mtu_is_set); + if (r < 0) + return r; if (socket_ipv6_is_supported()) { r = link_configure_addrgen_mode(link); diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 8b88d3de5d..b6b7c92b4f 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -166,7 +166,7 @@ bool link_has_carrier(Link *link); int link_ipv6ll_gained(Link *link, const struct in6_addr *address); -int link_set_mtu(Link *link, uint32_t mtu); +int link_set_mtu(Link *link, uint32_t mtu, bool force); int ipv4ll_configure(Link *link); int dhcp4_configure(Link *link); diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 75dd8b9e4e..034fa43999 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -174,9 +174,28 @@ static int network_resolve_stacked_netdevs(Network *network) { return 0; } +static uint32_t network_get_stacked_netdevs_mtu(Network *network) { + uint32_t mtu = 0; + NetDev *dev; + Iterator i; + + HASHMAP_FOREACH(dev, network->stacked_netdevs, i) + if (dev->kind == NETDEV_KIND_VLAN && dev->mtu > 0) + /* See vlan_dev_change_mtu() in kernel. + * Note that the additional 4bytes may not be necessary for all devices. */ + mtu = MAX(mtu, dev->mtu + 4); + + else if (dev->kind == NETDEV_KIND_MACVLAN && dev->mtu > mtu) + /* See macvlan_change_mtu() in kernel. */ + mtu = dev->mtu; + + return mtu; +} + static int network_verify(Network *network) { Address *address; Route *route; + uint32_t mtu; assert(network); assert(network->filename); @@ -246,7 +265,16 @@ static int network_verify(Network *network) { if (network->ip_masquerade) network->ip_forward |= ADDRESS_FAMILY_IPV4; - if (network->mtu > 0 && network->dhcp_use_mtu) { + network->mtu_is_set = network->mtu > 0; + mtu = network_get_stacked_netdevs_mtu(network); + if (network->mtu < mtu) { + if (network->mtu_is_set) + log_notice("%s: Bumping MTUBytes= from %"PRIu32" to %"PRIu32" because of stacked device", + network->filename, network->mtu, mtu); + network->mtu = mtu; + } + + if (network->mtu_is_set && network->dhcp_use_mtu) { log_warning("%s: MTUBytes= in [Link] section and UseMTU= in [DHCP] section are set. " "Disabling UseMTU=.", network->filename); network->dhcp_use_mtu = false; diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 6b9b155b67..63d0328750 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -227,6 +227,7 @@ struct Network { struct ether_addr *mac; uint32_t mtu; + bool mtu_is_set; /* Indicate MTUBytes= is specified. */ int arp; int multicast; int allmulticast; diff --git a/test/test-network/conf/21-macvlan.netdev b/test/test-network/conf/21-macvlan.netdev index e9a3c5b347..674c1f516b 100644 --- a/test/test-network/conf/21-macvlan.netdev +++ b/test/test-network/conf/21-macvlan.netdev @@ -1,3 +1,4 @@ [NetDev] Name=macvlan99 Kind=macvlan +MTUBytes=2000 diff --git a/test/test-network/conf/21-vlan.netdev.d/override.conf b/test/test-network/conf/21-vlan.netdev.d/override.conf index cd61be5310..3b8d47d9b1 100644 --- a/test/test-network/conf/21-vlan.netdev.d/override.conf +++ b/test/test-network/conf/21-vlan.netdev.d/override.conf @@ -1,3 +1,6 @@ +[NetDev] +MTUBytes=2000 + [VLAN] Id=99 GVRP=true diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index fa5e08e750..e410ccb265 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -343,15 +343,21 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): self.copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev', '21-vlan.network') self.start_networkd() + self.assertTrue(self.link_exits('test1')) self.assertTrue(self.link_exits('vlan99')) + output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1']).rstrip().decode('utf-8') + print(output) + self.assertTrue(output, ' mtu 2004 ') + output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vlan99']).rstrip().decode('utf-8') print(output) + self.assertTrue(output, ' mtu 2000 ') self.assertTrue(output, 'REORDER_HDR') self.assertTrue(output, 'LOOSE_BINDING') self.assertTrue(output, 'GVRP') self.assertTrue(output, 'MVRP') - self.assertTrue(output, '99') + self.assertTrue(output, ' id 99 ') def test_macvtap(self): self.copy_unit_to_networkd_unit_path('21-macvtap.netdev', '11-dummy.netdev', 'macvtap.network') @@ -363,8 +369,17 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): self.copy_unit_to_networkd_unit_path('21-macvlan.netdev', '11-dummy.netdev', 'macvlan.network') self.start_networkd() + self.assertTrue(self.link_exits('test1')) self.assertTrue(self.link_exits('macvlan99')) + output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1']).rstrip().decode('utf-8') + print(output) + self.assertTrue(output, ' mtu 2000 ') + + output = subprocess.check_output(['ip', '-d', 'link', 'show', 'macvlan99']).rstrip().decode('utf-8') + print(output) + self.assertTrue(output, ' mtu 2000 ') + @expectedFailureIfModuleIsNotAvailable('ipvlan') def test_ipvlan(self): self.copy_unit_to_networkd_unit_path('25-ipvlan.netdev', '11-dummy.netdev', 'ipvlan.network')