summary refs log tree commit diff
path: root/src/platform/tests
diff options
context:
space:
mode:
Diffstat (limited to 'src/platform/tests')
-rw-r--r--src/platform/tests/test-common.c54
-rw-r--r--src/platform/tests/test-common.h20
-rw-r--r--src/platform/tests/test-link.c15
-rw-r--r--src/platform/tests/test-nmp-object.c91
-rw-r--r--src/platform/tests/test-route.c208
5 files changed, 285 insertions, 103 deletions
diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c
index 18076712..9a12f8f9 100644
--- a/src/platform/tests/test-common.c
+++ b/src/platform/tests/test-common.c
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright 2016 Red Hat, Inc.
+ * Copyright 2016 - 2017 Red Hat, Inc.
  */
 
 #include "nm-default.h"
@@ -78,9 +78,9 @@ _ipx_address_get_all (NMPlatform *self, int ifindex, NMPObjectType obj_type)
 	g_assert (NM_IS_PLATFORM (self));
 	g_assert (ifindex > 0);
 	g_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS));
-	nmp_lookup_init_addrroute (&lookup,
-	                           obj_type,
-	                           ifindex);
+	nmp_lookup_init_object (&lookup,
+	                        obj_type,
+	                        ifindex);
 	return nmp_cache_lookup_to_array (nm_platform_lookup (self, &lookup),
 	                                  obj_type,
 	                                  FALSE /*addresses are always visible. */);
@@ -108,9 +108,9 @@ nmtstp_platform_ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t n
 	nm_platform_process_events (platform);
 
 	nm_dedup_multi_iter_for_each (&iter,
-	                              nm_platform_lookup_addrroute (platform,
-	                                                            NMP_OBJECT_TYPE_IP4_ROUTE,
-	                                                            ifindex)) {
+	                              nm_platform_lookup_object (platform,
+	                                                         NMP_OBJECT_TYPE_IP4_ROUTE,
+	                                                         ifindex)) {
 		const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (iter.current->obj);
 
 		if (   r->ifindex != ifindex
@@ -120,7 +120,7 @@ nmtstp_platform_ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t n
 			continue;
 		}
 
-		return nm_platform_ip_route_delete (platform, NMP_OBJECT_UP_CAST (r));
+		return nm_platform_object_delete (platform, NMP_OBJECT_UP_CAST (r));
 	}
 
 	return TRUE;
@@ -134,9 +134,9 @@ nmtstp_platform_ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_
 	nm_platform_process_events (platform);
 
 	nm_dedup_multi_iter_for_each (&iter,
-	                              nm_platform_lookup_addrroute (platform,
-	                                                            NMP_OBJECT_TYPE_IP6_ROUTE,
-	                                                            ifindex)) {
+	                              nm_platform_lookup_object (platform,
+	                                                         NMP_OBJECT_TYPE_IP6_ROUTE,
+	                                                         ifindex)) {
 		const NMPlatformIP6Route *r = NMP_OBJECT_CAST_IP6_ROUTE (iter.current->obj);
 
 		if (   r->ifindex != ifindex
@@ -146,7 +146,7 @@ nmtstp_platform_ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_
 			continue;
 		}
 
-		return nm_platform_ip_route_delete (platform, NMP_OBJECT_UP_CAST (r));
+		return nm_platform_object_delete (platform, NMP_OBJECT_UP_CAST (r));
 	}
 
 	return TRUE;
@@ -1703,8 +1703,8 @@ nmtstp_namespace_create (int unshare_flags, GError **error)
 		errsv = errno;
 		g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
 		             "pipe() failed with %d (%s)", errsv, strerror (errsv));
-		close (pipefd_c2p[0]);
-		close (pipefd_c2p[1]);
+		nm_close (pipefd_c2p[0]);
+		nm_close (pipefd_c2p[1]);
 		return FALSE;
 	}
 
@@ -1713,18 +1713,18 @@ nmtstp_namespace_create (int unshare_flags, GError **error)
 		errsv = errno;
 		g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
 		             "fork() failed with %d (%s)", errsv, strerror (errsv));
