diff options
author | Dan Streetman <ddstreet@canonical.com> | 2019-10-29 10:31:58 -0400 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2019-12-15 11:47:08 +0100 |
commit | 639dc9f4bfd2c09535bee079ae9bc7006b520a66 (patch) | |
tree | 1cd18ac6c5a2247c5e5801fe1f9188a0b0305fec | |
parent | cbced49daaa664484ede8561f417dc767487eaf4 (diff) | |
download | systemd-244.1.tar.gz |
network: set ipv6 mtu after link-up or device mtu changev244.1
The kernel resets the ipv6 mtu after NETDEV_UP or NETDEV_CHANGEMTU event,
so we must reset the ipv6 mtu to our configured value after we detect
IFF_UP flag set or after we set the device mtu.
Fixes: #13914.
(cherry picked from commit d236718c167af46bbf4460fc6b82db8396bd43a5)
-rw-r--r-- | src/network/networkd-link.c | 61 | ||||
-rw-r--r-- | src/network/networkd-link.h | 1 |
2 files changed, 54 insertions, 8 deletions
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 3369a0810c..2e60adbf78 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1341,7 +1341,7 @@ int link_set_mtu(Link *link, uint32_t mtu) { if (link_ipv6_enabled(link) && mtu < IPV6_MIN_MTU) { log_link_warning(link, "Bumping MTU to " STRINGIFY(IPV6_MIN_MTU) ", as " - "IPv6 is requested and requires a minimum MTU of " STRINGIFY(IPV6_MIN_MTU) " bytes: %m"); + "IPv6 is requested and requires a minimum MTU of " STRINGIFY(IPV6_MIN_MTU) " bytes"); mtu = IPV6_MIN_MTU; } @@ -2378,9 +2378,23 @@ static int link_set_ipv6_mtu(Link *link) { if (link->network->ipv6_mtu == 0) return 0; + /* IPv6 protocol requires a minimum MTU of IPV6_MTU_MIN(1280) bytes + * on the interface. Bump up IPv6 MTU bytes to IPV6_MTU_MIN. */ + if (link->network->ipv6_mtu < IPV6_MIN_MTU) { + log_link_notice(link, "Bumping IPv6 MTU to "STRINGIFY(IPV6_MIN_MTU)" byte minimum required"); + link->network->ipv6_mtu = IPV6_MIN_MTU; + } + r = sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "mtu", link->network->ipv6_mtu); - if (r < 0) - log_link_warning_errno(link, r, "Cannot set IPv6 MTU for interface: %m"); + if (r < 0) { + if (link->mtu < link->network->ipv6_mtu) + log_link_warning(link, "Cannot set IPv6 MTU %"PRIu32" higher than device MTU %"PRIu32, + link->network->ipv6_mtu, link->mtu); + else + log_link_warning_errno(link, r, "Cannot set IPv6 MTU for interface: %m"); + } + + link->ipv6_mtu_set = true; return 0; } @@ -2669,10 +2683,6 @@ static int link_configure(Link *link) { if (r < 0) return r; - r = link_set_ipv6_mtu(link); - if (r < 0) - return r; - if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)) { r = ipv4ll_configure(link); if (r < 0) @@ -2745,6 +2755,12 @@ static int link_configure_after_setting_mtu(Link *link) { if (link->setting_mtu) return 0; + /* The kernel resets ipv6 mtu after changing device mtu; + * we must set this here, after we've set device mtu */ + r = link_set_ipv6_mtu(link); + if (r < 0) + return r; + if (link_has_carrier(link) || link->network->configure_without_carrier) { r = link_acquire_conf(link); if (r < 0) @@ -3453,11 +3469,30 @@ int link_carrier_reset(Link *link) { return 0; } +/* This is called every time an interface admin state changes to up; + * specifically, when IFF_UP flag changes from unset to set */ +static int link_admin_state_up(Link *link) { + int r; + + /* We set the ipv6 mtu after the device mtu, but the kernel resets + * ipv6 mtu on NETDEV_UP, so we need to reset it. The check for + * ipv6_mtu_set prevents this from trying to set it too early before + * the link->network has been setup; we only need to reset it + * here if we've already set it during normal initialization. */ + if (link->ipv6_mtu_set) { + r = link_set_ipv6_mtu(link); + if (r < 0) + return r; + } + + return 0; +} + int link_update(Link *link, sd_netlink_message *m) { struct ether_addr mac; const char *ifname; uint32_t mtu; - bool had_carrier, carrier_gained, carrier_lost; + bool had_carrier, carrier_gained, carrier_lost, link_was_admin_up; int old_master, r; assert(link); @@ -3587,12 +3622,22 @@ int link_update(Link *link, sd_netlink_message *m) { old_master = link->master_ifindex; (void) sd_netlink_message_read_u32(m, IFLA_MASTER, (uint32_t *) &link->master_ifindex); + link_was_admin_up = link->flags & IFF_UP; had_carrier = link_has_carrier(link); r = link_update_flags(link, m, old_master != link->master_ifindex); if (r < 0) return r; + if (!link_was_admin_up && (link->flags & IFF_UP)) { + log_link_info(link, "Link UP"); + + r = link_admin_state_up(link); + if (r < 0) + return r; + } else if (link_was_admin_up && !(link->flags & IFF_UP)) + log_link_info(link, "Link DOWN"); + r = link_update_lldp(link); if (r < 0) return r; diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index c8b8241ff1..e0fa70c20f 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -116,6 +116,7 @@ typedef struct Link { bool routing_policy_rules_configured:1; bool qdiscs_configured:1; bool setting_mtu:1; + bool ipv6_mtu_set:1; LIST_HEAD(Address, pool_addresses); |