From 091e68c0868d87008e24a602ac16cb01125c56b9 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 15 Feb 2014 22:11:48 +0100 Subject: [PATCH] backport fixes for platform libnl3 caching --- 0045-platform-caching.patch | 1795 +++++++++++++++++++++++++++++++++++ NetworkManager.spec | 3 + 2 files changed, 1798 insertions(+) create mode 100644 0045-platform-caching.patch 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 +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 +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 +--- + 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 +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 +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 +--- + 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 +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 +--- + 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 + #include + ++#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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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]: [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 + [...] [platform/nm-linux-platform.c:1216] event_notification(): netlink event (type 16) for link: virbr0 (4) + [...] [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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 + #include + ++#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 +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 +--- + 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 +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 +--- + 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 - 0.9.9.0-29.git20140131 - update to new upstream snapshot