summary refs log tree commit diff
path: root/src/platform
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2017-05-11 14:55:55 +0200
committerMichael Biebl <biebl@debian.org>2017-05-11 14:55:55 +0200
commitc333f062ddcba9b35330647bf6cbd0a07f2d786e (patch)
tree257c3a0c74c09f4ad2328eab5b932806405f0c1c /src/platform
parenta222e56e103f949b148a6942e385ccca2c26d9f3 (diff)
New upstream version 1.8.0 upstream/1.8.0
Diffstat (limited to 'src/platform')
-rw-r--r--src/platform/nm-fake-platform.c130
-rw-r--r--src/platform/nm-linux-platform.c556
-rw-r--r--src/platform/nm-linux-platform.h2
-rw-r--r--src/platform/nm-platform-utils.c25
-rw-r--r--src/platform/nm-platform-utils.h6
-rw-r--r--src/platform/nm-platform.c318
-rw-r--r--src/platform/nm-platform.h81
-rw-r--r--src/platform/nmp-netns.c2
-rw-r--r--src/platform/nmp-object.c94
-rw-r--r--src/platform/nmp-object.h26
-rw-r--r--src/platform/tests/test-cleanup.c12
-rw-r--r--src/platform/tests/test-common.c50
-rw-r--r--src/platform/tests/test-common.h22
-rw-r--r--src/platform/tests/test-general.c4
-rw-r--r--src/platform/tests/test-link.c14
-rw-r--r--src/platform/tests/test-nmp-object.c42
-rw-r--r--src/platform/tests/test-route.c174
-rw-r--r--src/platform/wifi/wifi-utils-nl80211.c81
-rw-r--r--src/platform/wifi/wifi-utils-nl80211.h2
-rw-r--r--src/platform/wifi/wifi-utils-private.h3
-rw-r--r--src/platform/wifi/wifi-utils-wext.c276
-rw-r--r--src/platform/wifi/wifi-utils-wext.h2
-rw-r--r--src/platform/wifi/wifi-utils.c19
-rw-r--r--src/platform/wifi/wifi-utils.h4
24 files changed, 1291 insertions, 654 deletions
diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c
index b92f56ce..38706f37 100644
--- a/src/platform/nm-fake-platform.c
+++ b/src/platform/nm-fake-platform.c
@@ -82,13 +82,13 @@ G_DEFINE_TYPE (NMFakePlatform, nm_fake_platform, NM_TYPE_PLATFORM)
         if (nm_logging_enabled (__level, __domain)) { \
             char __prefix[32]; \
             const char *__p_prefix = _NMLOG_PREFIX_NAME; \
-            const void *const __self = (self); \
+            NMPlatform *const __self = (self); \
             \
-            if (__self && __self != nm_platform_try_get ()) { \
+            if (__self && nm_platform_get_log_with_ptr (self)) { \
                 g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \
                 __p_prefix = __prefix; \
             } \
-            _nm_log (__level, __domain, 0, \
+            _nm_log (__level, __domain, 0, NULL, NULL, \
                      "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
                      __p_prefix _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
         } \
@@ -573,6 +573,12 @@ link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu)
 	return !!device;
 }
 
+static gboolean
+link_set_sriov_num_vfs (NMPlatform *platform, int ifindex, guint num_vfs)
+{
+	return TRUE;
+}
+
 static const char *
 link_get_udi (NMPlatform *platform, int ifindex)
 {
@@ -633,6 +639,22 @@ link_supports_vlans (NMPlatform *platform, int ifindex)
 }
 
 static gboolean
+link_supports_sriov (NMPlatform *platform, int ifindex)
+{
+	NMFakePlatformLink *device = link_get (platform, ifindex);
+
+	if (!device)
+		return FALSE;
+
+	switch (device->link.type) {
+	case NM_LINK_TYPE_LOOPBACK:
+		return FALSE;
+	default:
+		return TRUE;
+	}
+}
+
+static gboolean
 link_enslave (NMPlatform *platform, int master, int slave)
 {
 	NMFakePlatformLink *device = link_get (platform, slave);
@@ -1225,42 +1247,29 @@ ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, gu
 }
 
 static gboolean
-ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
-               in_addr_t network, guint8 plen, in_addr_t gateway,
-               in_addr_t pref_src, guint32 metric, guint32 mss)
+ip4_route_add (NMPlatform *platform, const NMPlatformIP4Route *route)
 {
 	NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
-	NMPlatformIP4Route route;
+	NMPlatformIP4Route rt = *route;
 	guint i;
-	guint8 scope;
-
-	g_assert (plen <= 32);
 
-	scope = gateway == 0 ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE;
+	rt.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (rt.rt_source);
+	rt.network = nm_utils_ip4_address_clear_host_address (rt.network, rt.plen);
+	rt.scope_inv = nm_platform_route_scope_inv (rt.gateway ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK);
 
-	memset (&route, 0, sizeof (route));
-	route.ifindex = ifindex;
-	route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (source);
-	route.network = nm_utils_ip4_address_clear_host_address (network, plen);
-	route.plen = plen;
-	route.gateway = gateway;
-	route.metric = metric;
-	route.mss = mss;
-	route.scope_inv = nm_platform_route_scope_inv (scope);
-
-	if (gateway) {
+	if (rt.gateway) {
 		for (i = 0; i < priv->ip4_routes->len; i++) {
 			NMPlatformIP4Route *item = &g_array_index (priv->ip4_routes,
 			                                           NMPlatformIP4Route, i);
 			guint32 gate = ntohl (item->network) >> (32 - item->plen);
-			guint32 host = ntohl (gateway) >> (32 - item->plen);
+			guint32 host = ntohl (rt.gateway) >> (32 - item->plen);
 
-			if (ifindex == item->ifindex && gate == host)
+			if (rt.ifindex == item->ifindex && gate == host)
 				break;
 		}
 		if (i == priv->ip4_routes->len) {
 			nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip4-route '%d: %s/%d %d': Network Unreachable",
-			             route.ifindex, nm_utils_inet4_ntop (route.network, NULL), route.plen, route.metric);
+			             rt.ifindex, nm_utils_inet4_ntop (rt.network, NULL), rt.plen, rt.metric);
 			return FALSE;
 		}
 	}
@@ -1268,65 +1277,58 @@ ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
 	for (i = 0; i < priv->ip4_routes->len; i++) {
 		NMPlatformIP4Route *item = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i);
 
-		if (item->network != route.network)
+		if (item->network != rt.network)
 			continue;
-		if (item->plen != route.plen)
+		if (item->plen != rt.plen)
 			continue;
-		if (item->metric != metric)
+		if (item->metric != rt.metric)
 			continue;
 
-		if (item->ifindex != route.ifindex) {
+		if (item->ifindex != rt.ifindex) {
 			ip4_route_delete (platform, item->ifindex, item->network, item->plen, item->metric);
 			i--;
 			continue;
 		}
 
-		memcpy (item, &route, sizeof (route));
-		g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP4_ROUTE, ifindex, &route, (int) NM_PLATFORM_SIGNAL_CHANGED);
+		memcpy (item, &rt, sizeof (rt));
+		g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP4_ROUTE,
+		                       rt.ifindex, &rt, (int) NM_PLATFORM_SIGNAL_CHANGED);
 		return TRUE;
 	}
 
-	g_array_append_val (priv->ip4_routes, route);
-	g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP4_ROUTE, ifindex, &route, (int) NM_PLATFORM_SIGNAL_ADDED);
+	g_array_append_val (priv->ip4_routes, rt);
+	g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP4_ROUTE,
+	                       rt.ifindex, &rt, (int) NM_PLATFORM_SIGNAL_ADDED);
 
 	return TRUE;
 }
 
 static gboolean
-ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
-               struct in6_addr network, guint8 plen, struct in6_addr gateway,
-               guint32 metric, guint32 mss)
+ip6_route_add (NMPlatform *platform, const NMPlatformIP6Route *route)
 {
 	NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
-	NMPlatformIP6Route route;
+	NMPlatformIP6Route rt = *route;
 	guint i;
 
-	metric = nm_utils_ip6_route_metric_normalize (metric);
-
-	memset (&route, 0, sizeof (route));
-	route.ifindex = ifindex;
-	route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (source);
-	nm_utils_ip6_address_clear_host_address (&route.network, &network, plen);
-	route.plen = plen;
-	route.gateway = gateway;
-	route.metric = metric;
-	route.mss = mss;
+	rt.metric = nm_utils_ip6_route_metric_normalize (rt.metric);
+	rt.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (rt.rt_source);
+	nm_utils_ip6_address_clear_host_address (&rt.network, &rt.network, rt.plen);
 
-	if (!IN6_IS_ADDR_UNSPECIFIED(&gateway)) {
+	if (!IN6_IS_ADDR_UNSPECIFIED (&rt.gateway)) {
 		for (i = 0; i < priv->ip6_routes->len; i++) {
 			NMPlatformIP6Route *item = &g_array_index (priv->ip6_routes,
 			                                           NMPlatformIP6Route, i);
-			guint8 gate_bits = gateway.s6_addr[item->plen / 8] >> (8 - item->plen % 8);
+			guint8 gate_bits = rt.gateway.s6_addr[item->plen / 8] >> (8 - item->plen % 8);
 			guint8 host_bits = item->network.s6_addr[item->plen / 8] >> (8 - item->plen % 8);
 
-			if (   ifindex == item->ifindex
-			    && memcmp (&gateway, &item->network, item->plen / 8) == 0
+			if (   rt.ifindex == item->ifindex
+			    && memcmp (&rt.gateway, &item->network, item->plen / 8) == 0
 			    && gate_bits == host_bits)
 				break;
 		}
 		if (i == priv->ip6_routes->len) {
 			nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip6-route '%d: %s/%d %d': Network Unreachable",
-			             route.ifindex, nm_utils_inet6_ntop (&route.network, NULL), route.plen, route.metric);
+			             rt.ifindex, nm_utils_inet6_ntop (&rt.network, NULL), rt.plen, rt.metric);
 			return FALSE;
 		}
 	}
@@ -1334,26 +1336,28 @@ ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
 	for (i = 0; i < priv->ip6_routes->len; i++) {
 		NMPlatformIP6Route *item = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i);
 
-		if (!IN6_ARE_ADDR_EQUAL (&item->network, &route.network))
+		if (!IN6_ARE_ADDR_EQUAL (&item->network, &rt.network))
 			continue;
-		if (item->plen != route.plen)
+		if (item->plen != rt.plen)
 			continue;
-		if (item->metric != metric)
+		if (item->metric != rt.metric)
 			continue;
 
-		if (item->ifindex != route.ifindex) {
+		if (item->ifindex != rt.ifindex) {
 			ip6_route_delete (platform, item->ifindex, item->network, item->plen, item->metric);
 			i--;
 			continue;
 		}
 
-		memcpy (item, &route, sizeof (route));
-		g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP6_ROUTE, ifindex, &route, (int) NM_PLATFORM_SIGNAL_CHANGED);
+		memcpy (item, &rt, sizeof (rt));
+		g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP6_ROUTE,
+		                       rt.ifindex, &rt, (int) NM_PLATFORM_SIGNAL_CHANGED);
 		return TRUE;
 	}
 
-	g_array_append_val (priv->ip6_routes, route);
-	g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP6_ROUTE, ifindex, &route, (int) NM_PLATFORM_SIGNAL_ADDED);
+	g_array_append_val (priv->ip6_routes, rt);
+	g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP6_ROUTE,
+	                       rt.ifindex, &rt, (int) NM_PLATFORM_SIGNAL_ADDED);
 
 	return TRUE;
 }
@@ -1418,7 +1422,9 @@ nm_fake_platform_setup (void)
 {
 	NMPlatform *platform;
 
-	platform = g_object_new (NM_TYPE_FAKE_PLATFORM, NULL);
+	platform = g_object_new (NM_TYPE_FAKE_PLATFORM,
+	                         NM_PLATFORM_LOG_WITH_PTR, FALSE,
+	                         NULL);
 
 	nm_platform_setup (platform);
 
@@ -1486,11 +1492,13 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass)
 
 	platform_class->link_set_address = link_set_address;
 	platform_class->link_set_mtu = link_set_mtu;
+	platform_class->link_set_sriov_num_vfs = link_set_sriov_num_vfs;
 
 	platform_class->link_get_driver_info = link_get_driver_info;
 
 	platform_class->link_supports_carrier_detect = link_supports_carrier_detect;
 	platform_class->link_supports_vlans = link_supports_vlans;
+	platform_class->link_supports_sriov = link_supports_sriov;
 
 	platform_class->link_enslave = link_enslave;
 	platform_class->link_release = link_release;
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 2c5f0897..252f054d 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -38,7 +38,7 @@
 #include <linux/if_tunnel.h>
 #include <netlink/netlink.h>
 #include <netlink/msg.h>
-#include <gudev/gudev.h>
+#include <libudev.h>
 
 #include "nm-utils.h"
 #include "nm-core-internal.h"
@@ -51,6 +51,7 @@
 #include "wifi/wifi-utils.h"
 #include "wifi/wifi-utils-wext.h"
 #include "nm-utils/unaligned.h"
+#include "nm-utils/nm-udev-utils.h"
 
 #define VLAN_FLAG_MVRP 0x8
 
