summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2015-12-13 22:09:59 +0100
committerBeniamino Galvani <bgalvani@redhat.com>2016-01-08 16:11:27 +0100
commitf52974e3116858f4e26298d3e5b90f8d3ccc0745 (patch)
tree9145c2932078b3d47110b018fe770910fb37c089
parenta897adc84692d9fe3a105ab714887e127aadcfac (diff)
downloadNetworkManager-bg/device-zero-mac-fix-rh1288110-for-nm-1-0.tar.gz
device: wait for valid MAC before making ethernet devices availablebg/device-zero-mac-fix-rh1288110-for-nm-1-0
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)
-rw-r--r--src/devices/nm-device-ethernet.c35
-rw-r--r--src/devices/nm-device.c12
-rw-r--r--src/devices/nm-device.h3
3 files changed, 45 insertions, 5 deletions
diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c
index 2dda84b3e8..b281d03859 100644
--- a/src/devices/nm-device-ethernet.c
+++ b/src/devices/nm-device-ethernet.c
@@ -1598,10 +1598,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
@@ -1700,6 +1734,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 890427f70d..494e90772a 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 "
@@ -8862,19 +8859,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);
@@ -8895,7 +8897,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 49cef8e19c..0ba1c1f08d 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 */