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
This commit is contained in:
Beniamino Galvani 2019-09-11 10:57:07 +02:00
parent 4875745bc0
commit ec28f5b343
12 changed files with 73 additions and 28 deletions

View file

@ -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

View file

@ -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,

View file

@ -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,

View file

@ -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);

View file

@ -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

View file

@ -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 {

View file

@ -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). */

View file

@ -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,

View file

@ -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;

View file

@ -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,

View file

@ -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;

View file

@ -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);