summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2017-06-29 15:19:35 +0200
committerThomas Haller <thaller@redhat.com>2017-07-05 18:37:39 +0200
commit667c50f5d920e91d798d51c61e63e3ce87e277d3 (patch)
tree586ae996891847ad6df0ea66357ac2fd44571542
parentc9cd6d995482b9c7d1a06e0601d321968abcf9f7 (diff)
downloadNetworkManager-667c50f5d920e91d798d51c61e63e3ce87e277d3.tar.gz
core: avoid cloning platform routes but iterate the cache directly
-rw-r--r--src/devices/nm-device.c68
-rw-r--r--src/nm-default-route-manager.c93
-rw-r--r--src/nm-ip4-config.c61
-rw-r--r--src/nm-route-manager.c58
-rw-r--r--src/nm-test-utils-core.h38
-rw-r--r--src/platform/nm-platform.c72
-rw-r--r--src/platform/nm-platform.h11
-rw-r--r--src/platform/nmp-object.h33
-rw-r--r--src/platform/tests/test-cleanup.c22
-rw-r--r--src/platform/tests/test-common.h27
-rw-r--r--src/platform/tests/test-route.c28
-rw-r--r--src/tests/test-route-manager.c41
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)
{
@@ -3201,16 +3259,6 @@ ipx_route_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type, NM
}
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)
{
_CHECK_SELF (self, klass, NULL);
@@ -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 <arpa/inet.h>
#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;
}