about summary refs log tree commit diff
path: root/src/platform/tests
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2015-07-14 19:38:58 +0200
committerMichael Biebl <biebl@debian.org>2015-07-14 19:38:58 +0200
commit50a58f0fabd8a34c1b6108a107e08abe3c1ccd24 (patch)
tree6790165f39daee79e2b6c6617483320613493367 /src/platform/tests
parentf408e27bccfacf347605a8d98649975a68f38a17 (diff)
Imported Upstream version 1.0.4 upstream/1.0.4
Diffstat (limited to 'src/platform/tests')
-rw-r--r--src/platform/tests/Makefile.am26
-rw-r--r--src/platform/tests/Makefile.in545
-rw-r--r--src/platform/tests/dump.c33
-rw-r--r--src/platform/tests/platform.c119
-rw-r--r--src/platform/tests/test-address.c108
-rw-r--r--src/platform/tests/test-cleanup.c48
-rw-r--r--src/platform/tests/test-common.c201
-rw-r--r--src/platform/tests/test-common.h23
-rw-r--r--src/platform/tests/test-general.c67
-rw-r--r--src/platform/tests/test-link.c435
-rw-r--r--src/platform/tests/test-nmp-object.c425
-rw-r--r--src/platform/tests/test-route.c131
12 files changed, 1537 insertions, 624 deletions
diff --git a/src/platform/tests/Makefile.am b/src/platform/tests/Makefile.am
index c10600eb..54844ec1 100644
--- a/src/platform/tests/Makefile.am
+++ b/src/platform/tests/Makefile.am
@@ -37,6 +37,8 @@ noinst_PROGRAMS = \
 	test-link-linux \
 	test-address-fake \
 	test-address-linux \
+	test-general \
+	test-nmp-object \
 	test-route-fake \
 	test-route-linux \
 	test-cleanup-fake \
@@ -109,7 +111,27 @@ test_cleanup_linux_CPPFLAGS = \
 	-DKERNEL_HACKS=1
 test_cleanup_linux_LDADD = $(PLATFORM_LDADD)
 
-@VALGRIND_RULES@
-TESTS = test-link-fake test-address-fake test-route-fake test-cleanup-fake test-address-linux test-route-linux test-cleanup-linux
+test_nmp_object_SOURCES = \
+	test-nmp-object.c
+test_nmp_object_LDADD = \
+	$(top_builddir)/src/libNetworkManager.la
+
+test_general_SOURCES = \
+	test-general.c
+test_general_LDADD = \
+	$(top_builddir)/src/libNetworkManager.la
+
 
+@VALGRIND_RULES@
+TESTS = \
+	test-address-fake \
+	test-address-linux \
+	test-cleanup-fake \
+	test-cleanup-linux \
+	test-general \
+	test-link-fake \
+	test-link-linux \
+	test-nmp-object \
+	test-route-fake \
+	test-route-linux
 
diff --git a/src/platform/tests/Makefile.in b/src/platform/tests/Makefile.in
index 16a48430..a9333539 100644
--- a/src/platform/tests/Makefile.in
+++ b/src/platform/tests/Makefile.in
@@ -92,12 +92,14 @@ host_triplet = @host@
 noinst_PROGRAMS = dump$(EXEEXT) monitor$(EXEEXT) platform$(EXEEXT) \
 	test-link-fake$(EXEEXT) test-link-linux$(EXEEXT) \
 	test-address-fake$(EXEEXT) test-address-linux$(EXEEXT) \
+	test-general$(EXEEXT) test-nmp-object$(EXEEXT) \
 	test-route-fake$(EXEEXT) test-route-linux$(EXEEXT) \
 	test-cleanup-fake$(EXEEXT) test-cleanup-linux$(EXEEXT)
-TESTS = test-link-fake$(EXEEXT) test-address-fake$(EXEEXT) \
-	test-route-fake$(EXEEXT) test-cleanup-fake$(EXEEXT) \
-	test-address-linux$(EXEEXT) test-route-linux$(EXEEXT) \
-	test-cleanup-linux$(EXEEXT)
+TESTS = test-address-fake$(EXEEXT) test-address-linux$(EXEEXT) \
+	test-cleanup-fake$(EXEEXT) test-cleanup-linux$(EXEEXT) \
+	test-general$(EXEEXT) test-link-fake$(EXEEXT) \
+	test-link-linux$(EXEEXT) test-nmp-object$(EXEEXT) \
+	test-route-fake$(EXEEXT) test-route-linux$(EXEEXT)
 subdir = src/platform/tests
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \
@@ -172,6 +174,9 @@ am_test_cleanup_linux_OBJECTS =  \
 	test_cleanup_linux-test-cleanup.$(OBJEXT) $(am__objects_9)
 test_cleanup_linux_OBJECTS = $(am_test_cleanup_linux_OBJECTS)
 test_cleanup_linux_DEPENDENCIES = $(PLATFORM_LDADD)
+am_test_general_OBJECTS = test-general.$(OBJEXT)
+test_general_OBJECTS = $(am_test_general_OBJECTS)
+test_general_DEPENDENCIES = $(top_builddir)/src/libNetworkManager.la
 am__objects_10 = test_link_fake-nm-platform.$(OBJEXT) \
 	test_link_fake-nm-fake-platform.$(OBJEXT) \
 	test_link_fake-nm-linux-platform.$(OBJEXT)
@@ -190,6 +195,10 @@ am_test_link_linux_OBJECTS = test_link_linux-test-link.$(OBJEXT) \
 	$(am__objects_13)
 test_link_linux_OBJECTS = $(am_test_link_linux_OBJECTS)
 test_link_linux_DEPENDENCIES = $(PLATFORM_LDADD)
+am_test_nmp_object_OBJECTS = test-nmp-object.$(OBJEXT)
+test_nmp_object_OBJECTS = $(am_test_nmp_object_OBJECTS)
+test_nmp_object_DEPENDENCIES =  \
+	$(top_builddir)/src/libNetworkManager.la
 am__objects_14 = test_route_fake-nm-platform.$(OBJEXT) \
 	test_route_fake-nm-fake-platform.$(OBJEXT) \
 	test_route_fake-nm-linux-platform.$(OBJEXT)
@@ -245,12 +254,14 @@ am__v_CCLD_1 =
 SOURCES = $(dump_SOURCES) $(monitor_SOURCES) $(platform_SOURCES) \
 	$(test_address_fake_SOURCES) $(test_address_linux_SOURCES) \
 	$(test_cleanup_fake_SOURCES) $(test_cleanup_linux_SOURCES) \
-	$(test_link_fake_SOURCES) $(test_link_linux_SOURCES) \
+	$(test_general_SOURCES) $(test_link_fake_SOURCES) \
+	$(test_link_linux_SOURCES) $(test_nmp_object_SOURCES) \
 	$(test_route_fake_SOURCES) $(test_route_linux_SOURCES)
 DIST_SOURCES = $(dump_SOURCES) $(monitor_SOURCES) $(platform_SOURCES) \
 	$(test_address_fake_SOURCES) $(test_address_linux_SOURCES) \
 	$(test_cleanup_fake_SOURCES) $(test_cleanup_linux_SOURCES) \
-	$(test_link_fake_SOURCES) $(test_link_linux_SOURCES) \
+	$(test_general_SOURCES) $(test_link_fake_SOURCES) \
+	$(test_link_linux_SOURCES) $(test_nmp_object_SOURCES) \
 	$(test_route_fake_SOURCES) $(test_route_linux_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
@@ -298,13 +309,196 @@ am__tty_colors = { \
     std=''; \
   fi; \
 }
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__recheck_rx = ^[ 	]*:recheck:[ 	]*
+am__global_test_result_rx = ^[ 	]*:global-test-result:[ 	]*
+am__copy_in_global_log_rx = ^[ 	]*:copy-in-global-log:[ 	]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+  recheck = 1; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+        { \
+          if ((getline line2 < ($$0 ".log")) < 0) \
+	    recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+        { \
+          recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+        { \
+          break; \
+        } \
+    }; \
+  if (recheck) \
+    print $$0; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+  print "fatal: making $@: " msg | "cat >&2"; \
+  exit 1; \
+} \
+function rst_section(header) \
+{ \
+  print header; \
+  len = length(header); \
+  for (i = 1; i <= len; i = i + 1) \
+    printf "="; \
+  printf "\n\n"; \
+} \
+{ \
+  copy_in_global_log = 1; \
+  global_test_result = "RUN"; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+         fatal("failed to read from " $$0 ".trs"); \
+      if (line ~ /$(am__global_test_result_rx)/) \
+        { \
+          sub("$(am__global_test_result_rx)", "", line); \
+          sub("[ 	]*$$", "", line); \
+          global_test_result = line; \
+        } \
+      else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+        copy_in_global_log = 0; \
+    }; \
+  if (copy_in_global_log) \
+    { \
+      rst_section(global_test_result ": " $$0); \
+      while ((rc = (getline line < ($$0 ".log"))) != 0) \
+      { \
+        if (rc < 0) \
+          fatal("failed to read from " $$0 ".log"); \
+        print line; \
+      }; \
+      printf "\n"; \
+    }; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/   &   /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this.  Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+  --color-tests "$$am__color_tests" \
+  --enable-hard-errors "$$am__enable_hard_errors" \
+  --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test.  Creates the
+# directory for the log if needed.  Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log.  Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT.  Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup);					\
+$(am__vpath_adj_setup) $(am__vpath_adj)			\
+$(am__tty_colors);					\
+srcdir=$(srcdir); export srcdir;			\
+case "$@" in						\
+  */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;;	\
+    *) am__odir=.;; 					\
+esac;							\
+test "x$$am__odir" = x"." || test -d "$$am__odir" 	\
+  || $(MKDIR_P) "$$am__odir" || exit $$?;		\
+if test -f "./$$f"; then dir=./;			\
+elif test -f "$$f"; then dir=;				\
+else dir="$(srcdir)/"; fi;				\
+tst=$$dir$$f; log='$@'; 				\
+if test -n '$(DISABLE_HARD_ERRORS)'; then		\
+  am__enable_hard_errors=no; 				\
+else							\
+  am__enable_hard_errors=yes; 				\
+fi; 							\
+case " $(XFAIL_TESTS) " in				\
+  *[\ \	]$$f[\ \	]* | *[\ \	]$$dir$$f[\ \	]*) \
+    am__expect_failure=yes;;				\
+  *)							\
+    am__expect_failure=no;;				\
+esac; 							\
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed).  The result is saved in the shell variable
+# '$bases'.  This honors runtime overriding of TESTS and TEST_LOGS.  Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+  bases='$(TEST_LOGS)'; \
+  bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+  bases=`echo $$bases`
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+  case '$@' in \
+    */*) \
+      case '$*' in \
+        */*) b='$*';; \
+          *) b=`echo '$@' | sed 's/\.log$$//'`; \
+       esac;; \
+    *) \
+      b='$*';; \
+  esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+	$(TEST_LOG_FLAGS)
 am__DIST_COMMON = $(srcdir)/Makefile.in \
-	$(top_srcdir)/build-aux/depcomp
+	$(top_srcdir)/build-aux/depcomp \
+	$(top_srcdir)/build-aux/test-driver
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 ALL_LINGUAS = @ALL_LINGUAS@
 AMTAR = @AMTAR@
 AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AM_TESTS_FD_REDIRECT = @AM_TESTS_FD_REDIRECT@
 AR = @AR@
 AUTOCONF = @AUTOCONF@
 AUTOHEADER = @AUTOHEADER@
@@ -418,6 +612,7 @@ LIBTEAMDCTL_LIBS = @LIBTEAMDCTL_LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
 LN_S = @LN_S@
+LOG_DRIVER = @LOG_DRIVER@
 LTLIBICONV = @LTLIBICONV@
 LTLIBINTL = @LTLIBINTL@
 LTLIBOBJS = @LTLIBOBJS@
@@ -642,10 +837,22 @@ test_cleanup_linux_CPPFLAGS = \
 	-DKERNEL_HACKS=1
 
 test_cleanup_linux_LDADD = $(PLATFORM_LDADD)
+test_nmp_object_SOURCES = \
+	test-nmp-object.c
+
+test_nmp_object_LDADD = \
+	$(top_builddir)/src/libNetworkManager.la
+
+test_general_SOURCES = \
+	test-general.c
+
+test_general_LDADD = \
+	$(top_builddir)/src/libNetworkManager.la
+
 all: all-am
 
 .SUFFIXES:
-.SUFFIXES: .c .lo .o .obj
+.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs
 $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
 	@for dep in $?; do \
 	  case '$(am__configure_deps)' in \
