diff options
author | Thomas Haller <thaller@redhat.com> | 2017-07-03 17:03:54 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2017-07-05 18:37:39 +0200 |
commit | cfd1851c0067773211524c2b648330b6ee7a066c (patch) | |
tree | e1c608f2df5566c26978d983d7bc442834e3650f | |
parent | 28340588d9cbca3eed1f75a9d10b6a0b19068004 (diff) | |
download | NetworkManager-cfd1851c0067773211524c2b648330b6ee7a066c.tar.gz |
core: refactor NMIP6Config to use dedup-index for IPv6 routes
-rw-r--r-- | src/dns/nm-dns-dnsmasq.c | 9 | ||||
-rw-r--r-- | src/nm-dispatcher.c | 5 | ||||
-rw-r--r-- | src/nm-ip4-config.c | 27 | ||||
-rw-r--r-- | src/nm-ip4-config.h | 5 | ||||
-rw-r--r-- | src/nm-ip6-config.c | 470 | ||||
-rw-r--r-- | src/nm-ip6-config.h | 18 | ||||
-rw-r--r-- | src/nm-pacrunner-manager.c | 8 | ||||
-rw-r--r-- | src/tests/test-ip6-config.c | 12 | ||||
-rw-r--r-- | src/vpn/nm-vpn-connection.c | 16 |
9 files changed, 366 insertions, 204 deletions
diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c index 730134b5e1..d5b51af25e 100644 --- a/src/dns/nm-dns-dnsmasq.c +++ b/src/dns/nm-dns-dnsmasq.c @@ -111,7 +111,9 @@ get_ip6_rdns_domains (NMIP6Config *ip6) { char **strv; GPtrArray *domains = NULL; - int i; + guint i; + NMDedupMultiIter ipconf_iter; + const NMPlatformIP6Route *route; g_return_val_if_fail (ip6 != NULL, NULL); @@ -123,11 +125,8 @@ get_ip6_rdns_domains (NMIP6Config *ip6) nm_utils_get_reverse_dns_domains_ip6 (&address->address, address->plen, domains); } - for (i = 0; i < nm_ip6_config_get_num_routes (ip6); i++) { - const NMPlatformIP6Route *route = nm_ip6_config_get_route (ip6, i); - + nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &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 6bea925488..2393e8035f 100644 --- a/src/nm-dispatcher.c +++ b/src/nm-dispatcher.c @@ -182,6 +182,7 @@ static void dump_ip6_to_props (NMIP6Config *ip6, GVariantBuilder *builder) { GVariantBuilder int_builder; + NMDedupMultiIter ipconf_iter; guint n, i; const NMPlatformIP6Address *addr; const struct in6_addr *gw_bytes; @@ -230,9 +231,7 @@ dump_ip6_to_props (NMIP6Config *ip6, GVariantBuilder *builder) /* Static routes */ g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("a(ayuayu)")); - n = nm_ip6_config_get_num_routes (ip6); - for (i = 0; i < n; i++) { - route = nm_ip6_config_get_route (ip6, i); + nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route) { 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 eca46085ad..d5df277b14 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -46,14 +46,22 @@ G_STATIC_ASSERT (G_MAXUINT >= 0xFFFFFFFF); /*****************************************************************************/ -static gboolean -_idx_obj_id_equal_ip4_route (const NMPlatformIP4Route *r_a, - const NMPlatformIP4Route *r_b) +gboolean +nm_ip_config_obj_id_equal_ip4_route (const NMPlatformIP4Route *r_a, + const NMPlatformIP4Route *r_b) { return r_a->network == r_b->network && r_a->plen == r_b->plen; } +gboolean +nm_ip_config_obj_id_equal_ip6_route (const NMPlatformIP6Route *r_a, + const NMPlatformIP6Route *r_b) +{ + return r_a->plen == r_b->plen + && IN6_ARE_ADDR_EQUAL (&r_a->network, &r_b->network); +} + static guint _idx_obj_id_hash (const NMDedupMultiIdxType *idx_type, const NMDedupMultiObj *obj) @@ -68,10 +76,13 @@ _idx_obj_id_hash (const NMDedupMultiIdxType *idx_type, case NMP_OBJECT_TYPE_IP4_ROUTE: h = 40303327; h = NM_HASH_COMBINE (h, o->ip4_route.network); - h = NM_HASH_COMBINE (h, o->ip4_route.plen); + h = NM_HASH_COMBINE (h, o->ip_route.plen); break; case NMP_OBJECT_TYPE_IP6_ROUTE: - g_return_val_if_reached (0); + h = 577629323; + h = NM_HASH_COMBINE_IN6_ADDR (h, &o->ip6_route.network); + h = NM_HASH_COMBINE (h, o->ip_route.plen); + break; default: g_return_val_if_reached (0); }; @@ -94,9 +105,9 @@ _idx_obj_id_equal (const NMDedupMultiIdxType *idx_type, case NMP_OBJECT_TYPE_IP6_ADDRESS: g_return_val_if_reached (FALSE); case NMP_OBJECT_TYPE_IP4_ROUTE: - return _idx_obj_id_equal_ip4_route (&o_a->ip4_route, &o_b->ip4_route); + return nm_ip_config_obj_id_equal_ip4_route (&o_a->ip4_route, &o_b->ip4_route); case NMP_OBJECT_TYPE_IP6_ROUTE: - g_return_val_if_reached (FALSE); + return nm_ip_config_obj_id_equal_ip6_route (&o_a->ip6_route, &o_b->ip6_route); default: g_return_val_if_reached (FALSE); }; @@ -1300,7 +1311,7 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev if (nm_platform_ip4_route_cmp (r_src, r_dst) != 0) { are_equal = FALSE; - if (!_idx_obj_id_equal_ip4_route (r_src, r_dst)) { + if (!nm_ip_config_obj_id_equal_ip4_route (r_src, r_dst)) { has_relevant_changes = TRUE; break; } diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index f1f2979232..7049f9e5f3 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -43,6 +43,11 @@ gboolean nm_ip4_config_iter_ip4_route_next (NMDedupMultiIter *iter, const NMPlat nm_ip4_config_iter_ip4_route_next ((iter), (route)); \ ) +gboolean nm_ip_config_obj_id_equal_ip4_route (const NMPlatformIP4Route *r_a, + const NMPlatformIP4Route *r_b); +gboolean nm_ip_config_obj_id_equal_ip6_route (const NMPlatformIP6Route *r_a, + const NMPlatformIP6Route *r_b); + /*****************************************************************************/ #define NM_TYPE_IP4_CONFIG (nm_ip4_config_get_type ()) diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 7724ad4831..0dc7adcad2 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -29,11 +29,13 @@ #include "nm-utils/nm-dedup-multi.h" #include "nm-utils.h" +#include "platform/nmp-object.h" #include "platform/nm-platform.h" #include "platform/nm-platform-utils.h" #include "nm-route-manager.h" #include "nm-core-internal.h" #include "NetworkManagerUtils.h" +#include "nm-ip4-config.h" #include "introspection/org.freedesktop.NetworkManager.IP6Config.h" @@ -48,7 +50,6 @@ typedef struct { gint64 route_metric; struct in6_addr gateway; GArray *addresses; - GArray *routes; GArray *nameservers; GPtrArray *domains; GPtrArray *searches; @@ -56,6 +57,7 @@ typedef struct { GVariant *address_data_variant; GVariant *addresses_variant; NMDedupMultiIndex *multi_idx; + NMDedupMultiIdxType idx_ip6_routes; } NMIP6ConfigPrivate; struct _NMIP6Config { @@ -88,6 +90,10 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMIP6Config, /*****************************************************************************/ +static void _add_route (NMIP6Config *config, const NMPObject *o_new, const NMPlatformIP6Route *new); + +/*****************************************************************************/ + int nm_ip6_config_get_ifindex (const NMIP6Config *config) { @@ -110,6 +116,49 @@ nm_ip6_config_set_privacy (NMIP6Config *config, NMSettingIP6ConfigPrivacy privac /*****************************************************************************/ +static const NMDedupMultiHeadEntry * +_idx_ip6_routes (const NMIP6Config *self) +{ + const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); + + return nm_dedup_multi_index_lookup_head (priv->multi_idx, + &priv->idx_ip6_routes, + NULL); +} + +static const NMPlatformIP6Route * +_entry_iter_get_ip6_route (const CList *iter) +{ + const NMDedupMultiEntry *e = c_list_entry (iter, NMDedupMultiEntry, lst_entries); + const NMPObject *o = e->obj; + + nm_assert (o); + nm_assert (NMP_OBJECT_GET_TYPE (o) == NMP_OBJECT_TYPE_IP6_ROUTE); + return &o->ip6_route; +} + +void +nm_ip6_config_iter_ip6_route_init (NMDedupMultiIter *ipconf_iter, const NMIP6Config *self) +{ + g_return_if_fail (NM_IS_IP6_CONFIG (self)); + nm_dedup_multi_iter_init (ipconf_iter, _idx_ip6_routes (self)); +} + +gboolean +nm_ip6_config_iter_ip6_route_next (NMDedupMultiIter *ipconf_iter, const NMPlatformIP6Route **out_route) +{ + gboolean has_next; + + has_next = nm_dedup_multi_iter_next (ipconf_iter); + if (has_next) { + nm_assert (NMP_OBJECT_GET_TYPE (ipconf_iter->current->obj) == NMP_OBJECT_TYPE_IP6_ROUTE); + NM_SET_OUT (out_route, &(((const NMPObject *) ipconf_iter->current->obj)->ip6_route)); + } + return has_next; +} + +/*****************************************************************************/ + static void notify_addresses (NMIP6Config *self) { @@ -193,15 +242,6 @@ addresses_are_duplicate (const NMPlatformIP6Address *a, const NMPlatformIP6Addre return IN6_ARE_ADDR_EQUAL (&a->address, &b->address); } -static gboolean -routes_are_duplicate (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b, gboolean consider_gateway_and_metric) -{ - return IN6_ARE_ADDR_EQUAL (&a->network, &b->network) && a->plen == b->plen && - ( !consider_gateway_and_metric - || ( IN6_ARE_ADDR_EQUAL (&a->gateway, &b->gateway) - && nm_utils_ip6_route_metric_normalize (a->metric) == nm_utils_ip6_route_metric_normalize (b->metric))); -} - static gint _addresses_sort_cmp_get_prio (const struct in6_addr *addr) { @@ -315,10 +355,12 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i { NMIP6Config *config; NMIP6ConfigPrivate *priv; - guint i; guint32 lowest_metric = G_MAXUINT32; struct in6_addr old_gateway = IN6ADDR_ANY_INIT; - gboolean has_gateway = FALSE; + gboolean has_gateway; + const NMDedupMultiHeadEntry *pl_head_entry; + NMDedupMultiIter iter; + const NMPObject *plobj = NULL; gboolean notify_nameservers = FALSE; /* Slaves have no IP configuration */ @@ -329,47 +371,56 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i priv = NM_IP6_CONFIG_GET_PRIVATE (config); g_array_unref (priv->addresses); - g_array_unref (priv->routes); priv->addresses = nm_platform_ip6_address_get_all (platform, ifindex); - priv->routes = nm_platform_ip6_route_get_all (platform, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); + + pl_head_entry = nm_platform_lookup_route_visible (platform, + NMP_OBJECT_TYPE_IP6_ROUTE, + ifindex, + TRUE, + TRUE); /* Extract gateway from default route */ old_gateway = priv->gateway; - for (i = 0; i < priv->routes->len; ) { - const NMPlatformIP6Route *route = &g_array_index (priv->routes, NMPlatformIP6Route, i); - if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) { + lowest_metric = G_MAXUINT32; + has_gateway = FALSE; + nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) { + const NMPlatformIP6Route *route = NMP_OBJECT_CAST_IP6_ROUTE (plobj); + + if ( NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route) + && route->rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) { if (route->metric < lowest_metric) { priv->gateway = route->gateway; lowest_metric = route->metric; } has_gateway = TRUE; - /* Remove the default route from the list */ - g_array_remove_index_fast (priv->routes, i); - continue; } - i++; } /* we detect the route metric based on the default route. All non-default * routes have their route metrics explicitly set. */ priv->route_metric = has_gateway ? (gint64) lowest_metric : (gint64) -1; - /* If there is a host route to the gateway, ignore that route. It is - * automatically added by NetworkManager when needed. - */ - if (has_gateway) { - for (i = 0; i < priv->routes->len; i++) { - const NMPlatformIP6Route *route = &g_array_index (priv->routes, NMPlatformIP6Route, i); - - if ( route->plen == 128 - && IN6_ARE_ADDR_EQUAL (&route->network, &priv->gateway) - && IN6_IS_ADDR_UNSPECIFIED (&route->gateway)) { - g_array_remove_index (priv->routes, i); - i--; - } + nm_dedup_multi_iter_rewind (&iter); + nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) { + const NMPlatformIP6Route *route = NMP_OBJECT_CAST_IP6_ROUTE (plobj); + + if (route->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) + continue; + if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) + continue; + + if ( has_gateway + && route->plen == 128 + && IN6_ARE_ADDR_EQUAL (&route->network, &priv->gateway) + && IN6_IS_ADDR_UNSPECIFIED (&route->gateway)) { + /* If there is a host route to the gateway, ignore that route. It is + * automatically added by NetworkManager when needed. + */ + continue; } + _add_route (config, plobj, NULL); } /* If the interface has the default route, and has IPv6 addresses, capture @@ -403,7 +454,6 @@ nm_ip6_config_commit (const NMIP6Config *config, gboolean routes_full_sync) { const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); - gboolean success; g_return_val_if_fail (ifindex > 0, FALSE); g_return_val_if_fail (config != NULL, FALSE); @@ -413,21 +463,24 @@ nm_ip6_config_commit (const NMIP6Config *config, /* Routes */ { - guint i; - guint count = nm_ip6_config_get_num_routes (config); - GArray *routes = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP6Route), count); - const NMPlatformIP6Route *route; + const NMDedupMultiHeadEntry *head_entry; + gs_unref_array GArray *routes = NULL; + const CList *iter; + + head_entry = _idx_ip6_routes (config); - for (i = 0; i < count; i++) { - route = nm_ip6_config_get_route (config, i); - g_array_append_vals (routes, route, 1); + routes = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP6Route), head_entry ? head_entry->len : 0); + + if (head_entry) { + c_list_for_each (iter, &head_entry->lst_entries_head) + g_array_append_vals (routes, _entry_iter_get_ip6_route (iter), 1); } - success = nm_route_manager_ip6_route_sync (route_manager, ifindex, routes, TRUE, routes_full_sync); - g_array_unref (routes); + if (!nm_route_manager_ip6_route_sync (route_manager, ifindex, routes, TRUE, routes_full_sync)) + return FALSE; } - return success; + return TRUE; } static void @@ -558,7 +611,7 @@ nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIPConfig *setting, gu route.rt_source = NM_IP_CONFIG_SOURCE_USER; merge_route_attributes (s_route, &route); - nm_ip6_config_add_route (config, &route); + _add_route (config, NULL, &route); } /* DNS */ @@ -594,10 +647,12 @@ nm_ip6_config_create_setting (const NMIP6Config *config) { NMSettingIPConfig *s_ip6; const struct in6_addr *gateway; - guint naddresses, nroutes, nnameservers, nsearches, noptions; + guint naddresses, nnameservers, nsearches, noptions; const char *method = NULL; int i; gint64 route_metric; + NMDedupMultiIter ipconf_iter; + const NMPlatformIP6Route *route; s_ip6 = NM_SETTING_IP_CONFIG (nm_setting_ip6_config_new ()); @@ -610,7 +665,6 @@ nm_ip6_config_create_setting (const NMIP6Config *config) gateway = nm_ip6_config_get_gateway (config); naddresses = nm_ip6_config_get_num_addresses (config); - nroutes = nm_ip6_config_get_num_routes (config); nnameservers = nm_ip6_config_get_num_nameservers (config); nsearches = nm_ip6_config_get_num_searches (config); noptions = nm_ip6_config_get_num_dns_options (config); @@ -661,8 +715,7 @@ nm_ip6_config_create_setting (const NMIP6Config *config) NULL); /* Routes */ - for (i = 0; i < nroutes; i++) { - const NMPlatformIP6Route *route = nm_ip6_config_get_route (config, i); + nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, config, &route) { NMIPRoute *s_route; /* Ignore link-local route. */ @@ -718,6 +771,7 @@ nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFl NMIP6ConfigPrivate *dst_priv; const NMIP6ConfigPrivate *src_priv; guint32 i; + NMDedupMultiIter ipconf_iter; g_return_if_fail (src != NULL); g_return_if_fail (dst != NULL); @@ -743,8 +797,10 @@ nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFl /* routes */ if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_ROUTES)) { - for (i = 0; i < nm_ip6_config_get_num_routes (src); i++) - nm_ip6_config_add_route (dst, nm_ip6_config_get_route (src, i)); + const NMPlatformIP6Route *route; + + nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, src, &route) + _add_route (dst, NMP_OBJECT_UP_CAST (route), NULL); } if (dst_priv->route_metric == -1) @@ -834,21 +890,6 @@ _nameservers_get_index (const NMIP6Config *self, const struct in6_addr *ns) } static int -_routes_get_index (const NMIP6Config *self, const NMPlatformIP6Route *route) -{ - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); - guint i; - - for (i = 0; i < priv->routes->len; i++) { - const NMPlatformIP6Route *r = &g_array_index (priv->routes, NMPlatformIP6Route, i); - - if (routes_are_duplicate (route, r, FALSE)) - return (int) i; - } - return -1; -} - -static int _domains_get_index (const NMIP6Config *self, const char *domain) { const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); @@ -905,13 +946,18 @@ _dns_options_get_index (const NMIP6Config *self, const char *option) void nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src) { + NMIP6ConfigPrivate *priv_dst; guint i; gint idx; + const NMPlatformIP6Route *r; + NMDedupMultiIter ipconf_iter; const struct in6_addr *dst_tmp, *src_tmp; g_return_if_fail (src != NULL); g_return_if_fail (dst != NULL); + priv_dst = NM_IP6_CONFIG_GET_PRIVATE (dst); + g_object_freeze_notify (G_OBJECT (dst)); /* addresses */ @@ -940,10 +986,10 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src) /* ignore route_metric */ /* routes */ - for (i = 0; i < nm_ip6_config_get_num_routes (src); i++) { - idx = _routes_get_index (dst, nm_ip6_config_get_route (src, i)); - if (idx >= 0) - nm_ip6_config_del_route (dst, idx); + nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, src, &r) { + nm_dedup_multi_index_remove_obj (priv_dst->multi_idx, + &priv_dst->idx_ip6_routes, + NMP_OBJECT_UP_CAST (r)); } /* domains */ @@ -980,12 +1026,19 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src) void nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src) { + NMIP6ConfigPrivate *priv_dst; + const NMIP6ConfigPrivate *priv_src; guint i; gint idx; const struct in6_addr *dst_tmp, *src_tmp; + NMDedupMultiIter ipconf_iter; + const NMPlatformIP6Route *r; - g_return_if_fail (src != NULL); - g_return_if_fail (dst != NULL); + g_return_if_fail (src); + g_return_if_fail (dst); + + priv_dst = NM_IP6_CONFIG_GET_PRIVATE (dst); + priv_src = NM_IP6_CONFIG_GET_PRIVATE (src); g_object_freeze_notify (G_OBJECT (dst)); @@ -1012,12 +1065,15 @@ nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src) } /* routes */ - for (i = 0; i < nm_ip6_config_get_num_routes (dst); ) { - idx = _routes_get_index (src, nm_ip6_config_get_route (dst, i)); - if (idx < 0) - nm_ip6_config_del_route (dst, i); - else - i++; + nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, dst, &r) { + if (nm_dedup_multi_index_lookup_obj (priv_src->multi_idx, + &priv_src->idx_ip6_routes, + NMP_OBJECT_UP_CAST (r))) + continue; + + if (nm_dedup_multi_index_remove_entry (priv_dst->multi_idx, + ipconf_iter.current) != 1) + nm_assert_not_reached (); } /* ignore domains */ @@ -1052,7 +1108,7 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev NMIP6ConfigPrivate *dst_priv; const NMIP6ConfigPrivate *src_priv; const NMPlatformIP6Address *dst_addr, *src_addr; - const NMPlatformIP6Route *dst_route, *src_route; + NMDedupMultiIter ipconf_iter_src, ipconf_iter_dst; g_return_val_if_fail (NM_IS_IP6_CONFIG (src), FALSE); g_return_val_if_fail (NM_IS_IP6_CONFIG (dst), FALSE); @@ -1117,26 +1173,45 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev } /* routes */ - num = nm_ip6_config_get_num_routes (src); - are_equal = num == nm_ip6_config_get_num_routes (dst); - if (are_equal) { - for (i = 0; i < num; i++ ) { - if (nm_platform_ip6_route_cmp (src_route = nm_ip6_config_get_route (src, i), - dst_route = nm_ip6_config_get_route (dst, i))) { - are_equal = FALSE; - if (!routes_are_duplicate (src_route, dst_route, TRUE)) { - has_relevant_changes = TRUE; - break; - } + nm_ip6_config_iter_ip6_route_init (&ipconf_iter_src, src); + nm_ip6_config_iter_ip6_route_init (&ipconf_iter_dst, dst); + are_equal = TRUE; + while (TRUE) { + gboolean has; + const NMPlatformIP6Route *r_src, *r_dst; + + has = nm_ip6_config_iter_ip6_route_next (&ipconf_iter_src, &r_src); + if (has != nm_ip6_config_iter_ip6_route_next (&ipconf_iter_dst, &r_dst)) { + are_equal = FALSE; + has_relevant_changes = TRUE; + break; + } + if (!has) + break; + + if (nm_platform_ip6_route_cmp (r_src, r_dst) != 0) { + are_equal = FALSE; + if (!nm_ip_config_obj_id_equal_ip6_route (r_src, r_dst)) { + has_relevant_changes = TRUE; + break; } } - } else - has_relevant_changes = TRUE; + } if (!are_equal) { - nm_ip6_config_reset_routes (dst); - for (i = 0; i < num; i++) - nm_ip6_config_add_route (dst, nm_ip6_config_get_route (src, i)); + const NMPlatformIP6Route *r_src; + has_minor_changes = TRUE; + nm_dedup_multi_index_dirty_set_idx (dst_priv->multi_idx, &dst_priv->idx_ip6_routes); + nm_dedup_multi_iter_rewind (&ipconf_iter_src); + while (nm_ip6_config_iter_ip6_route_next (&ipconf_iter_src, &r_src)) { + nm_dedup_multi_index_add (dst_priv->multi_idx, + &dst_priv->idx_ip6_routes, + NMP_OBJECT_UP_CAST (r_src), + NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE, + NULL, + NULL); + } + nm_dedup_multi_index_dirty_remove_idx (dst_priv->multi_idx, &dst_priv->idx_ip6_routes, FALSE); } /* nameservers */ @@ -1252,6 +1327,8 @@ nm_ip6_config_dump (const NMIP6Config *config, const char *detail) const struct in6_addr *tmp; guint32 i; const char *str; + NMDedupMultiIter ipconf_iter; + const NMPlatformIP6Route *route; g_return_if_fail (config != NULL); @@ -1277,8 +1354,8 @@ nm_ip6_config_dump (const NMIP6Config *config, const char *detail) } /* routes */ - for (i = 0; i < nm_ip6_config_get_num_routes (config); i++) - g_message (" rt: %s", nm_platform_ip6_route_to_string (nm_ip6_config_get_route (config, i), NULL, 0)); + nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, config, &route) + g_message (" rt: %s", nm_platform_ip6_route_to_string (route, NULL, 0)); /* domains */ for (i = 0; i < nm_ip6_config_get_num_domains (config); i++) @@ -1524,13 +1601,84 @@ nm_ip6_config_reset_routes (NMIP6Config *config) { NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); - if (priv->routes->len != 0) { - g_array_set_size (priv->routes, 0); + if (nm_dedup_multi_index_remove_idx (priv->multi_idx, + &priv->idx_ip6_routes) > 0) { _notify (config, PROP_ROUTE_DATA); _notify (config, PROP_ROUTES); } } +static void +_add_route (NMIP6Config *config, const NMPObject *o_new, const NMPlatformIP6Route *new) +{ + NMIP6ConfigPrivate *priv; + NMPObject o_new_storage; + nm_auto_nmpobj const NMPObject *obj_old = NULL; + + nm_assert (NM_IS_IP6_CONFIG (config)); + + priv = NM_IP6_CONFIG_GET_PRIVATE (config); + + nm_assert (priv->ifindex > 0); + + /* we go through extra lengths to accept a full o_new object. That one, + * can be reused by increasing the ref-count. */ + if (!o_new) { + nm_assert (new); + nm_assert (new->plen > 0 && new->plen <= 128); + nmp_object_stackinit (&o_new_storage, NMP_OBJECT_TYPE_IP6_ROUTE, + (const NMPlatformObject *) new); + o_new_storage.ip6_route.ifindex = priv->ifindex; + o_new = &o_new_storage; + } else { + nm_assert (!new); + nm_assert (NMP_OBJECT_GET_TYPE (o_new) == NMP_OBJECT_TYPE_IP6_ROUTE); + nm_assert (o_new->ip6_route.plen > 0 && o_new->ip6_route.plen <= 128); + if (o_new->ip6_route.ifindex != priv->ifindex) { + nmp_object_stackinit (&o_new_storage, NMP_OBJECT_TYPE_IP6_ROUTE, &o_new->object); + o_new_storage.ip6_route.ifindex = priv->ifindex; + o_new = &o_new_storage; + } + } + + if (!nm_dedup_multi_index_add (priv->multi_idx, + &priv->idx_ip6_routes, + o_new, + NM_DEDUP_MULTI_IDX_MODE_APPEND, + NULL, + &obj_old)) + return; + + if (obj_old) { + NMIPConfigSource old_source; + + old_source = obj_old->ip_route.rt_source; + /* we want to keep the maximum rt_source. But since we expect + * that usually we already add the maxiumum right away, we first try to + * add the new route (replacing the old one). Only if we later + * find out that rt_source is now lower, we fix it. + */ + if (o_new->ip_route.rt_source < old_source) { + if (o_new != &o_new_storage) { + nmp_object_stackinit (&o_new_storage, NMP_OBJECT_TYPE_IP6_ROUTE, + &o_new->object); + o_new = &o_new_storage; + } + o_new_storage.ip_route.rt_source = old_source; + if (!nm_dedup_multi_index_add (priv->multi_idx, + &priv->idx_ip6_routes, + o_new, + NM_DEDUP_MULTI_IDX_MODE_APPEND, + NULL, + NULL)) + nm_assert_not_reached (); + } + } + + _notify (config, PROP_ROUTE_DATA); + _notify (config, PROP_ROUTES); +} + /** * nm_ip6_config_add_route: * @config: the #NMIP6Config @@ -1544,76 +1692,70 @@ nm_ip6_config_reset_routes (NMIP6Config *config) void nm_ip6_config_add_route (NMIP6Config *config, const NMPlatformIP6Route *new) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); - NMIPConfigSource old_source; - int i; - - g_return_if_fail (new != NULL); + g_return_if_fail (config); + g_return_if_fail (new); g_return_if_fail (new->plen > 0 && new->plen <= 128); - g_return_if_fail (priv->ifindex > 0); + g_return_if_fail (NM_IP6_CONFIG_GET_PRIVATE (config)->ifindex > 0); - for (i = 0; i < priv->routes->len; i++ ) { - NMPlatformIP6Route *item = &g_array_index (priv->routes, NMPlatformIP6Route, i); - - if (routes_are_duplicate (item, new, FALSE)) { - if (nm_platform_ip6_route_cmp (item, new) == 0) - return; - old_source = item->rt_source; - *item = *new; - /* Restore highest priority source */ - item->rt_source = MAX (old_source, new->rt_source); - item->ifindex = priv->ifindex; - goto NOTIFY; - } - } - - g_array_append_val (priv->routes, *new); - g_array_index (priv->routes, NMPlatformIP6Route, priv->routes->len - 1).ifindex = priv->ifindex; -NOTIFY: - _notify (config, PROP_ROUTE_DATA); - _notify (config, PROP_ROUTES); + _add_route (config, NULL, new); } void -nm_ip6_config_del_route (NMIP6Config *config, guint i) +_nmtst_ip6_config_del_route (NMIP6Config *self, guint i) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); + const NMPlatformIP6Route *r; - g_return_if_fail (i < priv->routes->len); + r = _nmtst_ip6_config_get_route (self, i); + g_return_if_fail (r); - g_array_remove_index (priv->routes, i); - _notify (config, PROP_ROUTE_DATA); - _notify (config, PROP_ROUTES); + if (nm_dedup_multi_index_remove_obj (priv->multi_idx, + &priv->idx_ip6_routes, + NMP_OBJECT_UP_CAST (r)) != 1) + g_return_if_reached (); + _notify (self, PROP_ROUTE_DATA); + _notify (self, PROP_ROUTES); } guint -nm_ip6_config_get_num_routes (const NMIP6Config *config) +nm_ip6_config_get_num_routes (const NMIP6Config *self) { - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + const NMDedupMultiHeadEntry *head_entry; - return priv->routes->len; + head_entry = _idx_ip6_routes (self); + nm_assert ((head_entry ? head_entry->len : 0) == c_list_length (&head_entry->lst_entries_head)); + return head_entry ? head_entry->len : 0; } const NMPlatformIP6Route * -nm_ip6_config_get_route (const NMIP6Config *config, guint i) -{ - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); - - return &g_array_index (priv->routes, NMPlatformIP6Route, i); +_nmtst_ip6_config_get_route (const NMIP6Config *self, guint i) +{ + const NMDedupMultiHeadEntry *head_entry; + CList *iter; + guint j; + + head_entry = _idx_ip6_routes (self); + if (head_entry) { + j = 0; + c_list_for_each (iter, &head_entry->lst_entries_head) { + if (i == j) + return _entry_iter_get_ip6_route (iter); + j++; + } + } + g_return_val_if_reached (NULL); } const NMPlatformIP6Route * -nm_ip6_config_get_direct_route_for_host (const NMIP6Config *config, const struct in6_addr *host) +nm_ip6_config_get_direct_route_for_host (const NMIP6Config *self, const struct in6_addr *host) { - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); - guint i; - NMPlatformIP6Route *best_route = NULL; + const NMPlatformIP6Route *best_route = NULL; + const NMPlatformIP6Route *item; + NMDedupMultiIter ipconf_iter; g_return_val_if_fail (host && !IN6_IS_ADDR_UNSPECIFIED (host), NULL); - for (i = 0; i < priv->routes->len; i++) { - NMPlatformIP6Route *item = &g_array_index (priv->routes, NMPlatformIP6Route, i); - + nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, self, &item) { if (!IN6_IS_ADDR_UNSPECIFIED (&item->gateway)) continue; @@ -1629,7 +1771,6 @@ nm_ip6_config_get_direct_route_for_host (const NMIP6Config *config, const struct best_route = item; } - return best_route; } @@ -1963,6 +2104,8 @@ nm_ip6_config_hash (const NMIP6Config *config, GChecksum *sum, gboolean dns_only { guint32 i; const char *s; + NMDedupMultiIter ipconf_iter; + const NMPlatformIP6Route *route; g_return_if_fail (config); g_return_if_fail (sum); @@ -1977,9 +2120,7 @@ nm_ip6_config_hash (const NMIP6Config *config, GChecksum *sum, gboolean dns_only hash_u32 (sum, address->plen); } - for (i = 0; i < nm_ip6_config_get_num_routes (config); i++) { - const NMPlatformIP6Route *route = nm_ip6_config_get_route (config, i); - + nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, config, &route) { hash_in6addr (sum, &route->network); hash_u32 (sum, route->plen); hash_in6addr (sum, &route->gateway); @@ -2074,6 +2215,9 @@ get_property (GObject *object, guint prop_id, { NMIP6Config *config = NM_IP6_CONFIG (object); NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMDedupMultiIter ipconf_iter; + const NMPlatformIP6Route *route; + GVariantBuilder array_builder, addr_builder, route_builder; switch (prop_id) { case PROP_IFINDEX: @@ -2082,7 +2226,6 @@ get_property (GObject *object, guint prop_id, case PROP_ADDRESS_DATA: case PROP_ADDRESSES: { - GVariantBuilder array_builder, addr_builder; gs_unref_array GArray *new = NULL; const struct in6_addr *gateway; guint naddr, i; @@ -2144,14 +2287,8 @@ return_cached: break; case PROP_ROUTE_DATA: { - GVariantBuilder array_builder, route_builder; - guint nroutes = nm_ip6_config_get_num_routes (config); - int i; - g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}")); - for (i = 0; i < nroutes; i++) { - const NMPlatformIP6Route *route = nm_ip6_config_get_route (config, i); - + nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, config, &route) { g_variant_builder_init (&route_builder, G_VARIANT_TYPE ("a{sv}")); g_variant_builder_add (&route_builder, "{sv}", "dest", @@ -2177,14 +2314,8 @@ return_cached: break; case PROP_ROUTES: { - GVariantBuilder array_builder; - int nroutes = nm_ip6_config_get_num_routes (config); - int i; - g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a(ayuayu)")); - for (i = 0; i < nroutes; i++) { - const NMPlatformIP6Route *route = nm_ip6_config_get_route (config, i); - + nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, config, &route) { /* legacy versions of nm_ip6_route_set_prefix() in libnm-util assert that the * plen is positive. Skip the default routes not to break older clients. */ if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) @@ -2263,8 +2394,10 @@ nm_ip6_config_init (NMIP6Config *config) { NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + nm_ip_config_dedup_multi_idx_type_init ((NMIPConfigDedupMultiIdxType *) &priv->idx_ip6_routes, + NMP_OBJECT_TYPE_IP6_ROUTE); + priv->addresses = g_array_new (FALSE, TRUE, sizeof (NMPlatformIP6Address)); - priv->routes = g_array_new (FALSE, TRUE, sizeof (NMPlatformIP6Route)); priv->nameservers = g_array_new (FALSE, TRUE, sizeof (struct in6_addr)); priv->domains = g_ptr_array_new_with_free_func (g_free); priv->searches = g_ptr_array_new_with_free_func (g_free); @@ -2301,8 +2434,9 @@ finalize (GObject *object) NMIP6Config *self = NM_IP6_CONFIG (object); NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); + nm_dedup_multi_index_remove_idx (priv->multi_idx, &priv->idx_ip6_routes); + g_array_unref (priv->addresses); - g_array_unref (priv->routes); g_array_unref (priv->nameservers); g_ptr_array_unref (priv->domains); g_ptr_array_unref (priv->searches); diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index 5dadf796f6..a390ff1c23 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -26,6 +26,20 @@ #include "nm-exported-object.h" #include "nm-setting-ip6-config.h" +#include "nm-utils/nm-dedup-multi.h" + +/*****************************************************************************/ + +void nm_ip6_config_iter_ip6_route_init (NMDedupMultiIter *iter, const NMIP6Config *self); +gboolean nm_ip6_config_iter_ip6_route_next (NMDedupMultiIter *iter, const NMPlatformIP6Route **out_route); + +#define nm_ip6_config_iter_ip6_route_for_each(iter, self, route) \ + for (nm_ip6_config_iter_ip6_route_init ((iter), (self)); \ + nm_ip6_config_iter_ip6_route_next ((iter), (route)); \ + ) + +/*****************************************************************************/ + #define NM_TYPE_IP6_CONFIG (nm_ip6_config_get_type ()) #define NM_IP6_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_IP6_CONFIG, NMIP6Config)) #define NM_IP6_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_IP6_CONFIG, NMIP6ConfigClass)) @@ -101,9 +115,9 @@ gboolean nm_ip6_config_has_any_dad_pending (const NMIP6Config *self, void nm_ip6_config_reset_routes (NMIP6Config *config); void nm_ip6_config_add_route (NMIP6Config *config, const NMPlatformIP6Route *route); -void nm_ip6_config_del_route (NMIP6Config *config, guint i); +void _nmtst_ip6_config_del_route (NMIP6Config *config, guint i); guint nm_ip6_config_get_num_routes (const NMIP6Config *config); -const NMPlatformIP6Route *nm_ip6_config_get_route (const NMIP6Config *config, guint i); +const NMPlatformIP6Route *_nmtst_ip6_config_get_route (const NMIP6Config *config, guint i); const NMPlatformIP6Route *nm_ip6_config_get_direct_route_for_host (const NMIP6Config *config, const struct in6_addr *host); const NMPlatformIP6Address *nm_ip6_config_get_subnet_for_host (const NMIP6Config *config, const struct in6_addr *host); diff --git a/src/nm-pacrunner-manager.c b/src/nm-pacrunner-manager.c index a4c345e5d7..d9095cce5b 100644 --- a/src/nm-pacrunner-manager.c +++ b/src/nm-pacrunner-manager.c @@ -202,8 +202,10 @@ get_ip4_domains (GPtrArray *domains, NMIP4Config *ip4) static void get_ip6_domains (GPtrArray *domains, NMIP6Config *ip6) { + NMDedupMultiIter ipconf_iter; char *cidr; - int i; + const NMPlatformIP6Route *routes; + guint i; /* Extract searches */ for (i = 0; i < nm_ip6_config_get_num_searches (ip6); i++) @@ -223,9 +225,7 @@ get_ip6_domains (GPtrArray *domains, NMIP6Config *ip6) g_ptr_array_add (domains, cidr); } - for (i = 0; i < nm_ip6_config_get_num_routes (ip6); i++) { - const NMPlatformIP6Route *routes = nm_ip6_config_get_route (ip6, i); - + nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &routes) { cidr = g_strdup_printf ("%s/%u", nm_utils_inet6_ntop (&routes->network, NULL), routes->plen); diff --git a/src/tests/test-ip6-config.c b/src/tests/test-ip6-config.c index bbb3278bc9..0887e9da98 100644 --- a/src/tests/test-ip6-config.c +++ b/src/tests/test-ip6-config.c @@ -98,7 +98,7 @@ test_subtract (void) g_assert (nm_ip6_config_get_gateway (dst) == NULL); g_assert_cmpuint (nm_ip6_config_get_num_routes (dst), ==, 1); - test_route = nm_ip6_config_get_route (dst, 0); + test_route = _nmtst_ip6_config_get_route (dst, 0); g_assert (test_route != NULL); tmp = *nmtst_inet6_from_string (expected_route_dest); @@ -207,27 +207,27 @@ test_add_route_with_source (void) route.rt_source = NM_IP_CONFIG_SOURCE_USER; nm_ip6_config_add_route (a, &route); - test_route = nm_ip6_config_get_route (a, 0); + test_route = _nmtst_ip6_config_get_route (a, 0); g_assert_cmpint (test_route->rt_source, ==, NM_IP_CONFIG_SOURCE_USER); route.rt_source = NM_IP_CONFIG_SOURCE_VPN; nm_ip6_config_add_route (a, &route); - test_route = nm_ip6_config_get_route (a, 0); + test_route = _nmtst_ip6_config_get_route (a, 0); g_assert_cmpint (test_route->rt_source, ==, NM_IP_CONFIG_SOURCE_USER); /* Test that a lower priority address source is overwritten */ - nm_ip6_config_del_route (a, 0); + _nmtst_ip6_config_del_route (a, 0); route.rt_source = NM_IP_CONFIG_SOURCE_KERNEL; nm_ip6_config_add_route (a, &route); - test_route = nm_ip6_config_get_route (a, 0); + test_route = _nmtst_ip6_config_get_route (a, 0); g_assert_cmpint (test_route->rt_source, ==, NM_IP_CONFIG_SOURCE_KERNEL); route.rt_source = NM_IP_CONFIG_SOURCE_USER; nm_ip6_config_add_route (a, &route); - test_route = nm_ip6_config_get_route (a, 0); + test_route = _nmtst_ip6_config_get_route (a, 0); g_assert_cmpint (test_route->rt_source, ==, NM_IP_CONFIG_SOURCE_USER); g_object_unref (a); diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c index 7c8f06ced6..ab6103d497 100644 --- a/src/vpn/nm-vpn-connection.c +++ b/src/vpn/nm-vpn-connection.c @@ -992,6 +992,8 @@ print_vpn_config (NMVpnConnection *self) _LOGI ("Data: No IPv4 configuration"); if (priv->ip6_config) { + const NMPlatformIP6Route *route; + _LOGI ("Data: IPv6 configuration:"); address6 = nm_ip6_config_get_address (priv->ip6_config, 0); @@ -1003,10 +1005,7 @@ print_vpn_config (NMVpnConnection *self) _LOGI ("Data: Internal Point-to-Point Address: %s", nm_utils_inet6_ntop (&address6->peer_address, NULL)); _LOGI ("Data: Maximum Segment Size (MSS): %d", nm_ip6_config_get_mss (priv->ip6_config)); - num = nm_ip6_config_get_num_routes (priv->ip6_config); - for (i = 0; i < num; i++) { - const NMPlatformIP6Route *route = nm_ip6_config_get_route (priv->ip6_config, i); - + nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, priv->ip6_config, &route) { _LOGI ("Data: Static Route: %s/%d Next Hop: %s", nm_utils_inet6_ntop (&route->network, NULL), route->plen, @@ -1578,7 +1577,6 @@ nm_vpn_connection_ip6_config_get (NMVpnConnection *self, GVariant *dict) const char *str; GVariant *v; gboolean b; - guint i, n; int ip_ifindex; g_return_if_fail (dict && g_variant_is_of_type (dict, G_VARIANT_TYPE_VARDICT)); @@ -1669,9 +1667,11 @@ nm_vpn_connection_ip6_config_get (NMVpnConnection *self, GVariant *dict) if ( g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_PRESERVE_ROUTES, "b", &b) && b) { if (priv->ip6_config) { - n = nm_ip6_config_get_num_routes (priv->ip6_config); - for (i = 0; i < n; i++) - nm_ip6_config_add_route (config, nm_ip6_config_get_route (priv->ip6_config, i)); + NMDedupMultiIter ipconf_iter; + const NMPlatformIP6Route *route; + + nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, priv->ip6_config, &route) + nm_ip6_config_add_route (config, route); } } else if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_ROUTES, "a(ayuayu)", &iter)) { GVariant *dest, *next_hop; |