Blob Blame History Raw
From d1529eaa50aa6b838234629fcd86b129a9598bf4 Mon Sep 17 00:00:00 2001
From: Beniamino Galvani <bgalvani@redhat.com>
Date: Sun, 13 Dec 2015 22:08:23 +0100
Subject: [PATCH 1/3] core: simplify generation of default connection for new
 devices

Instead of using a signal for triggering the generation of a default
connection when the device becomes managed, let the manager wait for a
transition to UNAVAILABLE or DISCONNECTED states.

This partially reverts b3b0b4625053 ("device: retry creation of
default connection after link is initialized").

(cherry picked from commit 44789e32912c48358dbb7971be57682bd330719d)
---
 src/devices/nm-device.c | 11 -----------
 src/nm-manager.c        | 17 +++++------------
 2 files changed, 5 insertions(+), 23 deletions(-)

diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index d4627ec..9f99478 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -95,7 +95,6 @@ enum {
 	REMOVED,
 	RECHECK_AUTO_ACTIVATE,
 	RECHECK_ASSUME,
-	LINK_INITIALIZED,
 	LAST_SIGNAL,
 };
 static guint signals[LAST_SIGNAL] = { 0 };
@@ -1515,9 +1514,6 @@ device_link_changed (NMDevice *self)
 		}
 	}
 
-	if (emit_link_initialized)
-		g_signal_emit (self, signals[LINK_INITIALIZED], 0);
-
 	return G_SOURCE_REMOVE;
 }
 
@@ -9867,13 +9863,6 @@ nm_device_class_init (NMDeviceClass *klass)
 		              0, NULL, NULL, NULL,
 		              G_TYPE_NONE, 0);
 
-	signals[LINK_INITIALIZED] =
-		g_signal_new (NM_DEVICE_LINK_INITIALIZED,
-		              G_OBJECT_CLASS_TYPE (object_class),
-		              G_SIGNAL_RUN_FIRST,
-		              0, NULL, NULL, NULL,
-		              G_TYPE_NONE, 0);
-
 	nm_dbus_manager_register_exported_type (nm_dbus_manager_get (),
 	                                        G_TYPE_FROM_CLASS (klass),
 	                                        &dbus_glib_nm_device_object_info);
diff --git a/src/nm-manager.c b/src/nm-manager.c
index a6c23b1..2d8b7a9 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -717,6 +717,7 @@ manager_device_state_changed (NMDevice *device,
                               gpointer user_data)
 {
 	NMManager *self = NM_MANAGER (user_data);
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
 
 	switch (new_state) {
 	case NM_DEVICE_STATE_UNMANAGED:
@@ -729,6 +730,10 @@ manager_device_state_changed (NMDevice *device,
 	default:
 		break;
 	}
+
+	if (   new_state == NM_DEVICE_STATE_UNAVAILABLE
+	    || new_state == NM_DEVICE_STATE_DISCONNECTED)
+		nm_settings_device_added (priv->settings, device);
 }
 
 static void device_has_pending_action_changed (NMDevice *device,
@@ -853,14 +858,6 @@ device_removed_cb (NMDevice *device, gpointer user_data)
 }
 
 static void
-device_link_initialized_cb (NMDevice *device, gpointer user_data)
-{
-	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (user_data);
-
-	nm_settings_device_added (priv->settings, device);
-}
-
-static void
 aipd_handle_event (DBusGProxy *proxy,
                    const char *event,
                    const char *iface,
@@ -1821,10 +1818,6 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume)
 	                  G_CALLBACK (device_removed_cb),
 	                  self);
 
-	g_signal_connect (device, NM_DEVICE_LINK_INITIALIZED,
-	                  G_CALLBACK (device_link_initialized_cb),
-	                  self);
-
 	g_signal_connect (device, "notify::" NM_DEVICE_IP_IFACE,
 	                  G_CALLBACK (device_ip_iface_changed),
 	                  self);
-- 
2.5.0

From 8fc5e8acaa31572d56ab5adc0880ba65d334796d Mon Sep 17 00:00:00 2001
From: Beniamino Galvani <bgalvani@redhat.com>
Date: Mon, 14 Dec 2015 08:46:29 +0100
Subject: [PATCH 2/3] device/trivial: split out
 nm_device_update_initial_hw_address()