-		close (pipefd_c2p[0]);
-		close (pipefd_c2p[1]);
-		close (pipefd_p2c[0]);
-		close (pipefd_p2c[1]);
+		nm_close (pipefd_c2p[0]);
+		nm_close (pipefd_c2p[1]);
+		nm_close (pipefd_p2c[0]);
+		nm_close (pipefd_p2c[1]);
 		return FALSE;
 	}
 
 	if (pid == 0) {
 		char read_buf[1];
 
-		close (pipefd_c2p[0]); /* close read-end */
-		close (pipefd_p2c[1]); /* close write-end */
+		nm_close (pipefd_c2p[0]); /* close read-end */
+		nm_close (pipefd_p2c[1]); /* close write-end */
 
 		if (unshare (unshare_flags) != 0) {
 			errsv = errno;
@@ -1742,7 +1742,7 @@ nmtstp_namespace_create (int unshare_flags, GError **error)
 			if (errsv == 0)
 				errsv = -2;
 		}
-		close (pipefd_c2p[1]);
+		nm_close (pipefd_c2p[1]);
 
 		/* wait until parent process terminates (or kills us). */
 		if (errsv == 0) {
@@ -1750,19 +1750,19 @@ nmtstp_namespace_create (int unshare_flags, GError **error)
 				r = read (pipefd_p2c[0], read_buf, sizeof (read_buf));
 			} while (r < 0 && errno == EINTR);
 		}
-		close (pipefd_p2c[0]);
+		nm_close (pipefd_p2c[0]);
 		_exit (0);
 	}
 
-	close (pipefd_c2p[1]); /* close write-end */
-	close (pipefd_p2c[0]); /* close read-end */
+	nm_close (pipefd_c2p[1]); /* close write-end */
+	nm_close (pipefd_p2c[0]); /* close read-end */
 
 	/* sync with child process. */
 	do {
 		r = read (pipefd_c2p[0], &errsv, sizeof (errsv));
 	} while (r < 0 && errno == EINTR);
 
-	close (pipefd_c2p[0]);
+	nm_close (pipefd_c2p[0]);
 
 	if (   r != sizeof (errsv)
 	    || errsv != 0) {
@@ -1775,7 +1775,7 @@ nmtstp_namespace_create (int unshare_flags, GError **error)
 			g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
 			             "child process signaled failure %d (%s)", errsv, strerror (errsv));
 		}
-		close (pipefd_p2c[1]);
+		nm_close (pipefd_p2c[1]);
 		kill (pid, SIGKILL);
 		do {
 			pid2 = waitpid (pid, &status, 0);
@@ -1809,7 +1809,7 @@ nmtstp_namespace_handle_release (NMTstpNamespaceHandle *ns_handle)
 
 	g_return_if_fail (ns_handle->pid > 0);
 
-	close (ns_handle->pipe_fd);
+	nm_close (ns_handle->pipe_fd);
 	ns_handle->pipe_fd = 0;
 
 	kill (ns_handle->pid, SIGKILL);
diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h
index 4010aa2f..fb406a3f 100644
--- a/src/platform/tests/test-common.h
+++ b/src/platform/tests/test-common.h
@@ -227,22 +227,22 @@ static inline GPtrArray *
 nmtstp_ip4_route_get_all (NMPlatform *platform,
                           int ifindex)
 {
-	return nm_platform_lookup_addrroute_clone (platform,
-	                                           NMP_OBJECT_TYPE_IP4_ROUTE,
-	                                           ifindex,
-	                                           nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel,
-	                                           NULL);
+	return nm_platform_lookup_object_clone (platform,
+	                                        NMP_OBJECT_TYPE_IP4_ROUTE,
+	                                        ifindex,
+	                                        nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel,
+	                                        NULL);
 }
 
 static inline GPtrArray *
 nmtstp_ip6_route_get_all (NMPlatform *platform,
                           int ifindex)
 {
-	return nm_platform_lookup_addrroute_clone (platform,
-	                                           NMP_OBJECT_TYPE_IP6_ROUTE,
-	                                           ifindex,
-	                                           nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel,
-	                                           NULL);
+	return nm_platform_lookup_object_clone (platform,
+	                                        NMP_OBJECT_TYPE_IP6_ROUTE,
+	                                        ifindex,
+	                                        nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel,
+	                                        NULL);
 }
 
 /*****************************************************************************/
diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c
index 9c72371c..d3a10bd6 100644
--- a/src/platform/tests/test-link.c
+++ b/src/platform/tests/test-link.c
@@ -1916,6 +1916,7 @@ _test_netns_check_skip (void)
 	static int support = -1;
 	static int support_errsv = 0;
 	NMPNetns *netns;
+	gs_unref_object NMPNetns *netns2 = NULL;
 
 	netns = nmp_netns_get_current ();
 	if (!netns) {
@@ -1931,10 +1932,20 @@ _test_netns_check_skip (void)
 			support_errsv = errno;
 	}
 	if (!support) {
-			_LOGD ("setns() failed with \"%s\". This indicates missing support (valgrind?)", g_strerror (support_errsv));
-			g_test_skip ("No netns support (setns failed)");
+		_LOGD ("setns() failed with \"%s\". This indicates missing support (valgrind?)", g_strerror (support_errsv));
+		g_test_skip ("No netns support (setns failed)");
 		return TRUE;
 	}
+
+	netns2 = nmp_netns_new ();
+	if (!netns2) {
+		/* skip tests for https://bugzilla.gnome.org/show_bug.cgi?id=790214 */
+		g_assert_cmpint (errno, ==, EINVAL);
+		g_test_skip ("No netns support to create another netns");
+		return TRUE;
+	}
+	nmp_netns_pop (netns2);
+
 	return FALSE;
 }
 
