Blame SOURCES/1004-fix-handling-generated-local-routes-rh1907661.patch

964b59
From 549687f0202469289cef3ac322f81a04677873b6 Mon Sep 17 00:00:00 2001
964b59
From: Thomas Haller <thaller@redhat.com>
964b59
Date: Tue, 23 Mar 2021 17:48:43 +0100
964b59
Subject: [PATCH 1/6] core: avoid logging pointer value in
964b59
 nm_device_set_ip_config()
964b59
964b59
(cherry picked from commit 5da8c073efd67f12292c1c5c67ada64b9c9f5a6c)
964b59
(cherry picked from commit c0e937c8b9a1077d1e77c3fe1f480b6e5b54c55b)
964b59
---
964b59
 src/core/devices/nm-device.c | 4 ++--
964b59
 1 file changed, 2 insertions(+), 2 deletions(-)
964b59
964b59
diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c
964b59
index 040dd0b4d367..44b87490c17e 100644
964b59
--- a/src/core/devices/nm-device.c
964b59
+++ b/src/core/devices/nm-device.c
964b59
@@ -13496,10 +13496,10 @@ nm_device_set_ip_config(NMDevice *  self,
964b59
     nm_assert(IS_IPv4 || !ip4_dev_route_blacklist);
964b59
 
964b59
     _LOGD(LOGD_IPX(IS_IPv4),
964b59
-          "ip%c-config: update (commit=%d, new-config=%p)",
964b59
+          "ip%c-config: update (commit=%d, new-config=" NM_HASH_OBFUSCATE_PTR_FMT")",
964b59
           nm_utils_addr_family_to_char(addr_family),
964b59
           commit,
964b59
-          new_config);
964b59
+          NM_HASH_OBFUSCATE_PTR(new_config));
964b59
 
964b59
     /* Always commit to nm-platform to update lifetimes */
964b59
     if (commit && new_config) {
964b59
-- 
964b59
2.30.2
964b59
964b59
964b59
From a633a7855bb08afc9709a8dbed01fb5e4278d540 Mon Sep 17 00:00:00 2001
964b59
From: Thomas Haller <thaller@redhat.com>
964b59
Date: Tue, 23 Mar 2021 17:56:37 +0100
964b59
Subject: [PATCH 2/6] core: log route-table-sync-mode in
964b59
 nm_device_set_ip_config()
964b59
964b59
(cherry picked from commit f6db2c6261b560ec34b56eeeb3766c9165f5619b)
964b59
(cherry picked from commit 2fb1a22e2be6d9e83bfc9e9873f93976286a55b0)
964b59
---
964b59
 src/core/devices/nm-device.c | 28 ++++++++++++++++++----------
964b59
 1 file changed, 18 insertions(+), 10 deletions(-)
964b59
964b59
diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c
964b59
index 44b87490c17e..5eaf8c23e7da 100644
964b59
--- a/src/core/devices/nm-device.c
964b59
+++ b/src/core/devices/nm-device.c
964b59
@@ -13478,12 +13478,13 @@ nm_device_set_ip_config(NMDevice *  self,
964b59
                         gboolean    commit,
964b59
                         GPtrArray * ip4_dev_route_blacklist)
964b59
 {
964b59
-    NMDevicePrivate *     priv    = NM_DEVICE_GET_PRIVATE(self);
964b59
-    const int             IS_IPv4 = NM_IS_IPv4(addr_family);
964b59
-    NMIPConfig *          old_config;
964b59
-    gboolean              has_changes = FALSE;
964b59
-    gboolean              success     = TRUE;
964b59
-    NMSettingsConnection *settings_connection;
964b59
+    NMDevicePrivate *      priv    = NM_DEVICE_GET_PRIVATE(self);
964b59
+    const int              IS_IPv4 = NM_IS_IPv4(addr_family);
964b59
+    NMIPConfig *           old_config;
964b59
+    gboolean               has_changes = FALSE;
964b59
+    gboolean               success     = TRUE;
964b59
+    NMSettingsConnection * settings_connection;
964b59
+    NMIPRouteTableSyncMode route_table_sync_mode;
964b59
 
964b59
     nm_assert_addr_family(addr_family);
964b59
     nm_assert(!new_config || nm_ip_config_get_addr_family(new_config) == addr_family);
964b59
@@ -13495,11 +13496,18 @@ nm_device_set_ip_config(NMDevice *  self,
964b59
                   })));