@@ -144,13 +145,13 @@
     G_STMT_START { \
         char __prefix[32]; \
         const char *__p_prefix = _NMLOG_PREFIX_NAME; \
-        const void *const __self = (self); \
+        NMPlatform *const __self = (self); \
         \
-        if (__self && __self != nm_platform_try_get ()) { \
+        if (__self && nm_platform_get_log_with_ptr (__self)) { \
             g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \
             __p_prefix = __prefix; \
         } \
-        _nm_log (__level, __domain, __errsv, \
+        _nm_log (__level, __domain, __errsv, NULL, NULL, \
                  "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
                  __p_prefix _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
     } G_STMT_END
@@ -298,7 +299,7 @@ _support_user_ipv6ll_get (void)
 {
 	if (_support_user_ipv6ll_still_undecided ()) {
 		_support_user_ipv6ll = -1;
-		_LOG2W ("kernel support for IFLA_INET6_ADDR_GEN_MODE %s", "failed to detect; assume no support");
+		_LOG2D ("kernel-support: IFLA_INET6_ADDR_GEN_MODE: %s", "failed to detect; assume no support");
 		return FALSE;
 	}
 	return _support_user_ipv6ll > 0;
@@ -309,13 +310,11 @@ static void
 _support_user_ipv6ll_detect (struct nlattr **tb)
 {
 	if (_support_user_ipv6ll_still_undecided ()) {
-		if (tb[IFLA_INET6_ADDR_GEN_MODE]) {
-			_support_user_ipv6ll = 1;
-			_LOG2D ("kernel support for IFLA_INET6_ADDR_GEN_MODE %s", "detected");
-		} else {
-			_support_user_ipv6ll = -1;
-			_LOG2D ("kernel support for IFLA_INET6_ADDR_GEN_MODE %s", "not detected");
-		}
+		gboolean supported = !!tb[IFLA_INET6_ADDR_GEN_MODE];
+
+		_support_user_ipv6ll = supported ? 1 : -1;
+		_LOG2D ("kernel-support: IFLA_INET6_ADDR_GEN_MODE: %s",
+		        supported ? "detected" : "not detected");
 	}
 }
 
@@ -1835,6 +1834,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
 		NMIPAddr gateway;
 	} nh;
 	guint32 mss;
+	guint32 window = 0, cwnd = 0, initcwnd = 0, initrwnd = 0, mtu = 0, lock = 0;
 	guint32 table;
 
 	if (!nlmsg_valid_hdr (nlh, sizeof (*rtm)))
@@ -1848,8 +1848,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
 	if (!NM_IN_SET (rtm->rtm_family, AF_INET, AF_INET6))
 		goto errout;
 
-	if (   rtm->rtm_type != RTN_UNICAST
-	    || rtm->rtm_tos != 0)
+	if (rtm->rtm_type != RTN_UNICAST)
 		goto errout;
 
 	err = nlmsg_parse (nlh, sizeof (struct rtmsg), tb, RTA_MAX, policy);
@@ -1943,21 +1942,34 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
 	mss = 0;
 	if (tb[RTA_METRICS]) {
 		struct nlattr *mtb[RTAX_MAX + 1];
-		int i;
+		static struct nla_policy rtax_policy[RTAX_MAX + 1] = {
+			[RTAX_LOCK]        = { .type = NLA_U32 },
+			[RTAX_ADVMSS]      = { .type = NLA_U32 },
+			[RTAX_WINDOW]      = { .type = NLA_U32 },
+			[RTAX_CWND]        = { .type = NLA_U32 },
+			[RTAX_INITCWND]    = { .type = NLA_U32 },
+			[RTAX_INITRWND]    = { .type = NLA_U32 },
+			[RTAX_MTU]         = { .type = NLA_U32 },
+		};
 
-		err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL);
+		err = nla_parse_nested (mtb, RTAX_MAX, tb[RTA_METRICS], rtax_policy);
 		if (err < 0)
 			goto errout;
 
-		for (i = 1; i <= RTAX_MAX; i++) {
-			if (mtb[i]) {
-				if (i == RTAX_ADVMSS) {
-					if (nla_len (mtb[i]) >= sizeof (uint32_t))
-						mss = nla_get_u32(mtb[i]);
-					break;
-				}
-			}
-		}
+		if (mtb[RTAX_LOCK])
+			lock = nla_get_u32 (mtb[RTAX_LOCK]);
+		if (mtb[RTAX_ADVMSS])
+			mss = nla_get_u32 (mtb[RTAX_ADVMSS]);
+		if (mtb[RTAX_WINDOW])
+			window = nla_get_u32 (mtb[RTAX_WINDOW]);
+		if (mtb[RTAX_CWND])
+			cwnd = nla_get_u32 (mtb[RTAX_CWND]);
+		if (mtb[RTAX_INITCWND])
+			initcwnd = nla_get_u32 (mtb[RTAX_INITCWND]);
+		if (mtb[RTAX_INITRWND])
+			initrwnd = nla_get_u32 (mtb[RTAX_INITRWND]);
+		if (mtb[RTAX_MTU])
+			mtu = nla_get_u32 (mtb[RTAX_MTU]);
 	}
 
 	/*****************************************************************/
@@ -1982,12 +1994,31 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
 	if (is_v4)
 		obj->ip4_route.scope_inv = nm_platform_route_scope_inv (rtm->rtm_scope);
 
-	if (is_v4) {
-		if (_check_addr_or_errout (tb, RTA_PREFSRC, addr_len))
+	if (_check_addr_or_errout (tb, RTA_PREFSRC, addr_len)) {
+		if (is_v4)
 			memcpy (&obj->ip4_route.pref_src, nla_data (tb[RTA_PREFSRC]), addr_len);
+		else
+			memcpy (&obj->ip6_route.pref_src, nla_data (tb[RTA_PREFSRC]), addr_len);
+	}
+
+	if (!is_v4 && tb[RTA_SRC]) {
+		_check_addr_or_errout (tb, RTA_SRC, addr_len);
+		memcpy (&obj->ip6_route.src, nla_data (tb[RTA_SRC]), addr_len);
+		obj->ip6_route.src_plen = rtm->rtm_src_len;
 	}
 
 	obj->ip_route.mss = mss;
+	obj->ip_route.window = window;
+	obj->ip_route.cwnd = cwnd;
+	obj->ip_route.initcwnd = initcwnd;
+	obj->ip_route.initrwnd = initrwnd;
+	obj->ip_route.mtu = mtu;
+	obj->ip_route.tos = rtm->rtm_tos;
+	obj->ip_route.lock_window = NM_FLAGS_HAS (lock, 1 << RTAX_WINDOW);
+	obj->ip_route.lock_cwnd = NM_FLAGS_HAS (lock, 1 << RTAX_CWND);
+	obj->ip_route.lock_initcwnd = NM_FLAGS_HAS (lock, 1 << RTAX_INITCWND);
+	obj->ip_route.lock_initrwnd = NM_FLAGS_HAS (lock, 1 << RTAX_INITRWND);
+	obj->ip_route.lock_mtu  = NM_FLAGS_HAS (lock, 1 << RTAX_MTU);
 
 	if (NM_FLAGS_HAS (rtm->rtm_flags, RTM_F_CLONED)) {
 		/* we must not straight way reject cloned routes, because we might have cached
@@ -2362,21 +2393,29 @@ _nl_msg_new_route (int nlmsg_type,
                    gconstpointer gateway,
                    guint32 metric,
                    guint32 mss,
-                   gconstpointer pref_src)
+                   gconstpointer pref_src,
+                   gconstpointer src,
+                   guint8 src_plen,
+                   guint8 tos,
+                   guint32 window,
+                   guint32 cwnd,
+                   guint32 initcwnd,
+                   guint32 initrwnd,
+                   guint32 mtu,
+                   guint32 lock)
 {
 	struct nl_msg *msg;
 	struct rtmsg rtmsg = {
 		.rtm_family = family,
-		.rtm_tos = 0,
+		.rtm_tos = tos,
 		.rtm_table = RT_TABLE_MAIN, /* omit setting RTA_TABLE attribute */
 		.rtm_protocol = nmp_utils_ip_config_source_coerce_to_rtprot (source),
 		.rtm_scope = scope,
 		.rtm_type = RTN_UNICAST,
 		.rtm_flags = 0,
 		.rtm_dst_len = plen,
-		.rtm_src_len = 0,
+		.rtm_src_len = src ? src_plen : 0,
 	};
-	NMIPAddr network_clean;
 
 	gsize addr_len;
 
@@ -2393,22 +2432,37 @@ _nl_msg_new_route (int nlmsg_type,
 
 	addr_len = family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr);
 
-	nm_utils_ipx_address_clear_host_address (family, &network_clean, network, plen);
-	NLA_PUT (msg, RTA_DST, addr_len, &network_clean);
+	NLA_PUT (msg, RTA_DST, addr_len, network);
+
+	if (src)
+		NLA_PUT (msg, RTA_SRC, addr_len, src);
 
 	NLA_PUT_U32 (msg, RTA_PRIORITY, metric);
 
 	if (pref_src)
 		NLA_PUT (msg, RTA_PREFSRC, addr_len, pref_src);
 
-	if (mss > 0) {
+	if (mss || window || cwnd || initcwnd || initrwnd || mtu || lock) {
 		struct nlattr *metrics;
 
 		metrics = nla_nest_start (msg, RTA_METRICS);
 		if (!metrics)
 			goto nla_put_failure;
 
-		NLA_PUT_U32 (msg, RTAX_ADVMSS, mss);
+		if (mss)
+			NLA_PUT_U32 (msg, RTAX_ADVMSS, mss);
+		if (window)
+			NLA_PUT_U32 (msg, RTAX_WINDOW, window);
+		if (cwnd)
+			NLA_PUT_U32 (msg, RTAX_CWND, cwnd);
+		if (initcwnd)
+			NLA_PUT_U32 (msg, RTAX_INITCWND, initcwnd);
+		if (initrwnd)
+			NLA_PUT_U32 (msg, RTAX_INITRWND, initrwnd);
+		if (mtu)
+			NLA_PUT_U32 (msg, RTAX_MTU, mtu);
+		if (lock)
+			NLA_PUT_U32 (msg, RTAX_LOCK, lock);
 
 		nla_nest_end(msg, metrics);
 	}
@@ -2452,15 +2506,15 @@ _support_kernel_extended_ifa_flags_detect (struct nl_msg *msg)
 	 * we assume, that the kernel supports extended flags, IFA_F_MANAGETEMPADDR
 	 * and IFA_F_NOPREFIXROUTE (they were added together).
 	 **/
-	_support_kernel_extended_ifa_flags = !!nlmsg_find_attr (msg_hdr, sizeof (struct ifaddrmsg), 8 /* IFA_FLAGS */);
-	_LOG2D ("support: kernel-extended-ifa-flags: %ssupported", _support_kernel_extended_ifa_flags ? "" : "not ");
+	_support_kernel_extended_ifa_flags = !!nlmsg_find_attr (msg_hdr, sizeof (struct ifaddrmsg), IFA_FLAGS);
+	_LOG2D ("kernel-support: extended-ifa-flags: %s", _support_kernel_extended_ifa_flags ? "detected" : "not detected");
 }
 
 static gboolean
 _support_kernel_extended_ifa_flags_get (void)
 {
 	if (_support_kernel_extended_ifa_flags_still_undecided ()) {
-		_LOG2W ("support: kernel-extended-ifa-flags: unable to detect kernel support for handling IPv6 temporary addresses. Assume support");
+		_LOG2D ("kernel-support: extended-ifa-flags: %s", "unable to detect kernel support for handling IPv6 temporary addresses. Assume support");
 		_support_kernel_extended_ifa_flags = 1;
 	}
 	return _support_kernel_extended_ifa_flags;
@@ -2492,7 +2546,7 @@ typedef struct {
 	gboolean sysctl_get_warned;
 	GHashTable *sysctl_get_prev_values;
 
-	GUdevClient *udev_client;
+	NMUdevClient *udev_client;
 
 	struct {
 		/* which delayed actions are scheduled, as marked in @flags.
@@ -2526,19 +2580,13 @@ struct _NMLinuxPlatformClass {
 
 G_DEFINE_TYPE (NMLinuxPlatform, nm_linux_platform, NM_TYPE_PLATFORM)
 
-static inline NMLinuxPlatformPrivate *
-NM_LINUX_PLATFORM_GET_PRIVATE (const void *self)
-{
-	nm_assert (NM_IS_LINUX_PLATFORM (self));
-
-	return &(((NMLinuxPlatform *) self)->_priv);
-}
+#define NM_LINUX_PLATFORM_GET_PRIVATE(self) _NM_GET_PRIVATE_VOID(self, NMLinuxPlatform, NM_IS_LINUX_PLATFORM)
 
 NMPlatform *
-nm_linux_platform_new (gboolean netns_support)
+nm_linux_platform_new (gboolean log_with_ptr, gboolean netns_support)
 {
 	return g_object_new (NM_TYPE_LINUX_PLATFORM,
-	                     NM_PLATFORM_REGISTER_SINGLETON, FALSE,
+	                     NM_PLATFORM_LOG_WITH_PTR, log_with_ptr,
 	                     NM_PLATFORM_NETNS_SUPPORT, netns_support,
 	                     NULL);
 }
@@ -2546,10 +2594,7 @@ nm_linux_platform_new (gboolean netns_support)
 void
 nm_linux_platform_setup (void)
 {
-	g_object_new (NM_TYPE_LINUX_PLATFORM,
-	              NM_PLATFORM_REGISTER_SINGLETON, TRUE,
-	              NM_PLATFORM_NETNS_SUPPORT, FALSE,
-	              NULL);
+	nm_platform_setup (nm_linux_platform_new (FALSE, FALSE));
 }
 
 static void
@@ -2584,23 +2629,24 @@ static void
 _log_dbg_sysctl_set_impl (NMPlatform *platform, const char *pathid, int dirfd, const char *path, const char *value)
 {
 	GError *error = NULL;
-	char *contents, *contents_escaped;
-	char *value_escaped = g_strescape (value, NULL);
+	char *contents;
+	gs_free char *value_escaped = g_strescape (value, NULL);
 
 	if (nm_utils_file_get_contents (dirfd, path, 1*1024*1024, &contents, NULL, &error) < 0) {
 		_LOGD ("sysctl: setting '%s' to '%s' (current value cannot be read: %s)", pathid, value_escaped, error->message);
 		g_clear_error (&error);
-	} else {
-		g_strstrip (contents);
-		contents_escaped = g_strescape (contents, NULL);
-		if (strcmp (contents, value) == 0)
-			_LOGD ("sysctl: setting '%s' to '%s' (current value is identical)", pathid, value_escaped);
-		else
-			_LOGD ("sysctl: setting '%s' to '%s' (current value is '%s')", pathid, value_escaped, contents_escaped);
-		g_free (contents);
-		g_free (contents_escaped);
+		return;
 	}
-	g_free (value_escaped);
+
+	g_strstrip (contents);
+	if (nm_streq (contents, value))
+		_LOGD ("sysctl: setting '%s' to '%s' (current value is identical)", pathid, value_escaped);
+	else {
+		gs_free char *contents_escaped = g_strescape (contents, NULL);
+
+		_LOGD ("sysctl: setting '%s' to '%s' (current value is '%s')", pathid, value_escaped, contents_escaped);
+	}
+	g_free (contents);
 }
 
 #define _log_dbg_sysctl_set(platform, pathid, dirfd, path, value) \
@@ -2750,26 +2796,23 @@ _log_dbg_sysctl_get_impl (NMPlatform *platform, const char *pathid, const char *
 
 	if (prev_value) {
 		if (strcmp (prev_value, contents) != 0) {
-			char *contents_escaped = g_strescape (contents, NULL);
-			char *prev_value_escaped = g_strescape (prev_value, NULL);
+			gs_free char *contents_escaped = g_strescape (contents, NULL);
+			gs_free char *prev_value_escaped = g_strescape (prev_value, NULL);
 
 			_LOGD ("sysctl: reading '%s': '%s' (changed from '%s' on last read)", pathid, contents_escaped, prev_value_escaped);
-			g_free (contents_escaped);
-			g_free (prev_value_escaped);
 			g_hash_table_insert (priv->sysctl_get_prev_values, g_strdup (pathid), g_strdup (contents));
 		}
 	} else {
-		char *contents_escaped = g_strescape (contents, NULL);
+		gs_free char *contents_escaped = g_strescape (contents, NULL);
 
 		_LOGD ("sysctl: reading '%s': '%s'", pathid, contents_escaped);
-		g_free (contents_escaped);
 		g_hash_table_insert (priv->sysctl_get_prev_values, g_strdup (pathid), g_strdup (contents));
-	}
 
-	if (   !priv->sysctl_get_warned
-	    && g_hash_table_size (priv->sysctl_get_prev_values) > 50000) {
-		_LOGW ("sysctl: the internal cache for debug-logging of sysctl values grew pretty large. You can clear it by disabling debug-logging: `nmcli general logging level KEEP domains PLATFORM:INFO`.");
-		priv->sysctl_get_warned = TRUE;
+		if (   !priv->sysctl_get_warned
+		    && g_hash_table_size (priv->sysctl_get_prev_values) > 50000) {
+			_LOGW ("sysctl: the internal cache for debug-logging of sysctl values grew pretty large. You can clear it by disabling debug-logging: `nmcli general logging level KEEP domains PLATFORM:INFO`.");
+			priv->sysctl_get_warned = TRUE;
+		}
 	}
 }
 
@@ -4352,18 +4395,23 @@ link_get_unmanaged (NMPlatform *platform, int ifindex, gboolean *unmanaged)
 {
 	NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
 	const NMPObject *link;
-	GUdevDevice *udev_device = NULL;
+	struct udev_device *udevice = NULL;
+	const char *uproperty;
 
 	link = nmp_cache_lookup_link (priv->cache, ifindex);
-	if (link)
-		udev_device = link->_link.udev.device;
+	if (!link)
+		return FALSE;
 
-	if (udev_device && g_udev_device_get_property (udev_device, "NM_UNMANAGED")) {
-		*unmanaged = g_udev_device_get_property_as_boolean (udev_device, "NM_UNMANAGED");
-		return TRUE;
-	}
+	udevice = link->_link.udev.device;
+	if (!udevice)
+		return FALSE;
 
-	return FALSE;
+	uproperty = udev_device_get_property_value (udevice, "NM_UNMANAGED");
+	if (!uproperty)
+		return FALSE;
+
+	*unmanaged = nm_udev_utils_property_as_boolean (uproperty);
+	return TRUE;
 }
 
 static gboolean
@@ -4463,10 +4511,10 @@ link_get_udi (NMPlatform *platform, int ifindex)
 	    || !obj->_link.netlink.is_in_netlink
 	    || !obj->_link.udev.device)
 		return NULL;
-	return g_udev_device_get_sysfs_path (obj->_link.udev.device);
+	return udev_device_get_syspath (obj->_link.udev.device);
 }
 
-static GObject *
+static struct udev_device *
 link_get_udev_device (NMPlatform *platform, int ifindex)
 {
 	const NMPObject *obj_cache;
@@ -4477,7 +4525,7 @@ link_get_udev_device (NMPlatform *platform, int ifindex)
 	 * appears invisible via other platform functions. */
 
 	obj_cache = nmp_cache_lookup_link (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, ifindex);
-	return obj_cache ? (GObject *) obj_cache->_link.udev.device : NULL;
+	return obj_cache ? obj_cache->_link.udev.device : NULL;
 }
 
 static NMPlatformError
@@ -4556,6 +4604,30 @@ link_supports_vlans (NMPlatform *platform, int ifindex)
 	return nmp_utils_ethtool_supports_vlans (ifindex);
 }
 
+static gboolean
+link_supports_sriov (NMPlatform *platform, int ifindex)
+{
+	nm_auto_pop_netns NMPNetns *netns = NULL;
+	nm_auto_close int dirfd = -1;
+	char ifname[IFNAMSIZ];
+	int total = -1;
+
+	if (!nm_platform_netns_push (platform, &netns))
+		return FALSE;
+
+	dirfd = nm_platform_sysctl_open_netdir (platform, ifindex, ifname);
+	if (dirfd < 0)
+		return FALSE;
+
+	total = nm_platform_sysctl_get_int32 (platform,
+	                                      NMP_SYSCTL_PATHID_NETDIR (dirfd,
+	                                                                ifname,
+	                                                                "device/sriov_totalvfs"),
+	                                      -1);
+
+	return total > 0;
+}
+
 static NMPlatformError
 link_set_address (NMPlatform *platform, int ifindex, gconstpointer address, size_t length)
 {
@@ -4647,6 +4719,71 @@ nla_put_failure:
 	g_return_val_if_reached (FALSE);
 }
 
+static gboolean
+link_set_sriov_num_vfs (NMPlatform *platform, int ifindex, guint num_vfs)
+{
+	nm_auto_pop_netns NMPNetns *netns = NULL;
+	nm_auto_close int dirfd = -1;
+	int total, current;
+	char ifname[IFNAMSIZ];
+	char buf[64];
+
+	_LOGD ("link: change %d: num VFs: %u", ifindex, num_vfs);
+
+	if (!nm_platform_netns_push (platform, &netns))
+		return FALSE;
+
+	dirfd = nm_platform_sysctl_open_netdir (platform, ifindex, ifname);
+	if (!dirfd)
+		return FALSE;
+
+	total = nm_platform_sysctl_get_int32 (platform,
+	                                      NMP_SYSCTL_PATHID_NETDIR (dirfd,
+	                                                                ifname,
+	                                                                "device/sriov_totalvfs"),
+	                                      -1);
+	if (total < 1)
+		return FALSE;
+	if (num_vfs > total) {
+		_LOGW ("link: %d only supports %u VFs (requested %u)", ifindex, total, num_vfs);
+		num_vfs = total;
+	}
+
+	current = nm_platform_sysctl_get_int32 (platform,
+	                                        NMP_SYSCTL_PATHID_NETDIR (dirfd,
+	                                                                  ifname,
+	                                                                  "device/sriov_numvfs"),
+	                                        -1);
+	if (current == num_vfs)
+		return TRUE;
+
+	if (current != 0) {
+		/* We need to destroy all other VFs before changing the value */
+		if (!nm_platform_sysctl_set (NM_PLATFORM_GET,
+		                             NMP_SYSCTL_PATHID_NETDIR (dirfd,
+		                                                       ifname,
+		                                                      "device/sriov_numvfs"),
+		                             "0")) {
+			_LOGW ("link: couldn't set SR-IOV num_vfs to %d: %s", 0, strerror (errno));
+			return FALSE;
+		}
+		if (num_vfs == 0)
+			return TRUE;
+	}
+
+	/* Finally, set the desired value */
+	if (!nm_platform_sysctl_set (NM_PLATFORM_GET,
+	                             NMP_SYSCTL_PATHID_NETDIR (dirfd,
+	                                                       ifname,
+	                                                       "device/sriov_numvfs"),
+	                             nm_sprintf_buf (buf, "%d", num_vfs))) {
+		_LOGW ("link: couldn't set SR-IOV num_vfs to %d: %s", num_vfs, strerror (errno));
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
 static char *
 link_get_physical_port_id (NMPlatform *platform, int ifindex)
 {
@@ -4691,7 +4828,7 @@ vlan_add (NMPlatform *platform,
 	vlan_flags &= (guint32) NM_VLAN_FLAGS_ALL;
 
 	_LOGD ("link: add vlan '%s', parent %d, vlan id %d, flags %X",
-	       name, parent, vlan_id, (unsigned int) vlan_flags);
+	       name, parent, vlan_id, (unsigned) vlan_flags);
 
 	nlmsg = _nl_msg_new_link (RTM_NEWLINK,
 	                          NLM_F_CREATE | NLM_F_EXCL,
@@ -5153,7 +5290,7 @@ _vlan_change_vlan_qos_mapping_create (gboolean is_ingress_map,
 	if (current_n_map) {
 		if (is_ingress_map) {
 			/* For the ingress-map, there are only 8 entries (0 to 7).
-			 * When the user requests to reset all entires, we don't actually
+			 * When the user requests to reset all entries, we don't actually
 			 * need the cached entries, we can just explicitly clear all possible
 			 * ones.
 			 *
@@ -5456,34 +5593,17 @@ wifi_get_wifi_data (NMPlatform *platform, int ifindex)
 	wifi_data = g_hash_table_lookup (priv->wifi_data, GINT_TO_POINTER (ifindex));
 	pllink = nm_platform_link_get (platform, ifindex);
 
-	/* @wifi_data contains an interface name which is used for WEXT queries. If
-	 * the interface name changes we should at least replace the name in the
-	 * existing structure; but probably a complete reinitialization is better
-	 * because during the initial creation there can be race conditions while
-	 * the interface is renamed by udev.
-	 */
-	if (wifi_data && pllink) {
-		if (!nm_streq (wifi_utils_get_iface (wifi_data), pllink->name)) {
-			_LOGD ("wifi: interface %s renamed to %s, dropping old data for ifindex %d",
-			       wifi_utils_get_iface (wifi_data),
-			       pllink->name,
-			       ifindex);
-			g_hash_table_remove (priv->wifi_data, GINT_TO_POINTER (ifindex));
-			wifi_data = NULL;
-		}
-	}
-
 	if (!wifi_data) {
 		if (pllink) {
 			if (pllink->type == NM_LINK_TYPE_WIFI)
-				wifi_data = wifi_utils_init (pllink->name, ifindex, TRUE);
+				wifi_data = wifi_utils_init (ifindex, TRUE);
 			else if (pllink->type == NM_LINK_TYPE_OLPC_MESH) {
 				/* The kernel driver now uses nl80211, but we force use of WEXT because
 				 * the cfg80211 interactions are not quite ready to support access to
 				 * mesh control through nl80211 just yet.
 				 */
 #if HAVE_WEXT
-				wifi_data = wifi_wext_init (pllink->name, ifindex, FALSE);
+				wifi_data = wifi_wext_init (ifindex, FALSE);
 #endif
 			}
 
@@ -5905,53 +6025,85 @@ ip6_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags fl
 	return ipx_route_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP6_ROUTE, flags);
 }
 
+static guint32
+ip_route_get_lock_flag (NMPlatformIPRoute *route)
+{
+	return   (((guint32) route->lock_window) << RTAX_WINDOW)
+	       | (((guint32) route->lock_cwnd) << RTAX_CWND)
+	       | (((guint32) route->lock_initcwnd) << RTAX_INITCWND)
+	       | (((guint32) route->lock_initrwnd) << RTAX_INITRWND)
+	       | (((guint32) route->lock_mtu) << RTAX_MTU);
+}
+
 static gboolean
-ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
-               in_addr_t network, guint8 plen, in_addr_t gateway,
-               in_addr_t pref_src, guint32 metric, guint32 mss)
+ip4_route_add (NMPlatform *platform, const NMPlatformIP4Route *route)
 {
 	NMPObject obj_id;
 	nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
+	in_addr_t network;
+
+	network = nm_utils_ip4_address_clear_host_address (route->network, route->plen);
 
+	/* FIXME: take the scope from route into account */
 	nlmsg = _nl_msg_new_route (RTM_NEWROUTE,
 	                           NLM_F_CREATE | NLM_F_REPLACE,
 	                           AF_INET,
-	                           ifindex,
-	                           source,
-	                           gateway ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK,
+	                           route->ifindex,
+	                           route->rt_source,
+	                           route->gateway ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK,
 	                           &network,
-	                           plen,
-	                           &gateway,
-	                           metric,
-	                           mss,
-	                           pref_src ? &pref_src : NULL);
-
-	nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric);
+	                           route->plen,
+	                           &route->gateway,
+	                           route->metric,
+	                           route->mss,
+	                           route->pref_src ? &route->pref_src : NULL,
+	                           NULL,
+	                           0,
+	                           route->tos,
+	                           route->window,
+	                           route->cwnd,
+	                           route->initcwnd,
+	                           route->initrwnd,
+	                           route->mtu,
+	                           ip_route_get_lock_flag ((NMPlatformIPRoute *) route));
+
+	nmp_object_stackinit_id_ip4_route (&obj_id, route->ifindex, network, route->plen, route->metric);
 	return do_add_addrroute (platform, &obj_id, nlmsg);
 }
 
 static gboolean
-ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
-               struct in6_addr network, guint8 plen, struct in6_addr gateway,
-               guint32 metric, guint32 mss)
+ip6_route_add (NMPlatform *platform, const NMPlatformIP6Route *route)
 {
 	NMPObject obj_id;
 	nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
+	struct in6_addr network;
 
+	nm_utils_ip6_address_clear_host_address (&network, &route->network, route->plen);
+
+	/* FIXME: take the scope from route into account */
 	nlmsg = _nl_msg_new_route (RTM_NEWROUTE,
 	                           NLM_F_CREATE | NLM_F_REPLACE,
 	                           AF_INET6,
-	                           ifindex,
-	                           source,
-	                           !IN6_IS_ADDR_UNSPECIFIED (&gateway) ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK,
+	                           route->ifindex,
+	                           route->rt_source,
+	                           IN6_IS_ADDR_UNSPECIFIED (&route->gateway) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE,
 	                           &network,
-	                           plen,
-	                           &gateway,
-	                           metric,
-	                           mss,
-	                           NULL);
-
-	nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric);
+	                           route->plen,
+	                           &route->gateway,
+	                           route->metric,
+	                           route->mss,
+	                           !IN6_IS_ADDR_UNSPECIFIED (&route->pref_src) ? &route->pref_src : NULL,
+	                           !IN6_IS_ADDR_UNSPECIFIED (&route->src) ? &route->src : NULL,
+	                           route->src_plen,
+	                           route->tos,
+	                           route->window,
+	                           route->cwnd,
+	                           route->initcwnd,
+	                           route->initrwnd,
+	                           route->mtu,
+	                           ip_route_get_lock_flag ((NMPlatformIPRoute *) route));
+
+	nmp_object_stackinit_id_ip6_route (&obj_id, route->ifindex, &network, route->plen, route->metric);
 	return do_add_addrroute (platform, &obj_id, nlmsg);
 }
 
@@ -5962,6 +6114,8 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 p
 	nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
 	NMPObject obj_id;
 
+	network = nm_utils_ip4_address_clear_host_address (network, plen);
+
 	nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric);
 
 	if (metric == 0) {
@@ -6004,7 +6158,16 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 p
 	                           NULL,
 	                           metric,
 	                           0,
-	                           NULL);
+	                           NULL,
+	                           NULL,
+	                           0,
+	                           0,
+	                           0,
+	                           0,
+	                           0,
+	                           0,
+	                           0,
+	                           0);
 	if (!nlmsg)
 		return FALSE;
 
@@ -6019,6 +6182,8 @@ ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, gu
 
 	metric = nm_utils_ip6_route_metric_normalize (metric);
 
+	nm_utils_ip6_address_clear_host_address (&network, &network, plen);
+
 	nlmsg = _nl_msg_new_route (RTM_DELROUTE,
 	                           0,
 	                           AF_INET6,
@@ -6030,7 +6195,16 @@ ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, gu
 	                           NULL,
 	                           metric,
 	                           0,
-	                           NULL);
+	                           NULL,
+	                           NULL,
+	                           0,
+	                           0,
+	                           0,
+	                           0,
+	                           0,
+	                           0,
+	                           0,
+	                           0);
 	if (!nlmsg)
 		return FALSE;
 
@@ -6423,14 +6597,16 @@ after_read:
 /*****************************************************************************/
 
 static void
-cache_update_link_udev (NMPlatform *platform, int ifindex, GUdevDevice *udev_device)
+cache_update_link_udev (NMPlatform *platform,
+                        int ifindex,
+                        struct udev_device *udevice)
 {
 	NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
 	nm_auto_nmpobj NMPObject *obj_cache = NULL;
 	gboolean was_visible;
 	NMPCacheOpsType cache_op;
 
-	cache_op = nmp_cache_update_link_udev (priv->cache, ifindex, udev_device, &obj_cache, &was_visible, cache_pre_hook, platform);
+	cache_op = nmp_cache_update_link_udev (priv->cache, ifindex, udevice, &obj_cache, &was_visible, cache_pre_hook, platform);
 
 	if (cache_op != NMP_CACHE_OPS_UNCHANGED) {
 		nm_auto_pop_netns NMPNetns *netns = NULL;
@@ -6443,55 +6619,58 @@ cache_update_link_udev (NMPlatform *platform, int ifindex, GUdevDevice *udev_dev
 
 static void
 udev_device_added (NMPlatform *platform,
-                   GUdevDevice *udev_device)
+                   struct udev_device *udevice)
 {
 	const char *ifname;
+	const char *ifindex_s;
 	int ifindex;
 
-	ifname = g_udev_device_get_name (udev_device);
+	ifname = udev_device_get_sysname (udevice);
 	if (!ifname) {
 		_LOGD ("udev-add: failed to get device's interface");
 		return;
 	}
 
-	if (!g_udev_device_get_property (udev_device, "IFINDEX")) {
+	ifindex_s = udev_device_get_property_value (udevice, "IFINDEX");
+	if (!ifindex_s) {
 		_LOGW ("udev-add[%s]failed to get device's ifindex", ifname);
 		return;
 	}
-	ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX");
+	ifindex = _nm_utils_ascii_str_to_int64 (ifindex_s, 10, 1, G_MAXINT, 0);
 	if (ifindex <= 0) {
 		_LOGW ("udev-add[%s]: retrieved invalid IFINDEX=%d", ifname, ifindex);
 		return;
 	}
 
-	if (!g_udev_device_get_sysfs_path (udev_device)) {
+	if (!udev_device_get_syspath (udevice)) {
 		_LOGD ("udev-add[%s,%d]: couldn't determine device path; ignoring...", ifname, ifindex);
 		return;
 	}
 
 	_LOGT ("udev-add[%s,%d]: device added", ifname, ifindex);
-	cache_update_link_udev (platform, ifindex, udev_device);
+	cache_update_link_udev (platform, ifindex, udevice);
 }
 
 static gboolean
-_udev_device_removed_match_link (const NMPObject *obj, gpointer udev_device)
+_udev_device_removed_match_link (const NMPObject *obj, gpointer udevice)
 {
-	return obj->_link.udev.device == udev_device;
+	return obj->_link.udev.device == udevice;
 }
 
 static void
 udev_device_removed (NMPlatform *platform,
-                     GUdevDevice *udev_device)
+                     struct udev_device *udevice)
 {
+	const char *ifindex_s;
 	int ifindex = 0;
 
-	if (g_udev_device_get_property (udev_device, "IFINDEX"))
-		ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX");
-	else {
+	ifindex_s = udev_device_get_property_value (udevice, "IFINDEX");
+	ifindex = _nm_utils_ascii_str_to_int64 (ifindex_s, 10, 1, G_MAXINT, 0);
+	if (ifindex <= 0) {
 		const NMPObject *obj;
 
 		obj = nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache,
-		                                  0, NULL, FALSE, NM_LINK_TYPE_NONE, _udev_device_removed_match_link, udev_device);
+		                                  0, NULL, FALSE, NM_LINK_TYPE_NONE, _udev_device_removed_match_link, udevice);
 		if (obj)
 			ifindex = obj->link.ifindex;
 	}
@@ -6504,9 +6683,8 @@ udev_device_removed (NMPlatform *platform,
 }
 
 static void
-handle_udev_event (GUdevClient *client,
-                   const char *action,
-                   GUdevDevice *udev_device,
+handle_udev_event (NMUdevClient *udev_client,
+                   struct udev_device *udevice,
                    gpointer user_data)
 {
 	nm_auto_pop_netns NMPNetns *netns = NULL;
@@ -6514,26 +6692,27 @@ handle_udev_event (GUdevClient *client,
 	const char *subsys;
 	const char *ifindex;
 	guint64 seqnum;
+	const char *action;
+
+	action = udev_device_get_action (udevice);
+	g_return_if_fail (action);
 
-	g_return_if_fail (action != NULL);
+	subsys = udev_device_get_subsystem (udevice);
+	g_return_if_fail (nm_streq0 (subsys, "net"));
 
 	if (!nm_platform_netns_push (platform, &netns))
 		return;
 
-	/* A bit paranoid */
-	subsys = g_udev_device_get_subsystem (udev_device);
-	g_return_if_fail (!g_strcmp0 (subsys, "net"));
-
-	ifindex = g_udev_device_get_property (udev_device, "IFINDEX");
-	seqnum = g_udev_device_get_seqnum (udev_device);
+	ifindex = udev_device_get_property_value (udevice, "IFINDEX");
+	seqnum = udev_device_get_seqnum (udevice);
 	_LOGD ("UDEV event: action '%s' subsys '%s' device '%s' (%s); seqnum=%" G_GUINT64_FORMAT,
-	        action, subsys, g_udev_device_get_name (udev_device),
+	        action, subsys, udev_device_get_sysname (udevice),
 	        ifindex ? ifindex : "unknown", seqnum);
 
-	if (!strcmp (action, "add") || !strcmp (action, "move"))
-		udev_device_added (platform, udev_device);
-	if (!strcmp (action, "remove"))
-		udev_device_removed (platform, udev_device);
+	if (NM_IN_STRSET (action, "add", "move"))
+		udev_device_added (platform, udevice);
+	else if (NM_IN_STRSET (action, "remove"))
+		udev_device_removed (platform, udevice);
 }
 
 /*****************************************************************************/
@@ -6554,8 +6733,10 @@ nm_linux_platform_init (NMLinuxPlatform *self)
 	priv->delayed_action.list_wait_for_nl_response = g_array_new (FALSE, TRUE, sizeof (DelayedActionWaitForNlResponseData));
 	priv->wifi_data = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) wifi_utils_deinit);
 
-	if (use_udev)
-		priv->udev_client = g_udev_client_new ((const char *[]) { "net", NULL });
+	if (use_udev) {
+		priv->udev_client = nm_udev_client_new ((const char *[]) { "net", NULL },
+		                                        handle_udev_event, self);
+	}
 }
 
 static void
@@ -6638,24 +6819,30 @@ constructed (GObject *_object)
 
 	/* Set up udev monitoring */
 	if (priv->udev_client) {
-		GUdevEnumerator *enumerator;
-		GList *devices, *iter;
-
-		g_signal_connect (priv->udev_client, "uevent", G_CALLBACK (handle_udev_event), platform);
+		struct udev_enumerate *enumerator;
+		struct udev_list_entry *devices, *l;
 
 		/* And read initial device list */
-		enumerator = g_udev_enumerator_new (priv->udev_client);
-		g_udev_enumerator_add_match_subsystem (enumerator, "net");
+		enumerator = nm_udev_client_enumerate_new (priv->udev_client);
+
+		udev_enumerate_add_match_is_initialized (enumerator);
 
-		g_udev_enumerator_add_match_is_initialized (enumerator);
+		udev_enumerate_scan_devices (enumerator);
 
-		devices = g_udev_enumerator_execute (enumerator);
-		for (iter = devices; iter; iter = g_list_next (iter)) {
-			udev_device_added (platform, G_UDEV_DEVICE (iter->data));
-			g_object_unref (G_UDEV_DEVICE (iter->data));
+		devices = udev_enumerate_get_list_entry (enumerator);
+		for (l = devices; l; l = udev_list_entry_get_next (l)) {
+			struct udev_device *udevice;
+
+			udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerator),
+			                                        udev_list_entry_get_name (l));
+			if (!udevice)
+				continue;
+
+			udev_device_added (platform, udevice);
+			udev_device_unref (udevice);
 		}
-		g_list_free (devices);
-		g_object_unref (enumerator);
+
+		udev_enumerate_unref (enumerator);
 	}
 }
 
@@ -6675,11 +6862,6 @@ dispose (GObject *object)
 
 	g_clear_pointer (&priv->prune_candidates, g_hash_table_unref);
 
-	if (priv->udev_client) {
-		g_signal_handlers_disconnect_by_func (priv->udev_client, G_CALLBACK (handle_udev_event), platform);
-		g_clear_object (&priv->udev_client);
-	}
-
 	G_OBJECT_CLASS (nm_linux_platform_parent_class)->dispose (object);
 }
 
@@ -6705,6 +6887,8 @@ finalize (GObject *object)
 		g_hash_table_destroy (priv->sysctl_get_prev_values);
 	}
 
