Blob Blame History Raw
From 891a9f859f1f399eaf16d9fa8e00d5bf4bb69100 Mon Sep 17 00:00:00 2001
From: Dan Winship <danw@gnome.org>
Date: Tue, 1 Oct 2013 11:08:31 -0400
Subject: [PATCH 01/14] logging: tweak logging-enabled functions

Rather than having separate nm_logging_level_enabled() and
nm_logging_domain_enabled(), have just nm_logging_enabled() that
checks both.

(cherry picked from commit 0e3432fbeaf2d995fbd26aab682970b824fbe032)
---
 src/devices/nm-device-team.c          |  2 +-
 src/devices/nm-device-wifi.c          |  2 +-
 src/devices/nm-device.c               |  4 ++--
 src/dhcp-manager/nm-dhcp-client.c     |  4 ++--
 src/logging/nm-logging.c              | 10 ++--------
 src/logging/nm-logging.h              |  3 +--
 src/nm-properties-changed-signal.c    |  2 +-
 src/ppp-manager/nm-ppp-manager.c      |  3 +--
 src/settings/nm-settings-connection.c |  2 +-
 9 files changed, 12 insertions(+), 20 deletions(-)

diff --git a/src/devices/nm-device-team.c b/src/devices/nm-device-team.c
index 31806bc..e6c7892 100644
--- a/src/devices/nm-device-team.c
+++ b/src/devices/nm-device-team.c
@@ -446,7 +446,7 @@ teamd_start (NMDevice *dev, NMSettingTeam *s_team, NMDeviceTeamPrivate *priv)
 		g_ptr_array_add (argv, (gpointer) config);
 	}
 
-	if (nm_logging_level_enabled (LOGL_DEBUG))
+	if (nm_logging_enabled (LOGL_DEBUG, LOGD_TEAM))
 		g_ptr_array_add (argv, (gpointer) "-gg");
 	g_ptr_array_add (argv, NULL);
 
diff --git a/src/devices/nm-device-wifi.c b/src/devices/nm-device-wifi.c
index e0e2d99..147ed08 100644
--- a/src/devices/nm-device-wifi.c
+++ b/src/devices/nm-device-wifi.c
@@ -1625,7 +1625,7 @@ request_wireless_scan (gpointer user_data)
 
 		ssids = build_hidden_probe_list (self);
 