diff --git a/src/platform/tests/test-nmp-object.c b/src/platform/tests/test-nmp-object.c
index a02388d2..3228de83 100644
--- a/src/platform/tests/test-nmp-object.c
+++ b/src/platform/tests/test-nmp-object.c
@@ -15,12 +15,13 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2015 Red Hat, Inc.
+ * Copyright (C) 2015 - 2017 Red Hat, Inc.
  */
 
 #include "nm-default.h"
 
 #include <libudev.h>
+#include <linux/pkt_sched.h>
 
 #include "platform/nmp-object.h"
 #include "nm-utils/nm-udev-utils.h"
@@ -454,6 +455,93 @@ test_cache_link (void)
 	nmp_cache_free (cache);
 }
 
+const char noqueue[] = "noqueue";
+const char fq_codel[] = "fq_codel";
+const char ingress[] = "ingress";
+
+static const NMPlatformQdisc pl_qdisc_1a = {
+	.ifindex = 1,
+	.kind = noqueue,
+	.addr_family = AF_UNSPEC,
+	.handle = 0,
+	.parent = TC_H_ROOT,
+	.info = 0,
+};
+
+static const NMPlatformQdisc pl_qdisc_1b = {
+	.ifindex = 1,
+	.kind = fq_codel,
+	.addr_family = AF_UNSPEC,
+	.handle = 0,
+	.parent = TC_H_ROOT,
+	.info = 0,
+};
+
+static const NMPlatformQdisc pl_qdisc_1c = {
+	.ifindex = 1,
+	.kind = ingress,
+	.addr_family = AF_UNSPEC,
+	.handle = TC_H_MAKE(TC_H_INGRESS, 0),
+	.parent = TC_H_INGRESS,
+	.info = 0,
+};
+
+static const NMPlatformQdisc pl_qdisc_2 = {
+	.ifindex = 2,
+	.kind = fq_codel,
+	.addr_family = AF_UNSPEC,
+	.handle = 0,
+	.parent = TC_H_ROOT,
+	.info = 0,
+};
+
+static void
+test_cache_qdisc (void)
+{
+	NMPCache *cache;
+	nm_auto_unref_dedup_multi_index NMDedupMultiIndex *multi_idx = NULL;
+	NMPLookup lookup;
+	const NMDedupMultiHeadEntry *head_entry;
+	nm_auto_nmpobj NMPObject *obj1a = nmp_object_new (NMP_OBJECT_TYPE_QDISC, (NMPlatformObject *) &pl_qdisc_1a);
+	nm_auto_nmpobj NMPObject *obj1b = nmp_object_new (NMP_OBJECT_TYPE_QDISC, (NMPlatformObject *) &pl_qdisc_1b);
+	nm_auto_nmpobj NMPObject *obj1c = nmp_object_new (NMP_OBJECT_TYPE_QDISC, (NMPlatformObject *) &pl_qdisc_1c);
+	nm_auto_nmpobj NMPObject *obj2 = nmp_object_new (NMP_OBJECT_TYPE_QDISC, (NMPlatformObject *) &pl_qdisc_2);
+
+	multi_idx = nm_dedup_multi_index_new ();
+	cache = nmp_cache_new (multi_idx, nmtst_get_rand_int () % 2);
+
+	g_assert (nmp_cache_lookup_obj (cache, obj1a) == NULL);
+
+	g_assert (nmp_cache_update_netlink (cache, obj1a, FALSE, NULL, NULL) == NMP_CACHE_OPS_ADDED);
+	g_assert (nmp_cache_lookup_obj (cache, obj1a) == obj1a);
+	g_assert (nmp_cache_lookup_obj (cache, obj1b) == obj1a);
+	g_assert (nmp_cache_lookup_obj (cache, obj2) == NULL);
+
+	g_assert (nmp_cache_update_netlink (cache, obj1b, FALSE, NULL, NULL) == NMP_CACHE_OPS_UPDATED);
+	g_assert (nmp_cache_lookup_obj (cache, obj1a) == obj1b);
+	g_assert (nmp_cache_lookup_obj (cache, obj1b) == obj1b);
+	g_assert (nmp_cache_lookup_obj (cache, obj2) == NULL);
+
+	g_assert (nmp_cache_update_netlink (cache, obj1c, FALSE, NULL, NULL) == NMP_CACHE_OPS_ADDED);
+	g_assert (nmp_cache_lookup_obj (cache, obj1a) == obj1b);
+	g_assert (nmp_cache_lookup_obj (cache, obj1b) == obj1b);
+	g_assert (nmp_cache_lookup_obj (cache, obj1c) == obj1c);
+	g_assert (nmp_cache_lookup_obj (cache, obj2) == NULL);
+
+	g_assert (nmp_cache_update_netlink (cache, obj2, FALSE, NULL, NULL) == NMP_CACHE_OPS_ADDED);
+	g_assert (nmp_cache_lookup_obj (cache, obj1a) == obj1b);
+	g_assert (nmp_cache_lookup_obj (cache, obj1b) == obj1b);
+	g_assert (nmp_cache_lookup_obj (cache, obj2) == obj2);
+
+	head_entry = nmp_cache_lookup (cache,
+	                               nmp_lookup_init_object (&lookup,
+	                                                       NMP_OBJECT_TYPE_QDISC,
+	                                                       1));
+	g_assert (head_entry->len == 2);
+
+	nmp_cache_free (cache);
+}
+
 /*****************************************************************************/
 
 NMTST_DEFINE ();
