diff options
author | Thomas Haller <thaller@redhat.com> | 2017-08-31 13:39:04 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2017-09-08 11:11:21 +0200 |
commit | 0918b4914d03ec14f71b3e56178c44a6ec648b34 (patch) | |
tree | caea55c278b80dff68ab754fb1a65351ae9695b4 | |
parent | a214f398e7b17cacad335f70462a606affc2ad63 (diff) |
core: support tracking default-route in NMIP4Config/NMIP6Config
Default-routes are for the most part like regular routes. Add support to
track them like regular routes in NMIP4Config/NMIP6Config.
One thing is, sometimes we need to figure out whether an ip-config
instance has a default-route. For that, keep track of the best
default-route (there might be multiple) and expose it. That is
the most complicated part of this patch, because there are so many
places where the list of routes gets modified (replace, intersect,
subtract, merge, add), and they all need to take care of updating
the best default-route.
In a next patch, NMDefaultRouteManager will be dropped and default-routes
will be tracked by NMIP4Config/NMIP6Config.
-rw-r--r-- | src/dns/nm-dns-dnsmasq.c | 12 | ||||
-rw-r--r-- | src/nm-dispatcher.c | 4 | ||||
-rw-r--r-- | src/nm-ip4-config.c | 257 | ||||
-rw-r--r-- | src/nm-ip4-config.h | 27 | ||||
-rw-r--r-- | src/nm-ip6-config.c | 196 | ||||
-rw-r--r-- | src/nm-ip6-config.h | 8 | ||||
-rw-r--r-- | src/nm-pacrunner-manager.c | 4 |
7 files changed, 439 insertions, 69 deletions
diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c index cb311dffd..3ec1fd2de 100644 --- a/src/dns/nm-dns-dnsmasq.c +++ b/src/dns/nm-dns-dnsmasq.c @@ -91,8 +91,10 @@ get_ip4_rdns_domains (NMIP4Config *ip4) nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ip4, &address) nm_utils_get_reverse_dns_domains_ip4 (address->address, address->plen, domains); - nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &route) - nm_utils_get_reverse_dns_domains_ip4 (route->network, route->plen, domains); + nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &route) { + if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) + nm_utils_get_reverse_dns_domains_ip4 (route->network, route->plen, domains); + } /* Terminating NULL so we can use g_strfreev() to free it */ g_ptr_array_add (domains, NULL); @@ -119,8 +121,10 @@ get_ip6_rdns_domains (NMIP6Config *ip6) nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6, &address) nm_utils_get_reverse_dns_domains_ip6 (&address->address, address->plen, domains); - nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route) - nm_utils_get_reverse_dns_domains_ip6 (&route->network, route->plen, domains); + nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route) { + if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) + nm_utils_get_reverse_dns_domains_ip6 (&route->network, route->plen, domains); + } /* Terminating NULL so we can use g_strfreev() to free it */ g_ptr_array_add (domains, NULL); diff --git a/src/nm-dispatcher.c b/src/nm-dispatcher.c index cb7bb3c5a..b5b11812e 100644 --- a/src/nm-dispatcher.c +++ b/src/nm-dispatcher.c @@ -166,6 +166,8 @@ dump_ip4_to_props (NMIP4Config *ip4, GVariantBuilder *builder) /* Static routes */ g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("aau")); nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &route) { + if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) + continue; array[0] = route->network; array[1] = route->plen; array[2] = route->gateway; @@ -235,6 +237,8 @@ dump_ip6_to_props (NMIP6Config *ip6, GVariantBuilder *builder) /* Static routes */ g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("a(ayuayu)")); nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route) { + if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) + continue; ip = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, &route->network, sizeof (struct in6_addr), 1); diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 9037c2d6f..cf8435414 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -377,6 +377,7 @@ typedef struct { GVariant *route_data_variant; GVariant *routes_variant; NMDedupMultiIndex *multi_idx; + const NMPObject *best_default_route; union { NMIPConfigDedupMultiIdxType idx_ip4_addresses_; NMDedupMultiIdxType idx_ip4_addresses; @@ -471,6 +472,95 @@ nm_ip_config_iter_ip4_route_init (NMDedupMultiIter *ipconf_iter, const NMIP4Conf /*****************************************************************************/ +const NMPObject * +_nm_ip_config_best_default_route_find_better (const NMPObject *obj_cur, const NMPObject *obj_cmp) +{ + int addr_family; + int c; + guint metric_cur, metric_cmp; + + nm_assert ( !obj_cur + || NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_cur), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); + nm_assert ( !obj_cmp + || ( !obj_cur + && NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_cmp), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)) + || NMP_OBJECT_GET_TYPE (obj_cur) == NMP_OBJECT_GET_TYPE (obj_cmp)); + nm_assert ( !obj_cur + || nm_ip_config_best_default_route_is (obj_cur)); + + /* assumes that @obj_cur is already the best default route (or NULL). It checks whether + * @obj_cmp is also a default route and returns the best of both. */ + if ( obj_cmp + && nm_ip_config_best_default_route_is (obj_cmp)) { + if (!obj_cur) + return obj_cmp; + + addr_family = NMP_OBJECT_GET_CLASS (obj_cmp)->addr_family; + metric_cur = nm_utils_ip_route_metric_normalize (addr_family, NMP_OBJECT_CAST_IP_ROUTE (obj_cur)->metric); + metric_cmp = nm_utils_ip_route_metric_normalize (addr_family, NMP_OBJECT_CAST_IP_ROUTE (obj_cmp)->metric); + + if (metric_cmp < metric_cur) + return obj_cmp; + + if (metric_cmp == metric_cur) { + /* Routes have the same metric. We still want to deterministically + * prefer one or the other. It's important to consistently choose one + * or the other, so that the order doesn't matter how routes are added + * (and merged). */ + c = nmp_object_cmp (obj_cur, obj_cmp); + if (c != 0) + return c < 0 ? obj_cur : obj_cmp; + + /* as last resort, compare pointers. */ + if (obj_cmp < obj_cur) + return obj_cmp; + } + } + return obj_cur; +} + +gboolean +_nm_ip_config_best_default_route_set (const NMPObject **best_default_route, const NMPObject *new_candidate) +{ + if (new_candidate == *best_default_route) + return FALSE; + nmp_object_ref (new_candidate); + nm_clear_nmp_object (best_default_route); + *best_default_route = new_candidate; + return TRUE; +} + +gboolean +_nm_ip_config_best_default_route_merge (const NMPObject **best_default_route, const NMPObject *new_candidate) +{ + new_candidate = _nm_ip_config_best_default_route_find_better (*best_default_route, + new_candidate); + return _nm_ip_config_best_default_route_set (best_default_route, new_candidate); +} + +const NMPObject * +nm_ip4_config_best_default_route_get (const NMIP4Config *self) +{ + g_return_val_if_fail (NM_IS_IP4_CONFIG (self), NULL); + + return NM_IP4_CONFIG_GET_PRIVATE (self)->best_default_route; +} + +const NMPObject * +_nm_ip4_config_best_default_route_find (const NMIP4Config *self) +{ + NMDedupMultiIter ipconf_iter; + const NMPObject *new_best_default_route = NULL; + + nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, self, NULL) { + new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, + ipconf_iter.current->obj); + } + return new_best_default_route; +} + +/*****************************************************************************/ + static void _notify_addresses (NMIP4Config *self) { @@ -487,6 +577,7 @@ _notify_routes (NMIP4Config *self) { NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + nm_assert (priv->best_default_route == _nm_ip4_config_best_default_route_find (self)); nm_clear_g_variant (&priv->route_data_variant); nm_clear_g_variant (&priv->routes_variant); _notify (self, PROP_ROUTE_DATA); @@ -1056,8 +1147,7 @@ nm_ip4_config_create_setting (const NMIP4Config *self) nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, self, &route) { NMIPRoute *s_route; - /* Ignore default route. */ - if (!route->plen) + if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) continue; /* Ignore routes provided by external sources */ @@ -1133,10 +1223,8 @@ nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src, NMIPConfigMergeFl /* routes */ if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_ROUTES)) { - const NMPlatformIP4Route *route; - - nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, src, &route) - _add_route (dst, NMP_OBJECT_UP_CAST (route), NULL, NULL); + nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, src, NULL) + _add_route (dst, ipconf_iter.current->obj, NULL, NULL); } if (dst_priv->route_metric == -1) @@ -1310,6 +1398,7 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src) const NMPlatformIP4Route *r; NMDedupMultiIter ipconf_iter; gboolean changed; + gboolean changed_default_route; g_return_if_fail (src != NULL); g_return_if_fail (dst != NULL); @@ -1349,12 +1438,24 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src) /* routes */ changed = FALSE; + changed_default_route = FALSE; nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, src, &r) { + nm_auto_nmpobj const NMPObject *obj_old = NULL; + if (nm_dedup_multi_index_remove_obj (dst_priv->multi_idx, &dst_priv->idx_ip4_routes, NMP_OBJECT_UP_CAST (r), - NULL)) + (gconstpointer *) &obj_old)) { + if (dst_priv->best_default_route == obj_old) { + nm_clear_nmp_object (&dst_priv->best_default_route); + changed_default_route = TRUE; + } changed = TRUE; + } + } + if (changed_default_route) { + _nm_ip_config_best_default_route_set (&dst_priv->best_default_route, + _nm_ip4_config_best_default_route_find (dst)); } if (changed) _notify_routes (dst); @@ -1421,16 +1522,17 @@ nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src) NMDedupMultiIter ipconf_iter; const NMPlatformIP4Address *a; const NMPlatformIP4Route *r; + const NMPObject *new_best_default_route; gboolean changed; g_return_if_fail (src); g_return_if_fail (dst); - g_object_freeze_notify (G_OBJECT (dst)); - dst_priv = NM_IP4_CONFIG_GET_PRIVATE (dst); src_priv = NM_IP4_CONFIG_GET_PRIVATE (src); + g_object_freeze_notify (G_OBJECT (dst)); + /* addresses */ changed = FALSE; nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, dst, &a) { @@ -1459,17 +1561,24 @@ nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src) /* routes */ changed = FALSE; + new_best_default_route = NULL; nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, dst, &r) { + const NMPObject *o = NMP_OBJECT_UP_CAST (r); + if (nm_dedup_multi_index_lookup_obj (src_priv->multi_idx, &src_priv->idx_ip4_routes, - NMP_OBJECT_UP_CAST (r))) + o)) { + new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, o); continue; + } if (nm_dedup_multi_index_remove_entry (dst_priv->multi_idx, ipconf_iter.current) != 1) nm_assert_not_reached (); changed = TRUE; } + if (_nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route)) + nm_assert (changed); if (changed) _notify_routes (dst); @@ -1509,6 +1618,7 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev const NMIP4ConfigPrivate *src_priv; NMDedupMultiIter ipconf_iter_src, ipconf_iter_dst; const NMDedupMultiHeadEntry *head_entry_src; + const NMPObject *new_best_default_route; g_return_val_if_fail (src != NULL, FALSE); g_return_val_if_fail (dst != NULL, FALSE); @@ -1627,19 +1737,25 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev } if (!are_equal) { has_minor_changes = TRUE; + new_best_default_route = NULL; nm_dedup_multi_index_dirty_set_idx (dst_priv->multi_idx, &dst_priv->idx_ip4_routes); nm_dedup_multi_iter_for_each (&ipconf_iter_src, head_entry_src) { + const NMPObject *o = ipconf_iter_src.current->obj; + const NMPObject *obj_new; + _nm_ip_config_add_obj (dst_priv->multi_idx, &dst_priv->idx_ip4_routes_, dst_priv->ifindex, - ipconf_iter_src.current->obj, + o, NULL, FALSE, TRUE, NULL, - NULL); + &obj_new); + new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, obj_new); } nm_dedup_multi_index_dirty_remove_idx (dst_priv->multi_idx, &dst_priv->idx_ip4_routes, FALSE); + _nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route); _notify_routes (dst); } @@ -2028,18 +2144,12 @@ nm_ip4_config_add_address (NMIP4Config *self, const NMPlatformIP4Address *new) void _nmtst_ip4_config_del_address (NMIP4Config *self, guint i) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); const NMPlatformIP4Address *a; a = _nmtst_ip4_config_get_address (self, i); - g_return_if_fail (a); - - if (nm_dedup_multi_index_remove_obj (priv->multi_idx, - &priv->idx_ip4_addresses, - NMP_OBJECT_UP_CAST (a), - NULL) != 1) - g_return_if_reached (); - _notify_addresses (self); + if (!nm_ip4_config_nmpobj_remove (self, + NMP_OBJECT_UP_CAST (a))) + g_assert_not_reached (); } guint @@ -2121,8 +2231,10 @@ nm_ip4_config_reset_routes (NMIP4Config *self) NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); if (nm_dedup_multi_index_remove_idx (priv->multi_idx, - &priv->idx_ip4_routes) > 0) + &priv->idx_ip4_routes) > 0) { + nm_clear_nmp_object (&priv->best_default_route); _notify_routes (self); + } } static void @@ -2132,6 +2244,7 @@ _add_route (NMIP4Config *self, const NMPObject **out_obj_new) { NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + nm_auto_nmpobj const NMPObject *obj_old = NULL; const NMPObject *obj_new_2; nm_assert ((!new) != (!obj_new)); @@ -2145,8 +2258,12 @@ _add_route (NMIP4Config *self, (const NMPlatformObject *) new, TRUE, FALSE, - NULL, + &obj_old, &obj_new_2)) { + if ( priv->best_default_route == obj_old + && obj_old != obj_new_2) + nm_clear_nmp_object (&priv->best_default_route); + _nm_ip_config_best_default_route_merge (&priv->best_default_route, obj_new_2); NM_SET_OUT (out_obj_new, nmp_object_ref (obj_new_2)); _notify_routes (self); } else @@ -2172,7 +2289,7 @@ nm_ip4_config_add_route (NMIP4Config *self, { g_return_if_fail (self); g_return_if_fail (new); - g_return_if_fail (new->plen > 0 && new->plen <= 32); + g_return_if_fail (new->plen <= 32); g_return_if_fail (NM_IP4_CONFIG_GET_PRIVATE (self)->ifindex > 0); _add_route (self, NULL, new, out_obj_new); @@ -2181,18 +2298,12 @@ nm_ip4_config_add_route (NMIP4Config *self, void _nmtst_ip4_config_del_route (NMIP4Config *self, guint i) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); const NMPlatformIP4Route *r; r = _nmtst_ip4_config_get_route (self, i); - g_return_if_fail (r); - - if (nm_dedup_multi_index_remove_obj (priv->multi_idx, - &priv->idx_ip4_routes, - NMP_OBJECT_UP_CAST (r), - NULL) != 1) - g_return_if_reached (); - _notify_routes (self); + if (!nm_ip4_config_nmpobj_remove (self, + NMP_OBJECT_UP_CAST (r))) + g_assert_not_reached (); } guint @@ -2701,6 +2812,84 @@ nm_ip4_config_get_metered (const NMIP4Config *self) /*****************************************************************************/ +const NMPObject * +nm_ip4_config_nmpobj_lookup (const NMIP4Config *self, const NMPObject *needle) +{ + const NMIP4ConfigPrivate *priv; + const NMDedupMultiIdxType *idx_type; + + g_return_val_if_fail (NM_IS_IP4_CONFIG (self), NULL); + + priv = NM_IP4_CONFIG_GET_PRIVATE (self); + switch (NMP_OBJECT_GET_TYPE (needle)) { + case NMP_OBJECT_TYPE_IP4_ADDRESS: + idx_type = &priv->idx_ip4_addresses; + break; + case NMP_OBJECT_TYPE_IP4_ROUTE: + idx_type = &priv->idx_ip4_routes; + break; + default: + g_return_val_if_reached (NULL); + } + + return nm_dedup_multi_entry_get_obj (nm_dedup_multi_index_lookup_obj (priv->multi_idx, + idx_type, + needle)); +} + +gboolean +nm_ip4_config_nmpobj_remove (NMIP4Config *self, + const NMPObject *needle) +{ + NMIP4ConfigPrivate *priv; + NMDedupMultiIdxType *idx_type; + nm_auto_nmpobj const NMPObject *obj_old = NULL; + guint n; + + g_return_val_if_fail (NM_IS_IP4_CONFIG (self), FALSE); + + priv = NM_IP4_CONFIG_GET_PRIVATE (self); + switch (NMP_OBJECT_GET_TYPE (needle)) { + case NMP_OBJECT_TYPE_IP4_ADDRESS: + idx_type = &priv->idx_ip4_addresses; + break; + case NMP_OBJECT_TYPE_IP4_ROUTE: + idx_type = &priv->idx_ip4_routes; + break; + default: + g_return_val_if_reached (FALSE); + } + + n = nm_dedup_multi_index_remove_obj (priv->multi_idx, + idx_type, + needle, + (gconstpointer *) &obj_old); + if (n != 1) { + nm_assert (n == 0); + return FALSE; + } + + nm_assert (NMP_OBJECT_GET_TYPE (obj_old) == NMP_OBJECT_GET_TYPE (needle)); + + switch (NMP_OBJECT_GET_TYPE (obj_old)) { + case NMP_OBJECT_TYPE_IP4_ADDRESS: + _notify_addresses (self); + break; + case NMP_OBJECT_TYPE_IP4_ROUTE: + if (priv->best_default_route == obj_old) { + _nm_ip_config_best_default_route_set (&priv->best_default_route, + _nm_ip4_config_best_default_route_find (self)); + } + _notify_routes (self); + break; + default: + nm_assert_not_reached (); + } + return TRUE; +} + +/*****************************************************************************/ + static inline void hash_u32 (GChecksum *sum, guint32 n) { @@ -3056,6 +3245,8 @@ finalize (GObject *object) NMIP4Config *self = NM_IP4_CONFIG (object); NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + nm_clear_nmp_object (&priv->best_default_route); + nm_dedup_multi_index_remove_idx (priv->multi_idx, &priv->idx_ip4_addresses); nm_dedup_multi_index_remove_idx (priv->multi_idx, &priv->idx_ip4_routes); diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index 1113c9928..7db858b7b 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -75,6 +75,25 @@ nm_ip_config_iter_ip4_route_next (NMDedupMultiIter *ipconf_iter, const NMPlatfor /*****************************************************************************/ +static inline gboolean +nm_ip_config_best_default_route_is (const NMPObject *obj) +{ + const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE (obj); + + /* return whether @obj is considered a default-route, that is, a route + * as added by NetworkManager. E.g. if the route is not in the main-table, + * it's considered just like a regular route. */ + return r + && !r->table_coerced + && NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r); +} + +const NMPObject *_nm_ip_config_best_default_route_find_better (const NMPObject *obj_cur, const NMPObject *obj_cmp); +gboolean _nm_ip_config_best_default_route_set (const NMPObject **best_default_route, const NMPObject *new_candidate); +gboolean _nm_ip_config_best_default_route_merge (const NMPObject **best_default_route, const NMPObject *new_candidate); + +/*****************************************************************************/ + gboolean nm_ip_config_obj_id_equal_ip4_address (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b); gboolean nm_ip_config_obj_id_equal_ip6_address (const NMPlatformIP6Address *a, @@ -163,6 +182,9 @@ gboolean nm_ip4_config_has_gateway (const NMIP4Config *self); guint32 nm_ip4_config_get_gateway (const NMIP4Config *self); gint64 nm_ip4_config_get_route_metric (const NMIP4Config *self); +const NMPObject *nm_ip4_config_best_default_route_get (const NMIP4Config *self); +const NMPObject *_nm_ip4_config_best_default_route_find (const NMIP4Config *self); + const NMDedupMultiHeadEntry *nm_ip4_config_lookup_addresses (const NMIP4Config *self); void nm_ip4_config_reset_addresses (NMIP4Config *self); void nm_ip4_config_add_address (NMIP4Config *self, const NMPlatformIP4Address *address); @@ -234,6 +256,11 @@ NMIPConfigSource nm_ip4_config_get_mtu_source (const NMIP4Config *self); void nm_ip4_config_set_metered (NMIP4Config *self, gboolean metered); gboolean nm_ip4_config_get_metered (const NMIP4Config *self); +const NMPObject *nm_ip4_config_nmpobj_lookup (const NMIP4Config *self, + const NMPObject *needle); +gboolean nm_ip4_config_nmpobj_remove (NMIP4Config *self, + const NMPObject *needle); + void nm_ip4_config_hash (const NMIP4Config *self, GChecksum *sum, gboolean dns_only); gboolean nm_ip4_config_equal (const NMIP4Config *a, const NMIP4Config *b); diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 641e73434..0aad49d54 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -72,6 +72,7 @@ typedef struct { GVariant *route_data_variant; GVariant *routes_variant; NMDedupMultiIndex *multi_idx; + const NMPObject *best_default_route; union { NMIPConfigDedupMultiIdxType idx_ip6_addresses_; NMDedupMultiIdxType idx_ip6_addresses; @@ -177,6 +178,29 @@ nm_ip_config_iter_ip6_route_init (NMDedupMultiIter *ipconf_iter, const NMIP6Conf /*****************************************************************************/ +const NMPObject * +nm_ip6_config_best_default_route_get (const NMIP6Config *self) +{ + g_return_val_if_fail (NM_IS_IP6_CONFIG (self), NULL); + + return NM_IP6_CONFIG_GET_PRIVATE (self)->best_default_route; +} + +const NMPObject * +_nm_ip6_config_best_default_route_find (const NMIP6Config *self) +{ + NMDedupMultiIter ipconf_iter; + const NMPObject *new_best_default_route = NULL; + + nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, self, NULL) { + new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, + ipconf_iter.current->obj); + } + return new_best_default_route; +} + +/*****************************************************************************/ + static void _notify_addresses (NMIP6Config *self) { @@ -193,6 +217,7 @@ _notify_routes (NMIP6Config *self) { NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); + nm_assert (priv->best_default_route == _nm_ip6_config_best_default_route_find (self)); nm_clear_g_variant (&priv->route_data_variant); nm_clear_g_variant (&priv->routes_variant); _notify (self, PROP_ROUTE_DATA); @@ -781,8 +806,7 @@ nm_ip6_config_create_setting (const NMIP6Config *self) if (IN6_IS_ADDR_LINKLOCAL (&route->network)) continue; - /* Ignore default route. */ - if (!route->plen) + if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) continue; /* Ignore routes provided by external sources */ @@ -857,10 +881,8 @@ nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFl /* routes */ if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_ROUTES)) { - const NMPlatformIP6Route *route; - - nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, src, &route) - _add_route (dst, NMP_OBJECT_UP_CAST (route), NULL, NULL); + nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, src, NULL) + _add_route (dst, ipconf_iter.current->obj, NULL, NULL); } if (dst_priv->route_metric == -1) @@ -997,6 +1019,7 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src) NMDedupMultiIter ipconf_iter; const struct in6_addr *dst_tmp, *src_tmp; gboolean changed; + gboolean changed_default_route; g_return_if_fail (src != NULL); g_return_if_fail (dst != NULL); @@ -1037,12 +1060,24 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src) /* routes */ changed = FALSE; + changed_default_route = FALSE; nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, src, &r) { + nm_auto_nmpobj const NMPObject *obj_old = NULL; + if (nm_dedup_multi_index_remove_obj (dst_priv->multi_idx, &dst_priv->idx_ip6_routes, NMP_OBJECT_UP_CAST (r), - NULL)) + (gconstpointer *) &obj_old)) { + if (dst_priv->best_default_route == obj_old) { + nm_clear_nmp_object (&dst_priv->best_default_route); + changed_default_route = TRUE; + } changed = TRUE; + } + } + if (changed_default_route) { + _nm_ip_config_best_default_route_set (&dst_priv->best_default_route, + _nm_ip6_config_best_default_route_find (dst)); } if (changed) _notify_routes (dst); @@ -1088,6 +1123,7 @@ nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src) const NMPlatformIP6Address *a; const NMPlatformIP6Route *r; gboolean changed; + const NMPObject *new_best_default_route; g_return_if_fail (src); g_return_if_fail (dst); @@ -1128,17 +1164,24 @@ nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src) /* routes */ changed = FALSE; + new_best_default_route = NULL; nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, dst, &r) { + const NMPObject *o = NMP_OBJECT_UP_CAST (r); + if (nm_dedup_multi_index_lookup_obj (src_priv->multi_idx, &src_priv->idx_ip6_routes, - NMP_OBJECT_UP_CAST (r))) + o)) { + new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, o); continue; + } if (nm_dedup_multi_index_remove_entry (dst_priv->multi_idx, ipconf_iter.current) != 1) nm_assert_not_reached (); changed = TRUE; } + if (_nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route)) + nm_assert (changed); if (changed) _notify_routes (dst); @@ -1175,6 +1218,7 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev const NMIP6ConfigPrivate *src_priv; NMDedupMultiIter ipconf_iter_src, ipconf_iter_dst; const NMDedupMultiHeadEntry *head_entry_src; + const NMPObject *new_best_default_route; g_return_val_if_fail (NM_IS_IP6_CONFIG (src), FALSE); g_return_val_if_fail (NM_IS_IP6_CONFIG (dst), FALSE); @@ -1293,19 +1337,25 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev } if (!are_equal) { has_minor_changes = TRUE; + new_best_default_route = NULL; nm_dedup_multi_index_dirty_set_idx (dst_priv->multi_idx, &dst_priv->idx_ip6_routes); nm_dedup_multi_iter_for_each (&ipconf_iter_src, head_entry_src) { + const NMPObject *o = ipconf_iter_src.current->obj; + const NMPObject *obj_new; + _nm_ip_config_add_obj (dst_priv->multi_idx, &dst_priv->idx_ip6_routes_, dst_priv->ifindex, - ipconf_iter_src.current->obj, + o, NULL, FALSE, TRUE, NULL, - NULL); + &obj_new); + new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, obj_new); } nm_dedup_multi_index_dirty_remove_idx (dst_priv->multi_idx, &dst_priv->idx_ip6_routes, FALSE); + _nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route); _notify_routes (dst); } @@ -1631,18 +1681,12 @@ nm_ip6_config_add_address (NMIP6Config *self, const NMPlatformIP6Address *new) void _nmtst_ip6_config_del_address (NMIP6Config *self, guint i) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); const NMPlatformIP6Address *a; a = _nmtst_ip6_config_get_address (self, i); - g_return_if_fail (a); - - if (nm_dedup_multi_index_remove_obj (priv->multi_idx, - &priv->idx_ip6_addresses, - NMP_OBJECT_UP_CAST (a), - NULL) != 1) - g_return_if_reached (); - _notify_addresses (self); + if (!nm_ip6_config_nmpobj_remove (self, + NMP_OBJECT_UP_CAST (a))) + g_assert_not_reached (); } guint @@ -1767,6 +1811,7 @@ nm_ip6_config_reset_routes_ndisc (NMIP6Config *self, NMIP6ConfigPrivate *priv; guint i; gboolean changed = FALSE; + const NMPObject *new_best_default_route; g_return_if_fail (NM_IS_IP6_CONFIG (self)); @@ -1776,9 +1821,11 @@ nm_ip6_config_reset_routes_ndisc (NMIP6Config *self, nm_dedup_multi_index_dirty_set_idx (priv->multi_idx, &priv->idx_ip6_routes); + new_best_default_route = NULL; for (i = 0; i < routes_n; i++) { const NMNDiscRoute *ndisc_route = &routes[i]; NMPObject obj; + const NMPObject *obj_new; NMPlatformIP6Route *r; nmp_object_stackinit (&obj, NMP_OBJECT_TYPE_IP6_ROUTE, NULL); @@ -1798,10 +1845,14 @@ nm_ip6_config_reset_routes_ndisc (NMIP6Config *self, FALSE, TRUE, NULL, - NULL)) + &obj_new)) changed = TRUE; + new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, obj_new); } + if (_nm_ip_config_best_default_route_set (&priv->best_default_route, new_best_default_route)) + changed = TRUE; + if (nm_dedup_multi_index_dirty_remove_idx (priv->multi_idx, &priv->idx_ip6_routes, FALSE) > 0) changed = TRUE; @@ -1815,8 +1866,10 @@ nm_ip6_config_reset_routes (NMIP6Config *self) NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); if (nm_dedup_multi_index_remove_idx (priv->multi_idx, - &priv->idx_ip6_routes) > 0) + &priv->idx_ip6_routes) > 0) { + nm_clear_nmp_object (&priv->best_default_route); _notify_routes (self); + } } static void @@ -1826,6 +1879,7 @@ _add_route (NMIP6Config *self, const NMPObject **out_obj_new) { NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); + nm_auto_nmpobj const NMPObject *obj_old = NULL; const NMPObject *obj_new_2; nm_assert ((!new) != (!obj_new)); @@ -1839,8 +1893,12 @@ _add_route (NMIP6Config *self, (const NMPlatformObject *) new, TRUE, FALSE, - NULL, + &obj_old, &obj_new_2)) { + if ( priv->best_default_route == obj_old + && obj_old != obj_new_2) + nm_clear_nmp_object (&priv->best_default_route); + _nm_ip_config_best_default_route_merge (&priv->best_default_route, obj_new_2); NM_SET_OUT (out_obj_new, nmp_object_ref (obj_new_2)); _notify_routes (self); } else @@ -1866,7 +1924,7 @@ nm_ip6_config_add_route (NMIP6Config *self, { g_return_if_fail (self); g_return_if_fail (new); - g_return_if_fail (new->plen > 0 && new->plen <= 128); + g_return_if_fail (new->plen <= 128); g_return_if_fail (NM_IP6_CONFIG_GET_PRIVATE (self)->ifindex > 0); _add_route (self, NULL, new, out_obj_new); @@ -1875,18 +1933,12 @@ nm_ip6_config_add_route (NMIP6Config *self, void _nmtst_ip6_config_del_route (NMIP6Config *self, guint i) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); const NMPlatformIP6Route *r; r = _nmtst_ip6_config_get_route (self, i); - g_return_if_fail (r); - - if (nm_dedup_multi_index_remove_obj (priv->multi_idx, - &priv->idx_ip6_routes, - NMP_OBJECT_UP_CAST (r), - NULL) != 1) - g_return_if_reached (); - _notify_routes (self); + if (!nm_ip6_config_nmpobj_remove (self, + NMP_OBJECT_UP_CAST (r))) + g_assert_not_reached (); } guint @@ -2251,6 +2303,84 @@ nm_ip6_config_get_mss (const NMIP6Config *self) /*****************************************************************************/ +const NMPObject * +nm_ip6_config_nmpobj_lookup (const NMIP6Config *self, const NMPObject *needle) +{ + const NMIP6ConfigPrivate *priv; + const NMDedupMultiIdxType *idx_type; + + g_return_val_if_fail (NM_IS_IP6_CONFIG (self), NULL); + + priv = NM_IP6_CONFIG_GET_PRIVATE (self); + switch (NMP_OBJECT_GET_TYPE (needle)) { + case NMP_OBJECT_TYPE_IP6_ADDRESS: + idx_type = &priv->idx_ip6_addresses; + break; + case NMP_OBJECT_TYPE_IP6_ROUTE: + idx_type = &priv->idx_ip6_routes; + break; + default: + g_return_val_if_reached (NULL); + } + + return nm_dedup_multi_entry_get_obj (nm_dedup_multi_index_lookup_obj (priv->multi_idx, + idx_type, + needle)); +} + +gboolean +nm_ip6_config_nmpobj_remove (NMIP6Config *self, + const NMPObject *needle) +{ + NMIP6ConfigPrivate *priv; + NMDedupMultiIdxType *idx_type; + nm_auto_nmpobj const NMPObject *obj_old = NULL; + guint n; + + g_return_val_if_fail (NM_IS_IP6_CONFIG (self), FALSE); + + priv = NM_IP6_CONFIG_GET_PRIVATE (self); + switch (NMP_OBJECT_GET_TYPE (needle)) { + case NMP_OBJECT_TYPE_IP6_ADDRESS: + idx_type = &priv->idx_ip6_addresses; + break; + case NMP_OBJECT_TYPE_IP6_ROUTE: + idx_type = &priv->idx_ip6_routes; + break; + default: + g_return_val_if_reached (FALSE); + } + + n = nm_dedup_multi_index_remove_obj (priv->multi_idx, + idx_type, + needle, + (gconstpointer *) &obj_old); + if (n != 1) { + nm_assert (n == 0); + return FALSE; + } + + nm_assert (NMP_OBJECT_GET_TYPE (obj_old) == NMP_OBJECT_GET_TYPE (needle)); + + switch (NMP_OBJECT_GET_TYPE (obj_old)) { + case NMP_OBJECT_TYPE_IP6_ADDRESS: + _notify_addresses (self); + break; + case NMP_OBJECT_TYPE_IP6_ROUTE: + if (priv->best_default_route == obj_old) { + _nm_ip_config_best_default_route_set (&priv->best_default_route, + _nm_ip6_config_best_default_route_find (self)); + } + _notify_routes (self); + break; + default: + nm_assert_not_reached (); + } + return TRUE; +} + +/*****************************************************************************/ + static inline void hash_u32 (GChecksum *sum, guint32 n) { @@ -2611,6 +2741,8 @@ finalize (GObject *object) NMIP6Config *self = NM_IP6_CONFIG (object); NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); + nm_clear_nmp_object (&priv->best_default_route); + nm_dedup_multi_index_remove_idx (priv->multi_idx, &priv->idx_ip6_addresses); nm_dedup_multi_index_remove_idx (priv->multi_idx, &priv->idx_ip6_routes); diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index 0a7fe1749..ec8bee881 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -127,6 +127,9 @@ void nm_ip6_config_set_gateway (NMIP6Config *self, const struct in6_addr *); const struct in6_addr *nm_ip6_config_get_gateway (const NMIP6Config *self); gint64 nm_ip6_config_get_route_metric (const NMIP6Config *self); +const NMPObject *nm_ip6_config_best_default_route_get (const NMIP6Config *self); +const NMPObject *_nm_ip6_config_best_default_route_find (const NMIP6Config *self); + const NMDedupMultiHeadEntry *nm_ip6_config_lookup_addresses (const NMIP6Config *self); void nm_ip6_config_reset_addresses (NMIP6Config *self); void nm_ip6_config_add_address (NMIP6Config *self, const NMPlatformIP6Address *address); @@ -184,6 +187,11 @@ gint nm_ip6_config_get_dns_priority (const NMIP6Config *self); void nm_ip6_config_set_mss (NMIP6Config *self, guint32 mss); guint32 nm_ip6_config_get_mss (const NMIP6Config *self); +const NMPObject *nm_ip6_config_nmpobj_lookup (const NMIP6Config *self, + const NMPObject *needle); +gboolean nm_ip6_config_nmpobj_remove (NMIP6Config *self, + const NMPObject *needle); + void nm_ip6_config_hash (const NMIP6Config *self, GChecksum *sum, gboolean dns_only); gboolean nm_ip6_config_equal (const NMIP6Config *a, const NMIP6Config *b); diff --git a/src/nm-pacrunner-manager.c b/src/nm-pacrunner-manager.c index 2558ca0f3..08e10e40d 100644 --- a/src/nm-pacrunner-manager.c +++ b/src/nm-pacrunner-manager.c @@ -192,6 +192,8 @@ get_ip4_domains (GPtrArray *domains, NMIP4Config *ip4) } nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &routes) { + if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (routes)) + continue; cidr = g_strdup_printf ("%s/%u", nm_utils_inet4_ntop (routes->network, NULL), routes->plen); @@ -225,6 +227,8 @@ get_ip6_domains (GPtrArray *domains, NMIP6Config *ip6) } nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &routes) { + if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (routes)) + continue; cidr = g_strdup_printf ("%s/%u", nm_utils_inet6_ntop (&routes->network, NULL), routes->plen); |