-		if (nm_logging_level_enabled (LOGL_DEBUG)) {
+		if (nm_logging_enabled (LOGL_DEBUG, LOGD_WIFI_SCAN)) {
 			if (ssids) {
 				guint i;
 				char *foo;
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 39146a6..7757153 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -2430,7 +2430,7 @@ aipd_start (NMDevice *self, NMDeviceStateReason *reason)
 	argv[i++] = "--script";
 	argv[i++] = (char *) nm_device_autoipd_helper_path;
 
-	if (nm_logging_level_enabled (LOGL_DEBUG))
+	if (nm_logging_enabled (LOGL_DEBUG, LOGD_AUTOIP4))
 		argv[i++] = "--debug";
 	argv[i++] = (char *) nm_device_get_ip_iface (self);
 	argv[i++] = NULL;
@@ -5147,7 +5147,7 @@ spawn_ping (NMDevice *self,
 
 	args[6] = str_timeout = g_strdup_printf ("%u", timeout);
 
-	if (nm_logging_level_enabled (LOGL_DEBUG)) {
+	if (nm_logging_enabled (LOGL_DEBUG, log_domain)) {
 		cmd = g_strjoinv (" ", (gchar **) args);
 		nm_log_dbg (log_domain, "(%s): running '%s'",
 		            nm_device_get_iface (self),
diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c
index dc89b41..2063049 100644
--- a/src/dhcp-manager/nm-dhcp-client.c
+++ b/src/dhcp-manager/nm-dhcp-client.c
@@ -431,7 +431,7 @@ get_duid (NMDHCPClient *self)
 		duid = generate_duid_from_machine_id ();
 		g_assert (duid);
 
-		if (nm_logging_level_enabled (LOGL_DEBUG)) {
+		if (nm_logging_enabled (LOGL_DEBUG, LOGD_DHCP6)) {
 			escaped = escape_duid (duid);
 			nm_log_dbg (LOGD_DHCP6, "Generated DUID %s", escaped);
 			g_free (escaped);
@@ -469,7 +469,7 @@ nm_dhcp_client_start_ip6 (NMDHCPClient *self,
 	if (!priv->duid)
 		priv->duid = NM_DHCP_CLIENT_GET_CLASS (self)->get_duid (self);
 
-	if (nm_logging_level_enabled (LOGL_DEBUG)) {
+	if (nm_logging_enabled (LOGL_DEBUG, LOGD_DHCP)) {
 		escaped = escape_duid (priv->duid);
 		nm_log_dbg (LOGD_DHCP, "(%s): DHCPv6 DUID is '%s'", priv->iface, escaped);
 		g_free (escaped);
diff --git a/src/logging/nm-logging.c b/src/logging/nm-logging.c
index cbb04a7..0acc5d2 100644
--- a/src/logging/nm-logging.c
+++ b/src/logging/nm-logging.c
@@ -279,15 +279,9 @@ nm_logging_all_domains_to_string (void)
 }
 
 gboolean
-nm_logging_level_enabled (guint32 level)
+nm_logging_enabled (guint32 level, guint64 domain)
 {
-	return !!(log_level & level);
-}
-
-gboolean
-nm_logging_domain_enabled (guint64 domain)
-{
-	return !!(log_domains & domain);
+	return !!(log_level & level) && !!(log_domains & domain);
 }
 
 void
diff --git a/src/logging/nm-logging.h b/src/logging/nm-logging.h
index 1e3a167..1612bee 100644
--- a/src/logging/nm-logging.h
+++ b/src/logging/nm-logging.h
@@ -108,8 +108,7 @@ void _nm_log (const char *loc,
 
 const char *nm_logging_level_to_string (void);
 char *nm_logging_domains_to_string (void);
-gboolean nm_logging_level_enabled (guint32 level);
-gboolean nm_logging_domain_enabled (guint64 domain);
+gboolean nm_logging_enabled (guint32 level, guint64 domain);
 
 const char *nm_logging_all_levels_to_string (void);
 const char *nm_logging_all_domains_to_string (void);
diff --git a/src/nm-properties-changed-signal.c b/src/nm-properties-changed-signal.c
index b61b871..6e07c25 100644
--- a/src/nm-properties-changed-signal.c
+++ b/src/nm-properties-changed-signal.c
@@ -102,7 +102,7 @@ properties_changed (gpointer data)
 
 	g_assert (info);
 
-	if (nm_logging_level_enabled (LOGL_DEBUG)) {
+	if (nm_logging_enabled (LOGL_DEBUG, LOGD_DBUS_PROPS)) {
 		GString *buf = g_string_new (NULL);
 
 		g_hash_table_foreach (info->hash, add_to_string, buf);
diff --git a/src/ppp-manager/nm-ppp-manager.c b/src/ppp-manager/nm-ppp-manager.c
index b2f2326..7b84937 100644
--- a/src/ppp-manager/nm-ppp-manager.c
+++ b/src/ppp-manager/nm-ppp-manager.c
@@ -831,8 +831,7 @@ create_pppd_cmd_line (NMPPPManager *self,
 	nm_cmd_line_add_string (cmd, ",");
 
 	ppp_debug = !!getenv ("NM_PPP_DEBUG");
-	if (   nm_logging_level_enabled (LOGL_DEBUG)
-	    && nm_logging_domain_enabled (LOGD_PPP))
+	if (nm_logging_enabled (LOGL_DEBUG, LOGD_PPP))
 		ppp_debug = TRUE;
 
 	if (ppp_debug)
diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c
index eac6ada..7ec3869 100644
--- a/src/settings/nm-settings-connection.c
+++ b/src/settings/nm-settings-connection.c
@@ -911,7 +911,7 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self,
 	if (existing_secrets)
 		g_hash_table_unref (existing_secrets);
 
-	if (nm_logging_level_enabled (LOGL_DEBUG)) {
+	if (nm_logging_enabled (LOGL_DEBUG, LOGD_SETTINGS)) {
 		if (hints)
 			joined_hints = g_strjoinv (",", (char **) hints);
 		nm_log_dbg (LOGD_SETTINGS, "(%s/%s:%u) secrets requested flags 0x%X hints '%s'",
-- 
1.8.5.3


From 706575ee78db7215e0db69d9eaeb3d596576c3f0 Mon Sep 17 00:00:00 2001
From: Thomas Haller <thaller@redhat.com>
Date: Mon, 28 Oct 2013 11:54:22 +0100
Subject: [PATCH 02/14] libnm-util: add nm_utils_inet[46]_ntop functions

https://bugzilla.gnome.org/show_bug.cgi?id=711684

(cherry picked from commit 41f8114359404ae2cf14724d84eccfc378e9317c)

Signed-off-by: Thomas Haller <thaller@redhat.com>
---
 libnm-util/libnm-util.ver |  2 ++
 libnm-util/nm-utils.c     | 55 +++++++++++++++++++++++++++++++++++++++++++++++
 libnm-util/nm-utils.h     | 10 +++++++++
 3 files changed, 67 insertions(+)

diff --git a/libnm-util/libnm-util.ver b/libnm-util/libnm-util.ver
index d3e430c..1f64c3d 100644
--- a/libnm-util/libnm-util.ver
+++ b/libnm-util/libnm-util.ver
@@ -564,6 +564,8 @@ global:
 	nm_utils_hwaddr_type;
 	nm_utils_hwaddr_valid;
 	nm_utils_iface_valid_name;
+	nm_utils_inet4_ntop;
+	nm_utils_inet6_ntop;
 	nm_utils_init;
 	nm_utils_ip4_addresses_from_gvalue;
 	nm_utils_ip4_addresses_to_gvalue;
diff --git a/libnm-util/nm-utils.c b/libnm-util/nm-utils.c
index c0b18f6..873401a 100644
--- a/libnm-util/nm-utils.c
+++ b/libnm-util/nm-utils.c
@@ -2273,3 +2273,58 @@ nm_utils_is_uuid (const char *str)
 
 	return FALSE;
 }
+
+static char _nm_utils_inet_ntop_buffer[NM_UTILS_INET_ADDRSTRLEN];
+
+/**
+ * nm_utils_inet4_ntop:
+ * @inaddr: the address that should be converted to string.
+ * @dst: the destination buffer, it must contain at least %INET_ADDRSTRLEN
+ *  or %NM_UTILS_INET_ADDRSTRLEN characters. If set to %NULL, it will return
+ *  a pointer to an internal, static buffer (shared with nm_utils_inet6_ntop()).
+ *  Beware, that the internal buffer will be overwritten with ever new call
+ *  of nm_utils_inet4_ntop() or nm_utils_inet6_ntop() that does not provied it's
+ *  own @dst buffer. Also, using the internal buffer is not thread safe. When
+ *  in doubt, pass your own @dst buffer to avoid these issues.
+ *
+ * Wrapper for inet_ntop.
+ *
+ * Returns: the input buffer @dst, or a pointer to an
+ *  internal, static buffer. This function cannot fail.
+ *
+ * Since: 0.9.10
+ **/
+const char *
+nm_utils_inet4_ntop (in_addr_t inaddr, char *dst)
+{
+	return inet_ntop (AF_INET, &inaddr, dst ? dst : _nm_utils_inet_ntop_buffer,
+	                  INET_ADDRSTRLEN);
+}
+
+/**
+ * nm_utils_inet6_ntop:
+ * @in6addr: the address that should be converted to string.
+ * @dst: the destination buffer, it must contain at least %INET6_ADDRSTRLEN
+ *  or %NM_UTILS_INET_ADDRSTRLEN characters. If set to %NULL, it will return
+ *  a pointer to an internal, static buffer (shared with nm_utils_inet4_ntop()).
+ *  Beware, that the internal buffer will be overwritten with ever new call
+ *  of nm_utils_inet4_ntop() or nm_utils_inet6_ntop() that does not provied it's
+ *  own @dst buffer. Also, using the internal buffer is not thread safe. When
+ *  in doubt, pass your own @dst buffer to avoid these issues.
+ *
+ * Wrapper for inet_ntop.
+ *
+ * Returns: the input buffer @dst, or a pointer to an
+ *  internal, static buffer. %NULL is not allowed as @in6addr,
+ *  otherwise, this function cannot fail.
+ *
+ * Since: 0.9.10
+ **/
+const char *
+nm_utils_inet6_ntop (const struct in6_addr *in6addr, char *dst)
+{
+	g_return_val_if_fail (in6addr, NULL);
+	return inet_ntop (AF_INET6, in6addr, dst ? dst : _nm_utils_inet_ntop_buffer,
+	                  INET6_ADDRSTRLEN);
+}
+
diff --git a/libnm-util/nm-utils.h b/libnm-util/nm-utils.h
index 25f4a56..f6fdf36 100644
--- a/libnm-util/nm-utils.h
+++ b/libnm-util/nm-utils.h
@@ -154,6 +154,16 @@ gboolean    nm_utils_iface_valid_name(const char *name);
 
 gboolean nm_utils_is_uuid (const char *str);
 
+/**
+ * NM_UTILS_INET_ADDRSTRLEN:
+ *
+ * Defines the minimal length for a char buffer that is suitable as @dst argument
+ * for both nm_utils_inet4_ntop() and nm_utils_inet6_ntop().
+ **/
+#define NM_UTILS_INET_ADDRSTRLEN     INET6_ADDRSTRLEN
+const char *nm_utils_inet4_ntop (in_addr_t inaddr, char *dst);
+const char *nm_utils_inet6_ntop (const struct in6_addr *in6addr, char *dst);
+
 G_END_DECLS
 
 #endif /* NM_UTILS_H */
-- 
1.8.5.3


From cdc8da432331fdfefc73d2fd69ac844310e61745 Mon Sep 17 00:00:00 2001
From: Dan Winship <danw@gnome.org>
Date: Mon, 16 Dec 2013 13:06:52 -0500
Subject: [PATCH 03/14] libnm-util: don't introspect nm_utils_inet[46]_ntop

nm_utils_inet4_ntop() and nm_utils_inet6_ntop() have arguments of
non-introspected types, so mark them (skip) to avoid warnings from
g-ir-scanner.

(cherry picked from commit d174825412eb5ceb5678dfd6bea00dfcad6a9e1d)
---
 libnm-util/nm-utils.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libnm-util/nm-utils.c b/libnm-util/nm-utils.c
index 873401a..030b8db 100644
--- a/libnm-util/nm-utils.c
+++ b/libnm-util/nm-utils.c
@@ -2277,7 +2277,7 @@ nm_utils_is_uuid (const char *str)
 static char _nm_utils_inet_ntop_buffer[NM_UTILS_INET_ADDRSTRLEN];
 
 /**
- * nm_utils_inet4_ntop:
+ * nm_utils_inet4_ntop: (skip)
  * @inaddr: the address that should be converted to string.
  * @dst: the destination buffer, it must contain at least %INET_ADDRSTRLEN
  *  or %NM_UTILS_INET_ADDRSTRLEN characters. If set to %NULL, it will return
@@ -2302,7 +2302,7 @@ nm_utils_inet4_ntop (in_addr_t inaddr, char *dst)
 }
 
 /**
- * nm_utils_inet6_ntop:
+ * nm_utils_inet6_ntop: (skip)
  * @in6addr: the address that should be converted to string.
  * @dst: the destination buffer, it must contain at least %INET6_ADDRSTRLEN
  *  or %NM_UTILS_INET_ADDRSTRLEN characters. If set to %NULL, it will return
-- 
1.8.5.3


From b0ea7caf77a4a1c79de35314205b6f0032c033b3 Mon Sep 17 00:00:00 2001
From: Thomas Haller <thaller@redhat.com>
Date: Tue, 11 Feb 2014 13:08:23 +0100
Subject: [PATCH 04/14] platform: refactor link_get() not to use auto_nl_object

The previous implementation called nl_object_get() and nl_object_put()
each time in link_get(). As nl_object_get() and nl_object_put()
causes debug logging in libnl, this clutters the output.

(cherry picked from commit e02b1a86208df7c7f2ae1d79e65597f02d8f6d27)

Signed-off-by: Thomas Haller <thaller@redhat.com>
---
 src/platform/nm-linux-platform.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 7933678..d576436 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -1459,7 +1459,7 @@ static struct rtnl_link *
 link_get (NMPlatform *platform, int ifindex)
 {
 	NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
-	auto_nl_object struct rtnl_link *rtnllink = rtnl_link_get (priv->link_cache, ifindex);
+	struct rtnl_link *rtnllink = rtnl_link_get (priv->link_cache, ifindex);
 
 	if (!rtnllink) {
 		platform->error = NM_PLATFORM_ERROR_NOT_FOUND;
@@ -1469,10 +1469,10 @@ link_get (NMPlatform *platform, int ifindex)
 	/* physical interfaces must be found by udev before they can be used */
 	if (!link_is_announceable (platform, rtnllink)) {
 		platform->error = NM_PLATFORM_ERROR_NOT_FOUND;
+		rtnl_link_put (rtnllink);
 		return NULL;
 	}
 
-	nl_object_get ((struct nl_object *) rtnllink);
 	return rtnllink;
 }
 
-- 
1.8.5.3


From 4f83bc2ab154f5ac4749e9514a850f0ae18b7ee4 Mon Sep 17 00:00:00 2001
From: Thomas Haller <thaller@redhat.com>
Date: Thu, 30 Jan 2014 20:31:29 +0100
Subject: [PATCH 05/14] core/platform: add debug logging when adding/deleting
 addresses

(cherry picked from commit 5d6a5f85726aa9d6dded482e46d7166db1b55aa1)

Signed-off-by: Thomas Haller <thaller@redhat.com>
---
 src/platform/nm-platform.c | 29 +++++++++++++++++++++++++++--
 1 file changed, 27 insertions(+), 2 deletions(-)

diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index 5871f86..1f0eee2 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -26,6 +26,8 @@
 #include <string.h>
 #include <netlink/route/addr.h>
 
+#include "NetworkManagerUtils.h"
+#include "nm-utils.h"
 #include "nm-platform.h"
 #include "NetworkManagerUtils.h"
 #include "nm-logging.h"
@@ -1168,7 +1170,18 @@ nm_platform_ip4_address_add (int ifindex,
 	g_return_val_if_fail (preferred >= 0, FALSE);
 	g_return_val_if_fail (klass->ip4_address_add, FALSE);
 
-	debug ("address: adding or updating IPv4 address");
+	if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) {
+		NMPlatformIP4Address addr = { 0 };
+
+		addr.ifindex = ifindex;
+		addr.address = address;
+		addr.peer_address = peer_address;
+		addr.plen = plen;
+		addr.lifetime = lifetime;
+		addr.preferred = preferred;
+
+		debug ("address: adding or updating IPv4 address: %s", nm_platform_ip4_address_to_string (&addr));
+	}
 	return klass->ip4_address_add (platform, ifindex, address, peer_address, plen, lifetime, preferred);
 }
 
@@ -1189,7 +1202,19 @@ nm_platform_ip6_address_add (int ifindex,
 	g_return_val_if_fail (preferred >= 0, FALSE);
 	g_return_val_if_fail (klass->ip6_address_add, FALSE);
 
-	debug ("address: adding or updating IPv6 address");
+	if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) {
+		NMPlatformIP6Address addr = { 0 };
+
+		addr.ifindex = ifindex;
+		addr.address = address;
+		addr.peer_address = peer_address;
+		addr.plen = plen;
+		addr.lifetime = lifetime;
+		addr.preferred = preferred;
+		addr.flags = flags;
+
+		debug ("address: adding or updating IPv6 address: %s", nm_platform_ip6_address_to_string (&addr));
+	}
 	return klass->ip6_address_add (platform, ifindex, address, peer_address, plen, lifetime, preferred, flags);
 }
 
-- 
1.8.5.3


From a8a92c5bd44fdf761d6151b31ebf6171b1a8af01 Mon Sep 17 00:00:00 2001
From: Thomas Haller <thaller@redhat.com>
Date: Thu, 13 Feb 2014 14:42:26 +0100
Subject: [PATCH 06/14] platform: add debug logging when adding/deleting routes

Also, change the logging of nm_platform_ip._address_delete()
to log what we are about to do, *before* checking for existing
addresses.

(cherry picked from commit e54a3ccaf8a5a95c6bf9ca2da1a0ee98db0b6541)

Signed-off-by: Thomas Haller <thaller@redhat.com>
---
 src/platform/nm-platform.c | 34 ++++++++++++++++++++++++++++++++--
 1 file changed, 32 insertions(+), 2 deletions(-)

diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index 1f0eee2..7de8db4 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -1227,13 +1227,14 @@ nm_platform_ip4_address_delete (int ifindex, in_addr_t address, int plen)
 	g_return_val_if_fail (plen > 0, FALSE);
 	g_return_val_if_fail (klass->ip4_address_delete, FALSE);
 
+	debug ("address: deleting IPv4 address %s/%d", nm_utils_inet4_ntop (address, NULL), plen);
+
 	if (!nm_platform_ip4_address_exists (ifindex, address, plen)) {
 		debug ("address doesn't exists");
 		platform->error = NM_PLATFORM_ERROR_NOT_FOUND;
 		return FALSE;
 	}
 
-	debug ("address: deleting IPv4 address");
 	return klass->ip4_address_delete (platform, ifindex, address, plen);
 }
 
@@ -1246,13 +1247,14 @@ nm_platform_ip6_address_delete (int ifindex, struct in6_addr address, int plen)
 	g_return_val_if_fail (plen > 0, FALSE);
 	g_return_val_if_fail (klass->ip6_address_delete, FALSE);
 
+	debug ("address: deleting IPv6 address %s/%d", nm_utils_inet6_ntop (&address, NULL), plen);
+
 	if (!nm_platform_ip6_address_exists (ifindex, address, plen)) {
 		debug ("address doesn't exists");
 		platform->error = NM_PLATFORM_ERROR_NOT_FOUND;
 		return FALSE;
 	}
 
-	debug ("address: deleting IPv6 address");
 	return klass->ip6_address_delete (platform, ifindex, address, plen);
 }
 
@@ -1489,6 +1491,18 @@ nm_platform_ip4_route_add (int ifindex,
 	if (!metric)
 		metric = 1024;
 
+	if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) {
+		NMPlatformIP4Route route = { 0 };
+
+		route.ifindex = ifindex;
+		route.network = network;
+		route.plen = plen;
+		route.gateway = gateway;
+		route.metric = metric;
+		route.mss = mss;
+
+		debug ("route: adding or updating IPv4 route: %s", nm_platform_ip4_route_to_string (&route));
+	}
 	return klass->ip4_route_add (platform, ifindex, network, plen, gateway, metric, mss);
 }
 
@@ -1505,6 +1519,18 @@ nm_platform_ip6_route_add (int ifindex,
 	if (!metric)
 		metric = 1024;
 
+	if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) {
+		NMPlatformIP6Route route = { 0 };
+
+		route.ifindex = ifindex;
+		route.network = network;
+		route.plen = plen;
+		route.gateway = gateway;
+		route.metric = metric;
+		route.mss = mss;
+
+		debug ("route: adding or updating IPv6 route: %s", nm_platform_ip6_route_to_string (&route));
+	}
 	return klass->ip6_route_add (platform, ifindex, network, plen, gateway, metric, mss);
 }
 
@@ -1516,6 +1542,8 @@ nm_platform_ip4_route_delete (int ifindex, in_addr_t network, int plen, int metr
 	g_return_val_if_fail (platform, FALSE);
 	g_return_val_if_fail (klass->ip4_route_delete, FALSE);
 
+	debug ("route: deleting IPv4 route %s/%d, metric=%d", nm_utils_inet4_ntop (network, NULL), plen, metric);
+
 	if (!nm_platform_ip4_route_exists (ifindex, network, plen, metric)) {
 		debug ("route not found");
 		platform->error = NM_PLATFORM_ERROR_NOT_FOUND;
@@ -1534,6 +1562,8 @@ nm_platform_ip6_route_delete (int ifindex,
 	g_return_val_if_fail (platform, FALSE);
 	g_return_val_if_fail (klass->ip6_route_delete, FALSE);
 
+	debug ("route: deleting IPv6 route %s/%d, metric=%d", nm_utils_inet6_ntop (&network, NULL), plen, metric);
+
 	if (!nm_platform_ip6_route_exists (ifindex, network, plen, metric)) {
 		debug ("route not found");
 		platform->error = NM_PLATFORM_ERROR_NOT_FOUND;
-- 
1.8.5.3


From c454e02657dc047a3911854a7866a3b4a6628082 Mon Sep 17 00:00:00 2001
From: Thomas Haller <thaller@redhat.com>
Date: Tue, 11 Feb 2014 22:10:05 +0100
Subject: [PATCH 07/14] platform: cleanup object_type_from_nl_object()

- change object_type_from_nl_object() to accept unknown object
  types.
- replace g_assert_not_reached() with g_return_if_fail().

(cherry picked from commit dc54b2e3b2565b9af6478f98e004eaa478809e51)

Signed-off-by: Thomas Haller <thaller@redhat.com>
---
 src/platform/nm-linux-platform.c | 49 +++++++++++++++++++++++++---------------
 1 file changed, 31 insertions(+), 18 deletions(-)

diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index d576436..46df2b8 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -138,12 +138,13 @@ nm_rtnl_addr_set_prefixlen (struct rtnl_addr *rtnladdr, int plen)
 #define rtnl_addr_set_prefixlen nm_rtnl_addr_set_prefixlen
 
 typedef enum {
+	UNKNOWN_OBJECT_TYPE,
 	LINK,
 	IP4_ADDRESS,
 	IP6_ADDRESS,
 	IP4_ROUTE,
 	IP6_ROUTE,
-	N_TYPES
+	N_TYPES,
 } ObjectType;
 
 typedef enum {
@@ -156,9 +157,10 @@ typedef enum {
 static ObjectType
 object_type_from_nl_object (const struct nl_object *object)
 {
-	const char *type_str = nl_object_get_type (object);
+	const char *type_str;
 
-	g_assert (object);
+	if (!object || !(type_str = nl_object_get_type (object)))
+		return UNKNOWN_OBJECT_TYPE;
 
 	if (!strcmp (type_str, "route/link"))
 		return LINK;
@@ -169,7 +171,7 @@ object_type_from_nl_object (const struct nl_object *object)
 		case AF_INET6:
 			return IP6_ADDRESS;
 		default:
-			g_assert_not_reached ();
+			return UNKNOWN_OBJECT_TYPE;
 		}
 	} else if (!strcmp (type_str, "route/route")) {
 		switch (rtnl_route_get_family ((struct rtnl_route *) object)) {
@@ -178,10 +180,10 @@ object_type_from_nl_object (const struct nl_object *object)
 		case AF_INET6:
 			return IP6_ROUTE;
 		default:
-			g_assert_not_reached ();
+			return UNKNOWN_OBJECT_TYPE;
 		}
 	} else
-		g_assert_not_reached ();
+		return UNKNOWN_OBJECT_TYPE;
 }
 
 /* libnl inclues LINK_ATTR_FAMILY in oo_id_attrs of link_obj_ops and thus
@@ -228,7 +230,10 @@ get_kernel_object (struct nl_sock *sock, struct nl_object *needle)
 				return NULL;
 			}
 		}
-	default:
+	case IP4_ADDRESS:
+	case IP6_ADDRESS:
+	case IP4_ROUTE:
+	case IP6_ROUTE:
 		/* Fallback to a one-time cache allocation. */
 		{
 			struct nl_cache *cache;
@@ -244,6 +249,9 @@ get_kernel_object (struct nl_sock *sock, struct nl_object *needle)
 			nl_cache_free (cache);
 			return object;
 		}
+	default:
+		g_return_val_if_reached (NULL);
+		return NULL;
 	}
 }
 
@@ -261,7 +269,8 @@ add_kernel_object (struct nl_sock *sock, struct nl_object *object)
 	case IP6_ROUTE:
 		return rtnl_route_add (sock, (struct rtnl_route *) object, NLM_F_CREATE | NLM_F_REPLACE);
 	default:
-		g_assert_not_reached ();
+		g_return_val_if_reached (-NLE_INVAL);
+		return -NLE_INVAL;
 	}
 }
 
@@ -279,7 +288,8 @@ delete_kernel_object (struct nl_sock *sock, struct nl_object *object)
 	case IP6_ROUTE:
 		return rtnl_route_delete (sock, (struct rtnl_route *) object, 0);
 	default:
-		g_assert_not_reached ();
+		g_return_val_if_reached (-NLE_INVAL);
+		return -NLE_INVAL;
 	}
 }
 
@@ -915,11 +925,11 @@ init_ip6_route (NMPlatformIP6Route *route, struct rtnl_route *rtnlroute)
 /* Object and cache manipulation */
 
 static const char *signal_by_type_and_status[N_TYPES][N_STATUSES] = {
-	{ NM_PLATFORM_LINK_ADDED, NM_PLATFORM_LINK_CHANGED, NM_PLATFORM_LINK_REMOVED },
-	{ NM_PLATFORM_IP4_ADDRESS_ADDED, NM_PLATFORM_IP4_ADDRESS_CHANGED, NM_PLATFORM_IP4_ADDRESS_REMOVED },
-	{ NM_PLATFORM_IP6_ADDRESS_ADDED, NM_PLATFORM_IP6_ADDRESS_CHANGED, NM_PLATFORM_IP6_ADDRESS_REMOVED },
-	{ NM_PLATFORM_IP4_ROUTE_ADDED, NM_PLATFORM_IP4_ROUTE_CHANGED, NM_PLATFORM_IP4_ROUTE_REMOVED },
-	{ NM_PLATFORM_IP6_ROUTE_ADDED, NM_PLATFORM_IP6_ROUTE_CHANGED, NM_PLATFORM_IP6_ROUTE_REMOVED }
+	[LINK]        = { NM_PLATFORM_LINK_ADDED,        NM_PLATFORM_LINK_CHANGED,        NM_PLATFORM_LINK_REMOVED },
+	[IP4_ADDRESS] = { NM_PLATFORM_IP4_ADDRESS_ADDED, NM_PLATFORM_IP4_ADDRESS_CHANGED, NM_PLATFORM_IP4_ADDRESS_REMOVED },
+	[IP6_ADDRESS] = { NM_PLATFORM_IP6_ADDRESS_ADDED, NM_PLATFORM_IP6_ADDRESS_CHANGED, NM_PLATFORM_IP6_ADDRESS_REMOVED },
+	[IP4_ROUTE]   = { NM_PLATFORM_IP4_ROUTE_ADDED,   NM_PLATFORM_IP4_ROUTE_CHANGED,   NM_PLATFORM_IP4_ROUTE_REMOVED },
+	[IP6_ROUTE]   = { NM_PLATFORM_IP6_ROUTE_ADDED,   NM_PLATFORM_IP6_ROUTE_CHANGED,   NM_PLATFORM_IP6_ROUTE_REMOVED }
 };
 
 static struct nl_cache *
@@ -937,7 +947,8 @@ choose_cache (NMPlatform *platform, struct nl_object *object)
 	case IP6_ROUTE:
 		return priv->route_cache;
 	default:
-		g_assert_not_reached ();
+		g_return_val_if_reached (NULL);
+		return NULL;
 	}
 }
 
@@ -1079,7 +1090,7 @@ announce_object (NMPlatform *platform, const struct nl_object *object, ObjectSta
 		}
 		return;
 	default:
-		error ("Announcing object: object type unknown: %d", object_type);
+		g_return_if_reached ();
 	}
 }
 
@@ -1926,7 +1937,8 @@ master_category (NMPlatform *platform, int master)
 	case NM_LINK_TYPE_BOND:
 		return "bonding";
 	default:
-		g_assert_not_reached ();
+		g_return_val_if_reached (NULL);
+		return NULL;
 	}
 }
 
@@ -1944,7 +1956,8 @@ slave_category (NMPlatform *platform, int slave)
 	case NM_LINK_TYPE_BRIDGE:
 		return "brport";
 	default:
-		g_assert_not_reached ();
+		g_return_val_if_reached (NULL);
+		return NULL;
 	}
 }
 