+	priv->udev_client = nm_udev_client_unref (priv->udev_client);
+
 	G_OBJECT_CLASS (nm_linux_platform_parent_class)->finalize (object);
 }
 
@@ -6750,6 +6934,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
 	platform_class->link_set_address = link_set_address;
 	platform_class->link_get_permanent_address = link_get_permanent_address;
 	platform_class->link_set_mtu = link_set_mtu;
+	platform_class->link_set_sriov_num_vfs = link_set_sriov_num_vfs;
 
 	platform_class->link_get_physical_port_id = link_get_physical_port_id;
 	platform_class->link_get_dev_id = link_get_dev_id;
@@ -6758,6 +6943,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
 
 	platform_class->link_supports_carrier_detect = link_supports_carrier_detect;
 	platform_class->link_supports_vlans = link_supports_vlans;
+	platform_class->link_supports_sriov = link_supports_sriov;
 
 	platform_class->link_enslave = link_enslave;
 	platform_class->link_release = link_release;
diff --git a/src/platform/nm-linux-platform.h b/src/platform/nm-linux-platform.h
index b3272aae..6b66ea69 100644
--- a/src/platform/nm-linux-platform.h
+++ b/src/platform/nm-linux-platform.h
@@ -35,7 +35,7 @@ typedef struct _NMLinuxPlatformClass NMLinuxPlatformClass;
 
 GType nm_linux_platform_get_type (void);
 
-NMPlatform *nm_linux_platform_new (gboolean netns_support);
+NMPlatform *nm_linux_platform_new (gboolean log_with_ptr, gboolean netns_support);
 
 void nm_linux_platform_setup (void);
 
diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c
index 65fb01bc..b664e8a9 100644
--- a/src/platform/nm-platform-utils.c
+++ b/src/platform/nm-platform-utils.c
@@ -32,6 +32,7 @@
 #include <linux/version.h>
 #include <linux/rtnetlink.h>
 #include <fcntl.h>
+#include <libudev.h>
 
 #include "nm-utils.h"
 #include "nm-setting-wired.h"
@@ -42,8 +43,8 @@
  * utils
  ******************************************************************/
 
-extern char *if_indextoname (unsigned int __ifindex, char *__ifname);
-unsigned int if_nametoindex (const char *__ifname);
+extern char *if_indextoname (unsigned __ifindex, char *__ifname);
+unsigned if_nametoindex (const char *__ifname);
 
 const char *
 nmp_utils_if_indextoname (int ifindex, char *out_ifname/*IFNAMSIZ*/)
@@ -440,7 +441,7 @@ nmp_utils_ethtool_set_wake_on_lan (int ifindex,
 		return TRUE;
 
 	nm_log_dbg (LOGD_PLATFORM, "setting Wake-on-LAN options 0x%x, password '%s'",
-	            (unsigned int) wol, wol_password);
+	            (unsigned) wol, wol_password);
 
 	wol_info.cmd = ETHTOOL_SWOL;
 	wol_info.wolopts = 0;
@@ -520,35 +521,33 @@ nmp_utils_mii_supports_carrier_detect (int ifindex)
  ******************************************************************/
 
 const char *
-nmp_utils_udev_get_driver (GUdevDevice *device)
+nmp_utils_udev_get_driver (struct udev_device *udevice)
 {
-	GUdevDevice *parent = NULL, *grandparent = NULL;
+	struct udev_device *parent = NULL, *grandparent = NULL;
 	const char *driver, *subsys;
 
-	driver = g_udev_device_get_driver (device);
+	driver = udev_device_get_driver (udevice);
 	if (driver)
 		goto out;
 
 	/* Try the parent */
-	parent = g_udev_device_get_parent (device);
+	parent = udev_device_get_parent (udevice);
 	if (parent) {
-		driver = g_udev_device_get_driver (parent);
+		driver = udev_device_get_driver (parent);
 		if (!driver) {
 			/* Try the grandparent if it's an ibmebus device or if the
 			 * subsys is NULL which usually indicates some sort of
 			 * platform device like a 'gadget' net interface.
 			 */
-			subsys = g_udev_device_get_subsystem (parent);
+			subsys = udev_device_get_subsystem (parent);
 			if (   (g_strcmp0 (subsys, "ibmebus") == 0)
 			    || (subsys == NULL)) {
-				grandparent = g_udev_device_get_parent (parent);
+				grandparent = udev_device_get_parent (parent);
 				if (grandparent)
-					driver = g_udev_device_get_driver (grandparent);
+					driver = udev_device_get_driver (grandparent);
 			}
 		}
 	}
-	g_clear_object (&parent);
-	g_clear_object (&grandparent);
 
 out:
 	/* Intern the string so we don't have to worry about memory
diff --git a/src/platform/nm-platform-utils.h b/src/platform/nm-platform-utils.h
index 699e80c6..ea25470e 100644
--- a/src/platform/nm-platform-utils.h
+++ b/src/platform/nm-platform-utils.h
@@ -21,8 +21,6 @@
 #ifndef __NM_PLATFORM_UTILS_H__
 #define __NM_PLATFORM_UTILS_H__
 
-#include <gudev/gudev.h>
-
 #include "nm-platform.h"
 #include "nm-setting-wired.h"
 
@@ -66,7 +64,9 @@ gboolean  nmp_utils_ethtool_get_permanent_address (int ifindex,
 gboolean nmp_utils_mii_supports_carrier_detect (int ifindex);
 
 
-const char *nmp_utils_udev_get_driver (GUdevDevice *device);
+struct udev_device;
+
+const char *nmp_utils_udev_get_driver (struct udev_device *udevice);
 
 NMIPConfigSource nmp_utils_ip_config_source_from_rtprot (guint8 rtprot) _nm_const;
 guint8           nmp_utils_ip_config_source_coerce_to_rtprot   (NMIPConfigSource source) _nm_const;
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index a9014b36..767187d9 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -43,10 +43,6 @@
 
 /*****************************************************************************/
 
-const NMIPAddr nm_ip_addr_zero = NMIPAddrInit;
-
-/*****************************************************************************/
-
 G_STATIC_ASSERT (sizeof ( ((NMPlatformLink *) NULL)->addr.data ) == NM_UTILS_HWADDR_LEN_MAX);
 G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPAddress, address_ptr) == G_STRUCT_OFFSET (NMPlatformIP4Address, address));
 G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPAddress, address_ptr) == G_STRUCT_OFFSET (NMPlatformIP6Address, address));
