From 2c1fb50fb56ee72b2cb9b7eb712e5c221d70379e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 7 Dec 2022 15:13:39 +0100 Subject: [PATCH] core: support flag "preserve-external-ip" for Reapply() call Reapply() is supposed to make sure that the system (the interface) is configured as indicated by the applied-connection. That means, it will remove/add configuration to make the system match the requested configuration. Add a flag "preserve-external-ip" which relaxes this. During reapply, IP addresses/routes that exist on the interface and which are not known (or added) by NetworkManager will be left alone. This will be used by nm-cloud-setup, so that it can reconfigure the interface in a less destructive way, which does not conflict with external `ip addr/route` calls. Note that the previous commit just adds "VersionInfo" and the possibility to expose capabilities (patch-level). This is not used for the new reapply flag, because, while we might backport the reapply flag, we won't backport the "VersionInfo" property. Exposing new capabilities via the "VersionInfo" property will only become useful in the future, where we can backport a capability to older NM versions (but those that have "VersionInfo" too). --- .../org.freedesktop.NetworkManager.Device.xml | 5 +- src/core/devices/nm-device.c | 73 ++++++++++++------- src/libnm-client-impl/libnm.ver | 1 + src/libnm-client-impl/nm-device.c | 4 +- src/libnm-core-public/nm-dbus-interface.h | 16 ++++ 5 files changed, 68 insertions(+), 31 deletions(-) diff --git a/introspection/org.freedesktop.NetworkManager.Device.xml b/introspection/org.freedesktop.NetworkManager.Device.xml index e694fcda3c..36f7f5d09c 100644 --- a/introspection/org.freedesktop.NetworkManager.Device.xml +++ b/introspection/org.freedesktop.NetworkManager.Device.xml @@ -322,7 +322,7 @@ Reapply: @connection: The optional connection settings that will be reapplied on the device. If empty, the currently active settings-connection will be used. The connection cannot arbitrarily differ from the current applied-connection otherwise the call will fail. Only certain changes are supported, like adding or removing IP addresses. @version_id: If non-zero, the current version id of the applied-connection must match. The current version id can be retrieved via GetAppliedConnection. This optional argument allows to catch concurrent modifications between the GetAppliedConnection call and Reapply. - @flags: Flags which would modify the behavior of the Reapply call. There are no flags defined currently and the users should use the value of 0. + @flags: Flags which would modify the behavior of the Reapply call. Invalid flags are rejected. Attempts to update the configuration of a device without deactivating it. NetworkManager has the concept of connections, which are profiles that @@ -344,6 +344,9 @@ Reapply can make the applied-connection different from the settings-connection, just like updating the settings-connection can make them different. + + Since 1.42, "preserve-external-ip" flag (0x1) is supported to not remove + externally added IP addresses and routes on the device during reapply. --> diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index abfb6c9e26..921c010340 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -12830,6 +12830,7 @@ reapply_connection(NMDevice *self, NMConnection *con_old, NMConnection *con_new) * the current settings connection * @version_id: either zero, or the current version id for the applied * connection. + * @reapply_flags: the #NMDeviceReapplyFlags. * @audit_args: on return, a string representing the changes * @error: the error if %FALSE is returned * @@ -12839,11 +12840,12 @@ reapply_connection(NMDevice *self, NMConnection *con_old, NMConnection *con_new) * Return: %FALSE if the new configuration can not be reapplied. */ static gboolean -check_and_reapply_connection(NMDevice *self, - NMConnection *connection, - guint64 version_id, - char **audit_args, - GError **error) +check_and_reapply_connection(NMDevice *self, + NMConnection *connection, + guint64 version_id, + NMDeviceReapplyFlags reapply_flags, + char **audit_args, + GError **error) { NMDeviceClass *klass = NM_DEVICE_GET_CLASS(self); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); @@ -13011,7 +13013,12 @@ check_and_reapply_connection(NMDevice *self, reactivate_proxy_config(self); - nm_device_l3cfg_commit(self, NM_L3_CFG_COMMIT_TYPE_REAPPLY, FALSE); + nm_device_l3cfg_commit( + self, + NM_FLAGS_HAS(reapply_flags, NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP) + ? NM_L3_CFG_COMMIT_TYPE_UPDATE + : NM_L3_CFG_COMMIT_TYPE_REAPPLY, + FALSE); } if (priv->state >= NM_DEVICE_STATE_IP_CHECK) @@ -13028,12 +13035,18 @@ nm_device_reapply(NMDevice *self, NMConnection *connection, GError **error) { g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - return check_and_reapply_connection(self, connection, 0, NULL, error); + return check_and_reapply_connection(self, + connection, + 0, + NM_DEVICE_REAPPLY_FLAGS_NONE, + NULL, + error); } typedef struct { - NMConnection *connection; - guint64 version_id; + NMConnection *connection; + guint64 version_id; + NMDeviceReapplyFlags reapply_flags; } ReapplyData; static void @@ -13044,16 +13057,16 @@ reapply_cb(NMDevice *self, gpointer user_data) { ReapplyData *reapply_data = user_data; - guint64 version_id = 0; - gs_unref_object NMConnection *connection = NULL; - GError *local = NULL; - gs_free char *audit_args = NULL; + guint64 version_id; + gs_unref_object NMConnection *connection = NULL; + NMDeviceReapplyFlags reapply_flags; + GError *local = NULL; + gs_free char *audit_args = NULL; - if (reapply_data) { - connection = reapply_data->connection; - version_id = reapply_data->version_id; - g_slice_free(ReapplyData, reapply_data); - } + connection = reapply_data->connection; + version_id = reapply_data->version_id; + reapply_flags = reapply_data->reapply_flags; + nm_g_slice_free(reapply_data); if (error) { nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_REAPPLY, @@ -13073,6 +13086,7 @@ reapply_cb(NMDevice *self, connection ?: nm_device_get_settings_connection_get_connection(self), version_id, + reapply_flags, &audit_args, &local)) { nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_REAPPLY, @@ -13106,12 +13120,12 @@ impl_device_reapply(NMDBusObject *obj, ReapplyData *reapply_data; gs_unref_variant GVariant *settings = NULL; guint64 version_id; - guint32 flags; + guint32 reapply_flags_u; + NMDeviceReapplyFlags reapply_flags; - g_variant_get(parameters, "(@a{sa{sv}}tu)", &settings, &version_id, &flags); + g_variant_get(parameters, "(@a{sa{sv}}tu)", &settings, &version_id, &reapply_flags_u); - /* No flags supported as of now. */ - if (flags != 0) { + if (NM_FLAGS_ANY(reapply_flags_u, ~((guint32) NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP))) { error = g_error_new_literal(NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "Invalid flags specified"); nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_REAPPLY, @@ -13124,6 +13138,9 @@ impl_device_reapply(NMDBusObject *obj, return; } + reapply_flags = reapply_flags_u; + nm_assert(reapply_flags_u == reapply_flags); + if (priv->state < NM_DEVICE_STATE_PREPARE || priv->state > NM_DEVICE_STATE_ACTIVATED) { error = g_error_new_literal(NM_DEVICE_ERROR, NM_DEVICE_ERROR_NOT_ACTIVE, @@ -13161,12 +13178,12 @@ impl_device_reapply(NMDBusObject *obj, nm_connection_clear_secrets(connection); } - if (connection || version_id) { - reapply_data = g_slice_new(ReapplyData); - reapply_data->connection = connection; - reapply_data->version_id = version_id; - } else - reapply_data = NULL; + reapply_data = g_slice_new(ReapplyData); + *reapply_data = (ReapplyData){ + .connection = connection, + .version_id = version_id, + .reapply_flags = reapply_flags, + }; nm_device_auth_request(self, invocation, diff --git a/src/libnm-client-impl/libnm.ver b/src/libnm-client-impl/libnm.ver index 9083ac3fd1..8c9a4ef158 100644 --- a/src/libnm-client-impl/libnm.ver +++ b/src/libnm-client-impl/libnm.ver @@ -1885,6 +1885,7 @@ global: nm_client_wait_shutdown; nm_client_wait_shutdown_finish; nm_device_loopback_get_type; + nm_device_reapply_flags_get_type; nm_range_cmp; nm_range_from_str; nm_range_get_range; diff --git a/src/libnm-client-impl/nm-device.c b/src/libnm-client-impl/nm-device.c index fcf07a6b52..ec246afc1a 100644 --- a/src/libnm-client-impl/nm-device.c +++ b/src/libnm-client-impl/nm-device.c @@ -2499,7 +2499,7 @@ nm_device_reapply_finish(NMDevice *device, GAsyncResult *result, GError **error) /** * nm_device_get_applied_connection: * @device: a #NMDevice - * @flags: the flags argument. Currently, this value must always be zero. + * @flags: the flags argument. See #NMDeviceReapplyFlags. * @version_id: (out) (allow-none): returns the current version id of * the applied connection * @cancellable: a #GCancellable, or %NULL @@ -2562,7 +2562,7 @@ nm_device_get_applied_connection(NMDevice *device, /** * nm_device_get_applied_connection_async: * @device: a #NMDevice - * @flags: the flags argument. Currently, this value must always be zero. + * @flags: the flags argument. See #NMDeviceReapplyFlags. * @cancellable: a #GCancellable, or %NULL * @callback: callback to be called when the reapply operation completes * @user_data: caller-specific data passed to @callback diff --git a/src/libnm-core-public/nm-dbus-interface.h b/src/libnm-core-public/nm-dbus-interface.h index bf8eba67d0..9f64f75f0b 100644 --- a/src/libnm-core-public/nm-dbus-interface.h +++ b/src/libnm-core-public/nm-dbus-interface.h @@ -1161,6 +1161,22 @@ typedef enum /*< flags >*/ { NM_SETTINGS_UPDATE2_FLAG_NO_REAPPLY = 0x40, } NMSettingsUpdate2Flags; +/** + * NMDeviceReapplyFlags: + * @NM_DEVICE_REAPPLY_FLAGS_NONE: no flag set. + * @NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP: during reapply, + * preserve external IP addresses and routes. + * + * Flags for the Reapply() D-Bus call of a device and + * nm_device_reapply_async(). + * + * Since: 1.42 + */ +typedef enum /*< flags >*/ { + NM_DEVICE_REAPPLY_FLAGS_NONE = 0, + NM_DEVICE_REAPPLY_FLAGS_PRESERVE_EXTERNAL_IP = 0x1, +} NMDeviceReapplyFlags; + /** * NMTernary: * @NM_TERNARY_DEFAULT: use the globally-configured default value.