-- 
1.8.5.3


From 8a05d8cdbc6ab5edc33dd0e87b5ebf702ae190f5 Mon Sep 17 00:00:00 2001
From: Thomas Haller <thaller@redhat.com>
Date: Thu, 13 Feb 2014 16:08:36 +0100
Subject: [PATCH 08/14] platform: add function choose_cache_by_type()

(cherry picked from commit a5f3fcae295b2bc9e39cf37b95c7e87a45eec76a)

Signed-off-by: Thomas Haller <thaller@redhat.com>
---
 src/platform/nm-linux-platform.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 46df2b8..5840ecc 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -933,11 +933,11 @@ static const char *signal_by_type_and_status[N_TYPES][N_STATUSES] = {
 };
 
 static struct nl_cache *
-choose_cache (NMPlatform *platform, struct nl_object *object)
+choose_cache_by_type (NMPlatform *platform, ObjectType object_type)
 {
 	NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
 
-	switch (object_type_from_nl_object (object)) {
+	switch (object_type) {
 	case LINK:
 		return priv->link_cache;
 	case IP4_ADDRESS:
@@ -952,6 +952,12 @@ choose_cache (NMPlatform *platform, struct nl_object *object)
 	}
 }
 
+static struct nl_cache *
+choose_cache (NMPlatform *platform, struct nl_object *object)
+{
+	return choose_cache_by_type (platform, object_type_from_nl_object (object));
+}
+
 static gboolean
 object_has_ifindex (struct nl_object *object, int ifindex)
 {
-- 
1.8.5.3


From f4c1c4d338a44e7ee85400e9c663fb3c36ec4ac0 Mon Sep 17 00:00:00 2001
From: Thomas Haller <thaller@redhat.com>
Date: Tue, 11 Feb 2014 20:16:03 +0100
Subject: [PATCH 09/14] platform: fix caching for link types

This bug was present since a long time, however libnl3-v3.2.23
(commit fdd1ba220dd7b780400e9d0652cde80e59f63572) changed the returned
family of bridge link objects, which breaks NetworkManager.

This resulted in error messages such as:

  DBG<4>            object.c:207  nl_object_get: New reference to object 0x19c34b0, total 2
  DBG<5>        route/link.c:895  link_keygen: link 0x19c34b0 key (dev 9 fam 7) keysz 8, hash 0x2b2
  DBG<2>         hashtable.c:127  nl_hash_table_add: Warning: Add to hashtable found duplicate...
  DBG<4>            object.c:221  nl_object_put: Returned object reference 0x19c34b0, 1 remaining
  NetworkManager[17745]: <error> [1392114373.475432] [platform/nm-linux-platform.c:1328] event_notification(): netlink cache error: Object exists

Even before the change of libnl, I saw the following error lines
 <debug> [...] [platform/nm-linux-platform.c:1216] event_notification(): netlink event (type 16) for link: virbr0 (4)
 <error> [...] [platform/nm-linux-platform.c:1265] event_notification(): netlink cache error: Object exists
Hence, the caching mechanism for libnl objects already had a bug.

For rtnl link objects, the identifier consists of family and ifindex.
Since in upper layers, we don't easily know the family, we need a way to find
the objects inside the cache. We do this, by only caching links of family
AF_UNSPEC.

Objects that we receive via event_notification() are never cached. They are only used
to trigger refetching the kernel_object. Their family is irrelevant, we
only need to know, that something about this ifindex changed.

For objects retrieved via get_kernel_object(), we only get link objects of
family AF_UNSPEC or AF_BRIDGE. In any case, we reset (coerce) their family
before caching. This way, inside the link cache, there are only objects with
(coerced) family AF_UNSPEC. We loose the information, which family the
link had, however we don't need it anyway.

https://bugzilla.gnome.org/show_bug.cgi?id=719905
https://bugzilla.redhat.com/show_bug.cgi?id=1063290

Duplicates:
https://bugzilla.gnome.org/show_bug.cgi?id=724225
https://bugzilla.redhat.com/show_bug.cgi?id=1063800

(cherry picked from commit a6f92665555c39dd609db42b4c350b1691149d17)

Signed-off-by: Thomas Haller <thaller@redhat.com>
---
 src/platform/nm-linux-platform.c | 52 ++++++++++++++++++++++++++++------------
 1 file changed, 37 insertions(+), 15 deletions(-)

diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 5840ecc..d56cf0d 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -186,26 +186,47 @@ object_type_from_nl_object (const struct nl_object *object)
 		return UNKNOWN_OBJECT_TYPE;
 }
 
-/* libnl inclues LINK_ATTR_FAMILY in oo_id_attrs of link_obj_ops and thus
- * refuses to search for items that lack this attribute. I believe this is a
- * bug or a bad design at the least. Address family is not an identifying
- * attribute of a network interface and IMO is not an attribute of a network
- * interface at all.
- */
+static void
+_nl_link_family_unset (struct nl_object *obj, int *family)
+{
+	if (!obj || object_type_from_nl_object (obj) != LINK)
+		*family = AF_UNSPEC;
+	else {
+		*family = rtnl_link_get_family ((struct rtnl_link *) obj);
+
+		/* Always explicitly set the family to AF_UNSPEC, even if rtnl_link_get_family() might
+		 * already return %AF_UNSPEC. The reason is, that %AF_UNSPEC is the default family
+		 * and libnl nl_object_identical() function will only succeed, if the family is
+		 * explicitly set (which we cannot be sure, unless setting it). */
+		rtnl_link_set_family ((struct rtnl_link *) obj, AF_UNSPEC);
+	}
+}
+
+/* In our link cache, we coerce the family of all link objects to AF_UNSPEC.
+ * Thus, before searching for an object, we fixup @needle to have the right
+ * id (by resetting the family). */
 static struct nl_object *
 nm_nl_cache_search (struct nl_cache *cache, struct nl_object *needle)
 {
-	if (object_type_from_nl_object (needle) == LINK)
-		rtnl_link_set_family ((struct rtnl_link *) needle, AF_UNSPEC);
+	int family;
+	struct nl_object *obj;
+
+	_nl_link_family_unset (needle, &family);
+	obj = nl_cache_search (cache, needle);
+	if (family != AF_UNSPEC) {
+		/* restore the family of the @needle instance. If the family was
+		 * unset before, we cannot make it unset again. Thus, in that case
+		 * we cannot undo _nl_link_family_unset() entirely. */
+		rtnl_link_set_family ((struct rtnl_link *) needle, family);
+	}
 
-	return nl_cache_search (cache, needle);
+	return obj;
 }
-#define nl_cache_search nm_nl_cache_search
 
 /* Ask the kernel for an object identical (as in nl_cache_identical) to the
  * needle argument. This is a kernel counterpart for nl_cache_search.
  *
- * libnl 3.2 doesn't seem to provide such functionality.
+ * The returned object must be freed by the caller with nl_object_put().
  */
 static struct nl_object *
 get_kernel_object (struct nl_sock *sock, struct nl_object *needle)
@@ -222,6 +243,7 @@ get_kernel_object (struct nl_sock *sock, struct nl_object *needle)
 			nle = rtnl_link_get_kernel (sock, ifindex, name, (struct rtnl_link **) &kernel_object);
 			switch (nle) {
 			case -NLE_SUCCESS:
+				_nl_link_family_unset (kernel_object, &nle);
 				return kernel_object;
 			case -NLE_NODEV:
 				return NULL;
@@ -1112,7 +1134,7 @@ refresh_object (NMPlatform *platform, struct nl_object *object, gboolean removed
 	int nle;
 
 	cache = choose_cache (platform, object);
-	cached_object = nl_cache_search (choose_cache (platform, object), object);
+	cached_object = nm_nl_cache_search (cache, object);
 	kernel_object = get_kernel_object (priv->nlh, object);
 
 	if (removed) {
@@ -1203,7 +1225,7 @@ delete_object (NMPlatform *platform, struct nl_object *obj)
 	 * for delete_kernel_object() and we need to search the cache first. If
 	 * that problem is fixed, we can use 'object' directly.
 	 */
-	cached_object = nl_cache_search (choose_cache (platform, object), object);
+	cached_object = nm_nl_cache_search (choose_cache (platform, object), object);
 	g_return_val_if_fail (cached_object, FALSE);
 
 	nle = delete_kernel_object (priv->nlh, cached_object);
@@ -1265,7 +1287,7 @@ event_notification (struct nl_msg *msg, gpointer user_data)
 	g_return_val_if_fail (object, NL_OK);
 
 	cache = choose_cache (platform, object);
-	cached_object = nl_cache_search (cache, object);
+	cached_object = nm_nl_cache_search (cache, object);
 	kernel_object = get_kernel_object (priv->nlh, object);
 
 	debug ("netlink event (type %d)", event);
@@ -1294,7 +1316,7 @@ event_notification (struct nl_msg *msg, gpointer user_data)
 		 * already removed and announced.
 		 */
 		if (event == RTM_DELLINK) {
-			if (!link_is_announceable (platform, (struct rtnl_link *) object))
+			if (!link_is_announceable (platform, (struct rtnl_link *) cached_object))
 				return NL_OK;
 		}
 		announce_object (platform, cached_object, REMOVED, NM_PLATFORM_REASON_EXTERNAL);
-- 
1.8.5.3


From 6f25528e819eee37842589cdd9b571ea2813177e Mon Sep 17 00:00:00 2001
From: Thomas Haller <thaller@redhat.com>
Date: Tue, 11 Feb 2014 20:12:12 +0100
Subject: [PATCH 10/14] platform: log the link family in event_notification()
 and get_kernel_object()

(cherry picked from commit ebbd6575ffc78f500062303fe18ecb908b2e29ea)

Signed-off-by: Thomas Haller <thaller@redhat.com>
---
 src/platform/nm-linux-platform.c | 51 ++++++++++++++++++++++++++++++++--------
 1 file changed, 41 insertions(+), 10 deletions(-)

diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index d56cf0d..741c4c8 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -231,24 +231,36 @@ nm_nl_cache_search (struct nl_cache *cache, struct nl_object *needle)
 static struct nl_object *
 get_kernel_object (struct nl_sock *sock, struct nl_object *needle)
 {
+	struct nl_object *object = NULL;
+	ObjectType type = object_type_from_nl_object (needle);
 
-	switch (object_type_from_nl_object (needle)) {
+	switch (type) {
 	case LINK:
 		{
-			struct nl_object *kernel_object;
 			int ifindex = rtnl_link_get_ifindex ((struct rtnl_link *) needle);
 			const char *name = rtnl_link_get_name ((struct rtnl_link *) needle);
 			int nle;
 
-			nle = rtnl_link_get_kernel (sock, ifindex, name, (struct rtnl_link **) &kernel_object);
+			nle = rtnl_link_get_kernel (sock, ifindex, name, (struct rtnl_link **) &object);
 			switch (nle) {
 			case -NLE_SUCCESS:
-				_nl_link_family_unset (kernel_object, &nle);
-				return kernel_object;
+				if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) {
+					name = rtnl_link_get_name ((struct rtnl_link *) object);
+					debug ("get_kernel_object for link: %s (%d, family %d)",
+					       name ? name : "(unknown)",
+					       rtnl_link_get_ifindex ((struct rtnl_link *) object),
+					       rtnl_link_get_family ((struct rtnl_link *) object));
+				}
+
+				_nl_link_family_unset (object, &nle);
+				return object;
 			case -NLE_NODEV:
+				debug ("get_kernel_object for link %s (%d) had no result",
+				       name ? name : "(unknown)", ifindex);
 				return NULL;
 			default:
-				error ("Netlink error: %s", nl_geterror (nle));
+				error ("get_kernel_object for link %s (%d) failed: %s (%d)",
+				       name ? name : "(unknown)", ifindex, nl_geterror (nle), nle);
 				return NULL;
 			}
 		}
@@ -259,16 +271,25 @@ get_kernel_object (struct nl_sock *sock, struct nl_object *needle)
 		/* Fallback to a one-time cache allocation. */
 		{
 			struct nl_cache *cache;
-			struct nl_object *object;
 			int nle;
 
 			nle = nl_cache_alloc_and_fill (
 					nl_cache_ops_lookup (nl_object_get_type (needle)),
 					sock, &cache);
-			g_return_val_if_fail (!nle, NULL);
+			if (nle) {
+				error ("get_kernel_object for type %d failed: %s (%d)",
+				       type, nl_geterror (nle), nle);
+				return NULL;
+			}
+
 			object = nl_cache_search (cache, needle);
 
 			nl_cache_free (cache);
+
+			if (object)
+				debug ("get_kernel_object for type %d returned %p", type, object);
+			else
+				debug ("get_kernel_object for type %d had no result", type);
 			return object;
 		}
 	default:
@@ -1286,12 +1307,22 @@ event_notification (struct nl_msg *msg, gpointer user_data)
 	nl_msg_parse (msg, ref_object, &object);
 	g_return_val_if_fail (object, NL_OK);
 
+	if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) {
+		if (object_type_from_nl_object (object) == LINK) {
+			const char *name = rtnl_link_get_name ((struct rtnl_link *) object);
+
+			debug ("netlink event (type %d) for link: %s (%d, family %d)",
+			       event, name ? name : "(unknown)",
+			       rtnl_link_get_ifindex ((struct rtnl_link *) object),
+			       rtnl_link_get_family ((struct rtnl_link *) object));
+		} else
+			debug ("netlink event (type %d)", event);
+	}
+
 	cache = choose_cache (platform, object);
 	cached_object = nm_nl_cache_search (cache, object);
 	kernel_object = get_kernel_object (priv->nlh, object);
 
-	debug ("netlink event (type %d)", event);
-
 	hack_empty_master_iff_lower_up (platform, kernel_object);
 
 	/* Removed object */
-- 
1.8.5.3


From fcd17881078a96baadb5b03f17fe045e289b4daa Mon Sep 17 00:00:00 2001
From: Thomas Haller <thaller@redhat.com>
Date: Thu, 13 Feb 2014 18:12:41 +0100
Subject: [PATCH 11/14] core: add function
 nm_utils_ip6_address_clear_host_address()

(cherry picked from commit e8775dd9fc7b4867b2a541a163d14c630bf1085b)

Signed-off-by: Thomas Haller <thaller@redhat.com>
---
 src/NetworkManagerUtils.c   | 44 ++++++++++++++++++++++++++++
 src/NetworkManagerUtils.h   |  3 ++
 src/rdisc/nm-lndp-rdisc.c   | 28 ++----------------
 src/rdisc/tests/Makefile.am | 22 +++++++++-----
 src/tests/test-general.c    | 71 +++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 136 insertions(+), 32 deletions(-)

diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
index bac5322..6fdb3bd 100644
--- a/src/NetworkManagerUtils.c
+++ b/src/NetworkManagerUtils.c
@@ -74,6 +74,50 @@ nm_ethernet_address_is_valid (const struct ether_addr *test_addr)
 }
 
 
+/* nm_utils_ip4_address_clear_host_address:
+ * @addr: source ip6 address
+ * @plen: prefix length of network
+ *
+ * returns: the input address, with the host address set to 0.
+ */
+in_addr_t
+nm_utils_ip4_address_clear_host_address (in_addr_t addr, guint8 plen)
+{
+	return addr & nm_utils_ip4_prefix_to_netmask (plen);
+}
+
+	/* nm_utils_ip6_address_clear_host_address:
+ * @dst: destination output buffer, will contain the network part of the @src address
+ * @src: source ip6 address
+ * @plen: prefix length of network
+ *
+ * Note: this function is self assignment save, to update @src inplace, set both
+ * @dst and @src to the same destination.
+ */
+void
+nm_utils_ip6_address_clear_host_address (struct in6_addr *dst, const struct in6_addr *src, guint8 plen)
+{
+	g_return_if_fail (plen <= 128);
+	g_return_if_fail (src);
+	g_return_if_fail (dst);
+
+	if (plen < 128) {
+		guint nbytes = plen / 8;
+		guint nbits = plen % 8;
+
+		if (nbytes && dst != src)
+			memcpy (dst, src, nbytes);
+		if (nbits) {
+			dst->s6_addr[nbytes] = (src->s6_addr[nbytes] & (0xFF << (8 - nbits)));
+			nbytes++;
+		}
+		if (nbytes <= 15)
+			memset (&dst->s6_addr[nbytes], 0, 16 - nbytes);
+	} else if (src != dst)
+		*dst = *src;
+}
+
+
 int
 nm_spawn_process (const char *args)
 {
diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h
index a15f74f..c39d512 100644
--- a/src/NetworkManagerUtils.h
+++ b/src/NetworkManagerUtils.h
@@ -34,6 +34,9 @@
 
 gboolean nm_ethernet_address_is_valid (const struct ether_addr *test_addr);
 
+in_addr_t nm_utils_ip4_address_clear_host_address (in_addr_t addr, guint8 plen);
+void nm_utils_ip6_address_clear_host_address (struct in6_addr *dst, const struct in6_addr *src, guint8 plen);
+
 int nm_spawn_process (const char *args);
 
 gboolean nm_match_spec_string (const GSList *specs, const char *string);
diff --git a/src/rdisc/nm-lndp-rdisc.c b/src/rdisc/nm-lndp-rdisc.c
index c328f99..7d61b59 100644
--- a/src/rdisc/nm-lndp-rdisc.c
+++ b/src/rdisc/nm-lndp-rdisc.c
@@ -26,6 +26,7 @@
 
 #include "nm-lndp-rdisc.h"
 
+#include "NetworkManagerUtils.h"
 #include "nm-logging.h"
 
 #define debug(...) nm_log_dbg (LOGD_IP6, __VA_ARGS__)
@@ -437,29 +438,6 @@ fill_address_from_mac (struct in6_addr *address, const char *mac)
 	memcpy (identifier + 5, mac + 3, 3);
 }
 
-/* Ensure the given address is masked with its prefix and that all host
- * bits are set to zero.  Some IPv6 router advertisement daemons (eg, radvd)
- * don't enforce this in their configuration.
- */
-static void
-set_address_masked (struct in6_addr *dst, struct in6_addr *src, guint8 plen)
-{
-	guint nbytes = plen / 8;
-	guint nbits = plen % 8;
-
-	g_return_if_fail (plen <= 128);
-	g_assert (src);
-	g_assert (dst);
-
-	if (plen >= 128)
-		*dst = *src;
-	else {
-		memset (dst, 0, sizeof (*dst));
-		memcpy (dst, src, nbytes);
-		dst->s6_addr[nbytes] = (src->s6_addr[nbytes] & (0xFF << (8 - nbits)));
-	}
-}
-
 static int
 receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
 {
@@ -535,7 +513,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
 		/* Device route */
 		memset (&route, 0, sizeof (route));
 		route.plen = ndp_msg_opt_prefix_len (msg, offset);
-		set_address_masked (&route.network, ndp_msg_opt_prefix (msg, offset), route.plen);
+		nm_utils_ip6_address_clear_host_address (&route.network, ndp_msg_opt_prefix (msg, offset), route.plen);
 		route.timestamp = now;
 		if (ndp_msg_opt_prefix_flag_on_link (msg, offset)) {
 			route.lifetime = ndp_msg_opt_prefix_valid_time (msg, offset);
@@ -566,7 +544,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
 		memset (&route, 0, sizeof (route));
 		route.gateway = gateway.address;
 		route.plen = ndp_msg_opt_route_prefix_len (msg, offset);
-		set_address_masked (&route.network, ndp_msg_opt_route_prefix (msg, offset), route.plen);
+		nm_utils_ip6_address_clear_host_address (&route.network, ndp_msg_opt_route_prefix (msg, offset), route.plen);
 		route.timestamp = now;
 		route.lifetime = ndp_msg_opt_route_lifetime (msg, offset);
 		route.preference = translate_preference (ndp_msg_opt_route_preference (msg, offset));
diff --git a/src/rdisc/tests/Makefile.am b/src/rdisc/tests/Makefile.am
index 7308cfe..9d21284 100644
--- a/src/rdisc/tests/Makefile.am
+++ b/src/rdisc/tests/Makefile.am
@@ -1,15 +1,24 @@
 AM_CPPFLAGS = \
 	-I${top_srcdir} \
+	-I$(top_srcdir)/include \
 	-I${top_srcdir}/src \
+	-I${top_srcdir}/src/devices \
 	-I${top_srcdir}/src/logging \
+	-I${top_srcdir}/src/platform \
+	-I${top_srcdir}/src/posix-signals \
 	-I${top_srcdir}/libnm-util \
 	-I${srcdir}/.. \
 	$(GLIB_CFLAGS) \
+	$(DBUS_CFLAGS) \
+	$(POLKIT_CFLAGS) \
 	$(LIBNL_CFLAGS) \
 	$(LIBNDP_CFLAGS)
 
 AM_CFLAGS = $(CODE_COVERAGE_CFLAGS)
-AM_LDFLAGS = $(GLIB_LIBS) $(CODE_COVERAGE_LDFLAGS)
+AM_LDFLAGS = \
+	$(GLIB_LIBS) \
+	$(DBUS_LIBS) \
+	$(CODE_COVERAGE_LDFLAGS)
 
 @GNOME_CODE_COVERAGE_RULES@
 
@@ -17,9 +26,8 @@ noinst_PROGRAMS = \
 	rdisc
 
 rdisc_SOURCES = \
-	rdisc.c \
-	../nm-rdisc.c \
-	../nm-fake-rdisc.c \
-	../nm-lndp-rdisc.c \
-	../../logging/nm-logging.c
-rdisc_LDADD = $(LIBNDP_LIBS)
+	rdisc.c
+rdisc_LDADD = \
+	$(top_builddir)/src/libNetworkManager.la \
+	$(LIBNDP_LIBS)
+
diff --git a/src/tests/test-general.c b/src/tests/test-general.c
index 649653c..3fd7115 100644
--- a/src/tests/test-general.c
+++ b/src/tests/test-general.c
@@ -60,6 +60,76 @@ test_nm_utils_ascii_str_to_int64 (void)
 	test_nm_utils_ascii_str_to_int64_do ("\r\n\t10000\t\n\t\n", 10, 0, 10000, -1, 0, 10000);
 }
 
+/* Reference implementation for nm_utils_ip6_address_clear_host_address.
+ * Taken originally from set_address_masked(), src/rdisc/nm-lndp-rdisc.c
+ **/
+static void
+ip6_address_clear_host_address_reference (struct in6_addr *dst, struct in6_addr *src, guint8 plen)
+{
+	guint nbytes = plen / 8;
+	guint nbits = plen % 8;
+
+	g_return_if_fail (plen <= 128);
+	g_assert (src);
+	g_assert (dst);
+
+	if (plen >= 128)
+		*dst = *src;
+	else {
+		memset (dst, 0, sizeof (*dst));
+		memcpy (dst, src, nbytes);
+		dst->s6_addr[nbytes] = (src->s6_addr[nbytes] & (0xFF << (8 - nbits)));
+	}
+}
+
+static void
+_randomize_in6_addr (struct in6_addr *addr, GRand *rand)
+{
+	int i;
+
+	for (i=0; i < 4; i++)
+		((guint32 *)addr)[i] = g_rand_int (rand);
+}
+
+static void
+test_nm_utils_ip6_address_clear_host_address (void)
+{
+	GRand *rand = g_rand_new ();
+	int plen, i;
+
+	g_rand_set_seed (rand, 0);
+
+	for (plen = 0; plen <= 128; plen++) {
+		for (i =0; i<50; i++) {
+			struct in6_addr addr_src, addr_ref;
+			struct in6_addr addr1, addr2;
+
+			_randomize_in6_addr (&addr_src, rand);
+			_randomize_in6_addr (&addr_ref, rand);
+			_randomize_in6_addr (&addr1, rand);
+			_randomize_in6_addr (&addr2, rand);
+
+			addr1 = addr_src;
+			ip6_address_clear_host_address_reference (&addr_ref, &addr1, plen);
+
+			_randomize_in6_addr (&addr1, rand);
+			_randomize_in6_addr (&addr2, rand);
+			addr1 = addr_src;
+			nm_utils_ip6_address_clear_host_address (&addr2, &addr1, plen);
+			g_assert_cmpint (memcmp (&addr1, &addr_src, sizeof (struct in6_addr)), ==, 0);
+			g_assert_cmpint (memcmp (&addr2, &addr_ref, sizeof (struct in6_addr)), ==, 0);
+
+			/* test for self assignment/inplace update. */
+			_randomize_in6_addr (&addr1, rand);
+			addr1 = addr_src;
+			nm_utils_ip6_address_clear_host_address (&addr1, &addr1, plen);
+			g_assert_cmpint (memcmp (&addr1, &addr_ref, sizeof (struct in6_addr)), ==, 0);
+		}
+	}
+
+	g_rand_free (rand);
+}
+
 /*******************************************/
 
 int
@@ -70,6 +140,7 @@ main (int argc, char **argv)
 	g_type_init ();
 
 	g_test_add_func ("/general/nm_utils_ascii_str_to_int64", test_nm_utils_ascii_str_to_int64);
+	g_test_add_func ("/general/nm_utils_ip6_address_clear_host_address", test_nm_utils_ip6_address_clear_host_address);
 
 	return g_test_run ();
 }
-- 
1.8.5.3


From b4e59bb6bac473414bfcf90a6acb48d70d128423 Mon Sep 17 00:00:00 2001
From: Thomas Haller <thaller@redhat.com>
Date: Thu, 13 Feb 2014 19:47:04 +0100
Subject: [PATCH 12/14] platform: clear host identifier before adding a route

Adding IPv4 routes, with a non-zero host identifer fails with an
error message. Adding IPv6 addresses, does not return an error,
but it seems to have no effect.

Thus we have to make sure that the host part of routes
is always zero.

(cherry picked from commit d6add4de5c5ae934a355bb72a14ab4d5d4b2472f)

Signed-off-by: Thomas Haller <thaller@redhat.com>
---
 src/platform/nm-linux-platform.c | 31 +++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 741c4c8..87663d2 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -43,6 +43,7 @@
 #include <netlink/route/route.h>
 #include <gudev/gudev.h>
 
+#include "NetworkManagerUtils.h"
 #include "nm-linux-platform.h"
 #include "nm-logging.h"
 #include "wifi/wifi-utils.h"
@@ -2543,16 +2544,42 @@ ip6_route_get_all (NMPlatform *platform, int ifindex, gboolean include_default)
 	return routes;
 }
 
+static void
+clear_host_address (int family, const void *network, int plen, void *dst)
+{
+	g_return_if_fail (plen == (guint8)plen);
+	g_return_if_fail (network);
+
+	switch (family) {
+	case AF_INET:
+		*((in_addr_t *) dst) = nm_utils_ip4_address_clear_host_address (*((in_addr_t *) network), plen);
+		break;
+	case AF_INET6:
+		nm_utils_ip6_address_clear_host_address ((struct in6_addr *) dst, (const struct in6_addr *) network, plen);
+		break;
+	default:
+		g_assert_not_reached ();
+	}
+}
+
 static struct nl_object *
 build_rtnl_route (int family, int ifindex, gconstpointer network, int plen, gconstpointer gateway, int metric, int mss)
 {
+	guint32 network_clean[4];
 	struct rtnl_route *rtnlroute = rtnl_route_alloc ();
 	struct rtnl_nexthop *nexthop = rtnl_route_nh_alloc ();
 	int addrlen = (family == AF_INET) ? sizeof (in_addr_t) : sizeof (struct in6_addr);
 	/* Workaround a libnl bug by using zero destination address length for default routes */
-	auto_nl_addr struct nl_addr *dst = nl_addr_build (family, network, plen ? addrlen : 0);
+	auto_nl_addr struct nl_addr *dst = NULL;
 	auto_nl_addr struct nl_addr *gw = gateway ? nl_addr_build (family, gateway, addrlen) : NULL;
 
+	/* There seem to be problems adding a route with non-zero host identifier.
+	 * Adding IPv6 routes is simply ignored, without error message.
+	 * In the IPv4 case, we got an error. Thus, we have to make sure, that
+	 * the address is sane. */
+	clear_host_address (family, network, plen, network_clean);
+	dst = nl_addr_build (family, network_clean, plen ? addrlen : 0);
+
 	g_assert (rtnlroute && dst && nexthop);
 
 	nl_addr_set_prefixlen (dst, plen);
@@ -2596,7 +2623,7 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, int plen
 static gboolean
 ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, int metric)
 {
-	struct in6_addr gateway = in6addr_any;
+	struct in6_addr gateway = IN6ADDR_ANY_INIT;
 
 	return delete_object (platform, build_rtnl_route (AF_INET6, ifindex, &network, plen, &gateway, metric, 0));
 }
-- 
1.8.5.3


From 0e49022c606fd7ed317f43e5d90ea8a62619234b Mon Sep 17 00:00:00 2001
From: Thomas Haller <thaller@redhat.com>
Date: Thu, 13 Feb 2014 15:11:05 +0100
Subject: [PATCH 13/14] platform: refactor delete_object() and allow deletion
 of objects that are not cached

- refactor delete_object() by merging with delete_kernel_object()

- allow deletion of object that we cannot find in the cache
  currently. The kernel might have such an address, even if we don't
  have it currently cached. In this case, fall back to @obj.

  Also try to work around an issue, that we cannot delete an IPv4 route without
  knowing its scope.

- suppress logging error message for NLE_NOADDR, which is a common
  failure when deleting an address. But at the same time, add some more
  debug logging, for NLE_NOADDR and NLE_OBJ_NOTFOUND.

(cherry picked from commit 5f5c7284d16c5f24200bbbd40c5e9a83f84516cd)

Signed-off-by: Thomas Haller <thaller@redhat.com>
---
 src/platform/nm-linux-platform.c | 88 ++++++++++++++++++++++++++--------------
 1 file changed, 57 insertions(+), 31 deletions(-)

diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 87663d2..df1b33a 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -318,25 +318,6 @@ add_kernel_object (struct nl_sock *sock, struct nl_object *object)
 	}
 }
 
-/* libnl 3.2 doesn't seem to provide such a generic way to delete libnl-route objects. */
-static int
-delete_kernel_object (struct nl_sock *sock, struct nl_object *object)
-{
-	switch (object_type_from_nl_object (object)) {
-	case LINK:
-		return rtnl_link_delete (sock, (struct rtnl_link *) object);
-	case IP4_ADDRESS:
-	case IP6_ADDRESS:
-		return rtnl_addr_delete (sock, (struct rtnl_addr *) object, 0);
-	case IP4_ROUTE:
-	case IP6_ROUTE:
-		return rtnl_route_delete (sock, (struct rtnl_route *) object, 0);
-	default:
-		g_return_val_if_reached (-NLE_INVAL);
-		return -NLE_INVAL;
-	}
-}
-
 /* nm_rtnl_link_parse_info_data(): Re-fetches a link from the kernel
  * and parses its IFLA_INFO_DATA using a caller-provided parser.
  *
@@ -1215,6 +1196,8 @@ add_object (NMPlatform *platform, struct nl_object *obj)
 		.dp_fd = stderr,
 	};
 
+	g_return_val_if_fail (object, FALSE);
+
 	nle = add_kernel_object (priv->nlh, object);
 
 	/* NLE_EXIST is considered equivalent to success to avoid race conditions. You
@@ -1239,26 +1222,48 @@ static gboolean
 delete_object (NMPlatform *platform, struct nl_object *obj)
 {
 	NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
-	auto_nl_object struct nl_object *object = obj;
+	auto_nl_object struct nl_object *obj_cleanup = obj;
 	auto_nl_object struct nl_object *cached_object = NULL;
+	struct nl_object *object;
+	int object_type;
 	int nle;
 
-	/* FIXME: For some reason the result of build_rtnl_route() is not suitable
-	 * for delete_kernel_object() and we need to search the cache first. If
-	 * that problem is fixed, we can use 'object' directly.
-	 */
-	cached_object = nm_nl_cache_search (choose_cache (platform, object), object);
-	g_return_val_if_fail (cached_object, FALSE);
+	object_type = object_type_from_nl_object (obj);
+	g_return_val_if_fail (object_type != UNKNOWN_OBJECT_TYPE, FALSE);
 
-	nle = delete_kernel_object (priv->nlh, cached_object);
+	cached_object = nm_nl_cache_search (choose_cache_by_type (platform, object_type), obj);
+	object = cached_object ? cached_object : obj;
+
+	switch (object_type) {
+	case LINK:
+		nle = rtnl_link_delete (priv->nlh, (struct rtnl_link *) object);
+		break;
+	case IP4_ADDRESS:
+	case IP6_ADDRESS:
+		nle = rtnl_addr_delete (priv->nlh, (struct rtnl_addr *) object, 0);
+		break;
+	case IP4_ROUTE:
+	case IP6_ROUTE:
+		nle = rtnl_route_delete (priv->nlh, (struct rtnl_route *) object, 0);
+		break;
+	default:
+		g_assert_not_reached ();
+	}
 
-	/* NLE_OBJ_NOTFOUND is considered equivalent to success to avoid race conditions. You
-	 * never know when something deletes the same object just before NetworkManager.
-	 */
 	switch (nle) {
 	case -NLE_SUCCESS:
+		break;
 	case -NLE_OBJ_NOTFOUND:
+		debug("delete_object failed with \"%s\" (%d), meaning the object was already removed",
+		      nl_geterror (nle), nle);
 		break;
+	case -NLE_NOADDR:
+		if (object_type == IP4_ADDRESS || object_type == IP6_ADDRESS) {
+			debug("delete_object for address failed with \"%s\" (%d), meaning the address was already removed",
+			      nl_geterror (nle), nle);
+			break;
+		}
+		/* fall-through to error, because we only expect this for addresses. */
 	default:
 		error ("Netlink error: %s", nl_geterror (nle));
 		return FALSE;
@@ -2588,6 +2593,7 @@ build_rtnl_route (int family, int ifindex, gconstpointer network, int plen, gcon
 	rtnl_route_set_tos (rtnlroute, 0);
 	rtnl_route_set_dst (rtnlroute, dst);
 	rtnl_route_set_priority (rtnlroute, metric);
+	rtnl_route_set_family (rtnlroute, family);
 
 	rtnl_route_nh_set_ifindex (nexthop, ifindex);
 	if (gw && !nl_addr_iszero (gw))
@@ -2616,8 +2622,28 @@ static gboolean
 ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, int plen, int metric)
 {
 	in_addr_t gateway = 0;
+	struct nl_object *route = build_rtnl_route (AF_INET, ifindex, &network, plen, &gateway, metric, 0);
+
+	g_return_val_if_fail (route, FALSE);
+
+	/* When searching for a matching IPv4 route to delete, the kernel
+	 * searches for a matching scope, unless the RTM_DELROUTE message
+	 * specifies RT_SCOPE_NOWHERE (see fib_table_delete()).
+	 *
+	 * However, if we set the scope of @rtnlroute to RT_SCOPE_NOWHERE (or
+	 * leave it unset), rtnl_route_build_msg() will reset the scope to
+	 * rtnl_route_guess_scope() -- which might be the wrong scope.
+	 *
+	 * As a workaround, we set the scope to RT_SCOPE_UNIVERSE, so libnl
+	 * will not overwrite it. But this only works if we guess correctly.
+	 *
+	 * As a better workaround, we don't use @rtnlroute as argument for
+	 * rtnl_route_delete(), but we look into our cache, if we already have
+	 * this route ready.
+	 **/
+	rtnl_route_set_scope ((struct rtnl_route *) route, RT_SCOPE_UNIVERSE);
 
-	return delete_object (platform, build_rtnl_route (AF_INET, ifindex, &network, plen, &gateway, metric, 0));
+	return delete_object (platform, route);
 }
 
 static gboolean
-- 
1.8.5.3


From abf58e4ace3cf6a7000d26155aa90c0c143135cf Mon Sep 17 00:00:00 2001
From: Thomas Haller <thaller@redhat.com>
Date: Thu, 13 Feb 2014 14:56:38 +0100
Subject: [PATCH 14/14] platform: do not check for _exists() before deleting
 addresses and routes

Before, nm_platform_ip4_address_exists(), et al. look into the cache to see
whether the address/route already exists and returned an error if it
did.

Change the semantic of the delete functions, to return success in case of
"nothing to delete". Also always try to delete the object in the
kernel. The reason is, that the cache might be out of date and the
caller really wants to delete it. So, to be sure, we always delete.

In most cases the object is actually in the cache (because that is
how the caller came to know that such an object might exist).
In those cases, the lookup was not useful either, because the object
was actually cached.

(cherry picked from commit 2bc90a5f2d3dabc84a6ce3a8eb6a0e2582c1c9f2)

Signed-off-by: Thomas Haller <thaller@redhat.com>
---
 src/platform/nm-fake-platform.c   | 24 ++++++++++++------------
 src/platform/nm-platform.c        | 28 ----------------------------
 src/platform/tests/test-address.c |  8 ++++----
 src/platform/tests/test-route.c   |  8 ++++----
 4 files changed, 20 insertions(+), 48 deletions(-)

diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c
index dcbf932..803015c 100644
--- a/src/platform/nm-fake-platform.c
+++ b/src/platform/nm-fake-platform.c
@@ -836,7 +836,7 @@ ip4_address_delete (NMPlatform *platform, int ifindex, in_addr_t addr, int plen)
 		}
 	}
 