@@ -62,13 +58,13 @@ G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPRoute, network_ptr) == G_STRUCT_OF
         if (nm_logging_enabled (__level, _NMLOG_DOMAIN)) { \
             char __prefix[32]; \
             const char *__p_prefix = _NMLOG_PREFIX_NAME; \
-            const void *const __self = (self); \
+            const NMPlatform *const __self = (self); \
             \
-            if (__self && __self != nm_platform_try_get ()) { \
+            if (__self && NM_PLATFORM_GET_PRIVATE (__self)->log_with_ptr) { \
                 g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \
                 __p_prefix = __prefix; \
             } \
-            _nm_log (__level, _NMLOG_DOMAIN, 0, \
+            _nm_log (__level, _NMLOG_DOMAIN, 0, NULL, NULL, \
                      "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
                      __p_prefix _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
         } \
@@ -83,12 +79,12 @@ static guint signals[_NM_PLATFORM_SIGNAL_ID_LAST] = { 0 };
 enum {
 	PROP_0,
 	PROP_NETNS_SUPPORT,
-	PROP_REGISTER_SINGLETON,
+	PROP_LOG_WITH_PTR,
 	LAST_PROP,
 };
 
 typedef struct _NMPlatformPrivate {
-	bool register_singleton:1;
+	bool log_with_ptr:1;
 } NMPlatformPrivate;
 
 G_DEFINE_TYPE (NMPlatform, nm_platform, G_TYPE_OBJECT)
@@ -97,6 +93,14 @@ G_DEFINE_TYPE (NMPlatform, nm_platform, G_TYPE_OBJECT)
 
 /*****************************************************************************/
 
+gboolean
+nm_platform_get_log_with_ptr (NMPlatform *self)
+{
+	return NM_PLATFORM_GET_PRIVATE (self)->log_with_ptr;
+}
+
+/*****************************************************************************/
+
 guint
 _nm_platform_signal_id_get (NMPlatformSignalIdType signal_type)
 {
@@ -187,12 +191,6 @@ nm_platform_get ()
 	return singleton_instance;
 }
 
-NMPlatform *
-nm_platform_try_get (void)
-{
-	return singleton_instance;
-}
-
 /*****************************************************************************/
 
 /**
@@ -444,11 +442,19 @@ _link_get_all_presort (gconstpointer  p_a,
 	const NMPlatformLink *a = p_a;
 	const NMPlatformLink *b = p_b;
 
-	if (a->ifindex < b->ifindex)
+	/* Loopback always first */
+	if (a->ifindex == 1)
 		return -1;
-	if (a->ifindex > b->ifindex)
+	if (b->ifindex == 1)
 		return 1;
-	return 0;
+
+	/* Initialized links first */
+	if (a->initialized > b->initialized)
+		return -1;
+	if (a->initialized < b->initialized)
+		return 1;
+
+	return strcmp (a->name, b->name);
 }
 
 /**
@@ -1000,7 +1006,7 @@ nm_platform_link_get_udi (NMPlatform *self, int ifindex)
 	return NULL;
 }
 
-GObject *
+struct udev_device *
 nm_platform_link_get_udev_device (NMPlatform *self, int ifindex)
 {
 	_CHECK_SELF (self, klass, FALSE);
@@ -1169,6 +1175,30 @@ nm_platform_link_supports_vlans (NMPlatform *self, int ifindex)
 	return klass->link_supports_vlans (self, ifindex);
 }
 
+gboolean
+nm_platform_link_supports_sriov (NMPlatform *self, int ifindex)
+{
+	_CHECK_SELF (self, klass, FALSE);
+
+	g_return_val_if_fail (ifindex >= 0, FALSE);
+
+	return klass->link_supports_sriov (self, ifindex);
+}
+
+gboolean
+nm_platform_link_set_sriov_num_vfs (NMPlatform *self, int ifindex, guint num_vfs)
+{
+	_CHECK_SELF (self, klass, FALSE);
+
+	g_return_val_if_fail (ifindex > 0, FALSE);
+
+	_LOGD ("link: setting %u VFs for %s (%d)",
+	       num_vfs,
+	       nm_strquote_a (25, nm_platform_link_get_name (self, ifindex)),
+	       ifindex);
+	return klass->link_set_sriov_num_vfs (self, ifindex, num_vfs);
+}
+
 /**
  * nm_platform_link_set_up:
  * @self: platform instance
@@ -1184,7 +1214,7 @@ nm_platform_link_set_up (NMPlatform *self, int ifindex, gboolean *out_no_firmwar
 
 	g_return_val_if_fail (ifindex > 0, FALSE);
 
-	_LOGD ("link: setting up '%s' (%d)", nm_platform_link_get_name (self, ifindex), ifindex);
+	_LOGD ("link: setting up %s (%d)", nm_strquote_a (25, nm_platform_link_get_name (self, ifindex)), ifindex);
 	return klass->link_set_up (self, ifindex, out_no_firmware);
 }
 
@@ -1202,7 +1232,7 @@ nm_platform_link_set_down (NMPlatform *self, int ifindex)
 
 	g_return_val_if_fail (ifindex > 0, FALSE);
 
-	_LOGD ("link: setting down '%s' (%d)", nm_platform_link_get_name (self, ifindex), ifindex);
+	_LOGD ("link: setting down %s (%d)", nm_strquote_a (25, nm_platform_link_get_name (self, ifindex)), ifindex);
 	return klass->link_set_down (self, ifindex);
 }
 
@@ -1220,7 +1250,7 @@ nm_platform_link_set_arp (NMPlatform *self, int ifindex)
 
 	g_return_val_if_fail (ifindex >= 0, FALSE);
 
-	_LOGD ("link: setting arp '%s' (%d)", nm_platform_link_get_name (self, ifindex), ifindex);
+	_LOGD ("link: setting arp %s (%d)", nm_strquote_a (25, nm_platform_link_get_name (self, ifindex)), ifindex);
 	return klass->link_set_arp (self, ifindex);
 }
 
@@ -3109,14 +3139,7 @@ nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRoute
 /**
  * nm_platform_ip4_route_add:
  * @self:
- * @ifindex:
- * @source:
- * network:
- * plen:
- * gateway:
- * pref_src:
- * metric:
- * mss:
+ * @route:
  *
  * For kernel, a gateway can be either explicitly set or left
  * at zero (0.0.0.0). In addition, there is the scope of the IPv4
@@ -3137,57 +3160,29 @@ nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRoute
  * Returns: %TRUE in case of success.
  */
 gboolean
-nm_platform_ip4_route_add (NMPlatform *self,
-                           int ifindex, NMIPConfigSource source,
-                           in_addr_t network, guint8 plen,
-                           in_addr_t gateway, in_addr_t pref_src,
-                           guint32 metric, guint32 mss)
+nm_platform_ip4_route_add (NMPlatform *self, const NMPlatformIP4Route *route)
 {
 	_CHECK_SELF (self, klass, FALSE);
 
-	g_return_val_if_fail (plen <= 32, FALSE);
+	g_return_val_if_fail (route, FALSE);
+	g_return_val_if_fail (route->plen <= 32, FALSE);
 
-	if (_LOGD_ENABLED ()) {
-		NMPlatformIP4Route route = { 0 };
-
-		route.ifindex = ifindex;
-		route.rt_source = source;
-		route.network = network;
-		route.plen = plen;
-		route.gateway = gateway;
-		route.metric = metric;
-		route.mss = mss;
-		route.pref_src = pref_src;
-
-		_LOGD ("route: adding or updating IPv4 route: %s", nm_platform_ip4_route_to_string (&route, NULL, 0));
-	}
-	return klass->ip4_route_add (self, ifindex, source, network, plen, gateway, pref_src, metric, mss);
+	_LOGD ("route: adding or updating IPv4 route: %s", nm_platform_ip4_route_to_string (route, NULL, 0));
+
+	return klass->ip4_route_add (self, route);
 }
 
 gboolean
-nm_platform_ip6_route_add (NMPlatform *self,
-                           int ifindex, NMIPConfigSource source,
-                           struct in6_addr network, guint8 plen, struct in6_addr gateway,
-                           guint32 metric, guint32 mss)
+nm_platform_ip6_route_add (NMPlatform *self, const NMPlatformIP6Route *route)
 {
 	_CHECK_SELF (self, klass, FALSE);
 
-	g_return_val_if_fail (plen <= 128, FALSE);
+	g_return_val_if_fail (route, FALSE);
+	g_return_val_if_fail (route->plen <= 128, FALSE);
 
-	if (_LOGD_ENABLED ()) {
-		NMPlatformIP6Route route = { 0 };
+	_LOGD ("route: adding or updating IPv6 route: %s", nm_platform_ip6_route_to_string (route, NULL, 0));
 
-		route.ifindex = ifindex;
-		route.rt_source = source;
-		route.network = network;
-		route.plen = plen;
-		route.gateway = gateway;
-		route.metric = metric;
-		route.mss = mss;
-
-		_LOGD ("route: adding or updating IPv6 route: %s", nm_platform_ip6_route_to_string (&route, NULL, 0));
-	}
-	return klass->ip6_route_add (self, ifindex, source, network, plen, gateway, metric, mss);
+	return klass->ip6_route_add (self, route);
 }
 
 gboolean
@@ -3900,6 +3895,7 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi
 	char s_pref_src[INET_ADDRSTRLEN];
 	char str_dev[TO_STRING_DEV_BUF_SIZE];
 	char str_scope[30], s_source[50];
+	char str_tos[32], str_window[32], str_cwnd[32], str_initcwnd[32], str_initrwnd[32], str_mtu[32];
 
 	if (!nm_utils_to_string_buffer_init_null (route, &buf, &len))
 		return buf;
@@ -3909,16 +3905,35 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi
 
 	_to_string_dev (NULL, route->ifindex, str_dev, sizeof (str_dev));
 
+	if (route->tos)
+		nm_sprintf_buf (str_tos, " tos 0x%x", (unsigned) route->tos);
+	if (route->window)
+		nm_sprintf_buf (str_window, " window %s%"G_GUINT32_FORMAT, route->lock_window ? "lock " : "", route->window);
+	if (route->cwnd)
+		nm_sprintf_buf (str_cwnd, " cwnd %s%"G_GUINT32_FORMAT, route->lock_cwnd ? "lock " : "", route->cwnd);
+	if (route->initcwnd)
+		nm_sprintf_buf (str_initcwnd, " initcwnd %s%"G_GUINT32_FORMAT, route->lock_initcwnd ? "lock " : "", route->initcwnd);
+	if (route->initrwnd)
+		nm_sprintf_buf (str_initrwnd, " initrwnd %s%"G_GUINT32_FORMAT, route->lock_initrwnd ? "lock " : "", route->initrwnd);
+	if (route->mtu)
+		nm_sprintf_buf (str_mtu, " mtu %s%"G_GUINT32_FORMAT, route->lock_mtu ? "lock " : "", route->mtu);
+
 	g_snprintf (buf, len,
 	            "%s/%d"
 	            " via %s"
 	            "%s"
 	            " metric %"G_GUINT32_FORMAT
 	            " mss %"G_GUINT32_FORMAT
-	            " src %s" /* source */
+	            " rt-src %s" /* protocol */
 	            "%s" /* cloned */
 	            "%s%s" /* scope */
 	            "%s%s" /* pref-src */
+	            "%s" /* tos */
+	            "%s" /* window */
+	            "%s" /* cwnd */
+	            "%s" /* initcwnd */
+	            "%s" /* initrwnd */
+	            "%s" /* mtu */
 	            "",
 	            s_network,
 	            route->plen,
@@ -3931,7 +3946,13 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi
 	            route->scope_inv ? " scope " : "",
 	            route->scope_inv ? (nm_platform_route_scope2str (nm_platform_route_scope_inv (route->scope_inv), str_scope, sizeof (str_scope))) : "",
 	            route->pref_src ? " pref-src " : "",
-	            route->pref_src ? inet_ntop (AF_INET, &route->pref_src, s_pref_src, sizeof(s_pref_src)) : "");
+	            route->pref_src ? inet_ntop (AF_INET, &route->pref_src, s_pref_src, sizeof(s_pref_src)) : "",
+	            route->tos ? str_tos : "",
+	            route->window ? str_window : "",
+	            route->cwnd ? str_cwnd : "",
+	            route->initcwnd ? str_initcwnd : "",
+	            route->initrwnd ? str_initrwnd : "",
+	            route->mtu ? str_mtu : "");
 	return buf;
 }
 
@@ -3950,25 +3971,54 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi
 const char *
 nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsize len)
 {
-	char s_network[INET6_ADDRSTRLEN], s_gateway[INET6_ADDRSTRLEN];
+	char s_network[INET6_ADDRSTRLEN], s_gateway[INET6_ADDRSTRLEN], s_pref_src[INET6_ADDRSTRLEN];
+	char s_src[INET6_ADDRSTRLEN];
 	char str_dev[TO_STRING_DEV_BUF_SIZE], s_source[50];
+	char str_tos[32], str_window[32], str_cwnd[32], str_initcwnd[32], str_initrwnd[32], str_mtu[32];
 
 	if (!nm_utils_to_string_buffer_init_null (route, &buf, &len))
 		return buf;
 
-	inet_ntop (AF_INET6, &route->network, s_network, sizeof(s_network));
-	inet_ntop (AF_INET6, &route->gateway, s_gateway, sizeof(s_gateway));
+	inet_ntop (AF_INET6, &route->network, s_network, sizeof (s_network));
+	inet_ntop (AF_INET6, &route->gateway, s_gateway, sizeof (s_gateway));
+	inet_ntop (AF_INET6, &route->src, s_src, sizeof (s_src));
+
+	if (IN6_IS_ADDR_UNSPECIFIED (&route->pref_src))
+		s_pref_src[0] = 0;
+	else
+		inet_ntop (AF_INET6, &route->pref_src, s_pref_src, sizeof (s_pref_src));
 
 	_to_string_dev (NULL, route->ifindex, str_dev, sizeof (str_dev));
 
+	if (route->tos)
+		nm_sprintf_buf (str_tos, " tos 0x%x", (unsigned) route->tos);
+	if (route->window)
+		nm_sprintf_buf (str_window, " window %s%"G_GUINT32_FORMAT, route->lock_window ? "lock " : "", route->window);
+	if (route->cwnd)
+		nm_sprintf_buf (str_cwnd, " cwnd %s%"G_GUINT32_FORMAT, route->lock_cwnd ? "lock " : "", route->cwnd);
+	if (route->initcwnd)
+		nm_sprintf_buf (str_initcwnd, " initcwnd %s%"G_GUINT32_FORMAT, route->lock_initcwnd ? "lock " : "", route->initcwnd);
+	if (route->initrwnd)
+		nm_sprintf_buf (str_initrwnd, " initrwnd %s%"G_GUINT32_FORMAT, route->lock_initrwnd ? "lock " : "", route->initrwnd);
+	if (route->mtu)
+		nm_sprintf_buf (str_mtu, " mtu %s%"G_GUINT32_FORMAT, route->lock_mtu ? "lock " : "", route->mtu);
+
 	g_snprintf (buf, len,
 	            "%s/%d"
 	            " via %s"
 	            "%s"
 	            " metric %"G_GUINT32_FORMAT
 	            " mss %"G_GUINT32_FORMAT
-	            " src %s" /* source */
+	            " rt-src %s" /* protocol */
+	            " src %s/%u" /* source */
 	            "%s" /* cloned */
+	            "%s%s" /* pref-src */
+	            "%s" /* tos */
+	            "%s" /* window */
+	            "%s" /* cwnd */
+	            "%s" /* initcwnd */
+	            "%s" /* initrwnd */
+	            "%s" /* mtu */
 	            "",
 	            s_network,
 	            route->plen,
@@ -3977,7 +4027,17 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi
 	            route->metric,
 	            route->mss,
 	            nmp_utils_ip_config_source_to_string (route->rt_source, s_source, sizeof (s_source)),
-	            route->rt_cloned ? " cloned" : "");
+	            s_src, route->src_plen,
+	            route->rt_cloned ? " cloned" : "",
+	            s_pref_src[0] ? " pref-src " : "",
+	            s_pref_src[0] ? s_pref_src : "",
+	            route->tos ? str_tos : "",
+	            route->window ? str_window : "",
+	            route->cwnd ? str_cwnd : "",
+	            route->initcwnd ? str_initcwnd : "",
+	            route->initrwnd ? str_initrwnd : "",
+	            route->mtu ? str_mtu : "");
+
 	return buf;
 }
 
@@ -4253,11 +4313,16 @@ nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatformIP6A
 }
 
 int
-nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b)
+nm_platform_ip4_route_cmp_full (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b, gboolean consider_host_part)
 {
 	_CMP_SELF (a, b);
 	_CMP_FIELD (a, b, ifindex);
-	_CMP_FIELD (a, b, network);
+	if (consider_host_part)
+		_CMP_FIELD (a, b, network);
+	else {
+		_CMP_DIRECT (nm_utils_ip4_address_clear_host_address (a->network, a->plen),
+		             nm_utils_ip4_address_clear_host_address (b->network, b->plen));
+	}
 	_CMP_FIELD (a, b, plen);
 	_CMP_FIELD (a, b, metric);
 	_CMP_FIELD (a, b, gateway);
@@ -4266,21 +4331,54 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route
 	_CMP_FIELD (a, b, scope_inv);
 	_CMP_FIELD (a, b, pref_src);
 	_CMP_FIELD (a, b, rt_cloned);
+	_CMP_FIELD (a, b, tos);
+	_CMP_FIELD (a, b, lock_window);
+	_CMP_FIELD (a, b, lock_cwnd);
+	_CMP_FIELD (a, b, lock_initcwnd);
+	_CMP_FIELD (a, b, lock_initrwnd);
+	_CMP_FIELD (a, b, lock_mtu);
+	_CMP_FIELD (a, b, window);
+	_CMP_FIELD (a, b, cwnd);
+	_CMP_FIELD (a, b, initcwnd);
+	_CMP_FIELD (a, b, initrwnd);
+	_CMP_FIELD (a, b, mtu);
 	return 0;
 }
 
 int
-nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b)
+nm_platform_ip6_route_cmp_full (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b, gboolean consider_host_part)
 {
 	_CMP_SELF (a, b);
 	_CMP_FIELD (a, b, ifindex);
-	_CMP_FIELD_MEMCMP (a, b, network);
+	if (consider_host_part)
+		_CMP_FIELD_MEMCMP (a, b, network);
+	else {
+		struct in6_addr n1, n2;
+
+		nm_utils_ip6_address_clear_host_address (&n1, &a->network, a->plen);
+		nm_utils_ip6_address_clear_host_address (&n2, &b->network, b->plen);
+		_CMP_DIRECT_MEMCMP (&n1, &n2, sizeof (struct in6_addr));
+	}
 	_CMP_FIELD (a, b, plen);
 	_CMP_FIELD (a, b, metric);
 	_CMP_FIELD_MEMCMP (a, b, gateway);
+	_CMP_FIELD_MEMCMP (a, b, pref_src);
+	_CMP_FIELD_MEMCMP (a, b, src);
+	_CMP_FIELD (a, b, src_plen);
 	_CMP_FIELD (a, b, rt_source);
 	_CMP_FIELD (a, b, mss);
 	_CMP_FIELD (a, b, rt_cloned);
+	_CMP_FIELD (a, b, tos);
+	_CMP_FIELD (a, b, lock_window);
+	_CMP_FIELD (a, b, lock_cwnd);
+	_CMP_FIELD (a, b, lock_initcwnd);
+	_CMP_FIELD (a, b, lock_initrwnd);
+	_CMP_FIELD (a, b, lock_mtu);
+	_CMP_FIELD (a, b, window);
+	_CMP_FIELD (a, b, cwnd);
+	_CMP_FIELD (a, b, initcwnd);
+	_CMP_FIELD (a, b, initrwnd);
+	_CMP_FIELD (a, b, mtu);
 	return 0;
 }
 
@@ -4411,28 +4509,27 @@ nm_platform_netns_push (NMPlatform *platform, NMPNetns **netns)
 static gboolean
 _vtr_v4_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, gint64 metric)
 {
-	return nm_platform_ip4_route_add (self,
-	                                  ifindex > 0 ? ifindex : route->rx.ifindex,
-	                                  route->rx.rt_source,
-	                                  route->r4.network,
-	                                  route->rx.plen,
-	                                  route->r4.gateway,
-	                                  route->r4.pref_src,
-	                                  metric >= 0 ? (guint32) metric : route->rx.metric,
-	                                  route->rx.mss);
+	NMPlatformIP4Route rt = route->r4;
+
+	if (ifindex > 0)
+		rt.ifindex = ifindex;
+	if (metric >= 0)
+		rt.metric = metric;
+
+	return nm_platform_ip4_route_add (self, &rt);
 }
 
 static gboolean
 _vtr_v6_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, gint64 metric)
 {
-	return nm_platform_ip6_route_add (self,
-	                                  ifindex > 0 ? ifindex : route->rx.ifindex,
-	                                  route->rx.rt_source,
-	                                  route->r6.network,
-	                                  route->rx.plen,
-	                                  route->r6.gateway,
-	                                  metric >= 0 ? (guint32) metric : route->rx.metric,
-	                                  route->rx.mss);
+	NMPlatformIP6Route rt = route->r6;
+
+	if (ifindex > 0)
+		rt.ifindex = ifindex;
+	if (metric >= 0)
+		rt.metric = metric;
+
+	return nm_platform_ip6_route_add (self, &rt);
 }
 
 static gboolean
@@ -4479,7 +4576,7 @@ const NMPlatformVTableRoute nm_platform_vtable_route_v4 = {
 	.is_ip4                         = TRUE,
 	.addr_family                    = AF_INET,
 	.sizeof_route                   = sizeof (NMPlatformIP4Route),
-	.route_cmp                      = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b)) nm_platform_ip4_route_cmp,
+	.route_cmp                      = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, gboolean consider_host_part)) nm_platform_ip4_route_cmp_full,
 	.route_to_string                = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip4_route_to_string,
 	.route_get_all                  = nm_platform_ip4_route_get_all,
 	.route_add                      = _vtr_v4_route_add,
@@ -4492,7 +4589,7 @@ const NMPlatformVTableRoute nm_platform_vtable_route_v6 = {
 	.is_ip4                         = FALSE,
 	.addr_family                    = AF_INET6,
 	.sizeof_route                   = sizeof (NMPlatformIP6Route),
-	.route_cmp                      = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b)) nm_platform_ip6_route_cmp,
+	.route_cmp                      = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, gboolean consider_host_part)) nm_platform_ip6_route_cmp_full,
 	.route_to_string                = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip6_route_to_string,
 	.route_get_all                  = nm_platform_ip6_route_get_all,
 	.route_add                      = _vtr_v6_route_add,
@@ -4521,9 +4618,9 @@ set_property (GObject *object, guint prop_id,
 				self->_netns = g_object_ref (netns);
 		}
 		break;
-	case PROP_REGISTER_SINGLETON:
+	case PROP_LOG_WITH_PTR:
 		/* construct-only */
-		priv->register_singleton = g_value_get_boolean (value);
+		priv->log_with_ptr = g_value_get_boolean (value);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -4532,18 +4629,6 @@ set_property (GObject *object, guint prop_id,
 }
 
 static void
-constructed (GObject *object)
-{
-	NMPlatform *self = NM_PLATFORM (object);
-	NMPlatformPrivate *priv =  NM_PLATFORM_GET_PRIVATE (self);
-
-	G_OBJECT_CLASS (nm_platform_parent_class)->constructed (object);
-
-	if (priv->register_singleton)
-		nm_platform_setup (self);
-}
-
-static void
 nm_platform_init (NMPlatform *self)
 {
 	self->_priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_PLATFORM, NMPlatformPrivate);
@@ -4565,7 +4650,6 @@ nm_platform_class_init (NMPlatformClass *platform_class)
 	g_type_class_add_private (object_class, sizeof (NMPlatformPrivate));
 
 	object_class->set_property = set_property;
-	object_class->constructed = constructed;
 	object_class->finalize = finalize;
 
 	platform_class->wifi_set_powersave = wifi_set_powersave;
@@ -4579,9 +4663,9 @@ nm_platform_class_init (NMPlatformClass *platform_class)
 	                           G_PARAM_STATIC_STRINGS));
 
 	g_object_class_install_property
