import UBI NetworkManager-1.46.0-8.el9_4

This commit is contained in:
eabdullin 2024-06-13 07:39:51 +00:00
parent e6659a867b
commit 6452331306
4 changed files with 753 additions and 1 deletions

View File

@ -0,0 +1,40 @@
From 6394c2b262d86824a41ca82ad76288c06bfd1989 Mon Sep 17 00:00:00 2001
From: Fernando Fernandez Mancera <ffmancera@riseup.net>
Date: Tue, 26 Mar 2024 12:53:27 +0100
Subject: [PATCH] libnm-lldp: use ETH_P_ALL instead of NM_ETHERTYPE_LLDP for
the socket
When creating the socket for listening to LLDP frames we are setting
NM_ETHERTYPE_LLDP (0x88cc) as protocol. In most of the cases, that is
correct but when the interface is attached as a port to a OVS bridge,
kernel is not matching the protocol correctly. The reason might be that
some metadata is added to the packet, but we are not completely sure
about it.
Instead, we should use ETH_P_ALL to match all the protocols. Later, we
have a eBPF filter to drop the packet by multicast MAC address or
protocol. This is how lldpd is doing it for example.
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1903
(cherry picked from commit 9ac1d6e22bfac7f576dec034a26ac7c9012e5b80)
(cherry picked from commit 2fac176986f3afaa84242e069613cc543bfcc58c)
---
src/libnm-lldp/nm-lldp-network.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/libnm-lldp/nm-lldp-network.c b/src/libnm-lldp/nm-lldp-network.c
index 811c3a7291..28cc745249 100644
--- a/src/libnm-lldp/nm-lldp-network.c
+++ b/src/libnm-lldp/nm-lldp-network.c
@@ -46,7 +46,7 @@ nm_lldp_network_bind_raw_socket(int ifindex)
assert(ifindex > 0);
- fd = socket(AF_PACKET, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, htobe16(NM_ETHERTYPE_LLDP));
+ fd = socket(AF_PACKET, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, htobe16(ETH_P_ALL));
if (fd < 0)
return -errno;
--
2.44.0

View File