-	g_assert_not_reached ();
+	return TRUE;
 }
 
 static gboolean
@@ -859,7 +859,7 @@ ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, int
 		}
 	}
 
-	g_assert_not_reached ();
+	return TRUE;
 }
 
 static gboolean
@@ -1073,11 +1073,11 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, int plen
 	NMPlatformIP4Route *route = ip4_route_get (platform, ifindex, network, plen, metric);
 	NMPlatformIP4Route deleted_route;
 
-	g_assert (route);
-
-	memcpy (&deleted_route, route, sizeof (deleted_route));
-	memset (route, 0, sizeof (*route));
-	g_signal_emit_by_name (platform, NM_PLATFORM_IP4_ROUTE_REMOVED, ifindex, &deleted_route, NM_PLATFORM_REASON_INTERNAL);
+	if (route) {
+		memcpy (&deleted_route, route, sizeof (deleted_route));
+		memset (route, 0, sizeof (*route));
+		g_signal_emit_by_name (platform, NM_PLATFORM_IP4_ROUTE_REMOVED, ifindex, &deleted_route, NM_PLATFORM_REASON_INTERNAL);
+	}
 
 	return TRUE;
 }
@@ -1088,11 +1088,11 @@ ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, in
 	NMPlatformIP6Route *route = ip6_route_get (platform, ifindex, network, plen, metric);
 	NMPlatformIP6Route deleted_route;
 
