diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c
index 5bfb76fb4c..1857602133 100644
--- a/clients/common/nm-meta-setting-desc.c
+++ b/clients/common/nm-meta-setting-desc.c
@@ -7536,6 +7536,9 @@ static const NMMetaPropertyInfo *const property_infos_WIREGUARD[] = {
.base = 16,
),
),
+ PROPERTY_INFO_WITH_DESC (NM_SETTING_WIREGUARD_MTU,
+ .property_type = &_pt_gobject_mtu,
+ ),
NULL
};
diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in
index 235a9c7f30..2bdff62d10 100644
--- a/clients/common/settings-docs.h.in
+++ b/clients/common/settings-docs.h.in
@@ -364,6 +364,7 @@
#define DESCRIBE_DOC_NM_SETTING_WIMAX_NETWORK_NAME N_("Network Service Provider (NSP) name of the WiMAX network this connection should use. Deprecated: 1")
#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_FWMARK N_("The use of fwmark is optional and is by default off. Setting it to 0 disables it. Otherwise it is a 32-bit fwmark for outgoing packets.")
#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_LISTEN_PORT N_("The listen-port. If listen-port is not specified, the port will be chosen randomly when the interface comes up.")
+#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple fragments. If zero a default MTU is used. Note that contrary to wg-quick's MTU setting, this does not take into account the current routes at the time of activation.")
#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_PRIVATE_KEY N_("The 256 bit private-key in base64 encoding.")
#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS N_("Flags indicating how to handle the \"private-key\" property.")
#define DESCRIBE_DOC_NM_SETTING_WPAN_CHANNEL N_("IEEE 802.15.4 channel. A positive integer or -1, meaning \"do not set, use whatever the device is already set to\".")
diff --git a/libnm-core/nm-setting-wireguard.c b/libnm-core/nm-setting-wireguard.c
index 19b418547d..317f30f845 100644
--- a/libnm-core/nm-setting-wireguard.c
+++ b/libnm-core/nm-setting-wireguard.c
@@ -850,10 +850,11 @@ typedef struct {
/*****************************************************************************/
NM_GOBJECT_PROPERTIES_DEFINE_BASE (
+ PROP_FWMARK,
+ PROP_LISTEN_PORT,
+ PROP_MTU,
PROP_PRIVATE_KEY,
PROP_PRIVATE_KEY_FLAGS,
- PROP_LISTEN_PORT,
- PROP_FWMARK,
);
typedef struct {
@@ -862,6 +863,7 @@ typedef struct {
GHashTable *peers_hash;
NMSettingSecretFlags private_key_flags;
guint32 fwmark;
+ guint32 mtu;
guint16 listen_port;
bool private_key_valid:1;
} NMSettingWireGuardPrivate;
@@ -978,6 +980,22 @@ nm_setting_wireguard_get_listen_port (NMSettingWireGuard *self)
return NM_SETTING_WIREGUARD_GET_PRIVATE (self)->listen_port;
}
+/**
+ * nm_setting_wireguard_get_mtu:
+ * @self: the #NMSettingWireGuard instance
+ *
+ * Returns: the MTU of the setting.
+ *
+ * Since: 1.16
+ */
+guint32
+nm_setting_wireguard_get_mtu (NMSettingWireGuard *self)
+{
+ g_return_val_if_fail (NM_IS_SETTING_WIREGUARD (self), 0);
+
+ return NM_SETTING_WIREGUARD_GET_PRIVATE (self)->mtu;
+}
+
/*****************************************************************************/
static void
@@ -2160,18 +2178,21 @@ get_property (GObject *object, guint prop_id,
NMSettingWireGuardPrivate *priv = NM_SETTING_WIREGUARD_GET_PRIVATE (setting);
switch (prop_id) {
+ case PROP_FWMARK:
+ g_value_set_uint (value, priv->fwmark);
+ break;
+ case PROP_LISTEN_PORT:
+ g_value_set_uint (value, priv->listen_port);
+ break;
+ case PROP_MTU:
+ g_value_set_uint (value, priv->mtu);
+ break;
case PROP_PRIVATE_KEY:
g_value_set_string (value, priv->private_key);
break;
case PROP_PRIVATE_KEY_FLAGS:
g_value_set_flags (value, priv->private_key_flags);
break;
- case PROP_LISTEN_PORT:
- g_value_set_uint (value, priv->listen_port);
- break;
- case PROP_FWMARK:
- g_value_set_uint (value, priv->fwmark);
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -2186,6 +2207,15 @@ set_property (GObject *object, guint prop_id,
const char *str;
switch (prop_id) {
+ case PROP_FWMARK:
+ priv->fwmark = g_value_get_uint (value);
+ break;
+ case PROP_LISTEN_PORT:
+ priv->listen_port = g_value_get_uint (value);
+ break;
+ case PROP_MTU:
+ priv->mtu = g_value_get_uint (value);
+ break;
case PROP_PRIVATE_KEY:
nm_clear_pointer (&priv->private_key, nm_free_secret);
str = g_value_get_string (value);
@@ -2203,12 +2233,6 @@ set_property (GObject *object, guint prop_id,
case PROP_PRIVATE_KEY_FLAGS:
priv->private_key_flags = g_value_get_flags (value);
break;
- case PROP_LISTEN_PORT:
- priv->listen_port = g_value_get_uint (value);
- break;
- case PROP_FWMARK:
- priv->fwmark = g_value_get_uint (value);
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -2338,6 +2362,25 @@ nm_setting_wireguard_class_init (NMSettingWireGuardClass *klass)
| NM_SETTING_PARAM_INFERRABLE
| G_PARAM_STATIC_STRINGS);
+ /**
+ * NMSettingWireGuard:mtu:
+ *
+ * If non-zero, only transmit packets of the specified size or smaller,
+ * breaking larger packets up into multiple fragments.
+ *
+ * If zero a default MTU is used. Note that contrary to wg-quick's MTU
+ * setting, this does not take into account the current routes at the
+ * time of activation.
+ *
+ * Since: 1.16
+ **/
+ obj_properties[PROP_MTU] =
+ g_param_spec_uint (NM_SETTING_WIREGUARD_MTU, "", "",
+ 0, G_MAXUINT32, 0,
+ G_PARAM_READWRITE
+ | NM_SETTING_PARAM_INFERRABLE
+ | G_PARAM_STATIC_STRINGS);
+
/* ---dbus---
* property: peers
* format: array of 'a{sv}'
diff --git a/libnm-core/nm-setting-wireguard.h b/libnm-core/nm-setting-wireguard.h
index 3810aa3048..257439267c 100644
--- a/libnm-core/nm-setting-wireguard.h
+++ b/libnm-core/nm-setting-wireguard.h
@@ -126,19 +126,21 @@ int nm_wireguard_peer_cmp (const NMWireGuardPeer *a,
#define NM_SETTING_WIREGUARD_SETTING_NAME "wireguard"
+#define NM_SETTING_WIREGUARD_FWMARK "fwmark"
+#define NM_SETTING_WIREGUARD_LISTEN_PORT "listen-port"
#define NM_SETTING_WIREGUARD_PRIVATE_KEY "private-key"
#define NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS "private-key-flags"
-#define NM_SETTING_WIREGUARD_LISTEN_PORT "listen-port"
-#define NM_SETTING_WIREGUARD_FWMARK "fwmark"
#define NM_SETTING_WIREGUARD_PEERS "peers"
-#define NM_WIREGUARD_PEER_ATTR_PUBLIC_KEY "public-key"
+#define NM_SETTING_WIREGUARD_MTU "mtu"
+
+#define NM_WIREGUARD_PEER_ATTR_ALLOWED_IPS "allowed-ips"
#define NM_WIREGUARD_PEER_ATTR_ENDPOINT "endpoint"
+#define NM_WIREGUARD_PEER_ATTR_PERSISTENT_KEEPALIVE "persistent-keepalive"
#define NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY "preshared-key"
#define NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY_FLAGS "preshared-key-flags"
-#define NM_WIREGUARD_PEER_ATTR_ALLOWED_IPS "allowed-ips"
-#define NM_WIREGUARD_PEER_ATTR_PERSISTENT_KEEPALIVE "persistent-keepalive"
+#define NM_WIREGUARD_PEER_ATTR_PUBLIC_KEY "public-key"
/*****************************************************************************/
@@ -194,6 +196,9 @@ gboolean nm_setting_wireguard_remove_peer (NMSettingWireGuard *self,
NM_AVAILABLE_IN_1_16
guint nm_setting_wireguard_clear_peers (NMSettingWireGuard *self);
+NM_AVAILABLE_IN_1_16
+guint32 nm_setting_wireguard_get_mtu (NMSettingWireGuard *self);
+
/*****************************************************************************/
G_END_DECLS
diff --git a/libnm/libnm.ver b/libnm/libnm.ver
index 136b0009de..cd523dae04 100644
--- a/libnm/libnm.ver
+++ b/libnm/libnm.ver
@@ -1466,6 +1466,7 @@ global:
nm_setting_wireguard_clear_peers;
nm_setting_wireguard_get_fwmark;
nm_setting_wireguard_get_listen_port;
+ nm_setting_wireguard_get_mtu;
nm_setting_wireguard_get_peer;
nm_setting_wireguard_get_peer_by_public_key;
nm_setting_wireguard_get_peers_len;
diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml
index b6577aed50..289342473a 100644
--- a/man/NetworkManager.conf.xml
+++ b/man/NetworkManager.conf.xml
@@ -827,6 +827,9 @@ ipv6.ip6-privacy=0
wifi.wake-on-wlan
+
+ wireguard.mtu
+
diff --git a/src/devices/nm-device-wireguard.c b/src/devices/nm-device-wireguard.c
index d08d6ad7af..4e8d630e48 100644
--- a/src/devices/nm-device-wireguard.c
+++ b/src/devices/nm-device-wireguard.c
@@ -1247,6 +1247,34 @@ act_stage2_config (NMDevice *device,
return NM_ACT_STAGE_RETURN_FAILURE;
}
+static guint32
+get_configured_mtu (NMDevice *device, NMDeviceMtuSource *out_source)
+{
+ /* 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
+ * each endpoint.
+ * For `wg-quick` this works very well, because whenever the script runs it
+ * determines the best setting at that point in time. It's simply not concerned
+ * with what happens later (and it's not around anyway).
+ *
+ * NetworkManager sticks around, so the right MTU would need to be re-determined
+ * whenever anything relevant changes. Which basically means, to re-evaluate whenever
+ * something related to addresses or routing changes (which happens all the time).
+ *
+ * The correct MTU indeed depends on the MTU setting of other interfaces (or routes).
+ * But it's still odd, that activating/deactivating a seemingly unrelated interface
+ * would trigger an MTU change. It's odd to explain/document and odd to implemented
+ * -- despite this being the reality.
+ *
+ * For now, only support configuring an explicit MTU, or leave the setting untouched.
+ * The same limitiation also applies to other "ip-tunnel" types, where we could use
+ * similar smarts for autodetecting the MTU.
+ */
+ return nm_device_get_configured_mtu_from_connection (device,
+ NM_TYPE_SETTING_WIREGUARD,
+ out_source);
+}
+
static void
device_state_changed (NMDevice *device,
NMDeviceState new_state,
@@ -1275,8 +1303,17 @@ can_reapply_change (NMDevice *device,
GError **error)
{
if (nm_streq (setting_name, NM_SETTING_WIREGUARD_SETTING_NAME)) {
- /* we allow reapplying all WireGuard settings. */
- return TRUE;
+ /* Most, but not all WireGuard settings can be reapplied. Whitelist.
+ *
+ * MTU cannot be reapplied. */
+ return nm_device_hash_check_invalid_keys (diffs,
+ NM_SETTING_WIREGUARD_SETTING_NAME,
+ error,
+ NM_SETTING_WIREGUARD_FWMARK,
+ NM_SETTING_WIREGUARD_LISTEN_PORT,
+ NM_SETTING_WIREGUARD_PEERS,
+ NM_SETTING_WIREGUARD_PRIVATE_KEY,
+ NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS);
}
return NM_DEVICE_CLASS (nm_device_wireguard_parent_class)->can_reapply_change (device,
@@ -1451,6 +1488,7 @@ nm_device_wireguard_class_init (NMDeviceWireGuardClass *klass)
device_class->update_connection = update_connection;
device_class->can_reapply_change = can_reapply_change;
device_class->reapply_connection = reapply_connection;
+ device_class->get_configured_mtu = get_configured_mtu;
obj_properties[PROP_PUBLIC_KEY] =
g_param_spec_variant (NM_DEVICE_WIREGUARD_PUBLIC_KEY,
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index cf4bb4d971..b24c9a7731 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -8871,6 +8871,10 @@ nm_device_get_configured_mtu_from_connection (NMDevice *self,
if (setting)
mtu = nm_setting_ip_tunnel_get_mtu (NM_SETTING_IP_TUNNEL (setting));
global_property_name = NM_CON_DEFAULT ("ip-tunnel.mtu");
+ } else if (setting_type == NM_TYPE_SETTING_WIREGUARD) {
+ if (setting)
+ mtu = nm_setting_wireguard_get_mtu (NM_SETTING_WIREGUARD (setting));
+ global_property_name = NM_CON_DEFAULT ("wireguard.mtu");
} else
g_return_val_if_reached (0);