manager: save timestamps when shutting down

Connection timestamps are updated (saved to disk) on connection up and
down. This way, the last used connection will take precedence for
autoconnect if they have the same priority.

But as we don't actually do connection down when NM stops, the last
connection timestamp of all active connections is the timestamp of when
they were brought up. Then, the activation order might be wrong on next
start.

One case where timestamps are wrong (although it is not clear how
important it is because the connections are activated on different
interfaces):
1. Activate con1 <- timestamp updated
2. Activate con2 <- timestamp updated
3. Deactivate con2 <- timestamp updated
4. Stop NM <- timestamp of con2 is higher than con1, but con1 was still
   active when con2 was brought down.

Other case that is reproducible (from
https://issues.redhat.com/browse/RHEL-35539):
1. Activate con1
2. Activate con2 on same interface:
   - As a consequence con1 is deactivated and its timestamp updated
   - The timestamp of con2 is also updated
3. Stop NM <- timestamp of con1 and con2 is the same, next activation
   order will be undefined.

Fix by saving the timestamps on NM shutdown.
This commit is contained in:
Íñigo Huguet
2024-05-22 12:37:41 +02:00
parent 60c4da0011
commit 4bf11b7d66

View File

@@ -7960,6 +7960,7 @@ nm_manager_write_device_state_all(NMManager *self)
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
gs_unref_hashtable GHashTable *preserve_ifindexes = NULL; gs_unref_hashtable GHashTable *preserve_ifindexes = NULL;
NMDevice *device; NMDevice *device;
NMActiveConnection *ac;
preserve_ifindexes = g_hash_table_new(nm_direct_hash, NULL); preserve_ifindexes = g_hash_table_new(nm_direct_hash, NULL);
@@ -7971,6 +7972,14 @@ nm_manager_write_device_state_all(NMManager *self)
} }
} }
/* Save to disk the timestamps of active connections as if we were bringing them down.
* Otherwise they will be wrong on next start and affect the activation order.
*/
c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) {
NMSettingsConnection *sett = nm_active_connection_get_settings_connection(ac);
nm_settings_connection_update_timestamp(sett, (guint64) time(NULL));
}
nm_config_device_state_prune_stale(preserve_ifindexes, NULL); nm_config_device_state_prune_stale(preserve_ifindexes, NULL);
} }