(cherry picked from commit 2a0a9aa2e45b064304f827c7eed49bc80c6e3702)
---
 src/devices/nm-device.c | 50 ++++++++++++++++++++++++++++---------------------
 1 file changed, 29 insertions(+), 21 deletions(-)

diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 9f99478..50cb630 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -389,6 +389,7 @@ static void _set_state_full (NMDevice *self,
                              gboolean quitting);
 
 static void nm_device_update_hw_address (NMDevice *self);
+static void nm_device_update_initial_hw_address (NMDevice *self);
 
 /***********************************************************/
 
@@ -8882,6 +8883,33 @@ nm_device_update_hw_address (NMDevice *self)
 	priv->hw_addr_len = hwaddrlen;
 }
 
+static void
+nm_device_update_initial_hw_address (NMDevice *self)
+{
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+
+	if (priv->hw_addr_len) {
+		priv->initial_hw_addr = g_strdup (priv->hw_addr);
+		_LOGD (LOGD_DEVICE | LOGD_HW, "read initial MAC address %s", priv->initial_hw_addr);
+
+		if (priv->ifindex > 0) {
+			guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
+			size_t len = 0;
+
+			if (nm_platform_link_get_permanent_address (NM_PLATFORM_GET, priv->ifindex, buf, &len)) {
+				g_warn_if_fail (len == priv->hw_addr_len);
+				priv->perm_hw_addr = nm_utils_hwaddr_ntoa (buf, priv->hw_addr_len);
+				_LOGD (LOGD_DEVICE | LOGD_HW, "read permanent MAC address %s",
+				       priv->perm_hw_addr);
+			} else {
+				/* Fall back to current address */
+				_LOGD (LOGD_HW | LOGD_ETHER, "unable to read permanent MAC address");
+				priv->perm_hw_addr = g_strdup (priv->hw_addr);
+			}
+		}
+	}
+}
+
 gboolean
 nm_device_set_hw_addr (NMDevice *self, const char *addr,
                        const char *detail, guint64 hw_log_domain)
@@ -9117,27 +9145,7 @@ constructed (GObject *object)
 	int master;
 
 	nm_device_update_hw_address (self);
-
-	if (priv->hw_addr_len) {
-		priv->initial_hw_addr = g_strdup (priv->hw_addr);
-		_LOGD (LOGD_DEVICE | LOGD_HW, "read initial MAC address %s", priv->initial_hw_addr);
-
-		if (priv->ifindex > 0) {
-			guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
-			size_t len = 0;
-
-			if (nm_platform_link_get_permanent_address (NM_PLATFORM_GET, priv->ifindex, buf, &len)) {
-				g_warn_if_fail (len == priv->hw_addr_len);
-				priv->perm_hw_addr = nm_utils_hwaddr_ntoa (buf, priv->hw_addr_len);
-				_LOGD (LOGD_DEVICE | LOGD_HW, "read permanent MAC address %s",
-				       priv->perm_hw_addr);
-			} else {
-				/* Fall back to current address */
-				_LOGD (LOGD_HW | LOGD_ETHER, "unable to read permanent MAC address");
-				priv->perm_hw_addr = g_strdup (priv->hw_addr);
-			}
-		}
-	}
+	nm_device_update_initial_hw_address (self);
 
 	/* Note: initial hardware address must be read before calling get_ignore_carrier() */
 	if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) {
-- 
2.5.0

From 1528c6fa3c3bc540c51dd9ba3115c83847c7d13a Mon Sep 17 00:00:00 2001
From: Beniamino Galvani <bgalvani@redhat.com>
Date: Sun, 13 Dec 2015 22:09:59 +0100
Subject: [PATCH 3/3] device: wait for valid MAC before making ethernet devices
 available

In certain situations, ethernet links first appear with a zero MAC
address and then the MAC changes some time later. Currently NM does
not deal correctly with this scenario since it initializes wrong
@initial_hwaddr and @permanent_hwaddr on the device and tries to
immediately activate it.

To fix this, initialize the device's addresses only when the MAC
becomes valid and make the device available only at that point.

(cherry picked from commit 92149f223fbd4068f30f31d14c6aa6c8e2146161)
---
 src/devices/nm-device-ethernet.c | 35 +++++++++++++++++++++++++++++++++++
 src/devices/nm-device.c          | 12 +++++++-----
 src/devices/nm-device.h          |  3 +++
 3 files changed, 45 insertions(+), 5 deletions(-)

diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c
index 7c0de88..002f1d1 100644
--- a/src/devices/nm-device-ethernet.c
+++ b/src/devices/nm-device-ethernet.c
@@ -1594,10 +1594,44 @@ link_changed (NMDevice *device, NMPlatformLink *info)
 {
 	NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device);
 	NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
+	static const guint8 zero_hwaddr[ETH_ALEN];
+	const guint8 *hwaddr;
+	gsize hwaddrlen = 0;
 
 	NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->link_changed (device, info);
 	if (!priv->subchan1 && info->initialized)
 		_update_s390_subchannels (self);
+
+	if (!nm_device_get_initial_hw_address (device)) {
+		hwaddr = nm_platform_link_get_address (NM_PLATFORM_GET,
+		                                       nm_device_get_ifindex (self),
+		                                       &hwaddrlen);
+		if (!nm_utils_hwaddr_matches (hwaddr, hwaddrlen, zero_hwaddr, ETH_ALEN)) {
+			_LOGD (LOGD_DEVICE, "device got a valid hw address");
+			nm_device_update_hw_address (self);
+			nm_device_update_initial_hw_address (self);
+			if (nm_device_get_state (device) == NM_DEVICE_STATE_UNAVAILABLE) {
+				/*
+				 * If the device is UNAVAILABLE, any previous try to
+				 * bring it up probably has failed because of the
+				 * invalid hardware address; try again.
+				 */
+				nm_device_bring_up (self, TRUE, NULL);
+				nm_device_queue_recheck_available (device,
+				                                   NM_DEVICE_STATE_REASON_NONE,
+				                                   NM_DEVICE_STATE_REASON_NONE);
+			}
+		}
+	}
+}
+
+static gboolean
+is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags)
+{
+	if (!NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->is_available (device, flags))
+		return FALSE;
+
+	return !!nm_device_get_initial_hw_address (device);
 }
 
 static void
