device: properly handle MTU for devices with @iface != @ip_iface

When the device has an IP interface different from the main one, we
previously took the MTU saved in priv->mtu (which is the MTU initially
set on the underlying interface) and applied it to the IP interface.

This is wrong as it forces the two MTUs to be equal and breaks
connectivity for devices with encapsulation (as PPP). Instead, track
the two MTUs in different variables.

https://bugzilla.redhat.com/show_bug.cgi?id=1385198
This commit is contained in:
Beniamino Galvani
2016-10-19 15:55:01 +02:00
parent 7b589e2b72
commit 00ce005e51

View File

@@ -298,6 +298,7 @@ typedef struct _NMDevicePrivate {
bool ignore_carrier; bool ignore_carrier;
gulong ignore_carrier_id; gulong ignore_carrier_id;
guint32 mtu; guint32 mtu;
guint32 ip_mtu;
bool up; /* IFF_UP */ bool up; /* IFF_UP */
/* Generic DHCP stuff */ /* Generic DHCP stuff */
@@ -815,12 +816,16 @@ nm_device_set_ip_iface (NMDevice *self, const char *iface)
} }
} }
/* We don't care about any saved values from the old iface */ /* We don't care about any saved values from the old iface */
g_hash_table_remove_all (priv->ip6_saved_properties); g_hash_table_remove_all (priv->ip6_saved_properties);
/* Emit change notification */ /* Emit change notification */
if (g_strcmp0 (old_ip_iface, priv->ip_iface)) if (g_strcmp0 (old_ip_iface, priv->ip_iface)) {
if (priv->ip_ifindex)
priv->ip_mtu = nm_platform_link_get_mtu (NM_PLATFORM_GET, priv->ip_ifindex);
_notify (self, PROP_IP_IFACE); _notify (self, PROP_IP_IFACE);
}
g_free (old_ip_iface); g_free (old_ip_iface);
} }
@@ -2067,6 +2072,9 @@ device_ip_link_changed (NMDevice *self)
_stats_update_counters_from_pllink (self, pllink); _stats_update_counters_from_pllink (self, pllink);
if (priv->ip_mtu != pllink->mtu)
priv->ip_mtu = pllink->mtu;
if (pllink->name[0] && g_strcmp0 (priv->ip_iface, pllink->name)) { if (pllink->name[0] && g_strcmp0 (priv->ip_iface, pllink->name)) {
_LOGI (LOGD_DEVICE, "interface index %d renamed ip_iface (%d) from '%s' to '%s'", _LOGI (LOGD_DEVICE, "interface index %d renamed ip_iface (%d) from '%s' to '%s'",
priv->ifindex, nm_device_get_ip_ifindex (self), priv->ifindex, nm_device_get_ip_ifindex (self),
@@ -6366,36 +6374,61 @@ linklocal6_start (NMDevice *self)
static void nm_device_ipv6_set_mtu (NMDevice *self, guint32 mtu); static void nm_device_ipv6_set_mtu (NMDevice *self, guint32 mtu);
static void
set_ip_mtu (NMDevice *self, guint32 mtu)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->ip_ifindex)
priv->ip_mtu = mtu;
else
priv->mtu = mtu;
}
static guint32
get_ip_mtu (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->ip_ifindex)
return priv->ip_mtu;
else
return priv->mtu;
}
static void static void
nm_device_set_mtu (NMDevice *self, guint32 mtu) nm_device_set_mtu (NMDevice *self, guint32 mtu)
{ {
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
int ifindex = nm_device_get_ip_ifindex (self); int ifindex = nm_device_get_ip_ifindex (self);
guint32 ip_mtu;
if (mtu) if (mtu)
priv->mtu = mtu; set_ip_mtu (self, mtu);
/* Ensure the IPv6 MTU is still alright. */ /* Ensure the IPv6 MTU is still alright. */
if (priv->ip6_mtu) if (priv->ip6_mtu)
nm_device_ipv6_set_mtu (self, priv->ip6_mtu); nm_device_ipv6_set_mtu (self, priv->ip6_mtu);
if (priv->mtu && priv->mtu != nm_platform_link_get_mtu (NM_PLATFORM_GET, ifindex)) ip_mtu = get_ip_mtu (self);
nm_platform_link_set_mtu (NM_PLATFORM_GET, ifindex, priv->mtu); if (ip_mtu && ip_mtu != nm_platform_link_get_mtu (NM_PLATFORM_GET, ifindex))
nm_platform_link_set_mtu (NM_PLATFORM_GET, ifindex, ip_mtu);
} }
static void static void
nm_device_ipv6_set_mtu (NMDevice *self, guint32 mtu) nm_device_ipv6_set_mtu (NMDevice *self, guint32 mtu)
{ {
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
guint32 plat_mtu = nm_device_ipv6_sysctl_get_int32 (self, "mtu", priv->mtu); guint32 ip_mtu = get_ip_mtu (self);
guint32 plat_mtu = nm_device_ipv6_sysctl_get_int32 (self, "mtu", ip_mtu);
char val[16]; char val[16];
priv->ip6_mtu = mtu ?: plat_mtu; priv->ip6_mtu = mtu ?: plat_mtu;
if (priv->ip6_mtu && priv->mtu && priv->mtu < priv->ip6_mtu) { if (priv->ip6_mtu && ip_mtu && ip_mtu < priv->ip6_mtu) {
_LOGI (LOGD_DEVICE | LOGD_IP6, "Lowering IPv6 MTU (%d) to match device MTU (%d)", _LOGI (LOGD_DEVICE | LOGD_IP6, "Lowering IPv6 MTU (%d) to match device MTU (%d)",
priv->ip6_mtu, priv->mtu); priv->ip6_mtu, ip_mtu);
priv->ip6_mtu = priv->mtu; priv->ip6_mtu = ip_mtu;
} }
if (priv->ip6_mtu && priv->ip6_mtu < 1280) { if (priv->ip6_mtu && priv->ip6_mtu < 1280) {
@@ -6404,9 +6437,9 @@ nm_device_ipv6_set_mtu (NMDevice *self, guint32 mtu)
priv->ip6_mtu = 1280; priv->ip6_mtu = 1280;
} }
if (priv->ip6_mtu && priv->mtu && priv->mtu < priv->ip6_mtu) { if (priv->ip6_mtu && ip_mtu && ip_mtu < priv->ip6_mtu) {
_LOGI (LOGD_DEVICE | LOGD_IP6, "Raising device MTU (%d) to match IPv6 MTU (%d)", _LOGI (LOGD_DEVICE | LOGD_IP6, "Raising device MTU (%d) to match IPv6 MTU (%d)",
priv->mtu, priv->ip6_mtu); ip_mtu, priv->ip6_mtu);
nm_device_set_mtu (self, priv->ip6_mtu); nm_device_set_mtu (self, priv->ip6_mtu);
} }