From 4d6bf4eef31b19779ad1d7df1687785e349f4807 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Wed, 25 Feb 2015 14:49:34 +0100 Subject: [PATCH 1/3] nm-device: set ipv6 mtu at config commit time Just a refactoring, doesn't make any actual difference. It is consistent with IPv4 and will make it easier to implement a policy to recover from incorrect MTUs settings. --- src/devices/nm-device.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 02c435749..e3e64787f 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -283,6 +283,7 @@ typedef struct { NMIP6Config * wwan_ip6_config; NMIP6Config * ext_ip6_config; /* Stuff added outside NM */ gboolean nm_ipv6ll; /* TRUE if NM handles the device's IPv6LL address */ + guint32 ip6_mtu; NMRDisc * rdisc; gulong rdisc_changed_id; @@ -4078,6 +4079,18 @@ print_support_extended_ifa_flags (NMSettingIP6ConfigPrivacy use_tempaddr) warn = 2; } +static void +nm_device_ipv6_set_mtu (NMDevice *self, guint32 mtu) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + char val[16]; + + if (mtu) { + g_snprintf (val, sizeof (val), "%d", mtu); + nm_device_ipv6_sysctl_set (self, "mtu", val); + } +} + static void rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *self) { @@ -4224,12 +4237,8 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *self) nm_device_ipv6_sysctl_set (self, "hop_limit", val); } - if (changed & NM_RDISC_CONFIG_MTU) { - char val[16]; - - g_snprintf (val, sizeof (val), "%d", rdisc->mtu); - nm_device_ipv6_sysctl_set (self, "mtu", val); - } + if (changed & NM_RDISC_CONFIG_MTU) + priv->ip6_mtu = rdisc->mtu; nm_device_activate_schedule_ip6_config_result (self); } @@ -6053,6 +6062,7 @@ nm_device_set_ip6_config (NMDevice *self, /* Always commit to nm-platform to update lifetimes */ if (commit && new_config) { + nm_device_ipv6_set_mtu (self, priv->ip6_mtu); success = nm_ip6_config_commit (new_config, ip_ifindex); if (!success) reason_local = NM_DEVICE_STATE_REASON_CONFIG_FAILED; From 1bc202af028ad8987a92500bba6bb36156d8be5f Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Wed, 25 Feb 2015 15:21:48 +0100 Subject: [PATCH 2/3] nm-device: move device MTU setting from IP4Config to NMDevice Just a refactoring, no functional change. This will make it easier to coordinate the device MTU with IPv6 MTU. --- src/devices/nm-device.c | 10 ++++++++++ src/nm-ip4-config.c | 5 ----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index e3e64787f..808ba6f0b 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -4079,6 +4079,14 @@ print_support_extended_ifa_flags (NMSettingIP6ConfigPrivacy use_tempaddr) warn = 2; } +static void +nm_device_set_mtu (NMDevice *self, guint32 mtu) +{ + /* MTU */ + if (mtu && mtu != nm_platform_link_get_mtu (ifindex)) + nm_platform_link_set_mtu (ifindex, mtu); +} + static void nm_device_ipv6_set_mtu (NMDevice *self, guint32 mtu) { @@ -5928,6 +5936,8 @@ nm_device_set_ip4_config (NMDevice *self, if (commit && new_config) { gboolean assumed = nm_device_uses_assumed_connection (self); + nm_device_set_mtu (self, nm_ip4_config_get_mtu (new_config)); + /* for assumed devices we set the device_route_metric to the default which will * stop nm_platform_ip4_address_sync() to replace the device routes. */ success = nm_ip4_config_commit (new_config, ip_ifindex, diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 1f3e5954b..10e2b62c6 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -264,7 +264,6 @@ gboolean nm_ip4_config_commit (const NMIP4Config *config, int ifindex, guint32 default_route_metric) { NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - guint32 mtu = nm_ip4_config_get_mtu (config); int i; g_return_val_if_fail (ifindex > 0, FALSE); @@ -299,10 +298,6 @@ nm_ip4_config_commit (const NMIP4Config *config, int ifindex, guint32 default_ro return FALSE; } - /* MTU */ - if (mtu && mtu != nm_platform_link_get_mtu (ifindex)) - nm_platform_link_set_mtu (ifindex, mtu); - return TRUE; } From 7ba2a058f201ac237e2c5ddf6f513f8c306f314d Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Wed, 25 Feb 2015 15:35:26 +0100 Subject: [PATCH 3/3] nm-device: avoid improper IPv6 MTU configuration Ensure it's always (before address configuration starts and on updates) >= 1280 and not higher than the device MTU. --- src/devices/nm-device.c | 53 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 808ba6f0b..c31b47667 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -464,6 +464,12 @@ nm_device_ipv6_sysctl_set (NMDevice *self, const char *property, const char *val return nm_platform_sysctl_set (nm_utils_ip6_property_path (nm_device_get_ip_iface (self), property), value); } +static guint32 +nm_device_ipv6_sysctl_get_int32 (NMDevice *self, const char *property, gint32 fallback) +{ + return nm_platform_sysctl_get_int32 (nm_utils_ip6_property_path (nm_device_get_ip_iface (self), property), fallback); +} + static gboolean device_has_capability (NMDevice *self, NMDeviceCapabilities caps) { @@ -4079,21 +4085,53 @@ print_support_extended_ifa_flags (NMSettingIP6ConfigPrivacy use_tempaddr) warn = 2; } +static void nm_device_ipv6_set_mtu (NMDevice *self, guint32 mtu); + static void nm_device_set_mtu (NMDevice *self, guint32 mtu) { - /* MTU */ - if (mtu && mtu != nm_platform_link_get_mtu (ifindex)) - nm_platform_link_set_mtu (ifindex, mtu); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + int ifindex = nm_device_get_ifindex (self); + + if (mtu) + priv->mtu = mtu; + + /* Ensure the IPv6 MTU is still alright. */ + if (priv->ip6_mtu) + nm_device_ipv6_set_mtu (self, priv->ip6_mtu); + + if (priv->mtu != nm_platform_link_get_mtu (ifindex)) + nm_platform_link_set_mtu (ifindex, priv->mtu); } static void nm_device_ipv6_set_mtu (NMDevice *self, guint32 mtu) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + guint32 plat_mtu = nm_device_ipv6_sysctl_get_int32 (self, "mtu", priv->mtu); char val[16]; - if (mtu) { + priv->ip6_mtu = mtu ?: plat_mtu; + + if (priv->ip6_mtu && priv->mtu < priv->ip6_mtu) { + _LOGW (LOGD_DEVICE | LOGD_IP6, "Lowering IPv6 MTU (%d) to match device MTU (%d)", + priv->ip6_mtu, priv->mtu); + priv->ip6_mtu = priv->mtu; + } + + if (priv->ip6_mtu < 1280) { + _LOGW (LOGD_DEVICE | LOGD_IP6, "IPv6 MTU (%d) smaller than 1280, adjusting", + priv->ip6_mtu); + priv->ip6_mtu = 1280; + } + + if (priv->mtu < priv->ip6_mtu) { + _LOGW (LOGD_DEVICE | LOGD_IP6, "Raising device MTU (%d) to match IPv6 MTU (%d)", + priv->mtu, priv->ip6_mtu); + nm_device_set_mtu (self, priv->ip6_mtu); + } + + if (priv->ip6_mtu != plat_mtu) { g_snprintf (val, sizeof (val), "%d", mtu); nm_device_ipv6_sysctl_set (self, "mtu", val); } @@ -4598,6 +4636,13 @@ act_stage3_ip6_config_start (NMDevice *self, return NM_ACT_STAGE_RETURN_STOP; } + /* Ensure the MTU makes sense. If it was below 1280 the kernel would not + * expose any ipv6 sysctls or allow presence of any addresses on the interface, + * including LL, which * would make it impossible to autoconfigure MTU to a + * correct value. */ + if (!nm_device_uses_assumed_connection (self)) + nm_device_ipv6_set_mtu (self, priv->ip6_mtu); + /* Any method past this point requires an IPv6LL address. Use NM-controlled * IPv6LL if this is not an assumed connection, since assumed connections * will already have IPv6 set up.