-	g_assert (route);
-
-	memcpy (&deleted_route, route, sizeof (deleted_route));
-	memset (route, 0, sizeof (*route));
-	g_signal_emit_by_name (platform, NM_PLATFORM_IP6_ROUTE_REMOVED, ifindex, &deleted_route, NM_PLATFORM_REASON_INTERNAL);
+	if (route) {
+		memcpy (&deleted_route, route, sizeof (deleted_route));
+		memset (route, 0, sizeof (*route));
+		g_signal_emit_by_name (platform, NM_PLATFORM_IP6_ROUTE_REMOVED, ifindex, &deleted_route, NM_PLATFORM_REASON_INTERNAL);
+	}
 
 	return TRUE;
 }
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index 7de8db4..87a7ef9 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -1228,13 +1228,6 @@ nm_platform_ip4_address_delete (int ifindex, in_addr_t address, int plen)
 	g_return_val_if_fail (klass->ip4_address_delete, FALSE);
 
 	debug ("address: deleting IPv4 address %s/%d", nm_utils_inet4_ntop (address, NULL), plen);
-
-	if (!nm_platform_ip4_address_exists (ifindex, address, plen)) {
-		debug ("address doesn't exists");
-		platform->error = NM_PLATFORM_ERROR_NOT_FOUND;
-		return FALSE;
-	}
-
 	return klass->ip4_address_delete (platform, ifindex, address, plen);
 }
 
