summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2015-04-13 11:43:12 -0500
committerDan Williams <dcbw@redhat.com>2015-05-06 16:14:24 -0500
commitcd3df12c8f8ed6c868c12bc4e7fe6ba162dafc5b (patch)
treea0d645ff29c22751bdbd9ded69f3f520a92dd2f8
parent477cbc848af27f0eccf59092873d75e5a50552c1 (diff)
downloadNetworkManager-cd3df12c8f8ed6c868c12bc4e7fe6ba162dafc5b.tar.gz
vlan: don't fail if parent isn't found at construct time for existing devices
For existing devices, depending on the order that netlink sends interfaces to us, the parent may be found after the VLAN interface and not be available when the VLAN interface is constructed. Instead of failing construction, when a NMDeviceVlan has no parent keep it unavailable for activation. Then have the Manager notify existing devices when a new device is found, and let NMDeviceVlan find the parent later and become available via that mechanism. This doesn't apply to VLANs created by NM itself, because the kernel requires a parent ifindex when creating a VLAN device. Thus this fix only applies to VLANs created outside NetworkManager, or existing when NM starts up.
-rw-r--r--introspection/nm-device.xml10
-rw-r--r--libnm-core/nm-dbus-interface.h4
-rw-r--r--libnm-util/NetworkManager.h4
-rw-r--r--src/devices/nm-device-vlan.c108
-rw-r--r--src/devices/nm-device.h15
-rw-r--r--src/nm-manager.c23
6 files changed, 131 insertions, 33 deletions
diff --git a/introspection/nm-device.xml b/introspection/nm-device.xml
index 7aef2f35b1..71b830f108 100644
--- a/introspection/nm-device.xml
+++ b/introspection/nm-device.xml
@@ -648,6 +648,16 @@
A new connection activation was enqueued.
</tp:docstring>
</tp:enumvalue>
+ <tp:enumvalue suffix="PARENT_CHANGED" value="61">
+ <tp:docstring>
+ The device's parent changed.
+ </tp:docstring>
+ </tp:enumvalue>
+ <tp:enumvalue suffix="PARENT_MANAGED_CHANGED" value="62">
+ <tp:docstring>
+ The device parent's management changed.
+ </tp:docstring>
+ </tp:enumvalue>
</tp:enum>
<tp:struct name="NM_DEVICE_STATE_REASON_STRUCT">
diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h
index 9bab80f354..ccc3b3a9e9 100644
--- a/libnm-core/nm-dbus-interface.h
+++ b/libnm-core/nm-dbus-interface.h
@@ -467,6 +467,8 @@ typedef enum {
* @NM_DEVICE_STATE_REASON_MODEM_AVAILABLE: Modem now ready and available
* @NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT: SIM PIN was incorrect
* @NM_DEVICE_STATE_REASON_NEW_ACTIVATION: New connection activation was enqueued
+ * @NM_DEVICE_STATE_REASON_PARENT_CHANGED: the device's parent changed
+ * @NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED: the device parent's management changed
*
* Device state change reason codes
*
@@ -534,6 +536,8 @@ typedef enum {
NM_DEVICE_STATE_REASON_MODEM_AVAILABLE = 58,
NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT = 59,
NM_DEVICE_STATE_REASON_NEW_ACTIVATION = 60,
+ NM_DEVICE_STATE_REASON_PARENT_CHANGED = 61,
+ NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED = 62,
} NMDeviceStateReason;
diff --git a/libnm-util/NetworkManager.h b/libnm-util/NetworkManager.h
index 5a98b8e496..4fa861e88f 100644
--- a/libnm-util/NetworkManager.h
+++ b/libnm-util/NetworkManager.h
@@ -472,6 +472,8 @@ typedef enum {
* @NM_DEVICE_STATE_REASON_MODEM_AVAILABLE: Modem now ready and available
* @NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT: SIM PIN was incorrect
* @NM_DEVICE_STATE_REASON_NEW_ACTIVATION: New connection activation was enqueued
+ * @NM_DEVICE_STATE_REASON_PARENT_CHANGED: the device's parent changed
+ * @NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED: the device parent's management changed
*
* Device state change reason codes
*
@@ -539,6 +541,8 @@ typedef enum {
NM_DEVICE_STATE_REASON_MODEM_AVAILABLE = 58,
NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT = 59,
NM_DEVICE_STATE_REASON_NEW_ACTIVATION = 60,
+ NM_DEVICE_STATE_REASON_PARENT_CHANGED = 61,
+ NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED = 62,
NM_DEVICE_STATE_REASON_LAST = 0xFFFF
} NMDeviceStateReason;
diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c
index b2a2fbf5f4..5513d73abb 100644
--- a/src/devices/nm-device-vlan.c
+++ b/src/devices/nm-device-vlan.c
@@ -107,6 +107,15 @@ bring_up (NMDevice *dev, gboolean *no_firmware)
/******************************************************************/
+static gboolean
+is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags)
+{
+ if (!NM_DEVICE_VLAN_GET_PRIVATE (device)->parent)
+ return FALSE;
+
+ return NM_DEVICE_CLASS (nm_device_vlan_parent_class)->is_available (device, flags);
+}
+
static void
parent_state_changed (NMDevice *parent,
NMDeviceState new_state,
@@ -124,9 +133,13 @@ parent_state_changed (NMDevice *parent,
}
static void
-nm_device_vlan_set_parent (NMDeviceVlan *device, NMDevice *parent)
+nm_device_vlan_set_parent (NMDeviceVlan *self, NMDevice *parent, gboolean construct)
{
- NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device);
+ NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
+ NMDevice *device = NM_DEVICE (self);
+
+ if (parent == priv->parent)
+ return;
if (priv->parent_state_id) {
g_signal_handler_disconnect (priv->parent, priv->parent_state_id);
@@ -140,10 +153,56 @@ nm_device_vlan_set_parent (NMDeviceVlan *device, NMDevice *parent)
"state-changed",
G_CALLBACK (parent_state_changed),
device);
+
+ /* Set parent-dependent unmanaged flag */
+ if (construct) {
+ nm_device_set_initial_unmanaged_flag (device,
+ NM_UNMANAGED_PARENT,
+ !nm_device_get_managed (parent));
+ } else {
+ nm_device_set_unmanaged (device,
+ NM_UNMANAGED_PARENT,
+ !nm_device_get_managed (parent),
+ NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED);
+ }
}
+
+ /* Recheck availability now that the parent has changed */
+ nm_device_queue_recheck_available (self,
+ NM_DEVICE_STATE_REASON_PARENT_CHANGED,
+ NM_DEVICE_STATE_REASON_PARENT_CHANGED);
g_object_notify (G_OBJECT (device), NM_DEVICE_VLAN_PARENT);
}
+static gboolean
+component_added (NMDevice *device, GObject *component)
+{
+ NMDeviceVlan *self = NM_DEVICE_VLAN (device);
+ NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
+ NMDevice *added_device;
+ int parent_ifindex = -1;
+
+ if (priv->parent)
+ return FALSE;
+
+ if (!NM_IS_DEVICE (component))
+ return FALSE;
+ added_device = NM_DEVICE (component);
+
+ if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, nm_device_get_ifindex (device), &parent_ifindex, NULL)) {
+ _LOGW (LOGD_VLAN, "failed to get VLAN interface info while checking added component.");
+ return FALSE;
+ }
+
+ if (nm_device_get_ifindex (added_device) != parent_ifindex)
+ return FALSE;
+
+ nm_device_vlan_set_parent (self, added_device, FALSE);
+
+ /* Don't claim parent exclusively */
+ return FALSE;
+}
+
/******************************************************************/
static gboolean
@@ -153,6 +212,9 @@ match_parent (NMDeviceVlan *self, const char *parent)
g_return_val_if_fail (parent != NULL, FALSE);
+ if (!priv->parent)
+ return FALSE;
+
if (nm_utils_is_uuid (parent)) {
NMActRequest *parent_req;
NMConnection *parent_connection;
@@ -309,8 +371,7 @@ update_connection (NMDevice *device, NMConnection *connection)
parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex);
g_assert (parent);
- if (priv->parent != parent)
- nm_device_vlan_set_parent (NM_DEVICE_VLAN (device), parent);
+ nm_device_vlan_set_parent (NM_DEVICE_VLAN (device), parent, FALSE);
/* Update parent in the connection; default to parent's interface name */
new_parent = nm_device_get_iface (parent);
@@ -426,12 +487,6 @@ constructed (GObject *object)
if (G_OBJECT_CLASS (nm_device_vlan_parent_class)->constructed)
G_OBJECT_CLASS (nm_device_vlan_parent_class)->constructed (object);
- if (!priv->parent) {
- _LOGE (LOGD_VLAN, "no parent specified.");
- priv->invalid = TRUE;
- return;
- }
-
itype = nm_platform_link_get_type (NM_PLATFORM_GET, ifindex);
if (itype != NM_LINK_TYPE_VLAN) {
_LOGE (LOGD_VLAN, "failed to get VLAN interface type.");
@@ -445,18 +500,27 @@ constructed (GObject *object)
return;
}
- if ( parent_ifindex < 0
- || parent_ifindex != nm_device_get_ip_ifindex (priv->parent)
- || vlan_id < 0) {
+ if (parent_ifindex < 0 || vlan_id < 0) {
_LOGW (LOGD_VLAN, "VLAN parent ifindex (%d) or VLAN ID (%d) invalid.",
parent_ifindex, priv->vlan_id);
priv->invalid = TRUE;
return;
}
+ if (priv->parent && parent_ifindex != nm_device_get_ip_ifindex (priv->parent)) {
+ _LOGW (LOGD_VLAN, "VLAN parent %s (%d) and parent ifindex %d don't match.",
+ nm_device_get_iface (priv->parent),
+ nm_device_get_ifindex (priv->parent),
+ parent_ifindex);
+ priv->invalid = TRUE;
+ return;
+ }
+
priv->vlan_id = vlan_id;
- _LOGI (LOGD_HW | LOGD_VLAN, "VLAN ID %d with parent %s",
- priv->vlan_id, nm_device_get_iface (priv->parent));
+ _LOGI (LOGD_HW | LOGD_VLAN, "VLAN ID %d with parent %s (%d)",
+ priv->vlan_id,
+ priv->parent ? nm_device_get_iface (priv->parent) : "unknown",
+ parent_ifindex);
}
static void
@@ -489,7 +553,7 @@ set_property (GObject *object, guint prop_id,
switch (prop_id) {
case PROP_INT_PARENT_DEVICE:
- nm_device_vlan_set_parent (NM_DEVICE_VLAN (object), g_value_get_object (value));
+ nm_device_vlan_set_parent (NM_DEVICE_VLAN (object), g_value_get_object (value), TRUE);
break;
case PROP_VLAN_ID:
priv->vlan_id = g_value_get_uint (value);
@@ -512,7 +576,7 @@ dispose (GObject *object)
}
priv->disposed = TRUE;
- nm_device_vlan_set_parent (self, NULL);
+ nm_device_vlan_set_parent (self, NULL, FALSE);
G_OBJECT_CLASS (nm_device_vlan_parent_class)->dispose (object);
}
@@ -551,6 +615,8 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass)
parent_class->act_stage1_prepare = act_stage1_prepare;
parent_class->ip4_config_pre_commit = ip4_config_pre_commit;
parent_class->deactivate = deactivate;
+ parent_class->is_available = is_available;
+ parent_class->component_added = component_added;
parent_class->check_connection_compatible = check_connection_compatible;
parent_class->complete_connection = complete_connection;
@@ -626,10 +692,6 @@ new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error)
device = NULL;
}
- /* Set initial parent-dependent unmanaged flag */
- if (device)
- nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_PARENT, !nm_device_get_managed (parent));
-
return device;
}
@@ -682,10 +744,6 @@ create_virtual_device_for_connection (NMDeviceFactory *factory,
device = NULL;
}
- /* Set initial parent-dependent unmanaged flag */
- if (device)
- nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_PARENT, !nm_device_get_managed (parent));
-
return device;
}
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index f7ba2a5296..e3daa9b615 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -237,6 +237,21 @@ typedef struct {
gboolean (* have_any_ready_slaves) (NMDevice *self,
const GSList *slaves);
+ /**
+ * component_added:
+ * @self: the #NMDevice
+ * @component: the component (device, modem, etc) which was added
+ *
+ * Notifies @self that a new component was added to the Manager. This
+ * may include any kind of %GObject subclass, and the device is expected
+ * to match only specific components they care about, like %NMModem objects
+ * or %NMDevice objects.
+ *
+ * Returns: %TRUE if the component was claimed exclusively and no further
+ * devices should be notified of the new component. %FALSE to indicate
+ * that the component was not exclusively claimed and other devices should
+ * be notified.
+ */
gboolean (* component_added) (NMDevice *self, GObject *component);
gboolean (* owns_iface) (NMDevice *self, const char *iface);
diff --git a/src/nm-manager.c b/src/nm-manager.c
index fe80156712..755b1f1916 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -1776,6 +1776,18 @@ device_ip_iface_changed (NMDevice *device,
}
}
+static gboolean
+notify_component_added (NMManager *self, GObject *component)
+{
+ GSList *iter;
+
+ for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = iter->next) {
+ if (nm_device_notify_component_added (NM_DEVICE (iter->data), component))
+ return TRUE;
+ }
+ return FALSE;
+}
+
/**
* add_device:
* @self: the #NMManager
@@ -1893,6 +1905,8 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume)
g_signal_emit (self, signals[DEVICE_ADDED], 0, device);
g_object_notify (G_OBJECT (self), NM_MANAGER_DEVICES);
+ notify_component_added (self, G_OBJECT (device));
+
/* New devices might be master interfaces for virtual interfaces; so we may
* need to create new virtual interfaces now.
*/
@@ -1929,14 +1943,7 @@ factory_component_added_cb (NMDeviceFactory *factory,
GObject *component,
gpointer user_data)
{
- NMManager *self = NM_MANAGER (user_data);
- GSList *iter;
-
- for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = iter->next) {
- if (nm_device_notify_component_added (NM_DEVICE (iter->data), component))
- return TRUE;
- }
- return FALSE;
+ return notify_component_added (NM_MANAGER (user_data), component);
}
#define PLUGIN_PREFIX "libnm-device-plugin-"