-	 (object_class, PROP_REGISTER_SINGLETON,
-	     g_param_spec_boolean (NM_PLATFORM_REGISTER_SINGLETON, "", "",
-	                           FALSE,
+	 (object_class, PROP_LOG_WITH_PTR,
+	     g_param_spec_boolean (NM_PLATFORM_LOG_WITH_PTR, "", "",
+	                           TRUE,
 	                           G_PARAM_WRITABLE |
 	                           G_PARAM_CONSTRUCT_ONLY |
 	                           G_PARAM_STATIC_STRINGS));
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index 63dbe5a0..43be17fa 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -45,10 +45,12 @@
 /*****************************************************************************/
 
 #define NM_PLATFORM_NETNS_SUPPORT      "netns-support"
-#define NM_PLATFORM_REGISTER_SINGLETON "register-singleton"
+#define NM_PLATFORM_LOG_WITH_PTR       "log-with-ptr"
 
 /*****************************************************************************/
 
+struct udev_device;
+
 /* workaround for older libnl version, that does not define these flags. */
 #ifndef IFA_F_MANAGETEMPADDR
 #define IFA_F_MANAGETEMPADDR 0x100
@@ -91,24 +93,6 @@ typedef enum { /*< skip >*/
 	NM_PLATFORM_ERROR_OPNOTSUPP,
 } NMPlatformError;
 
-
-typedef struct {
-	union {
-		guint8 addr_ptr[1];
-		in_addr_t addr4;
-		struct in6_addr addr6;
-
-		/* NMIPAddr is really a union for IP addresses.
-		 * However, as ethernet addresses fit in here nicely, ruse
-		 * it also for an ethernet MAC address. */
-		guint8 addr_eth[6 /*ETH_ALEN*/];
-	};
-} NMIPAddr;
-
-extern const NMIPAddr nm_ip_addr_zero;
-
-#define NMIPAddrInit { .addr6 = IN6ADDR_ANY_INIT }
-
 #define NM_PLATFORM_LINK_OTHER_NETNS    (-1)
 
 #define __NMPlatformObject_COMMON \
@@ -324,9 +308,20 @@ typedef union {
 	 * of platform users. This flag is internal to track those hidden
 	 * routes. Such a route is not alive, according to nmp_object_is_alive(). */ \
 	bool rt_cloned:1; \
+	bool lock_window:1; \
+	bool lock_cwnd:1; \
+	bool lock_initcwnd:1; \
+	bool lock_initrwnd:1; \
+	bool lock_mtu:1; \
 	\
 	guint32 metric; \
 	guint32 mss; \
+	guint32 tos; \
+	guint32 window; \
+	guint32 cwnd; \
+	guint32 initcwnd; \
+	guint32 initrwnd; \
+	guint32 mtu; \
 	;
 
 typedef struct {
@@ -358,6 +353,9 @@ struct _NMPlatformIP6Route {
 	__NMPlatformIPRoute_COMMON;
 	struct in6_addr network;
 	struct in6_addr gateway;
+	struct in6_addr pref_src;
+	struct in6_addr src;
+	guint8 src_plen;
 };
 
 typedef union {
@@ -376,7 +374,7 @@ typedef struct {
 	gboolean is_ip4;
 	int addr_family;
 	gsize sizeof_route;
-	int (*route_cmp) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b);
+	int (*route_cmp) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, gboolean consider_host_part);
 	const char *(*route_to_string) (const NMPlatformIPXRoute *route, char *buf, gsize len);
 	GArray *(*route_get_all) (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags);
 	gboolean (*route_add) (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, gint64 metric);
@@ -548,7 +546,7 @@ typedef struct {
 	gboolean (*link_set_noarp) (NMPlatform *, int ifindex);
 
 	const char *(*link_get_udi) (NMPlatform *self, int ifindex);
-	GObject *(*link_get_udev_device) (NMPlatform *self, int ifindex);
+	struct udev_device *(*link_get_udev_device) (NMPlatform *self, int ifindex);
 
 	NMPlatformError (*link_set_user_ipv6ll_enabled) (NMPlatform *, int ifindex, gboolean enabled);
 	gboolean (*link_set_token) (NMPlatform *, int ifindex, NMUtilsIPv6IfaceId iid);
@@ -559,6 +557,7 @@ typedef struct {
 	                                        size_t *length);
 	NMPlatformError (*link_set_address) (NMPlatform *, int ifindex, gconstpointer address, size_t length);
 	gboolean (*link_set_mtu) (NMPlatform *, int ifindex, guint32 mtu);
+	gboolean (*link_set_sriov_num_vfs) (NMPlatform *, int ifindex, guint num_vfs);
 
 	char *   (*link_get_physical_port_id) (NMPlatform *, int ifindex);
 	guint    (*link_get_dev_id) (NMPlatform *, int ifindex);
@@ -571,6 +570,7 @@ typedef struct {
 
 	gboolean (*link_supports_carrier_detect) (NMPlatform *, int ifindex);
 	gboolean (*link_supports_vlans) (NMPlatform *, int ifindex);
+	gboolean (*link_supports_sriov) (NMPlatform *, int ifindex);
 
 	gboolean (*link_enslave) (NMPlatform *, int master, int slave);
 	gboolean (*link_release) (NMPlatform *, int master, int slave);
@@ -667,12 +667,8 @@ typedef struct {
 
 	GArray * (*ip4_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteFlags flags);
 	GArray * (*ip6_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteFlags flags);
-	gboolean (*ip4_route_add) (NMPlatform *, int ifindex, NMIPConfigSource source,
-	                           in_addr_t network, guint8 plen, in_addr_t gateway,
-	                           in_addr_t pref_src, guint32 metric, guint32 mss);
-	gboolean (*ip6_route_add) (NMPlatform *, int ifindex, NMIPConfigSource source,
-	                           struct in6_addr network, guint8 plen, struct in6_addr gateway,
-	                           guint32 metric, guint32 mss);
+	gboolean (*ip4_route_add) (NMPlatform *, const NMPlatformIP4Route *route);
+	gboolean (*ip6_route_add) (NMPlatform *, const NMPlatformIP6Route *route);
 	gboolean (*ip4_route_delete) (NMPlatform *, int ifindex, in_addr_t network, guint8 plen, guint32 metric);
 	gboolean (*ip6_route_delete) (NMPlatform *, int ifindex, struct in6_addr network, guint8 plen, guint32 metric);
 	const NMPlatformIP4Route *(*ip4_route_get) (NMPlatform *, int ifindex, in_addr_t network, guint8 plen, guint32 metric);
@@ -707,7 +703,6 @@ GType nm_platform_get_type (void);
 
 void nm_platform_setup (NMPlatform *instance);
 NMPlatform *nm_platform_get (void);
-NMPlatform *nm_platform_try_get (void);
 
 #define NM_PLATFORM_GET (nm_platform_get ())
 
@@ -730,6 +725,8 @@ _nm_platform_uint8_inv (guint8 scope)
 	return (guint8) ~scope;
 }
 
+gboolean nm_platform_get_log_with_ptr (NMPlatform *self);
+
 NMPNetns *nm_platform_netns_get (NMPlatform *self);
 gboolean nm_platform_netns_push (NMPlatform *platform, NMPNetns **netns);
 
@@ -804,7 +801,7 @@ gboolean nm_platform_link_set_noarp (NMPlatform *self, int ifindex);
 
 const char *nm_platform_link_get_udi (NMPlatform *self, int ifindex);
 
-GObject *nm_platform_link_get_udev_device (NMPlatform *self, int ifindex);
+struct udev_device *nm_platform_link_get_udev_device (NMPlatform *self, int ifindex);
 
 NMPlatformError nm_platform_link_set_user_ipv6ll_enabled (NMPlatform *self, int ifindex, gboolean enabled);
 gboolean nm_platform_link_set_ipv6_token (NMPlatform *self, int ifindex, NMUtilsIPv6IfaceId iid);
@@ -812,6 +809,7 @@ gboolean nm_platform_link_set_ipv6_token (NMPlatform *self, int ifindex, NMUtils
 gboolean nm_platform_link_get_permanent_address (NMPlatform *self, int ifindex, guint8 *buf, size_t *length);
 NMPlatformError nm_platform_link_set_address (NMPlatform *self, int ifindex, const void *address, size_t length);
 gboolean nm_platform_link_set_mtu (NMPlatform *self, int ifindex, guint32 mtu);
+gboolean nm_platform_link_set_sriov_num_vfs (NMPlatform *self, int ifindex, guint num_vfs);
 
 char    *nm_platform_link_get_physical_port_id (NMPlatform *self, int ifindex);
 guint    nm_platform_link_get_dev_id (NMPlatform *self, int ifindex);
@@ -824,6 +822,7 @@ gboolean nm_platform_link_get_driver_info (NMPlatform *self,
 
 gboolean nm_platform_link_supports_carrier_detect (NMPlatform *self, int ifindex);
 gboolean nm_platform_link_supports_vlans (NMPlatform *self, int ifindex);
+gboolean nm_platform_link_supports_sriov (NMPlatform *self, int ifindex);
 
 gboolean nm_platform_link_enslave (NMPlatform *self, int master, int slave);
 gboolean nm_platform_link_release (NMPlatform *self, int master, int slave);
@@ -969,12 +968,8 @@ const NMPlatformIP4Route *nm_platform_ip4_route_get (NMPlatform *self, int ifind
 const NMPlatformIP6Route *nm_platform_ip6_route_get (NMPlatform *self, int ifindex, struct in6_addr network, guint8 plen, guint32 metric);
 GArray *nm_platform_ip4_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags);
 GArray *nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags);
-gboolean nm_platform_ip4_route_add (NMPlatform *self, int ifindex, NMIPConfigSource source,
-                                    in_addr_t network, guint8 plen, in_addr_t gateway,
-                                    in_addr_t pref_src, guint32 metric, guint32 mss);
-gboolean nm_platform_ip6_route_add (NMPlatform *self, int ifindex, NMIPConfigSource source,
-                                    struct in6_addr network, guint8 plen, struct in6_addr gateway,
-                                    guint32 metric, guint32 mss);
+gboolean nm_platform_ip4_route_add (NMPlatform *self, const NMPlatformIP4Route *route);
+gboolean nm_platform_ip6_route_add (NMPlatform *self, const NMPlatformIP6Route *route);
 gboolean nm_platform_ip4_route_delete (NMPlatform *self, int ifindex, in_addr_t network, guint8 plen, guint32 metric);
 gboolean nm_platform_ip6_route_delete (NMPlatform *self, int ifindex, struct in6_addr network, guint8 plen, guint32 metric);
 
@@ -1011,8 +1006,20 @@ int nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVla
 int nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *b);
 int nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b);
 int nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatformIP6Address *b);
-int nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b);
-int nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b);
+int nm_platform_ip4_route_cmp_full (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b, gboolean consider_host_part);
+int nm_platform_ip6_route_cmp_full (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b, gboolean consider_host_part);
+
+static inline int
+nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b)
+{
+	return nm_platform_ip4_route_cmp_full (a, b, TRUE);
+}
+
+static inline int
+nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b)
+{
+	return nm_platform_ip6_route_cmp_full (a, b, TRUE);
+}
 
 gboolean nm_platform_check_support_kernel_extended_ifa_flags (NMPlatform *self);
 gboolean nm_platform_check_support_user_ipv6ll (NMPlatform *self);
diff --git a/src/platform/nmp-netns.c b/src/platform/nmp-netns.c
index c9c6850d..4acd4761 100644
--- a/src/platform/nmp-netns.c
+++ b/src/platform/nmp-netns.c
@@ -75,7 +75,7 @@ __ns_types_to_str (int ns_types, int ns_types_already_set, char *buf, gsize len)
             NMPNetns *_netns = (netns); \
             char _sbuf[20]; \
             \
-            _nm_log (_level, _NMLOG_DOMAIN, 0, \
+            _nm_log (_level, _NMLOG_DOMAIN, 0, NULL, NULL, \
                      "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
                      _NMLOG_PREFIX_NAME, \
                      (_netns ? nm_sprintf_buf (_sbuf, "[%p]", _netns) : "") \
diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c
index 1503ca9a..ecec8f0f 100644
--- a/src/platform/nmp-object.c
+++ b/src/platform/nmp-object.c
@@ -24,6 +24,7 @@
 
 #include <unistd.h>
 #include <linux/rtnetlink.h>
+#include <libudev.h>
 
 #include "nm-utils.h"
 
@@ -40,7 +41,7 @@
         if (nm_logging_enabled (__level, _NMLOG_DOMAIN)) { \
             const NMPObject *const __obj = (obj); \
             \
-            _nm_log (__level, _NMLOG_DOMAIN, 0, \
+            _nm_log (__level, _NMLOG_DOMAIN, 0, NULL, NULL, \
                      "nmp-object[%p/%s]: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
                      __obj, \
                      (__obj ? NMP_OBJECT_GET_CLASS (__obj)->obj_type_name : "???") \
@@ -48,10 +49,6 @@
         } \
     } G_STMT_END
 
-/* logging to trace object lifetime and references.
- * Disabled by default. */
-#define _LOGr(...) G_STMT_START { if (FALSE) { _LOGt (__VA_ARGS__); } } G_STMT_END
-
 /*****************************************************************************/
 
 struct _NMPCache {
@@ -125,14 +122,14 @@ _vlan_xgress_qos_mappings_cpy (guint *dst_n_map,
 /*****************************************************************************/
 
 static const char *
-_link_get_driver (GUdevDevice *udev_device, const char *kind, int ifindex)
+_link_get_driver (struct udev_device *udevice, const char *kind, int ifindex)
 {
 	const char *driver = NULL;
 
 	nm_assert (kind == g_intern_string (kind));
 
-	if (udev_device) {
-		driver = nmp_utils_udev_get_driver (udev_device);
+	if (udevice) {
+		driver = nmp_utils_udev_get_driver (udevice);
 		if (driver)
 			return driver;
 	}
@@ -214,8 +211,6 @@ nmp_object_ref (NMPObject *obj)
 	g_return_val_if_fail (obj->_ref_count != NMP_REF_COUNT_STACKINIT, NULL);
 	obj->_ref_count++;
 
-	_LOGr (obj, "ref: %d", obj->_ref_count);
-
 	return obj;
 }
 
@@ -225,9 +220,6 @@ nmp_object_unref (NMPObject *obj)
 	if (obj) {
 		g_return_if_fail (obj->_ref_count > 0);
 		g_return_if_fail (obj->_ref_count != NMP_REF_COUNT_STACKINIT);
-		_LOGr (obj, "%s: %d",
-		       obj->_ref_count <= 1 ? "destroy" : "unref",
-		       obj->_ref_count - 1);
 		if (--obj->_ref_count <= 0) {
 			const NMPClass *klass = obj->_class;
 
@@ -242,7 +234,10 @@ nmp_object_unref (NMPObject *obj)
 static void
 _vt_cmd_obj_dispose_link (NMPObject *obj)
 {
-	g_clear_object (&obj->_link.udev.device);
+	if (obj->_link.udev.device) {
+		udev_device_unref (obj->_link.udev.device);
+		obj->_link.udev.device = NULL;
+	}
 	nmp_object_unref (obj->_link.netlink.lnk);
 }
 
@@ -265,7 +260,6 @@ _nmp_object_new_from_class (const NMPClass *klass)
 	obj = g_slice_alloc0 (klass->sizeof_data + G_STRUCT_OFFSET (NMPObject, object));
 	obj->_class = klass;
 	obj->_ref_count = 1;
-	_LOGr (obj, "new");
 	return obj;
 }
 
@@ -495,7 +489,7 @@ _vt_cmd_obj_to_string_link (const NMPObject *obj, NMPObjectToStringMode to_strin
 static const char *
 _vt_cmd_obj_to_string_lnk_vlan (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size)
 {
-	const NMPClass *klass = NMP_OBJECT_GET_CLASS (obj);
+	const NMPClass *klass;
 	char buf2[sizeof (_nm_utils_to_string_buffer)];
 	char *b;
 	gsize l;
@@ -619,8 +613,7 @@ _vt_cmd_obj_cmp_link (const NMPObject *obj1, const NMPObject *obj2)
 			return 1;
 
 		/* Only compare based on pointer values. That is ugly because it's not a
-		 * stable sort order, but probably udev gives us always the same GUdevDevice
-		 * instance.
+		 * stable sort order.
 		 *
 		 * Have this check as very last. */
 		return (obj1->_link.udev.device < obj2->_link.udev.device) ? -1 : 1;
@@ -687,15 +680,17 @@ _vt_cmd_obj_copy_link (NMPObject *dst, const NMPObject *src)
 {
 	if (dst->_link.udev.device != src->_link.udev.device) {
 		if (src->_link.udev.device)
-			g_object_ref (src->_link.udev.device);
+			udev_device_ref (src->_link.udev.device);
 		if (dst->_link.udev.device)
-			g_object_unref (dst->_link.udev.device);
+			udev_device_unref (dst->_link.udev.device);
+		dst->_link.udev.device = src->_link.udev.device;
 	}
 	if (dst->_link.netlink.lnk != src->_link.netlink.lnk) {
 		if (src->_link.netlink.lnk)
 			nmp_object_ref (src->_link.netlink.lnk);
 		if (dst->_link.netlink.lnk)
 			nmp_object_unref (dst->_link.netlink.lnk);
+		dst->_link.netlink.lnk = src->_link.netlink.lnk;
 	}
 	dst->_link = src->_link;
 }
@@ -810,12 +805,17 @@ _vt_cmd_plobj_id_equal (ip4_route, NMPlatformIP4Route,
                            obj1->ifindex == obj2->ifindex
                         && obj1->plen == obj2->plen
                         && obj1->metric == obj2->metric
-                        && obj1->network == obj2->network);
+                        && nm_utils_ip4_address_clear_host_address (obj1->network, obj1->plen) == nm_utils_ip4_address_clear_host_address (obj2->network, obj2->plen));
 _vt_cmd_plobj_id_equal (ip6_route, NMPlatformIP6Route,
                            obj1->ifindex == obj2->ifindex
                         && obj1->plen == obj2->plen
                         && obj1->metric == obj2->metric
-                        && IN6_ARE_ADDR_EQUAL( &obj1->network, &obj2->network));
+                        && ({
+                                struct in6_addr n1, n2;
+
+                                IN6_ARE_ADDR_EQUAL(nm_utils_ip6_address_clear_host_address (&n1, &obj1->network, obj1->plen),
+                                                   nm_utils_ip6_address_clear_host_address (&n2, &obj2->network, obj2->plen));
+                            }));
 
 guint
 nmp_object_id_hash (const NMPObject *obj)
@@ -869,14 +869,17 @@ _vt_cmd_plobj_id_hash (ip4_route, NMPlatformIP4Route, {
 	hash = hash      + ((guint) obj->ifindex);
 	hash = hash * 33 + ((guint) obj->plen);
 	hash = hash * 33 + ((guint) obj->metric);
-	hash = hash * 33 + ((guint) obj->network);
+	hash = hash * 33 + ((guint) nm_utils_ip4_address_clear_host_address (obj->network, obj->plen));
 })
 _vt_cmd_plobj_id_hash (ip6_route, NMPlatformIP6Route, {
 	hash = (guint) 3999787007u;
 	hash = hash      + ((guint) obj->ifindex);
 	hash = hash * 33 + ((guint) obj->plen);
 	hash = hash * 33 + ((guint) obj->metric);
-	hash = hash * 33 + _id_hash_ip6_addr (&obj->network);
+	hash = hash * 33 + ({
+	                        struct in6_addr n1;
+	                        _id_hash_ip6_addr (nm_utils_ip6_address_clear_host_address (&n1, &obj->network, obj->plen));
+	                    });
 })
 
 gboolean
@@ -985,11 +988,6 @@ nmp_cache_id_hash (const NMPCacheId *id)
 	guint hash = 5381;
 	guint i, n;
 
-	/* for hashing we only iterate over the actually set bytes and skip the
-	 * zero padding at the end (which depends on the type of the id).
-	 *
-	 * For the equal implementation, we don't care about that and compare the
-	 * entire NMPCacheId sized struct. */
 	n = _nmp_cache_id_size_by_type (id->_id_type);
 	for (i = 0; i < n; i++)
 		hash = ((hash << 5) + hash) + ((char *) id)[i]; /* hash * 33 + c */
@@ -1033,6 +1031,20 @@ _nmp_cache_id_init (NMPCacheId *id, NMPCacheIdType id_type)
 	 * all structs have the packed attribute, there are no holes
 	 * due to alignment, and it becomes simple for nmp_cache_id_init_*()
 	 * to ensure that all fields are set. */
+
+#if NM_MORE_ASSERTS
+	nm_assert (id);
+	{
+		guint i;
+
+		/* initialized with some bogus canary to hopefully detect when we miss
+		 * to initialize a field of the cache-id. */
+		for (i = 0; i < sizeof (*id); i++) {
+			((char *) id)[i] = GPOINTER_TO_UINT (id) ^ i;
+		}
+	}
+#endif
+
 	id->_id_type = id_type;
 }
 
@@ -1533,13 +1545,17 @@ nmp_cache_lookup_link_full (const NMPCache *cache,
 		    && strlen (ifname) <= sizeof (cache_id.link_by_ifname.ifname_short)) {
 			p_cache_id = nmp_cache_id_init_link_by_ifname (&cache_id, ifname);
 			ifname = NULL;
-		} else
+		} else {
 			p_cache_id = nmp_cache_id_init_object_type (&cache_id, NMP_OBJECT_TYPE_LINK, visible_only);
+			visible_only = FALSE;
+		}
 
 		list = nmp_cache_lookup_multi (cache, p_cache_id, &len);
 		for (i = 0; i < len; i++) {
 			obj = NMP_OBJECT_UP_CAST (list[i]);
 
+			if (visible_only && !nmp_object_is_visible (obj))
+				continue;
 			if (link_type != NM_LINK_TYPE_NONE && obj->link.type != link_type)
 				continue;
 			if (ifname && strcmp (ifname, obj->link.name))
@@ -1857,8 +1873,8 @@ nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj,
 				_nmp_object_fixup_link_master_connected (obj, cache);
 
 				/* Merge the netlink parts with what we have from udev. */
-				g_clear_object (&obj->_link.udev.device);
-				obj->_link.udev.device = old->_link.udev.device ? g_object_ref (old->_link.udev.device) : NULL;
+				udev_device_unref (obj->_link.udev.device);
+				obj->_link.udev.device = old->_link.udev.device ? udev_device_ref (old->_link.udev.device) : NULL;
 				_nmp_object_fixup_link_udev_fields (obj, cache->use_udev);
 			}
 		} else
@@ -1883,7 +1899,7 @@ nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj,
 }
 
 NMPCacheOpsType
-nmp_cache_update_link_udev (NMPCache *cache, int ifindex, GUdevDevice *udev_device, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data)
+nmp_cache_update_link_udev (NMPCache *cache, int ifindex, struct udev_device *udevice, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data)
 {
 	NMPObject *old;
 	nm_auto_nmpobj NMPObject *obj = NULL;
@@ -1896,12 +1912,12 @@ nmp_cache_update_link_udev (NMPCache *cache, int ifindex, GUdevDevice *udev_devi
 		*out_was_visible = FALSE;
 
 	if (!old) {
-		if (!udev_device)
+		if (!udevice)
 			return NMP_CACHE_OPS_UNCHANGED;
 
 		obj = nmp_object_new (NMP_OBJECT_TYPE_LINK, NULL);
 		obj->link.ifindex = ifindex;
-		obj->_link.udev.device = g_object_ref (udev_device);
+		obj->_link.udev.device = udev_device_ref (udevice);
 
 		_nmp_object_fixup_link_udev_fields (obj, cache->use_udev);
 
@@ -1922,10 +1938,10 @@ nmp_cache_update_link_udev (NMPCache *cache, int ifindex, GUdevDevice *udev_devi
 		if (out_was_visible)
 			*out_was_visible = nmp_object_is_visible (old);
 
-		if (old->_link.udev.device == udev_device)
+		if (old->_link.udev.device == udevice)
 			return NMP_CACHE_OPS_UNCHANGED;
 
-		if (!udev_device && !old->_link.netlink.is_in_netlink) {
+		if (!udevice && !old->_link.netlink.is_in_netlink) {
 			/* the update would make @old invalid. Remove it. */
 			if (pre_hook)
 				pre_hook (cache, old, NULL, NMP_CACHE_OPS_REMOVED, user_data);
@@ -1935,8 +1951,8 @@ nmp_cache_update_link_udev (NMPCache *cache, int ifindex, GUdevDevice *udev_devi
 
 		obj = nmp_object_clone (old, FALSE);
 
-		g_clear_object (&obj->_link.udev.device);
-		obj->_link.udev.device = udev_device ? g_object_ref (udev_device) : NULL;
+		udev_device_unref (obj->_link.udev.device);
+		obj->_link.udev.device = udevice ? udev_device_ref (udevice) : NULL;
 
 		_nmp_object_fixup_link_udev_fields (obj, cache->use_udev);
 
diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h
index dd11b985..b69680f6 100644
--- a/src/platform/nmp-object.h
+++ b/src/platform/nmp-object.h
@@ -21,11 +21,11 @@
 #ifndef __NMP_OBJECT_H__
 #define __NMP_OBJECT_H__
 
-#include <gudev/gudev.h>
-
 #include "nm-platform.h"
 #include "nm-multi-index.h"
 
+struct udev_device;
+
 typedef enum { /*< skip >*/
 	NMP_OBJECT_TO_STRING_ID,
 	NMP_OBJECT_TO_STRING_PUBLIC,
@@ -186,7 +186,23 @@ typedef struct {
 	} netlink;
 
 	struct {
-		GUdevDevice *device;
+		/* note that "struct udev_device" references the library context
+		 * "struct udev", but doesn't own it.
+		 *
+		 * Hence, the udev.device shall not be used after the library
+		 * context is is destroyed.
+		 *
+		 * In case of NMPObjectLink instances that you obtained from the
+		 * platform cache, that means that you shall no keep references
+		 * to those instances that outlife the NMPlatform instance.
+		 *
+		 * In practice, the requirement is less strict and you'll be even
+		 * fine if the platform instance (and the "struct udev" instance)
+		 * are already destroyed while you still hold onto a reference to
+		 * the NMPObjectLink instance. Just don't make use of udev functions
+		 * that cause access to the udev library context.
+		 */
+		struct udev_device *device;
 	} udev;
 } NMPObjectLink;
 
@@ -307,7 +323,7 @@ NMP_CLASS_IS_VALID (const NMPClass *klass)
 {
 	return klass >= &_nmp_classes[0]
 	    && klass <= &_nmp_classes[G_N_ELEMENTS (_nmp_classes)]
-	    && ((((char *) klass) - ((char *) NULL)) % (&_nmp_classes[1] - &_nmp_classes[0])) == 0;
+	    && ((((char *) klass) - ((char *) _nmp_classes)) % (sizeof (_nmp_classes[0]))) == 0;
 }
 
 #define NMP_REF_COUNT_STACKINIT (G_MAXINT)
@@ -442,7 +458,7 @@ void ASSERT_nmp_cache_is_consistent (const NMPCache *cache);
 NMPCacheOpsType nmp_cache_remove (NMPCache *cache, const NMPObject *obj, gboolean equals_by_ptr, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data);
 NMPCacheOpsType nmp_cache_remove_netlink (NMPCache *cache, const NMPObject *obj, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data);
 NMPCacheOpsType nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data);
-NMPCacheOpsType nmp_cache_update_link_udev (NMPCache *cache, int ifindex, GUdevDevice *udev_device, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data);
+NMPCacheOpsType nmp_cache_update_link_udev (NMPCache *cache, int ifindex, struct udev_device *udevice, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data);
 NMPCacheOpsType nmp_cache_update_link_master_connected (NMPCache *cache, int ifindex, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data);
 
 NMPCache *nmp_cache_new (gboolean use_udev);
diff --git a/src/platform/tests/test-cleanup.c b/src/platform/tests/test-cleanup.c
index 4ac49298..71a92cbf 100644
--- a/src/platform/tests/test-cleanup.c
+++ b/src/platform/tests/test-cleanup.c
@@ -65,12 +65,12 @@ test_cleanup_internal (void)
 	/* Add routes and addresses */
 	g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr4, plen4, addr4, lifetime, preferred, 0, NULL));
 	g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr6, plen6, in6addr_any, 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));
+	nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway4, 32, INADDR_ANY, 0, metric, mss);
+	nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network4, plen4, gateway4, 0, metric, mss);
+	nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway4, 0, metric, mss);
+	nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway6, 128, in6addr_any, in6addr_any, metric, mss);
+	nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network6, plen6, gateway6, in6addr_any, metric, mss);
+	nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway6, in6addr_any, metric, mss);
 
 	addresses4 = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex);
 	addresses6 = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex);
diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c
index 0e42a727..04db862d 100644
--- a/src/platform/tests/test-common.c
+++ b/src/platform/tests/test-common.c
@@ -783,6 +783,54 @@ nmtstp_ip6_address_add (NMPlatform *platform,
 	                 NULL);
 }
 
+void nmtstp_ip4_route_add (NMPlatform *platform,
+                           int ifindex,
+                           NMIPConfigSource source,
+                           in_addr_t network,
+                           guint8 plen,
+                           in_addr_t gateway,
+                           in_addr_t pref_src,
+                           guint32 metric,
+                           guint32 mss)
+{
+	NMPlatformIP4Route route = { };
+
+	route.ifindex = ifindex;
+	route.rt_source = source;
+	route.network = network;
+	route.plen = plen;
+	route.gateway = gateway;
+	route.pref_src = pref_src;
+	route.metric = metric;
+	route.mss = mss;
+
+	g_assert (nm_platform_ip4_route_add (platform, &route));
+}
+
+void nmtstp_ip6_route_add (NMPlatform *platform,
+                           int ifindex,
+                           NMIPConfigSource source,
+                           struct in6_addr network,
+                           guint8 plen,
+                           struct in6_addr gateway,
+                           struct in6_addr pref_src,
+                           guint32 metric,
+                           guint32 mss)
+{
+	NMPlatformIP6Route route = { };
+
+	route.ifindex = ifindex;
+	route.rt_source = source;
+	route.network = network;
+	route.plen = plen;
+	route.gateway = gateway;
+	route.pref_src = pref_src;
+	route.metric = metric;
+	route.mss = mss;
+
+	g_assert (nm_platform_ip6_route_add (platform, &route));
+}
+
 /*****************************************************************************/
 
 static void
@@ -1547,7 +1595,7 @@ nmtstp_namespace_get_fd_for_process (pid_t pid, const char *ns_name)
 	g_return_val_if_fail (pid > 0, 0);
 	g_return_val_if_fail (ns_name && ns_name[0] && strlen (ns_name) < 50, 0);
 
-	nm_sprintf_buf (p, "/proc/%lu/ns/%s", (long unsigned) pid, ns_name);
+	nm_sprintf_buf (p, "/proc/%lu/ns/%s", (unsigned long) pid, ns_name);
 
 	return open(p, O_RDONLY | O_CLOEXEC);
 }
diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h
index 48a41de6..a52a5db5 100644
--- a/src/platform/tests/test-common.h
+++ b/src/platform/tests/test-common.h
@@ -26,7 +26,7 @@
         if (nm_logging_enabled (__level, __domain)) { \
             gint64 _ts = nm_utils_get_monotonic_timestamp_ns (); \
             \
-            _nm_log (__level, __domain, 0, \
+            _nm_log (__level, __domain, 0, NULL, NULL, \
                      "%s[%ld.%09ld]: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
                      _NMLOG_PREFIX_NAME, \
                      (long) (_ts / NM_UTILS_NS_PER_SECOND), \
@@ -167,6 +167,26 @@ void nmtstp_ip6_address_del (NMPlatform *platform,
                              struct in6_addr address,
                              int plen);
 
+void nmtstp_ip4_route_add (NMPlatform *platform,
+                           int ifindex,
+                           NMIPConfigSource source,
+                           in_addr_t network,
+                           guint8 plen,
+                           in_addr_t gateway,
+                           in_addr_t pref_src,
+                           guint32 metric,
+                           guint32 mss);
+
+void nmtstp_ip6_route_add (NMPlatform *platform,
+                           int ifindex,
+                           NMIPConfigSource source,
+                           struct in6_addr network,
+                           guint8 plen,
+                           struct in6_addr gateway,
+                           struct in6_addr pref_src,
+                           guint32 metric,
+                           guint32 mss);
+
 /*****************************************************************************/
 
 const NMPlatformLink *nmtstp_link_get_typed (NMPlatform *platform, int ifindex, const char *name, NMLinkType link_type);
diff --git a/src/platform/tests/test-general.c b/src/platform/tests/test-general.c
index 658aad26..2ccfac7d 100644
--- a/src/platform/tests/test-general.c
+++ b/src/platform/tests/test-general.c
@@ -35,7 +35,7 @@ test_init_linux_platform (void)
 {
 	gs_unref_object NMPlatform *platform = NULL;
 
-	platform = nm_linux_platform_new (NM_PLATFORM_NETNS_SUPPORT_DEFAULT);
+	platform = nm_linux_platform_new (TRUE, NM_PLATFORM_NETNS_SUPPORT_DEFAULT);
 }
 
 /*****************************************************************************/
@@ -46,7 +46,7 @@ test_link_get_all (void)
 	gs_unref_object NMPlatform *platform = NULL;
 	gs_unref_array GArray *links = NULL;
 
-	platform = nm_linux_platform_new (NM_PLATFORM_NETNS_SUPPORT_DEFAULT);
+	platform = nm_linux_platform_new (TRUE, NM_PLATFORM_NETNS_SUPPORT_DEFAULT);
 
 	links = nm_platform_link_get_all (platform);
 }
diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c
index c2b3de13..ed435567 100644
--- a/src/platform/tests/test-link.c
+++ b/src/platform/tests/test-link.c
@@ -1900,7 +1900,7 @@ _test_netns_create_platform (void)
 	netns = nmp_netns_new ();
 	g_assert (NMP_IS_NETNS (netns));
 
-	platform = nm_linux_platform_new (TRUE);
+	platform = nm_linux_platform_new (TRUE, TRUE);
 	g_assert (NM_IS_LINUX_PLATFORM (platform));
 
 	nmp_netns_pop (netns);
@@ -1961,7 +1961,7 @@ test_netns_general (gpointer fixture, gconstpointer test_data)
 	if (_test_netns_check_skip ())
 		return;
 
-	platform_1 = nm_linux_platform_new (TRUE);
+	platform_1 = nm_linux_platform_new (TRUE, TRUE);
 	platform_2 = _test_netns_create_platform ();
 
 	/* add some dummy devices. The "other-*" devices are there to bump the ifindex */
@@ -2061,7 +2061,7 @@ test_netns_set_netns (gpointer fixture, gconstpointer test_data)
 	if (_test_netns_check_skip ())
 		return;
 
-	platforms[0] = platform_0 = nm_linux_platform_new (TRUE);
+	platforms[0] = platform_0 = nm_linux_platform_new (TRUE, TRUE);
 	platforms[1] = platform_1 = _test_netns_create_platform ();
 	platforms[2] = platform_2 = _test_netns_create_platform ();
 
@@ -2156,7 +2156,7 @@ test_netns_push (gpointer fixture, gconstpointer test_data)
 	if (_test_netns_check_skip ())
 		return;
 
-	pl[0].platform = platform_0 = nm_linux_platform_new (TRUE);
+	pl[0].platform = platform_0 = nm_linux_platform_new (TRUE, TRUE);
 	pl[1].platform = platform_1 = _test_netns_create_platform ();
 	pl[2].platform = platform_2 = _test_netns_create_platform ();
 
@@ -2288,7 +2288,7 @@ test_netns_bind_to_path (gpointer fixture, gconstpointer test_data)
 	if (_test_netns_check_skip ())
 		return;
 
-	platforms[0] = platform_0 = nm_linux_platform_new (TRUE);
+	platforms[0] = platform_0 = nm_linux_platform_new (TRUE, TRUE);
 	platforms[1] = platform_1 = _test_netns_create_platform ();
 	platforms[2] = platform_2 = _test_netns_create_platform ();
 
@@ -2404,8 +2404,6 @@ test_sysctl_rename (void)
 		g_assert_cmpint (ifindex[0], ==, (gint32) nm_platform_sysctl_get_int32 (PL, NMP_SYSCTL_PATHID_NETDIR (dirfd, s ?: "<unknown>", "ifindex"), -1));
 		break;
 	}
-	default:
-		g_assert_not_reached ();
 	}
 
 	nm_platform_process_events (PL);
@@ -2435,7 +2433,7 @@ test_sysctl_netns_switch (void)
 	if (_test_netns_check_skip ())
 		return;
 
-	platforms[0] = platform_0 = nm_linux_platform_new (TRUE);
+	platforms[0] = platform_0 = nm_linux_platform_new (TRUE, TRUE);
 	platforms[1] = platform_1 = _test_netns_create_platform ();
 	platforms[2] = platform_2 = _test_netns_create_platform ();
 	PL = platforms[nmtst_get_rand_int () % 3];
diff --git a/src/platform/tests/test-nmp-object.c b/src/platform/tests/test-nmp-object.c
index f7b209de..42dfc572 100644
--- a/src/platform/tests/test-nmp-object.c
+++ b/src/platform/tests/test-nmp-object.c
@@ -20,7 +20,10 @@
 
 #include "nm-default.h"
 
+#include <libudev.h>
+
 #include "platform/nmp-object.h"
+#include "nm-utils/nm-udev-utils.h"
 
 #include "nm-test-utils-core.h"
 
@@ -159,7 +162,7 @@ _nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj,
 
 	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);
+		obj_clone->_link.udev.device = udev_device_ref (obj_old->_link.udev.device);
 	_nmp_object_fixup_link_udev_fields (obj_clone, nmp_cache_use_udev_get (cache));
 
 	g_assert (cache);
@@ -219,8 +222,8 @@ test_cache_link (void)
 	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);
+	struct udev_device *udev_device_2 = g_list_nth_data (global.udev_devices, 0);
+	struct udev_device *udev_device_3 = g_list_nth_data (global.udev_devices, 0);
 	NMPCacheOpsType ops_type;
 
 	cache = nmp_cache_new (nmtst_get_rand_int () % 2);
@@ -390,23 +393,40 @@ int
 main (int argc, char **argv)
 {
 	int result;
-	gs_unref_object GUdevClient *udev_client = NULL;
+	NMUdevClient *udev_client;
 
 	nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT");
 
-	udev_client = g_udev_client_new ((const char *[]) { "net", NULL });
+	udev_client = nm_udev_client_new ((const char *[]) { "net", NULL },
+	                                  NULL, NULL);
 	{
-		gs_unref_object GUdevEnumerator *udev_enumerator = g_udev_enumerator_new (udev_client);
+		struct udev_enumerate *enumerator;
+		struct udev_list_entry *devices, *l;
 
-		g_udev_enumerator_add_match_subsystem (udev_enumerator, "net");
+		enumerator = nm_udev_client_enumerate_new (udev_client);
 
 		/* 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);
+			udev_enumerate_add_match_is_initialized (enumerator);
+
+		udev_enumerate_scan_devices (enumerator);
+
+		devices = udev_enumerate_get_list_entry (enumerator);
+		for (l = devices; l != NULL; l = udev_list_entry_get_next (l)) {
+			struct udev_device *udevice;
+
+			udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerator),
+			                                        udev_list_entry_get_name (l));
+			if (udevice == NULL)
+				continue;
 
-		global.udev_devices = g_udev_enumerator_execute (udev_enumerator);
+			global.udev_devices = g_list_prepend (global.udev_devices, udevice);
+		}
+		global.udev_devices = g_list_reverse (global.udev_devices);
+
+		udev_enumerate_unref (enumerator);
 	}
 
 	g_test_add_func ("/nmp-object/cache_link", test_cache_link);
@@ -414,10 +434,12 @@ main (int argc, char **argv)
 	result = g_test_run ();
 
 	while (global.udev_devices) {
-		g_object_unref (global.udev_devices->data);
+		udev_device_unref (global.udev_devices->data);
 		global.udev_devices = g_list_remove (global.udev_devices, global.udev_devices->data);
 	}
 
+	nm_udev_client_unref (udev_client);
+
 	return result;
 }
 
diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c
index 59a05bd4..6862f13e 100644
--- a/src/platform/tests/test-route.c
+++ b/src/platform/tests/test-route.c
@@ -94,7 +94,7 @@ test_ip4_route_metric0 (void)
 	nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, metric);
 
 	/* add the first route */
-	g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, metric, mss));
+	nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, metric, mss);
 	accept_signal (route_added);
 
 	nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0);
@@ -108,7 +108,7 @@ test_ip4_route_metric0 (void)
 	nmtstp_assert_ip4_route_exists (NULL, TRUE,  DEVICE_NAME, network, plen, metric);
 
 	/* add the second route */
-	g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, 0, mss));
+	nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, INADDR_ANY, 0, 0, mss);
 	accept_signal (route_added);
 
 	nmtstp_assert_ip4_route_exists (NULL, TRUE,  DEVICE_NAME, network, plen, 0);
@@ -160,27 +160,27 @@ test_ip4_route (void)
 	inet_pton (AF_INET, "198.51.100.1", &gateway);
 
 	/* Add route to gateway */
-	g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 32, INADDR_ANY, 0, metric, mss));
+	nmtstp_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 */
 	nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, metric);
-	g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, 0, metric, mss));
+	nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, 0, metric, mss);
 	nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric);
 	accept_signal (route_added);
 
 	/* Add route again */
-	g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, 0, metric, mss));
+	nmtstp_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 */
 	nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, 0, 0, metric);
-	g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway, 0, metric, mss));
+	nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway, 0, metric, mss);
 	nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, 0, 0, metric);
 	accept_signal (route_added);
 
 	/* Add default route again */
-	g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway, 0, metric, mss));
+	nmtstp_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 */
@@ -222,6 +222,14 @@ test_ip4_route (void)
 	/* Remove route again */
 	g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric));
 
+	/* Remove default route */
+	g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, 0, 0, metric));
+	accept_signal (route_removed);
+
+	/* Remove route to gateway */
+	g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, gateway, 32, metric));
+	accept_signal (route_removed);
+
 	free_signal (route_added);
 	free_signal (route_changed);
 	free_signal (route_removed);
@@ -238,36 +246,55 @@ test_ip6_route (void)
 	NMPlatformIP6Route rts[3];
 	struct in6_addr network;
 	guint8 plen = 64;
-	struct in6_addr gateway;
+	struct in6_addr gateway, pref_src;
 	/* Choose a high metric so that we hopefully don't conflict. */
 	int metric = 22987;
 	int mss = 1000;
 
 	inet_pton (AF_INET6, "2001:db8:a:b:0:0:0:0", &network);
 	inet_pton (AF_INET6, "2001:db8:c:d:1:2:3:4", &gateway);
+	inet_pton (AF_INET6, "::42", &pref_src);
+
+	g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, pref_src, 128, in6addr_any,
+	                                       NM_PLATFORM_LIFETIME_PERMANENT, NM_PLATFORM_LIFETIME_PERMANENT, 0));
+	accept_signals (route_added, 0, 1);
+
+	/* Wait that the address becomes non-tentative.  Dummy interfaces are NOARP
+	 * and thus don't do DAD, but the kernel sets the address as tentative for a
+	 * small amount of time, which prevents the immediate addition of the route
+	 * with RTA_PREFSRC */
+	NMTST_WAIT_ASSERT (200, {
+		const NMPlatformIP6Address *plt_addr;
+
+		nmtstp_wait_for_signal (NM_PLATFORM_GET, 50);
+		nm_platform_process_events (NM_PLATFORM_GET);
+		plt_addr = nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, pref_src, 128);
+		if (plt_addr && !NM_FLAGS_HAS (plt_addr->n_ifa_flags, IFA_F_TENTATIVE))
+			break;
+	});
 
 	/* Add route to gateway */
-	g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 128, in6addr_any, metric, mss));
+	nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 128, in6addr_any, in6addr_any, metric, mss);
 	accept_signal (route_added);
 
 	/* Add route */
 	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));
+	nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, pref_src, 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 (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, metric, mss));
+	nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network, plen, gateway, pref_src, metric, mss);
 	accept_signals (route_changed, 0, 1);
 
 	/* Add default route */
 	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));
+	nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, in6addr_any, 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 (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, metric, mss));
+	nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway, in6addr_any, metric, mss);
 	accept_signals (route_changed, 0, 1);
 
 	/* Test route listing */
@@ -278,6 +305,7 @@ test_ip6_route (void)
 	rts[0].plen = 128;
 	rts[0].ifindex = ifindex;
 	rts[0].gateway = in6addr_any;
+	rts[0].pref_src = in6addr_any;
 	rts[0].metric = nm_utils_ip6_route_metric_normalize (metric);
 	rts[0].mss = mss;
 	rts[1].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
@@ -285,6 +313,7 @@ test_ip6_route (void)
 	rts[1].plen = plen;
 	rts[1].ifindex = ifindex;
 	rts[1].gateway = gateway;
+	rts[1].pref_src = pref_src;
 	rts[1].metric = nm_utils_ip6_route_metric_normalize (metric);
 	rts[1].mss = mss;
 	rts[2].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
@@ -292,6 +321,7 @@ test_ip6_route (void)
 	rts[2].plen = 0;
 	rts[2].ifindex = ifindex;
 	rts[2].gateway = gateway;
+	rts[2].pref_src = in6addr_any;
 	rts[2].metric = nm_utils_ip6_route_metric_normalize (metric);
 	rts[2].mss = mss;
 	g_assert_cmpint (routes->len, ==, 3);
@@ -306,6 +336,14 @@ test_ip6_route (void)
 	/* Remove route again */
 	g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric));
 
+	/* Remove default route */
+	g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, in6addr_any, 0, metric));
+	accept_signal (route_removed);
+
+	/* Remove route to gateway */
+	g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, gateway, 128, metric));
+	accept_signal (route_removed);
+
 	free_signal (route_added);
 	free_signal (route_changed);
 	free_signal (route_removed);
@@ -334,6 +372,114 @@ test_ip4_zero_gateway (void)
 	nm_platform_process_events (NM_PLATFORM_GET);
 }
 