@@ -1248,13 +1241,6 @@ nm_platform_ip6_address_delete (int ifindex, struct in6_addr address, int plen)
 	g_return_val_if_fail (klass->ip6_address_delete, FALSE);
 
 	debug ("address: deleting IPv6 address %s/%d", nm_utils_inet6_ntop (&address, NULL), plen);
-
-	if (!nm_platform_ip6_address_exists (ifindex, address, plen)) {
-		debug ("address doesn't exists");
-		platform->error = NM_PLATFORM_ERROR_NOT_FOUND;
-		return FALSE;
-	}
-
 	return klass->ip6_address_delete (platform, ifindex, address, plen);
 }
 
@@ -1543,13 +1529,6 @@ nm_platform_ip4_route_delete (int ifindex, in_addr_t network, int plen, int metr
 	g_return_val_if_fail (klass->ip4_route_delete, FALSE);
 
 	debug ("route: deleting IPv4 route %s/%d, metric=%d", nm_utils_inet4_ntop (network, NULL), plen, metric);
-
-	if (!nm_platform_ip4_route_exists (ifindex, network, plen, metric)) {
-		debug ("route not found");
-		platform->error = NM_PLATFORM_ERROR_NOT_FOUND;
-		return FALSE;
-	}
-
 	return klass->ip4_route_delete (platform, ifindex, network, plen, metric);
 }
 
