From 353c7c95c1c664c024c4267e67ed2d4b57b44437 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Wed, 18 Sep 2019 10:54:13 +0200 Subject: [PATCH 1/6] device: reset ip6_mtu on cleanup ip6_mtu contains the MTU received through IPv6 autoconfiguration; it should be reset when the connection is deactivated. https://bugzilla.redhat.com/show_bug.cgi?id=1753128 --- src/devices/nm-device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 1fe74b55e3..09241d8ffb 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -14845,6 +14845,7 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType clean } priv->mtu_source = NM_DEVICE_MTU_SOURCE_NONE; + priv->ip6_mtu = 0; if (priv->mtu_initial || priv->ip6_mtu_initial) { ifindex = nm_device_get_ip_ifindex (self); From 6455a4e52852a936ae34e6596a2d309a44fb8fcc Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Wed, 11 Sep 2019 10:57:07 +0200 Subject: [PATCH 2/6] device: expand comment on MTU selection --- src/devices/nm-device.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 09241d8ffb..440a94c238 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -9376,9 +9376,21 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config) { guint32 mtu = 0; - /* preferably, get the MTU from explicit user-configuration. - * Only if that fails, look at the current @config (which contains - * MTUs from DHCP/PPP) or maybe fallback to a device-specific MTU. */ + /* We take the MTU from various sources: (in order of increasing + * priority) parent link, IP configuration (which contains the + * MTU from DHCP/PPP), connection profile. + * + * We could just compare it with the platform MTU and apply it + * when different, but this would revert at random times manual + * changes done by the user with the MTU from the connection. + * + * Instead, we remember the source of the currently configured + * MTU and apply the new one only when the new source has a + * higher priority, so that we don't set a MTU from same source + * multiple times. An exception to this is for the PARENT + * source, since we need to keep tracking the parent MTU when it + * changes. + */ if (NM_DEVICE_GET_CLASS (self)->get_configured_mtu) mtu = NM_DEVICE_GET_CLASS (self)->get_configured_mtu (self, &source); From 5cf57f452233b1211fcff7c8cf689d9d5cb48092 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 12 Sep 2019 17:29:49 +0200 Subject: [PATCH 3/6] device: introduce generic function to inherit MTU from parent Introduce a generic function to set a MTU based on parent's one. Also define a device-specific @mtu_parent_delta value that specifies the difference from parent MTU that should be set by default. For VLAN it is zero but other interface types (for example MACsec) require a positive value due to encapsulation overhead. --- src/devices/nm-device-private.h | 3 +++ src/devices/nm-device-vlan.c | 23 ++--------------------- src/devices/nm-device.c | 27 +++++++++++++++++++++++++++ src/devices/nm-device.h | 4 ++++ 4 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h index 4c38fa7a2a..b4bc6a1bfc 100644 --- a/src/devices/nm-device-private.h +++ b/src/devices/nm-device-private.h @@ -168,6 +168,9 @@ guint32 nm_device_get_configured_mtu_from_connection (NMDevice *device, guint32 nm_device_get_configured_mtu_for_wired (NMDevice *self, NMDeviceMtuSource *out_source); +guint32 nm_device_get_configured_mtu_wired_parent (NMDevice *self, + NMDeviceMtuSource *out_source); + void nm_device_commit_mtu (NMDevice *self); /*****************************************************************************/ diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c index 02262b21d6..b6efeb81a5 100644 --- a/src/devices/nm-device-vlan.c +++ b/src/devices/nm-device-vlan.c @@ -502,26 +502,6 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) return NM_ACT_STAGE_RETURN_SUCCESS; } -static guint32 -get_configured_mtu (NMDevice *self, NMDeviceMtuSource *out_source) -{ - guint32 mtu = 0; - int ifindex; - - mtu = nm_device_get_configured_mtu_for_wired (self, out_source); - if (*out_source != NM_DEVICE_MTU_SOURCE_NONE) - return mtu; - - /* Inherit the MTU from parent device, if any */ - ifindex = nm_device_parent_get_ifindex (self); - if (ifindex > 0) { - mtu = nm_platform_link_get_mtu (nm_device_get_platform (NM_DEVICE (self)), ifindex); - *out_source = NM_DEVICE_MTU_SOURCE_PARENT; - } - - return mtu; -} - /*****************************************************************************/ static void @@ -577,6 +557,7 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass) device_class->connection_type_supported = NM_SETTING_VLAN_SETTING_NAME; device_class->connection_type_check_compatible = NM_SETTING_VLAN_SETTING_NAME; device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_VLAN); + device_class->mtu_parent_delta = 0; /* VLANs can have the same MTU of parent */ device_class->create_and_realize = create_and_realize; device_class->link_changed = link_changed; @@ -584,7 +565,7 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass) device_class->get_generic_capabilities = get_generic_capabilities; device_class->act_stage1_prepare_set_hwaddr_ethernet = TRUE; device_class->act_stage1_prepare = act_stage1_prepare; - device_class->get_configured_mtu = get_configured_mtu; + device_class->get_configured_mtu = nm_device_get_configured_mtu_wired_parent; device_class->is_available = is_available; device_class->parent_changed_notify = parent_changed_notify; diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 440a94c238..b6a00df645 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -9324,6 +9324,33 @@ nm_device_get_configured_mtu_for_wired (NMDevice *self, NMDeviceMtuSource *out_s out_source); } +guint32 +nm_device_get_configured_mtu_wired_parent (NMDevice *self, + NMDeviceMtuSource *out_source) +{ + guint32 mtu = 0; + int ifindex; + + mtu = nm_device_get_configured_mtu_for_wired (self, out_source); + if (*out_source != NM_DEVICE_MTU_SOURCE_NONE) { + nm_assert (mtu > 0); + return mtu; + } + + /* Inherit the MTU from parent device, if any */ + ifindex = nm_device_parent_get_ifindex (self); + if (ifindex > 0) { + mtu = nm_platform_link_get_mtu (nm_device_get_platform (self), ifindex); + if (mtu >= NM_DEVICE_GET_CLASS (self)->mtu_parent_delta) { + mtu -= NM_DEVICE_GET_CLASS (self)->mtu_parent_delta; + *out_source = NM_DEVICE_MTU_SOURCE_PARENT; + } else + mtu = 0; + } + + return mtu; +} + /*****************************************************************************/ static void diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index df8777b720..40d9676d2d 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -225,6 +225,10 @@ typedef struct _NMDeviceClass { const NMLinkType *link_types; + /* if the device MTU is set based on parent's one, this specifies + * a delta in the MTU allowed value due the encapsulation overhead */ + guint16 mtu_parent_delta; + /* Whether the device type is a master-type. This depends purely on the * type (NMDeviceClass), not the actual device instance. */ bool is_master:1; From 438a0a9ad5287a82b1872c9783cc8fa4b548d49e Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 12 Sep 2019 17:33:49 +0200 Subject: [PATCH 4/6] macsec: update MTU according to parent's one A MACsec connection doesn't have an ordering dependency with its parent connection and so it's possible that the parent gets activated later and sets a greater MTU than the original one. It is reasonable and useful to keep the MACsec MTU configured by default as the maximum allowed by the parent interface, that is the parent MTU minus the encapsulation overhead (32). The user can of course override this by setting an explicit value in the connection. We already do something similar for VLANs. https://bugzilla.redhat.com/show_bug.cgi?id=1723690 --- src/devices/nm-device-macsec.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/devices/nm-device-macsec.c b/src/devices/nm-device-macsec.c index 17ee53c565..c9592a4971 100644 --- a/src/devices/nm-device-macsec.c +++ b/src/devices/nm-device-macsec.c @@ -52,6 +52,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceMacsec, typedef struct { NMPlatformLnkMacsec props; gulong parent_state_id; + gulong parent_mtu_id; Supplicant supplicant; guint supplicant_timeout_id; NMActRequestGetSecretsCallId *macsec_secrets_id; @@ -99,6 +100,17 @@ parent_state_changed (NMDevice *parent, nm_device_set_unmanaged_by_flags (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent, FALSE), reason); } +static void +parent_mtu_maybe_changed (NMDevice *parent, + GParamSpec *pspec, + gpointer user_data) +{ + /* the MTU of a MACsec device is limited by the parent's MTU. + * + * When the parent's MTU changes, try to re-set the MTU. */ + nm_device_commit_mtu (user_data); +} + static void parent_changed_notify (NMDevice *device, int old_ifindex, @@ -119,12 +131,16 @@ parent_changed_notify (NMDevice *device, * because NMDevice's dispose() will unset the parent, which in turn calls * parent_changed_notify(). */ nm_clear_g_signal_handler (old_parent, &priv->parent_state_id); + nm_clear_g_signal_handler (old_parent, &priv->parent_mtu_id); if (new_parent) { priv->parent_state_id = g_signal_connect (new_parent, NM_DEVICE_STATE_CHANGED, G_CALLBACK (parent_state_changed), device); + priv->parent_mtu_id = g_signal_connect (new_parent, "notify::" NM_DEVICE_MTU, + G_CALLBACK (parent_mtu_maybe_changed), device); + /* Set parent-dependent unmanaged flag */ nm_device_set_unmanaged_by_flags (device, @@ -779,11 +795,15 @@ static void dispose (GObject *object) { NMDeviceMacsec *self = NM_DEVICE_MACSEC (object); + NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE (self); macsec_secrets_cancel (self); supplicant_interface_release (self); G_OBJECT_CLASS (nm_device_macsec_parent_class)->dispose (object); + + nm_assert (priv->parent_state_id == 0); + nm_assert (priv->parent_mtu_id == 0); } static const NMDBusInterfaceInfoExtended interface_info_device_macsec = { @@ -826,6 +846,7 @@ nm_device_macsec_class_init (NMDeviceMacsecClass *klass) device_class->connection_type_supported = NM_SETTING_MACSEC_SETTING_NAME; device_class->connection_type_check_compatible = NM_SETTING_MACSEC_SETTING_NAME; device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_MACSEC); + device_class->mtu_parent_delta = 32; device_class->act_stage2_config = act_stage2_config; device_class->create_and_realize = create_and_realize; @@ -835,7 +856,7 @@ nm_device_macsec_class_init (NMDeviceMacsecClass *klass) device_class->is_available = is_available; device_class->parent_changed_notify = parent_changed_notify; device_class->state_changed = device_state_changed; - device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; + device_class->get_configured_mtu = nm_device_get_configured_mtu_wired_parent; obj_properties[PROP_SCI] = g_param_spec_uint64 (NM_DEVICE_MACSEC_SCI, "", "", From 4875745bc09c2f535cd28c13ea864cffbce37b0a Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 13 Sep 2019 11:40:51 +0200 Subject: [PATCH 5/6] macvlan: update MTU according to parent's one --- src/devices/nm-device-macvlan.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/devices/nm-device-macvlan.c b/src/devices/nm-device-macvlan.c index f27211f5f5..3633f02d46 100644 --- a/src/devices/nm-device-macvlan.c +++ b/src/devices/nm-device-macvlan.c @@ -34,6 +34,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceMacvlan, typedef struct { gulong parent_state_id; + gulong parent_mtu_id; NMPlatformLnkMacvlan props; } NMDeviceMacvlanPrivate; @@ -120,6 +121,17 @@ parent_state_changed (NMDevice *parent, nm_device_set_unmanaged_by_flags (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent, FALSE), reason); } +static void +parent_mtu_maybe_changed (NMDevice *parent, + GParamSpec *pspec, + gpointer user_data) +{ + /* the MTU of a macvlan/macvtap device is limited by the parent's MTU. + * + * When the parent's MTU changes, try to re-set the MTU. */ + nm_device_commit_mtu (user_data); +} + static void parent_changed_notify (NMDevice *device, int old_ifindex, @@ -136,12 +148,15 @@ parent_changed_notify (NMDevice *device, * because NMDevice's dispose() will unset the parent, which in turn calls * parent_changed_notify(). */ nm_clear_g_signal_handler (old_parent, &priv->parent_state_id); + nm_clear_g_signal_handler (old_parent, &priv->parent_mtu_id); if (new_parent) { priv->parent_state_id = g_signal_connect (new_parent, NM_DEVICE_STATE_CHANGED, G_CALLBACK (parent_state_changed), device); + priv->parent_mtu_id = g_signal_connect (new_parent, "notify::" NM_DEVICE_MTU, + G_CALLBACK (parent_mtu_maybe_changed), device); /* Set parent-dependent unmanaged flag */ nm_device_set_unmanaged_by_flags (device, @@ -447,6 +462,17 @@ nm_device_macvlan_init (NMDeviceMacvlan *self) { } +static void +dispose (GObject *object) +{ + NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (object); + + G_OBJECT_CLASS (nm_device_macvlan_parent_class)->dispose (object); + + nm_assert (priv->parent_state_id == 0); + nm_assert (priv->parent_mtu_id == 0); +} + static const NMDBusInterfaceInfoExtended interface_info_device_macvlan = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( NM_DBUS_INTERFACE_DEVICE_MACVLAN, @@ -470,6 +496,7 @@ nm_device_macvlan_class_init (NMDeviceMacvlanClass *klass) NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); + object_class->dispose = dispose; object_class->get_property = get_property; object_class->set_property = set_property; @@ -478,13 +505,14 @@ nm_device_macvlan_class_init (NMDeviceMacvlanClass *klass) device_class->connection_type_supported = NM_SETTING_MACVLAN_SETTING_NAME; device_class->connection_type_check_compatible = NM_SETTING_MACVLAN_SETTING_NAME; device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVTAP); + device_class->mtu_parent_delta = 0; device_class->act_stage1_prepare_set_hwaddr_ethernet = TRUE; device_class->check_connection_compatible = check_connection_compatible; device_class->complete_connection = complete_connection; device_class->create_and_realize = create_and_realize; device_class->get_generic_capabilities = get_generic_capabilities; - device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; + device_class->get_configured_mtu = nm_device_get_configured_mtu_wired_parent; device_class->is_available = is_available; device_class->link_changed = link_changed; device_class->parent_changed_notify = parent_changed_notify; From ec28f5b343816d6696f6a4994efcfa919b6f02b2 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Wed, 11 Sep 2019 10:57:07 +0200 Subject: [PATCH 6/6] device: fix setting MTU from connection when limited by parent We try to set only one time the MTU from the connection to not interfere with manual user changes. If at some point the parent interface changes temporarily MTU to a lower value (for example, because the connection was reactivated), the kernel will also lower the MTU on child interface and we will not update it ever again. Add a workaround to this. If we detect that the MTU we want to set from connection is higher that the allowed one, go into a state where we follow the parent MTU until it is possible to set again the desired MTU. This is a bit ugly, but I can't think of any nicer way to do it. https://bugzilla.redhat.com/show_bug.cgi?id=1751079 --- src/devices/nm-device-ethernet.c | 6 ++- src/devices/nm-device-infiniband.c | 4 +- src/devices/nm-device-ip-tunnel.c | 4 +- src/devices/nm-device-private.h | 5 ++- src/devices/nm-device-wireguard.c | 2 +- src/devices/nm-device.c | 58 ++++++++++++++++++++------- src/devices/nm-device.h | 4 +- src/devices/wifi/nm-device-iwd.c | 4 +- src/devices/wifi/nm-device-wifi-p2p.c | 4 +- src/devices/wifi/nm-device-wifi.c | 4 +- src/devices/wwan/nm-modem.c | 4 +- src/devices/wwan/nm-modem.h | 2 +- 12 files changed, 73 insertions(+), 28 deletions(-) diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index 83f2f61cf4..ddd5132690 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -1329,13 +1329,15 @@ act_stage3_ip_config_start (NMDevice *device, } static guint32 -get_configured_mtu (NMDevice *device, NMDeviceMtuSource *out_source) +get_configured_mtu (NMDevice *device, + NMDeviceMtuSource *out_source, + gboolean *out_force) { /* MTU only set for plain ethernet */ if (NM_DEVICE_ETHERNET_GET_PRIVATE ((NMDeviceEthernet *) device)->ppp_manager) return 0; - return nm_device_get_configured_mtu_for_wired (device, out_source); + return nm_device_get_configured_mtu_for_wired (device, out_source, out_force); } static void diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c index d9b83b4284..24593ff1f5 100644 --- a/src/devices/nm-device-infiniband.c +++ b/src/devices/nm-device-infiniband.c @@ -97,7 +97,9 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) } static guint32 -get_configured_mtu (NMDevice *device, NMDeviceMtuSource *out_source) +get_configured_mtu (NMDevice *device, + NMDeviceMtuSource *out_source, + gboolean *out_force) { return nm_device_get_configured_mtu_from_connection (device, NM_TYPE_SETTING_INFINIBAND, diff --git a/src/devices/nm-device-ip-tunnel.c b/src/devices/nm-device-ip-tunnel.c index 34c35fc5b8..0becb5e568 100644 --- a/src/devices/nm-device-ip-tunnel.c +++ b/src/devices/nm-device-ip-tunnel.c @@ -840,7 +840,9 @@ create_and_realize (NMDevice *device, } static guint32 -get_configured_mtu (NMDevice *device, NMDeviceMtuSource *out_source) +get_configured_mtu (NMDevice *device, + NMDeviceMtuSource *out_source, + gboolean *out_force) { return nm_device_get_configured_mtu_from_connection (device, NM_TYPE_SETTING_IP_TUNNEL, diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h index b4bc6a1bfc..e87733ef3f 100644 --- a/src/devices/nm-device-private.h +++ b/src/devices/nm-device-private.h @@ -166,10 +166,11 @@ guint32 nm_device_get_configured_mtu_from_connection (NMDevice *device, GType setting_type, NMDeviceMtuSource *out_source); -guint32 nm_device_get_configured_mtu_for_wired (NMDevice *self, NMDeviceMtuSource *out_source); +guint32 nm_device_get_configured_mtu_for_wired (NMDevice *self, NMDeviceMtuSource *out_source, gboolean *out_force); guint32 nm_device_get_configured_mtu_wired_parent (NMDevice *self, - NMDeviceMtuSource *out_source); + NMDeviceMtuSource *out_source, + gboolean *out_force); void nm_device_commit_mtu (NMDevice *self); diff --git a/src/devices/nm-device-wireguard.c b/src/devices/nm-device-wireguard.c index c769a86be3..d65607089b 100644 --- a/src/devices/nm-device-wireguard.c +++ b/src/devices/nm-device-wireguard.c @@ -1691,7 +1691,7 @@ act_stage3_ip_config_start (NMDevice *device, } static guint32 -get_configured_mtu (NMDevice *device, NMDeviceMtuSource *out_source) +get_configured_mtu (NMDevice *device, NMDeviceMtuSource *out_source, gboolean *out_force) { /* When "MTU" for `wg-quick up` is unset, it calls `ip route get` for * each configured endpoint, to determine the suitable MTU how to reach diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index b6a00df645..57de04d4db 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -9317,7 +9317,9 @@ nm_device_get_configured_mtu_from_connection (NMDevice *self, } guint32 -nm_device_get_configured_mtu_for_wired (NMDevice *self, NMDeviceMtuSource *out_source) +nm_device_get_configured_mtu_for_wired (NMDevice *self, + NMDeviceMtuSource *out_source, + gboolean *out_force) { return nm_device_get_configured_mtu_from_connection (self, NM_TYPE_SETTING_WIRED, @@ -9326,26 +9328,43 @@ nm_device_get_configured_mtu_for_wired (NMDevice *self, NMDeviceMtuSource *out_s guint32 nm_device_get_configured_mtu_wired_parent (NMDevice *self, - NMDeviceMtuSource *out_source) + NMDeviceMtuSource *out_source, + gboolean *out_force) { guint32 mtu = 0; + guint32 parent_mtu = 0; int ifindex; - mtu = nm_device_get_configured_mtu_for_wired (self, out_source); + ifindex = nm_device_parent_get_ifindex (self); + if (ifindex > 0) { + parent_mtu = nm_platform_link_get_mtu (nm_device_get_platform (self), ifindex); + if (parent_mtu >= NM_DEVICE_GET_CLASS (self)->mtu_parent_delta) + parent_mtu -= NM_DEVICE_GET_CLASS (self)->mtu_parent_delta; + else + parent_mtu = 0; + } + + mtu = nm_device_get_configured_mtu_for_wired (self, out_source, NULL); + + if (parent_mtu && mtu > parent_mtu) { + /* Trying to set a MTU that is out of range from configuration: + * fall back to the parent MTU and set force flag so that it + * overrides an MTU with higher priority already configured. + */ + *out_source = NM_DEVICE_MTU_SOURCE_PARENT; + *out_force = TRUE; + return parent_mtu; + } + if (*out_source != NM_DEVICE_MTU_SOURCE_NONE) { nm_assert (mtu > 0); return mtu; } /* Inherit the MTU from parent device, if any */ - ifindex = nm_device_parent_get_ifindex (self); - if (ifindex > 0) { - mtu = nm_platform_link_get_mtu (nm_device_get_platform (self), ifindex); - if (mtu >= NM_DEVICE_GET_CLASS (self)->mtu_parent_delta) { - mtu -= NM_DEVICE_GET_CLASS (self)->mtu_parent_delta; - *out_source = NM_DEVICE_MTU_SOURCE_PARENT; - } else - mtu = 0; + if (parent_mtu) { + mtu = parent_mtu; + *out_source = NM_DEVICE_MTU_SOURCE_PARENT; } return mtu; @@ -9402,6 +9421,7 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config) { guint32 mtu = 0; + gboolean force = FALSE; /* We take the MTU from various sources: (in order of increasing * priority) parent link, IP configuration (which contains the @@ -9417,12 +9437,18 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config) * multiple times. An exception to this is for the PARENT * source, since we need to keep tracking the parent MTU when it * changes. + * + * The subclass can set the @force argument to TRUE to signal that the + * returned MTU should be applied even if it has a lower priority. This + * is useful when the value from a lower source should + * preempt the one from higher ones. */ if (NM_DEVICE_GET_CLASS (self)->get_configured_mtu) - mtu = NM_DEVICE_GET_CLASS (self)->get_configured_mtu (self, &source); + mtu = NM_DEVICE_GET_CLASS (self)->get_configured_mtu (self, &source, &force); if ( config + && !force && source < NM_DEVICE_MTU_SOURCE_IP_CONFIG && nm_ip4_config_get_mtu (config)) { mtu = nm_ip4_config_get_mtu (config); @@ -9431,14 +9457,16 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config) if (mtu != 0) { _LOGT (LOGD_DEVICE, - "mtu: value %u from source '%s' (%u), current source '%s' (%u)", + "mtu: value %u from source '%s' (%u), current source '%s' (%u)%s", (guint) mtu, mtu_source_to_str (source), (guint) source, - mtu_source_to_str (priv->mtu_source), (guint) priv->mtu_source); + mtu_source_to_str (priv->mtu_source), (guint) priv->mtu_source, + force ? " (forced)" : ""); } if ( mtu != 0 - && ( source > priv->mtu_source + && ( force + || source > priv->mtu_source || (priv->mtu_source == NM_DEVICE_MTU_SOURCE_PARENT && source == priv->mtu_source))) mtu_desired = mtu; else { diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index 40d9676d2d..aa2de5a4de 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -325,7 +325,9 @@ typedef struct _NMDeviceClass { NMSettingsConnection *sett_conn, char **specific_object); - guint32 (*get_configured_mtu) (NMDevice *self, NMDeviceMtuSource *out_source); + guint32 (*get_configured_mtu) (NMDevice *self, + NMDeviceMtuSource *out_source, + gboolean *out_force); /* allow the subclass to overwrite the routing table. This is mainly useful * to change from partial mode (route-table=0) to full-sync mode (route-table=254). */ diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c index 8e3aafda12..6b587e3f3b 100644 --- a/src/devices/wifi/nm-device-iwd.c +++ b/src/devices/wifi/nm-device-iwd.c @@ -1865,7 +1865,9 @@ out: } static guint32 -get_configured_mtu (NMDevice *device, NMDeviceMtuSource *out_source) +get_configured_mtu (NMDevice *device, + NMDeviceMtuSource *out_source, + gboolean *out_force) { return nm_device_get_configured_mtu_from_connection (device, NM_TYPE_SETTING_WIRELESS, diff --git a/src/devices/wifi/nm-device-wifi-p2p.c b/src/devices/wifi/nm-device-wifi-p2p.c index cd672f89da..34ff70fa0e 100644 --- a/src/devices/wifi/nm-device-wifi-p2p.c +++ b/src/devices/wifi/nm-device-wifi-p2p.c @@ -604,7 +604,9 @@ deactivate (NMDevice *device) } static guint32 -get_configured_mtu (NMDevice *device, NMDeviceMtuSource *out_source) +get_configured_mtu (NMDevice *device, + NMDeviceMtuSource *out_source, + gboolean *out_force) { *out_source = NM_DEVICE_MTU_SOURCE_NONE; return 0; diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index 04c90058a1..1d49ea4344 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -2895,7 +2895,9 @@ act_stage3_ip_config_start (NMDevice *device, } static guint32 -get_configured_mtu (NMDevice *device, NMDeviceMtuSource *out_source) +get_configured_mtu (NMDevice *device, + NMDeviceMtuSource *out_source, + gboolean *out_force) { return nm_device_get_configured_mtu_from_connection (device, NM_TYPE_SETTING_WIRELESS, diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c index e49cffcfaf..ad6449b17e 100644 --- a/src/devices/wwan/nm-modem.c +++ b/src/devices/wwan/nm-modem.c @@ -910,7 +910,9 @@ nm_modem_stage3_ip6_config_start (NMModem *self, } guint32 -nm_modem_get_configured_mtu (NMDevice *self, NMDeviceMtuSource *out_source) +nm_modem_get_configured_mtu (NMDevice *self, + NMDeviceMtuSource *out_source, + gboolean *out_force) { NMConnection *connection; NMSetting *setting; diff --git a/src/devices/wwan/nm-modem.h b/src/devices/wwan/nm-modem.h index c83ca538b9..f2de990b80 100644 --- a/src/devices/wwan/nm-modem.h +++ b/src/devices/wwan/nm-modem.h @@ -275,7 +275,7 @@ void nm_modem_emit_ip6_config_result (NMModem *self, const char *nm_modem_ip_type_to_string (NMModemIPType ip_type); -guint32 nm_modem_get_configured_mtu (NMDevice *self, NMDeviceMtuSource *out_source); +guint32 nm_modem_get_configured_mtu (NMDevice *self, NMDeviceMtuSource *out_source, gboolean *out_force); void _nm_modem_set_operator_code (NMModem *self, const char *operator_code); void _nm_modem_set_apn (NMModem *self, const char *apn);