@@ -500,6 +588,7 @@ main (int argc, char **argv)
 
 	g_test_add_func ("/nmp-object/obj-base", test_obj_base);
 	g_test_add_func ("/nmp-object/cache_link", test_cache_link);
+	g_test_add_func ("/nmp-object/cache_qdisc", test_cache_qdisc);
 
 	result = g_test_run ();
 
diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c
index 2c00fada..fe97db07 100644
--- a/src/platform/tests/test-route.c
+++ b/src/platform/tests/test-route.c
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright 2016 Red Hat, Inc.
+ * Copyright 2016 - 2017 Red Hat, Inc.
  */
 
 #include "nm-default.h"
@@ -31,6 +31,42 @@
 #define EX             NMTSTP_ENV1_EX
 
 static void
+_wait_for_ipv4_addr_device_route (NMPlatform *platform,
+                                  gint64 timeout_ms,
+                                  int ifindex,
+                                  in_addr_t addr,
+                                  guint8 plen)
+{
+	/* Wait that the addresses gets a device-route. After adding a address,
+	 * the device route is not added immediately. It takes a moment... */
+
+	addr = nm_utils_ip4_address_clear_host_address (addr, plen);
+	NMTST_WAIT_ASSERT (400, {
+		NMDedupMultiIter iter;
+		NMPLookup lookup;
+		const NMPObject *o;
+
+		nmp_cache_iter_for_each (&iter,
+		                         nm_platform_lookup (platform,
+		                                             nmp_lookup_init_object (&lookup,
+		                                                                     NMP_OBJECT_TYPE_IP4_ROUTE,
+		                                                                     ifindex)),
+		                         &o) {
+			const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (o);
+
+			if (   r->plen == plen
+			    && addr == nm_utils_ip4_address_clear_host_address (r->network, plen)
+			    && r->metric == 0
+			    && r->scope_inv == nm_platform_route_scope_inv (RT_SCOPE_LINK)
+			    && r->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL)
+				return;
+		}
+		nmtstp_assert_wait_for_signal (platform,
+		                               (nmtst_wait_end_us - g_get_monotonic_time ()) / 1000);
+	});
+}
+
+static void
 _wait_for_ipv6_addr_non_tentative (NMPlatform *platform,
                                    gint64 timeout_ms,
                                    int ifindex,
@@ -44,7 +80,7 @@ _wait_for_ipv6_addr_non_tentative (NMPlatform *platform,
 	 * small amount of time, which prevents the immediate addition of the route
 	 * with RTA_PREFSRC */
 
-	NMTST_WAIT_ASSERT (400, {
+	NMTST_WAIT_ASSERT (timeout_ms, {
 		gboolean should_wait = FALSE;
 		const NMPlatformIP6Address *plt_addr;
 
@@ -63,7 +99,6 @@ _wait_for_ipv6_addr_non_tentative (NMPlatform *platform,
 	});
 }
 
-
 static void
 ip4_route_callback (NMPlatform *platform, int obj_type_i, int ifindex, const NMPlatformIP4Route *received, int change_type_i, SignalData *data)
 {
@@ -417,7 +452,7 @@ test_ip_route_get (void)
 	g_assert (!NMP_OBJECT_IS_STACKINIT (route));
 	g_assert (route->parent._ref_count == 1);
 	r = NMP_OBJECT_CAST_IP4_ROUTE (route);
-	g_assert (r->rt_cloned);
+	g_assert (NM_FLAGS_HAS (r->r_rtm_flags, RTM_F_CLONED));
 	g_assert (r->ifindex == ifindex);
 	g_assert (r->network == a);
 	g_assert (r->plen == 32);
@@ -448,63 +483,114 @@ test_ip4_zero_gateway (void)
 }
 
 static void
-test_ip4_route_options (void)
+test_ip4_route_options (gconstpointer test_data)
 {
-	int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
-	NMPlatformIP4Route route = { };
-	in_addr_t network;
-	GPtrArray *routes;
-	NMPlatformIP4Route rts[1];
+	const int TEST_IDX = GPOINTER_TO_INT (test_data);
+	const int IFINDEX = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
+	gs_unref_ptrarray GPtrArray *routes = NULL;
+#define RTS_MAX 3
+	NMPlatformIP4Route rts_add[RTS_MAX] = { };
+	NMPlatformIP4Route rts_cmp[RTS_MAX] = { };
+	NMPlatformIP4Address addr[1] = { };
+	guint i;
+	guint rts_n = 0;
+	guint addr_n = 0;
 
-	inet_pton (AF_INET, "172.16.1.0", &network);
+	switch (TEST_IDX) {
+	case 1:
+		rts_add[rts_n++] = ((NMPlatformIP4Route) {
+			.ifindex = IFINDEX,
+			.rt_source = NM_IP_CONFIG_SOURCE_USER,
+			.network = nmtst_inet4_from_string ("172.16.1.0"),
+			.plen = 24,
+			.metric = 20,
+			.tos = 0x28,
+			.window = 10000,
+			.cwnd = 16,
+			.initcwnd = 30,
+			.initrwnd = 50,
+			.mtu = 1350,
+			.lock_cwnd = TRUE,
+		});
+		break;
+	case 2:
+		addr[addr_n++] = ((NMPlatformIP4Address) {
+			.ifindex = IFINDEX,
+			.address = nmtst_inet4_from_string ("172.16.1.5"),
+			.peer_address = nmtst_inet4_from_string ("172.16.1.5"),
+			.plen = 24,
+			.lifetime = NM_PLATFORM_LIFETIME_PERMANENT,
+			.preferred = NM_PLATFORM_LIFETIME_PERMANENT,
+			.n_ifa_flags = 0,
+		});
+		rts_add[rts_n++] = ((NMPlatformIP4Route) {
+			.ifindex = IFINDEX,
+			.rt_source = NM_IP_CONFIG_SOURCE_USER,
+			.network = nmtst_inet4_from_string ("172.17.1.0"),
+			.gateway = nmtst_inet4_from_string ("172.16.1.1"),
+			.plen = 24,
+			.metric = 20,
+		});
+		rts_add[rts_n++] = ((NMPlatformIP4Route) {
+			.ifindex = IFINDEX,
+			.rt_source = NM_IP_CONFIG_SOURCE_USER,
+			.network = nmtst_inet4_from_string ("172.19.1.0"),
+			.gateway = nmtst_inet4_from_string ("172.18.1.1"),
+			.r_rtm_flags = RTNH_F_ONLINK,
+			.plen = 24,
+			.metric = 20,
+		});
+		break;
+	default:
+		g_assert_not_reached ();
+		break;
+	}
+	g_assert (rts_n <= G_N_ELEMENTS (rts_add));
+	g_assert (addr_n <= G_N_ELEMENTS (addr));
 
-	route.ifindex = ifindex;
-	route.rt_source = NM_IP_CONFIG_SOURCE_USER;
-	route.network = network;
-	route.plen = 24;
-	route.metric = 20;
-	route.tos = 0x28;
-	route.window = 10000;
-	route.cwnd = 16;
-	route.initcwnd = 30;
-	route.initrwnd = 50;
-	route.mtu = 1350;
-	route.lock_cwnd = TRUE;
+	for (i = 0; i < addr_n; i++) {
+		const NMPlatformIP4Address *a = &addr[i];
+
+		g_assert (a->ifindex == IFINDEX);
+		g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET,
+		                                       a->ifindex,
+		                                       a->address,
+		                                       a->plen,
+		                                       a->peer_address,
+		                                       a->lifetime,
+		                                       a->preferred,
+		                                       a->n_ifa_flags,
+		                                       a->label));
+		if (a->peer_address == a->address)
+			_wait_for_ipv4_addr_device_route (NM_PLATFORM_GET, 200, a->ifindex, a->address, a->plen);
+	}
 
-	g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, &route) == NM_PLATFORM_ERROR_SUCCESS);
+	for (i = 0; i < rts_n; i++)
+		g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, &rts_add[i]) == NM_PLATFORM_ERROR_SUCCESS);
 
