summary refs log tree commit diff
path: root/src/nm-checkpoint.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-checkpoint.c')
-rw-r--r--src/nm-checkpoint.c154
1 files changed, 110 insertions, 44 deletions
diff --git a/src/nm-checkpoint.c b/src/nm-checkpoint.c
index 7d89e61e..3f2f0eaa 100644
--- a/src/nm-checkpoint.c
+++ b/src/nm-checkpoint.c
@@ -24,6 +24,7 @@
 
 #include <string.h>
 
+#include "nm-active-connection.h"
 #include "nm-auth-subject.h"
 #include "nm-core-utils.h"
 #include "nm-dbus-interface.h"
@@ -42,6 +43,7 @@ typedef struct {
 	NMDevice *device;
 	NMConnection *applied_connection;
 	NMConnection *settings_connection;
+	guint64 ac_version_id;
 	NMDeviceState state;
 	bool realized:1;
 	bool unmanaged_explicit:1;
@@ -92,7 +94,7 @@ G_DEFINE_TYPE (NMCheckpoint, nm_checkpoint, NM_TYPE_EXPORTED_OBJECT)
 				g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", ""_NMLOG_PREFIX_NAME"", (self)); \
 			else \
 				g_strlcpy (__prefix, _NMLOG_PREFIX_NAME, sizeof (__prefix)); \
-			_nm_log ((level), (_NMLOG_DOMAIN), 0, \
+			_nm_log ((level), (_NMLOG_DOMAIN), 0, NULL, NULL, \
 			          "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
 			          __prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
 		} \
@@ -116,6 +118,62 @@ nm_checkpoint_includes_device (NMCheckpoint *self, NMDevice *device)
 	return g_hash_table_contains (priv->devices, device);
 }
 
