summaryrefslogtreecommitdiff
path: root/src/libnm-platform/nm-platform.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnm-platform/nm-platform.c')
-rw-r--r--src/libnm-platform/nm-platform.c91
1 files changed, 91 insertions, 0 deletions
diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c
index e3f8be9cc7..9eee50fdbe 100644
--- a/src/libnm-platform/nm-platform.c
+++ b/src/libnm-platform/nm-platform.c
@@ -4312,6 +4312,11 @@ nm_platform_ip_route_get_prune_list(NMPlatform * self,
GPtrArray * routes_prune;
const NMDedupMultiHeadEntry *head_entry;
CList * iter;
+ NMPlatformIP4Route rt_local4;
+ NMPlatformIP6Route rt_local6;
+ const NMPlatformLink * pllink;
+ const NMPlatformLnkVrf * lnk_vrf;
+ guint32 local_table;
nm_assert(NM_IS_PLATFORM(self));
nm_assert(NM_IN_SET(addr_family, AF_INET, AF_INET6));
@@ -4326,6 +4331,14 @@ nm_platform_ip_route_get_prune_list(NMPlatform * self,
if (!head_entry)
return NULL;
+ lnk_vrf = nm_platform_link_get_lnk_vrf(self, ifindex, &pllink);
+ if (!lnk_vrf && pllink && pllink->master > 0)
+ lnk_vrf = nm_platform_link_get_lnk_vrf(self, pllink->master, NULL);
+ local_table = lnk_vrf ? lnk_vrf->table : RT_TABLE_LOCAL;
+
+ rt_local4.plen = 0;
+ rt_local6.plen = 0;
+
routes_prune = g_ptr_array_new_full(head_entry->len, (GDestroyNotify) nm_dedup_multi_obj_unref);
c_list_for_each (iter, &head_entry->lst_entries_head) {
@@ -4342,6 +4355,84 @@ nm_platform_ip_route_get_prune_list(NMPlatform * self,
continue;
break;
case NM_IP_ROUTE_TABLE_SYNC_MODE_ALL:
+
+ /* FIXME: we should better handle routes that are automatically added by kernel.
+ *
+ * For now, make a good guess which are those routes and exclude them from
+ * pruning them. */
+
+ if (NM_IS_IPv4(addr_family)) {
+ /* for each IPv4 address kernel adds a route like
+ *
+ * local $ADDR dev $IFACE table local proto kernel scope host src $PRIMARY_ADDR
+ *
+ * Check whether route could be of that kind. */
+ if (nm_platform_ip_route_get_effective_table(&rt->rx) == local_table
+ && rt->rx.plen == 32 && rt->rx.rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL
+ && rt->rx.metric == 0
+ && rt->r4.scope_inv == nm_platform_route_scope_inv(RT_SCOPE_HOST)
+ && rt->r4.gateway == INADDR_ANY) {
+ if (rt_local4.plen == 0) {
+ rt_local4 = (NMPlatformIP4Route){
+ .ifindex = ifindex,
+ .type_coerced = nm_platform_route_type_coerce(RTN_LOCAL),
+ .plen = 32,
+ .rt_source = NM_IP_CONFIG_SOURCE_RTPROT_KERNEL,
+ .metric = 0,
+ .table_coerced = nm_platform_route_table_coerce(local_table),
+ .scope_inv = nm_platform_route_scope_inv(RT_SCOPE_HOST),
+ .gateway = INADDR_ANY,
+ };
+ }
+
+ /* the possible "network" depends on the addresses we have. We don't check that
+ * carefully. If the other parameters match, we assume that this route is the one
+ * generated by kernel. */
+ rt_local4.network = rt->r4.network;
+ rt_local4.pref_src = rt->r4.pref_src;
+
+ /* to be more confident about comparing the value, use our nm_platform_ip4_route_cmp()
+ * implementation. That will also consider parameters that we leave unspecified here. */
+ if (nm_platform_ip4_route_cmp(&rt->r4,
+ &rt_local4,
+ NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
+ == 0)
+ continue;
+ }
+ } else {
+ /* for each IPv6 address (that is no longer tentative) kernel adds a route like
+ *
+ * local $ADDR dev $IFACE table local proto kernel metric 0 pref medium
+ *
+ * Same as for the IPv4 case. */
+ if (nm_platform_ip_route_get_effective_table(&rt->rx) == local_table
+ && rt->rx.plen == 128 && rt->rx.rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL
+ && rt->rx.metric == 0 && rt->r6.rt_pref == NM_ICMPV6_ROUTER_PREF_MEDIUM
+ && IN6_IS_ADDR_UNSPECIFIED(&rt->r6.gateway)) {
+ if (rt_local6.plen == 0) {
+ rt_local6 = (NMPlatformIP6Route){
+ .ifindex = ifindex,
+ .type_coerced = nm_platform_route_type_coerce(RTN_LOCAL),
+ .plen = 128,
+ .rt_source = NM_IP_CONFIG_SOURCE_RTPROT_KERNEL,
+ .metric = 0,
+ .table_coerced = nm_platform_route_table_coerce(local_table),
+ .rt_pref = NM_ICMPV6_ROUTER_PREF_MEDIUM,
+ .gateway = IN6ADDR_ANY_INIT,
+ };
+ }
+
+ rt_local6.network = rt->r6.network;
+
+ if (nm_platform_ip6_route_cmp(&rt->r6,
+ &rt_local6,
+ NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY)
+ == 0)
+ continue;
+ }
+ }
+ break;
+
case NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE:
break;