@@ -713,6 +920,10 @@ test-cleanup-linux$(EXEEXT): $(test_cleanup_linux_OBJECTS) $(test_cleanup_linux_
 	@rm -f test-cleanup-linux$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(test_cleanup_linux_OBJECTS) $(test_cleanup_linux_LDADD) $(LIBS)
 
+test-general$(EXEEXT): $(test_general_OBJECTS) $(test_general_DEPENDENCIES) $(EXTRA_test_general_DEPENDENCIES) 
+	@rm -f test-general$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(test_general_OBJECTS) $(test_general_LDADD) $(LIBS)
+
 test-link-fake$(EXEEXT): $(test_link_fake_OBJECTS) $(test_link_fake_DEPENDENCIES) $(EXTRA_test_link_fake_DEPENDENCIES) 
 	@rm -f test-link-fake$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(test_link_fake_OBJECTS) $(test_link_fake_LDADD) $(LIBS)
@@ -721,6 +932,10 @@ test-link-linux$(EXEEXT): $(test_link_linux_OBJECTS) $(test_link_linux_DEPENDENC
 	@rm -f test-link-linux$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(test_link_linux_OBJECTS) $(test_link_linux_LDADD) $(LIBS)
 
+test-nmp-object$(EXEEXT): $(test_nmp_object_OBJECTS) $(test_nmp_object_DEPENDENCIES) $(EXTRA_test_nmp_object_DEPENDENCIES) 
+	@rm -f test-nmp-object$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(test_nmp_object_OBJECTS) $(test_nmp_object_LDADD) $(LIBS)
+
 test-route-fake$(EXEEXT): $(test_route_fake_OBJECTS) $(test_route_fake_DEPENDENCIES) $(EXTRA_test_route_fake_DEPENDENCIES) 
 	@rm -f test-route-fake$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(test_route_fake_OBJECTS) $(test_route_fake_LDADD) $(LIBS)
@@ -741,6 +956,8 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-linux-platform.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-platform.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/platform.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-general.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-nmp-object.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_address_fake-nm-fake-platform.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_address_fake-nm-linux-platform.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_address_fake-nm-platform.Po@am__quote@
@@ -1463,98 +1680,231 @@ cscopelist-am: $(am__tagged_files)
 distclean-tags:
 	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
 
-check-TESTS: $(TESTS)
-	@failed=0; all=0; xfail=0; xpass=0; skip=0; \
-	srcdir=$(srcdir); export srcdir; \
-	list=' $(TESTS) '; \
-	$(am__tty_colors); \
-	if test -n "$$list"; then \
-	  for tst in $$list; do \
-	    if test -f ./$$tst; then dir=./; \
-	    elif test -f $$tst; then dir=; \
-	    else dir="$(srcdir)/"; fi; \
-	    if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \
-	      all=`expr $$all + 1`; \
-	      case " $(XFAIL_TESTS) " in \
-	      *[\ \	]$$tst[\ \	]*) \
-		xpass=`expr $$xpass + 1`; \
-		failed=`expr $$failed + 1`; \
-		col=$$red; res=XPASS; \
-	      ;; \
-	      *) \
-		col=$$grn; res=PASS; \
-	      ;; \
-	      esac; \
-	    elif test $$? -ne 77; then \
-	      all=`expr $$all + 1`; \
-	      case " $(XFAIL_TESTS) " in \
-	      *[\ \	]$$tst[\ \	]*) \
-		xfail=`expr $$xfail + 1`; \
-		col=$$lgn; res=XFAIL; \
-	      ;; \
-	      *) \
-		failed=`expr $$failed + 1`; \
-		col=$$red; res=FAIL; \
-	      ;; \
-	      esac; \
-	    else \
-	      skip=`expr $$skip + 1`; \
-	      col=$$blu; res=SKIP; \
-	    fi; \
-	    echo "$${col}$$res$${std}: $$tst"; \
-	  done; \
-	  if test "$$all" -eq 1; then \
-	    tests="test"; \
-	    All=""; \
-	  else \
-	    tests="tests"; \
-	    All="All "; \
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'.  Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+	rm -f $< $@
+	$(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+	@:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+	@$(am__set_TESTS_bases); \
+	am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+	redo_bases=`for i in $$bases; do \
+	              am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+	            done`; \
+	if test -n "$$redo_bases"; then \
+	  redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+	  redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+	  if $(am__make_dryrun); then :; else \
+	    rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
 	  fi; \
-	  if test "$$failed" -eq 0; then \
-	    if test "$$xfail" -eq 0; then \
-	      banner="$$All$$all $$tests passed"; \
-	    else \
-	      if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
-	      banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
-	    fi; \
-	  else \
-	    if test "$$xpass" -eq 0; then \
-	      banner="$$failed of $$all $$tests failed"; \
+	fi; \
+	if test -n "$$am__remaking_logs"; then \
+	  echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+	       "recursion detected" >&2; \
+	elif test -n "$$redo_logs"; then \
+	  am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+	fi; \
+	if $(am__make_dryrun); then :; else \
+	  st=0;  \
+	  errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+	  for i in $$redo_bases; do \
+	    test -f $$i.trs && test -r $$i.trs \
+	      || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+	    test -f $$i.log && test -r $$i.log \
+	      || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+	  done; \
+	  test $$st -eq 0 || exit 1; \
+	fi
+	@$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+	ws='[ 	]'; \
+	results=`for b in $$bases; do echo $$b.trs; done`; \
+	test -n "$$results" || results=/dev/null; \
+	all=`  grep "^$$ws*:test-result:"           $$results | wc -l`; \
+	pass=` grep "^$$ws*:test-result:$$ws*PASS"  $$results | wc -l`; \
+	fail=` grep "^$$ws*:test-result:$$ws*FAIL"  $$results | wc -l`; \
+	skip=` grep "^$$ws*:test-result:$$ws*SKIP"  $$results | wc -l`; \
+	xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+	xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+	error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+	if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+	  success=true; \
+	else \
+	  success=false; \
+	fi; \
+	br='==================='; br=$$br$$br$$br$$br; \
+	result_count () \
+	{ \
+	    if test x"$$1" = x"--maybe-color"; then \
+	      maybe_colorize=yes; \
+	    elif test x"$$1" = x"--no-color"; then \
+	      maybe_colorize=no; \
 	    else \
-	      if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
-	      banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+	      echo "$@: invalid 'result_count' usage" >&2; exit 4; \
 	    fi; \
-	  fi; \
-	  dashes="$$banner"; \
-	  skipped=""; \
-	  if test "$$skip" -ne 0; then \
-	    if test "$$skip" -eq 1; then \
-	      skipped="($$skip test was not run)"; \
+	    shift; \
+	    desc=$$1 count=$$2; \
+	    if test $$maybe_colorize = yes && test $$count -gt 0; then \
+	      color_start=$$3 color_end=$$std; \
 	    else \
-	      skipped="($$skip tests were not run)"; \
+	      color_start= color_end=; \
 	    fi; \
-	    test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
-	      dashes="$$skipped"; \
-	  fi; \
-	  report=""; \
-	  if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
-	    report="Please report to $(PACKAGE_BUGREPORT)"; \
-	    test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
-	      dashes="$$report"; \
-	  fi; \
-	  dashes=`echo "$$dashes" | sed s/./=/g`; \
-	  if test "$$failed" -eq 0; then \
-	    col="$$grn"; \
-	  else \
-	    col="$$red"; \
-	  fi; \
-	  echo "$${col}$$dashes$${std}"; \
-	  echo "$${col}$$banner$${std}"; \
-	  test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \
-	  test -z "$$report" || echo "$${col}$$report$${std}"; \
-	  echo "$${col}$$dashes$${std}"; \
-	  test "$$failed" -eq 0; \
-	else :; fi
+	    echo "$${color_start}# $$desc $$count$${color_end}"; \
+	}; \
+	create_testsuite_report () \
+	{ \
+	  result_count $$1 "TOTAL:" $$all   "$$brg"; \
+	  result_count $$1 "PASS: " $$pass  "$$grn"; \
+	  result_count $$1 "SKIP: " $$skip  "$$blu"; \
+	  result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+	  result_count $$1 "FAIL: " $$fail  "$$red"; \
+	  result_count $$1 "XPASS:" $$xpass "$$red"; \
+	  result_count $$1 "ERROR:" $$error "$$mgn"; \
+	}; \
+	{								\
+	  echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" |	\
+	    $(am__rst_title);						\
+	  create_testsuite_report --no-color;				\
+	  echo;								\
+	  echo ".. contents:: :depth: 2";				\
+	  echo;								\
+	  for b in $$bases; do echo $$b; done				\
+	    | $(am__create_global_log);					\
+	} >$(TEST_SUITE_LOG).tmp || exit 1;				\
+	mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG);			\
+	if $$success; then						\
+	  col="$$grn";							\
+	 else								\
+	  col="$$red";							\
+	  test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG);		\
+	fi;								\
+	echo "$${col}$$br$${std}"; 					\
+	echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}";	\
+	echo "$${col}$$br$${std}"; 					\
+	create_testsuite_report --maybe-color;				\
+	echo "$$col$$br$$std";						\
+	if $$success; then :; else					\
+	  echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}";		\
+	  if test -n "$(PACKAGE_BUGREPORT)"; then			\
+	    echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}";	\
+	  fi;								\
+	  echo "$$col$$br$$std";					\
+	fi;								\
+	$$success || exit 1
+
+check-TESTS:
+	@list='$(RECHECK_LOGS)';           test -z "$$list" || rm -f $$list
+	@list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+	log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+	exit $$?;
+recheck: all 
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	bases=`for i in $$bases; do echo $$i; done \
+	         | $(am__list_recheck_tests)` || exit 1; \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	log_list=`echo $$log_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+	        am__force_recheck=am--force-recheck \
+	        TEST_LOGS="$$log_list"; \
+	exit $$?
+test-address-fake.log: test-address-fake$(EXEEXT)
+	@p='test-address-fake$(EXEEXT)'; \
+	b='test-address-fake'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+test-address-linux.log: test-address-linux$(EXEEXT)
+	@p='test-address-linux$(EXEEXT)'; \
+	b='test-address-linux'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+test-cleanup-fake.log: test-cleanup-fake$(EXEEXT)
+	@p='test-cleanup-fake$(EXEEXT)'; \
+	b='test-cleanup-fake'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+test-cleanup-linux.log: test-cleanup-linux$(EXEEXT)
+	@p='test-cleanup-linux$(EXEEXT)'; \
+	b='test-cleanup-linux'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+test-general.log: test-general$(EXEEXT)
+	@p='test-general$(EXEEXT)'; \
+	b='test-general'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+test-link-fake.log: test-link-fake$(EXEEXT)
+	@p='test-link-fake$(EXEEXT)'; \
+	b='test-link-fake'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+test-link-linux.log: test-link-linux$(EXEEXT)
+	@p='test-link-linux$(EXEEXT)'; \
+	b='test-link-linux'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+test-nmp-object.log: test-nmp-object$(EXEEXT)
+	@p='test-nmp-object$(EXEEXT)'; \
+	b='test-nmp-object'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+test-route-fake.log: test-route-fake$(EXEEXT)
+	@p='test-route-fake$(EXEEXT)'; \
+	b='test-route-fake'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+test-route-linux.log: test-route-linux$(EXEEXT)
+	@p='test-route-linux$(EXEEXT)'; \
+	b='test-route-linux'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+	@p='$<'; \
+	$(am__set_b); \
+	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@	@p='$<'; \
+@am__EXEEXT_TRUE@	$(am__set_b); \
+@am__EXEEXT_TRUE@	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@	--log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@	"$$tst" $(AM_TESTS_FD_REDIRECT)
 
 distdir: $(DISTFILES)
 	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
@@ -1611,6 +1961,9 @@ install-strip:
 	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
 	fi
 mostlyclean-generic:
+	-test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+	-test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+	-test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
 
 clean-generic:
 
@@ -1706,7 +2059,7 @@ uninstall-am:
 	installcheck-am installdirs maintainer-clean \
 	maintainer-clean-generic mostlyclean mostlyclean-compile \
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
-	tags tags-am uninstall uninstall-am
+	recheck tags tags-am uninstall uninstall-am
 
 .PRECIOUS: Makefile
 
diff --git a/src/platform/tests/dump.c b/src/platform/tests/dump.c
index 3bb61da4..54de1da7 100644
--- a/src/platform/tests/dump.c
+++ b/src/platform/tests/dump.c
@@ -7,6 +7,7 @@
 #include "nm-platform.h"
 #include "nm-linux-platform.h"
 #include "nm-fake-platform.h"
+#include "nm-macros-internal.h"
 
 static void
 dump_interface (NMPlatformLink *link)
@@ -26,14 +27,14 @@ dump_interface (NMPlatformLink *link)
 	size_t addrlen;
 	int i;
 
-	g_assert (link->up || !link->connected);
+	g_assert (NM_FLAGS_HAS (link->flags, IFF_UP) || !link->connected);
 
-	printf ("%d: %s: %s", link->ifindex, link->name, link->type_name);
-	if (link->up)
+	printf ("%d: %s: %s", link->ifindex, link->name, nm_link_type_to_string (link->type));
+	if (NM_FLAGS_HAS (link->flags, IFF_UP))
 		printf (" %s", link->connected ? "CONNECTED" : "DISCONNECTED");
 	else
 		printf (" DOWN");
-	if (!link->arp)
+	if (NM_FLAGS_HAS (link->flags, IFF_NOARP))
 		printf (" noarp");
 	if (link->master)
 		printf (" master %d", link->master);
@@ -43,22 +44,22 @@ dump_interface (NMPlatformLink *link)
 	printf ("\n");
 	if (link->driver)
 		printf ("    driver: %s\n", link->driver);
-	printf ("    UDI: %s\n", link->udi);
-	if (!nm_platform_vlan_get_info (link->ifindex, &vlan_parent, &vlan_id))
+	printf ("    UDI: %s\n", nm_platform_link_get_udi (NM_PLATFORM_GET, link->ifindex));
+	if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, link->ifindex, &vlan_parent, &vlan_id))
 		g_assert_not_reached ();
 	if (vlan_parent)
 		printf ("    vlan parent %d id %d\n", vlan_parent, vlan_id);
 
-	if (nm_platform_link_is_software (link->ifindex))
+	if (nm_platform_link_is_software (NM_PLATFORM_GET, link->ifindex))
 		printf ("    class software\n");
-	if (nm_platform_link_supports_slaves (link->ifindex))
+	if (nm_platform_link_supports_slaves (NM_PLATFORM_GET, link->ifindex))
 		printf ("    class supports-slaves\n");
-	if (nm_platform_link_supports_carrier_detect (link->ifindex))
+	if (nm_platform_link_supports_carrier_detect (NM_PLATFORM_GET, link->ifindex))
 		printf ("    feature carrier-detect\n");
-	if (nm_platform_link_supports_vlans (link->ifindex))
+	if (nm_platform_link_supports_vlans (NM_PLATFORM_GET, link->ifindex))
 		printf ("    feature vlans\n");
 
-	address = nm_platform_link_get_address (link->ifindex, &addrlen);
+	address = nm_platform_link_get_address (NM_PLATFORM_GET, link->ifindex, &addrlen);
 	if (address) {
 		printf ("    link-address ");
 		for (i = 0; i < addrlen; i++)
@@ -66,8 +67,8 @@ dump_interface (NMPlatformLink *link)
 		printf ("\n");
 	}
 
-	ip4_addresses = nm_platform_ip4_address_get_all (link->ifindex);
-	ip6_addresses = nm_platform_ip6_address_get_all (link->ifindex);
+	ip4_addresses = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, link->ifindex);
+	ip6_addresses = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, link->ifindex);
 
 	g_assert (ip4_addresses);
 	g_assert (ip6_addresses);
@@ -85,8 +86,8 @@ dump_interface (NMPlatformLink *link)
 	g_array_unref (ip4_addresses);
 	g_array_unref (ip6_addresses);
 
-	ip4_routes = nm_platform_ip4_route_get_all (link->ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
-	ip6_routes = nm_platform_ip6_route_get_all (link->ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
+	ip4_routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, link->ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
+	ip6_routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, link->ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
 
 	g_assert (ip4_routes);
 	g_assert (ip6_routes);
@@ -112,7 +113,7 @@ dump_interface (NMPlatformLink *link)
 static void
 dump_all (void)
 {
-	GArray *links = nm_platform_link_get_all ();
+	GArray *links = nm_platform_link_get_all (NM_PLATFORM_GET);
 	int i;
 
 	for (i = 0; i < links->len; i++)
diff --git a/src/platform/tests/platform.c b/src/platform/tests/platform.c
index eea6610d..24e828c1 100644
--- a/src/platform/tests/platform.c
+++ b/src/platform/tests/platform.c
@@ -44,13 +44,13 @@ typedef const char *string_t;
 static gboolean
 do_sysctl_set (char **argv)
 {
-	return nm_platform_sysctl_set (argv[0], argv[1]);
+	return nm_platform_sysctl_set (NM_PLATFORM_GET, argv[0], argv[1]);
 }
 
 static gboolean
 do_sysctl_get (char **argv)
 {
-	gs_free char *value = nm_platform_sysctl_get (argv[0]);
+	gs_free char *value = nm_platform_sysctl_get (NM_PLATFORM_GET, argv[0]);
 
 	printf ("%s\n", value);
 
@@ -66,7 +66,7 @@ parse_ifindex (const char *str)
 	ifindex = strtol (str, &endptr, 10);
 
 	if (*endptr) {
-		ifindex = nm_platform_link_get_ifindex (str);
+		ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, str);
 	}
 
 	return ifindex;
@@ -79,7 +79,7 @@ do_link_get_all (char **argv)
 	NMPlatformLink *device;
 	int i;
 
-	links = nm_platform_link_get_all ();
+	links = nm_platform_link_get_all (NM_PLATFORM_GET);
 	for (i = 0; i < links->len; i++) {
 		device = &g_array_index (links, NMPlatformLink, i);
 
@@ -93,25 +93,25 @@ do_link_get_all (char **argv)
 static gboolean
 do_dummy_add (char **argv)
 {
-	return nm_platform_dummy_add (argv[0]);
+	return nm_platform_dummy_add (NM_PLATFORM_GET, argv[0], NULL) == NM_PLATFORM_ERROR_SUCCESS;
 }
 
 static gboolean
 do_bridge_add (char **argv)
 {
-	return nm_platform_bridge_add (argv[0], NULL, 0);
+	return nm_platform_bridge_add (NM_PLATFORM_GET, argv[0], NULL, 0, NULL) == NM_PLATFORM_ERROR_SUCCESS;
 }
 
 static gboolean
 do_bond_add (char **argv)
 {
-	return nm_platform_bond_add (argv[0]);
+	return nm_platform_bond_add (NM_PLATFORM_GET, argv[0], NULL) == NM_PLATFORM_ERROR_SUCCESS;
 }
 
 static gboolean
 do_team_add (char **argv)
 {
-	return nm_platform_team_add (argv[0]);
+	return nm_platform_team_add (NM_PLATFORM_GET, argv[0], NULL) == NM_PLATFORM_ERROR_SUCCESS;
 }
 
 static gboolean
@@ -122,13 +122,13 @@ do_vlan_add (char **argv)
 	int vlanid = strtol (*argv++, NULL, 10);
 	guint32 vlan_flags = strtol (*argv++, NULL, 10);
 
-	return nm_platform_vlan_add (name, parent, vlanid, vlan_flags);
+	return nm_platform_vlan_add (NM_PLATFORM_GET, name, parent, vlanid, vlan_flags, NULL) == NM_PLATFORM_ERROR_SUCCESS;
 }
 
 static gboolean
 do_link_exists (char **argv)
 {
-	gboolean value = nm_platform_link_exists (argv[0]);
+	gboolean value = !!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, argv[0]);
 
 	print_boolean (value);
 
@@ -140,7 +140,7 @@ do_link_exists (char **argv)
 	do_link_##cmdname (char **argv) \
 	{ \
 		int ifindex = parse_ifindex (argv[0]); \
-		return ifindex ? nm_platform_link_##cmdname (ifindex) : FALSE; \
+		return ifindex ? nm_platform_link_##cmdname (NM_PLATFORM_GET, ifindex) : FALSE; \
 	}
 
 #define LINK_CMD_GET_FULL(cmdname, type, cond) \
@@ -149,7 +149,7 @@ do_link_exists (char **argv)
 	{ \
 		int ifindex = parse_ifindex (argv[0]); \
 		if (ifindex) { \
-			type##_t value = nm_platform_link_##cmdname (ifindex); \
+			type##_t value = nm_platform_link_##cmdname (NM_PLATFORM_GET, ifindex); \
 			if (cond) { \
 				print_##type (value); \
 				return TRUE; \
@@ -169,7 +169,7 @@ LINK_CMD (delete)
 static gboolean
 do_link_get_ifindex (char **argv)
 {
-	int ifindex = nm_platform_link_get_ifindex (argv[0]);
+	int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, argv[0]);
 
 	if (ifindex)
 		printf ("%d\n", ifindex);
@@ -182,7 +182,14 @@ LINK_CMD_GET_FULL (get_type, decimal, value > 0)
 LINK_CMD_GET (is_software, boolean)
 LINK_CMD_GET (supports_slaves, boolean)
 
-LINK_CMD (set_up)
+static gboolean
+do_link_set_up (char **argv)
+{
+	int ifindex = parse_ifindex (argv[0]);
+
+	return ifindex ? nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, NULL) : FALSE;
+}
+
 LINK_CMD (set_down)
 LINK_CMD (set_arp)
 LINK_CMD (set_noarp)
@@ -213,7 +220,7 @@ do_link_set_address (char **argv)
 		g_assert (!*endptr);
 	}
 
-	return nm_platform_link_set_address (ifindex, address, sizeof (address));
+	return nm_platform_link_set_address (NM_PLATFORM_GET, ifindex, address, sizeof (address));
 }
 
 static gboolean
@@ -224,7 +231,7 @@ do_link_get_address (char **argv)
 	size_t length;
 	int i;
 
-	address = nm_platform_link_get_address (ifindex, &length);
+	address = nm_platform_link_get_address (NM_PLATFORM_GET, ifindex, &length);
 
 	if (!address || length <= 0)
 		return FALSE;
@@ -242,7 +249,7 @@ do_link_set_mtu (char **argv)
 	int ifindex = parse_ifindex (*argv++);
 	int mtu = strtoul (*argv++, NULL, 10);
 
-	return nm_platform_link_set_mtu (ifindex, mtu);
+	return nm_platform_link_set_mtu (NM_PLATFORM_GET, ifindex, mtu);
 }
 
 LINK_CMD_GET (get_mtu, decimal);
@@ -255,7 +262,7 @@ do_link_enslave (char **argv)
 	int master = parse_ifindex (*argv++);
 	int slave = parse_ifindex (*argv++);
 
-	return nm_platform_link_enslave (master, slave);
+	return nm_platform_link_enslave (NM_PLATFORM_GET, master, slave);
 }
 
 static gboolean
@@ -264,7 +271,7 @@ do_link_release (char **argv)
 	int master = parse_ifindex (*argv++);
 	int slave = parse_ifindex (*argv++);
 
-	return nm_platform_link_release (master, slave);
+	return nm_platform_link_release (NM_PLATFORM_GET, master, slave);
 }
 
 LINK_CMD_GET (get_master, decimal)
@@ -276,7 +283,7 @@ do_master_set_option (char **argv)
 	const char *option = *argv++;
 	const char *value = *argv++;
 
-	return nm_platform_master_set_option (ifindex, option, value);
+	return nm_platform_master_set_option (NM_PLATFORM_GET, ifindex, option, value);
 }
 
 static gboolean
@@ -284,7 +291,7 @@ do_master_get_option (char **argv)
 {
 	int ifindex = parse_ifindex (*argv++);
 	const char *option = *argv++;
-	gs_free char *value = nm_platform_master_get_option (ifindex, option);
+	gs_free char *value = nm_platform_master_get_option (NM_PLATFORM_GET, ifindex, option);
 
 	printf ("%s\n", value);
 
@@ -298,7 +305,7 @@ do_slave_set_option (char **argv)
 	const char *option = *argv++;
 	const char *value = *argv++;
 
-	return nm_platform_slave_set_option (ifindex, option, value);
+	return nm_platform_slave_set_option (NM_PLATFORM_GET, ifindex, option, value);
 }
 
 static gboolean
@@ -306,7 +313,7 @@ do_slave_get_option (char **argv)
 {
 	int ifindex = parse_ifindex (*argv++);
 	const char *option = *argv++;
-	gs_free char *value = nm_platform_slave_get_option (ifindex, option);
+	gs_free char *value = nm_platform_slave_get_option (NM_PLATFORM_GET, ifindex, option);
 
 	printf ("%s\n", value);
 
@@ -320,7 +327,7 @@ do_vlan_get_info (char **argv)
 	int parent;
 	int vlanid;
 
-	if (!nm_platform_vlan_get_info (ifindex, &parent, &vlanid))
+	if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, ifindex, &parent, &vlanid))
 		return FALSE;
 
 	printf ("%d %d\n", parent, vlanid);
@@ -335,7 +342,7 @@ do_vlan_set_ingress_map (char **argv)
 	int from = strtol (*argv++, NULL, 10);
 	int to = strtol (*argv++, NULL, 10);
 
-	return nm_platform_vlan_set_ingress_map (ifindex, from, to);
+	return nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, from, to);
 }
 
 static gboolean
@@ -345,7 +352,7 @@ do_vlan_set_egress_map (char **argv)
 	int from = strtol (*argv++, NULL, 10);
 	int to = strtol (*argv++, NULL, 10);
 
-	return nm_platform_vlan_set_egress_map (ifindex, from, to);
+	return nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, from, to);
 }
 
 static gboolean
@@ -354,7 +361,7 @@ do_veth_get_properties (char **argv)
 	int ifindex = parse_ifindex (*argv++);
 	NMPlatformVethProperties props;
 
-	if (!nm_platform_veth_get_properties (ifindex, &props))
+	if (!nm_platform_veth_get_properties (NM_PLATFORM_GET, ifindex, &props))
 		return FALSE;
 
 	printf ("peer: %d\n", props.peer);
@@ -368,7 +375,7 @@ do_tun_get_properties (char **argv)
 	int ifindex = parse_ifindex (*argv++);
 	NMPlatformTunProperties props;
 
-	if (!nm_platform_tun_get_properties (ifindex, &props))
+	if (!nm_platform_tun_get_properties (NM_PLATFORM_GET, ifindex, &props))
 		return FALSE;
 
 	printf ("mode: %s\n", props.mode);
@@ -396,7 +403,7 @@ do_macvlan_get_properties (char **argv)
 	int ifindex = parse_ifindex (*argv++);
 	NMPlatformMacvlanProperties props;
 
-	if (!nm_platform_macvlan_get_properties (ifindex, &props))
+	if (!nm_platform_macvlan_get_properties (NM_PLATFORM_GET, ifindex, &props))
 		return FALSE;
 
 	printf ("parent: %d\n", props.parent_ifindex);
@@ -413,7 +420,7 @@ do_vxlan_get_properties (char **argv)
 	NMPlatformVxlanProperties props;
 	char addrstr[INET6_ADDRSTRLEN];
 
-	if (!nm_platform_vxlan_get_properties (ifindex, &props))
+	if (!nm_platform_vxlan_get_properties (NM_PLATFORM_GET, ifindex, &props))
 		return FALSE;
 
 	printf ("parent-ifindex: %u\n", props.parent_ifindex);
@@ -460,7 +467,7 @@ do_gre_get_properties (char **argv)
 	NMPlatformGreProperties props;
 	char addrstr[INET_ADDRSTRLEN];
 
-	if (!nm_platform_gre_get_properties (ifindex, &props))
+	if (!nm_platform_gre_get_properties (NM_PLATFORM_GET, ifindex, &props))
 		return FALSE;
 
 	printf ("parent-ifindex: %u\n", props.parent_ifindex);
@@ -496,7 +503,7 @@ do_ip4_address_get_all (char **argv)
 	int i;
 
 	if (ifindex) {
-		addresses = nm_platform_ip4_address_get_all (ifindex);
+		addresses = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex);
 		for (i = 0; i < addresses->len; i++) {
 			address = &g_array_index (addresses, NMPlatformIP4Address, i);
 			inet_ntop (AF_INET, &address->address, addrstr, sizeof (addrstr));
@@ -518,7 +525,7 @@ do_ip6_address_get_all (char **argv)
 	int i;
 
 	if (ifindex) {
-		addresses = nm_platform_ip6_address_get_all (ifindex);
+		addresses = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex);
 		for (i = 0; i < addresses->len; i++) {
 			address = &g_array_index (addresses, NMPlatformIP6Address, i);
 			inet_ntop (AF_INET6, &address->address, addrstr, sizeof (addrstr));
@@ -576,7 +583,7 @@ do_ip4_address_add (char **argv)
 		guint32 lifetime = strtol (*argv++, NULL, 10);
 		guint32 preferred = strtol (*argv++, NULL, 10);
 
-		gboolean value = nm_platform_ip4_address_add (ifindex, address, 0, plen, lifetime, preferred, NULL);
+		gboolean value = nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, address, 0, plen, lifetime, preferred, NULL);
 		return value;
 	} else
 		return FALSE;
@@ -594,7 +601,7 @@ do_ip6_address_add (char **argv)
 		guint32 preferred = strtol (*argv++, NULL, 10);
 		guint flags = (*argv) ? rtnl_addr_str2flags (*argv++) : 0;
 
-		gboolean value = nm_platform_ip6_address_add (ifindex, address, in6addr_any, plen, lifetime, preferred, flags);
+		gboolean value = nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, address, in6addr_any, plen, lifetime, preferred, flags);
 		return value;
 	} else
 		return FALSE;
@@ -608,7 +615,7 @@ do_ip6_address_add (char **argv)
 		v##_t address; \
 		int plen; \
 		if (ifindex && parse_##v##_address (*argv++, &address, &plen)) { \
-			gboolean value = nm_platform_##v##_address_##cmdname (ifindex, address, plen, ##__VA_ARGS__); \
+			gboolean value = !!nm_platform_##v##_address_##cmdname (NM_PLATFORM_GET, ifindex, address, plen, ##__VA_ARGS__); \
 			if (print) { \
 				print_boolean (value); \
 				return TRUE; \
@@ -621,7 +628,7 @@ do_ip6_address_add (char **argv)
 #define ADDR_CMD_PRINT(cmdname) ADDR_CMD_FULL (ip4, cmdname, TRUE) ADDR_CMD_FULL (ip6, cmdname, TRUE)
 
 ADDR_CMD (delete)
-ADDR_CMD_PRINT (exists)
+ADDR_CMD_PRINT (get)
 
 static gboolean
 do_ip4_route_get_all (char **argv)
@@ -633,7 +640,7 @@ do_ip4_route_get_all (char **argv)
 	int i;
 
 	if (ifindex) {
-		routes = nm_platform_ip4_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
+		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);
 		for (i = 0; i < routes->len; i++) {
 			route = &g_array_index (routes, NMPlatformIP4Route, i);
 			inet_ntop (AF_INET, &route->network, networkstr, sizeof (networkstr));
@@ -657,7 +664,7 @@ do_ip6_route_get_all (char **argv)
 	int i;
 
 	if (ifindex) {
-		routes = nm_platform_ip6_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
+		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);
 		for (i = 0; i < routes->len; i++) {
 			route = &g_array_index (routes, NMPlatformIP6Route, i);
 			inet_ntop (AF_INET6, &route->network, networkstr, sizeof (networkstr));
@@ -683,7 +690,7 @@ do_ip4_route_add (char **argv)
 	metric = strtol (*argv++, NULL, 10);
 	mss = strtol (*argv++, NULL, 10);
 
-	return nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER,
+	return nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER,
 	                                  network, plen, gateway, 0,
 	                                  metric, mss);
 }
@@ -699,7 +706,7 @@ do_ip6_route_add (char **argv)
 	parse_ip6_address (*argv++, &gateway, NULL);
 	metric = strtol (*argv++, NULL, 10);
 	mss = strtol (*argv++, NULL, 10);
-	return nm_platform_ip6_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER,
+	return nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER,
 	                                  network, plen, gateway,
 	                                  metric, mss);
 }
@@ -714,7 +721,7 @@ do_ip4_route_delete (char **argv)
 	parse_ip4_address (*argv++, &network, &plen);
 	metric = strtol (*argv++, NULL, 10);
 
-	return nm_platform_ip4_route_delete (ifindex, network, plen, metric);
+	return nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric);
 }
 
 static gboolean
@@ -727,11 +734,11 @@ do_ip6_route_delete (char **argv)
 	parse_ip6_address (*argv++, &network, &plen);
 	metric = strtol (*argv++, NULL, 10);
 
-	return nm_platform_ip6_route_delete (ifindex, network, plen, metric);
+	return nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric);
 }
 
 static gboolean
-do_ip4_route_exists (char **argv)
+do_ip4_route_get (char **argv)
 {
 	int ifindex = parse_ifindex (*argv++);
 	in_addr_t network;
@@ -740,12 +747,12 @@ do_ip4_route_exists (char **argv)
 	parse_ip4_address (*argv++, &network, &plen);
 	metric = strtol (*argv++, NULL, 10);
 
-	print_boolean (nm_platform_ip4_route_exists (ifindex, network, plen, metric));
+	print_boolean (!!nm_platform_ip4_route_get (NM_PLATFORM_GET, ifindex, network, plen, metric));
 	return TRUE;
 }
 
 static gboolean
-do_ip6_route_exists (char **argv)
+do_ip6_route_get (char **argv)
 {
 	int ifindex = parse_ifindex (*argv++);
 	struct in6_addr network;
@@ -754,7 +761,7 @@ do_ip6_route_exists (char **argv)
 	parse_ip6_address (*argv++, &network, &plen);
 	metric = strtol (*argv++, NULL, 10);
 
-	print_boolean (nm_platform_ip6_route_exists (ifindex, network, plen, metric));
+	print_boolean (!!nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, network, plen, metric));
 	return TRUE;
 }
 
@@ -831,9 +838,9 @@ static const command_t commands[] = {
 		"<ifname/ifindex> <address>/<plen>" },
 	{ "ip6-address-delete", "delete IPv6 address", do_ip6_address_delete, 2,
 		"<ifname/ifindex> <address>/<plen>" },
-	{ "ip4-address-exists", "check for existence of IPv4 address", do_ip4_address_exists, 2,
+	{ "ip4-address-exists", "check for existence of IPv4 address", do_ip4_address_get, 2,
 		"<ifname/ifindex> <address>/<plen>" },
-	{ "ip6-address-exists", "check for existence of IPv6 address", do_ip6_address_exists, 2,
+	{ "ip6-address-exists", "check for existence of IPv6 address", do_ip6_address_get, 2,
 		"<ifname/ifindex> <address>/<plen>" },
 	{ "ip4-route-get-all", "print all IPv4 routes", do_ip4_route_get_all, 1, "<ifname/ifindex>" },
 	{ "ip6-route-get-all", "print all IPv6 routes", do_ip6_route_get_all, 1, "<ifname/ifindex>" },
@@ -845,9 +852,9 @@ static const command_t commands[] = {
 		"<ifname/ifindex> <network>/<plen> <metric>" },
 	{ "ip6-route-delete", "delete IPv6 route", do_ip6_route_delete, 3,
 		"<ifname/ifindex> <network>/<plen> <metric>" },
-	{ "ip4-route-exists", "check for existence of IPv4 route", do_ip4_route_exists, 3,
+	{ "ip4-route-exists", "check for existence of IPv4 route", do_ip4_route_get, 3,
 		"<ifname/ifindex> <network>/<plen> <metric>" },
-	{ "ip6-route-exists", "check for existence of IPv6 route", do_ip6_route_exists, 3,
+	{ "ip6-route-exists", "check for existence of IPv6 route", do_ip6_route_get, 3,
 		"<ifname/ifindex> <network>/<plen> <metric>" },
 	{ NULL, NULL, NULL, 0, NULL },
 };
@@ -858,7 +865,6 @@ main (int argc, char **argv)
 	const char *arg0 = *argv++;
 	const command_t *command = NULL;
 	gboolean status = TRUE;
-	int error;
 
 #if !GLIB_CHECK_VERSION (2, 35, 0)
 	g_type_init ();
@@ -892,12 +898,5 @@ main (int argc, char **argv)
 		error ("\n");
 	}
 
-	error = nm_platform_get_error ();
-	if (error) {
-		const char *msg = nm_platform_get_error_msg ();
-
-		error ("nm-platform: %s\n", msg);
-	}
-
-	return !!error;
+	return EXIT_SUCCESS;
 }
diff --git a/src/platform/tests/test-address.c b/src/platform/tests/test-address.c
index 5561038d..d6f346b3 100644
--- a/src/platform/tests/test-address.c
+++ b/src/platform/tests/test-address.c
@@ -9,7 +9,7 @@
 #define IP6_PLEN 64
 
 static void
-ip4_address_callback (NMPlatform *platform, int ifindex, NMPlatformIP4Address *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data)
+ip4_address_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPlatformIP4Address *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data)
 {
 	g_assert (received);
 	g_assert_cmpint (received->ifindex, ==, ifindex);
@@ -24,14 +24,12 @@ ip4_address_callback (NMPlatform *platform, int ifindex, NMPlatformIP4Address *r
 	if (data->loop)
 		g_main_loop_quit (data->loop);
 
-	if (data->received)
-		g_error ("Received signal '%s' a second time.", data->name);
-
-	data->received = TRUE;
+	data->received_count++;
+	debug ("Received signal '%s' %dth time.", data->name, data->received_count);
 }
 
 static void
-ip6_address_callback (NMPlatform *platform, int ifindex, NMPlatformIP6Address *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data)
+ip6_address_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPlatformIP6Address *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data)
 {
 	g_assert (received);
 	g_assert_cmpint (received->ifindex, ==, ifindex);
@@ -46,16 +44,14 @@ ip6_address_callback (NMPlatform *platform, int ifindex, NMPlatformIP6Address *r
 	if (data->loop)
 		g_main_loop_quit (data->loop);
 
-	if (data->received)
-		g_error ("Received signal '%s' a second time.", data->name);
-
-	data->received = TRUE;
+	data->received_count++;
+	debug ("Received signal '%s' %dth time.", data->name, data->received_count);
 }
 
 static void
 test_ip4_address (void)
 {
-	int ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
+	int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
 	SignalData *address_added = add_signal_ifindex (NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip4_address_callback, ifindex);
 	SignalData *address_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, ip4_address_callback, ifindex);
 	SignalData *address_removed = add_signal_ifindex (NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip4_address_callback, ifindex);
@@ -68,23 +64,18 @@ test_ip4_address (void)
 	inet_pton (AF_INET, IP4_ADDRESS, &addr);
 
 	/* Add address */
-	g_assert (!nm_platform_ip4_address_exists (ifindex, addr, IP4_PLEN));
-	no_error ();
-	g_assert (nm_platform_ip4_address_add (ifindex, addr, 0, IP4_PLEN, lifetime, preferred, NULL));
-	no_error ();
-	g_assert (nm_platform_ip4_address_exists (ifindex, addr, IP4_PLEN));
-	no_error ();
+	g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN));
+	g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr, 0, IP4_PLEN, lifetime, preferred, NULL));
+	g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN));
 	accept_signal (address_added);
 
 	/* Add address again (aka update) */
-	g_assert (nm_platform_ip4_address_add (ifindex, addr, 0, IP4_PLEN, lifetime, preferred, NULL));
-	no_error ();
-	accept_signal (address_changed);
+	g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr, 0, IP4_PLEN, lifetime, preferred, NULL));
+	accept_signals (address_changed, 0, 1);
 
 	/* Test address listing */
-	addresses = nm_platform_ip4_address_get_all (ifindex);
+	addresses = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex);
 	g_assert (addresses);
-	no_error ();
 	g_assert_cmpint (addresses->len, ==, 1);
 	address = &g_array_index (addresses, NMPlatformIP4Address, 0);
 	g_assert_cmpint (address->ifindex, ==, ifindex);
@@ -93,14 +84,12 @@ test_ip4_address (void)
 	g_array_unref (addresses);
 
 	/* Remove address */
-	g_assert (nm_platform_ip4_address_delete (ifindex, addr, IP4_PLEN, 0));
-	no_error ();
-	g_assert (!nm_platform_ip4_address_exists (ifindex, addr, IP4_PLEN));
+	g_assert (nm_platform_ip4_address_delete (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0));
+	g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN));
 	accept_signal (address_removed);
 
 	/* Remove address again */
-	g_assert (nm_platform_ip4_address_delete (ifindex, addr, IP4_PLEN, 0));
-	no_error ();
+	g_assert (nm_platform_ip4_address_delete (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0));
 
 	free_signal (address_added);
 	free_signal (address_changed);
@@ -110,7 +99,7 @@ test_ip4_address (void)
 static void
 test_ip6_address (void)
 {
-	int ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
+	int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
 	SignalData *address_added = add_signal_ifindex (NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip6_address_callback, ifindex);
 	SignalData *address_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, ip6_address_callback, ifindex);
 	SignalData *address_removed = add_signal_ifindex (NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip6_address_callback, ifindex);
@@ -124,23 +113,18 @@ test_ip6_address (void)
 	inet_pton (AF_INET6, IP6_ADDRESS, &addr);
 
 	/* Add address */
-	g_assert (!nm_platform_ip6_address_exists (ifindex, addr, IP6_PLEN));
-	no_error ();
-	g_assert (nm_platform_ip6_address_add (ifindex, addr, in6addr_any, IP6_PLEN, lifetime, preferred, flags));
-	no_error ();
-	g_assert (nm_platform_ip6_address_exists (ifindex, addr, IP6_PLEN));
-	no_error ();
+	g_assert (!nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN));
+	g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr, in6addr_any, IP6_PLEN, lifetime, preferred, flags));
+	g_assert (nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN));
 	accept_signal (address_added);
 
 	/* Add address again (aka update) */
-	g_assert (nm_platform_ip6_address_add (ifindex, addr, in6addr_any, IP6_PLEN, lifetime, preferred, flags));
-	no_error ();
-	accept_signal (address_changed);
+	g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr, in6addr_any, IP6_PLEN, lifetime, preferred, flags));
+	accept_signals (address_changed, 0, 1);
 
 	/* Test address listing */
-	addresses = nm_platform_ip6_address_get_all (ifindex);
+	addresses = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex);
 	g_assert (addresses);
-	no_error ();
 	g_assert_cmpint (addresses->len, ==, 1);
 	address = &g_array_index (addresses, NMPlatformIP6Address, 0);
 	g_assert_cmpint (address->ifindex, ==, ifindex);
@@ -149,14 +133,12 @@ test_ip6_address (void)
 	g_array_unref (addresses);
 
 	/* Remove address */
-	g_assert (nm_platform_ip6_address_delete (ifindex, addr, IP6_PLEN));
-	no_error ();
-	g_assert (!nm_platform_ip6_address_exists (ifindex, addr, IP6_PLEN));
+	g_assert (nm_platform_ip6_address_delete (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN));
+	g_assert (!nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN));
 	accept_signal (address_removed);
 
 	/* Remove address again */
-	g_assert (nm_platform_ip6_address_delete (ifindex, addr, IP6_PLEN));
-	no_error ();
+	g_assert (nm_platform_ip6_address_delete (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN));
 
 	free_signal (address_added);
 	free_signal (address_changed);
@@ -168,7 +150,7 @@ test_ip4_address_external (void)
 {
 	SignalData *address_added = add_signal (NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip4_address_callback);
 	SignalData *address_removed = add_signal (NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip4_address_callback);
-	int ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
+	int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
 	in_addr_t addr;
 	guint32 lifetime = 2000;
 	guint32 preferred = 1000;
@@ -179,28 +161,26 @@ test_ip4_address_external (void)
 	/* Looks like addresses are not announced by kerenl when the interface
 	 * is down. Link-local IPv6 address is automatically added.
 	 */
-	g_assert (nm_platform_link_set_up (nm_platform_link_get_ifindex (DEVICE_NAME)));
+	g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME), NULL));
 
 	/* Add/delete notification */
 	run_command ("ip address add %s/%d dev %s valid_lft %d preferred_lft %d",
 			IP4_ADDRESS, IP4_PLEN, DEVICE_NAME, lifetime, preferred);
 	wait_signal (address_added);
-	g_assert (nm_platform_ip4_address_exists (ifindex, addr, IP4_PLEN));
+	g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN));
 	run_command ("ip address delete %s/%d dev %s", IP4_ADDRESS, IP4_PLEN, DEVICE_NAME);
 	wait_signal (address_removed);
-	g_assert (!nm_platform_ip4_address_exists (ifindex, addr, IP4_PLEN));
+	g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN));
 
 	/* Add/delete conflict */
 	run_command ("ip address add %s/%d dev %s valid_lft %d preferred_lft %d",
 			IP4_ADDRESS, IP4_PLEN, DEVICE_NAME, lifetime, preferred);
-	g_assert (nm_platform_ip4_address_add (ifindex, addr, 0, IP4_PLEN, lifetime, preferred, NULL));
-	no_error ();
-	g_assert (nm_platform_ip4_address_exists (ifindex, addr, IP4_PLEN));
+	g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr, 0, IP4_PLEN, lifetime, preferred, NULL));
+	g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN));
 	accept_signal (address_added);
 	/*run_command ("ip address delete %s/%d dev %s", IP4_ADDRESS, IP4_PLEN, DEVICE_NAME);
 	g_assert (nm_platform_ip4_address_delete (ifindex, addr, IP4_PLEN, 0));
-	no_error ();
-	g_assert (!nm_platform_ip4_address_exists (ifindex, addr, IP4_PLEN));
+	g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN));
 	accept_signal (address_removed);*/
 
 	free_signal (address_added);
@@ -212,7 +192,7 @@ test_ip6_address_external (void)
 {
 	SignalData *address_added = add_signal (NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip6_address_callback);
 	SignalData *address_removed = add_signal (NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip6_address_callback);
-	int ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
+	int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
 	struct in6_addr addr;
 	guint32 lifetime = 2000;
 	guint32 preferred = 1000;
@@ -224,22 +204,20 @@ test_ip6_address_external (void)
 	run_command ("ip address add %s/%d dev %s valid_lft %d preferred_lft %d",
 			IP6_ADDRESS, IP6_PLEN, DEVICE_NAME, lifetime, preferred);
 	wait_signal (address_added);
-	g_assert (nm_platform_ip6_address_exists (ifindex, addr, IP6_PLEN));
+	g_assert (nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN));
 	run_command ("ip address delete %s/%d dev %s", IP6_ADDRESS, IP6_PLEN, DEVICE_NAME);
 	wait_signal (address_removed);
-	g_assert (!nm_platform_ip6_address_exists (ifindex, addr, IP6_PLEN));
+	g_assert (!nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN));
 
 	/* Add/delete conflict */
 	run_command ("ip address add %s/%d dev %s valid_lft %d preferred_lft %d",
 			IP6_ADDRESS, IP6_PLEN, DEVICE_NAME, lifetime, preferred);
-	g_assert (nm_platform_ip6_address_add (ifindex, addr, in6addr_any, IP6_PLEN, lifetime, preferred, flags));
-	no_error ();
-	g_assert (nm_platform_ip6_address_exists (ifindex, addr, IP6_PLEN));
+	g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr, in6addr_any, IP6_PLEN, lifetime, preferred, flags));
+	g_assert (nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN));
 	accept_signal (address_added);
 	/*run_command ("ip address delete %s/%d dev %s", IP6_ADDRESS, IP6_PLEN, DEVICE_NAME);
-	g_assert (nm_platform_ip6_address_delete (ifindex, addr, IP6_PLEN));
-	no_error ();
-	g_assert (!nm_platform_ip6_address_exists (ifindex, addr, IP6_PLEN));
+	g_assert (nm_platform_ip6_address_delete (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN));
+	g_assert (!nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN));
 	wait_signal (address_removed);*/
 
 	free_signal (address_added);
@@ -257,9 +235,9 @@ setup_tests (void)
 {
 	SignalData *link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME);
 
-	nm_platform_link_delete (nm_platform_link_get_ifindex (DEVICE_NAME));
-	g_assert (!nm_platform_link_exists (DEVICE_NAME));
-	g_assert (nm_platform_dummy_add (DEVICE_NAME));
+	nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME));
+	g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, DEVICE_NAME));
+	g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL) == NM_PLATFORM_ERROR_SUCCESS);
 	accept_signal (link_added);
 	free_signal (link_added);
 
diff --git a/src/platform/tests/test-cleanup.c b/src/platform/tests/test-cleanup.c
index 0d0f3f63..0b825114 100644
--- a/src/platform/tests/test-cleanup.c
+++ b/src/platform/tests/test-cleanup.c
@@ -35,30 +35,30 @@ test_cleanup_internal (void)
 	inet_pton (AF_INET6, "2001:db8:e:f:1:2:3:4", &gateway6);
 
 	/* Create and set up device */
-	g_assert (nm_platform_dummy_add (DEVICE_NAME));
+	g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL) == NM_PLATFORM_ERROR_SUCCESS);
 	accept_signal (link_added);
 	free_signal (link_added);
-	g_assert (nm_platform_link_set_up (nm_platform_link_get_ifindex (DEVICE_NAME)));
-	ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
+	g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME), NULL));
+	ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
 	g_assert (ifindex > 0);
 
 	/* Add routes and addresses */
-	g_assert (nm_platform_ip4_address_add (ifindex, addr4, 0, plen4, lifetime, preferred, NULL));
-	g_assert (nm_platform_ip6_address_add (ifindex, addr6, in6addr_any, plen6, lifetime, preferred, flags));
-	g_assert (nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, gateway4, 32, INADDR_ANY, 0, metric, mss));
-	g_assert (nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, network4, plen4, gateway4, 0, metric, mss));
-	g_assert (nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway4, 0, metric, mss));
-	g_assert (nm_platform_ip6_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, gateway6, 128, in6addr_any, metric, mss));
-	g_assert (nm_platform_ip6_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, network6, plen6, gateway6, metric, mss));
-	g_assert (nm_platform_ip6_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway6, metric, mss));
-
-	addresses4 = nm_platform_ip4_address_get_all (ifindex);
-	addresses6 = nm_platform_ip6_address_get_all (ifindex);
-	routes4 = nm_platform_ip4_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
-	routes6 = nm_platform_ip6_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
+	g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr4, 0, plen4, lifetime, preferred, NULL));
+	g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr6, in6addr_any, plen6, lifetime, preferred, flags));
+	g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway4, 32, INADDR_ANY, 0, metric, mss));
+	g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network4, plen4, gateway4, 0, metric, mss));
+	g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway4, 0, metric, mss));
+	g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway6, 128, in6addr_any, metric, mss));
+	g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network6, plen6, gateway6, metric, mss));
+	g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway6, metric, mss));
+
+	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);
 
 	g_assert_cmpint (addresses4->len, ==, 1);
-	g_assert_cmpint (addresses6->len, ==, 1);
+	g_assert_cmpint (addresses6->len, ==, 2); /* also has a IPv6 LL address. */
 	g_assert_cmpint (routes4->len, ==, 3);
 	g_assert_cmpint (routes6->len, ==, 3);
 
@@ -68,12 +68,12 @@ test_cleanup_internal (void)
 	g_array_unref (routes6);
 
 	/* Delete interface with all addresses and routes */
-	g_assert (nm_platform_link_delete (ifindex));
+	g_assert (nm_platform_link_delete (NM_PLATFORM_GET, ifindex));
 
-	addresses4 = nm_platform_ip4_address_get_all (ifindex);
-	addresses6 = nm_platform_ip6_address_get_all (ifindex);
-	routes4 = nm_platform_ip4_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
-	routes6 = nm_platform_ip6_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
+	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);
 
 	g_assert_cmpint (addresses4->len, ==, 0);
 	g_assert_cmpint (addresses6->len, ==, 0);
@@ -95,8 +95,8 @@ init_tests (int *argc, char ***argv)
 void
 setup_tests (void)
 {
-	nm_platform_link_delete (nm_platform_link_get_ifindex (DEVICE_NAME));
-	g_assert (!nm_platform_link_exists (DEVICE_NAME));
+	nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME));
+	g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, DEVICE_NAME));
 
 	g_test_add_func ("/internal", test_cleanup_internal);
 	/* FIXME: add external cleanup check */
diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c
index 1980282d..b0eae63b 100644
--- a/src/platform/tests/test-common.c
+++ b/src/platform/tests/test-common.c
@@ -1,9 +1,31 @@
 #include "config.h"
 
+#include <sys/mount.h>
+#include <sched.h>
+
 #include "test-common.h"
 
 #include "nm-test-utils.h"
 
+#define SIGNAL_DATA_FMT "'%s-%s' ifindex %d%s%s%s (%d times received)"
+#define SIGNAL_DATA_ARG(data) (data)->name, nm_platform_signal_change_type_to_string ((data)->change_type), (data)->ifindex, (data)->ifname ? " ifname '" : "", (data)->ifname ? (data)->ifname : "", (data)->ifname ? "'" : "", (data)->received_count
+
+
+gboolean
+nmtst_platform_is_root_test (void)
+{
+	NM_PRAGMA_WARNING_DISABLE("-Wtautological-compare")
+	return (SETUP == nm_linux_platform_setup);
+	NM_PRAGMA_WARNING_REENABLE
+}
+
+gboolean
+nmtst_platform_is_sysfs_writable (void)
+{
+	return    !nmtst_platform_is_root_test ()
+	       || (access ("/sys/devices", W_OK) == 0);
+}
+
 SignalData *
 add_signal_full (const char *name, NMPlatformSignalChangeType change_type, GCallback callback, int ifindex, const char *ifname)
 {
@@ -11,7 +33,7 @@ add_signal_full (const char *name, NMPlatformSignalChangeType change_type, GCall
 
 	data->name = name;
 	data->change_type = change_type;
-	data->received = FALSE;
+	data->received_count = 0;
 	data->handler_id = g_signal_connect (nm_platform_get (), name, callback, data);
 	data->ifindex = ifindex;
 	data->ifname = ifname;
@@ -21,58 +43,60 @@ add_signal_full (const char *name, NMPlatformSignalChangeType change_type, GCall
 	return data;
 }
 
-static const char *
-_change_type_to_string (NMPlatformSignalChangeType change_type)
+void
+_accept_signal (const char *file, int line, const char *func, SignalData *data)
 {
-    switch (change_type) {
-    case NM_PLATFORM_SIGNAL_ADDED:
-        return "added";
-    case NM_PLATFORM_SIGNAL_CHANGED:
-        return "changed";
-    case NM_PLATFORM_SIGNAL_REMOVED:
-        return "removed";
-    default:
-        g_return_val_if_reached ("UNKNOWN");
-    }
+	debug ("NMPlatformSignalAssert: %s:%d, %s(): Accepting signal one time: "SIGNAL_DATA_FMT, file, line, func, SIGNAL_DATA_ARG (data));
+	if (data->received_count != 1)
+		g_error ("NMPlatformSignalAssert: %s:%d, %s(): failure to accept signal one time: "SIGNAL_DATA_FMT, file, line, func, SIGNAL_DATA_ARG (data));
+	data->received_count = 0;
 }
 
 void
-accept_signal (SignalData *data)
+_accept_signals (const char *file, int line, const char *func, SignalData *data, int min, int max)
 {
-	debug ("Accepting signal '%s-%s' ifindex %d ifname %s.", data->name, _change_type_to_string (data->change_type), data->ifindex, data->ifname);
-	if (!data->received)
-		g_error ("Attemted to accept a non-received signal '%s-%s'.", data->name, _change_type_to_string (data->change_type));
+	debug ("NMPlatformSignalAssert: %s:%d, %s(): Accepting signal [%d,%d] times: "SIGNAL_DATA_FMT, file, line, func, min, max, SIGNAL_DATA_ARG (data));
+	if (data->received_count < min || data->received_count > max)
+		g_error ("NMPlatformSignalAssert: %s:%d, %s(): failure to accept signal [%d,%d] times: "SIGNAL_DATA_FMT, file, line, func, min, max, SIGNAL_DATA_ARG (data));
+	data->received_count = 0;
+}
 
-	data->received = FALSE;
+void
+_ensure_no_signal (const char *file, int line, const char *func, SignalData *data)
+{
+	debug ("NMPlatformSignalAssert: %s:%d, %s(): Accepting signal 0 times: "SIGNAL_DATA_FMT, file, line, func, SIGNAL_DATA_ARG (data));
+	if (data->received_count > 0)
+		g_error ("NMPlatformSignalAssert: %s:%d, %s(): failure to accept signal 0 times: "SIGNAL_DATA_FMT, file, line, func, SIGNAL_DATA_ARG (data));
 }
 
 void
-wait_signal (SignalData *data)
+_wait_signal (const char *file, int line, const char *func, SignalData *data)
 {
-	if (data->received)
-		g_error ("Signal '%s' received before waiting for it.", data->name);
+	debug ("NMPlatformSignalAssert: %s:%d, %s(): wait signal: "SIGNAL_DATA_FMT, file, line, func, SIGNAL_DATA_ARG (data));
+	if (data->received_count)
+		g_error ("NMPlatformSignalAssert: %s:%d, %s(): failure to wait for signal: "SIGNAL_DATA_FMT, file, line, func, SIGNAL_DATA_ARG (data));
 
 	data->loop = g_main_loop_new (NULL, FALSE);
 	g_main_loop_run (data->loop);
 	g_clear_pointer (&data->loop, g_main_loop_unref);
 
-	accept_signal (data);
+	_accept_signal (file, line, func, data);
 }
 
 void
-free_signal (SignalData *data)
+_free_signal (const char *file, int line, const char *func, SignalData *data)
 {
-	if (data->received)
-		g_error ("Attempted to free received but not accepted signal '%s-%s'.", data->name, _change_type_to_string (data->change_type));
+	debug ("NMPlatformSignalAssert: %s:%d, %s(): free signal: "SIGNAL_DATA_FMT, file, line, func, SIGNAL_DATA_ARG (data));
+	if (data->received_count != 0)
+		g_error ("NMPlatformSignalAssert: %s:%d, %s(): failure to free non-accepted signal: "SIGNAL_DATA_FMT, file, line, func, SIGNAL_DATA_ARG (data));
 
 	g_signal_handler_disconnect (nm_platform_get (), data->handler_id);
 	g_free (data);
 }
 
 void
-link_callback (NMPlatform *platform, int ifindex, NMPlatformLink *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data)
+link_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPlatformLink *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data)
 {
-	
 	GArray *links;
 	NMPlatformLink *cached;
 	int i;
@@ -84,7 +108,7 @@ link_callback (NMPlatform *platform, int ifindex, NMPlatformLink *received, NMPl
 
 	if (data->ifindex && data->ifindex != received->ifindex)
 		return;
-	if (data->ifname && g_strcmp0 (data->ifname, nm_platform_link_get_name (ifindex)) != 0)
+	if (data->ifname && g_strcmp0 (data->ifname, nm_platform_link_get_name (NM_PLATFORM_GET, ifindex)) != 0)
 		return;
 	if (change_type != data->change_type)
 		return;
@@ -94,20 +118,17 @@ link_callback (NMPlatform *platform, int ifindex, NMPlatformLink *received, NMPl
 		g_main_loop_quit (data->loop);
 	}
 
-	if (data->received)
-		g_error ("Received signal '%s-%s' a second time.", data->name, _change_type_to_string (data->change_type));
-
-	debug ("Received signal '%s-%s' ifindex %d ifname '%s'.", data->name, _change_type_to_string (data->change_type), ifindex, received->name);
-	data->received = TRUE;
+	data->received_count++;
+	debug ("Received signal '%s-%s' ifindex %d ifname '%s' %dth time.", data->name, nm_platform_signal_change_type_to_string (data->change_type), ifindex, received->name, data->received_count);
 
 	if (change_type == NM_PLATFORM_SIGNAL_REMOVED)
-		g_assert (!nm_platform_link_get_name (ifindex));
+		g_assert (!nm_platform_link_get_name (NM_PLATFORM_GET, ifindex));
 	else
-		g_assert (nm_platform_link_get_name (ifindex));
+		g_assert (nm_platform_link_get_name (NM_PLATFORM_GET, ifindex));
 
 	/* Check the data */
 	g_assert (received->ifindex > 0);
-	links = nm_platform_link_get_all ();
+	links = nm_platform_link_get_all (NM_PLATFORM_GET);
 	for (i = 0; i < links->len; i++) {
 		cached = &g_array_index (links, NMPlatformLink, i);
 		if (cached->ifindex == received->ifindex) {
@@ -221,9 +242,9 @@ _assert_ip4_route_exists (const char *file, guint line, const char *func, gboole
 		         exists ? "doesn't" : "does");
 	}
 
-	ifindex = nm_platform_link_get_ifindex (ifname);
+	ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, ifname);
 	g_assert (ifindex > 0);
-	if (!nm_platform_ip4_route_exists (ifindex, network, plen, metric) != !exists) {
+	if (!nm_platform_ip4_route_get (NM_PLATFORM_GET, ifindex, network, plen, metric) != !exists) {
 		g_error ("[%s:%u] %s(): The ip4 route %s/%d metric %u %s, but platform thinks %s",
 		         file, line, func,
 		         nm_utils_inet4_ntop (network, NULL), plen, metric,
@@ -249,6 +270,46 @@ run_command (const char *format, ...)
 
 NMTST_DEFINE();
 
+static gboolean
+unshare_user (void)
+{
+	FILE *f;
+	uid_t uid = geteuid ();
+	gid_t gid = getegid ();
+
+	/* Already a root? */
+	if (gid == 0 && uid == 0)
+		return TRUE;
+
+	/* Become a root in new user NS. */
+	if (unshare (CLONE_NEWUSER) != 0)
+		return FALSE;
+
+	/* Since Linux 3.19 we have to disable setgroups() in order to map users.
+	 * Just proceed if the file is not there. */
+	f = fopen ("/proc/self/setgroups", "w");
+	if (f) {
+		fprintf (f, "deny");
+		fclose (f);
+	}
+
+	/* Map current UID to root in NS to be created. */
+	f = fopen ("/proc/self/uid_map", "w");
+	if (!f)
+		return FALSE;
+	fprintf (f, "0 %d 1", uid);
+	fclose (f);
+
+	/* Map current GID to root in NS to be created. */
+	f = fopen ("/proc/self/gid_map", "w");
+	if (!f)
+		return FALSE;
+	fprintf (f, "0 %d 1", gid);
+	fclose (f);
+
+	return TRUE;
+}
+
 int
 main (int argc, char **argv)
 {
@@ -257,20 +318,62 @@ main (int argc, char **argv)
 
 	init_tests (&argc, &argv);
 
-	NM_PRAGMA_WARNING_DISABLE("-Wtautological-compare")
-	if (SETUP == nm_linux_platform_setup && getuid() != 0) {
-		/* Try to exec as sudo, this function does not return, if a sudo-cmd is set. */
-		nmtst_reexec_sudo ();
+	if (   nmtst_platform_is_root_test ()
+	    && (geteuid () != 0 || getegid () != 0)) {
+		if (   g_getenv ("NMTST_FORCE_REAL_ROOT")
+		    || !unshare_user ()) {
+			/* Try to exec as sudo, this function does not return, if a sudo-cmd is set. */
+			nmtst_reexec_sudo ();
 
 #ifdef REQUIRE_ROOT_TESTS
-		g_print ("Fail test: requires root privileges (%s)\n", program);
-		return EXIT_FAILURE;
+			g_print ("Fail test: requires root privileges (%s)\n", program);
+			return EXIT_FAILURE;
 #else
-		g_print ("Skipping test: requires root privileges (%s)\n", program);
-		return 77;
+			g_print ("Skipping test: requires root privileges (%s)\n", program);
+			return g_test_run ();
 #endif
+		}
+	}
+
+	if (nmtst_platform_is_root_test () && !g_getenv ("NMTST_NO_UNSHARE")) {
+		int errsv;
+
+		if (unshare (CLONE_NEWNET | CLONE_NEWNS) != 0) {
+			errsv = errno;
+			g_error ("unshare(CLONE_NEWNET|CLONE_NEWNS) failed with %s (%d)", strerror (errsv), errsv);
+		}
+
+		/* Mount our /sys instance, so that gudev sees only our devices.
+		 * Needs to be read-only, because we don't run udev. */
+		if (mount (NULL, "/sys", "sysfs", MS_SLAVE, NULL) != 0) {
+			errsv = errno;
+			g_error ("mount(\"/\", MS_SLAVE) failed with %s (%d)", strerror (errsv), errsv);
+		}
+		if (mount ("sys", "/sys", "sysfs", MS_RDONLY, NULL) != 0) {
+			errsv = errno;
+			g_error ("mount(\"/sys\") failed with %s (%d)", strerror (errsv), errsv);
+		}
+
+		/* Create a writable /sys/devices tree. This makes it possible to run tests
+		 * that modify values via sysfs (such as bridge forward delay). */
+		if (mount ("sys", "/sys/devices", "sysfs", 0, NULL) != 0) {
+			errsv = errno;
+			g_error ("mount(\"/sys/devices\") failed with %s (%d)", strerror (errsv), errsv);
+		}
+		if (mount (NULL, "/sys/devices", "sysfs", MS_REMOUNT, NULL) != 0) {
+			/* Read-write remount failed. Never mind, we're probably just a root in
+			 * our user NS. */
+			if (umount ("/sys/devices") != 0) {
+				errsv = errno;
+				g_error ("umount(\"/sys/devices\") failed with  %s (%d)", strerror (errsv), errsv);
+			}
+		} else {
+			if (mount ("/sys/devices/devices", "/sys/devices", "sysfs", MS_BIND, NULL) != 0) {
+				errsv = errno;
+				g_error ("mount(\"/sys\") failed with %s (%d)", strerror (errsv), errsv);
+			}
+		}
 	}
-	NM_PRAGMA_WARNING_REENABLE
 
 	SETUP ();
 
@@ -278,8 +381,8 @@ main (int argc, char **argv)
 
 	result = g_test_run ();
 
-	nm_platform_link_delete (nm_platform_link_get_ifindex (DEVICE_NAME));
+	nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME));
 
-	nm_platform_free ();
+	g_object_unref (nm_platform_get ());
 	return result;
 }
diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h
index 367833d1..3d647543 100644
--- a/src/platform/tests/test-common.h
+++ b/src/platform/tests/test-common.h
@@ -15,33 +15,40 @@
 
 #define debug(...) nm_log_dbg (LOGD_PLATFORM, __VA_ARGS__)
 
-#define error(err) g_assert (nm_platform_get_error () == err)
-#define no_error() error (NM_PLATFORM_ERROR_NONE)
-
 typedef struct {
 	int handler_id;
 	const char *name;
 	NMPlatformSignalChangeType change_type;
-	gboolean received;
+	gint received_count;
 	GMainLoop *loop;
 	int ifindex;
 	const char *ifname;
 } SignalData;
 
+gboolean nmtst_platform_is_root_test (void);
+gboolean nmtst_platform_is_sysfs_writable (void);
+
 SignalData *add_signal_full (const char *name, NMPlatformSignalChangeType change_type, GCallback callback, int ifindex, const char *ifname);
 #define add_signal(name, change_type, callback) add_signal_full (name, change_type, (GCallback) callback, 0, NULL)
 #define add_signal_ifindex(name, change_type, callback, ifindex) add_signal_full (name, change_type, (GCallback) callback, ifindex, NULL)
 #define add_signal_ifname(name, change_type, callback, ifname) add_signal_full (name, change_type, (GCallback) callback, 0, ifname)
-void accept_signal (SignalData *data);
-void wait_signal (SignalData *data);
-void free_signal (SignalData *data);
+void _accept_signal (const char *file, int line, const char *func, SignalData *data);
+void _accept_signals (const char *file, int line, const char *func, SignalData *data, int min, int max);
+void _wait_signal (const char *file, int line, const char *func, SignalData *data);
+void _ensure_no_signal (const char *file, int line, const char *func, SignalData *data);
+void _free_signal (const char *file, int line, const char *func, SignalData *data);
+#define accept_signal(data) _accept_signal(__FILE__, __LINE__, G_STRFUNC, data)
+#define accept_signals(data, min, max) _accept_signals(__FILE__, __LINE__, G_STRFUNC, data, min, max)
+#define wait_signal(data) _wait_signal(__FILE__, __LINE__, G_STRFUNC, data)
+#define ensure_no_signal(data) _ensure_no_signal(__FILE__, __LINE__, G_STRFUNC, data)
+#define free_signal(data) _free_signal(__FILE__, __LINE__, G_STRFUNC, data)
 
 gboolean ip4_route_exists (const char *ifname, guint32 network, int plen, guint32 metric);
 
 void _assert_ip4_route_exists (const char *file, guint line, const char *func, gboolean exists, const char *ifname, guint32 network, int plen, guint32 metric);
 #define assert_ip4_route_exists(exists, ifname, network, plen, metric) _assert_ip4_route_exists (__FILE__, __LINE__, G_STRFUNC, exists, ifname, network, plen, metric)
 
-void link_callback (NMPlatform *platform, int ifindex, NMPlatformLink *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data);
+void link_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPlatformLink *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data);
 
 void run_command (const char *format, ...);
 
diff --git a/src/platform/tests/test-general.c b/src/platform/tests/test-general.c
new file mode 100644
index 00000000..0a397b37
--- /dev/null
+++ b/src/platform/tests/test-general.c
@@ -0,0 +1,67 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* nm-platform.c - Handle runtime kernel networking configuration
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * 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.
+ */
+
+#include "nm-platform-utils.h"
+
+#include <linux/rtnetlink.h>
+
+#include "nm-linux-platform.h"
+#include "nm-logging.h"
+
+#include "nm-test-utils.h"
+
+
+/******************************************************************/
+
+static void
+test_init_linux_platform (void)
+{
+	gs_unref_object NMPlatform *platform = NULL;
+
+	platform = g_object_new (NM_TYPE_LINUX_PLATFORM, NULL);
+}
+
+/******************************************************************/
+
+static void
+test_link_get_all (void)
+{
+	gs_unref_object NMPlatform *platform = NULL;
+	gs_unref_array GArray *links = NULL;
+
+	platform = g_object_new (NM_TYPE_LINUX_PLATFORM, NULL);
+
+	links = nm_platform_link_get_all (platform);
+}
+
+/******************************************************************/
+
+NMTST_DEFINE ();
+
+int
+main (int argc, char **argv)
+{
+	nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT");
+
+	g_test_add_func ("/general/init_linux_platform", test_init_linux_platform);
+	g_test_add_func ("/general/link_get_all", test_link_get_all);
+
+	return g_test_run ();
+}
diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c
index 99556e0a..dc7b8397 100644
--- a/src/platform/tests/test-link.c
+++ b/src/platform/tests/test-link.c
@@ -21,112 +21,94 @@ test_bogus(void)
 {
 	size_t addrlen;
 
-	g_assert (!nm_platform_link_exists (BOGUS_NAME));
-	no_error ();
-	g_assert (!nm_platform_link_delete (BOGUS_IFINDEX));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
-	g_assert (!nm_platform_link_get_ifindex (BOGUS_NAME));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
-	g_assert (!nm_platform_link_get_name (BOGUS_IFINDEX));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
-	g_assert (!nm_platform_link_get_type (BOGUS_IFINDEX));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
-	g_assert (!nm_platform_link_get_type_name (BOGUS_IFINDEX));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
-
-	g_assert (!nm_platform_link_set_up (BOGUS_IFINDEX));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
-	g_assert (!nm_platform_link_set_down (BOGUS_IFINDEX));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
-	g_assert (!nm_platform_link_set_arp (BOGUS_IFINDEX));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
-	g_assert (!nm_platform_link_set_noarp (BOGUS_IFINDEX));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
-	g_assert (!nm_platform_link_is_up (BOGUS_IFINDEX));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
-	g_assert (!nm_platform_link_is_connected (BOGUS_IFINDEX));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
-	g_assert (!nm_platform_link_uses_arp (BOGUS_IFINDEX));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
-
-	g_assert (!nm_platform_link_get_address (BOGUS_IFINDEX, &addrlen));
+	g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, BOGUS_NAME));
+	g_assert (!nm_platform_link_delete (NM_PLATFORM_GET, BOGUS_IFINDEX));
+	g_assert (!nm_platform_link_get_ifindex (NM_PLATFORM_GET, BOGUS_NAME));
+	g_assert (!nm_platform_link_get_name (NM_PLATFORM_GET, BOGUS_IFINDEX));
+	g_assert (!nm_platform_link_get_type (NM_PLATFORM_GET, BOGUS_IFINDEX));
+	g_assert (!nm_platform_link_get_type_name (NM_PLATFORM_GET, BOGUS_IFINDEX));
+
+	g_assert (!nm_platform_link_set_up (NM_PLATFORM_GET, BOGUS_IFINDEX, NULL));
+	g_assert (!nm_platform_link_set_down (NM_PLATFORM_GET, BOGUS_IFINDEX));
+	g_assert (!nm_platform_link_set_arp (NM_PLATFORM_GET, BOGUS_IFINDEX));
+	g_assert (!nm_platform_link_set_noarp (NM_PLATFORM_GET, BOGUS_IFINDEX));
+	g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, BOGUS_IFINDEX));
+	g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, BOGUS_IFINDEX));
+	g_assert (!nm_platform_link_uses_arp (NM_PLATFORM_GET, BOGUS_IFINDEX));
+
+	g_assert (!nm_platform_link_get_address (NM_PLATFORM_GET, BOGUS_IFINDEX, &addrlen));
 	g_assert (!addrlen);
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
-	g_assert (!nm_platform_link_get_address (BOGUS_IFINDEX, NULL));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
-	g_assert (!nm_platform_link_set_mtu (BOGUS_IFINDEX, MTU));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
-	g_assert (!nm_platform_link_get_mtu (BOGUS_IFINDEX));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
-
-	g_assert (!nm_platform_link_supports_carrier_detect (BOGUS_IFINDEX));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
-	g_assert (!nm_platform_link_supports_vlans (BOGUS_IFINDEX));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
-
-	g_assert (!nm_platform_vlan_get_info (BOGUS_IFINDEX, NULL, NULL));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
-	g_assert (!nm_platform_vlan_set_ingress_map (BOGUS_IFINDEX, 0, 0));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
-	g_assert (!nm_platform_vlan_set_egress_map (BOGUS_IFINDEX, 0, 0));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
+	g_assert (!nm_platform_link_get_address (NM_PLATFORM_GET, BOGUS_IFINDEX, NULL));
+	g_assert (!nm_platform_link_set_mtu (NM_PLATFORM_GET, BOGUS_IFINDEX, MTU));
+	g_assert (!nm_platform_link_get_mtu (NM_PLATFORM_GET, BOGUS_IFINDEX));
+
+	g_assert (!nm_platform_link_supports_carrier_detect (NM_PLATFORM_GET, BOGUS_IFINDEX));
+	g_assert (!nm_platform_link_supports_vlans (NM_PLATFORM_GET, BOGUS_IFINDEX));
+
+	g_assert (!nm_platform_vlan_get_info (NM_PLATFORM_GET, BOGUS_IFINDEX, NULL, NULL));
+	g_assert (!nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, BOGUS_IFINDEX, 0, 0));
+	g_assert (!nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, BOGUS_IFINDEX, 0, 0));
 }
 
 static void
 test_loopback (void)
 {
-	g_assert (nm_platform_link_exists (LO_NAME));
-	g_assert_cmpint (nm_platform_link_get_type (LO_INDEX), ==, NM_LINK_TYPE_LOOPBACK);
-	g_assert_cmpint (nm_platform_link_get_ifindex (LO_NAME), ==, LO_INDEX);
-	g_assert_cmpstr (nm_platform_link_get_name (LO_INDEX), ==, LO_NAME);
-	g_assert_cmpstr (nm_platform_link_get_type_name (LO_INDEX), ==, LO_TYPEDESC);
-
-	g_assert (nm_platform_link_supports_carrier_detect (LO_INDEX));
-	g_assert (!nm_platform_link_supports_vlans (LO_INDEX));
+	g_assert (nm_platform_link_get_by_ifname (NM_PLATFORM_GET, LO_NAME));
+	g_assert_cmpint (nm_platform_link_get_type (NM_PLATFORM_GET, LO_INDEX), ==, NM_LINK_TYPE_LOOPBACK);
+	g_assert_cmpint (nm_platform_link_get_ifindex (NM_PLATFORM_GET, LO_NAME), ==, LO_INDEX);
+	g_assert_cmpstr (nm_platform_link_get_name (NM_PLATFORM_GET, LO_INDEX), ==, LO_NAME);
+	g_assert_cmpstr (nm_platform_link_get_type_name (NM_PLATFORM_GET, LO_INDEX), ==, LO_TYPEDESC);
+
+	g_assert (nm_platform_link_supports_carrier_detect (NM_PLATFORM_GET, LO_INDEX));
+	g_assert (!nm_platform_link_supports_vlans (NM_PLATFORM_GET, LO_INDEX));
 }
 
-static int
+static gboolean
 software_add (NMLinkType link_type, const char *name)
 {
 	switch (link_type) {
 	case NM_LINK_TYPE_DUMMY:
-		return nm_platform_dummy_add (name);
+		return nm_platform_dummy_add (NM_PLATFORM_GET, name, NULL) == NM_PLATFORM_ERROR_SUCCESS;
 	case NM_LINK_TYPE_BRIDGE:
-		return nm_platform_bridge_add (name, NULL, 0);
+		return nm_platform_bridge_add (NM_PLATFORM_GET, name, NULL, 0, NULL) == NM_PLATFORM_ERROR_SUCCESS;
 	case NM_LINK_TYPE_BOND:
 		{
-			gboolean bond0_exists = nm_platform_link_exists ("bond0");
-			gboolean result = nm_platform_bond_add (name);
-			NMPlatformError error = nm_platform_get_error ();
+			gboolean bond0_exists = !!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "bond0");
+			NMPlatformError plerr;
+
+			plerr = nm_platform_bond_add (NM_PLATFORM_GET, name, NULL);
 
 			/* Check that bond0 is *not* automatically created. */
 			if (!bond0_exists)
-				g_assert (!nm_platform_link_exists ("bond0"));
-
-			nm_platform_set_error (error);
-			return result;
+				g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "bond0"));
+			return plerr == NM_PLATFORM_ERROR_SUCCESS;
 		}
 	case NM_LINK_TYPE_TEAM:
-		return nm_platform_team_add (name);
+		return nm_platform_team_add (NM_PLATFORM_GET, name, NULL) == NM_PLATFORM_ERROR_SUCCESS;
 	case NM_LINK_TYPE_VLAN: {
 		SignalData *parent_added;
 		SignalData *parent_changed;
 
 		/* Don't call link_callback for the bridge interface */
 		parent_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, PARENT_NAME);
-		if (nm_platform_bridge_add (PARENT_NAME, NULL, 0))
+		if (nm_platform_bridge_add (NM_PLATFORM_GET, PARENT_NAME, NULL, 0, NULL) == NM_PLATFORM_ERROR_SUCCESS)
 			accept_signal (parent_added);
 		free_signal (parent_added);
 
 		{
-			int parent_ifindex = nm_platform_link_get_ifindex (PARENT_NAME);
+			int parent_ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, PARENT_NAME);
+			gboolean was_up = nm_platform_link_is_up (NM_PLATFORM_GET, parent_ifindex);
 
 			parent_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, link_callback, parent_ifindex);
-			g_assert (nm_platform_link_set_up (parent_ifindex));
-			accept_signal (parent_changed);
+			g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, parent_ifindex, NULL));
+			if (was_up) {
+				/* when NM is running in the background, it will mess with addrgenmode which might cause additional signals. */
+				accept_signals (parent_changed, 0, 1);
+			} else
+				accept_signal (parent_changed);
 			free_signal (parent_changed);
 
-			return nm_platform_vlan_add (name, parent_ifindex, VLAN_ID, 0);
+			return nm_platform_vlan_add (NM_PLATFORM_GET, name, parent_ifindex, VLAN_ID, 0, NULL) == NM_PLATFORM_ERROR_SUCCESS;
 		}
 	}
 	default:
@@ -142,9 +124,12 @@ test_slave (int master, int type, SignalData *master_changed)
 	SignalData *link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, SLAVE_NAME);
 	SignalData *link_changed, *link_removed;
 	char *value;
+	NMLinkType link_type = nm_platform_link_get_type (NM_PLATFORM_GET, master);
+
+	g_assert (NM_IN_SET (link_type, NM_LINK_TYPE_TEAM, NM_LINK_TYPE_BOND, NM_LINK_TYPE_BRIDGE));
 
 	g_assert (software_add (type, SLAVE_NAME));
-	ifindex = nm_platform_link_get_ifindex (SLAVE_NAME);
+	ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, SLAVE_NAME);
 	g_assert (ifindex > 0);
 	link_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, link_callback, ifindex);
 	link_removed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, link_callback, ifindex);
@@ -154,46 +139,55 @@ test_slave (int master, int type, SignalData *master_changed)
 	 *
 	 * See https://bugzilla.redhat.com/show_bug.cgi?id=910348
 	 */
-	g_assert (nm_platform_link_set_down (ifindex));
-	g_assert (!nm_platform_link_is_up (ifindex));
-	accept_signal (link_changed);
+	g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
+	g_assert (nm_platform_link_set_down (NM_PLATFORM_GET, ifindex));
+	g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
+	ensure_no_signal (link_changed);
 
 	/* Enslave */
 	link_changed->ifindex = ifindex;
-	g_assert (nm_platform_link_enslave (master, ifindex)); no_error ();
-	g_assert_cmpint (nm_platform_link_get_master (ifindex), ==, master); no_error ();
-	accept_signal (link_changed);
-	accept_signal (master_changed);
+	g_assert (nm_platform_link_enslave (NM_PLATFORM_GET, master, ifindex));
+	g_assert_cmpint (nm_platform_link_get_master (NM_PLATFORM_GET, ifindex), ==, master);
+
+	accept_signals (link_changed, 1, 3);
+	accept_signals (master_changed, 0, 1);
+
+	/* enslaveing brings put the slave */
+	if (NM_IN_SET (link_type, NM_LINK_TYPE_BOND, NM_LINK_TYPE_TEAM))
+		g_assert (nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
+	else
+		g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
 
 	/* Set master up */
-	g_assert (nm_platform_link_set_up (master));
-	accept_signal (master_changed);
+	g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, master, NULL));
+	g_assert (nm_platform_link_is_up (NM_PLATFORM_GET, master));
+	accept_signals (master_changed, 1, 2);
 
 	/* Master with a disconnected slave is disconnected
 	 *
 	 * For some reason, bonding and teaming slaves are automatically set up. We
 	 * need to set them back down for this test.
 	 */
-	switch (nm_platform_link_get_type (master)) {
+	switch (nm_platform_link_get_type (NM_PLATFORM_GET, master)) {
 	case NM_LINK_TYPE_BOND:
 	case NM_LINK_TYPE_TEAM:
-		g_assert (nm_platform_link_set_down (ifindex));
+		g_assert (nm_platform_link_set_down (NM_PLATFORM_GET, ifindex));
 		accept_signal (link_changed);
-		accept_signal (master_changed);
+		accept_signals (master_changed, 0, 2);
 		break;
 	default:
 		break;
 	}
-	g_assert (!nm_platform_link_is_up (ifindex));
-	g_assert (!nm_platform_link_is_connected (ifindex));
-	if (nm_platform_link_is_connected (master)) {
-		if (nm_platform_link_get_type (master) == NM_LINK_TYPE_TEAM) {
+	g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
+	g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
+	if (nm_platform_link_is_connected (NM_PLATFORM_GET, master)) {
+		if (nm_platform_link_get_type (NM_PLATFORM_GET, master) == NM_LINK_TYPE_TEAM) {
 			/* Older team versions (e.g. Fedora 17) have a bug that team master stays
 			 * IFF_LOWER_UP even if its slave is down. Double check it with iproute2 and if
 			 * `ip link` also claims master to be up, accept it. */
 			char *stdout_str = NULL;
 
-			nmtst_spawn_sync (NULL, &stdout_str, NULL, 0, "/sbin/ip", "link", "show", "dev", nm_platform_link_get_name (master));
+			nmtst_spawn_sync (NULL, &stdout_str, NULL, 0, "/sbin/ip", "link", "show", "dev", nm_platform_link_get_name (NM_PLATFORM_GET, master));
 
 			g_assert (strstr (stdout_str, "LOWER_UP"));
 			g_free (stdout_str);
@@ -202,47 +196,59 @@ test_slave (int master, int type, SignalData *master_changed)
 	}
 
 	/* Set slave up and see if master gets up too */
-	g_assert (nm_platform_link_set_up (ifindex)); no_error ();
-	g_assert (nm_platform_link_is_connected (ifindex));
-	g_assert (nm_platform_link_is_connected (master));
-	accept_signal (link_changed);
-	accept_signal (master_changed);
+	g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, NULL));
+	g_assert (nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
+	g_assert (nm_platform_link_is_connected (NM_PLATFORM_GET, master));
+	accept_signals (link_changed, 1, 3);
+	/* NM running, can cause additional change of addrgenmode */
+	accept_signals (master_changed, 1, 2);
 
 	/* Enslave again
 	 *
 	 * Gracefully succeed if already enslaved.
 	 */
-	g_assert (nm_platform_link_enslave (master, ifindex)); no_error ();
-	accept_signal (link_changed);
-	accept_signal (master_changed);
+	ensure_no_signal (link_changed);
+	g_assert (nm_platform_link_enslave (NM_PLATFORM_GET, master, ifindex));
+	accept_signals (link_changed, 0, 2);
+	ensure_no_signal (master_changed);
 
 	/* Set slave option */
 	switch (type) {
 	case NM_LINK_TYPE_BRIDGE:
-		g_assert (nm_platform_slave_set_option (ifindex, "priority", "789"));
-		no_error ();
-		value = nm_platform_slave_get_option (ifindex, "priority");
-		no_error ();
-		g_assert_cmpstr (value, ==, "789");
-		g_free (value);
+		if (nmtst_platform_is_sysfs_writable ()) {
+			g_assert (nm_platform_slave_set_option (NM_PLATFORM_GET, ifindex, "priority", "789"));
+			value = nm_platform_slave_get_option (NM_PLATFORM_GET, ifindex, "priority");
+			g_assert_cmpstr (value, ==, "789");
+			g_free (value);
+		}
 		break;
 	default:
 		break;
 	}
 
 	/* Release */
-	g_assert (nm_platform_link_release (master, ifindex));
-	g_assert_cmpint (nm_platform_link_get_master (ifindex), ==, 0); no_error ();
-	accept_signal (link_changed);
-	accept_signal (master_changed);
+	ensure_no_signal (link_changed);
+	g_assert (nm_platform_link_release (NM_PLATFORM_GET, master, ifindex));
+	g_assert_cmpint (nm_platform_link_get_master (NM_PLATFORM_GET, ifindex), ==, 0);
+	accept_signals (link_changed, 1, 3);
+	if (link_type != NM_LINK_TYPE_TEAM)
+		accept_signals (master_changed, 1, 2);
+	else
+		accept_signals (master_changed, 1, 1);
+
+	ensure_no_signal (master_changed);
 
 	/* Release again */
-	g_assert (!nm_platform_link_release (master, ifindex));
-	error (NM_PLATFORM_ERROR_NOT_SLAVE);
+	ensure_no_signal (link_changed);
+	g_assert (!nm_platform_link_release (NM_PLATFORM_GET, master, ifindex));
+
+	ensure_no_signal (master_changed);
 
 	/* Remove */
-	g_assert (nm_platform_link_delete (ifindex));
-	no_error ();
+	ensure_no_signal (link_changed);
+	g_assert (nm_platform_link_delete (NM_PLATFORM_GET, ifindex));
+	accept_signals (master_changed, 0, 1);
+	accept_signals (link_changed, 0, 1);
 	accept_signal (link_removed);
 
 	free_signal (link_added);
@@ -262,53 +268,50 @@ test_software (NMLinkType link_type, const char *link_typename)
 	/* Add */
 	link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME);
 	g_assert (software_add (link_type, DEVICE_NAME));
-	no_error ();
 	accept_signal (link_added);
-	g_assert (nm_platform_link_exists (DEVICE_NAME));
-	ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
+	g_assert (nm_platform_link_get_by_ifname (NM_PLATFORM_GET, DEVICE_NAME));
+	ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
 	g_assert (ifindex >= 0);
-	g_assert_cmpint (nm_platform_link_get_type (ifindex), ==, link_type);
-	g_assert_cmpstr (nm_platform_link_get_type_name (ifindex), ==, link_typename);
+	g_assert_cmpint (nm_platform_link_get_type (NM_PLATFORM_GET, ifindex), ==, link_type);
+	g_assert_cmpstr (nm_platform_link_get_type_name (NM_PLATFORM_GET, ifindex), ==, link_typename);
 	link_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, link_callback, ifindex);
 	link_removed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, link_callback, ifindex);
 	if (link_type == NM_LINK_TYPE_VLAN) {
-		g_assert (nm_platform_vlan_get_info (ifindex, &vlan_parent, &vlan_id));
-		g_assert_cmpint (vlan_parent, ==, nm_platform_link_get_ifindex (PARENT_NAME));
+		g_assert (nm_platform_vlan_get_info (NM_PLATFORM_GET, ifindex, &vlan_parent, &vlan_id));
+		g_assert_cmpint (vlan_parent, ==, nm_platform_link_get_ifindex (NM_PLATFORM_GET, PARENT_NAME));
 		g_assert_cmpint (vlan_id, ==, VLAN_ID);
-		no_error ();
 	}
 
 	/* Add again */
 	g_assert (!software_add (link_type, DEVICE_NAME));
-	error (NM_PLATFORM_ERROR_EXISTS);
 
 	/* Set ARP/NOARP */
-	g_assert (nm_platform_link_uses_arp (ifindex));
-	g_assert (nm_platform_link_set_noarp (ifindex));
-	g_assert (!nm_platform_link_uses_arp (ifindex));
-	accept_signal (link_changed);
-	g_assert (nm_platform_link_set_arp (ifindex));
-	g_assert (nm_platform_link_uses_arp (ifindex));
+	g_assert (nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex));
+	g_assert (nm_platform_link_set_noarp (NM_PLATFORM_GET, ifindex));
+	g_assert (!nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex));
+	accept_signals (link_changed, 1, 2);
+	g_assert (nm_platform_link_set_arp (NM_PLATFORM_GET, ifindex));
+	g_assert (nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex));
 	accept_signal (link_changed);
 
 	/* Set master option */
 	switch (link_type) {
 	case NM_LINK_TYPE_BRIDGE:
-		g_assert (nm_platform_master_set_option (ifindex, "forward_delay", "789"));
-		no_error ();
-		value = nm_platform_master_get_option (ifindex, "forward_delay");
-		no_error ();
-		g_assert_cmpstr (value, ==, "789");
-		g_free (value);
+		if (nmtst_platform_is_sysfs_writable ()) {
+			g_assert (nm_platform_master_set_option (NM_PLATFORM_GET, ifindex, "forward_delay", "789"));
+			value = nm_platform_master_get_option (NM_PLATFORM_GET, ifindex, "forward_delay");
+			g_assert_cmpstr (value, ==, "789");
+			g_free (value);
+		}
 		break;
 	case NM_LINK_TYPE_BOND:
-		g_assert (nm_platform_master_set_option (ifindex, "mode", "active-backup"));
-		no_error ();
-		value = nm_platform_master_get_option (ifindex, "mode");
-		no_error ();
-		/* When reading back, the output looks slightly different. */
-		g_assert (g_str_has_prefix (value, "active-backup"));
-		g_free (value);
+		if (nmtst_platform_is_sysfs_writable ()) {
+			g_assert (nm_platform_master_set_option (NM_PLATFORM_GET, ifindex, "mode", "active-backup"));
+			value = nm_platform_master_get_option (NM_PLATFORM_GET, ifindex, "mode");
+			/* When reading back, the output looks slightly different. */
+			g_assert (g_str_has_prefix (value, "active-backup"));
+			g_free (value);
+		}
 		break;
 	default:
 		break;
@@ -326,33 +329,29 @@ test_software (NMLinkType link_type, const char *link_typename)
 	default:
 		break;
 	}
+	free_signal (link_changed);
 
 	/* Delete */
-	g_assert (nm_platform_link_delete (ifindex));
-	no_error ();
-	g_assert (!nm_platform_link_exists (DEVICE_NAME)); no_error ();
-	g_assert_cmpint (nm_platform_link_get_type (ifindex), ==, NM_LINK_TYPE_NONE);
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
-	g_assert (!nm_platform_link_get_type (ifindex));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
+	g_assert (nm_platform_link_delete (NM_PLATFORM_GET, ifindex));
+	g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, DEVICE_NAME));
+	g_assert_cmpint (nm_platform_link_get_type (NM_PLATFORM_GET, ifindex), ==, NM_LINK_TYPE_NONE);
+	g_assert (!nm_platform_link_get_type (NM_PLATFORM_GET, ifindex));
 	accept_signal (link_removed);
 
 	/* Delete again */
-	g_assert (!nm_platform_link_delete (nm_platform_link_get_ifindex (DEVICE_NAME)));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
+	g_assert (!nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME)));
 
 	/* VLAN: Delete parent */
 	if (link_type == NM_LINK_TYPE_VLAN) {
 		SignalData *link_removed_parent = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, link_callback, vlan_parent);
 
-		g_assert (nm_platform_link_delete (vlan_parent));
+		g_assert (nm_platform_link_delete (NM_PLATFORM_GET, vlan_parent));
 		accept_signal (link_removed_parent);
 		free_signal (link_removed_parent);
 	}
 
 	/* No pending signal */
 	free_signal (link_added);
-	free_signal (link_changed);
 	free_signal (link_removed);
 }
 
@@ -365,14 +364,12 @@ test_bridge (void)
 static void
 test_bond (void)
 {
-	NM_PRAGMA_WARNING_DISABLE("-Wtautological-compare")
-	if (SETUP == nm_linux_platform_setup &&
+	if (nmtst_platform_is_root_test () &&
 	    !g_file_test ("/proc/1/net/bonding", G_FILE_TEST_IS_DIR) &&
 	    system("modprobe --show bonding") != 0) {
 		g_test_skip ("Skipping test for bonding: bonding module not available");
 		return;
 	}
-	NM_PRAGMA_WARNING_REENABLE
 
 	test_software (NM_LINK_TYPE_BOND, "bond");
 }
@@ -400,76 +397,70 @@ test_internal (void)
 	int ifindex;
 
 	/* Check the functions for non-existent devices */
-	g_assert (!nm_platform_link_exists (DEVICE_NAME)); no_error ();
-	g_assert (!nm_platform_link_get_ifindex (DEVICE_NAME));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
+	g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, DEVICE_NAME));
+	g_assert (!nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME));
 
 	/* Add device */
-	g_assert (nm_platform_dummy_add (DEVICE_NAME));
-	no_error ();
+	g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL) == NM_PLATFORM_ERROR_SUCCESS);
 	accept_signal (link_added);
 
 	/* Try to add again */
-	g_assert (!nm_platform_dummy_add (DEVICE_NAME));
-	error (NM_PLATFORM_ERROR_EXISTS);
+	g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL) == NM_PLATFORM_ERROR_EXISTS);
 
 	/* Check device index, name and type */
-	ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
+	ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
 	g_assert (ifindex > 0);
-	g_assert_cmpstr (nm_platform_link_get_name (ifindex), ==, DEVICE_NAME);
-	g_assert_cmpint (nm_platform_link_get_type (ifindex), ==, NM_LINK_TYPE_DUMMY);
-	g_assert_cmpstr (nm_platform_link_get_type_name (ifindex), ==, DUMMY_TYPEDESC);
+	g_assert_cmpstr (nm_platform_link_get_name (NM_PLATFORM_GET, ifindex), ==, DEVICE_NAME);
+	g_assert_cmpint (nm_platform_link_get_type (NM_PLATFORM_GET, ifindex), ==, NM_LINK_TYPE_DUMMY);
+	g_assert_cmpstr (nm_platform_link_get_type_name (NM_PLATFORM_GET, ifindex), ==, DUMMY_TYPEDESC);
 	link_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, link_callback, ifindex);
 	link_removed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, link_callback, ifindex);
 
 	/* Up/connected */
-	g_assert (!nm_platform_link_is_up (ifindex)); no_error ();
-	g_assert (!nm_platform_link_is_connected (ifindex)); no_error ();
-	g_assert (nm_platform_link_set_up (ifindex)); no_error ();
-	g_assert (nm_platform_link_is_up (ifindex)); no_error ();
-	g_assert (nm_platform_link_is_connected (ifindex)); no_error ();
+	g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
+	g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
+	g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, NULL));
+	g_assert (nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
+	g_assert (nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
 	accept_signal (link_changed);
-	g_assert (nm_platform_link_set_down (ifindex)); no_error ();
-	g_assert (!nm_platform_link_is_up (ifindex)); no_error ();
-	g_assert (!nm_platform_link_is_connected (ifindex)); no_error ();
+	g_assert (nm_platform_link_set_down (NM_PLATFORM_GET, ifindex));
+	g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
+	g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
 	accept_signal (link_changed);
 
 	/* arp/noarp */
-	g_assert (!nm_platform_link_uses_arp (ifindex));
-	g_assert (nm_platform_link_set_arp (ifindex));
-	g_assert (nm_platform_link_uses_arp (ifindex));
+	g_assert (!nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex));
+	g_assert (nm_platform_link_set_arp (NM_PLATFORM_GET, ifindex));
+	g_assert (nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex));
 	accept_signal (link_changed);
-	g_assert (nm_platform_link_set_noarp (ifindex));
-	g_assert (!nm_platform_link_uses_arp (ifindex));
+	g_assert (nm_platform_link_set_noarp (NM_PLATFORM_GET, ifindex));
+	g_assert (!nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex));
 	accept_signal (link_changed);
 
 	/* Features */
-	g_assert (!nm_platform_link_supports_carrier_detect (ifindex));
-	g_assert (nm_platform_link_supports_vlans (ifindex));
+	g_assert (!nm_platform_link_supports_carrier_detect (NM_PLATFORM_GET, ifindex));
+	g_assert (nm_platform_link_supports_vlans (NM_PLATFORM_GET, ifindex));
 
 	/* Set MAC address */
-	g_assert (nm_platform_link_set_address (ifindex, mac, sizeof (mac)));
-	address = nm_platform_link_get_address (ifindex, &addrlen);
+	g_assert (nm_platform_link_set_address (NM_PLATFORM_GET, ifindex, mac, sizeof (mac)));
+	address = nm_platform_link_get_address (NM_PLATFORM_GET, ifindex, &addrlen);
 	g_assert (addrlen == sizeof(mac));
 	g_assert (!memcmp (address, mac, addrlen));
-	address = nm_platform_link_get_address (ifindex, NULL);
+	address = nm_platform_link_get_address (NM_PLATFORM_GET, ifindex, NULL);
 	g_assert (!memcmp (address, mac, addrlen));
 	accept_signal (link_changed);
 
 	/* Set MTU */
-	g_assert (nm_platform_link_set_mtu (ifindex, MTU));
-	no_error ();
-	g_assert_cmpint (nm_platform_link_get_mtu (ifindex), ==, MTU);
+	g_assert (nm_platform_link_set_mtu (NM_PLATFORM_GET, ifindex, MTU));
+	g_assert_cmpint (nm_platform_link_get_mtu (NM_PLATFORM_GET, ifindex), ==, MTU);
 	accept_signal (link_changed);
 
 	/* Delete device */
-	g_assert (nm_platform_link_delete (ifindex));
-	no_error ();
+	g_assert (nm_platform_link_delete (NM_PLATFORM_GET, ifindex));
 	accept_signal (link_removed);
 
 	/* Try to delete again */
-	g_assert (!nm_platform_link_delete (ifindex));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
+	g_assert (!nm_platform_link_delete (NM_PLATFORM_GET, ifindex));
 
 	free_signal (link_added);
 	free_signal (link_changed);
@@ -479,60 +470,56 @@ test_internal (void)
 static void
 test_external (void)
 {
-	NMPlatformLink link;
+	const NMPlatformLink *pllink;
 	SignalData *link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME);
 	SignalData *link_changed, *link_removed;
 	int ifindex;
-	gboolean success;
 
 	run_command ("ip link add %s type %s", DEVICE_NAME, "dummy");
 	wait_signal (link_added);
-	g_assert (nm_platform_link_exists (DEVICE_NAME));
-	ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
+
+	g_assert (nm_platform_link_get_by_ifname (NM_PLATFORM_GET, DEVICE_NAME));
+	ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
 	g_assert (ifindex > 0);
-	g_assert_cmpstr (nm_platform_link_get_name (ifindex), ==, DEVICE_NAME);
-	g_assert_cmpint (nm_platform_link_get_type (ifindex), ==, NM_LINK_TYPE_DUMMY);
-	g_assert_cmpstr (nm_platform_link_get_type_name (ifindex), ==, DUMMY_TYPEDESC);
+	g_assert_cmpstr (nm_platform_link_get_name (NM_PLATFORM_GET, ifindex), ==, DEVICE_NAME);
+	g_assert_cmpint (nm_platform_link_get_type (NM_PLATFORM_GET, ifindex), ==, NM_LINK_TYPE_DUMMY);
+	g_assert_cmpstr (nm_platform_link_get_type_name (NM_PLATFORM_GET, ifindex), ==, DUMMY_TYPEDESC);
 	link_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, link_callback, ifindex);
 	link_removed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, link_callback, ifindex);
 
-	success = nm_platform_link_get (ifindex, &link);
-	g_assert (success);
-	if (!link.driver) {
+	pllink = nm_platform_link_get (NM_PLATFORM_GET, ifindex);
+	g_assert (pllink);
+	if (!pllink->initialized) {
 		/* we still lack the notification via UDEV. Expect another link changed signal. */
 		wait_signal (link_changed);
 	}
 
 	/* Up/connected/arp */
-	g_assert (!nm_platform_link_is_up (ifindex));
-	g_assert (!nm_platform_link_is_connected (ifindex));
-	g_assert (!nm_platform_link_uses_arp (ifindex));
+	g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
+	g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
+	g_assert (!nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex));
+
 	run_command ("ip link set %s up", DEVICE_NAME);
 	wait_signal (link_changed);
-	g_assert (nm_platform_link_is_up (ifindex));
-	g_assert (nm_platform_link_is_connected (ifindex));
+
+	g_assert (nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
+	g_assert (nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
 	run_command ("ip link set %s down", DEVICE_NAME);
 	wait_signal (link_changed);
-	g_assert (!nm_platform_link_is_up (ifindex));
-	g_assert (!nm_platform_link_is_connected (ifindex));
-	/* This test doesn't trigger a netlink event at least on
-	 * 3.8.2-206.fc18.x86_64. Disabling the waiting and checking code
-	 * because of that.
-	 */
+	g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
+	g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
+
 	run_command ("ip link set %s arp on", DEVICE_NAME);
-#if 0
 	wait_signal (link_changed);
-	g_assert (nm_platform_link_uses_arp (ifindex));
-#endif
+	g_assert (nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex));
 	run_command ("ip link set %s arp off", DEVICE_NAME);
-#if 0
 	wait_signal (link_changed);
-	g_assert (!nm_platform_link_uses_arp (ifindex));
-#endif
+	g_assert (!nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex));
 
 	run_command ("ip link del %s", DEVICE_NAME);
 	wait_signal (link_removed);
-	g_assert (!nm_platform_link_exists (DEVICE_NAME));
+	accept_signals (link_changed, 0, 1);
+	g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, DEVICE_NAME));
 
 	free_signal (link_added);
 	free_signal (link_changed);
@@ -548,12 +535,12 @@ init_tests (int *argc, char ***argv)
 void
 setup_tests (void)
 {
-	nm_platform_link_delete (nm_platform_link_get_ifindex (DEVICE_NAME));
-	nm_platform_link_delete (nm_platform_link_get_ifindex (SLAVE_NAME));
-	nm_platform_link_delete (nm_platform_link_get_ifindex (PARENT_NAME));
-	g_assert (!nm_platform_link_exists (DEVICE_NAME));
-	g_assert (!nm_platform_link_exists (SLAVE_NAME));
-	g_assert (!nm_platform_link_exists (PARENT_NAME));
+	nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME));
+	nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, SLAVE_NAME));
+	nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, PARENT_NAME));
+	g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, DEVICE_NAME));
+	g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, SLAVE_NAME));
+	g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, PARENT_NAME));
 
 	g_test_add_func ("/link/bogus", test_bogus);
 	g_test_add_func ("/link/loopback", test_loopback);
diff --git a/src/platform/tests/test-nmp-object.c b/src/platform/tests/test-nmp-object.c
new file mode 100644
index 00000000..88bb0707
--- /dev/null
+++ b/src/platform/tests/test-nmp-object.c
@@ -0,0 +1,425 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* nm-platform.c - Handle runtime kernel networking configuration
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * 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.
+ */
+
+#include "nmp-object.h"
+
+#include "nm-logging.h"
+
+#include "nm-test-utils.h"
+
+struct {
+	GList *udev_devices;
+} global;
+
+/******************************************************************/
+
+static gboolean
+_nmp_object_id_equal (const NMPObject *a, const NMPObject *b)
+{
+	gboolean a_b = nmp_object_id_equal (a, b);
+
+	g_assert (NM_IN_SET (a_b, FALSE, TRUE) && a_b == nmp_object_id_equal (b, a));
+	return a_b;
+}
+#define nmp_object_id_equal _nmp_object_id_equal
+
+static gboolean
+_nmp_object_equal (const NMPObject *a, const NMPObject *b)
+{
+	gboolean a_b = nmp_object_equal (a, b);
+
+	g_assert (NM_IN_SET (a_b, FALSE, TRUE) && a_b == nmp_object_equal (b, a));
+	return a_b;
+}
+#define nmp_object_equal _nmp_object_equal
+
+/******************************************************************/
+
+static void
+_assert_cache_multi_lookup_contains (const NMPCache *cache, const NMPCacheId *cache_id, const NMPObject *obj, gboolean contains)
+{
+	const NMPlatformObject *const *objects;
+	guint i, len;
+	gboolean found;
+
+	g_assert (cache_id);
+	g_assert (NMP_OBJECT_IS_VALID (obj));
+
+	g_assert (nmp_cache_lookup_obj (cache, obj) == obj);
+
+	objects = nmp_cache_lookup_multi (cache, cache_id, &len);
+
+	g_assert ((len == 0 && !objects) || (len > 0 && objects && !objects[len]));
+
+	found = FALSE;
+	for (i = 0; i < len; i++) {
+		NMPObject *o;
+
+		g_assert (objects[i]);
+		o = NMP_OBJECT_UP_CAST (objects[i]);
+		g_assert (NMP_OBJECT_IS_VALID (o));
+
+		if (obj == o) {
+			g_assert (!found);
+			found = TRUE;
+		}
+	}
+
+	g_assert (!!contains == found);
+}
+
+/******************************************************************/
+
+typedef struct {
+	NMPCache *cache;
+	NMPCacheOpsType expected_ops_type;
+	const NMPObject *obj_clone;
+	NMPObject *new_clone;
+	gboolean was_visible;
+	gboolean called;
+} _NMPCacheUpdateData;
+
+static void
+_nmp_cache_update_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMPCacheOpsType ops_type, gpointer user_data)
+{
+	_NMPCacheUpdateData *data = user_data;
+
+	g_assert (data);
+	g_assert (!data->called);
+	g_assert (data->cache == cache);
+
+	g_assert_cmpint (data->expected_ops_type, ==, ops_type);
+
+	switch (ops_type) {
+	case NMP_CACHE_OPS_ADDED:
+		g_assert (!old);
+		g_assert (NMP_OBJECT_IS_VALID (new));
+		g_assert (nmp_object_is_alive (new));
+		g_assert (nmp_object_id_equal (data->obj_clone, new));
+		g_assert (nmp_object_equal (data->obj_clone, new));
+		break;
+	case NMP_CACHE_OPS_UPDATED:
+		g_assert (NMP_OBJECT_IS_VALID (old));
+		g_assert (NMP_OBJECT_IS_VALID (new));
+		g_assert (nmp_object_is_alive (old));
+		g_assert (nmp_object_is_alive (new));
+		g_assert (nmp_object_id_equal (data->obj_clone, new));
+		g_assert (nmp_object_id_equal (data->obj_clone, old));
+		g_assert (nmp_object_id_equal (old, new));
+		g_assert (nmp_object_equal (data->obj_clone, new));
+		g_assert (!nmp_object_equal (data->obj_clone, old));
+		g_assert (!nmp_object_equal (old, new));
+		break;
+	case NMP_CACHE_OPS_REMOVED:
+		g_assert (!new);
+		g_assert (NMP_OBJECT_IS_VALID (old));
+		g_assert (nmp_object_is_alive (old));
+		g_assert (nmp_object_id_equal (data->obj_clone, old));
+		break;
+	default:
+		g_assert_not_reached ();
+	}
+
+	data->was_visible = old ? nmp_object_is_visible (old) : FALSE;
+	data->new_clone = new ? nmp_object_clone (new, FALSE) : NULL;
+	data->called = TRUE;
+}
+
+static void
+_nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj, gboolean *out_was_visible, NMPCacheOpsType expected_ops_type)
+{
+	NMPCacheOpsType ops_type;
+	NMPObject *obj2;
+	gboolean was_visible;
+	auto_nmp_obj NMPObject *obj_clone = nmp_object_clone (obj, FALSE);
+	auto_nmp_obj NMPObject *new_clone = NULL;
+	const NMPObject *obj_old;
+	_NMPCacheUpdateData data = {
+		.cache = cache,
+		.expected_ops_type = expected_ops_type,
+		.obj_clone = obj_clone,
+	};
+
+	obj_old = nmp_cache_lookup_link (cache, obj->object.ifindex);
+	if (obj_old && obj_old->_link.udev.device)
+		obj_clone->_link.udev.device = g_object_ref (obj_old->_link.udev.device);
+	_nmp_object_fixup_link_udev_fields (obj_clone, nmp_cache_use_udev_get (cache));
+
+	g_assert (cache);
+	g_assert (NMP_OBJECT_IS_VALID (obj));
+
+	ops_type = nmp_cache_update_netlink (cache, obj, &obj2, &was_visible, _nmp_cache_update_hook, &data);
+
+	new_clone = data.new_clone;
+
+	g_assert_cmpint (ops_type, ==, expected_ops_type);
+
+	if (ops_type != NMP_CACHE_OPS_UNCHANGED) {
+		g_assert (NMP_OBJECT_IS_VALID (obj2));
+		g_assert (data.called);
+		g_assert_cmpint (data.was_visible, ==, was_visible);
+
+		if (ops_type == NMP_CACHE_OPS_REMOVED)
+			g_assert (!data.new_clone);
+		else {
+			g_assert (data.new_clone);
+			g_assert (nmp_object_equal (obj2, data.new_clone));
+		}
+	} else {
+		g_assert (!data.called);
+		g_assert (!obj2 || was_visible == nmp_object_is_visible (obj2));
+	}
+
+	g_assert (!obj2 || nmp_object_id_equal (obj, obj2));
+	if (ops_type != NMP_CACHE_OPS_REMOVED && obj2)
+		g_assert (nmp_object_equal (obj, obj2));
+
+	if (out_obj)
+		*out_obj = obj2;
+	else
+		nmp_object_unref (obj2);
+	if (out_was_visible)
+		*out_was_visible = was_visible;
+}
+
+static const NMPlatformLink pl_link_2 = {
+	.ifindex = 2,
+	.name = "eth0",
+	.type = NM_LINK_TYPE_ETHERNET,
+};
+
+static const NMPlatformLink pl_link_3 = {
+	.ifindex = 3,
+	.name = "wlan0",
+	.type = NM_LINK_TYPE_WIFI,
+};
+
+static void
+test_cache_link (void)
+{
+	NMPCache *cache;
+	NMPObject *obj1, *obj2;
+	NMPObject objs1;
+	gboolean was_visible;
+	NMPCacheId cache_id_storage;
+	GUdevDevice *udev_device_2 = g_list_nth_data (global.udev_devices, 0);
+	GUdevDevice *udev_device_3 = g_list_nth_data (global.udev_devices, 0);
+	NMPCacheOpsType ops_type;
+
+	cache = nmp_cache_new ();
+
+	nmp_cache_use_udev_set (cache, g_rand_int_range (nmtst_get_rand (), 0, 2));
+
+	/* if we have a link, and don't set is_in_netlink, adding it has no effect. */
+	obj1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
+	g_assert (NMP_OBJECT_UP_CAST (&obj1->object) == obj1);
+	g_assert (!nmp_object_is_alive (obj1));
+	_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_UNCHANGED);
+	ASSERT_nmp_cache_is_consistent (cache);
+	g_assert (!obj2);
+	g_assert (!was_visible);
+	g_assert (!nmp_cache_lookup_obj (cache, obj1));
+	g_assert (!nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)));
+	nmp_object_unref (obj1);
+
+	/* Only when setting @is_in_netlink the link is added. */
+	obj1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
+	obj1->_link.netlink.is_in_netlink = TRUE;
+	g_assert (nmp_object_is_alive (obj1));
+	_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_ADDED);
+	ASSERT_nmp_cache_is_consistent (cache);
+	g_assert (nmp_object_equal (obj1, obj2));
+	g_assert (!was_visible);
+	g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2);
+	g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2);
+	g_assert (nmp_object_is_visible (obj2));
+	_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, TRUE), obj2, TRUE);
+	_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, FALSE), obj2, TRUE);
+	nmp_object_unref (obj1);
+	nmp_object_unref (obj2);
+
+	/* updating the same link with identical value, has no effect. */
+	obj1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
+	obj1->_link.netlink.is_in_netlink = TRUE;
+	g_assert (nmp_object_is_alive (obj1));
+	_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_UNCHANGED);
+	ASSERT_nmp_cache_is_consistent (cache);
+	g_assert (obj2 != obj1);
+	g_assert (nmp_object_equal (obj1, obj2));
+	g_assert (was_visible);
+	g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2);
+	g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2);
+	nmp_object_unref (obj1);
+	nmp_object_unref (obj2);
+
+	/* remove the link from netlink */
+	obj1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
+	g_assert (!nmp_object_is_alive (obj1));
+	_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_REMOVED);
+	ASSERT_nmp_cache_is_consistent (cache);
+	g_assert (obj2 != obj1);
+	g_assert (was_visible);
+	g_assert (!nmp_cache_lookup_obj (cache, obj1));
+	g_assert (!nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)));
+	nmp_object_unref (obj1);
+	nmp_object_unref (obj2);
+
+	if (udev_device_2) {
+		/* now add the link only with aspect UDEV. */
+		ops_type = nmp_cache_update_link_udev (cache, pl_link_2.ifindex, udev_device_2, &obj2, &was_visible, NULL, NULL);
+		ASSERT_nmp_cache_is_consistent (cache);
+		g_assert_cmpint (ops_type, ==, NMP_CACHE_OPS_ADDED);
+		g_assert (!was_visible);
+		g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2);
+		g_assert (!nmp_object_is_visible (obj2));
+		_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, TRUE), obj2, FALSE);
+		_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, FALSE), obj2, TRUE);
+		nmp_object_unref (obj2);
+	}
+
+	/* add it in netlink too. */
+	obj1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
+	obj1->_link.netlink.is_in_netlink = TRUE;
+	g_assert (nmp_object_is_alive (obj1));
+	_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, udev_device_2 ? NMP_CACHE_OPS_UPDATED : NMP_CACHE_OPS_ADDED);
+	ASSERT_nmp_cache_is_consistent (cache);
+	g_assert (nmp_object_equal (obj1, obj2));
+	g_assert (!was_visible);
+	g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2);
+	g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2);
+	g_assert (nmp_object_is_visible (obj2));
+	_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, TRUE), obj2, TRUE);
+	_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, FALSE), obj2, TRUE);
+	nmp_object_unref (obj1);
+	nmp_object_unref (obj2);
+
+	/* remove again from netlink. */
+	obj1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
+	obj1->_link.netlink.is_in_netlink = FALSE;
+	g_assert (!nmp_object_is_alive (obj1));
+	_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, udev_device_2 ? NMP_CACHE_OPS_UPDATED : NMP_CACHE_OPS_REMOVED);
+	ASSERT_nmp_cache_is_consistent (cache);
+	g_assert (obj2 != obj1);
+	g_assert (was_visible);
+	if (udev_device_2) {
+		g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2);
+		g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2);
+		g_assert (!nmp_object_is_visible (obj2));
+		_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, TRUE), obj2, FALSE);
+		_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, FALSE), obj2, TRUE);
+	} else {
+		g_assert (nmp_cache_lookup_obj (cache, obj1) == NULL);
+		g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == NULL);
+		g_assert (nmp_object_is_visible (obj2));
+	}
+	nmp_object_unref (obj1);
+	nmp_object_unref (obj2);
+
+	/* now another link only with aspect UDEV. */
+	if (udev_device_3) {
+		/* now add the link only with aspect UDEV. */
+		ops_type = nmp_cache_update_link_udev (cache, pl_link_3.ifindex, udev_device_3, &obj2, &was_visible, NULL, NULL);
+		g_assert_cmpint (ops_type, ==, NMP_CACHE_OPS_ADDED);
+		ASSERT_nmp_cache_is_consistent (cache);
+		g_assert (NMP_OBJECT_IS_VALID (obj2));
+		g_assert (!was_visible);
+		g_assert (!nmp_object_is_visible (obj2));
+		g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_3.ifindex)) == obj2);
+		_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, TRUE), obj2, FALSE);
+		_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, FALSE), obj2, TRUE);
+		g_assert_cmpint (obj2->_link.netlink.is_in_netlink, ==, FALSE);
+		g_assert_cmpint (obj2->link.initialized, ==, FALSE);
+		nmp_object_unref (obj2);
+
+		/* add it in netlink too. */
+		obj1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_3);
+		obj1->_link.netlink.is_in_netlink = TRUE;
+		g_assert (nmp_object_is_alive (obj1));
+		_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_UPDATED);
+		ASSERT_nmp_cache_is_consistent (cache);
+		g_assert (obj2 != obj1);
+		g_assert (nmp_object_equal (obj1, obj2));
+		g_assert (!was_visible);
+		g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2);
+		g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_3.ifindex)) == obj2);
+		g_assert (nmp_object_is_visible (obj2));
+		_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, TRUE), obj2, TRUE);
+		_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, FALSE), obj2, TRUE);
+		g_assert_cmpint (obj2->_link.netlink.is_in_netlink, ==, TRUE);
+		g_assert_cmpint (obj2->link.initialized, ==, TRUE);
+		nmp_object_unref (obj1);
+		nmp_object_unref (obj2);
+
+		/* remove UDEV. */
+		ops_type = nmp_cache_update_link_udev (cache, pl_link_3.ifindex, NULL, &obj2, &was_visible, NULL, NULL);
+		g_assert_cmpint (ops_type, ==, NMP_CACHE_OPS_UPDATED);
+		ASSERT_nmp_cache_is_consistent (cache);
+		g_assert (was_visible);
+		g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_3.ifindex)) == obj2);
+		g_assert (nmp_object_is_visible (obj2));
+		_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, TRUE), obj2, TRUE);
+		_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, FALSE), obj2, TRUE);
+		g_assert_cmpint (obj2->_link.netlink.is_in_netlink, ==, TRUE);
+		g_assert_cmpint (obj2->link.initialized, ==, !nmp_cache_use_udev_get (cache));
+		nmp_object_unref (obj2);
+	}
+
+	nmp_cache_free (cache);
+}
+
+/******************************************************************/
+
+NMTST_DEFINE ();
+
+int
+main (int argc, char **argv)
+{
+	int result;
+	gs_unref_object GUdevClient *udev_client = NULL;
+
+	nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT");
+
+	udev_client = g_udev_client_new ((const char *[]) { "net", NULL });
+	{
+		gs_unref_object GUdevEnumerator *udev_enumerator = g_udev_enumerator_new (udev_client);
+
+		g_udev_enumerator_add_match_subsystem (udev_enumerator, "net");
+
+		/* Demand that the device is initialized (udev rules ran,
+		 * device has a stable name now) in case udev is running
+		 * (not in a container). */
+		if (access ("/sys", W_OK) == 0)
+			g_udev_enumerator_add_match_is_initialized (udev_enumerator);
+
+		global.udev_devices = g_udev_enumerator_execute (udev_enumerator);
+	}
+
+	g_test_add_func ("/nmp-object/cache_link", test_cache_link);
+
+	result = g_test_run ();
+
+	while (global.udev_devices) {
+		g_object_unref (global.udev_devices->data);
+		global.udev_devices = g_list_remove (global.udev_devices, global.udev_devices->data);
+	}
+
+	return result;
+}
+
diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c
index 2d3caaf1..cf322dec 100644
--- a/src/platform/tests/test-route.c
+++ b/src/platform/tests/test-route.c
@@ -1,5 +1,7 @@
 #include "config.h"
 
+#include <linux/rtnetlink.h>
+
 #include "test-common.h"
 #include "nm-test-utils.h"
 #include "NetworkManagerUtils.h"
@@ -7,7 +9,7 @@
 #define DEVICE_NAME "nm-test-device"
 
 static void
-ip4_route_callback (NMPlatform *platform, int ifindex, NMPlatformIP4Route *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data)
+ip4_route_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, const NMPlatformIP4Route *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data)
 {
 	g_assert (received);
 	g_assert_cmpint (received->ifindex, ==, ifindex);
@@ -22,14 +24,12 @@ ip4_route_callback (NMPlatform *platform, int ifindex, NMPlatformIP4Route *recei
 	if (data->loop)
 		g_main_loop_quit (data->loop);
 
-	if (data->received)
-		g_error ("Received signal '%s' a second time.", data->name);
-
-	data->received = TRUE;
+	data->received_count++;
+	debug ("Received signal '%s' %dth time.", data->name, data->received_count);
 }
 
 static void
-ip6_route_callback (NMPlatform *platform, int ifindex, NMPlatformIP6Route *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data)
+ip6_route_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, const NMPlatformIP6Route *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data)
 {
 	g_assert (received);
 	g_assert_cmpint (received->ifindex, ==, ifindex);
@@ -44,16 +44,14 @@ ip6_route_callback (NMPlatform *platform, int ifindex, NMPlatformIP6Route *recei
 	if (data->loop)
 		g_main_loop_quit (data->loop);
 
-	if (data->received)
-		g_error ("Received signal '%s' a second time.", data->name);
-
-	data->received = TRUE;
+	data->received_count++;
+	debug ("Received signal '%s' %dth time.", data->name, data->received_count);
 }
 
 static void
 test_ip4_route_metric0 (void)
 {
-	int ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
+	int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
 	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);
@@ -67,48 +65,42 @@ test_ip4_route_metric0 (void)
 	assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, metric);
 
 	/* add the first route */
-	g_assert (nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, metric, mss));
-	no_error ();
+	g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, metric, mss));
 	accept_signal (route_added);
 
 	assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, 0);
 	assert_ip4_route_exists (TRUE,  DEVICE_NAME, network, plen, metric);
 
 	/* Deleting route with metric 0 does nothing */
-	g_assert (nm_platform_ip4_route_delete (ifindex, network, plen, 0));
-	no_error ();
-	g_assert (!route_removed->received);
+	g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, 0));
+	ensure_no_signal (route_removed);
 
 	assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, 0);
 	assert_ip4_route_exists (TRUE,  DEVICE_NAME, network, plen, metric);
 
 	/* add the second route */
-	g_assert (nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, 0, mss));
-	no_error ();
+	g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, 0, mss));
 	accept_signal (route_added);
 
 	assert_ip4_route_exists (TRUE,  DEVICE_NAME, network, plen, 0);
 	assert_ip4_route_exists (TRUE,  DEVICE_NAME, network, plen, metric);
 
 	/* Delete route with metric 0 */
-	g_assert (nm_platform_ip4_route_delete (ifindex, network, plen, 0));
-	no_error ();
+	g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, 0));
 	accept_signal (route_removed);
 
 	assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, 0);
 	assert_ip4_route_exists (TRUE,  DEVICE_NAME, network, plen, metric);
 
 	/* Delete route with metric 0 again (we expect nothing to happen) */
-	g_assert (nm_platform_ip4_route_delete (ifindex, network, plen, 0));
-	no_error ();
-	g_assert (!route_removed->received);
+	g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, 0));
+	ensure_no_signal (route_removed);
 
 	assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, 0);
 	assert_ip4_route_exists (TRUE,  DEVICE_NAME, network, plen, metric);
 
 	/* Delete the other route */
-	g_assert (nm_platform_ip4_route_delete (ifindex, network, plen, metric));
-	no_error ();
+	g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric));
 	accept_signal (route_removed);
 
 	assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, 0);
@@ -122,7 +114,7 @@ test_ip4_route_metric0 (void)
 static void
 test_ip4_route (void)
 {
-	int ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
+	int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
 	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);
@@ -139,40 +131,31 @@ test_ip4_route (void)
 	inet_pton (AF_INET, "198.51.100.1", &gateway);
 
 	/* Add route to gateway */
-	g_assert (nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 32, INADDR_ANY, 0, metric, mss));
-	no_error ();
+	g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 32, INADDR_ANY, 0, metric, mss));
 	accept_signal (route_added);
 
 	/* Add route */
 	assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, metric);
-	no_error ();
-	g_assert (nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, 0, metric, mss));
-	no_error ();
+	g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, 0, metric, mss));
 	assert_ip4_route_exists (TRUE, DEVICE_NAME, network, plen, metric);
-	no_error ();
 	accept_signal (route_added);
 
 	/* Add route again */
-	g_assert (nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, 0, metric, mss));
-	no_error ();
-	accept_signal (route_changed);
+	g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, 0, metric, mss));
+	accept_signals (route_changed, 0, 1);
 
 	/* Add default route */
 	assert_ip4_route_exists (FALSE, DEVICE_NAME, 0, 0, metric);
-	no_error ();
-	g_assert (nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway, 0, metric, mss));
-	no_error ();
+	g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway, 0, metric, mss));
 	assert_ip4_route_exists (TRUE, DEVICE_NAME, 0, 0, metric);
-	no_error ();
 	accept_signal (route_added);
 
 	/* Add default route again */
-	g_assert (nm_platform_ip4_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway, 0, metric, mss));
-	no_error ();
-	accept_signal (route_changed);
+	g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway, 0, metric, mss));
+	accept_signals (route_changed, 0, 1);
 
 	/* Test route listing */
-	routes = nm_platform_ip4_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
+	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);
 	memset (rts, 0, sizeof (rts));
 	rts[0].source = NM_IP_CONFIG_SOURCE_USER;
 	rts[0].network = gateway;
@@ -181,6 +164,7 @@ test_ip4_route (void)
 	rts[0].gateway = INADDR_ANY;
 	rts[0].metric = metric;
 	rts[0].mss = mss;
+	rts[0].scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK);
 	rts[1].source = NM_IP_CONFIG_SOURCE_USER;
 	rts[1].network = network;
 	rts[1].plen = plen;
@@ -188,6 +172,7 @@ test_ip4_route (void)
 	rts[1].gateway = gateway;
 	rts[1].metric = metric;
 	rts[1].mss = mss;
+	rts[1].scope_inv = nm_platform_route_scope_inv (RT_SCOPE_UNIVERSE);
 	rts[2].source = NM_IP_CONFIG_SOURCE_USER;
 	rts[2].network = 0;
 	rts[2].plen = 0;
@@ -195,20 +180,18 @@ test_ip4_route (void)
 	rts[2].gateway = gateway;
 	rts[2].metric = metric;
 	rts[2].mss = mss;
+	rts[2].scope_inv = nm_platform_route_scope_inv (RT_SCOPE_UNIVERSE);
 	g_assert_cmpint (routes->len, ==, 3);
-	g_assert (!memcmp (routes->data, rts, sizeof (rts)));
 	nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, rts, routes->len, TRUE);
 	g_array_unref (routes);
 
 	/* Remove route */
-	g_assert (nm_platform_ip4_route_delete (ifindex, network, plen, metric));
-	no_error ();
+	g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric));
 	assert_ip4_route_exists (FALSE, DEVICE_NAME, network, plen, metric);
 	accept_signal (route_removed);
 
 	/* Remove route again */
-	g_assert (nm_platform_ip4_route_delete (ifindex, network, plen, metric));
-	no_error ();
+	g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric));
 
 	free_signal (route_added);
 	free_signal (route_changed);
@@ -218,7 +201,7 @@ test_ip4_route (void)
 static void
 test_ip6_route (void)
 {
-	int ifindex = nm_platform_link_get_ifindex (DEVICE_NAME);
+	int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
 	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);
@@ -235,40 +218,31 @@ test_ip6_route (void)
 	inet_pton (AF_INET6, "2001:db8:c:d:1:2:3:4", &gateway);
 
 	/* Add route to gateway */
-	g_assert (nm_platform_ip6_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 128, in6addr_any, metric, mss));
-	no_error ();
+	g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 128, in6addr_any, metric, mss));
 	accept_signal (route_added);
 
 	/* Add route */
-	g_assert (!nm_platform_ip6_route_exists (ifindex, network, plen, metric));
-	no_error ();
-	g_assert (nm_platform_ip6_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, metric, mss));
-	no_error ();
-	g_assert (nm_platform_ip6_route_exists (ifindex, network, plen, metric));
-	no_error ();
+	g_assert (!nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, network, plen, metric));
+	g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, metric, mss));
+	g_assert (nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, network, plen, metric));
 	accept_signal (route_added);
 
 	/* Add route again */
-	g_assert (nm_platform_ip6_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, metric, mss));
-	no_error ();
-	accept_signal (route_changed);
+	g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, metric, mss));
+	accept_signals (route_changed, 0, 1);
 
 	/* Add default route */
-	g_assert (!nm_platform_ip6_route_exists (ifindex, in6addr_any, 0, metric));
-	no_error ();
-	g_assert (nm_platform_ip6_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, metric, mss));
-	no_error ();
-	g_assert (nm_platform_ip6_route_exists (ifindex, in6addr_any, 0, metric));
-	no_error ();
+	g_assert (!nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, in6addr_any, 0, metric));
+	g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, metric, mss));
+	g_assert (nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, in6addr_any, 0, metric));
 	accept_signal (route_added);
 
 	/* Add default route again */
-	g_assert (nm_platform_ip6_route_add (ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, metric, mss));
-	no_error ();
-	accept_signal (route_changed);
+	g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, metric, mss));
+	accept_signals (route_changed, 0, 1);
 
 	/* Test route listing */
-	routes = nm_platform_ip6_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
+	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);
 	memset (rts, 0, sizeof (rts));
 	rts[0].source = NM_IP_CONFIG_SOURCE_USER;
 	rts[0].network = gateway;
@@ -292,19 +266,16 @@ test_ip6_route (void)
 	rts[2].metric = nm_utils_ip6_route_metric_normalize (metric);
 	rts[2].mss = mss;
 	g_assert_cmpint (routes->len, ==, 3);
-	g_assert (!memcmp (routes->data, rts, sizeof (rts)));
 	nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, rts, routes->len, TRUE);
 	g_array_unref (routes);
 
 	/* Remove route */
-	g_assert (nm_platform_ip6_route_delete (ifindex, network, plen, metric));
-	no_error ();
-	g_assert (!nm_platform_ip6_route_exists (ifindex, network, plen, metric));
+	g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric));
+	g_assert (!nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, network, plen, metric));
 	accept_signal (route_removed);
 
 	/* Remove route again */
-	g_assert (nm_platform_ip6_route_delete (ifindex, network, plen, metric));
-	no_error ();
+	g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric));
 
 	free_signal (route_added);
 	free_signal (route_changed);
@@ -322,13 +293,13 @@ setup_tests (void)
 {
 	SignalData *link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME);
 
-	nm_platform_link_delete (nm_platform_link_get_ifindex (DEVICE_NAME));
-	g_assert (!nm_platform_link_exists (DEVICE_NAME));
-	g_assert (nm_platform_dummy_add (DEVICE_NAME));
+	nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME));
+	g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, DEVICE_NAME));
+	g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL) == NM_PLATFORM_ERROR_SUCCESS);
 	accept_signal (link_added);
 	free_signal (link_added);
 
-	g_assert (nm_platform_link_set_up (nm_platform_link_get_ifindex (DEVICE_NAME)));
+	g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME), NULL));
 
 	g_test_add_func ("/route/ip4", test_ip4_route);
 	g_test_add_func ("/route/ip6", test_ip6_route);