From 667c50f5d920e91d798d51c61e63e3ce87e277d3 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 29 Jun 2017 15:19:35 +0200 Subject: core: avoid cloning platform routes but iterate the cache directly --- src/devices/nm-device.c | 68 ++++++++++++++-------------- src/nm-default-route-manager.c | 93 ++++++++++++++++++++++----------------- src/nm-ip4-config.c | 61 +++++++++++++------------ src/nm-route-manager.c | 58 ++++++++++++++++++++---- src/nm-test-utils-core.h | 38 ++++++++++++++++ src/platform/nm-platform.c | 72 +++++++++++++++++++++++++----- src/platform/nm-platform.h | 11 ++++- src/platform/nmp-object.h | 33 ++++++++++++++ src/platform/tests/test-cleanup.c | 22 +++++---- src/platform/tests/test-common.h | 27 ++++++++++++ src/platform/tests/test-route.c | 28 +++++------- src/tests/test-route-manager.c | 41 +++++++++++++---- 12 files changed, 392 insertions(+), 160 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index dd9c96cf91..db59171b02 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -42,6 +42,7 @@ #include "NetworkManagerUtils.h" #include "nm-manager.h" #include "platform/nm-platform.h" +#include "platform/nmp-object.h" #include "ndisc/nm-ndisc.h" #include "ndisc/nm-lndp-ndisc.h" #include "dhcp/nm-dhcp-manager.h" @@ -5405,45 +5406,46 @@ ipv4ll_start (NMDevice *self) static gboolean _device_get_default_route_from_platform (NMDevice *self, int addr_family, NMPlatformIPRoute *out_route) { - gboolean success = FALSE; int ifindex = nm_device_get_ip_ifindex (self); - GArray *routes; - - if (addr_family == AF_INET) - routes = nm_platform_ip4_route_get_all (nm_device_get_platform (self), ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT); - else - routes = nm_platform_ip6_route_get_all (nm_device_get_platform (self), ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT); - - if (routes) { - guint route_metric = G_MAXUINT32, m; - const NMPlatformIPRoute *route = NULL, *r; - guint i; + const NMDedupMultiHeadEntry *pl_head_entry; + NMDedupMultiIter iter; + const NMPObject *plobj = NULL; + const NMPlatformIPRoute *route = NULL; + guint32 route_metric = G_MAXUINT32; + + pl_head_entry = nm_platform_lookup_route_visible (nm_device_get_platform (self), + addr_family == AF_INET + ? NMP_OBJECT_TYPE_IP4_ROUTE + : NMP_OBJECT_TYPE_IP6_ROUTE, + ifindex, + TRUE, + FALSE); + nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) { + guint32 m; + const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE (plobj); + + if (r->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) + continue; /* if there are several default routes, find the one with the best metric */ - for (i = 0; i < routes->len; i++) { - if (addr_family == AF_INET) { - r = (const NMPlatformIPRoute *) &g_array_index (routes, NMPlatformIP4Route, i); - m = r->metric; - } else { - r = (const NMPlatformIPRoute *) &g_array_index (routes, NMPlatformIP6Route, i); - m = nm_utils_ip6_route_metric_normalize (r->metric); - } - if (!route || m < route_metric) { - route = r; - route_metric = m; - } - } + m = r->metric; + if (addr_family != AF_INET) + m = nm_utils_ip6_route_metric_normalize (r->metric); - if (route) { - if (addr_family == AF_INET) - *((NMPlatformIP4Route *) out_route) = *((NMPlatformIP4Route *) route); - else - *((NMPlatformIP6Route *) out_route) = *((NMPlatformIP6Route *) route); - success = TRUE; + if (!route || m < route_metric) { + route = NMP_OBJECT_CAST_IP_ROUTE (plobj); + route_metric = m; } - g_array_free (routes, TRUE); } - return success; + + if (route) { + if (addr_family == AF_INET) + *((NMPlatformIP4Route *) out_route) = *((NMPlatformIP4Route *) route); + else + *((NMPlatformIP6Route *) out_route) = *((NMPlatformIP6Route *) route); + return TRUE; + } + return FALSE; } /*****************************************************************************/ diff --git a/src/nm-default-route-manager.c b/src/nm-default-route-manager.c index 609c1658ef..fb61ef751c 100644 --- a/src/nm-default-route-manager.c +++ b/src/nm-default-route-manager.c @@ -28,6 +28,7 @@ #include "devices/nm-device.h" #include "vpn/nm-vpn-connection.h" #include "platform/nm-platform.h" +#include "platform/nmp-object.h" #include "nm-manager.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" @@ -195,26 +196,20 @@ typedef struct { static const VTableIP vtable_ip4, vtable_ip6; -static NMPlatformIPRoute * -_vt_route_index (const VTableIP *vtable, GArray *routes, guint index) -{ - if (vtable->vt->is_ip4) - return (NMPlatformIPRoute *) &g_array_index (routes, NMPlatformIP4Route, index); - else - return (NMPlatformIPRoute *) &g_array_index (routes, NMPlatformIP6Route, index); -} - static gboolean -_vt_routes_has_entry (const VTableIP *vtable, GArray *routes, const Entry *entry) +_vt_routes_has_entry (const VTableIP *vtable, const GPtrArray *routes, const Entry *entry) { guint i; NMPlatformIPXRoute route = entry->route; + if (!routes) + return FALSE; + route.rx.metric = entry->effective_metric; if (vtable->vt->is_ip4) { for (i = 0; i < routes->len; i++) { - NMPlatformIP4Route *r = &g_array_index (routes, NMPlatformIP4Route, i); + const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE ((NMPObject *) routes->pdata[i]); route.rx.rt_source = r->rt_source; if (nm_platform_ip4_route_cmp (r, &route.r4) == 0) @@ -222,7 +217,7 @@ _vt_routes_has_entry (const VTableIP *vtable, GArray *routes, const Entry *entry } } else { for (i = 0; i < routes->len; i++) { - NMPlatformIP6Route *r = &g_array_index (routes, NMPlatformIP6Route, i); + const NMPlatformIP6Route *r = NMP_OBJECT_CAST_IP6_ROUTE ((NMPObject *) routes->pdata[i]); route.rx.rt_source = r->rt_source; if (nm_platform_ip6_route_cmp (r, &route.r6) == 0) @@ -331,19 +326,28 @@ _platform_route_sync_flush (const VTableIP *vtable, NMDefaultRouteManager *self, { NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self); GPtrArray *entries = vtable->get_entries (priv); - GArray *routes; + gs_unref_ptrarray GPtrArray *routes = NULL; guint i, j; gboolean changed = FALSE; /* prune all other default routes from this device. */ - routes = vtable->vt->route_get_all (priv->platform, 0, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT); + + routes = nm_platform_lookup_route_visible_clone (priv->platform, + vtable->vt->obj_type, + 0, + TRUE, + FALSE, + nm_platform_lookup_predicate_routes_skip_rtprot_kernel, + NULL); + if (!routes) + return FALSE; for (i = 0; i < routes->len; i++) { const NMPlatformIPRoute *route; gboolean has_ifindex_synced = FALSE; Entry *entry = NULL; - route = _vt_route_index (vtable, routes, i); + route = NMP_OBJECT_CAST_IP_ROUTE ((NMPObject *) routes->pdata[i]); /* look at all entries and see if the route for this ifindex pair is * a known entry. */ @@ -372,7 +376,6 @@ _platform_route_sync_flush (const VTableIP *vtable, NMDefaultRouteManager *self, changed = TRUE; } } - g_array_free (routes, TRUE); return changed; } @@ -419,7 +422,7 @@ _sort_entries_cmp (gconstpointer a, gconstpointer b, gpointer user_data) } static GHashTable * -_get_assumed_interface_metrics (const VTableIP *vtable, NMDefaultRouteManager *self, GArray *routes) +_get_assumed_interface_metrics (const VTableIP *vtable, NMDefaultRouteManager *self, const GPtrArray *routes) { NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self); GPtrArray *entries; @@ -435,24 +438,26 @@ _get_assumed_interface_metrics (const VTableIP *vtable, NMDefaultRouteManager *s result = g_hash_table_new (NULL, NULL); - for (i = 0; i < routes->len; i++) { - gboolean ifindex_has_synced_entry = FALSE; - const NMPlatformIPRoute *route; + if (routes) { + for (i = 0; i < routes->len; i++) { + gboolean ifindex_has_synced_entry = FALSE; + const NMPlatformIPRoute *route; - route = _vt_route_index (vtable, routes, i); + route = NMP_OBJECT_CAST_IP_ROUTE ((NMPObject *) routes->pdata[i]); - for (j = 0; j < entries->len; j++) { - Entry *e = g_ptr_array_index (entries, j); + for (j = 0; j < entries->len; j++) { + Entry *e = g_ptr_array_index (entries, j); - if ( e->synced - && e->route.rx.ifindex == route->ifindex) { - ifindex_has_synced_entry = TRUE; - break; + if ( e->synced + && e->route.rx.ifindex == route->ifindex) { + ifindex_has_synced_entry = TRUE; + break; + } } - } - if (!ifindex_has_synced_entry) - g_hash_table_add (result, GUINT_TO_POINTER (vtable->vt->metric_normalize (route->metric))); + if (!ifindex_has_synced_entry) + g_hash_table_add (result, GUINT_TO_POINTER (vtable->vt->metric_normalize (route->metric))); + } } /* also add all non-synced metrics from our entries list. We might have there some metrics that @@ -493,7 +498,7 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c GPtrArray *entries; GArray *changed_metrics = g_array_new (FALSE, FALSE, sizeof (guint32)); GHashTable *assumed_metrics; - GArray *routes; + gs_unref_ptrarray GPtrArray *routes = NULL; gboolean changed = FALSE; int ifindex_to_flush = 0; @@ -511,7 +516,13 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c entries = vtable->get_entries (priv); - routes = vtable->vt->route_get_all (priv->platform, 0, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT); + routes = nm_platform_lookup_route_visible_clone (priv->platform, + vtable->vt->obj_type, + 0, + TRUE, + FALSE, + nm_platform_lookup_predicate_routes_skip_rtprot_kernel, + NULL); assumed_metrics = _get_assumed_interface_metrics (vtable, self, routes); @@ -560,13 +571,15 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c * If there are any, we have to pick another effective_metric. */ /* However, if there is a matching route (ifindex+metric) for our current entry, we are done. */ - for (j = 0; j < routes->len; j++) { - const NMPlatformIPRoute *r = _vt_route_index (vtable, routes, i); - - if ( r->metric == expected_metric - && r->ifindex == entry->route.rx.ifindex) { - has_metric_for_ifindex = TRUE; - break; + if (routes) { + for (j = 0; j < routes->len; j++) { + const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE ((NMPObject *) routes->pdata[i]); + + if ( r->metric == expected_metric + && r->ifindex == entry->route.rx.ifindex) { + has_metric_for_ifindex = TRUE; + break; + } } } if (has_metric_for_ifindex) @@ -611,8 +624,6 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c last_metric = expected_metric; } - g_array_free (routes, TRUE); - g_array_sort_with_data (changed_metrics, nm_cmp_uint32_p_with_data, NULL); last_metric = -1; for (j = 0; j < changed_metrics->len; j++) { diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 1f0d86d30e..50000e6275 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -386,11 +386,12 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i { NMIP4Config *config; NMIP4ConfigPrivate *priv; - guint i; - guint32 lowest_metric = G_MAXUINT32; + guint32 lowest_metric; guint32 old_gateway = 0; gboolean old_has_gateway = FALSE; - gs_unref_array GArray *routes = NULL; + const NMDedupMultiHeadEntry *pl_head_entry; + NMDedupMultiIter iter; + const NMPObject *plobj = NULL; /* Slaves have no IP configuration */ if (nm_platform_link_get_master (platform, ifindex) > 0) @@ -404,50 +405,56 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i priv->addresses = nm_platform_ip4_address_get_all (platform, ifindex); g_array_sort (priv->addresses, sort_captured_addresses); - routes = nm_platform_ip4_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_IP4_ROUTE, + ifindex, + TRUE, + TRUE); /* Extract gateway from default route */ old_gateway = priv->gateway; old_has_gateway = priv->has_gateway; - for (i = 0; i < routes->len; ) { - const NMPlatformIP4Route *route = &g_array_index (routes, NMPlatformIP4Route, i); - if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) { + lowest_metric = G_MAXUINT32; + priv->has_gateway = FALSE; + nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) { + const NMPlatformIP4Route *route = NMP_OBJECT_CAST_IP4_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; } priv->has_gateway = TRUE; - /* Remove the default route from the list */ - g_array_remove_index_fast (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 = priv->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 (priv->has_gateway) { - for (i = 0; i < routes->len; i++) { - const NMPlatformIP4Route *route = &g_array_index (routes, NMPlatformIP4Route, i); - - if ( (route->plen == 32) - && (route->network == priv->gateway) - && (route->gateway == 0)) { - g_array_remove_index (routes, i); - i--; - } + nm_dedup_multi_iter_rewind (&iter); + nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) { + const NMPlatformIP4Route *route = NMP_OBJECT_CAST_IP4_ROUTE (plobj); + + if (route->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) + continue; + if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) + continue; + + if ( priv->has_gateway + && route->plen == 32 + && route->network == priv->gateway + && route->gateway == 0) { + /* 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); } - for (i = 0; i < routes->len; i++) - _add_route (config, NULL, &g_array_index (routes, NMPlatformIP4Route, i)); - /* If the interface has the default route, and has IPv4 addresses, capture * nameservers from /etc/resolv.conf. */ diff --git a/src/nm-route-manager.c b/src/nm-route-manager.c index 6c1f78ac96..574493d990 100644 --- a/src/nm-route-manager.c +++ b/src/nm-route-manager.c @@ -306,6 +306,50 @@ _route_index_create (const VTableIP *vtable, const GArray *routes) return index; } +static RouteIndex * +_route_index_create_from_platform (const VTableIP *vtable, + NMPlatform *platform, + int ifindex, + gboolean ignore_kernel_routes, + GPtrArray **out_storage) +{ + RouteIndex *index; + guint i, len; + GPtrArray *storage; + + nm_assert (out_storage && !*out_storage); + + storage = nm_platform_lookup_route_visible_clone (platform, + vtable->vt->obj_type, + ifindex, + FALSE, + TRUE, + NULL, + NULL); + if (!storage) + return _route_index_create (vtable, NULL); + + len = storage->len; + index = g_malloc (sizeof (RouteIndex) + len * sizeof (NMPlatformIPXRoute *)); + + index->len = len; + for (i = 0; i < len; i++) { + /* we cast away the const-ness of the NMPObjects. The caller must + * ensure not to modify the object via index->entries. */ + index->entries[i] = NMP_OBJECT_CAST_IPX_ROUTE ((NMPObject *) storage->pdata[i]); + } + index->entries[i] = NULL; + + /* this is a stable sort, which is very important at this point. */ + g_qsort_with_data (index->entries, + len, + sizeof (NMPlatformIPXRoute *), + (GCompareDataFunc) _route_index_create_sort, + (gpointer) vtable); + *out_storage = storage; + return index; +} + static int _vx_route_id_cmp_full (const NMPlatformIPXRoute *r1, const NMPlatformIPXRoute *r2, const VTableIP *vtable) { @@ -458,7 +502,7 @@ static gboolean _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes, gboolean full_sync) { NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (self); - GArray *plat_routes; + gs_unref_ptrarray GPtrArray *plat_routes = NULL; RouteEntries *ipx_routes; RouteIndex *plat_routes_idx, *known_routes_idx; gboolean success = TRUE; @@ -475,16 +519,15 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const nm_platform_process_events (priv->platform); ipx_routes = vtable->vt->is_ip4 ? &priv->ip4_routes : &priv->ip6_routes; - plat_routes = vtable->vt->route_get_all (priv->platform, ifindex, - ignore_kernel_routes - ? NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT - : NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_RTPROT_KERNEL); - plat_routes_idx = _route_index_create (vtable, plat_routes); + + /* the objects referenced by play_routes_idx are shared from the platform cache. They + * must not be modified. */ + plat_routes_idx = _route_index_create_from_platform (vtable, priv->platform, ifindex, ignore_kernel_routes, &plat_routes); + known_routes_idx = _route_index_create (vtable, known_routes); effective_metrics = &g_array_index (ipx_routes->effective_metrics, gint64, 0); - ASSERT_route_index_valid (vtable, plat_routes, plat_routes_idx, TRUE); ASSERT_route_index_valid (vtable, known_routes, known_routes_idx, FALSE); _LOGD (vtable->vt->addr_family, "%3d: sync %u IPv%c routes", ifindex, known_routes_idx->len, vtable->vt->is_ip4 ? '4' : '6'); @@ -918,7 +961,6 @@ next: g_free (known_routes_idx); g_free (plat_routes_idx); - g_array_unref (plat_routes); return success; } diff --git a/src/nm-test-utils-core.h b/src/nm-test-utils-core.h index 8ee7205de8..879e9190af 100644 --- a/src/nm-test-utils-core.h +++ b/src/nm-test-utils-core.h @@ -226,6 +226,25 @@ nmtst_platform_ip4_routes_equal (const NMPlatformIP4Route *a, const NMPlatformIP } } +#ifdef __NMP_OBJECT_H__ + +static inline void +nmtst_platform_ip4_routes_equal_aptr (const NMPObject *const*a, const NMPlatformIP4Route *b, gsize len, gboolean ignore_order) +{ + gsize i; + gs_free NMPlatformIP4Route *c_a = NULL; + + g_assert (len > 0); + g_assert (a); + + c_a = g_new (NMPlatformIP4Route, len); + for (i = 0; i < len; i++) + c_a[i] = *NMP_OBJECT_CAST_IP4_ROUTE (a[i]); + nmtst_platform_ip4_routes_equal (c_a, b, len, ignore_order); +} + +#endif + static inline int _nmtst_platform_ip6_routes_equal_sort (gconstpointer a, gconstpointer b, gpointer user_data) { @@ -260,6 +279,25 @@ nmtst_platform_ip6_routes_equal (const NMPlatformIP6Route *a, const NMPlatformIP } } +#ifdef __NMP_OBJECT_H__ + +static inline void +nmtst_platform_ip6_routes_equal_aptr (const NMPObject *const*a, const NMPlatformIP6Route *b, gsize len, gboolean ignore_order) +{ + gsize i; + gs_free NMPlatformIP6Route *c_a = NULL; + + g_assert (len > 0); + g_assert (a); + + c_a = g_new (NMPlatformIP6Route, len); + for (i = 0; i < len; i++) + c_a[i] = *NMP_OBJECT_CAST_IP6_ROUTE (a[i]); + nmtst_platform_ip6_routes_equal (c_a, b, len, ignore_order); +} + +#endif + #endif diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index d529cdd713..c8008216b2 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -2659,6 +2659,64 @@ nm_platform_lookup (NMPlatform *platform, lookup); } +gboolean +nm_platform_lookup_predicate_routes_skip_rtprot_kernel (const NMPObject *obj, + gpointer user_data) +{ + nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE, + NMP_OBJECT_TYPE_IP6_ROUTE)); + return obj->ip_route.rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL; +} + +/** + * nm_platform_lookup_clone: + * @platform: + * @lookup: + * @predicate: if given, only objects for which @predicate returns %TRUE are included + * in the result. + * @user_data: user data for @predicate + * + * Returns the result of lookup in a GPtrArray. The result array contains + * references objects from the cache, it's destroy function will unref them. + * + * The user must unref the GPtrArray, which will also unref the NMPObject + * elements. + * + * The elements in the array *must* not be modified. + * + * Returns: the result of the lookup. + */ +GPtrArray * +nm_platform_lookup_clone (NMPlatform *platform, + const NMPLookup *lookup, + gboolean (*predicate) (const NMPObject *obj, gpointer user_data), + gpointer user_data) +{ + const NMDedupMultiHeadEntry *head_entry; + GPtrArray *result; + NMDedupMultiIter iter; + const NMPObject *plobj = NULL; + + head_entry = nm_platform_lookup (platform, lookup); + if (!head_entry) + return NULL; + + result = g_ptr_array_new_full (head_entry->len, + (GDestroyNotify) nmp_object_unref); + nmp_cache_iter_for_each (&iter, head_entry, &plobj) { + if ( predicate + && !predicate (plobj, user_data)) + continue; + g_ptr_array_add (result, (gpointer) nmp_object_ref (plobj)); + } + + if (result->len == 0) { + g_ptr_array_unref (result); + return NULL; + } + return result; +} + void nm_platform_ip4_address_set_addr (NMPlatformIP4Address *addr, in_addr_t address, guint8 plen) { @@ -3200,16 +3258,6 @@ ipx_route_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type, NM return array; } -GArray * -nm_platform_ip4_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags) -{ - _CHECK_SELF (self, klass, NULL); - - g_return_val_if_fail (ifindex >= 0, NULL); - - return ipx_route_get_all (self, ifindex, NMP_OBJECT_TYPE_IP4_ROUTE, flags); -} - GArray * nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags) { @@ -5026,11 +5074,11 @@ _vtr_v6_route_delete_default (NMPlatform *self, int ifindex, guint32 metric) const NMPlatformVTableRoute nm_platform_vtable_route_v4 = { .is_ip4 = TRUE, + .obj_type = NMP_OBJECT_TYPE_IP4_ROUTE, .addr_family = AF_INET, .sizeof_route = sizeof (NMPlatformIP4Route), .route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, gboolean consider_host_part)) nm_platform_ip4_route_cmp_full, .route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip4_route_to_string, - .route_get_all = nm_platform_ip4_route_get_all, .route_add = _vtr_v4_route_add, .route_delete = _vtr_v4_route_delete, .route_delete_default = _vtr_v4_route_delete_default, @@ -5039,11 +5087,11 @@ const NMPlatformVTableRoute nm_platform_vtable_route_v4 = { const NMPlatformVTableRoute nm_platform_vtable_route_v6 = { .is_ip4 = FALSE, + .obj_type = NMP_OBJECT_TYPE_IP6_ROUTE, .addr_family = AF_INET6, .sizeof_route = sizeof (NMPlatformIP6Route), .route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, gboolean consider_host_part)) nm_platform_ip6_route_cmp_full, .route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip6_route_to_string, - .route_get_all = nm_platform_ip6_route_get_all, .route_add = _vtr_v6_route_add, .route_delete = _vtr_v6_route_delete, .route_delete_default = _vtr_v6_route_delete_default, diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index bbb43269f2..f4c499787e 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -373,11 +373,11 @@ typedef union { typedef struct { gboolean is_ip4; + NMPObjectType obj_type; int addr_family; gsize sizeof_route; int (*route_cmp) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, gboolean consider_host_part); const char *(*route_to_string) (const NMPlatformIPXRoute *route, char *buf, gsize len); - GArray *(*route_get_all) (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags); gboolean (*route_add) (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, gint64 metric); gboolean (*route_delete) (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route); gboolean (*route_delete_default) (NMPlatform *self, int ifindex, guint32 metric); @@ -778,6 +778,14 @@ struct _NMPLookup; const struct _NMDedupMultiHeadEntry *nm_platform_lookup (NMPlatform *platform, const struct _NMPLookup *lookup); +gboolean nm_platform_lookup_predicate_routes_skip_rtprot_kernel (const NMPObject *obj, + gpointer user_data); + +GPtrArray *nm_platform_lookup_clone (NMPlatform *platform, + const struct _NMPLookup *lookup, + gboolean (*predicate) (const NMPObject *obj, gpointer user_data), + gpointer user_data); + /* convienience methods to lookup the link and access fields of NMPlatformLink. */ int nm_platform_link_get_ifindex (NMPlatform *self, const char *name); const char *nm_platform_link_get_name (NMPlatform *self, int ifindex); @@ -972,7 +980,6 @@ gboolean nm_platform_address_flush (NMPlatform *self, int ifindex); const NMPlatformIP4Route *nm_platform_ip4_route_get (NMPlatform *self, int ifindex, in_addr_t network, guint8 plen, guint32 metric); const NMPlatformIP6Route *nm_platform_ip6_route_get (NMPlatform *self, int ifindex, struct in6_addr network, guint8 plen, guint32 metric); -GArray *nm_platform_ip4_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags); GArray *nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags); gboolean nm_platform_ip4_route_add (NMPlatform *self, const NMPlatformIP4Route *route); gboolean nm_platform_ip6_route_add (NMPlatform *self, const NMPlatformIP6Route *route); diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 18c9220ab8..6c0098bfce 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -339,6 +339,24 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) return obj ? obj->_class->obj_type : NMP_OBJECT_TYPE_UNKNOWN; } +#define NMP_OBJECT_CAST_IPX_ROUTE(obj) \ + ({ \ + typeof (*(obj)) *_obj = (obj); \ + _nm_unused const NMPObject *_obj_type_check = _obj; \ + \ + nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); \ + &_obj->ipx_route; \ + }) + +#define NMP_OBJECT_CAST_IP_ROUTE(obj) \ + ({ \ + typeof (*(obj)) *_obj = (obj); \ + _nm_unused const NMPObject *_obj_type_check = _obj; \ + \ + nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); \ + &_obj->ip_route; \ + }) + #define NMP_OBJECT_CAST_IP4_ROUTE(obj) \ ({ \ typeof (*(obj)) *_obj = (obj); \ @@ -623,6 +641,21 @@ nm_platform_lookup_route_visible (NMPlatform *platform, return nm_platform_lookup (platform, &lookup); } +static inline GPtrArray * +nm_platform_lookup_route_visible_clone (NMPlatform *platform, + NMPObjectType obj_type, + int ifindex, + gboolean with_default, + gboolean with_non_default, + gboolean (*predicate) (const NMPObject *obj, gpointer user_data), + gpointer user_data) +{ + NMPLookup lookup; + + nmp_lookup_init_route_visible (&lookup, obj_type, ifindex, with_default, with_non_default); + return nm_platform_lookup_clone (platform, &lookup, predicate, user_data); +} + static inline const NMDedupMultiHeadEntry * nm_platform_lookup_route_by_dest (NMPlatform *platform, int addr_family, diff --git a/src/platform/tests/test-cleanup.c b/src/platform/tests/test-cleanup.c index 26c8c2b4bd..690ba35a53 100644 --- a/src/platform/tests/test-cleanup.c +++ b/src/platform/tests/test-cleanup.c @@ -29,8 +29,8 @@ test_cleanup_internal (void) int ifindex; GArray *addresses4; GArray *addresses6; - GArray *routes4; - GArray *routes6; + GPtrArray *routes4; + GPtrArray *routes6; in_addr_t addr4; in_addr_t network4; int plen4 = 24; @@ -72,8 +72,8 @@ test_cleanup_internal (void) addresses4 = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex); addresses6 = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex); - routes4 = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); - routes6 = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); + routes4 = nmtstp_ip4_route_get_all (NM_PLATFORM_GET, ifindex); + routes6 = nmtstp_ip6_route_get_all (NM_PLATFORM_GET, ifindex); g_assert_cmpint (addresses4->len, ==, 1); g_assert_cmpint (addresses6->len, ==, 2); /* also has a IPv6 LL address. */ @@ -82,26 +82,24 @@ test_cleanup_internal (void) g_array_unref (addresses4); g_array_unref (addresses6); - g_array_unref (routes4); - g_array_unref (routes6); + g_ptr_array_unref (routes4); + g_ptr_array_unref (routes6); /* Delete interface with all addresses and routes */ g_assert (nm_platform_link_delete (NM_PLATFORM_GET, ifindex)); addresses4 = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex); addresses6 = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex); - routes4 = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); - routes6 = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); + routes4 = nmtstp_ip4_route_get_all (NM_PLATFORM_GET, ifindex); + routes6 = nmtstp_ip6_route_get_all (NM_PLATFORM_GET, ifindex); g_assert_cmpint (addresses4->len, ==, 0); g_assert_cmpint (addresses6->len, ==, 0); - g_assert_cmpint (routes4->len, ==, 0); - g_assert_cmpint (routes6->len, ==, 0); + g_assert (!routes4); + g_assert (!routes6); g_array_unref (addresses4); g_array_unref (addresses6); - g_array_unref (routes4); - g_array_unref (routes6); } NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP; diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h index b4ed0682ea..e047705fd3 100644 --- a/src/platform/tests/test-common.h +++ b/src/platform/tests/test-common.h @@ -5,6 +5,7 @@ #include #include "platform/nm-platform.h" +#include "platform/nmp-object.h" #include "platform/nm-fake-platform.h" #include "platform/nm-linux-platform.h" @@ -187,6 +188,32 @@ void nmtstp_ip6_route_add (NMPlatform *platform, guint32 metric, guint32 mss); +static inline GPtrArray * +nmtstp_ip4_route_get_all (NMPlatform *platform, + int ifindex) +{ + return nm_platform_lookup_route_visible_clone (platform, + NMP_OBJECT_TYPE_IP4_ROUTE, + ifindex, + TRUE, + TRUE, + nm_platform_lookup_predicate_routes_skip_rtprot_kernel, + NULL); +} + +static inline GPtrArray * +nmtstp_ip6_route_get_all (NMPlatform *platform, + int ifindex) +{ + return nm_platform_lookup_route_visible_clone (platform, + NMP_OBJECT_TYPE_IP6_ROUTE, + ifindex, + TRUE, + TRUE, + nm_platform_lookup_predicate_routes_skip_rtprot_kernel, + NULL); +} + /*****************************************************************************/ const NMPlatformLink *nmtstp_link_get_typed (NMPlatform *platform, int ifindex, const char *name, NMLinkType link_type); diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index c96af93e51..f4ac2a6e6c 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -182,7 +182,7 @@ test_ip4_route (void) SignalData *route_added = add_signal (NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip4_route_callback); SignalData *route_changed = add_signal (NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, ip4_route_callback); SignalData *route_removed = add_signal (NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip4_route_callback); - GArray *routes; + GPtrArray *routes; NMPlatformIP4Route rts[3]; in_addr_t network; guint8 plen = 24; @@ -219,7 +219,7 @@ test_ip4_route (void) accept_signals (route_changed, 0, 1); /* Test route listing */ - routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); + routes = nmtstp_ip4_route_get_all (NM_PLATFORM_GET, ifindex); memset (rts, 0, sizeof (rts)); rts[0].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER); rts[0].network = gateway; @@ -246,8 +246,8 @@ test_ip4_route (void) rts[2].mss = mss; rts[2].scope_inv = nm_platform_route_scope_inv (RT_SCOPE_UNIVERSE); g_assert_cmpint (routes->len, ==, 3); - nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, rts, routes->len, TRUE); - g_array_unref (routes); + nmtst_platform_ip4_routes_equal_aptr ((const NMPObject *const*) routes->pdata, rts, routes->len, TRUE); + g_ptr_array_unref (routes); /* Remove route */ g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric)); @@ -277,7 +277,7 @@ test_ip6_route (void) SignalData *route_added = add_signal (NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip6_route_callback); SignalData *route_changed = add_signal (NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, ip6_route_callback); SignalData *route_removed = add_signal (NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip6_route_callback); - GArray *routes; + GPtrArray *routes; NMPlatformIP6Route rts[3]; struct in6_addr network; guint8 plen = 64; @@ -321,7 +321,7 @@ test_ip6_route (void) accept_signals (route_changed, 0, 1); /* Test route listing */ - routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); + routes = nmtstp_ip6_route_get_all (NM_PLATFORM_GET, ifindex); memset (rts, 0, sizeof (rts)); rts[0].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER); rts[0].network = gateway; @@ -348,8 +348,8 @@ test_ip6_route (void) rts[2].metric = nm_utils_ip6_route_metric_normalize (metric); rts[2].mss = mss; g_assert_cmpint (routes->len, ==, 3); - nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, rts, routes->len, TRUE); - g_array_unref (routes); + nmtst_platform_ip6_routes_equal_aptr ((const NMPObject *const*) routes->pdata, rts, routes->len, TRUE); + g_ptr_array_unref (routes); /* Remove route */ g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric)); @@ -400,7 +400,7 @@ test_ip4_route_options (void) int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); NMPlatformIP4Route route = { }; in_addr_t network; - GArray *routes; + GPtrArray *routes; NMPlatformIP4Route rts[1]; inet_pton (AF_INET, "172.16.1.0", &network); @@ -421,9 +421,7 @@ test_ip4_route_options (void) g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, &route)); /* Test route listing */ - routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, - NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | - NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); + routes = nmtstp_ip4_route_get_all (NM_PLATFORM_GET, ifindex); memset (rts, 0, sizeof (rts)); rts[0].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER); rts[0].scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK); @@ -438,14 +436,12 @@ test_ip4_route_options (void) rts[0].initrwnd = 50; rts[0].mtu = 1350; rts[0].lock_cwnd = TRUE; - g_assert_cmpint (routes->len, ==, 1); - nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, rts, routes->len, TRUE); + nmtst_platform_ip4_routes_equal_aptr ((const NMPObject *const*) routes->pdata, rts, routes->len, TRUE); + g_ptr_array_unref (routes); /* Remove route */ g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, 24, 20)); - - g_array_unref (routes); } diff --git a/src/tests/test-route-manager.c b/src/tests/test-route-manager.c index 6650d26c43..f647cc7494 100644 --- a/src/tests/test-route-manager.c +++ b/src/tests/test-route-manager.c @@ -145,15 +145,38 @@ update_dev0_ip4 (int ifindex) static GArray * ip4_routes (test_fixture *fixture) { - GArray *routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, - fixture->ifindex0, - NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); - GArray *routes1 = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, - fixture->ifindex1, - NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); - - g_array_append_vals (routes, routes1->data, routes1->len); - g_array_free (routes1, TRUE); + GArray *routes; + const NMDedupMultiHeadEntry *pl_head_entry; + NMDedupMultiIter iter; + const NMPObject *plobj = NULL; + guint i; + + routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Route)); + + for (i = 0; i < 2; i++) { + int ifindex; + + if (i == 0) + ifindex = fixture->ifindex0; + else + ifindex = fixture->ifindex1; + + pl_head_entry = nm_platform_lookup_route_visible (NM_PLATFORM_GET, + NMP_OBJECT_TYPE_IP4_ROUTE, + ifindex, + FALSE, + TRUE); + nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) { + const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (plobj); + + if (r->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) + continue; + g_assert (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r)); + g_assert (r->ifindex == ifindex); + g_assert (nmp_object_is_visible (plobj)); + g_array_append_vals (routes, r, 1); + } + } return routes; } -- cgit v1.2.1