-	/* Test route listing */
-	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);
-	rts[0].network = network;
-	rts[0].plen = 24;
-	rts[0].ifindex = ifindex;
-	rts[0].metric = 20;
-	rts[0].tos = 0x28;
-	rts[0].window = 10000;
-	rts[0].cwnd = 16;
-	rts[0].initcwnd = 30;
-	rts[0].initrwnd = 50;
-	rts[0].mtu = 1350;
-	rts[0].lock_cwnd = TRUE;
-	g_assert_cmpint (routes->len, ==, 1);
-	nmtst_platform_ip4_routes_equal_aptr ((const NMPObject *const*) routes->pdata, rts, routes->len, TRUE);
+	for (i = 0; i < rts_n; i++) {
+		rts_cmp[i] = rts_add[i];
+		nm_platform_ip_route_normalize (AF_INET, NM_PLATFORM_IP_ROUTE_CAST (&rts_cmp[i]));
+	}
 
-	/* Remove route */
-	g_assert (nm_platform_ip_route_delete (NM_PLATFORM_GET, routes->pdata[0]));
+	routes = nmtstp_ip4_route_get_all (NM_PLATFORM_GET, IFINDEX);
+	g_assert_cmpint (routes->len, ==, rts_n);
+	nmtst_platform_ip4_routes_equal_aptr ((const NMPObject *const*) routes->pdata, rts_cmp, routes->len, TRUE);
 