@@ -1563,13 +1542,6 @@ nm_platform_ip6_route_delete (int ifindex,
 	g_return_val_if_fail (klass->ip6_route_delete, FALSE);
 
 	debug ("route: deleting IPv6 route %s/%d, metric=%d", nm_utils_inet6_ntop (&network, NULL), plen, metric);
-
-	if (!nm_platform_ip6_route_exists (ifindex, network, plen, metric)) {
-		debug ("route not found");
-		platform->error = NM_PLATFORM_ERROR_NOT_FOUND;
-		return FALSE;
-	}
-
 	return klass->ip6_route_delete (platform, ifindex, network, plen, metric);
 }
 
diff --git a/src/platform/tests/test-address.c b/src/platform/tests/test-address.c
index c9672fa..2b5980e 100644
--- a/src/platform/tests/test-address.c
+++ b/src/platform/tests/test-address.c
@@ -89,8 +89,8 @@ test_ip4_address (void)
 	accept_signal (address_removed);
 
 	/* Remove address again */
-	g_assert (!nm_platform_ip4_address_delete (ifindex, addr, IP4_PLEN));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
+	g_assert (nm_platform_ip4_address_delete (ifindex, addr, IP4_PLEN));
+	no_error ();
 
 	free_signal (address_added);
 	free_signal (address_changed);
