From ed78d3b3dc1406f6a1186b482a160452527cba6e Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Thu, 4 Dec 2014 16:22:39 +0100 Subject: [PATCH 1/7] platform: ensure all objects in link cache are of AF_UNSPEC family We assume that in nm_nl_cache_search() and correctly set that in get_kernel_object(), but we rtnl_link_alloc_cache() can initialize the cache with devices of other families. The consequence is that we don't notify when the bridge changes to IFF_UP as we fail to match and remove the old downed object from the cache: nm_device_bring_up(): [0xf506c0] (bridge0): bringing up device. nm_platform_link_set_up(): link: setting up 'bridge0' (12) link_change_flags(): link: change 12: flags set 'up' (1) get_kernel_object(): get_kernel_object for link: bridge0 (12, family 7) log_link(): signal: link added: 12: bridge0 mtu 1500 bridge driver 'bridge' udi '/sys/devices/virtual/net/bridge0' get_kernel_object(): get_kernel_object for link: bridge0 (12, family 7) log_link(): signal: link changed: 12: bridge0 mtu 1500 bridge driver 'bridge' udi '/sys/devices/virtual/net/bridge0' log_link(): signal: link changed: 12: bridge0 mtu 1500 bridge driver 'bridge' udi '/sys/devices/virtual/net/bridge0' (bridge0): device not up after timeout! (bridge0): preparing device --- src/platform/nm-linux-platform.c | 38 +++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 7ced0ba77b..668acdb933 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -3982,6 +3982,42 @@ ip6_route_exists (NMPlatform *platform, int ifindex, struct in6_addr network, in /******************************************************************/ +/* Initialize the link cache while ensuring all links are of AF_UNSPEC, + * family (even though the kernel might set AF_BRIDGE for bridges). + * See also: _nl_link_family_unset() */ +static void +init_link_cache (NMPlatform *platform) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + struct nl_object *object = NULL; + + rtnl_link_alloc_cache (priv->nlh, AF_UNSPEC, &priv->link_cache); + + do { + for (object = nl_cache_get_first (priv->link_cache); object; object = nl_cache_get_next (object)) { + if (rtnl_link_get_family ((struct rtnl_link *)object) != AF_UNSPEC) + break; + } + + if (object) { + /* A non-AF_UNSPEC object encoutnered */ + struct nl_object *existing; + + nl_object_get (object); + nl_cache_remove (object); + rtnl_link_set_family ((struct rtnl_link *)object, AF_UNSPEC); + existing = nl_cache_search (priv->link_cache, object); + if (existing) + nl_object_put (existing); + else + nl_cache_add (priv->link_cache, object); + nl_object_put (object); + } + } while (object); +} + +/******************************************************************/ + #define EVENT_CONDITIONS ((GIOCondition) (G_IO_IN | G_IO_PRI)) #define ERROR_CONDITIONS ((GIOCondition) (G_IO_ERR | G_IO_NVAL)) #define DISCONNECT_CONDITIONS ((GIOCondition) (G_IO_HUP)) @@ -4233,7 +4269,7 @@ setup (NMPlatform *platform) event_handler, platform); /* Allocate netlink caches */ - rtnl_link_alloc_cache (priv->nlh, AF_UNSPEC, &priv->link_cache); + init_link_cache (platform); rtnl_addr_alloc_cache (priv->nlh, &priv->address_cache); rtnl_route_alloc_cache (priv->nlh, AF_UNSPEC, 0, &priv->route_cache); g_assert (priv->link_cache && priv->address_cache && priv->route_cache); From 85b811cc7c83eea19020dbf2d03cf085f5fa2097 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 29 Sep 2014 17:58:44 +0200 Subject: [PATCH 2/7] platform: refactor the object comparison logic into a separate function One from libnl is not good enough (see comment). --- src/platform/nm-linux-platform.c | 46 ++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 668acdb933..3cf4cc8306 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -1880,6 +1880,33 @@ _rtnl_addr_timestamps_equal_fuzzy (guint32 ts1, guint32 ts2) return diff <= 2; } +static gboolean +nm_nl_object_diff (ObjectType type, struct nl_object *_a, struct nl_object *_b) +{ + if (nl_object_diff (_a, _b)) { + /* libnl thinks objects are different*/ + return TRUE; + } + + if (type == OBJECT_TYPE_IP4_ADDRESS || type == OBJECT_TYPE_IP6_ADDRESS) { + struct rtnl_addr *a = (struct rtnl_addr *) _a; + struct rtnl_addr *b = (struct rtnl_addr *) _b; + + /* libnl nl_object_diff() ignores differences in timestamp. Let's care about + * them (if they are large enough). + * + * Note that these valid and preferred timestamps are absolute, after + * _rtnl_addr_hack_lifetimes_rel_to_abs(). */ + if ( !_rtnl_addr_timestamps_equal_fuzzy (rtnl_addr_get_preferred_lifetime (a), + rtnl_addr_get_preferred_lifetime (b)) + || !_rtnl_addr_timestamps_equal_fuzzy (rtnl_addr_get_valid_lifetime (a), + rtnl_addr_get_valid_lifetime (b))) + return TRUE; + } + + return FALSE; +} + /* This function does all the magic to avoid race conditions caused * by concurrent usage of synchronous commands and an asynchronous cache. This * might be a nice future addition to libnl but it requires to do all operations @@ -1985,24 +2012,9 @@ event_notification (struct nl_msg *msg, gpointer user_data) * This also catches notifications for internal addition or change, unless * another action occured very soon after it. */ - if (!nl_object_diff (kernel_object, cached_object)) { - if (type == OBJECT_TYPE_IP4_ADDRESS || type == OBJECT_TYPE_IP6_ADDRESS) { - struct rtnl_addr *c = (struct rtnl_addr *) cached_object; - struct rtnl_addr *k = (struct rtnl_addr *) kernel_object; + if (!nm_nl_object_diff (type, kernel_object, cached_object)) + return NL_OK; - /* libnl nl_object_diff() ignores differences in timestamp. Let's care about - * them (if they are large enough). - * - * Note that these valid and preferred timestamps are absolute, after - * _rtnl_addr_hack_lifetimes_rel_to_abs(). */ - if ( _rtnl_addr_timestamps_equal_fuzzy (rtnl_addr_get_preferred_lifetime (c), - rtnl_addr_get_preferred_lifetime (k)) - && _rtnl_addr_timestamps_equal_fuzzy (rtnl_addr_get_valid_lifetime (c), - rtnl_addr_get_valid_lifetime (k))) - return NL_OK; - } else - return NL_OK; - } /* Handle external change */ nl_cache_remove (cached_object); nle = nl_cache_add (cache, kernel_object); From 2b8060b9b36fe8f540b38c085600f3771d4ac6b4 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 8 Dec 2014 18:08:42 +0100 Subject: [PATCH 3/7] platform: resynchronize with kernel when we're out of buffer space Kernel can return ENOBUFS in variety of reasons. If that happens, we know we've lost events and should pick up kernel state. Simple reproducer that triggers an ENOBUFS condition no matter how big our netlink socket buffer is: ip link add bridge0 type bridge for i in seq $(0 1023); do ip link add dummy$i type dummy; \ ip link set dummy$i master bridge0; done ip link del bridge0 --- src/platform/nm-linux-platform.c | 94 ++++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 10 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 3cf4cc8306..1fb0bd014e 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -4028,6 +4028,70 @@ init_link_cache (NMPlatform *platform) } while (object); } +/* Calls announce_object with appropriate arguments for all objects + * which are not coherent between old and new caches and deallocates + * the old cache. */ +static void +cache_announce_changes (NMPlatform *platform, struct nl_cache *new, struct nl_cache *old) +{ + struct nl_object *object; + + if (!old) + return; + + for (object = nl_cache_get_first (new); object; object = nl_cache_get_next (object)) { + struct nl_object *cached_object = nm_nl_cache_search (old, object); + + if (cached_object) { + ObjectType type = object_type_from_nl_object (object); + if (nm_nl_object_diff (type, object, cached_object)) + announce_object (platform, object, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_EXTERNAL); + nl_object_put (cached_object); + } else + announce_object (platform, object, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_EXTERNAL); + } + for (object = nl_cache_get_first (old); object; object = nl_cache_get_next (object)) { + struct nl_object *cached_object = nm_nl_cache_search (new, object); + if (cached_object) + nl_object_put (cached_object); + else + announce_object (platform, object, NM_PLATFORM_SIGNAL_REMOVED, NM_PLATFORM_REASON_EXTERNAL); + } + + nl_cache_free (old); +} + +/* Creates and populates the netlink object caches. Called upon platform init and + * when we run out of sync (out of buffer space, netlink congestion control). In case + * the caches already exist, it finds changed, added and removed objects, announces + * them and destroys the old caches. */ +static void +cache_repopulate_all (NMPlatform *platform) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + struct nl_cache *old_link_cache = priv->link_cache; + struct nl_cache *old_address_cache = priv->address_cache; + struct nl_cache *old_route_cache = priv->route_cache; + struct nl_object *object; + + debug ("platform: %spopulate platform cache", old_link_cache ? "re" : ""); + + /* Allocate new netlink caches */ + init_link_cache (platform); + rtnl_addr_alloc_cache (priv->nlh, &priv->address_cache); + rtnl_route_alloc_cache (priv->nlh, AF_UNSPEC, 0, &priv->route_cache); + g_assert (priv->link_cache && priv->address_cache && priv->route_cache); + + for (object = nl_cache_get_first (priv->address_cache); object; object = nl_cache_get_next (object)) { + _rtnl_addr_hack_lifetimes_rel_to_abs ((struct rtnl_addr *) object); + } + + /* Make sure all changes we've missed are announced. */ + cache_announce_changes (platform, priv->link_cache, old_link_cache); + cache_announce_changes (platform, priv->address_cache, old_address_cache); + cache_announce_changes (platform, priv->route_cache, old_route_cache); +} + /******************************************************************/ #define EVENT_CONDITIONS ((GIOCondition) (G_IO_IN | G_IO_PRI)) @@ -4056,7 +4120,8 @@ event_handler (GIOChannel *channel, GIOCondition io_condition, gpointer user_data) { - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (user_data); + NMPlatform *platform = NM_PLATFORM (user_data); + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); int nle; nle = nl_recvmsgs_default (priv->nlh_event); @@ -4068,6 +4133,17 @@ event_handler (GIOChannel *channel, * and can happen easily. */ debug ("Uncritical failure to retrieve incoming events: %s (%d)", nl_geterror (nle), nle); break; + case -NLE_NOMEM: + warning ("Too many netlink events. Need to resynchronize platform cache"); + /* Drain the event queue, we've lost events and are out of sync anyway and we'd + * like to free up some space. We'll read in the status synchronously. */ + nl_socket_modify_cb (priv->nlh_event, NL_CB_VALID, NL_CB_DEFAULT, NULL, NULL); + do { + nle = nl_recvmsgs_default (priv->nlh_event); + } while (nle != -NLE_AGAIN); + nl_socket_modify_cb (priv->nlh_event, NL_CB_VALID, NL_CB_CUSTOM, event_notification, user_data); + cache_repopulate_all (platform); + break; default: error ("Failed to retrieve incoming events: %s (%d)", nl_geterror (nle), nle); break; @@ -4099,6 +4175,12 @@ setup_socket (gboolean event, gpointer user_data) nle = nl_socket_set_passcred (sock, 1); g_assert (!nle); + /* No blocking for event socket, so that we can drain it safely. */ + if (event) { + nle = nl_socket_set_nonblocking (sock); + g_assert (!nle); + } + return sock; } @@ -4244,7 +4326,6 @@ setup (NMPlatform *platform) int channel_flags; gboolean status; int nle; - struct nl_object *object; /* Initialize netlink socket for requests */ priv->nlh = setup_socket (FALSE, platform); @@ -4280,14 +4361,7 @@ setup (NMPlatform *platform) (EVENT_CONDITIONS | ERROR_CONDITIONS | DISCONNECT_CONDITIONS), event_handler, platform); - /* Allocate netlink caches */ - init_link_cache (platform); - rtnl_addr_alloc_cache (priv->nlh, &priv->address_cache); - rtnl_route_alloc_cache (priv->nlh, AF_UNSPEC, 0, &priv->route_cache); - g_assert (priv->link_cache && priv->address_cache && priv->route_cache); - - for (object = nl_cache_get_first (priv->address_cache); object; object = nl_cache_get_next (object)) - _rtnl_addr_hack_lifetimes_rel_to_abs ((struct rtnl_addr *) object); + cache_repopulate_all (platform); #if HAVE_LIBNL_INET6_ADDR_GEN_MODE /* Initial check for user IPv6LL support once the link cache is allocated From 8b77b931698468419d1ed04738069613a4fea79b Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 8 Dec 2014 18:42:57 +0100 Subject: [PATCH 4/7] Revert "platform: increase NL buffer for systems with lots of interfaces (rh #1141256)" This reverts commit efd09845c41e08469d6f6bffa23bd90b6bd06e85. It turns out that the socket space might not be the only buffer that may get too full. 128K ought to be enough for it and we should resynchronize with the kernel now if needed. --- src/platform/nm-linux-platform.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 1fb0bd014e..cdf3ce24dd 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -4195,7 +4195,6 @@ udev_device_added (NMPlatform *platform, const char *ifname; int ifindex; gboolean was_announceable = FALSE; - int nle; ifname = g_udev_device_get_name (udev_device); if (!ifname) { @@ -4226,12 +4225,6 @@ udev_device_added (NMPlatform *platform, g_hash_table_insert (priv->udev_devices, GINT_TO_POINTER (ifindex), g_object_ref (udev_device)); - /* Grow the netlink socket buffer beyond 128k if we have more that 32 interfaces. */ - nle = nl_socket_set_buffer_size (priv->nlh_event, - MAX (131072, 4096 * g_hash_table_size (priv->udev_devices)), 0); - if (nle) - warning ("udev-add: failed to adjust netlink socket buffer size"); - /* Announce devices only if they also have been discovered via Netlink. */ if (rtnllink && link_is_announceable (platform, rtnllink)) announce_object (platform, (struct nl_object *) rtnllink, was_announceable ? NM_PLATFORM_SIGNAL_CHANGED : NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_EXTERNAL); From 81553b69786eade65ced35782486d2807cfa2504 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Fri, 5 Dec 2014 13:10:51 +0100 Subject: [PATCH 5/7] device: release and enslave an interface if its master changed In case of an atomic master change, we'd not notice that the master changed: ip link set dummy0 master bridge0 ip link set dummy0 master bridge1 --- src/devices/nm-device.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index f834875cbf..0956135a97 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -1180,6 +1180,8 @@ device_link_changed (NMDevice *self, NMPlatformLink *info) } /* Update slave status for external changes */ + if (priv->enslaved && info->master != nm_device_get_ifindex (priv->master)) + nm_device_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_NONE); if (info->master && !priv->enslaved) { NMDevice *master; @@ -1197,8 +1199,7 @@ device_link_changed (NMDevice *self, NMPlatformLink *info) info->master, nm_platform_link_get_name (info->master)); } - } else if (priv->enslaved && !info->master) - nm_device_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_NONE); + } if (klass->link_changed) klass->link_changed (self, info); From 25387cd1ffc4b3135a13e9222c0b0e5dea506c80 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Fri, 5 Dec 2014 13:12:55 +0100 Subject: [PATCH 6/7] device: set the master on device addition Otherwise we won't notice the device is a slave on NM startup until someone changes the link or tries to activate the device. --- src/devices/nm-device.c | 65 +++++++++++++++++++++++++++++------------ src/devices/nm-device.h | 2 ++ src/nm-manager.c | 1 + 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 0956135a97..f9333909d6 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -977,6 +977,22 @@ nm_device_release_one_slave (NMDevice *self, NMDevice *slave, gboolean configure return success; } +/** + * nm_device_finish_init: + * @self: the master device + * + * Whatever needs to be done post-initialization, when the device has a DBus + * object name. + */ +void +nm_device_finish_init (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + if (priv->master) + nm_device_enslave_slave (priv->master, self, NULL); +} + static void carrier_changed (NMDevice *self, gboolean carrier) { @@ -1137,6 +1153,27 @@ update_for_ip_ifname_change (NMDevice *self) } } +static void +device_set_master (NMDevice *self, int ifindex) +{ + NMDevice *master; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + master = nm_manager_get_device_by_ifindex (nm_manager_get (), ifindex); + if (master && NM_DEVICE_GET_CLASS (master)->enslave_slave) { + g_clear_object (&priv->master); + priv->master = g_object_ref (master); + nm_device_master_add_slave (master, self, FALSE); + } else if (master) { + _LOGI (LOGD_DEVICE, "enslaved to non-master-type device %s; ignoring", + nm_device_get_iface (master)); + } else { + _LOGW (LOGD_DEVICE, "enslaved to unknown device %d %s", + ifindex, + nm_platform_link_get_name (ifindex)); + } +} + static void device_link_changed (NMDevice *self, NMPlatformLink *info) { @@ -1182,24 +1219,10 @@ device_link_changed (NMDevice *self, NMPlatformLink *info) /* Update slave status for external changes */ if (priv->enslaved && info->master != nm_device_get_ifindex (priv->master)) nm_device_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_NONE); - if (info->master && !priv->enslaved) { - NMDevice *master; - - master = nm_manager_get_device_by_ifindex (nm_manager_get (), info->master); - if (master && NM_DEVICE_GET_CLASS (master)->enslave_slave) { - g_clear_object (&priv->master); - priv->master = g_object_ref (master); - nm_device_master_add_slave (master, self, FALSE); - nm_device_enslave_slave (master, self, NULL); - } else if (master) { - _LOGI (LOGD_DEVICE, "enslaved to non-master-type device %s; ignoring", - nm_device_get_iface (master)); - } else { - _LOGW (LOGD_DEVICE, "enslaved to unknown device %d %s", - info->master, - nm_platform_link_get_name (info->master)); - } - } + if (info->master && !priv->enslaved) + device_set_master (self, info->master); + if (priv->master) + nm_device_enslave_slave (priv->master, self, NULL); if (klass->link_changed) klass->link_changed (self, info); @@ -7945,6 +7968,7 @@ constructed (GObject *object) { NMDevice *self = NM_DEVICE (object); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + int master; nm_device_update_hw_address (self); @@ -7977,6 +8001,11 @@ constructed (GObject *object) if (priv->is_software) priv->capabilities |= NM_DEVICE_CAP_IS_SOFTWARE; + /* Enslave ourselves */ + master = nm_platform_link_get_master (priv->ifindex); + if (master) + device_set_master (self, master); + priv->con_provider = nm_connection_provider_get (); g_assert (priv->con_provider); g_signal_connect (priv->con_provider, diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index ab54262623..38eddaa8df 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -216,6 +216,8 @@ GType nm_device_get_type (void); const char * nm_device_get_path (NMDevice *dev); void nm_device_dbus_export (NMDevice *device); +void nm_device_finish_init (NMDevice *device); + const char * nm_device_get_udi (NMDevice *dev); const char * nm_device_get_iface (NMDevice *dev); int nm_device_get_ifindex (NMDevice *dev); diff --git a/src/nm-manager.c b/src/nm-manager.c index 1c946ec41a..06f24abdb8 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -1819,6 +1819,7 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume) nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_INTERNAL, sleeping); nm_device_dbus_export (device); + nm_device_finish_init (device); if (try_assume) { connection_assumed = recheck_assume_connection (device, self); From 62ad694421ae96de61436f87cdec1a01e3e2879a Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Fri, 5 Dec 2014 17:49:11 +0100 Subject: [PATCH 7/7] device: assume connections for device with slaves If a bridge/team/bond has slaves, assume it's connected. Recheck as devices appear. https://bugzilla.redhat.com/show_bug.cgi?id=1141266 --- src/devices/nm-device.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index f9333909d6..50fc07562e 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -1404,6 +1404,7 @@ nm_device_master_add_slave (NMDevice *self, NMDevice *slave, gboolean configure) G_CALLBACK (slave_state_changed), self); priv->slaves = g_slist_append (priv->slaves, info); } + nm_device_queue_recheck_assume (self); return TRUE; } @@ -1989,8 +1990,9 @@ nm_device_generate_connection (NMDevice *self, NMDevice *master) ip6_method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG); if ( g_strcmp0 (ip4_method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0 && g_strcmp0 (ip6_method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0 - && !nm_setting_connection_get_master (NM_SETTING_CONNECTION (s_con))) { - _LOGD (LOGD_DEVICE, "ignoring generated connection (no IP and not slave)"); + && !nm_setting_connection_get_master (NM_SETTING_CONNECTION (s_con)) + && !priv->slaves) { + _LOGD (LOGD_DEVICE, "ignoring generated connection (no IP and not in master-slave relationship)"); g_object_unref (connection); connection = NULL; } @@ -2150,7 +2152,7 @@ nm_device_emit_recheck_assume (gpointer self) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); priv->recheck_assume_id = 0; - if (!nm_device_get_act_request (self) && (priv->ip4_config || priv->ip6_config)) { + if (!nm_device_get_act_request (self)) { _LOGD (LOGD_DEVICE, "emit RECHECK_ASSUME signal"); g_signal_emit (self, signals[RECHECK_ASSUME], 0); }