-	g_ptr_array_unref (routes);
+	for (i = 0; i < rts_n; i++) {
+		g_assert (nmtstp_platform_ip4_route_delete (NM_PLATFORM_GET, IFINDEX,
+		                                            rts_add[i].network, rts_add[i].plen,
+		                                            rts_add[i].metric));
+	}
+#undef RTS_MAX
 }
 
-
 static void
 test_ip6_route_options (gconstpointer test_data)
 {
 	const int TEST_IDX = GPOINTER_TO_INT (test_data);
 	const int IFINDEX = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
-	GPtrArray *routes;
+	gs_unref_ptrarray GPtrArray *routes = NULL;
 #define RTS_MAX 3
 	NMPlatformIP6Route rts_add[RTS_MAX] = { };
 	NMPlatformIP6Route rts_cmp[RTS_MAX] = { };
@@ -582,6 +668,8 @@ test_ip6_route_options (gconstpointer test_data)
 	default:
 		g_assert_not_reached ();
 	}
+	g_assert (rts_n <= G_N_ELEMENTS (rts_add));
+	g_assert (addr_n <= G_N_ELEMENTS (addr));
 
 	for (i = 0; i < addr_n; i++) {
 		g_assert (addr[i].ifindex == IFINDEX);
@@ -595,28 +683,19 @@ test_ip6_route_options (gconstpointer test_data)
 		                                       addr[i].preferred,
 		                                       addr[i].n_ifa_flags));
 	}