+static void
+test_ip4_route_options (void)
+{
+	int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
+	NMPlatformIP4Route route = { };
+	in_addr_t network;
+	GArray *routes;
+	NMPlatformIP4Route rts[1];
+
+	inet_pton (AF_INET, "172.16.1.0", &network);
+
+	route.ifindex = ifindex;
+	route.rt_source = NM_IP_CONFIG_SOURCE_USER;
+	route.network = network;
+	route.plen = 24;
+	route.metric = 20;
+	route.tos = 0x28;
+	route.window = 10000;
+	route.cwnd = 16;
+	route.initcwnd = 30;
+	route.initrwnd = 50;
+	route.mtu = 1350;
+	route.lock_cwnd = TRUE;
+
+	g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, &route));
+
+	/* Test route listing */
+	routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex,
+	                                        NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT |
+	                                        NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
+	memset (rts, 0, sizeof (rts));
+	rts[0].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
+	rts[0].scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK);
+	rts[0].network = network;
+	rts[0].plen = 24;
+	rts[0].ifindex = ifindex;
+	rts[0].metric = 20;
+	rts[0].tos = 0x28;
+	rts[0].window = 10000;
+	rts[0].cwnd = 16;
+	rts[0].initcwnd = 30;
+	rts[0].initrwnd = 50;
+	rts[0].mtu = 1350;
+	rts[0].lock_cwnd = TRUE;
+
+	g_assert_cmpint (routes->len, ==, 1);
+	nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, rts, routes->len, TRUE);
+
+	/* Remove route */
+	g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, 24, 20));
+
+	g_array_unref (routes);
+}
+
+
+static void
+test_ip6_route_options (void)
+{
+	int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
+	NMPlatformIP6Route route = { };
+	struct in6_addr network;
+	GArray *routes;
+	NMPlatformIP6Route rts[3];
+
+	inet_pton (AF_INET6, "2001:db8:a:b:0:0:0:0", &network);
+
+	route.ifindex = ifindex;
+	route.rt_source = NM_IP_CONFIG_SOURCE_USER;
+	route.network = network;
+	route.plen = 64;
+	route.gateway = in6addr_any;
+	route.metric = 1024;
+	route.window = 20000;
+	route.cwnd = 8;
+	route.initcwnd = 22;
+	route.initrwnd = 33;
+	route.mtu = 1300;
+	route.lock_mtu = TRUE;
+
+	g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, &route));
+
+	/* Test route listing */
+	routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex,
+	                                        NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT |
+	                                        NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
+	memset (rts, 0, sizeof (rts));
+	rts[0].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
+	rts[0].network = network;
+	rts[0].plen = 64;
+	rts[0].ifindex = ifindex;
+	rts[0].gateway = in6addr_any;
+	rts[0].metric = 1024;
+	rts[0].window = 20000;
+	rts[0].cwnd = 8;
+	rts[0].initcwnd = 22;
+	rts[0].initrwnd = 33;
+	rts[0].mtu = 1300;
+	rts[0].lock_mtu = TRUE;
+
+	g_assert_cmpint (routes->len, ==, 1);
+	nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, rts, routes->len, TRUE);
+
+	/* Remove route */
+	g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, 64, 1024));
+
+	g_array_unref (routes);
+}
+
 /*****************************************************************************/
 
 NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP;
@@ -360,6 +506,8 @@ _nmtstp_setup_tests (void)
 	g_test_add_func ("/route/ip4", test_ip4_route);
 	g_test_add_func ("/route/ip6", test_ip6_route);
 	g_test_add_func ("/route/ip4_metric0", test_ip4_route_metric0);
+	g_test_add_func ("/route/ip4_options", test_ip4_route_options);
+	g_test_add_func ("/route/ip6_options", test_ip6_route_options);
 
 	if (nmtstp_is_root_test ())
 		g_test_add_func ("/route/ip4_zero_gateway", test_ip4_zero_gateway);
diff --git a/src/platform/wifi/wifi-utils-nl80211.c b/src/platform/wifi/wifi-utils-nl80211.c
index ac51678f..06eb7cb9 100644
--- a/src/platform/wifi/wifi-utils-nl80211.c
+++ b/src/platform/wifi/wifi-utils-nl80211.c
@@ -27,7 +27,6 @@
 #include <sys/ioctl.h>
 #include <net/ethernet.h>
 #include <unistd.h>
-#include <math.h>
 #include <netlink/netlink.h>
 #include <netlink/msg.h>
 #include <linux/nl80211.h>
@@ -35,8 +34,17 @@
 #include "wifi-utils-private.h"
 #include "wifi-utils-nl80211.h"
 #include "platform/nm-platform.h"
+#include "platform/nm-platform-utils.h"
 #include "nm-utils.h"
 