@@ -1696,6 +1730,7 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass)
 	parent_class->update_connection = update_connection;
 	parent_class->carrier_changed = carrier_changed;
 	parent_class->link_changed = link_changed;
+	parent_class->is_available = is_available;
 
 	parent_class->state_changed = device_state_changed;
 
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 50cb630..39977c6 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -388,9 +388,6 @@ static void _set_state_full (NMDevice *self,
                              NMDeviceStateReason reason,
                              gboolean quitting);
 
-static void nm_device_update_hw_address (NMDevice *self);
-static void nm_device_update_initial_hw_address (NMDevice *self);
-
 /***********************************************************/
 
 #define QUEUED_PREFIX "queued state change to "
@@ -8850,19 +8847,24 @@ nm_device_get_hw_address (NMDevice *self)
 	return priv->hw_addr_len ? priv->hw_addr : NULL;
 }
 
-static void
+void
 nm_device_update_hw_address (NMDevice *self)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	int ifindex = nm_device_get_ifindex (self);
 	const guint8 *hwaddr;
 	gsize hwaddrlen = 0;
+	static const guint8 zero_hwaddr[ETH_ALEN];
 
 	if (ifindex <= 0)
 		return;
 
 	hwaddr = nm_platform_link_get_address (NM_PLATFORM_GET, ifindex, &hwaddrlen);
 
+	if (   priv->type == NM_DEVICE_TYPE_ETHERNET
+	    && nm_utils_hwaddr_matches (hwaddr, hwaddrlen, zero_hwaddr, sizeof (zero_hwaddr)))
+		hwaddrlen = 0;
+
 	if (hwaddrlen) {
 		if (!priv->hw_addr || !nm_utils_hwaddr_matches (priv->hw_addr, -1, hwaddr, hwaddrlen)) {
 			g_free (priv->hw_addr);
@@ -8883,7 +8885,7 @@ nm_device_update_hw_address (NMDevice *self)
 	priv->hw_addr_len = hwaddrlen;
 }
 
-static void
+void
 nm_device_update_initial_hw_address (NMDevice *self)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index 49cef8e..0ba1c1f 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -441,6 +441,9 @@ const NMPlatformIP6Route *nm_device_get_ip6_default_route (NMDevice *self, gbool
 
 void nm_device_spawn_iface_helper (NMDevice *self);
 
+void nm_device_update_hw_address (NMDevice *self);
+void nm_device_update_initial_hw_address (NMDevice *self);
+
 G_END_DECLS
 
 /* For testing only */
-- 
2.5.0