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).
This commit is contained in:
Thomas Haller 2022-12-07 15:13:39 +01:00
parent b88cdf2a6b
commit 2c1fb50fb5
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
5 changed files with 68 additions and 31 deletions

View file

@ -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.
-->
<method name="Reapply">
<arg name="connection" type="a{sa{sv}}" direction="in"/>

View file

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

View file

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

View file

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

View file

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