964b59
     nm_assert(IS_IPv4 || !ip4_dev_route_blacklist);
964b59
 
964b59
+    if (commit && new_config)
964b59
+        route_table_sync_mode = _get_route_table_sync_mode_stateful(self, addr_family);
964b59
+    else
964b59
+        route_table_sync_mode = NM_IP_ROUTE_TABLE_SYNC_MODE_NONE;
964b59
+
964b59
     _LOGD(LOGD_IPX(IS_IPv4),
964b59
-          "ip%c-config: update (commit=%d, new-config=" NM_HASH_OBFUSCATE_PTR_FMT")",
964b59
+          "ip%c-config: update (commit=%d, new-config=" NM_HASH_OBFUSCATE_PTR_FMT
964b59
+          ", route-table-sync-mode=%d)",
964b59
           nm_utils_addr_family_to_char(addr_family),
964b59
           commit,
964b59
-          NM_HASH_OBFUSCATE_PTR(new_config));
964b59
+          NM_HASH_OBFUSCATE_PTR(new_config),
964b59
+          (int) route_table_sync_mode);
964b59
 
964b59
     /* Always commit to nm-platform to update lifetimes */
964b59
     if (commit && new_config) {
964b59
@@ -13508,7 +13516,7 @@ nm_device_set_ip_config(NMDevice *  self,
964b59
         if (IS_IPv4) {
964b59
             success = nm_ip4_config_commit(NM_IP4_CONFIG(new_config),
964b59
                                            nm_device_get_platform(self),
964b59
-                                           _get_route_table_sync_mode_stateful(self, AF_INET));
964b59
+                                           route_table_sync_mode);
964b59
             nm_platform_ip4_dev_route_blacklist_set(nm_device_get_platform(self),
964b59
                                                     nm_ip_config_get_ifindex(new_config),
964b59
                                                     ip4_dev_route_blacklist);
964b59
@@ -13517,7 +13525,7 @@ nm_device_set_ip_config(NMDevice *  self,
964b59
 
964b59
             success = nm_ip6_config_commit(NM_IP6_CONFIG(new_config),
964b59
                                            nm_device_get_platform(self),
964b59
-                                           _get_route_table_sync_mode_stateful(self, AF_INET6),
964b59
+                                           route_table_sync_mode,
964b59
                                            &temporary_not_available);
964b59
 
964b59
             if (!_rt6_temporary_not_available_set(self, temporary_not_available))
964b59
-- 
964b59
2.30.2
964b59
964b59
964b59
From a9aead98e4c2d5ce73ab6388360139489f677320 Mon Sep 17 00:00:00 2001
964b59
From: Thomas Haller <thaller@redhat.com>
964b59
Date: Mon, 22 Mar 2021 17:31:35 +0100
964b59
Subject: [PATCH 3/6] core: add NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE mode
964b59
964b59
When we deactivate a device, we flush all IP addresses and
964b59
routes. Thus, have yet another sync mode for that. It will sync more
964b59
than "ALL".
964b59
964b59
(cherry picked from commit e226b5eb829e5e8c623948e35d406e815cd05089)
964b59
(cherry picked from commit b263454f241ea944d87e13f935530d0539343bce)
964b59
---
964b59
 src/core/nm-types.h             | 12 ++++++++----
964b59
 src/core/platform/nm-platform.c | 29 +++++++++++++++++++----------
964b59
 2 files changed, 27 insertions(+), 14 deletions(-)
964b59
964b59
diff --git a/src/core/nm-types.h b/src/core/nm-types.h
964b59
index ab2314594d4a..8a32b7d20459 100644
964b59
--- a/src/core/nm-types.h
964b59
+++ b/src/core/nm-types.h
964b59
@@ -245,12 +245,16 @@ typedef enum {
964b59
  *   local table (255).
964b59
  * @NM_IP_ROUTE_TABLE_SYNC_MODE_ALL: NM will sync all tables, including the
964b59
  *   local table (255).
964b59
+ * @NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE: NM will sync all tables (including
964b59
+ *   the local table). It will thereby remove all addresses, that is during
964b59
+ *   deactivation.
964b59
  */
964b59
 typedef enum {
964b59
-    NM_IP_ROUTE_TABLE_SYNC_MODE_NONE = 0,
964b59
-    NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN = 1,
964b59
-    NM_IP_ROUTE_TABLE_SYNC_MODE_FULL = 2,
964b59
-    NM_IP_ROUTE_TABLE_SYNC_MODE_ALL  = 3,
964b59
+    NM_IP_ROUTE_TABLE_SYNC_MODE_NONE,
964b59
+    NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN,
964b59
+    NM_IP_ROUTE_TABLE_SYNC_MODE_FULL,
964b59
+    NM_IP_ROUTE_TABLE_SYNC_MODE_ALL,
964b59
+    NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE,
964b59
 } NMIPRouteTableSyncMode;
964b59
 
964b59
 /* settings */
964b59
diff --git a/src/core/platform/nm-platform.c b/src/core/platform/nm-platform.c
964b59
index 0e5f8ab54806..8cfcf8bc6654 100644
964b59
--- a/src/core/platform/nm-platform.c
964b59
+++ b/src/core/platform/nm-platform.c
964b59
@@ -4363,7 +4363,8 @@ nm_platform_ip_route_get_prune_list(NMPlatform *           self,
964b59
     nm_assert(NM_IN_SET(route_table_sync,
964b59
                         NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN,
964b59
                         NM_IP_ROUTE_TABLE_SYNC_MODE_FULL,
964b59
-                        NM_IP_ROUTE_TABLE_SYNC_MODE_ALL));
964b59
+                        NM_IP_ROUTE_TABLE_SYNC_MODE_ALL,
964b59
+                        NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE));
964b59
 
964b59
     nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP_ROUTE(NM_IS_IPv4(addr_family)), ifindex);
964b59
     head_entry = nm_platform_lookup(self, &lookup);
964b59
@@ -4375,16 +4376,24 @@ nm_platform_ip_route_get_prune_list(NMPlatform *           self,
964b59
     c_list_for_each (iter, &head_entry->lst_entries_head) {
964b59
         const NMPObject *obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj;
964b59
 
964b59
-        if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_FULL) {
964b59
-            if (nm_platform_ip_route_get_effective_table(NMP_OBJECT_CAST_IP_ROUTE(obj))
964b59
-                == RT_TABLE_LOCAL)
964b59
-                continue;
964b59
-        } else if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN) {
964b59
+        switch (route_table_sync) {
964b59
+        case NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN:
964b59
             if (!nm_platform_route_table_is_main(
964b59
                     nm_platform_ip_route_get_effective_table(NMP_OBJECT_CAST_IP_ROUTE(obj))))
964b59
                 continue;
964b59
-        } else
964b59
-            nm_assert(route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_ALL);
964b59
+            break;
964b59
+        case NM_IP_ROUTE_TABLE_SYNC_MODE_FULL:
964b59
+            if (nm_platform_ip_route_get_effective_table(NMP_OBJECT_CAST_IP_ROUTE(obj))
964b59
+                == RT_TABLE_LOCAL)
964b59
+                continue;
964b59
+            break;
964b59
+        case NM_IP_ROUTE_TABLE_SYNC_MODE_ALL:
964b59
+        case NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE:
964b59
+            break;
964b59
+        default:
964b59
+            nm_assert_not_reached();
964b59
+            break;
964b59
+        }
964b59
 
964b59
         g_ptr_array_add(routes_prune, (gpointer) nmp_object_ref(obj));
964b59
     }
964b59
@@ -4679,7 +4688,7 @@ nm_platform_ip_route_flush(NMPlatform *self, int addr_family, int ifindex)
964b59
         routes_prune = nm_platform_ip_route_get_prune_list(self,
964b59
                                                            AF_INET,
964b59
                                                            ifindex,
964b59
-                                                           NM_IP_ROUTE_TABLE_SYNC_MODE_ALL);
964b59
+                                                           NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE);
964b59
         success &= nm_platform_ip_route_sync(self, AF_INET, ifindex, NULL, routes_prune, NULL);