@ -0,0 +1,210 @@
From ed5cbbc5847527ed0cfc33f521f7c724975c846b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=8D=C3=B1igo=20Huguet?= <ihuguet@redhat.com>
Date: Tue, 30 Apr 2024 12:45:04 +0200
Subject: [PATCH] platform: avoid routes resync for routes that we don't track
When we recibe a Netlink message with a "route change" event, normally
we just ignore it if it's a route that we don't track (i.e. because of
the route protocol).
However, it's not that easy if it has the NLM_F_REPLACE flag because
that means that it might be replacing another route. If the kernel has
similar routes which are candidates for the replacement, it's hard for
NM to guess which one of those is being replaced (as the kernel doesn't
have a "route ID" or similar field to indicate it). Moreover, the kernel
might choose to replace a route that we don't have on cache, so we know
nothing about it.
It is important to note that we cannot just discard Netlink messages of
routes that we don't track if they has the NLM_F_REPLACE. For example,
if we are tracking a route with proto=static, we might receive a replace
message, changing that route to proto=other_proto_that_we_dont_track. We
need to process that message and remove the route from our cache.
As NM doesn't know what route is being replaced, trying to guess will
lead to errors that will leave the cache in an inconsistent state.
Because of that, it just do a cache resync for the routes.
For IPv4 there was an optimization to this: if we don't have in the
cache any route candidate for the replacement there are only 2 possible
options: either add the new route to the cache or discard it if we are
not interested on it. We don't need a resync for that.
This commit is extending that optimization to IPv6 routes. There is no
reason why it shouldn't work in the same way than with IPv4. This
optimization will only work well as long as we find potential candidate
routes in the same way than the kernel (comparing the same fields). NM
calls to this "comparing by WEAK_ID". But this can also happen with IPv4
routes.
It is worth it to enable this optimization because there are routing
daemons using custom routing protocols that makes tens or hundreds of
updates per second. If they use NLM_F_REPLACE, this caused NM to do a
resync hundreds of times per second leading to a 100% CPU usage:
https://issues.redhat.com/browse/RHEL-26195
An additional but smaller optimization is done in this commit: if we
receive a route message for routes that we don't track AND doesn't have
the NLM_F_REPLACE flag, we can ignore the entire message, thus avoiding
the memory allocation of the nmp_object. That nmp_object was going to be
ignored later, anyway, so better to avoid these allocations that, with
the routing daemon of the above's example, can happen hundreds of times
per second.
With this changes, the CPU usage doing `ip route replace` 300 times/s
drops from 100% to 1%. Doing `ip route replace` as fast as possible,
without any rate limitting, still keeps NM with a 3% CPU usage in the
system that I have used to test.
(cherry picked from commit 4d426f581de402e0aebd2ab273ff6649a0a6fee6)
(cherry picked from commit 15ffa8ec6ff7bf43ed1eb123c0d419d6fab8b268)
---
src/libnm-platform/nm-linux-platform.c | 69 ++++++++++++++++----------
src/libnm-platform/nmp-object.c | 22 +++++---
2 files changed, 57 insertions(+), 34 deletions(-)
diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c
index 9ecac2d9b3..5b595a9b71 100644
--- a/src/libnm-platform/nm-linux-platform.c
+++ b/src/libnm-platform/nm-linux-platform.c
@@ -3903,6 +3903,34 @@ _new_from_nl_addr(const struct nlmsghdr *nlh, gboolean id_only)
return g_steal_pointer(&obj);
}
+static gboolean
+ip_route_is_tracked(guint8 proto, guint8 type)
+{
+ if (proto > RTPROT_STATIC && !NM_IN_SET(proto, RTPROT_DHCP, RTPROT_RA)) {
+ /* We ignore certain rtm_protocol, because NetworkManager would only ever
+ * configure certain protocols. Other routes are not configured by NetworkManager
+ * and we don't track them in the platform cache.
+ *
+ * This is to help with the performance overhead of a huge number of
+ * routes, for example with the bird BGP software, that adds routes
+ * with RTPROT_BIRD protocol. */
+ return FALSE;
+ }
+
+ if (!NM_IN_SET(type,
+ RTN_UNICAST,
+ RTN_LOCAL,
+ RTN_BLACKHOLE,
+ RTN_UNREACHABLE,
+ RTN_PROHIBIT,
+ RTN_THROW)) {
+ /* Certain route types are ignored and not placed into the cache. */
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
/* Copied and heavily modified from libnl3's rtnl_route_parse() and parse_multipath(). */
static NMPObject *
_new_from_nl_route(const struct nlmsghdr *nlh, gboolean id_only, ParseNlmsgIter *parse_nlmsg_iter)
@@ -3963,6 +3991,16 @@ _new_from_nl_route(const struct nlmsghdr *nlh, gboolean id_only, ParseNlmsgIter
* only handle ~supported~ routes.
*****************************************************************/
+ /* If it's a route that we don't need to track, abort here to avoid unnecessary
+ * memory allocations to create the nmp_object. However, if the message has the
+ * NLM_F_REPLACE flag, it might be replacing a route that we were tracking so we
+ * have to stop tracking it. That means that we have to process all messages with
+ * NLM_F_REPLACE. See nmp_cache_update_netlink_route().
+ */
+ if (!ip_route_is_tracked(rtm->rtm_protocol, rtm->rtm_type)
+ && !(nlh->nlmsg_flags & NLM_F_REPLACE))
+ return NULL;
+
addr_family = rtm->rtm_family;
if (addr_family == AF_INET)
@@ -5519,39 +5557,18 @@ ip_route_get_lock_flag(const NMPlatformIPRoute *route)
static gboolean
ip_route_is_alive(const NMPlatformIPRoute *route)
{
- guint8 prot;
+ guint8 proto, type;
nm_assert(route);
nm_assert(route->rt_source >= NM_IP_CONFIG_SOURCE_RTPROT_UNSPEC
&& route->rt_source <= _NM_IP_CONFIG_SOURCE_RTPROT_LAST);
- prot = route->rt_source - 1;
-
- nm_assert(nmp_utils_ip_config_source_from_rtprot(prot) == route->rt_source);
-
- if (prot > RTPROT_STATIC && !NM_IN_SET(prot, RTPROT_DHCP, RTPROT_RA)) {
- /* We ignore certain rtm_protocol, because NetworkManager would only ever
- * configure certain protocols. Other routes are not configured by NetworkManager
- * and we don't track them in the platform cache.
- *
- * This is to help with the performance overhead of a huge number of
- * routes, for example with the bird BGP software, that adds routes
- * with RTPROT_BIRD protocol. */
- return FALSE;
- }
+ proto = route->rt_source - 1;
+ type = nm_platform_route_type_uncoerce(route->type_coerced);
- if (!NM_IN_SET(nm_platform_route_type_uncoerce(route->type_coerced),
- RTN_UNICAST,
- RTN_LOCAL,
- RTN_BLACKHOLE,
- RTN_UNREACHABLE,
- RTN_PROHIBIT,
- RTN_THROW)) {
- /* Certain route types are ignored and not placed into the cache. */
- return FALSE;
- }
+ nm_assert(nmp_utils_ip_config_source_from_rtprot(proto) == route->rt_source);
- return TRUE;
+ return ip_route_is_tracked(proto, type);
}
/* Copied and modified from libnl3's build_route_msg() and rtnl_route_build_msg(). */
diff --git a/src/libnm-platform/nmp-object.c b/src/libnm-platform/nmp-object.c
index 4090da71a3..cb4e9764d1 100644
--- a/src/libnm-platform/nmp-object.c
+++ b/src/libnm-platform/nmp-object.c
@@ -2988,6 +2988,13 @@ nmp_cache_update_netlink_route(NMPCache *cache,
* Since we don't cache all routes (see "route_is_alive"), we cannot know
* with certainty which route was replaced.
*
+ * For example, the kernel might have 3 similar routes (same WEAK_ID), one
+ * of which is not tracked by us so we don't have it into the cache. If we
+ * receive a route replace message, we don't know to what of the 3 routes
+ * it affects (one of the 3 we don't even know that exists). Moreover, if
+ * we only have one route on cache, we don't know if the replace is for a
+ * different one that we don't track.
+ *
* Even if we would cache *all* routes (which we cannot, if kernel adds new
* routing features that modify the known nmp_object_id_equal()), it would
* be hard to find the right route that was replaced. Well, probably we
@@ -3002,15 +3009,14 @@ nmp_cache_update_netlink_route(NMPCache *cache,
* [2] https://bugzilla.redhat.com/show_bug.cgi?id=1337860
*
* We need to resync.
+ *
+ * However, a resync is expensive. Think of a routing daemon that updates
+ * hundreds of routes per second, the performance penalty is huge. We can
+ * optimize it: if we don't have any matching route on cache (by WEAK_ID),
+ * we don't have anything to replace and we don't need a full resync, but
+ * only to add or discard the new route as usual.
*/
- if (NMP_OBJECT_GET_TYPE(obj_hand_over) == NMP_OBJECT_TYPE_IP4_ROUTE
- && !nmp_cache_lookup_all(cache, NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID, obj_hand_over)) {
- /* For IPv4, we can do a small optimization. We skip the resync, if we have
- * no conflicting routes (by weak-id).
- *
- * This optimization does not work for IPv6 (maybe should be fixed).
- */
- } else {
+ if (nmp_cache_lookup_all(cache, NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID, obj_hand_over)) {
entry_replace = NULL;
resync_required = TRUE;
goto out;
--
2.44.0

View File

@ -0,0 +1,487 @@
From d6837f0bd30da069d327099cb555854630cd4584 Mon Sep 17 00:00:00 2001
From: Beniamino Galvani <bgalvani@redhat.com>
Date: Thu, 2 May 2024 16:40:26 +0200
Subject: [PATCH 1/2] settings: add
nm_settings_connection_persist_mode_to_string()
(cherry picked from commit a48b7fe7b9d8adf4902c7b3cfcc4d89bc46cbbef)
(cherry picked from commit e5837aa1d3960b743adcff0a5041445ccd65fb93)
---
src/core/settings/nm-settings-connection.c | 23 ++++++++++++++++++++++
src/core/settings/nm-settings-connection.h | 4 ++++
2 files changed, 27 insertions(+)
diff --git a/src/core/settings/nm-settings-connection.c b/src/core/settings/nm-settings-connection.c
index 176cc2c252..459c60ad1e 100644
--- a/src/core/settings/nm-settings-connection.c
+++ b/src/core/settings/nm-settings-connection.c
@@ -226,6 +226,29 @@ static guint _get_seen_bssids(NMSettingsConnection *self,
/*****************************************************************************/
+char *
+nm_settings_connection_persist_mode_to_string(NMSettingsConnectionPersistMode mode)
+{
+ switch (mode) {
+ case NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY:
+ return "in-memory";
+ case NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_DETACHED:
+ return "in-memory-detached";
+ case NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY:
+ return "in-memory-only";
+ case NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP:
+ return "keep";
+ case NM_SETTINGS_CONNECTION_PERSIST_MODE_NO_PERSIST:
+ return "no-persist";
+ case NM_SETTINGS_CONNECTION_PERSIST_MODE_TO_DISK:
+ return "to-disk";
+ }
+
+ return nm_assert_unreachable_val(NULL);
+}
+
+/*****************************************************************************/
+
NMSettings *
nm_settings_connection_get_settings(NMSettingsConnection *self)
{
diff --git a/src/core/settings/nm-settings-connection.h b/src/core/settings/nm-settings-connection.h
index 835a978e40..d15a75b749 100644
--- a/src/core/settings/nm-settings-connection.h
+++ b/src/core/settings/nm-settings-connection.h
@@ -379,4 +379,8 @@ void _nm_settings_connection_emit_signal_updated_internal(
void _nm_settings_connection_cleanup_after_remove(NMSettingsConnection *self);
+/*****************************************************************************/
+
+char *nm_settings_connection_persist_mode_to_string(NMSettingsConnectionPersistMode mode);
+
#endif /* __NETWORKMANAGER_SETTINGS_CONNECTION_H__ */
--
2.41.0
From c6f9d0a6d5c864ba0141b6e985727cd69c5560fa Mon Sep 17 00:00:00 2001
From: Beniamino Galvani <bgalvani@redhat.com>
Date: Mon, 15 Apr 2024 10:51:24 +0200
Subject: [PATCH 2/2] checkpoint: preserve in-memory state of connections
If a connection is in-memory (i.e. has flag "unsaved"), after a
checkpoint and rollback it can be wrongly persisted to disk:
- if the connection was modified and written to disk after the
rollback, during the rollback we update it again with persist mode
"keep", which keeps it on disk;
- if the connection was deleted after the rollback, during the
rollback we add it again with persist mode "to-disk".
Instead, remember whether the connection had the "unsaved" flag set
and try to restore the previous state.
However, this is not straightforward as there are 4 different possible
states for the settings connection: persistent; in-memory only;
in-memory shadowing a persistent file; in-memory shadowing a detached
persistent file (i.e. the deletion of the connection doesn't delete
the persistent file). Handle all those cases.
Fixes: 3e09aed2a09f ('checkpoint: add create, rollback and destroy D-Bus API')
(cherry picked from commit c979bfeb8b0d3bed19bac2ad01a6a6ed899f924e)
(cherry picked from commit ebf25794d9cd89190775ac401c36d63aa1c108f7)
---
NEWS | 8 ++
src/core/nm-checkpoint.c | 242 ++++++++++++++++++++++++++++++++-------
2 files changed, 211 insertions(+), 39 deletions(-)
diff --git a/NEWS b/NEWS
index 6ac3118db9..e33152c6f4 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,11 @@
+===============================================
+NetworkManager-1.46.2
+Overview of changes since NetworkManager-1.46.0
+===============================================
+
+* Properly restore in-memory connection profiles during the rollback
+ of a checkpoint.
+
=============================================
NetworkManager-1.46
Overview of changes since NetworkManager-1.44
diff --git a/src/core/nm-checkpoint.c b/src/core/nm-checkpoint.c
index cc5c189bf9..ffcf6e3aad 100644
--- a/src/core/nm-checkpoint.c
+++ b/src/core/nm-checkpoint.c
@@ -10,6 +10,7 @@
#include "nm-active-connection.h"
#include "nm-act-request.h"
#include "libnm-core-aux-intern/nm-auth-subject.h"
+#include "libnm-core-intern/nm-keyfile-internal.h"
#include "nm-core-utils.h"
#include "nm-dbus-interface.h"
#include "devices/nm-device.h"
@@ -17,6 +18,7 @@
#include "nm-manager.h"
#include "settings/nm-settings.h"
#include "settings/nm-settings-connection.h"
+#include "settings/plugins/keyfile/nms-keyfile-storage.h"
#include "nm-simple-connection.h"
#include "nm-utils.h"
@@ -29,11 +31,14 @@ typedef struct {
NMDevice *device;
NMConnection *applied_connection;
NMConnection *settings_connection;
+ NMConnection *settings_connection_shadowed;
guint64 ac_version_id;
NMDeviceState state;
bool is_software : 1;
bool realized : 1;
bool activation_lifetime_bound_to_profile_visibility : 1;
+ bool settings_connection_is_unsaved : 1;
+ bool settings_connection_is_shadowed_owned : 1;
NMUnmanFlagOp unmanaged_explicit;
NMActivationReason activation_reason;
gulong dev_exported_change_id;
@@ -150,37 +155,111 @@ nm_checkpoint_includes_devices_of(NMCheckpoint *self, NMCheckpoint *cp_for_devic
return NULL;
}
+static NMConnection *
+parse_connection_from_shadowed_file(const char *path, GError **error)
+{
+ nm_auto_unref_keyfile GKeyFile *keyfile = NULL;
+ gs_free char *base_dir = NULL;
+ char *sep;
+
+ keyfile = g_key_file_new();
+ if (!g_key_file_load_from_file(keyfile, path, G_KEY_FILE_NONE, error))
+ return NULL;
+
+ sep = strrchr(path, '/');
+ base_dir = g_strndup(path, sep - path);
+
+ return nm_keyfile_read(keyfile, base_dir, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, error);
+}
+
static NMSettingsConnection *
-find_settings_connection(NMCheckpoint *self,
- DeviceCheckpoint *dev_checkpoint,
- gboolean *need_update,
- gboolean *need_activation)
+find_settings_connection(NMCheckpoint *self,
+ DeviceCheckpoint *dev_checkpoint,
+ gboolean *need_update,
+ gboolean *need_update_shadowed,
+ gboolean *need_activation,
+ NMSettingsConnectionPersistMode *persist_mode)
{
NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE(self);
NMActiveConnection *active;
NMSettingsConnection *sett_conn;
+ const char *shadowed_file;
+ NMConnection *shadowed_connection = NULL;
const char *uuid, *ac_uuid;
const CList *tmp_clist;
-
- *need_activation = FALSE;
- *need_update = FALSE;
+ gboolean sett_conn_unsaved;
+ NMSettingsStorage *storage;
+
+ *need_activation = FALSE;
+ *need_update = FALSE;
+ *need_update_shadowed = FALSE;
+
+ /* With regard to storage, there are 4 different possible states for the settings
+ * connection: 1) persistent; 2) in-memory only; 3) in-memory shadowing a persistent
+ * file; 4) in-memory shadowing a detached persistent file (i.e. the deletion of
+ * the connection doesn't delete the persistent file).
+ */
+ if (dev_checkpoint->settings_connection_is_unsaved) {
+ if (dev_checkpoint->settings_connection_shadowed) {
+ if (dev_checkpoint->settings_connection_is_shadowed_owned)
+ *persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY;
+ else
+ *persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_DETACHED;
+ } else
+ *persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY;
+ } else {
+ *persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_TO_DISK;
+ }
uuid = nm_connection_get_uuid(dev_checkpoint->settings_connection);
sett_conn = nm_settings_get_connection_by_uuid(NM_SETTINGS_GET, uuid);
- if (!sett_conn)
- return NULL;
-
- /* Now check if the connection changed, ... */
- if (!nm_connection_compare(dev_checkpoint->settings_connection,
- nm_settings_connection_get_connection(sett_conn),
- NM_SETTING_COMPARE_FLAG_EXACT)) {
+ /* Check if the connection changed */
+ if (sett_conn
+ && !nm_connection_compare(dev_checkpoint->settings_connection,
+ nm_settings_connection_get_connection(sett_conn),
+ NM_SETTING_COMPARE_FLAG_IGNORE_TIMESTAMP)) {
_LOGT("rollback: settings connection %s changed", uuid);
*need_update = TRUE;
*need_activation = TRUE;
}
- /* ... is active, ... */
+ storage = sett_conn ? nm_settings_connection_get_storage(sett_conn) : NULL;
+ shadowed_file = storage ? nm_settings_storage_get_shadowed_storage(storage, NULL) : NULL;
+ shadowed_connection =
+ shadowed_file ? parse_connection_from_shadowed_file(shadowed_file, NULL) : NULL;
+
+ if (dev_checkpoint->settings_connection_shadowed) {
+ if (!shadowed_connection
+ || !nm_connection_compare(dev_checkpoint->settings_connection_shadowed,
+ shadowed_connection,
+ NM_SETTING_COMPARE_FLAG_IGNORE_TIMESTAMP)) {
+ _LOGT("rollback: shadowed connection changed for %s", uuid);
+ *need_update_shadowed = TRUE;
+ *need_update = TRUE;
+ }
+ } else {
+ if (shadowed_connection) {
+ _LOGT("rollback: shadowed connection changed for %s", uuid);
+ *need_update = TRUE;
+ }
+ }
+
+ if (!sett_conn)
+ return NULL;
+
+ /* Check if the connection unsaved flag changed */
+ sett_conn_unsaved = NM_FLAGS_HAS(nm_settings_connection_get_flags(sett_conn),
+ NM_SETTINGS_CONNECTION_INT_FLAGS_UNSAVED);
+ if (sett_conn_unsaved != dev_checkpoint->settings_connection_is_unsaved) {
+ _LOGT("rollback: storage changed for settings connection %s: unsaved (%d -> %d)",
+ uuid,
+ dev_checkpoint->settings_connection_is_unsaved,
+ sett_conn_unsaved);
+ *need_update = TRUE;
+ }
+
+ /* Check if the active state changed */
nm_manager_for_each_active_connection (priv->manager, active, tmp_clist) {
ac_uuid =
nm_settings_connection_get_uuid(nm_active_connection_get_settings_connection(active));
@@ -196,7 +275,7 @@ find_settings_connection(NMCheckpoint *self,
return sett_conn;
}
- /* ... or if the connection was reactivated/reapplied */
+ /* Check 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;
@@ -212,12 +291,19 @@ restore_and_activate_connection(NMCheckpoint *self, DeviceCheckpoint *dev_checkp
NMSettingsConnection *connection;
gs_unref_object NMAuthSubject *subject = NULL;
GError *local_error = NULL;
- gboolean need_update, need_activation;
+ gboolean need_update;
+ gboolean need_update_shadowed;
+ gboolean need_activation;
NMSettingsConnectionPersistMode persist_mode;
NMSettingsConnectionIntFlags sett_flags;
NMSettingsConnectionIntFlags sett_mask;
- connection = find_settings_connection(self, dev_checkpoint, &need_update, &need_activation);
+ connection = find_settings_connection(self,
+ dev_checkpoint,
+ &need_update,
+ &need_update_shadowed,
+ &need_activation,
+ &persist_mode);
/* FIXME: we need to ensure to re-create/update the profile for the
* same settings plugin. E.g. if it was a keyfile in /run or /etc,
@@ -229,9 +315,26 @@ restore_and_activate_connection(NMCheckpoint *self, DeviceCheckpoint *dev_checkp
sett_mask = NM_SETTINGS_CONNECTION_INT_FLAGS_NONE;
if (connection) {
+ if (need_update_shadowed) {
+ _LOGD("rollback: updating shadowed file for connection %s",
+ nm_connection_get_uuid(dev_checkpoint->settings_connection));
+ nm_settings_connection_update(
+ connection,
+ NULL,
+ dev_checkpoint->settings_connection_shadowed,
+ NM_SETTINGS_CONNECTION_PERSIST_MODE_TO_DISK,
+ sett_flags,
+ sett_mask,
+ NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_SYSTEM_SECRETS
+ | NM_SETTINGS_CONNECTION_UPDATE_REASON_UPDATE_NON_SECRET,
+ "checkpoint-rollback",
+ NULL);
+ }
+
if (need_update) {
- _LOGD("rollback: updating connection %s", nm_settings_connection_get_uuid(connection));
- persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP;
+ _LOGD("rollback: updating connection %s with persist mode \"%s\"",
+ nm_connection_get_uuid(dev_checkpoint->settings_connection),
+ nm_settings_connection_persist_mode_to_string(persist_mode));
nm_settings_connection_update(
connection,
NULL,
@@ -246,21 +349,54 @@ restore_and_activate_connection(NMCheckpoint *self, DeviceCheckpoint *dev_checkp
}
} else {
/* The connection was deleted, recreate it */
- _LOGD("rollback: adding connection %s again",
- nm_connection_get_uuid(dev_checkpoint->settings_connection));
-
- persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_TO_DISK;
- if (!nm_settings_add_connection(NM_SETTINGS_GET,
- NULL,
- dev_checkpoint->settings_connection,
- persist_mode,
- NM_SETTINGS_CONNECTION_ADD_REASON_NONE,
- sett_flags,
- &connection,
- &local_error)) {
- _LOGD("rollback: connection add failure: %s", local_error->message);
- g_clear_error(&local_error);
- return FALSE;
+ if (need_update_shadowed) {
+ _LOGD("rollback: adding back shadowed file for connection %s",
+ nm_connection_get_uuid(dev_checkpoint->settings_connection));
+
+ if (!nm_settings_add_connection(NM_SETTINGS_GET,
+ NULL,
+ dev_checkpoint->settings_connection_shadowed,
+ NM_SETTINGS_CONNECTION_PERSIST_MODE_TO_DISK,
+ NM_SETTINGS_CONNECTION_ADD_REASON_NONE,
+ sett_flags,
+ &connection,
+ &local_error)) {
+ _LOGD("rollback: connection add failure: %s", local_error->message);
+ g_clear_error(&local_error);
+ return FALSE;
+ }
+
+ _LOGD("rollback: updating connection %s with persist mode \"%s\"",
+ nm_connection_get_uuid(dev_checkpoint->settings_connection),
+ nm_settings_connection_persist_mode_to_string(persist_mode));
+
+ nm_settings_connection_update(
+ connection,
+ NULL,
+ dev_checkpoint->settings_connection,
+ persist_mode,
+ sett_flags,
+ sett_mask,
+ NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_SYSTEM_SECRETS
+ | NM_SETTINGS_CONNECTION_UPDATE_REASON_UPDATE_NON_SECRET,
+ "checkpoint-rollback",
+ NULL);
+ } else {
+ _LOGD("rollback: adding back connection %s with persist mode \"%s\"",
+ nm_connection_get_uuid(dev_checkpoint->settings_connection),
+ nm_settings_connection_persist_mode_to_string(persist_mode));
+ if (!nm_settings_add_connection(NM_SETTINGS_GET,
+ NULL,
+ dev_checkpoint->settings_connection,
+ persist_mode,
+ NM_SETTINGS_CONNECTION_ADD_REASON_NONE,
+ sett_flags,
+ &connection,
+ &local_error)) {
+ _LOGD("rollback: connection add failure: %s", local_error->message);
+ g_clear_error(&local_error);
+ return FALSE;
+ }
}
need_activation = TRUE;
}
@@ -362,11 +498,15 @@ nm_checkpoint_rollback(NMCheckpoint *self)
while (g_hash_table_iter_next(&iter, (gpointer *) &device, (gpointer *) &dev_checkpoint)) {
guint32 result = NM_ROLLBACK_RESULT_OK;
- _LOGD("rollback: restoring device %s (state %d, realized %d, explicitly unmanaged %d)",
+ _LOGD("rollback: restoring device %s (state %d, realized %d, explicitly unmanaged %d, "
+ "connection-unsaved %d, connection-shadowed %d, connection-shadowed-owned %d)",
dev_checkpoint->original_dev_name,
(int) dev_checkpoint->state,
dev_checkpoint->realized,
- dev_checkpoint->unmanaged_explicit);
+ dev_checkpoint->unmanaged_explicit,
+ dev_checkpoint->settings_connection_is_unsaved,
+ !!dev_checkpoint->settings_connection_shadowed,
+ dev_checkpoint->settings_connection_is_shadowed_owned);
if (nm_device_is_real(device)) {
if (!dev_checkpoint->realized) {
@@ -518,6 +658,7 @@ device_checkpoint_destroy(gpointer data)
g_clear_object(&dev_checkpoint->applied_connection);
g_clear_object(&dev_checkpoint->settings_connection);
g_clear_object(&dev_checkpoint->device);
+ g_clear_object(&dev_checkpoint->settings_connection_shadowed);
g_free(dev_checkpoint->original_dev_path);
g_free(dev_checkpoint->original_dev_name);
@@ -555,7 +696,7 @@ _dev_exported_changed(NMDBusObject *obj, NMCheckpoint *checkpoint)
}
static DeviceCheckpoint *
-device_checkpoint_create(NMCheckpoint *checkpoint, NMDevice *device)
+device_checkpoint_create(NMCheckpoint *self, NMDevice *device)
{
DeviceCheckpoint *dev_checkpoint;
NMConnection *applied_connection;
@@ -579,7 +720,7 @@ device_checkpoint_create(NMCheckpoint *checkpoint, NMDevice *device)
dev_checkpoint->dev_exported_change_id = g_signal_connect(device,
NM_DBUS_OBJECT_EXPORTED_CHANGED,
G_CALLBACK(_dev_exported_changed),
- checkpoint);
+ self);
if (nm_device_get_unmanaged_mask(device, NM_UNMANAGED_USER_EXPLICIT)) {
dev_checkpoint->unmanaged_explicit =
@@ -589,6 +730,11 @@ device_checkpoint_create(NMCheckpoint *checkpoint, NMDevice *device)
act_request = nm_device_get_act_request(device);
if (act_request) {
+ NMSettingsStorage *storage;
+ gboolean shadowed_owned = FALSE;
+ const char *shadowed_file;
+ gs_free_error GError *error = NULL;
+
settings_connection = nm_act_request_get_settings_connection(act_request);
applied_connection = nm_act_request_get_applied_connection(act_request);
@@ -602,6 +748,24 @@ device_checkpoint_create(NMCheckpoint *checkpoint, NMDevice *device)
dev_checkpoint->activation_lifetime_bound_to_profile_visibility =
NM_FLAGS_HAS(nm_active_connection_get_state_flags(NM_ACTIVE_CONNECTION(act_request)),
NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY);
+
+ dev_checkpoint->settings_connection_is_unsaved =
+ NM_FLAGS_HAS(nm_settings_connection_get_flags(settings_connection),
+ NM_SETTINGS_CONNECTION_INT_FLAGS_UNSAVED);
+
+ storage = nm_settings_connection_get_storage(settings_connection);
+ shadowed_file =
+ storage ? nm_settings_storage_get_shadowed_storage(storage, &shadowed_owned) : NULL;
+ if (shadowed_file) {
+ dev_checkpoint->settings_connection_is_shadowed_owned = shadowed_owned;
+ dev_checkpoint->settings_connection_shadowed =
+ parse_connection_from_shadowed_file(shadowed_file, &error);
+ if (!dev_checkpoint->settings_connection_shadowed) {
+ _LOGW("error reading shadowed connection file for %s: %s",
+ nm_device_get_iface(device),
+ error->message);
+ }
+ }
}
return dev_checkpoint;
--
2.41.0

View File

@ -7,7 +7,7 @@
%global epoch_version 1
%global real_version 1.46.0
%global rpm_version %{real_version}
%global release_version 4
%global release_version 8
%global snapshot %{nil}
%global git_sha %{nil}
%global bcond_default_debug 0
@ -218,6 +218,9 @@ Patch1002: 1002-allow-rollback-on-internal-global-dns-rhel-29725.patch
Patch1003: 1003-do-not-allow-ovs-bridge-and-port-to-be-parent-rhel-28545.patch
Patch1004: 1004-nm-dispatcher-fix-crash-rhel28973.patch
Patch1005: 1005-fix-race-condition-while-enumerating-devices-rhel25808.patch
Patch1006: 1006-fix-lldp-for-ovs-bridge-ports-rhel31766.patch
Patch1007: 1007-platform-avoid-routes-resync-rhel36162.patch
Patch1008: 1008-checkpoint-preserve-in-memory-state-rhel32493.patch
Requires(post): systemd
%if 0%{?fedora} || 0%{?rhel} >= 8
@ -1272,6 +1275,18 @@ fi
%changelog
* Thu May 23 2024 Beniamino Galvani <bgalvani@redhat.com> - 1:1.46.0-8
- Preserve in-memory state of connections after checkpoint/rollback (RHEL-32493)
* Tue May 14 2024 Íñigo Huguet <ihuguet@redhat.com> - 1:1.46.0-7
- Fix CPU usage of 100% when updating routes cache (RHEL-36162)
* Mon Apr 08 2024 Fernando Fernandez Mancera <ferferna@redhat.com> - 1:1.46.0-6
- Rebuild because build must go on 0day not 9.4.0
* Fri Apr 05 2024 Fernando Fernandez Mancera <ferferna@redhat.com> - 1:1.46.0-5
- Fix LLDP for OVS Bridge ports (RHEL-31766)
* Tue Mar 26 2024 Beniamino Galvani <bgalvani@redhat.com> - 1:1.46.0-4
- Fix nm-dispatcher crash (RHEL-28973)
- Fix race condition while enumerating devices (RHEL-25808)