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-07 11:53:05 +0100
commit92149f223fbd4068f30f31d14c6aa6c8e2146161 (patch)
tree47672b32eda661a3d87268b12657bfb28803a05e
parent2a0a9aa2e45b064304f827c7eed49bc80c6e3702 (diff)
downloadNetworkManager-92149f223fbd4068f30f31d14c6aa6c8e2146161.tar.gz
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.
-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 c35d472f81..e341cc730a 100644
--- a/src/devices/nm-device-ethernet.c
+++ b/src/devices/nm-device-ethernet.c
@@ -1607,10 +1607,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
@@ -1711,6 +1745,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 ca7866bb5d..a4b611b5f9 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -402,9 +402,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);
-
static gboolean queued_ip4_config_change (gpointer user_data);
static gboolean queued_ip6_config_change (gpointer user_data);
@@ -9860,19 +9857,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) {
priv->hw_addr_len = hwaddrlen;
if (!priv->hw_addr || !nm_utils_hwaddr_matches (priv->hw_addr, -1, hwaddr, hwaddrlen)) {
@@ -9894,7 +9896,7 @@ nm_device_update_hw_address (NMDevice *self)
}
}
-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 3ad900f385..8c864e6ff4 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -567,6 +567,9 @@ void nm_device_reapply_settings_immediately (NMDevice *self);
void nm_device_update_firewall_zone (NMDevice *self);
void nm_device_update_metered (NMDevice *self);
+void nm_device_update_hw_address (NMDevice *self);
+void nm_device_update_initial_hw_address (NMDevice *self);
+
G_END_DECLS
#endif /* NM_DEVICE_H */