diff options
Diffstat (limited to 'src/core/platform')
| -rw-r--r-- | src/core/platform/nm-platform.c | 124 | ||||
| -rw-r--r-- | src/core/platform/tests/test-common.c | 5 |
2 files changed, 116 insertions, 13 deletions
diff --git a/src/core/platform/nm-platform.c b/src/core/platform/nm-platform.c index 0e5f8ab5..459a3307 100644 --- a/src/core/platform/nm-platform.c +++ b/src/core/platform/nm-platform.c @@ -4357,34 +4357,134 @@ 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)); 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)); + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL, + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE)); nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP_ROUTE(NM_IS_IPv4(addr_family)), ifindex); head_entry = nm_platform_lookup(self, &lookup); 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) { - const NMPObject *obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj; + const NMPObject * obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj; + const NMPlatformIPXRoute *rt = NMP_OBJECT_CAST_IPX_ROUTE(obj); - if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_FULL) { - if (nm_platform_ip_route_get_effective_table(NMP_OBJECT_CAST_IP_ROUTE(obj)) - == RT_TABLE_LOCAL) + switch (route_table_sync) { + case NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN: + if (!nm_platform_route_table_is_main(nm_platform_ip_route_get_effective_table(&rt->rx))) continue; - } else if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN) { - if (!nm_platform_route_table_is_main( - nm_platform_ip_route_get_effective_table(NMP_OBJECT_CAST_IP_ROUTE(obj)))) + break; + case NM_IP_ROUTE_TABLE_SYNC_MODE_FULL: + if (nm_platform_ip_route_get_effective_table(&rt->rx) == RT_TABLE_LOCAL) continue; - } else - nm_assert(route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_ALL); + 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; + + default: + nm_assert_not_reached(); + break; + } g_ptr_array_add(routes_prune, (gpointer) nmp_object_ref(obj)); } @@ -4679,7 +4779,7 @@ 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); + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE); success &= nm_platform_ip_route_sync(self, AF_INET, ifindex, NULL, routes_prune, NULL); } if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET6)) { @@ -4688,7 +4788,7 @@ 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); + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE); success &= nm_platform_ip_route_sync(self, AF_INET6, ifindex, NULL, routes_prune, NULL); } return success; diff --git a/src/core/platform/tests/test-common.c b/src/core/platform/tests/test-common.c index 4a117d59..1b977145 100644 --- a/src/core/platform/tests/test-common.c +++ b/src/core/platform/tests/test-common.c @@ -1542,7 +1542,10 @@ nmtstp_link_bridge_add(NMPlatform * platform, ll = NMP_OBJECT_CAST_LNK_BRIDGE(NMP_OBJECT_UP_CAST(pllink)->_link.netlink.lnk); - g_assert_cmpint(lnk->forward_delay, ==, ll->forward_delay); + /* account for roundtrip rounding error with clock_t_to_jiffies()/jiffies_to_clock_t(). */ + g_assert_cmpint(lnk->forward_delay, >=, ll->forward_delay - 1); + g_assert_cmpint(lnk->forward_delay, <=, ll->forward_delay); + g_assert_cmpint(lnk->hello_time, ==, ll->hello_time); g_assert_cmpint(lnk->max_age, ==, ll->max_age); g_assert_cmpint(lnk->ageing_time, ==, ll->ageing_time); |