-
 	_wait_for_ipv6_addr_non_tentative (NM_PLATFORM_GET, 400, IFINDEX, addr_n, addr_in6);
 
 	for (i = 0; i < rts_n; i++)
 		g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, &rts_add[i]) == NM_PLATFORM_ERROR_SUCCESS);
 
-	routes = nmtstp_ip6_route_get_all (NM_PLATFORM_GET, IFINDEX);
-	switch (TEST_IDX) {
-	case 1:
-	case 2:
-	case 3:
-		for (i = 0; i < rts_n; i++) {
-			rts_cmp[i] = rts_add[i];
-			rts_cmp[i].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
-		}
-		break;
-	default:
-		g_assert_not_reached ();
+	for (i = 0; i < rts_n; i++) {
+		rts_cmp[i] = rts_add[i];
+		nm_platform_ip_route_normalize (AF_INET6, NM_PLATFORM_IP_ROUTE_CAST (&rts_cmp[i]));
 	}
+
+	routes = nmtstp_ip6_route_get_all (NM_PLATFORM_GET, IFINDEX);
 	g_assert_cmpint (routes->len, ==, rts_n);
 	nmtst_platform_ip6_routes_equal_aptr ((const NMPObject *const*) routes->pdata, rts_cmp, routes->len, TRUE);
-	g_ptr_array_unref (routes);
 
 	for (i = 0; i < rts_n; i++) {
 		g_assert (nmtstp_platform_ip6_route_delete (NM_PLATFORM_GET, IFINDEX,
@@ -631,6 +710,7 @@ test_ip6_route_options (gconstpointer test_data)
 		                        rts_add[i].network,
 		                        rts_add[i].plen);
 	}
+#undef RTS_MAX
 }
 
 /*****************************************************************************/
@@ -714,7 +794,7 @@ again_find_idx:
 			order_len--;
 
 			r->ifindex = iface_data[idx].ifindex;
-			g_assert (nm_platform_ip_route_delete (platform, &o));
+			g_assert (nm_platform_object_delete (platform, &o));
 		}
 
 		head_entry = nm_platform_lookup (platform,
@@ -771,7 +851,9 @@ _nmtstp_setup_tests (void)
 	add_test_func ("/route/ip4", test_ip4_route);
 	add_test_func ("/route/ip6", test_ip6_route);
 	add_test_func ("/route/ip4_metric0", test_ip4_route_metric0);
-	add_test_func ("/route/ip4_options", test_ip4_route_options);
+	add_test_func_data ("/route/ip4_options/1", test_ip4_route_options, GINT_TO_POINTER (1));
+	if (nmtstp_is_root_test ())
+		add_test_func_data ("/route/ip4_options/2", test_ip4_route_options, GINT_TO_POINTER (2));
 	add_test_func_data ("/route/ip6_options/1", test_ip6_route_options, GINT_TO_POINTER (1));
 	add_test_func_data ("/route/ip6_options/2", test_ip6_route_options, GINT_TO_POINTER (2));
 	add_test_func_data ("/route/ip6_options/3", test_ip6_route_options, GINT_TO_POINTER (3));