+static NMSettingsConnection *
+find_settings_connection (NMCheckpoint *self,
+                          DeviceCheckpoint *dev_checkpoint,
+                          gboolean *need_update,
+                          gboolean *need_activation)
+{
+	NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self);
+	const GSList *active_connections, *iter;
+	NMActiveConnection *active = NULL;
+	NMSettingsConnection *connection;
+	const char *uuid, *ac_uuid;
+
+	*need_activation = FALSE;
+	*need_update = FALSE;
+
+	uuid = nm_connection_get_uuid (dev_checkpoint->settings_connection);
+	connection = nm_settings_get_connection_by_uuid (nm_settings_get (), uuid);
+
+	if (!connection)
+		return NULL;
+
+	/* Now check if the connection changed, ... */
+	if (!nm_connection_compare (dev_checkpoint->settings_connection,
+	                            NM_CONNECTION (connection),
+	                            NM_SETTING_COMPARE_FLAG_EXACT)) {
+		_LOGT ("rollback: settings connection %s changed", uuid);
+		*need_update = TRUE;
+		*need_activation = TRUE;
+	}
+
+	/* ... is active, ... */
+	active_connections = nm_manager_get_active_connections (priv->manager);
+	for (iter = active_connections; iter; iter = g_slist_next (iter)) {
+		active = iter->data;
+		ac_uuid = nm_settings_connection_get_uuid (nm_active_connection_get_settings_connection (active));
+		if (nm_streq (uuid, ac_uuid)) {
+			_LOGT ("rollback: connection %s is active", uuid);
+			break;
+		}
+	}
+
+	if (!iter) {
+		_LOGT ("rollback: connection %s is not active", uuid);
+		*need_activation = TRUE;
+		return connection;
+	}
+
+	/* ... or if the connection was reactivated/reapplied */
+	if (nm_active_connection_version_id_get (active) != dev_checkpoint->ac_version_id) {
+		_LOGT ("rollback: active connection version id of %s changed", uuid);
+		*need_activation = TRUE;
+	}
+
+	return connection;
+}
+
 GVariant *
 nm_checkpoint_rollback (NMCheckpoint *self)
 {
@@ -135,7 +193,6 @@ nm_checkpoint_rollback (NMCheckpoint *self)
 	while (g_hash_table_iter_next (&iter, (gpointer *) &device, (gpointer *) &dev_checkpoint)) {
 		gs_unref_object NMAuthSubject *subject = NULL;
 		guint32 result = NM_ROLLBACK_RESULT_OK;
-		const char *con_uuid;
 
 		_LOGD ("rollback: restoring device %s (state %d, realized %d, explicitly unmanaged %d)",
 		       nm_device_get_iface (device),
@@ -180,27 +237,26 @@ activate:
 		}
 
 		if (dev_checkpoint->applied_connection) {
-			/* The device had an active connection, check if the
-			 * connection still exists
-			 * */
-			con_uuid = nm_connection_get_uuid (dev_checkpoint->settings_connection);
-			connection = nm_settings_get_connection_by_uuid (nm_settings_get (), con_uuid);
+			gboolean need_update, need_activation;
 
+			/* The device had an active connection: check if the
+			 * connection still exists, is active and was changed */
+			connection = find_settings_connection (self, dev_checkpoint, &need_update, &need_activation);
 			if (connection) {
-				/* If the connection is still there, restore its content
-				 * and save it
-				 * */
-				_LOGD ("rollback: connection %s still exists", con_uuid);
-
-				nm_connection_replace_settings_from_connection (NM_CONNECTION (connection),
-				                                                dev_checkpoint->settings_connection);
-				nm_settings_connection_commit_changes (connection,
-				                                       NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE,
-				                                       NULL,
-				                                       NULL);
+				if (need_update) {
+					_LOGD ("rollback: updating connection %s",
+					        nm_settings_connection_get_uuid (connection));
+					nm_connection_replace_settings_from_connection (NM_CONNECTION (connection),
+					                                                dev_checkpoint->settings_connection);
+					nm_settings_connection_commit_changes (connection,
+					                                       NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE,
+					                                       NULL,
+					                                       NULL);
+				}
 			} else {
 				/* The connection was deleted, recreate it */
-				_LOGD ("rollback: adding connection %s again", con_uuid);
+				_LOGD ("rollback: adding connection %s again",
+				       nm_connection_get_uuid (dev_checkpoint->settings_connection));
 
 				connection = nm_settings_add_connection (nm_settings_get (),
 				                                         dev_checkpoint->settings_connection,
@@ -212,24 +268,29 @@ activate:
 					result = NM_ROLLBACK_RESULT_ERR_FAILED;
 					goto next_dev;
 				}
+				need_activation = TRUE;
 			}
 
-			/* Now re-activate the connection */
-			subject = nm_auth_subject_new_internal ();
-			if (!nm_manager_activate_connection (priv->manager,
-			                                     connection,
-			                                     dev_checkpoint->applied_connection,
-			                                     NULL,
-			                                     device,
-			                                     subject,
-			                                     &local_error)) {
-				_LOGW ("rollback: reactivation of connection %s/%s failed: %s",
-				       nm_connection_get_id ((NMConnection *) connection),
-				       nm_connection_get_uuid ((NMConnection *	) connection),
-				       local_error->message);
-				g_clear_error (&local_error);
-				result = NM_ROLLBACK_RESULT_ERR_FAILED;
-				goto next_dev;
+			if (need_activation) {
+				_LOGD ("rollback: reactivating connection %s",
+				       nm_settings_connection_get_uuid (connection));
+				subject = nm_auth_subject_new_internal ();
+				if (!nm_manager_activate_connection (priv->manager,
+				                                     connection,
+				                                     dev_checkpoint->applied_connection,
+				                                     NULL,
+				                                     device,
+				                                     subject,
+				                                     NM_ACTIVATION_TYPE_MANAGED,
+				                                     &local_error)) {
+					_LOGW ("rollback: reactivation of connection %s/%s failed: %s",
+					       nm_connection_get_id ((NMConnection *) connection),
+					       nm_connection_get_uuid ((NMConnection *	) connection),
+					       local_error->message);
+					g_clear_error (&local_error);
+					result = NM_ROLLBACK_RESULT_ERR_FAILED;
+					goto next_dev;
+				}
 			}
 		} else {
 			/* The device was initially disconnected, deactivate any existing connection */
@@ -249,26 +310,25 @@ next_dev:
 
 	if (NM_FLAGS_HAS (priv->flags, NM_CHECKPOINT_CREATE_FLAG_DELETE_NEW_CONNECTIONS)) {
 		NMSettingsConnection *con;
-		gs_free_slist GSList *list = NULL;
-		GSList *item;
+		gs_free NMSettingsConnection **list = NULL;
+		guint i;
 
 		g_return_val_if_fail (priv->connection_uuids, NULL);
-		list = nm_settings_get_connections_sorted (nm_settings_get ());
+		list = nm_settings_get_connections_sorted (nm_settings_get (), NULL);
 
-		for (item = list; item; item = g_slist_next (item)) {
-			con = item->data;
+		for (i = 0; list[i]; i++) {
+			con = list[i];
 			if (!g_hash_table_contains (priv->connection_uuids,
 			                            nm_settings_connection_get_uuid (con))) {
-				_LOGD ("rollback: deleting new connection %s (%s)",
-				       nm_settings_connection_get_uuid (con),
-				       nm_settings_connection_get_id (con));
+				_LOGD ("rollback: deleting new connection %s",
+				       nm_settings_connection_get_uuid (con));
 				nm_settings_connection_delete (con, NULL, NULL);
 			}
 		}
 	}
 
 	if (NM_FLAGS_HAS (priv->flags, NM_CHECKPOINT_CREATE_FLAG_DISCONNECT_NEW_DEVICES)) {
-		const GSList *list = nm_manager_get_devices (priv->manager);
+		const GSList *list;
 		NMDeviceState state;
 		NMDevice *dev;
 
@@ -300,6 +360,7 @@ device_checkpoint_create (NMDevice *device,
 	NMSettingsConnection *settings_connection;
 	const char *path;
 	gboolean unmanaged_explicit;
+	NMActRequest *act_request;
 
 	path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (device));
 	unmanaged_explicit = !!nm_device_get_unmanaged_flags (device,
@@ -321,6 +382,11 @@ device_checkpoint_create (NMDevice *device,
 		g_return_val_if_fail (settings_connection, NULL);
 		dev_checkpoint->settings_connection =
 			nm_simple_connection_new_clone (NM_CONNECTION (settings_connection));
+
+		act_request = nm_device_get_act_request (device);
+		g_return_val_if_fail (act_request, NULL);
+		dev_checkpoint->ac_version_id =
+			nm_active_connection_version_id_get (NM_ACTIVE_CONNECTION (act_request));
 	}
 
 	return dev_checkpoint;