+#define _NMLOG_PREFIX_NAME      "wifi-nl80211"
+#define _NMLOG(level, domain, ...) \
+	G_STMT_START { \
+		nm_log ((level), (domain), NULL, NULL, \
+		        "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
+		        _NMLOG_PREFIX_NAME \
+		        _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
+	} G_STMT_END
 
 /*****************************************************************************
  * Copied from libnl3/genl:
@@ -219,9 +227,9 @@ out_cb_free:
 	nl_cb_put (cb);
 out:
 	if (result >= 0)
-		nm_log_dbg (LOGD_WIFI, "genl_ctrl_resolve: resolved \"%s\" as 0x%x", name, result);
+		_LOGD (LOGD_WIFI, "genl_ctrl_resolve: resolved \"%s\" as 0x%x", name, result);
 	else
-		nm_log_err (LOGD_WIFI, "genl_ctrl_resolve: failed resolve \"%s\"", name);
+		_LOGE (LOGD_WIFI, "genl_ctrl_resolve: failed resolve \"%s\"", name);
 	return result;
 }
 
@@ -333,8 +341,8 @@ _nl80211_send_and_recv (struct nl_sock *nl_sock,
 			    genlmsg_hdr (nlmsg_hdr (msg))->cmd == NL80211_CMD_GET_SCAN)
 				break;
 
-			nm_log_warn (LOGD_WIFI, "nl_recvmsgs() error: (%d) %s",
-			             err, nl_geterror (err));
+			_LOGW (LOGD_WIFI, "nl_recvmsgs() error: (%d) %s",
+			       err, nl_geterror (err));
 			break;
 		}
 	}
@@ -934,8 +942,9 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg)
 
 		nla_for_each_nested (nl_freq, tb_band[NL80211_BAND_ATTR_FREQS],
 		                     rem_freq) {
-			nla_parse_nested (tb_freq, NL80211_FREQUENCY_ATTR_MAX,
-			                  nl_freq, freq_policy);
+			if (nla_parse_nested (tb_freq, NL80211_FREQUENCY_ATTR_MAX,
+			                      nl_freq, freq_policy) < 0)
+				continue;
 
 			if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
 				continue;
@@ -955,8 +964,9 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg)
 
 		nla_for_each_nested (nl_freq, tb_band[NL80211_BAND_ATTR_FREQS],
 		                    rem_freq) {
-			nla_parse_nested (tb_freq, NL80211_FREQUENCY_ATTR_MAX,
-			                  nl_freq, freq_policy);
+			if (nla_parse_nested (tb_freq, NL80211_FREQUENCY_ATTR_MAX,
+			                      nl_freq, freq_policy) < 0)
+				continue;
 
 			if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
 				continue;
@@ -1003,7 +1013,9 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg)
 			case WLAN_CIPHER_SUITE_SMS4:
 				break;
 			default:
-				nm_log_dbg (LOGD_PLATFORM | LOGD_WIFI, "Don't know the meaning of NL80211_ATTR_CIPHER_SUITE %#8.8x.", ciphers[i]);
+				_LOGD (LOGD_PLATFORM | LOGD_WIFI,
+				       "don't know the meaning of NL80211_ATTR_CIPHER_SUITE %#8.8x.",
+				       ciphers[i]);
 				break;
 			}
 		}
@@ -1030,13 +1042,20 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg)
 }
 
 WifiData *
-wifi_nl80211_init (const char *iface, int ifindex)
+wifi_nl80211_init (int ifindex)
 {
 	WifiDataNl80211 *nl80211;
 	struct nl_msg *msg;
 	struct nl80211_device_info device_info = {};
+	char ifname[IFNAMSIZ];
+
+	if (!nmp_utils_if_indextoname (ifindex, ifname)) {
+		_LOGW (LOGD_PLATFORM | LOGD_WIFI,
+		       "can't determine interface name for ifindex %d", ifindex);
+		nm_sprintf_buf (ifname, "if %d", ifindex);
+	}
 
-	nl80211 = wifi_data_new (iface, ifindex, sizeof (*nl80211));
+	nl80211 = wifi_data_new (ifindex, sizeof (*nl80211));
 	nl80211->parent.get_mode = wifi_nl80211_get_mode;
 	nl80211->parent.set_mode = wifi_nl80211_set_mode;
 	nl80211->parent.set_powersave = wifi_nl80211_set_powersave;
@@ -1071,44 +1090,44 @@ wifi_nl80211_init (const char *iface, int ifindex)
 
 	if (nl80211_send_and_recv (nl80211, msg, nl80211_wiphy_info_handler,
 	                           &device_info) < 0) {
-		nm_log_dbg (LOGD_PLATFORM | LOGD_WIFI,
-		            "(%s): NL80211_CMD_GET_WIPHY request failed",
-		            nl80211->parent.iface);
+		_LOGD (LOGD_PLATFORM | LOGD_WIFI,
+		       "(%s): NL80211_CMD_GET_WIPHY request failed",
+		       ifname);
 		goto error;
 	}
 
 	if (!device_info.success) {
-		nm_log_dbg (LOGD_PLATFORM | LOGD_WIFI,
-		            "(%s): NL80211_CMD_GET_WIPHY request indicated failure",
-		            nl80211->parent.iface);
+		_LOGD (LOGD_PLATFORM | LOGD_WIFI,
+		       "(%s): NL80211_CMD_GET_WIPHY request indicated failure",
+		       ifname);
 		goto error;
 	}
 
 	if (!device_info.supported) {
-		nm_log_dbg (LOGD_PLATFORM | LOGD_WIFI,
-		            "(%s): driver does not fully support nl80211, falling back to WEXT",
-		            nl80211->parent.iface);
+		_LOGD (LOGD_PLATFORM | LOGD_WIFI,
+		       "(%s): driver does not fully support nl80211, falling back to WEXT",
+		       ifname);
 		goto error;
 	}
 
 	if (!device_info.can_scan_ssid) {
-		nm_log_err (LOGD_PLATFORM | LOGD_WIFI,
-		            "(%s): driver does not support SSID scans",
-		            nl80211->parent.iface);
+		_LOGE (LOGD_PLATFORM | LOGD_WIFI,
+		       "(%s): driver does not support SSID scans",
+		       ifname);
 		goto error;
 	}
 
 	if (device_info.num_freqs == 0 || device_info.freqs == NULL) {
 		nm_log_err (LOGD_PLATFORM | LOGD_WIFI,
 		            "(%s): driver reports no supported frequencies",
-		            nl80211->parent.iface);
+		            ifname);
 		goto error;
 	}
 
 	if (device_info.caps == 0) {
-		nm_log_err (LOGD_PLATFORM | LOGD_WIFI,
-		            "(%s): driver doesn't report support of any encryption",
-		            nl80211->parent.iface);
+		_LOGE (LOGD_PLATFORM | LOGD_WIFI,
+		       "(%s): driver doesn't report support of any encryption",
+		       ifname);
 		goto error;
 	}
 
@@ -1120,9 +1139,9 @@ wifi_nl80211_init (const char *iface, int ifindex)
 	if (device_info.can_wowlan)
 		nl80211->parent.get_wowlan = wifi_nl80211_get_wowlan;
 
-	nm_log_info (LOGD_PLATFORM | LOGD_WIFI,
-	             "(%s): using nl80211 for WiFi device control",
-	             nl80211->parent.iface);
+	_LOGI (LOGD_PLATFORM | LOGD_WIFI,
+	       "(%s): using nl80211 for WiFi device control",
+	       ifname);
 
 	return (WifiData *) nl80211;
 
diff --git a/src/platform/wifi/wifi-utils-nl80211.h b/src/platform/wifi/wifi-utils-nl80211.h
index b3e8c897..aff24555 100644
--- a/src/platform/wifi/wifi-utils-nl80211.h
+++ b/src/platform/wifi/wifi-utils-nl80211.h
@@ -23,6 +23,6 @@
 
 #include "wifi-utils.h"
 
-WifiData *wifi_nl80211_init (const char *iface, int ifindex);
+WifiData *wifi_nl80211_init (int ifindex);
 
 #endif  /* __WIFI_UTILS_NL80211_H__ */
diff --git a/src/platform/wifi/wifi-utils-private.h b/src/platform/wifi/wifi-utils-private.h
index ebe76f1b..11a0f060 100644
--- a/src/platform/wifi/wifi-utils-private.h
+++ b/src/platform/wifi/wifi-utils-private.h
@@ -25,7 +25,6 @@
 #include "wifi-utils.h"
 
 struct WifiData {
-	char *iface;
 	int ifindex;
 	NMDeviceWifiCapabilities caps;
 
@@ -69,7 +68,7 @@ struct WifiData {
 	gboolean (*indicate_addressing_running) (WifiData *data, gboolean running);
 };
 
-gpointer wifi_data_new (const char *iface, int ifindex, gsize len);
+gpointer wifi_data_new (int ifindex, gsize len);
 void wifi_data_free (WifiData *data);
 
 #endif  /* __WIFI_UTILS_PRIVATE_H__ */
diff --git a/src/platform/wifi/wifi-utils-wext.c b/src/platform/wifi/wifi-utils-wext.c
index af8cf2de..1bc29ae8 100644
--- a/src/platform/wifi/wifi-utils-wext.c
+++ b/src/platform/wifi/wifi-utils-wext.c
@@ -26,7 +26,6 @@
 #include <sys/ioctl.h>
 #include <net/ethernet.h>
 #include <unistd.h>
-#include <math.h>
 
 #include "wifi-utils-private.h"
 #include "wifi-utils-wext.h"
@@ -69,8 +68,17 @@ struct iw_range_with_scan_capa
 	/* don't need the rest... */
 };
 
+#define _NMLOG_PREFIX_NAME      "wifi-wext"
+#define _NMLOG(level, domain, ...) \
+	G_STMT_START { \
+		nm_log ((level), (domain), NULL, NULL, \
+		        "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
+		        _NMLOG_PREFIX_NAME \
+		        _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
+	} G_STMT_END
+
 static guint32
-iw_freq_to_uint32 (struct iw_freq *freq)
+iw_freq_to_uint32 (const struct iw_freq *freq)
 {
 	if (freq->e == 0) {
 		/* Some drivers report channel not frequency.  Convert to a
@@ -81,8 +89,7 @@ iw_freq_to_uint32 (struct iw_freq *freq)
 		else if (freq->m == 14)
 			return 2484;
 	}
-
-	return (guint32) (((double) freq->m) * pow (10, freq->e) / 1000000);
+	return (guint32) ((((double) freq->m) * nm_utils_exp10 (freq->e)) / 1000000.0);
 }
 
 static void
@@ -94,20 +101,36 @@ wifi_wext_deinit (WifiData *parent)
 		close (wext->fd);
 }
 
+static gboolean
+get_ifname (int ifindex, char *buffer, const char *op)
+{
+	int errsv;
+
+	if (!nmp_utils_if_indextoname (ifindex, buffer)) {
+		errsv = errno;
+		_LOGW (LOGD_PLATFORM | LOGD_WIFI,
+		       "error getting interface name for ifindex %d, operation '%s': %s (%d)",
+		       ifindex, op, g_strerror (errsv), errsv);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
 static NM80211Mode
-wifi_wext_get_mode (WifiData *data)
+wifi_wext_get_mode_ifname (WifiData *data, const char *ifname)
 {
 	WifiDataWext *wext = (WifiDataWext *) data;
 	struct iwreq wrq;
 
 	memset (&wrq, 0, sizeof (struct iwreq));
-	nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface);
+	nm_utils_ifname_cpy (wrq.ifr_name, ifname);
 
 	if (ioctl (wext->fd, SIOCGIWMODE, &wrq) < 0) {
 		if (errno != ENODEV) {
-			nm_log_warn (LOGD_PLATFORM | LOGD_WIFI,
-			             "(%s): error %d getting card mode",
-			             wext->parent.iface, errno);
+			_LOGW (LOGD_PLATFORM | LOGD_WIFI,
+			       "(%s): error %d getting card mode",
+			       ifname, errno);
 		}
 		return NM_802_11_MODE_UNKNOWN;
 	}
@@ -126,13 +149,28 @@ wifi_wext_get_mode (WifiData *data)
 	return NM_802_11_MODE_UNKNOWN;
 }
 
+static NM80211Mode
+wifi_wext_get_mode (WifiData *data)
+{
+	char ifname[IFNAMSIZ];
+
+	if (!get_ifname (data->ifindex, ifname, "get-mode"))
+		return FALSE;
+
+	return wifi_wext_get_mode_ifname (data, ifname);
+}
+
 static gboolean
 wifi_wext_set_mode (WifiData *data, const NM80211Mode mode)
 {
 	WifiDataWext *wext = (WifiDataWext *) data;
 	struct iwreq wrq;
+	char ifname[IFNAMSIZ];
+
+	if (!get_ifname (data->ifindex, ifname, "set-mode"))
+		return FALSE;
 
-	if (wifi_wext_get_mode (data) == mode)
+	if (wifi_wext_get_mode_ifname (data, ifname) == mode)
 		return TRUE;
 
 	memset (&wrq, 0, sizeof (struct iwreq));
@@ -151,11 +189,12 @@ wifi_wext_set_mode (WifiData *data, const NM80211Mode mode)
 		return FALSE;
 	}
 
-	nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface);
+	nm_utils_ifname_cpy (wrq.ifr_name, ifname);
 	if (ioctl (wext->fd, SIOCSIWMODE, &wrq) < 0) {
 		if (errno != ENODEV) {
-			nm_log_err (LOGD_PLATFORM | LOGD_WIFI, "(%s): error setting mode %d",
-			            wext->parent.iface, mode);
+			_LOGE (LOGD_PLATFORM | LOGD_WIFI,
+			       "(%s): error setting mode %d",
+			       ifname, mode);
 		}
 		return FALSE;
 	}
@@ -168,6 +207,10 @@ wifi_wext_set_powersave (WifiData *data, guint32 powersave)
 {
 	WifiDataWext *wext = (WifiDataWext *) data;
 	struct iwreq wrq;
+	char ifname[IFNAMSIZ];
+
+	if (!get_ifname (data->ifindex, ifname, "set-powersave"))
+		return FALSE;
 
 	memset (&wrq, 0, sizeof (struct iwreq));
 	if (powersave == 1) {
@@ -175,11 +218,12 @@ wifi_wext_set_powersave (WifiData *data, guint32 powersave)
 	} else
 		wrq.u.power.disabled = 1;
 
-	nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface);
+	nm_utils_ifname_cpy (wrq.ifr_name, ifname);
 	if (ioctl (wext->fd, SIOCSIWPOWER, &wrq) < 0) {
 		if (errno != ENODEV) {
-			nm_log_err (LOGD_PLATFORM | LOGD_WIFI, "(%s): error setting powersave %" G_GUINT32_FORMAT,
-			            wext->parent.iface, powersave);
+			_LOGE (LOGD_PLATFORM | LOGD_WIFI,
+			       "(%s): error setting powersave %" G_GUINT32_FORMAT,
+			       ifname, powersave);
 		}
 		return FALSE;
 	}
@@ -192,13 +236,17 @@ wifi_wext_get_freq (WifiData *data)
 {
 	WifiDataWext *wext = (WifiDataWext *) data;
 	struct iwreq wrq;
+	char ifname[IFNAMSIZ];
+
+	if (!get_ifname (data->ifindex, ifname, "get-freq"))
+		return FALSE;
 
 	memset (&wrq, 0, sizeof (struct iwreq));
-	nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface);
+	nm_utils_ifname_cpy (wrq.ifr_name, ifname);
 	if (ioctl (wext->fd, SIOCGIWFREQ, &wrq) < 0) {
-		nm_log_warn (LOGD_PLATFORM | LOGD_WIFI,
-		             "(%s): error getting frequency: %s",
-		             wext->parent.iface, strerror (errno));
+		_LOGW (LOGD_PLATFORM | LOGD_WIFI,
+		       "(%s): error getting frequency: %s",
+		       ifname, strerror (errno));
 		return 0;
 	}
 
@@ -226,13 +274,17 @@ wifi_wext_get_bssid (WifiData *data, guint8 *out_bssid)
 {
 	WifiDataWext *wext = (WifiDataWext *) data;
 	struct iwreq wrq;
+	char ifname[IFNAMSIZ];
+
+	if (!get_ifname (data->ifindex, ifname, "get-bssid"))
+		return FALSE;
 
 	memset (&wrq, 0, sizeof (wrq));
-	nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface);
+	nm_utils_ifname_cpy (wrq.ifr_name, ifname);
 	if (ioctl (wext->fd, SIOCGIWAP, &wrq) < 0) {
-		nm_log_warn (LOGD_PLATFORM | LOGD_WIFI,
-		             "(%s): error getting associated BSSID: %s",
-		             wext->parent.iface, strerror (errno));
+		_LOGW (LOGD_PLATFORM | LOGD_WIFI,
+		       "(%s): error getting associated BSSID: %s",
+		       ifname, strerror (errno));
 		return FALSE;
 	}
 	memcpy (out_bssid, &(wrq.u.ap_addr.sa_data), ETH_ALEN);
@@ -245,9 +297,13 @@ wifi_wext_get_rate (WifiData *data)
 	WifiDataWext *wext = (WifiDataWext *) data;
 	struct iwreq wrq;
 	int err;
+	char ifname[IFNAMSIZ];
+
+	if (!get_ifname (data->ifindex, ifname, "get-rate"))
+		return FALSE;
 
 	memset (&wrq, 0, sizeof (wrq));
-	nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface);
+	nm_utils_ifname_cpy (wrq.ifr_name, ifname);
 	err = ioctl (wext->fd, SIOCGIWRATE, &wrq);
 	return ((err == 0) ? wrq.u.bitrate.value / 1000 : 0);
 }
@@ -264,16 +320,16 @@ wext_qual_to_percent (const struct iw_quality *qual,
 
 	/* Magically convert the many different WEXT quality representations to a percentage */
 
-	nm_log_dbg (LOGD_WIFI,
-	            "QL: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X, updated: 0x%X  ** MAX: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X, updated: 0x%X",
-	            (__s8) qual->qual, qual->qual, qual->qual,
-	            (__s8) qual->level, qual->level, qual->level,
-	            (__s8) qual->noise, qual->noise, qual->noise,
-	            qual->updated,
-	            (__s8) max_qual->qual, max_qual->qual, max_qual->qual,
-	            (__s8) max_qual->level, max_qual->level, max_qual->level,
-	            (__s8) max_qual->noise, max_qual->noise, max_qual->noise,
-	            max_qual->updated);
+	_LOGD (LOGD_WIFI,
+	       "QL: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X, updated: 0x%X  ** MAX: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X, updated: 0x%X",
+	       (__s8) qual->qual, qual->qual, qual->qual,
+	       (__s8) qual->level, qual->level, qual->level,
+	       (__s8) qual->noise, qual->noise, qual->noise,
+	       qual->updated,
+	       (__s8) max_qual->qual, max_qual->qual, max_qual->qual,
+	       (__s8) max_qual->level, max_qual->level, max_qual->level,
+	       (__s8) max_qual->noise, max_qual->noise, max_qual->noise,
+	       max_qual->updated);
 
 	/* Try using the card's idea of the signal quality first as long as it tells us what the max quality is.
 	 * Drivers that fill in quality values MUST treat them as percentages, ie the "Link Quality" MUST be
@@ -319,8 +375,8 @@ wext_qual_to_percent (const struct iw_quality *qual,
 		/* A sort of signal-to-noise ratio calculation */
 		level_percent = (int) (100 - 70 * (((double)max_level - (double)level) /
 		                                   ((double)max_level - (double)noise)));
-		nm_log_dbg (LOGD_WIFI, "QL1: level_percent is %d.  max_level %d, level %d, noise_floor %d.",
-		            level_percent, max_level, level, noise);
+		_LOGD (LOGD_WIFI, "QL1: level_percent is %d.  max_level %d, level %d, noise_floor %d.",
+		       level_percent, max_level, level, noise);
 	} else if (   (max_qual->level != 0)
 	           && !(max_qual->updated & IW_QUAL_LEVEL_INVALID) /* Valid max_qual->level as upper bound */
 	           && !(qual->updated & IW_QUAL_LEVEL_INVALID)) {
@@ -331,18 +387,18 @@ wext_qual_to_percent (const struct iw_quality *qual,
 		/* Signal level is relavtive (0 -> max_qual->level) */
 		level = CLAMP (level, 0, max_qual->level);
 		level_percent = (int)(100 * ((double)level / (double)max_qual->level));
-		nm_log_dbg (LOGD_WIFI, "QL2: level_percent is %d.  max_level %d, level %d.",
-		            level_percent, max_qual->level, level);
+		_LOGD (LOGD_WIFI, "QL2: level_percent is %d.  max_level %d, level %d.",
+		       level_percent, max_qual->level, level);
 	} else if (percent == -1) {
-		nm_log_dbg (LOGD_WIFI, "QL: Could not get quality %% value from driver.  Driver is probably buggy.");
+		_LOGD (LOGD_WIFI, "QL: Could not get quality %% value from driver.  Driver is probably buggy.");
 	}
 
 	/* If the quality percent was 0 or doesn't exist, then try to use signal levels instead */
 	if ((percent < 1) && (level_percent >= 0))
 		percent = level_percent;
 
-	nm_log_dbg (LOGD_WIFI, "QL: Final quality percent is %d (%d).",
-	            percent, CLAMP (percent, 0, 100));
+	_LOGD (LOGD_WIFI, "QL: Final quality percent is %d (%d).",
+	       percent, CLAMP (percent, 0, 100));
 	return (CLAMP (percent, 0, 100));
 }
 
@@ -352,17 +408,21 @@ wifi_wext_get_qual (WifiData *data)
 	WifiDataWext *wext = (WifiDataWext *) data;
 	struct iwreq wrq;
 	struct iw_statistics stats;
+	char ifname[IFNAMSIZ];
+
+	if (!get_ifname (data->ifindex, ifname, "get-qual"))
+		return FALSE;
 
 	memset (&stats, 0, sizeof (stats));
 	wrq.u.data.pointer = &stats;
 	wrq.u.data.length = sizeof (stats);
 	wrq.u.data.flags = 1;  /* Clear updated flag */
-	nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface);
+	nm_utils_ifname_cpy (wrq.ifr_name, ifname);
 
 	if (ioctl (wext->fd, SIOCGIWSTATS, &wrq) < 0) {
-		nm_log_warn (LOGD_PLATFORM | LOGD_WIFI,
-		             "(%s): error getting signal strength: %s",
-		             wext->parent.iface, strerror (errno));
+		_LOGW (LOGD_PLATFORM | LOGD_WIFI,
+		       "(%s): error getting signal strength: %s",
+		       ifname, strerror (errno));
 		return -1;
 	}
 
@@ -392,9 +452,13 @@ wifi_wext_set_mesh_channel (WifiData *data, guint32 channel)
 {
 	WifiDataWext *wext = (WifiDataWext *) data;
 	struct iwreq wrq;
+	char ifname[IFNAMSIZ];
+
+	if (!get_ifname (data->ifindex, ifname, "set-mesh-channel"))
+		return FALSE;
 
 	memset (&wrq, 0, sizeof (struct iwreq));
-	nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface);
+	nm_utils_ifname_cpy (wrq.ifr_name, ifname);
 
 	if (channel > 0) {
 		wrq.u.freq.flags = IW_FREQ_FIXED;
@@ -403,9 +467,9 @@ wifi_wext_set_mesh_channel (WifiData *data, guint32 channel)
 	}
 
 	if (ioctl (wext->fd, SIOCSIWFREQ, &wrq) < 0) {
-		nm_log_err (LOGD_PLATFORM | LOGD_WIFI | LOGD_OLPC,
-		            "(%s): error setting channel to %d: %s",
-		            wext->parent.iface, channel, strerror (errno));
+		_LOGE (LOGD_PLATFORM | LOGD_WIFI | LOGD_OLPC,
+		       "(%s): error setting channel to %d: %s",
+		       ifname, channel, strerror (errno));
 		return FALSE;
 	}
 
@@ -418,6 +482,11 @@ wifi_wext_set_mesh_ssid (WifiData *data, const guint8 *ssid, gsize len)
 	WifiDataWext *wext = (WifiDataWext *) data;
 	struct iwreq wrq;
 	char buf[IW_ESSID_MAX_SIZE + 1];
+	char ifname[IFNAMSIZ];
+	int errsv;
+
+	if (!get_ifname (data->ifindex, ifname, "set-mesh-ssid"))
+		return FALSE;
 
 	memset (buf, 0, sizeof (buf));
 	memcpy (buf, ssid, MIN (sizeof (buf) - 1, len));
@@ -426,16 +495,17 @@ wifi_wext_set_mesh_ssid (WifiData *data, const guint8 *ssid, gsize len)
 	wrq.u.essid.length = len;
 	wrq.u.essid.flags = (len > 0) ? 1 : 0; /* 1=enable SSID, 0=disable/any */
 
-	nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface);
+	nm_utils_ifname_cpy (wrq.ifr_name, ifname);
 	if (ioctl (wext->fd, SIOCSIWESSID, &wrq) == 0)
 		return TRUE;
 
 	if (errno != ENODEV) {
-		nm_log_err (LOGD_PLATFORM | LOGD_WIFI | LOGD_OLPC,
-		            "(%s): error setting SSID to '%s': %s",
-		            wext->parent.iface,
-		            ssid ? nm_utils_escape_ssid (ssid, len) : "(null)",
-		            strerror (errno));
+		errsv = errno;
+		_LOGE (LOGD_PLATFORM | LOGD_WIFI | LOGD_OLPC,
+		       "(%s): error setting SSID to '%s': %s",
+		       ifname,
+		       ssid ? nm_utils_escape_ssid (ssid, len) : "(null)",
+		       strerror (errsv));
 	}
 
 	return FALSE;
@@ -444,12 +514,12 @@ wifi_wext_set_mesh_ssid (WifiData *data, const guint8 *ssid, gsize len)
 /*****************************************************************************/
 
 static gboolean
-wext_can_scan (WifiDataWext *wext)
+wext_can_scan_ifname (WifiDataWext *wext, const char *ifname)
 {
 	struct iwreq wrq;
 
 	memset (&wrq, 0, sizeof (struct iwreq));
-	nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface);
+	nm_utils_ifname_cpy (wrq.ifr_name, ifname);
 	if (ioctl (wext->fd, SIOCSIWSCAN, &wrq) < 0) {
 		if (errno == EOPNOTSUPP)
 			return FALSE;
@@ -458,16 +528,17 @@ wext_can_scan (WifiDataWext *wext)
 }
 
 static gboolean
-wext_get_range (WifiDataWext *wext,
-                struct iw_range *range,
-                guint32 *response_len)
+wext_get_range_ifname (WifiDataWext *wext,
+                       const char *ifname,
+                       struct iw_range *range,
+                       guint32 *response_len)
 {
 	int i = 26;
 	gboolean success = FALSE;
 	struct iwreq wrq;
 
 	memset (&wrq, 0, sizeof (struct iwreq));
-	nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface);
+	nm_utils_ifname_cpy (wrq.ifr_name, ifname);
 	wrq.u.data.pointer = (caddr_t) range;
 	wrq.u.data.length = sizeof (struct iw_range);
 
@@ -482,9 +553,9 @@ wext_get_range (WifiDataWext *wext,
 			success = TRUE;
 			break;
 		} else if (errno != EAGAIN) {
-			nm_log_err (LOGD_PLATFORM | LOGD_WIFI,
-			            "(%s): couldn't get driver range information (%d).",
-			            wext->parent.iface, errno);
+			_LOGE (LOGD_PLATFORM | LOGD_WIFI,
+			       "(%s): couldn't get driver range information (%d).",
+			       ifname, errno);
 			break;
 		}
 
@@ -492,9 +563,9 @@ wext_get_range (WifiDataWext *wext,
 	}
 
 	if (i <= 0) {
-		nm_log_warn (LOGD_PLATFORM | LOGD_WIFI,
-		             "(%s): driver took too long to respond to IWRANGE query.",
-		             wext->parent.iface);
+		_LOGW (LOGD_PLATFORM | LOGD_WIFI,
+		       "(%s): driver took too long to respond to IWRANGE query.",
+		       ifname);
 	}
 
 	return success;
@@ -506,7 +577,7 @@ wext_get_range (WifiDataWext *wext,
                   NM_WIFI_DEVICE_CAP_RSN)
 
 static guint32
-wext_get_caps (WifiDataWext *wext, struct iw_range *range)
+wext_get_caps (WifiDataWext *wext, const char *ifname, struct iw_range *range)
 {
 	guint32 caps = NM_WIFI_DEVICE_CAP_NONE;
 
@@ -531,16 +602,18 @@ wext_get_caps (WifiDataWext *wext, struct iw_range *range)
 	/* Check for cipher support but not WPA support */
 	if (    (caps & (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
 	    && !(caps & (NM_WIFI_DEVICE_CAP_WPA | NM_WIFI_DEVICE_CAP_RSN))) {
-		nm_log_warn (LOGD_WIFI, "%s: device supports WPA ciphers but not WPA protocol; "
-		             "WPA unavailable.", wext->parent.iface);
+		_LOGW (LOGD_WIFI,
+		       "%s: device supports WPA ciphers but not WPA protocol; WPA unavailable.",
+		       ifname);
 		caps &= ~WPA_CAPS;
 	}
 
 	/* Check for WPA support but not cipher support */
 	if (    (caps & (NM_WIFI_DEVICE_CAP_WPA | NM_WIFI_DEVICE_CAP_RSN))
 	    && !(caps & (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | NM_WIFI_DEVICE_CAP_CIPHER_CCMP))) {
-		nm_log_warn (LOGD_WIFI, "%s: device supports WPA protocol but not WPA ciphers; "
-		             "WPA unavailable.", wext->parent.iface);
+		_LOGW (LOGD_WIFI,
+		       "%s: device supports WPA protocol but not WPA ciphers; WPA unavailable.",
+		       ifname);
 		caps &= ~WPA_CAPS;
 	}
 
@@ -554,7 +627,7 @@ wext_get_caps (WifiDataWext *wext, struct iw_range *range)
 }
 
 WifiData *
-wifi_wext_init (const char *iface, int ifindex, gboolean check_scan)
+wifi_wext_init (int ifindex, gboolean check_scan)
 {
 	WifiDataWext *wext;
 	struct iw_range range;
@@ -562,8 +635,15 @@ wifi_wext_init (const char *iface, int ifindex, gboolean check_scan)
 	struct iw_range_with_scan_capa *scan_capa_range;
 	int i;
 	gboolean freq_valid = FALSE, has_5ghz = FALSE, has_2ghz = FALSE;
+	char ifname[IFNAMSIZ];
+
+	if (!nmp_utils_if_indextoname (ifindex, ifname)) {
+		_LOGW (LOGD_PLATFORM | LOGD_WIFI,
+		       "can't determine interface name for ifindex %d", ifindex);
+		return NULL;
+	}
 
-	wext = wifi_data_new (iface, ifindex, sizeof (*wext));
+	wext = wifi_data_new (ifindex, sizeof (*wext));
 	wext->parent.get_mode = wifi_wext_get_mode;
 	wext->parent.set_mode = wifi_wext_set_mode;
 	wext->parent.set_powersave = wifi_wext_set_powersave;
@@ -582,17 +662,17 @@ wifi_wext_init (const char *iface, int ifindex, gboolean check_scan)
 		goto error;
 
 	memset (&range, 0, sizeof (struct iw_range));
-	if (wext_get_range (wext, &range, &response_len) == FALSE) {
-		nm_log_info (LOGD_PLATFORM | LOGD_WIFI, "(%s): driver WEXT range request failed",
-		             wext->parent.iface);
+	if (wext_get_range_ifname (wext, ifname, &range, &response_len) == FALSE) {
+		_LOGI (LOGD_PLATFORM | LOGD_WIFI, "(%s): driver WEXT range request failed",
+		       ifname);
 		goto error;
 	}
 
 	if ((response_len < 300) || (range.we_version_compiled < 21)) {
-		nm_log_info (LOGD_PLATFORM | LOGD_WIFI,
-		             "(%s): driver WEXT version too old (got %d, expected >= 21)",
-		             wext->parent.iface,
-		             range.we_version_compiled);
+		_LOGI (LOGD_PLATFORM | LOGD_WIFI,
+		       "(%s): driver WEXT version too old (got %d, expected >= 21)",
+		       ifname,
+		       range.we_version_compiled);
 		goto error;
 	}
 
@@ -612,10 +692,10 @@ wifi_wext_init (const char *iface, int ifindex, gboolean check_scan)
 	}
 
 	/* Check for scanning capability; cards that can't scan are not supported */
-	if (check_scan && (wext_can_scan (wext) == FALSE)) {
-		nm_log_info (LOGD_PLATFORM | LOGD_WIFI,
-		             "(%s): drivers that cannot scan are unsupported",
-		             wext->parent.iface);
+	if (check_scan && (wext_can_scan_ifname (wext, ifname) == FALSE)) {
+		_LOGI (LOGD_PLATFORM | LOGD_WIFI,
+		       "(%s): drivers that cannot scan are unsupported",
+		       ifname);
 		goto error;
 	}
 
@@ -625,18 +705,18 @@ wifi_wext_init (const char *iface, int ifindex, gboolean check_scan)
 	 */
 	scan_capa_range = (struct iw_range_with_scan_capa *) &range;
 	if (scan_capa_range->scan_capa & NM_IW_SCAN_CAPA_ESSID) {
-		nm_log_info (LOGD_PLATFORM | LOGD_WIFI,
-		             "(%s): driver supports SSID scans (scan_capa 0x%02X).",
-		             wext->parent.iface,
-		             scan_capa_range->scan_capa);
+		_LOGI (LOGD_PLATFORM | LOGD_WIFI,
+		       "(%s): driver supports SSID scans (scan_capa 0x%02X).",
+		       ifname,
+		       scan_capa_range->scan_capa);
 	} else {
-		nm_log_info (LOGD_PLATFORM | LOGD_WIFI,
-		             "(%s): driver does not support SSID scans (scan_capa 0x%02X).",
-		             wext->parent.iface,
-		             scan_capa_range->scan_capa);
+		_LOGI (LOGD_PLATFORM | LOGD_WIFI,
+		       "(%s): driver does not support SSID scans (scan_capa 0x%02X).",
+		       ifname,
+		       scan_capa_range->scan_capa);
 	}
 
-	wext->parent.caps = wext_get_caps (wext, &range);
+	wext->parent.caps = wext_get_caps (wext, ifname, &range);
 	if (freq_valid)
 		wext->parent.caps |= NM_WIFI_DEVICE_CAP_FREQ_VALID;
 	if (has_2ghz)
@@ -644,9 +724,9 @@ wifi_wext_init (const char *iface, int ifindex, gboolean check_scan)
 	if (has_5ghz)
 		wext->parent.caps |= NM_WIFI_DEVICE_CAP_FREQ_5GHZ;
 
-	nm_log_info (LOGD_PLATFORM | LOGD_WIFI,
-	             "(%s): using WEXT for WiFi device control",
-	             wext->parent.iface);
+	_LOGI (LOGD_PLATFORM | LOGD_WIFI,
+	       "(%s): using WEXT for WiFi device control",
+	       ifname);
 
 	return (WifiData *) wext;
 
diff --git a/src/platform/wifi/wifi-utils-wext.h b/src/platform/wifi/wifi-utils-wext.h
index e168fe28..3ef5a173 100644
--- a/src/platform/wifi/wifi-utils-wext.h
+++ b/src/platform/wifi/wifi-utils-wext.h
@@ -23,7 +23,7 @@
 
 #include "wifi-utils.h"
 
-WifiData *wifi_wext_init (const char *iface, int ifindex, gboolean check_scan);
+WifiData *wifi_wext_init (int ifindex, gboolean check_scan);
 
 gboolean wifi_wext_is_wifi (const char *iface);
 
diff --git a/src/platform/wifi/wifi-utils.c b/src/platform/wifi/wifi-utils.c
index b8da02c1..d0052121 100644
--- a/src/platform/wifi/wifi-utils.c
+++ b/src/platform/wifi/wifi-utils.c
@@ -38,12 +38,11 @@
 #include "platform/nm-platform-utils.h"
 
 gpointer
-wifi_data_new (const char *iface, int ifindex, gsize len)
+wifi_data_new (int ifindex, gsize len)
 {
 	WifiData *data;
 
 	data = g_malloc0 (len);
-	data->iface = g_strdup (iface);
 	data->ifindex = ifindex;
 	return data;
 }
@@ -51,7 +50,6 @@ wifi_data_new (const char *iface, int ifindex, gsize len)
 void
 wifi_data_free (WifiData *data)
 {
-	g_free (data->iface);
 	memset (data, 0, sizeof (*data));
 	g_free (data);
 }
@@ -59,17 +57,16 @@ wifi_data_free (WifiData *data)
 /*****************************************************************************/
 
 WifiData *
-wifi_utils_init (const char *iface, int ifindex, gboolean check_scan)
+wifi_utils_init (int ifindex, gboolean check_scan)
 {
 	WifiData *ret;
 
-	g_return_val_if_fail (iface != NULL, NULL);
 	g_return_val_if_fail (ifindex > 0, NULL);
 
-	ret = wifi_nl80211_init (iface, ifindex);
+	ret = wifi_nl80211_init (ifindex);
 	if (ret == NULL) {
 #if HAVE_WEXT
-		ret = wifi_wext_init (iface, ifindex, check_scan);
+		ret = wifi_wext_init (ifindex, check_scan);
 #endif
 	}
 	return ret;
@@ -83,14 +80,6 @@ wifi_utils_get_ifindex (WifiData *data)
 	return data->ifindex;
 }
 
-const char *
-wifi_utils_get_iface (WifiData *data)
-{
-	g_return_val_if_fail (data != NULL, NULL);
-
-	return data->iface;
-}
-
 NMDeviceWifiCapabilities
 wifi_utils_get_caps (WifiData *data)
 {
diff --git a/src/platform/wifi/wifi-utils.h b/src/platform/wifi/wifi-utils.h
index 4fd5a80b..705717b0 100644
--- a/src/platform/wifi/wifi-utils.h
+++ b/src/platform/wifi/wifi-utils.h
@@ -30,12 +30,10 @@ typedef struct WifiData WifiData;
 
 gboolean wifi_utils_is_wifi (int dirfd, const char *ifname);
 
-WifiData *wifi_utils_init (const char *iface, int ifindex, gboolean check_scan);
+WifiData *wifi_utils_init (int ifindex, gboolean check_scan);
 
 int wifi_utils_get_ifindex (WifiData *data);
 
-const char *wifi_utils_get_iface (WifiData *data);
-
 void wifi_utils_deinit (WifiData *data);
 
 NMDeviceWifiCapabilities wifi_utils_get_caps (WifiData *data);