@@ -145,8 +145,8 @@ test_ip6_address (void)
 	accept_signal (address_removed);
 
 	/* Remove address again */
-	g_assert (!nm_platform_ip6_address_delete (ifindex, addr, IP6_PLEN));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
+	g_assert (nm_platform_ip6_address_delete (ifindex, addr, IP6_PLEN));
+	no_error ();
 
 	free_signal (address_added);
 	free_signal (address_changed);
diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c
index 6c764ad..f333ffc 100644
--- a/src/platform/tests/test-route.c
+++ b/src/platform/tests/test-route.c
@@ -113,8 +113,8 @@ test_ip4_route ()
 	accept_signal (route_removed);
 
 	/* Remove route again */
-	g_assert (!nm_platform_ip4_route_delete (ifindex, network, plen, metric));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
+	g_assert (nm_platform_ip4_route_delete (ifindex, network, plen, metric));
+	no_error ();
 
 	free_signal (route_added);
 	free_signal (route_changed);
@@ -196,8 +196,8 @@ test_ip6_route ()
 	accept_signal (route_removed);
 
 	/* Remove route again */
-	g_assert (!nm_platform_ip6_route_delete (ifindex, network, plen, metric));
-	error (NM_PLATFORM_ERROR_NOT_FOUND);
+	g_assert (nm_platform_ip6_route_delete (ifindex, network, plen, metric));
+	no_error ();
 
 	free_signal (route_added);
 	free_signal (route_changed);
-- 
1.8.5.3