[NetworkManager/f20] backport fixes for platform libnl3 caching

thaller thaller at fedoraproject.org
Sun Feb 16 14:39:27 UTC 2014


commit 091e68c0868d87008e24a602ac16cb01125c56b9
Author: Thomas Haller <thaller at redhat.com>
Date:   Sat Feb 15 22:11:48 2014 +0100

    backport fixes for platform libnl3 caching

 0045-platform-caching.patch | 1795 +++++++++++++++++++++++++++++++++++++++++++
 NetworkManager.spec         |    3 +
 2 files changed, 1798 insertions(+), 0 deletions(-)
---
diff --git a/0045-platform-caching.patch b/0045-platform-caching.patch
new file mode 100644
index 0000000..7c8ad09
--- /dev/null
+++ b/0045-platform-caching.patch
@@ -0,0 +1,1795 @@
+From 891a9f859f1f399eaf16d9fa8e00d5bf4bb69100 Mon Sep 17 00:00:00 2001
+From: Dan Winship <danw at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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
+
diff --git a/NetworkManager.spec b/NetworkManager.spec
index 58fa925..45b1fb2 100644
--- a/NetworkManager.spec
+++ b/NetworkManager.spec
@@ -71,6 +71,7 @@ Patch41: load-connections-ret-value.patch
 Patch42: bgo723163-add-and-activate-fix.patch
 Patch43: NM-before-network-service.patch
 Patch44: 0044-ipv6-privacy.patch
+Patch45: 0045-platform-caching.patch
 
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
@@ -238,6 +239,7 @@ deployments.
 %patch42 -p1 -b .bgo723163-add-and-activate-fix
 %patch43 -p1 -b .NM-before-network-service
 %patch44 -p1 -b .0044-ipv6-privacy.orig
+%patch45 -p1 -b .0045-platform-caching.orig
 
 %build
 
@@ -441,6 +443,7 @@ fi
 - support for ipv6 private addresses (rfc4941) (rh #1047139)
 - add ipv6 autoconf addresses with /64 prefix (rh #1045118)
 - wait for IPv6 LL before starting autoconf
+- bugfix caching of libnl objects (caused error with new libnl3 version when activating bridges) (rh #1063290)
 
 * Tue Feb  4 2014 Thomas Haller <thaller at redhat.com> - 0.9.9.0-29.git20140131
 - update to new upstream snapshot


More information about the scm-commits mailing list