From aac913b604526445e74d2cea515e8f4663e5994e Mon Sep 17 00:00:00 2001 From: MSVSphere Packaging Team Date: Fri, 17 Jan 2025 03:20:11 +0300 Subject: [PATCH] import NetworkManager-1.48.10-5.el9_5 --- ...es-added-by-nm-on-reapply-rhel-73013.patch | 541 ++++++++++++++++++ ...fined-in-ipvx-route-table-rhel-73166.patch | 60 ++ ...-rules-in-vpn-conenctions-rhel-73167.patch | 238 ++++++++ SPECS/NetworkManager.spec | 12 +- 4 files changed, 850 insertions(+), 1 deletion(-) create mode 100644 SOURCES/1006-remove-routes-added-by-nm-on-reapply-rhel-73013.patch create mode 100644 SOURCES/1007-vpn-place-gateway-route-to-table-defined-in-ipvx-route-table-rhel-73166.patch create mode 100644 SOURCES/1008-vpn-support-routing-rules-in-vpn-conenctions-rhel-73167.patch diff --git a/SOURCES/1006-remove-routes-added-by-nm-on-reapply-rhel-73013.patch b/SOURCES/1006-remove-routes-added-by-nm-on-reapply-rhel-73013.patch new file mode 100644 index 0000000..c828fa1 --- /dev/null +++ b/SOURCES/1006-remove-routes-added-by-nm-on-reapply-rhel-73013.patch @@ -0,0 +1,541 @@ +From 9628d71b541635047807e3344b871f701bddf77e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=8D=C3=B1igo=20Huguet?= +Date: Wed, 4 Dec 2024 14:24:38 +0100 +Subject: [PATCH 1/4] libnmc: fix bug checking VersionInfo's capabilities + +Remove the `+ 31u` that was making that it would search for bit 1 at +array's element 1, instead of element 0. Fixed comparison >len that +shoudl be >=len. Fix a few typos. + +Fixes: bc6098d44106 ('libnm: add internal nmc_client_has_{version_info_v,version_info_capability,capability}() helper') +(cherry picked from commit 5a65170b49d38f5195da900f63710c847ce3364e) +--- + src/libnm-client-aux-extern/nm-libnm-aux.c | 11 ++++------- + src/libnm-client-impl/nm-client.c | 4 ++-- + 2 files changed, 6 insertions(+), 9 deletions(-) + +diff --git a/src/libnm-client-aux-extern/nm-libnm-aux.c b/src/libnm-client-aux-extern/nm-libnm-aux.c +index 5855bc299b..77f4a19559 100644 +--- a/src/libnm-client-aux-extern/nm-libnm-aux.c ++++ b/src/libnm-client-aux-extern/nm-libnm-aux.c +@@ -169,14 +169,11 @@ nmc_client_has_version_info_capability(NMClient *nmc, NMVersionInfoCapability ca + len--; + ver++; + +- idx = (gsize) capability; +- if (idx >= G_MAXSIZE - 31u) +- return FALSE; +- +- idx_hi = ((idx + 31u) / 32u); +- idx_lo = (idx % 32u); ++ idx = (gsize) capability; ++ idx_hi = idx / 32u; ++ idx_lo = idx % 32u; + +- if (idx_hi > len) ++ if (idx_hi >= len) + return FALSE; + + return NM_FLAGS_ANY(ver[idx_hi], (1ull << idx_lo)); +diff --git a/src/libnm-client-impl/nm-client.c b/src/libnm-client-impl/nm-client.c +index 4ecc83899c..677f9aacab 100644 +--- a/src/libnm-client-impl/nm-client.c ++++ b/src/libnm-client-impl/nm-client.c +@@ -6315,7 +6315,7 @@ nm_client_get_capabilities(NMClient *client, gsize *length) + * + * If available, the first element in the array is NM_VERSION which + * encodes the daemon version as "(major << 16 | minor << 8 | micro)". +- * The following elements are a bitfield of %NMVersionInfoCapabilities ++ * The following elements are a bitfield of %NMVersionInfoCapability + * that indicate that the daemon supports a certain capability. + * + * Returns: (transfer none) (array length=length): the +@@ -8312,7 +8312,7 @@ nm_client_class_init(NMClientClass *client_class) + * Expose version info and capabilities of NetworkManager. If non-empty, + * the first element is NM_VERSION, which encodes the version of the + * daemon as "(major << 16 | minor << 8 | micro)". The following elements +- * is a bitfields of %NMVersionInfoCapabilities. If a bit is set, then ++ * is a bitfields of %NMVersionInfoCapability. If a bit is set, then + * the running NetworkManager has the respective capability. + * + * Since: 1.42 +-- +2.47.1 + + +From 2498b7aa0b0e654d97c6ded907c20341b866af21 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=8D=C3=B1igo=20Huguet?= +Date: Wed, 27 Nov 2024 08:48:50 +0100 +Subject: [PATCH 2/4] platform: rename NM_IP_ROUTE_TABLE_SYNC_MODE_FULL -> + ALL_EXCEPT_LOCAL + +The difference between FULL and ALL was not obvious without reading the +documentation. Moreover, a new mode is going to be introduced so the +confusion could grow. Rename to a more explicit name. + +(cherry picked from commit e1840ad5fbe4684cb8fce4a638617729969255e5) +--- + src/libnm-platform/nm-platform.c | 4 ++-- + src/libnm-platform/nmp-base.h | 6 +++--- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c +index af04f29fad..ac2ecb421c 100644 +--- a/src/libnm-platform/nm-platform.c ++++ b/src/libnm-platform/nm-platform.c +@@ -4890,7 +4890,7 @@ nm_platform_ip_route_get_prune_list(NMPlatform *self, + nm_assert(NM_IN_SET(addr_family, AF_INET, AF_INET6)); + nm_assert(NM_IN_SET(route_table_sync, + NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN, +- NM_IP_ROUTE_TABLE_SYNC_MODE_FULL, ++ NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_EXCEPT_LOCAL, + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL, + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE)); + +@@ -4915,7 +4915,7 @@ nm_platform_ip_route_get_prune_list(NMPlatform *self, + if (!nm_platform_route_table_is_main(nm_platform_ip_route_get_effective_table(&rt->rx))) + continue; + break; +- case NM_IP_ROUTE_TABLE_SYNC_MODE_FULL: ++ case NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_EXCEPT_LOCAL: + if (nm_platform_ip_route_get_effective_table(&rt->rx) == RT_TABLE_LOCAL) + continue; + break; +diff --git a/src/libnm-platform/nmp-base.h b/src/libnm-platform/nmp-base.h +index c7d487e23c..9e2e1063a1 100644 +--- a/src/libnm-platform/nmp-base.h ++++ b/src/libnm-platform/nmp-base.h +@@ -211,8 +211,8 @@ nmp_object_type_to_flags(NMPObjectType obj_type) + * @NM_IP_ROUTE_TABLE_SYNC_MODE_NONE: indicate an invalid setting. + * @NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN: only the main table is synced. For all + * other tables, NM won't delete any extra routes. +- * @NM_IP_ROUTE_TABLE_SYNC_MODE_FULL: NM will sync all tables, except the +- * local table (255). ++ * @NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_EXCEPT_LOCAL: NM will sync all tables, except ++ * the local table (255). + * @NM_IP_ROUTE_TABLE_SYNC_MODE_ALL: NM will sync all tables, including the + * local table (255). + * @NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE: NM will sync all tables (including +@@ -222,7 +222,7 @@ nmp_object_type_to_flags(NMPObjectType obj_type) + typedef enum { + NM_IP_ROUTE_TABLE_SYNC_MODE_NONE, + NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN, +- NM_IP_ROUTE_TABLE_SYNC_MODE_FULL, ++ NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_EXCEPT_LOCAL, + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL, + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE, + } NMIPRouteTableSyncMode; +-- +2.47.1 + + +From f970d505e9f5cfdc6b699105e404cd06c51439ca Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=8D=C3=B1igo=20Huguet?= +Date: Wed, 27 Nov 2024 13:53:02 +0100 +Subject: [PATCH 3/4] l3cfg: remove routes added by NM on reapply + +By default, on reapply we were only syncing the main routes table. This +causes that routes added by NM to other tables are not removed on +reapply. This was done to preserve routes added externally, but routes +added by NM itself should be removed. + +Add a new route table syncing mode "main + NM routes". This mode +maintains the normal behaviour of syncing completely the main table, +and for other tables removes only routes that were added by us, leaving +the rest untouched. Use this mode by default, as this is what a user +would expect on reapply. + +Note: this might not work if NM is restarted between the profile being +modified and the reapply, because NM forgets what routes were added by +itself because of the restart. This is a rare corner case, though. + +Use the D-Bus property "VersionInfo" to expose a capability flag +indicating that this bug is fixed. It is the first capability that we +expose in this way. However, it is convenient to do it this way as it's +something that clients like nmstate needs to know, so they can decide +whether a conn down is needed or not. It is not enough to decide that by +version number because it might be fixed via a downstream patch in distros +like RHEL. + +https://issues.redhat.com/browse/RHEL-67324 +https://issues.redhat.com/browse/RHEL-66262 + +Fixes: e9c17fcc9b33 ('l3cfg: default to 'main' route table sync mode') +(cherry picked from commit e330eb9c4a721d158641701cb48cd8094246d258) +--- + src/core/nm-l3cfg.c | 22 ++++++- + src/core/nm-manager.c | 29 +++++---- + src/libnm-core-public/nm-dbus-interface.h | 13 ++-- + src/libnm-platform/nm-platform.c | 78 ++++++++++++++++++++++- + src/libnm-platform/nm-platform.h | 5 +- + src/libnm-platform/nmp-base.h | 4 ++ + 6 files changed, 127 insertions(+), 24 deletions(-) + +diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c +index 57baeac25d..9dd8275b1f 100644 +--- a/src/core/nm-l3cfg.c ++++ b/src/core/nm-l3cfg.c +@@ -4997,7 +4997,7 @@ _l3_commit_one(NML3Cfg *self, + } + + if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_NONE) +- route_table_sync = NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN; ++ route_table_sync = NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN_AND_NM_ROUTES; + + if (any_dirty) + _obj_states_track_prune_dirty(self, TRUE); +@@ -5026,6 +5026,8 @@ _l3_commit_one(NML3Cfg *self, + } + + if (c_list_is_empty(&self->priv.p->blocked_lst_head_x[IS_IPv4])) { ++ gs_unref_ptrarray GPtrArray *routes_old = NULL; ++ + addresses_prune = + nm_platform_ip_address_get_prune_list(self->priv.platform, + addr_family, +@@ -5033,10 +5035,26 @@ _l3_commit_one(NML3Cfg *self, + nm_g_array_data(ipv6_temp_addrs_keep), + nm_g_array_len(ipv6_temp_addrs_keep)); + ++ if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN_AND_NM_ROUTES) { ++ NMDedupMultiIter iter; ++ const NMPObject *rt_obj; ++ ++ routes_old = g_ptr_array_new(); ++ nm_l3_config_data_iter_obj_for_each (&iter, ++ l3cd_old, ++ &rt_obj, ++ NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4)) ++ g_ptr_array_add(routes_old, (gpointer) rt_obj); ++ ++ nm_platform_route_objs_sort(routes_old, NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY); ++ } ++ + routes_prune = nm_platform_ip_route_get_prune_list(self->priv.platform, + addr_family, + self->priv.ifindex, +- route_table_sync); ++ route_table_sync, ++ routes_old); ++ + _obj_state_zombie_lst_prune_all(self, addr_family); + } + } else { +diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c +index 0a7e7b2e4a..a673279712 100644 +--- a/src/core/nm-manager.c ++++ b/src/core/nm-manager.c +@@ -462,21 +462,24 @@ static GVariant * + _version_info_get(void) + { + const guint32 arr[] = { ++ /* The array contains as first element NM_VERSION, which can be ++ * used to numerically compare the version (see also NM_ENCODE_VERSION, ++ * nm_utils_version(), nm_encode_version() and nm_decode_version(). */ + NM_VERSION, +- }; + +- /* The array contains as first element NM_VERSION, which can be +- * used to numerically compare the version (see also NM_ENCODE_VERSION, +- * nm_utils_version(), nm_encode_version() and nm_decode_version(). +- * +- * The following elements of the array are a bitfield of capabilities. +- * These capabilities should only depend on compile-time abilities +- * (unlike NM_MANAGER_CAPABILITIES, NMCapability). The supported values +- * are from NMVersionInfoCapability enum. This way to expose capabilities +- * is more cumbersome but more efficient compared to NM_MANAGER_CAPABILITIES. +- * As such, it is cheap to add capabilities for something, where you would +- * avoid it as NM_MANAGER_CAPABILITIES due to the overhead. +- */ ++ /* The following elements of the array are a bitfield of capabilities. ++ * These capabilities should only depend on compile-time abilities ++ * (unlike NM_MANAGER_CAPABILITIES, NMCapability). The supported values ++ * are from NMVersionInfoCapability enum. This way to expose capabilities ++ * is more cumbersome but more efficient compared to NM_MANAGER_CAPABILITIES. ++ * As such, it is cheap to add capabilities for something, where you would ++ * avoid it as NM_MANAGER_CAPABILITIES due to the overhead. ++ * ++ * Each of the array's elements has 32 bits. This means that capabilities ++ * with index 0-31 goes to element #1, with index 32-63 to element #2, ++ * with index 64-95 to element #3 and so on. */ ++ 1 << NM_VERSION_INFO_CAPABILITY_SYNC_ROUTE_WITH_TABLE, ++ }; + + return nm_g_variant_new_au(arr, G_N_ELEMENTS(arr)); + } +diff --git a/src/libnm-core-public/nm-dbus-interface.h b/src/libnm-core-public/nm-dbus-interface.h +index 5eedd7da3a..9c737dbea5 100644 +--- a/src/libnm-core-public/nm-dbus-interface.h ++++ b/src/libnm-core-public/nm-dbus-interface.h +@@ -93,16 +93,19 @@ + + /** + * NMVersionInfoCapability: +- * %_NM_VERSION_INFO_CAPABILITY_UNUSED: a dummy capability. It has no meaning, +- * don't use it. ++ * @NM_VERSION_INFO_CAPABILITY_SYNC_ROUTE_WITH_TABLE: Contains the fix to a bug that ++ * caused that routes in table other than main were not removed on reapply nor ++ * on connection down. ++ * https://issues.redhat.com/browse/RHEL-66262 ++ * https://issues.redhat.com/browse/RHEL-67324 + * +- * Currently no enum values are defined. These capabilities are exposed +- * on D-Bus in the "VersionInfo" bit field. ++ * The numeric values represent the bit index of the capability. These capabilities ++ * can be queried in the "VersionInfo" D-Bus property. + * + * Since: 1.42 + */ + typedef enum { +- _NM_VERSION_INFO_CAPABILITY_UNUSED = 0x7FFFFFFFu, ++ NM_VERSION_INFO_CAPABILITY_SYNC_ROUTE_WITH_TABLE = 0, + } NMVersionInfoCapability; + + /** +diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c +index ac2ecb421c..6523fb8a98 100644 +--- a/src/libnm-platform/nm-platform.c ++++ b/src/libnm-platform/nm-platform.c +@@ -61,6 +61,8 @@ G_STATIC_ASSERT(sizeof(((NMPlatformLink *) NULL)->l_address.data) == _NM_UTILS_H + G_STATIC_ASSERT(sizeof(((NMPlatformLink *) NULL)->l_perm_address.data) == _NM_UTILS_HWADDR_LEN_MAX); + G_STATIC_ASSERT(sizeof(((NMPlatformLink *) NULL)->l_broadcast.data) == _NM_UTILS_HWADDR_LEN_MAX); + ++static int _route_objs_cmp_values(gconstpointer a, gconstpointer b, gpointer user_data); ++ + static const char * + _nmp_link_port_data_to_string(NMPortKind port_kind, + const NMPlatformLinkPortData *port_data, +@@ -4872,11 +4874,24 @@ nm_platform_ip_address_get_prune_list(NMPlatform *self, + return result; + } + ++static gboolean ++_route_obj_find_bsearch(GPtrArray *sorted_routes_objs, const NMPObject *route_obj) ++{ ++ gssize pos = ++ nm_ptrarray_find_bsearch((gconstpointer *) sorted_routes_objs->pdata, ++ sorted_routes_objs->len, ++ route_obj, ++ _route_objs_cmp_values, ++ GINT_TO_POINTER((int) NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)); ++ return pos >= 0; ++} ++ + GPtrArray * + nm_platform_ip_route_get_prune_list(NMPlatform *self, + int addr_family, + int ifindex, +- NMIPRouteTableSyncMode route_table_sync) ++ NMIPRouteTableSyncMode route_table_sync, ++ GPtrArray *sorted_old_routes_objs) + { + NMPLookup lookup; + GPtrArray *routes_prune = NULL; +@@ -4891,9 +4906,20 @@ nm_platform_ip_route_get_prune_list(NMPlatform *self, + nm_assert(NM_IN_SET(route_table_sync, + NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN, + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_EXCEPT_LOCAL, ++ NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN_AND_NM_ROUTES, + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL, + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE)); + ++ if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN_AND_NM_ROUTES) { ++ nm_assert(sorted_old_routes_objs); ++ nm_assert(nm_utils_ptrarray_is_sorted( ++ (gconstpointer *) sorted_old_routes_objs->pdata, ++ sorted_old_routes_objs->len, ++ FALSE, ++ _route_objs_cmp_values, ++ GINT_TO_POINTER((int) NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY))); ++ } ++ + nmp_lookup_init_object_by_ifindex(&lookup, + NMP_OBJECT_TYPE_IP_ROUTE(NM_IS_IPv4(addr_family)), + ifindex); +@@ -4915,6 +4941,11 @@ nm_platform_ip_route_get_prune_list(NMPlatform *self, + if (!nm_platform_route_table_is_main(nm_platform_ip_route_get_effective_table(&rt->rx))) + continue; + break; ++ case NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN_AND_NM_ROUTES: ++ if (!nm_platform_route_table_is_main(nm_platform_ip_route_get_effective_table(&rt->rx)) ++ && !_route_obj_find_bsearch(sorted_old_routes_objs, obj)) ++ continue; ++ break; + case NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_EXCEPT_LOCAL: + if (nm_platform_ip_route_get_effective_table(&rt->rx) == RT_TABLE_LOCAL) + continue; +@@ -5284,7 +5315,8 @@ nm_platform_ip_route_flush(NMPlatform *self, int addr_family, int ifindex) + routes_prune = nm_platform_ip_route_get_prune_list(self, + AF_INET, + ifindex, +- NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE); ++ NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE, ++ NULL); + success &= nm_platform_ip_route_sync(self, AF_INET, ifindex, NULL, routes_prune, NULL); + } + if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET6)) { +@@ -5293,7 +5325,8 @@ nm_platform_ip_route_flush(NMPlatform *self, int addr_family, int ifindex) + routes_prune = nm_platform_ip_route_get_prune_list(self, + AF_INET6, + ifindex, +- NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE); ++ NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE, ++ NULL); + success &= nm_platform_ip_route_sync(self, AF_INET6, ifindex, NULL, routes_prune, NULL); + } + return success; +@@ -8767,6 +8800,45 @@ nm_platform_lnk_wireguard_cmp(const NMPlatformLnkWireGuard *a, const NMPlatformL + return 0; + } + ++static int ++_route_objs_cmp_values(gconstpointer a, gconstpointer b, gpointer user_data) ++{ ++ const NMPObject *a_obj = a; ++ const NMPObject *b_obj = b; ++ NMPlatformIPRouteCmpType cmp_type = GPOINTER_TO_INT(user_data); ++ ++ nm_assert(a_obj && b_obj); ++ nm_assert(NMP_OBJECT_CAST_IP_ROUTE(a_obj) && NMP_OBJECT_CAST_IP_ROUTE(b_obj)); ++ ++ if (NMP_OBJECT_GET_ADDR_FAMILY(a_obj) != NMP_OBJECT_GET_ADDR_FAMILY(b_obj)) { ++ return NMP_OBJECT_GET_ADDR_FAMILY(a_obj) == AF_INET ? 1 : -1; ++ } else if (NMP_OBJECT_GET_ADDR_FAMILY(a_obj) == AF_INET) { ++ return nm_platform_ip4_route_cmp(NMP_OBJECT_CAST_IP4_ROUTE(a_obj), ++ NMP_OBJECT_CAST_IP4_ROUTE(b_obj), ++ cmp_type); ++ } else { ++ return nm_platform_ip6_route_cmp(NMP_OBJECT_CAST_IP6_ROUTE(a_obj), ++ NMP_OBJECT_CAST_IP6_ROUTE(b_obj), ++ cmp_type); ++ } ++} ++ ++static int ++_route_objs_cmp(gconstpointer a, gconstpointer b, gpointer user_data) ++{ ++ nm_assert(a && b); ++ ++ return _route_objs_cmp_values(*((const NMPObject **) a), *((const NMPObject **) b), user_data); ++} ++ ++void ++nm_platform_route_objs_sort(GPtrArray *routes_objs, NMPlatformIPRouteCmpType cmp_type) ++{ ++ nm_assert(routes_objs); ++ ++ g_ptr_array_sort_with_data(routes_objs, _route_objs_cmp, GINT_TO_POINTER((int) cmp_type)); ++} ++ + void + nm_platform_ip4_rt_nexthop_hash_update(const NMPlatformIP4RtNextHop *obj, + gboolean for_id, +diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h +index e33be81356..22bf0fdbec 100644 +--- a/src/libnm-platform/nm-platform.h ++++ b/src/libnm-platform/nm-platform.h +@@ -2389,7 +2389,8 @@ int nm_platform_ip6_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatf + GPtrArray *nm_platform_ip_route_get_prune_list(NMPlatform *self, + int addr_family, + int ifindex, +- NMIPRouteTableSyncMode route_table_sync); ++ NMIPRouteTableSyncMode route_table_sync, ++ GPtrArray *old_routes_objs); + + gboolean nm_platform_ip_route_sync(NMPlatform *self, + int addr_family, +@@ -2495,6 +2496,8 @@ int nm_platform_lnk_wireguard_cmp(const NMPlatformLnkWireGuard *a, const NMPlatf + + GHashTable *nm_platform_ip4_address_addr_to_hash(NMPlatform *self, int ifindex); + ++void nm_platform_route_objs_sort(GPtrArray *routes_objs, NMPlatformIPRouteCmpType cmp_type); ++ + int nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a, + const NMPlatformIP4Route *b, + NMPlatformIPRouteCmpType cmp_type); +diff --git a/src/libnm-platform/nmp-base.h b/src/libnm-platform/nmp-base.h +index 9e2e1063a1..3784a78e9d 100644 +--- a/src/libnm-platform/nmp-base.h ++++ b/src/libnm-platform/nmp-base.h +@@ -211,6 +211,9 @@ nmp_object_type_to_flags(NMPObjectType obj_type) + * @NM_IP_ROUTE_TABLE_SYNC_MODE_NONE: indicate an invalid setting. + * @NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN: only the main table is synced. For all + * other tables, NM won't delete any extra routes. ++ * @NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN_AND_NM_ROUTES: only the main table is synced, ++ * plus individual routes in other tables added by NM, leaving routes that ++ * were not added by NM untouched. + * @NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_EXCEPT_LOCAL: NM will sync all tables, except + * the local table (255). + * @NM_IP_ROUTE_TABLE_SYNC_MODE_ALL: NM will sync all tables, including the +@@ -222,6 +225,7 @@ nmp_object_type_to_flags(NMPObjectType obj_type) + typedef enum { + NM_IP_ROUTE_TABLE_SYNC_MODE_NONE, + NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN, ++ NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN_AND_NM_ROUTES, + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_EXCEPT_LOCAL, + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL, + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE, +-- +2.47.1 + + +From 2ac691360f265d655b1e2e1caf9344ae0ec6a802 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=8D=C3=B1igo=20Huguet?= +Date: Tue, 10 Dec 2024 10:15:52 +0100 +Subject: [PATCH 4/4] l3cfg: get routes to prune from the list of routes + configured by NM + +We always sync routes in the main table, but routes in tables other +than main are only pruned if were added by NM, by default. Get the list +of routes to prune from other tables using obj_state->os_nm_configured, +as this tracks what routes were effectively added by NM. + +The list should be the same that the one obtained from l3cfg_old. It +could be different if we commited the l3cfg with an NMIPRouteTableSyncMode +of NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN, thus not deleting some routes at +commit time. However, since the previous commit, we never do it. + +What all this shows is that starting to use different NMIPRouteTableSyncModes +is probably a bad idea: it will be a source of bugs of routes not being +always synced as users expect, and the use case for them is still to be +known. + +(cherry picked from commit c06d130c38a4d4238e18c06f0152f8f1a6bafa7f) +--- + src/core/nm-l3cfg.c | 20 +++++++++++--------- + 1 file changed, 11 insertions(+), 9 deletions(-) + +diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c +index 9dd8275b1f..f29cfa1baf 100644 +--- a/src/core/nm-l3cfg.c ++++ b/src/core/nm-l3cfg.c +@@ -5036,15 +5036,17 @@ _l3_commit_one(NML3Cfg *self, + nm_g_array_len(ipv6_temp_addrs_keep)); + + if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN_AND_NM_ROUTES) { +- NMDedupMultiIter iter; +- const NMPObject *rt_obj; +- +- routes_old = g_ptr_array_new(); +- nm_l3_config_data_iter_obj_for_each (&iter, +- l3cd_old, +- &rt_obj, +- NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4)) +- g_ptr_array_add(routes_old, (gpointer) rt_obj); ++ GHashTableIter h_iter; ++ ObjStateData *obj_state; ++ ++ /* Get list of all the routes that were configured by us */ ++ routes_old = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref); ++ g_hash_table_iter_init(&h_iter, self->priv.p->obj_state_hash); ++ while (g_hash_table_iter_next(&h_iter, (gpointer *) &obj_state, NULL)) { ++ if (NMP_OBJECT_GET_TYPE(obj_state->obj) == NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4) ++ && obj_state->os_nm_configured) ++ g_ptr_array_add(routes_old, (gpointer) nmp_object_ref(obj_state->obj)); ++ } + + nm_platform_route_objs_sort(routes_old, NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY); + } +-- +2.47.1 + diff --git a/SOURCES/1007-vpn-place-gateway-route-to-table-defined-in-ipvx-route-table-rhel-73166.patch b/SOURCES/1007-vpn-place-gateway-route-to-table-defined-in-ipvx-route-table-rhel-73166.patch new file mode 100644 index 0000000..b92dc58 --- /dev/null +++ b/SOURCES/1007-vpn-place-gateway-route-to-table-defined-in-ipvx-route-table-rhel-73166.patch @@ -0,0 +1,60 @@ +From d9addb0ded2da8b86fa4b6e1cdc4b96f83729afd Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Wed, 11 Dec 2024 22:22:59 +0800 +Subject: [PATCH 1/1] vpn: Place gateway route to table defined in + ipvx.route-table + +Previously, NM create direct route to gateway to main(254) route table +regardless `ipvx.route-table` value. + +Fixed by setting `NMPlatformIP4Route.table_any` to `TRUE`. + +Resolves: https://issues.redhat.com/browse/RHEL-69901 + +Signed-off-by: Gris Ge +(cherry picked from commit 6d06286f1db7421bef1c4dab5fada918c59daf87) +(cherry picked from commit 29f23d3519dbb4dcffc9682fbdfb721cfc0b851c) +(cherry picked from commit 0dc07c5ca4d32b5ea8e104cbad106da9bb5b096d) +--- + src/core/vpn/nm-vpn-connection.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/core/vpn/nm-vpn-connection.c b/src/core/vpn/nm-vpn-connection.c +index b5a7fc4c29..88c5703a69 100644 +--- a/src/core/vpn/nm-vpn-connection.c ++++ b/src/core/vpn/nm-vpn-connection.c +@@ -1242,6 +1242,7 @@ _parent_device_l3cd_add_gateway_route(NML3ConfigData *l3cd, + .gateway = parent_gw.addr4, + .rt_source = NM_IP_CONFIG_SOURCE_VPN, + .metric_any = TRUE, ++ .table_any = TRUE, + }; + } else { + route.r6 = (NMPlatformIP6Route){ +@@ -1251,6 +1252,7 @@ _parent_device_l3cd_add_gateway_route(NML3ConfigData *l3cd, + .gateway = parent_gw.addr6, + .rt_source = NM_IP_CONFIG_SOURCE_VPN, + .metric_any = TRUE, ++ .table_any = TRUE, + }; + } + nm_l3_config_data_add_route(l3cd, addr_family, NULL, &route.rx); +@@ -1267,6 +1269,7 @@ _parent_device_l3cd_add_gateway_route(NML3ConfigData *l3cd, + .plen = 32, + .rt_source = NM_IP_CONFIG_SOURCE_VPN, + .metric_any = TRUE, ++ .table_any = TRUE, + }; + } else { + route.r6 = (NMPlatformIP6Route){ +@@ -1274,6 +1277,7 @@ _parent_device_l3cd_add_gateway_route(NML3ConfigData *l3cd, + .plen = 128, + .rt_source = NM_IP_CONFIG_SOURCE_VPN, + .metric_any = TRUE, ++ .table_any = TRUE, + }; + } + nm_l3_config_data_add_route(l3cd, addr_family, NULL, &route.rx); +-- +2.45.0 + diff --git a/SOURCES/1008-vpn-support-routing-rules-in-vpn-conenctions-rhel-73167.patch b/SOURCES/1008-vpn-support-routing-rules-in-vpn-conenctions-rhel-73167.patch new file mode 100644 index 0000000..fb5aacb --- /dev/null +++ b/SOURCES/1008-vpn-support-routing-rules-in-vpn-conenctions-rhel-73167.patch @@ -0,0 +1,238 @@ +From 50331402dae72990a268704e4047d6c762572755 Mon Sep 17 00:00:00 2001 +From: Wen Liang +Date: Fri, 20 Dec 2024 10:10:25 -0500 +Subject: [PATCH 1/1] vpn: fix routing rules support in vpn conenctions + +This commit introduces the ability to manage routing rules specifically +for VPN connections. These rules allow finer control over traffic +routing by enabling the specification of policy-based routing for +traffic over the VPN. + +- Updated the connection backend to apply rules during VPN activation. +- Ensured proper cleanup of routing rules upon VPN deactivation. + +This enhancement improves VPN usability in scenarios requiring advanced +routing configurations, such as split tunneling and traffic +prioritization. + +Resolves: https://issues.redhat.com/browse/RHEL-70160 +https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2092 +https://gitlab.freedesktop.org/NetworkManager/NetworkManager-ci/-/merge_requests/1842 +(cherry picked from commit 308e34a501482d01c1cc6c87c38791ad9f34dc1f) +(cherry picked from commit a24b347e93e37b04aa0f5698efcb462c02517c09) +(cherry picked from commit b5c46f8a8d644e1c5a6dc07e06d5dab3338e9a91) +--- + src/core/devices/nm-device.c | 62 +++++++++++++++++++------------- + src/core/devices/nm-device.h | 6 ++++ + src/core/vpn/nm-vpn-connection.c | 7 +++- + 3 files changed, 50 insertions(+), 25 deletions(-) + +diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c +index f9a2e7e8fe..070ba46495 100644 +--- a/src/core/devices/nm-device.c ++++ b/src/core/devices/nm-device.c +@@ -10327,31 +10327,34 @@ lldp_setup(NMDevice *self, NMTernary enabled) + * as externally added ones. Don't restart NetworkManager if + * you care about that. + */ +-static void +-_routing_rules_sync(NMDevice *self, NMTernary set_mode) ++void ++nm_routing_rules_sync(NMConnection *applied_connection, ++ NMTernary set_mode, ++ GPtrArray *(*get_extra_rules)(NMDevice *self), ++ NMDevice *self, ++ NMNetns *netns) + { +- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); +- NMPGlobalTracker *global_tracker = nm_netns_get_global_tracker(nm_device_get_netns(self)); +- NMDeviceClass *klass = NM_DEVICE_GET_CLASS(self); ++ NMPGlobalTracker *global_tracker = nm_netns_get_global_tracker(netns); + gboolean untrack_only_dirty = FALSE; + gboolean keep_deleted_rules; + gpointer user_tag_1; + gpointer user_tag_2; + +- /* take two arbitrary user-tag pointers that belong to @self. */ +- user_tag_1 = &priv->v4_route_table; +- user_tag_2 = &priv->v6_route_table; ++ if (self) { ++ user_tag_1 = ((guint32 *) self) + 1; ++ user_tag_2 = ((guint32 *) self) + 2; ++ } else { ++ user_tag_1 = ((guint32 *) applied_connection) + 1; ++ user_tag_2 = ((guint32 *) applied_connection) + 2; ++ } + + if (set_mode == NM_TERNARY_TRUE) { +- NMConnection *applied_connection; + NMSettingIPConfig *s_ip; + guint i, num; + int is_ipv4; + + untrack_only_dirty = TRUE; + +- applied_connection = nm_device_get_applied_connection(self); +- + for (is_ipv4 = 0; applied_connection && is_ipv4 < 2; is_ipv4++) { + int addr_family = is_ipv4 ? AF_INET : AF_INET6; + +@@ -10390,10 +10393,10 @@ _routing_rules_sync(NMDevice *self, NMTernary set_mode) + } + } + +- if (klass->get_extra_rules) { ++ if (get_extra_rules) { + gs_unref_ptrarray GPtrArray *extra_rules = NULL; + +- extra_rules = klass->get_extra_rules(self); ++ extra_rules = get_extra_rules(self); + if (extra_rules) { + for (i = 0; i < extra_rules->len; i++) { + nmp_global_tracker_track_rule( +@@ -10408,7 +10411,7 @@ _routing_rules_sync(NMDevice *self, NMTernary set_mode) + } + + nmp_global_tracker_untrack_all(global_tracker, user_tag_1, !untrack_only_dirty, TRUE); +- if (klass->get_extra_rules) ++ if (get_extra_rules) + nmp_global_tracker_untrack_all(global_tracker, user_tag_2, !untrack_only_dirty, TRUE); + + keep_deleted_rules = FALSE; +@@ -10468,8 +10471,8 @@ tc_commit(NMDevice *self) + static void + activate_stage2_device_config(NMDevice *self) + { +- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); +- NMDeviceClass *klass; ++ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); ++ NMDeviceClass *klass = NM_DEVICE_GET_CLASS(self); + NMActStageReturn ret; + NMSettingWired *s_wired; + gboolean no_firmware = FALSE; +@@ -10494,7 +10497,11 @@ activate_stage2_device_config(NMDevice *self) + priv->tc_committed = TRUE; + } + +- _routing_rules_sync(self, NM_TERNARY_TRUE); ++ nm_routing_rules_sync(nm_device_get_applied_connection(self), ++ NM_TERNARY_TRUE, ++ klass->get_extra_rules, ++ self, ++ nm_device_get_netns(self)); + + if (!nm_device_sys_iface_state_is_external_or_assume(self)) { + if (!nm_device_bring_up_full(self, FALSE, TRUE, &no_firmware)) { +@@ -10506,7 +10513,6 @@ activate_stage2_device_config(NMDevice *self) + } + } + +- klass = NM_DEVICE_GET_CLASS(self); + if (klass->act_stage2_config_also_for_external_or_assume + || !nm_device_sys_iface_state_is_external_or_assume(self)) { + NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; +@@ -13881,7 +13887,11 @@ check_and_reapply_connection(NMDevice *self, + + nm_device_activate_schedule_stage3_ip_config(self, FALSE); + +- _routing_rules_sync(self, NM_TERNARY_TRUE); ++ nm_routing_rules_sync(nm_device_get_applied_connection(self), ++ NM_TERNARY_TRUE, ++ klass->get_extra_rules, ++ self, ++ nm_device_get_netns(self)); + + reactivate_proxy_config(self); + +@@ -16444,6 +16454,7 @@ static void + nm_device_cleanup(NMDevice *self, NMDeviceStateReason reason, CleanupType cleanup_type) + { + NMDevicePrivate *priv; ++ NMDeviceClass *klass = NM_DEVICE_GET_CLASS(self); + int ifindex; + + g_return_if_fail(NM_IS_DEVICE(self)); +@@ -16468,8 +16479,8 @@ nm_device_cleanup(NMDevice *self, NMDeviceStateReason reason, CleanupType cleanu + } + + /* Call device type-specific deactivation */ +- if (NM_DEVICE_GET_CLASS(self)->deactivate) +- NM_DEVICE_GET_CLASS(self)->deactivate(self); ++ if (klass->deactivate) ++ klass->deactivate(self); + + ifindex = nm_device_get_ip_ifindex(self); + +@@ -16491,8 +16502,11 @@ nm_device_cleanup(NMDevice *self, NMDeviceStateReason reason, CleanupType cleanu + + priv->tc_committed = FALSE; + +- _routing_rules_sync(self, +- cleanup_type == CLEANUP_TYPE_KEEP ? NM_TERNARY_DEFAULT : NM_TERNARY_FALSE); ++ nm_routing_rules_sync(nm_device_get_applied_connection(self), ++ cleanup_type == CLEANUP_TYPE_KEEP ? NM_TERNARY_DEFAULT : NM_TERNARY_FALSE, ++ klass->get_extra_rules, ++ self, ++ nm_device_get_netns(self)); + + if (ifindex > 0) + nm_platform_ip4_dev_route_blacklist_set(nm_device_get_platform(self), ifindex, NULL); +@@ -16521,7 +16535,7 @@ nm_device_cleanup(NMDevice *self, NMDeviceStateReason reason, CleanupType cleanu + /* for other device states (UNAVAILABLE, DISCONNECTED), allow the + * device to overwrite the reset behavior, so that Wi-Fi can set + * a randomized MAC address used during scanning. */ +- NM_DEVICE_GET_CLASS(self)->deactivate_reset_hw_addr(self); ++ klass->deactivate_reset_hw_addr(self); + } + } + +diff --git a/src/core/devices/nm-device.h b/src/core/devices/nm-device.h +index 37eda5c0c8..c3a06c12e6 100644 +--- a/src/core/devices/nm-device.h ++++ b/src/core/devices/nm-device.h +@@ -848,4 +848,10 @@ void nm_device_clear_dns_lookup_data(NMDevice *self, const char *reason); + + gboolean nm_device_get_allow_autoconnect_on_external(NMDevice *self); + ++void nm_routing_rules_sync(NMConnection *applied_connection, ++ NMTernary set_mode, ++ GPtrArray *(*get_extra_rules)(NMDevice *self), ++ NMDevice *self, ++ NMNetns *netns); ++ + #endif /* __NETWORKMANAGER_DEVICE_H__ */ +diff --git a/src/core/vpn/nm-vpn-connection.c b/src/core/vpn/nm-vpn-connection.c +index 88c5703a69..c14682b8cc 100644 +--- a/src/core/vpn/nm-vpn-connection.c ++++ b/src/core/vpn/nm-vpn-connection.c +@@ -905,7 +905,8 @@ fw_call_cleanup(NMVpnConnection *self) + static void + vpn_cleanup(NMVpnConnection *self, NMDevice *parent_dev) + { +- const char *iface; ++ NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); ++ const char *iface; + + /* Remove zone from firewall */ + iface = nm_vpn_connection_get_ip_iface(self, FALSE); +@@ -917,6 +918,8 @@ vpn_cleanup(NMVpnConnection *self, NMDevice *parent_dev) + fw_call_cleanup(self); + + _l3cfg_l3cd_clear_all(self); ++ ++ nm_routing_rules_sync(_get_applied_connection(self), NM_TERNARY_FALSE, NULL, NULL, priv->netns); + } + + static void +@@ -2278,6 +2281,8 @@ _dbus_signal_ip_config_cb(NMVpnConnection *self, int addr_family, GVariant *dict + + _l3cfg_l3cd_set(self, L3CD_TYPE_IP_X(IS_IPv4), l3cd); + ++ nm_routing_rules_sync(_get_applied_connection(self), NM_TERNARY_TRUE, NULL, NULL, priv->netns); ++ + _check_complete(self, TRUE); + } + +-- +2.45.0 + diff --git a/SPECS/NetworkManager.spec b/SPECS/NetworkManager.spec index 14ac59e..13ce63f 100644 --- a/SPECS/NetworkManager.spec +++ b/SPECS/NetworkManager.spec @@ -6,7 +6,7 @@ %global epoch_version 1 %global real_version 1.48.10 %global rpm_version %{real_version} -%global release_version 3 +%global release_version 5 %global snapshot %{nil} %global git_sha %{nil} %global bcond_default_debug 0 @@ -216,6 +216,9 @@ Patch1002: 1002-cloud-setup-ensure-azure-places-primary-address-first-rhel-56387 Patch1003: 1003-only-validate-sriov-capability-when-enabled-rhel-58397.patch Patch1004: 1004-fix-bug-when-deactivating-port-connections-rhel-50747.patch Patch1005: 1005-fix-validation-of-ovs-dpdk-interface-name-rhel-60022.patch +Patch1006: 1006-remove-routes-added-by-nm-on-reapply-rhel-73013.patch +Patch1007: 1007-vpn-place-gateway-route-to-table-defined-in-ipvx-route-table-rhel-73166.patch +Patch1008: 1008-vpn-support-routing-rules-in-vpn-conenctions-rhel-73167.patch Requires(post): systemd %if 0%{?fedora} || 0%{?rhel} >= 8 @@ -1272,6 +1275,13 @@ fi %changelog +* Thu Jan 09 2025 Wen Liang - 1:1.48.10-5 +- vpn: Support routing rules in vpn conenctions (RHEL-73167) +- vpn: Place gateway route to table defined in ipvx.route-table (RHEL-73166) + +* Wed Jan 08 2025 Íñigo Huguet - 1:1.48.10-4 +- Remove routes added by NetworkManager when doing reapply, also those not in main table (RHEL-73013) + * Tue Nov 12 2024 Beniamino Galvani - 1:1.48.10-3 - Only validate the SR-IOV device capability when SR-IOV is enabled (RHEL-58397) - Fix bug when deactivating port connections (RHEL-50747)