964b59
     }
964b59
     if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET6)) {
964b59
@@ -4688,7 +4697,7 @@ nm_platform_ip_route_flush(NMPlatform *self, int addr_family, int ifindex)
964b59
         routes_prune = nm_platform_ip_route_get_prune_list(self,
964b59
                                                            AF_INET6,
964b59
                                                            ifindex,
964b59
-                                                           NM_IP_ROUTE_TABLE_SYNC_MODE_ALL);
964b59
+                                                           NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE);
964b59
         success &= nm_platform_ip_route_sync(self, AF_INET6, ifindex, NULL, routes_prune, NULL);
964b59
     }
964b59
     return success;
964b59
-- 
964b59
2.30.2
964b59
964b59
964b59
From 7e6bf896b89c6c51f3524fa26f1214f65e748843 Mon Sep 17 00:00:00 2001
964b59
From: Thomas Haller <thaller@redhat.com>
964b59
Date: Mon, 22 Mar 2021 21:43:47 +0100
964b59
Subject: [PATCH 4/6] core: don't add ff00::/8 unicast route to
964b59
 nm_ip6_config_add_dependent_routes()
964b59
964b59
This effectively reverts commit cd89026c5f4f ('core: add dependent
964b59
multicast route configured by kernel for IPv6').
964b59
964b59
It's not clear to me why this was done or why it would be correct.
964b59
964b59
True, kernel automatically adds multicast route like
964b59
964b59
  multicast ff00::/8 dev $IFACE table local proto kernel metric 256 pref medium
964b59
964b59
But NetworkManager ignores all multicast routes for now. So the dependent
964b59
routes cannot contain multicast routes as they are not handled. Also,
964b59
the code added a unicast route, so I don't understand why the comment
964b59
is talking about multicast.
964b59
964b59
This seems just wrong. Drop it.
964b59
964b59
(cherry picked from commit c29d995000a147cecbe1dbaa9607936c1844ba10)
964b59
(cherry picked from commit 40bc834176fbe8c17a22c7ea77f3cb8aa6c407b6)
964b59
---
964b59
 src/core/nm-ip6-config.c | 17 -----------------
964b59
 1 file changed, 17 deletions(-)
964b59
964b59
diff --git a/src/core/nm-ip6-config.c b/src/core/nm-ip6-config.c
964b59
index 1f7def346510..f498fc796a44 100644
964b59
--- a/src/core/nm-ip6-config.c
964b59
+++ b/src/core/nm-ip6-config.c
964b59
@@ -396,23 +396,6 @@ nm_ip6_config_add_dependent_routes(NMIP6Config *self,
964b59
      *
964b59
      * For manually added IPv6 routes, add the device routes explicitly. */
964b59
 
964b59
-    /* Pre-generate multicast route */
964b59
-    {
964b59
-        nm_auto_nmpobj NMPObject *r = NULL;
964b59
-        NMPlatformIP6Route *      route;
964b59
-
964b59
-        r                         = nmp_object_new(NMP_OBJECT_TYPE_IP6_ROUTE, NULL);
964b59
-        route                     = NMP_OBJECT_CAST_IP6_ROUTE(r);
964b59
-        route->ifindex            = ifindex;
964b59
-        route->network.s6_addr[0] = 0xffu;
964b59
-        route->plen               = 8;
964b59
-        route->table_coerced      = nm_platform_route_table_coerce(RT_TABLE_LOCAL);
964b59
-        route->type_coerced       = nm_platform_route_type_coerce(RTN_UNICAST);
964b59
-        route->metric             = 256;
964b59
-
964b59
-        _add_route(self, r, NULL, NULL);
964b59
-    }
964b59
-
964b59
     nm_ip_config_iter_ip6_address_for_each (&iter, self, &my_addr) {
964b59
         NMPlatformIP6Route *route;
964b59
         gboolean            has_peer;
964b59
-- 
964b59
2.30.2
964b59
964b59
964b59
From 542388d6b508981656eb96e6940fdf3359ac1353 Mon Sep 17 00:00:00 2001
964b59
From: Thomas Haller <thaller@redhat.com>
964b59
Date: Tue, 23 Mar 2021 10:05:30 +0100
964b59
Subject: [PATCH 5/6] core: minor cleanup in
964b59
 nm_platform_ip_route_get_prune_list()
964b59
964b59
(cherry picked from commit fe1bf4c907c29997cbc6a28bc0781bfc419cb07f)
964b59
(cherry picked from commit 087c7f394cbffcf4bc786a8e92825059d340dfc9)
964b59
---
964b59
 src/core/platform/nm-platform.c | 10 +++++-----
964b59
 1 file changed, 5 insertions(+), 5 deletions(-)
964b59
964b59
diff --git a/src/core/platform/nm-platform.c b/src/core/platform/nm-platform.c
964b59
index 8cfcf8bc6654..45636ea85ed3 100644
964b59
--- a/src/core/platform/nm-platform.c
964b59
+++ b/src/core/platform/nm-platform.c
964b59
@@ -4374,22 +4374,22 @@ nm_platform_ip_route_get_prune_list(NMPlatform *           self,
964b59
     routes_prune = g_ptr_array_new_full(head_entry->len, (GDestroyNotify) nm_dedup_multi_obj_unref);
964b59
 
964b59
     c_list_for_each (iter, &head_entry->lst_entries_head) {
964b59
-        const NMPObject *obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj;
964b59
+        const NMPObject *         obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj;
964b59
+        const NMPlatformIPXRoute *rt  = NMP_OBJECT_CAST_IPX_ROUTE(obj);
964b59
 
964b59
         switch (route_table_sync) {
964b59
         case NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN:
964b59
-            if (!nm_platform_route_table_is_main(
964b59
-                    nm_platform_ip_route_get_effective_table(NMP_OBJECT_CAST_IP_ROUTE(obj))))
964b59
+            if (!nm_platform_route_table_is_main(nm_platform_ip_route_get_effective_table(&rt->rx)))
964b59
                 continue;
964b59
             break;
964b59
         case NM_IP_ROUTE_TABLE_SYNC_MODE_FULL:
964b59
-            if (nm_platform_ip_route_get_effective_table(NMP_OBJECT_CAST_IP_ROUTE(obj))
964b59
-                == RT_TABLE_LOCAL)
964b59
+            if (nm_platform_ip_route_get_effective_table(&rt->rx) == RT_TABLE_LOCAL)
964b59
                 continue;
964b59
             break;
964b59
         case NM_IP_ROUTE_TABLE_SYNC_MODE_ALL:
964b59
         case NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE:
964b59
             break;
964b59
+
964b59
         default:
964b59
             nm_assert_not_reached();
964b59
             break;
964b59
-- 
964b59
2.30.2
964b59
964b59
964b59
From 0a331bb0f4646e3590e30660ed5c4bf599275a8b Mon Sep 17 00:00:00 2001
964b59
From: Thomas Haller <thaller@redhat.com>
964b59
Date: Fri, 19 Mar 2021 21:20:52 +0100
964b59
Subject: [PATCH 6/6] core: don't add dependent local route for addresses
964b59
964b59
When adding an IPv4 address, kernel automatically adds a local route.
964b59
This is done by fib_add_ifaddr(). Note that if the address is
964b59
IFA_F_SECONDARY, then the "src" is the primary address. That means, with
964b59
964b59
  nmcli connection add con-name t type ethernet ifname t autoconnect no \
964b59
     ipv4.method manual ipv6.method disabled \
964b59
     ipv4.addresses '192.168.77.10/24, 192.168.77.11/24'
964b59
964b59
we get two routes:
964b59
964b59
  "local 192.168.77.10 dev t table local proto kernel scope host src 192.168.77.10"
964b59
  "local 192.168.77.11 dev t table local proto kernel scope host src 192.168.77.10"
964b59
964b59
Our code would only generate instead:
964b59
964b59
  "local 192.168.77.10 dev t table local proto kernel scope host src 192.168.77.10"
964b59
  "local 192.168.77.11 dev t table local proto kernel scope host src 192.168.77.11"
964b59
964b59
Afterwards, this artificial route will be leaked:
964b59
964b59
    #!/bin/bash
964b59
964b59
    set -vx
964b59
964b59
    nmcli connection delete t || :
964b59
    ip link delete t || :
964b59
964b59
    ip link add name t type veth peer t-veth
964b59
964b59
    nmcli connection add con-name t type ethernet ifname t autoconnect no ipv4.method manual ipv4.addresses '192.168.77.10/24, 192.168.77.11/24' ipv6.method disabled
964b59
964b59
    nmcli connection up t
964b59
964b59
    ip route show table all dev t | grep --color '^\|192.168.77.11'
964b59
964b59
    sleep 1
964b59
964b59
    nmcli device modify t -ipv4.addresses 192.168.77.11/24
964b59
964b59
    ip route show table all dev t | grep --color '^\|192.168.77.11'
964b59
964b59
    ip route show table all dev t | grep -q 192.168.77.11 && echo "the local route 192.168.77.11 is still there, because NM adds a local route with wrong pref-src"
964b59
964b59
It will also be leaked because in the example above ipv4.route-table is
964b59
unset, so we are not in full route sync mode and the local table is not
964b59
synced.
964b59
964b59
This was introduced by commit 3e5fc04df320 ('core: add dependent local
964b59
routes configured by kernel'), but it's unclear to me why we really need
964b59
this. Drop it again and effectively revert commit 3e5fc04df320 ('core:
964b59
add dependent local routes configured by kernel').
964b59
964b59
I think this "solution" is still bad. We need to improve our route sync
964b59
approach with L3Cfg rework. For now, it's probably good enough.
964b59
964b59
https://bugzilla.redhat.com/show_bug.cgi?id=1907661
964b59
(cherry picked from commit 557644f5e03a77b3ebe09ceba672217959cf3bdc)
964b59
(cherry picked from commit eb1c607c7054ff6b60209ef3afb10db74e19305e)
964b59
---
964b59
 src/core/nm-ip4-config.c        | 15 ------
964b59
 src/core/nm-ip6-config.c        | 16 ------
964b59
 src/core/platform/nm-platform.c | 91 +++++++++++++++++++++++++++++++++
964b59
 3 files changed, 91 insertions(+), 31 deletions(-)
964b59
964b59
diff --git a/src/core/nm-ip4-config.c b/src/core/nm-ip4-config.c
964b59
index c49dfb4c34b8..608b7fc8b70c 100644
964b59
--- a/src/core/nm-ip4-config.c
964b59
+++ b/src/core/nm-ip4-config.c
964b59
@@ -649,21 +649,6 @@ nm_ip4_config_add_dependent_routes(NMIP4Config *self,
964b59
         if (my_addr->external)
964b59
             continue;
964b59
 
964b59
-        /* Pre-generate local route added by kernel */
964b59
-        r                   = nmp_object_new(NMP_OBJECT_TYPE_IP4_ROUTE, NULL);
964b59
-        route               = NMP_OBJECT_CAST_IP4_ROUTE(r);
964b59
-        route->ifindex      = ifindex;
964b59
-        route->rt_source    = NM_IP_CONFIG_SOURCE_KERNEL;
964b59
-        route->network      = my_addr->address;
964b59
-        route->plen         = 32;
964b59
-        route->pref_src     = my_addr->address;
964b59
-        route->type_coerced = nm_platform_route_type_coerce(RTN_LOCAL);
964b59
-        route->scope_inv    = nm_platform_route_scope_inv(RT_SCOPE_HOST);
964b59
-        route->table_coerced =
964b59
-            nm_platform_route_table_coerce(is_vrf ? route_table : RT_TABLE_LOCAL);
964b59
-        _add_route(self, r, NULL, NULL);
964b59
-        nm_clear_pointer(&r, nmp_object_unref);
964b59
-
964b59
         if (nm_utils_ip4_address_is_zeronet(network)) {
964b59
             /* Kernel doesn't add device-routes for destinations that
964b59
              * start with 0.x.y.z. Skip them. */
964b59
diff --git a/src/core/nm-ip6-config.c b/src/core/nm-ip6-config.c
964b59
index f498fc796a44..1e36050d9bff 100644
964b59
--- a/src/core/nm-ip6-config.c
964b59
+++ b/src/core/nm-ip6-config.c
964b59
@@ -404,22 +404,6 @@ nm_ip6_config_add_dependent_routes(NMIP6Config *self,
964b59
         if (my_addr->external)
964b59
             continue;
964b59
 
964b59
-        {
964b59
-            nm_auto_nmpobj NMPObject *r = NULL;
964b59
-
964b59
-            /* Pre-generate local route added by kernel */
964b59
-            r                   = nmp_object_new(NMP_OBJECT_TYPE_IP6_ROUTE, NULL);
964b59
-            route               = NMP_OBJECT_CAST_IP6_ROUTE(r);
964b59
-            route->ifindex      = ifindex;
964b59
-            route->network      = my_addr->address;
964b59
-            route->plen         = 128;
964b59
-            route->type_coerced = nm_platform_route_type_coerce(RTN_LOCAL);
964b59
-            route->metric       = 0;
964b59
-            route->table_coerced =
964b59
-                nm_platform_route_table_coerce(is_vrf ? route_table : RT_TABLE_LOCAL);
964b59
-            _add_route(self, r, NULL, NULL);
964b59
-        }
964b59
-
964b59
         if (NM_FLAGS_HAS(my_addr->n_ifa_flags, IFA_F_NOPREFIXROUTE))
964b59
             continue;
964b59
         if (my_addr->plen == 0)
964b59
diff --git a/src/core/platform/nm-platform.c b/src/core/platform/nm-platform.c
964b59
index 45636ea85ed3..459a33071700 100644
964b59
--- a/src/core/platform/nm-platform.c
964b59
+++ b/src/core/platform/nm-platform.c
964b59
@@ -4357,6 +4357,11 @@ nm_platform_ip_route_get_prune_list(NMPlatform *           self,
964b59
     GPtrArray *                  routes_prune;
964b59
     const NMDedupMultiHeadEntry *head_entry;
964b59
     CList *                      iter;
964b59
+    NMPlatformIP4Route           rt_local4;
964b59
+    NMPlatformIP6Route           rt_local6;
964b59
+    const NMPlatformLink *       pllink;
964b59
+    const NMPlatformLnkVrf *     lnk_vrf;
964b59
+    guint32                      local_table;
964b59
 
964b59
     nm_assert(NM_IS_PLATFORM(self));
964b59
     nm_assert(NM_IN_SET(addr_family, AF_INET, AF_INET6));
964b59
@@ -4371,6 +4376,14 @@ nm_platform_ip_route_get_prune_list(NMPlatform *           self,
964b59
     if (!head_entry)
964b59
         return NULL;
964b59
 
964b59
+    lnk_vrf = nm_platform_link_get_lnk_vrf(self, ifindex, &pllink);
964b59
+    if (!lnk_vrf && pllink && pllink->master > 0)
964b59
+        lnk_vrf = nm_platform_link_get_lnk_vrf(self, pllink->master, NULL);
964b59
+    local_table = lnk_vrf ? lnk_vrf->table : RT_TABLE_LOCAL;
964b59
+
964b59
+    rt_local4.plen = 0;
964b59
+    rt_local6.plen = 0;
964b59
+
964b59
     routes_prune = g_ptr_array_new_full(head_entry->len, (GDestroyNotify) nm_dedup_multi_obj_unref);
964b59
 
964b59
     c_list_for_each (iter, &head_entry->lst_entries_head) {
964b59
@@ -4387,6 +4400,84 @@ nm_platform_ip_route_get_prune_list(NMPlatform *           self,
964b59
                 continue;
964b59
             break;
964b59
         case NM_IP_ROUTE_TABLE_SYNC_MODE_ALL:
964b59
+
964b59
+            /* FIXME: we should better handle routes that are automatically added by kernel.
964b59
+             *
964b59
+             * For now, make a good guess which are those routes and exclude them from
964b59
+             * pruning them. */
964b59
+
964b59
+            if (NM_IS_IPv4(addr_family)) {
964b59
+                /* for each IPv4 address kernel adds a route like
964b59
+                 *
964b59
+                 *  local $ADDR dev $IFACE table local proto kernel scope host src $PRIMARY_ADDR
964b59
+                 *
964b59
+                 * Check whether route could be of that kind. */
964b59
+                if (nm_platform_ip_route_get_effective_table(&rt->rx) == local_table
964b59
+                    && rt->rx.plen == 32 && rt->rx.rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL
964b59
+                    && rt->rx.metric == 0
964b59
+                    && rt->r4.scope_inv == nm_platform_route_scope_inv(RT_SCOPE_HOST)
964b59
+                    && rt->r4.gateway == INADDR_ANY) {
964b59
+                    if (rt_local4.plen == 0) {
964b59
+                        rt_local4 = (NMPlatformIP4Route){
964b59
+                            .ifindex       = ifindex,
964b59
+                            .type_coerced  = nm_platform_route_type_coerce(RTN_LOCAL),
964b59
+                            .plen          = 32,
964b59
+                            .rt_source     = NM_IP_CONFIG_SOURCE_RTPROT_KERNEL,
964b59
+                            .metric        = 0,
964b59
+                            .table_coerced = nm_platform_route_table_coerce(local_table),
964b59
+                            .scope_inv     = nm_platform_route_scope_inv(RT_SCOPE_HOST),
964b59
+                            .gateway       = INADDR_ANY,
964b59
+                        };
964b59
+                    }
964b59
+
964b59
+                    /* the possible "network" depends on the addresses we have. We don't check that
964b59
+                     * carefully. If the other parameters match, we assume that this route is the one
964b59
+                     * generated by kernel. */
964b59
+                    rt_local4.network  = rt->r4.network;
964b59
+                    rt_local4.pref_src = rt->r4.pref_src;
964b59
+
964b59
+                    /* to be more confident about comparing the value, use our nm_platform_ip4_route_cmp()
964b59
+                     * implementation. That will also consider parameters that we leave unspecified here. */
964b59
+                    if (nm_platform_ip4_route_cmp(&rt->r4,
964b59
+                                                  &rt_local4,
964b59
+                                                  NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
964b59
+                        == 0)
964b59
+                        continue;
964b59
+                }
964b59
+            } else {
964b59
+                /* for each IPv6 address (that is no longer tentative) kernel adds a route like
964b59
+                 *
964b59
+                 *  local $ADDR dev $IFACE table local proto kernel metric 0 pref medium
964b59
+                 *
964b59
+                 * Same as for the IPv4 case. */
964b59
+                if (nm_platform_ip_route_get_effective_table(&rt->rx) == local_table
964b59
+                    && rt->rx.plen == 128 && rt->rx.rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL
964b59
+                    && rt->rx.metric == 0 && rt->r6.rt_pref == NM_ICMPV6_ROUTER_PREF_MEDIUM
964b59
+                    && IN6_IS_ADDR_UNSPECIFIED(&rt->r6.gateway)) {
964b59
+                    if (rt_local6.plen == 0) {
964b59
+                        rt_local6 = (NMPlatformIP6Route){
964b59
+                            .ifindex       = ifindex,
964b59
+                            .type_coerced  = nm_platform_route_type_coerce(RTN_LOCAL),
964b59
+                            .plen          = 128,
964b59
+                            .rt_source     = NM_IP_CONFIG_SOURCE_RTPROT_KERNEL,
964b59
+                            .metric        = 0,
964b59
+                            .table_coerced = nm_platform_route_table_coerce(local_table),
964b59
+                            .rt_pref       = NM_ICMPV6_ROUTER_PREF_MEDIUM,
964b59
+                            .gateway       = IN6ADDR_ANY_INIT,
964b59
+                        };
964b59
+                    }
964b59
+
964b59
+                    rt_local6.network = rt->r6.network;
964b59
+
964b59
+                    if (nm_platform_ip6_route_cmp(&rt->r6,
964b59
+                                                  &rt_local6,
964b59
+                                                  NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
964b59
+                        == 0)
964b59
+                        continue;
964b59
+                }
964b59
+            }
964b59
+            break;
964b59
+
964b59
         case NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE:
964b59
             break;
964b59
 
964b59
-- 
964b59
2.30.2
964b59