summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2020-01-15 18:30:17 +0100
committerBeniamino Galvani <bgalvani@redhat.com>2020-01-17 13:41:15 +0100
commit385c5cf5e539b196dc90ed711f27f0bf98ddcf64 (patch)
tree21d276cd61221d3f2db5671208070a3901353d2b
parentc2f8400e6606918873505280d0edff3577e7d7ab (diff)
downloadNetworkManager-bg/ovs-deactivate-async-rh1782701.tar.gz
ovs: wait that link disappears before continuing with deactivationbg/ovs-deactivate-async-rh1782701
When we deactivate a virtual device, we usually schedule the deletion of the link in an idle handler. That action will be executed at a later time when the device is already in the disconnected state. Similarly, for ovs interfaces we send the deletion command to the ovsdb and then proceed to the disconnected state. However, in the first case there is the guarantee that the link will be deleted at some point, while for ovs interfaces it may happen that ovs decides to reuse the same link if there is an addition queued. Since reusing the same link confuses NM, let's implement deactivate_async() for ovs-interfaces and wait that the link actually goes away before proceeding. https://bugzilla.redhat.com/show_bug.cgi?id=1782701
-rw-r--r--src/devices/ovs/nm-device-ovs-interface.c115
1 files changed, 115 insertions, 0 deletions
diff --git a/src/devices/ovs/nm-device-ovs-interface.c b/src/devices/ovs/nm-device-ovs-interface.c
index 726e990131..93d9864812 100644
--- a/src/devices/ovs/nm-device-ovs-interface.c
+++ b/src/devices/ovs/nm-device-ovs-interface.c
@@ -21,6 +21,7 @@ _LOG_DECLARE_SELF(NMDeviceOvsInterface);
typedef struct {
bool waiting_for_interface:1;
+ int link_ifindex;
} NMDeviceOvsInterfacePrivate;
struct _NMDeviceOvsInterface {
@@ -98,6 +99,9 @@ link_changed (NMDevice *device,
{
NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE (device);
+ if (pllink)
+ priv->link_ifindex = pllink->ifindex;
+
if ( pllink
&& priv->waiting_for_interface
&& nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG) {
@@ -153,6 +157,116 @@ deactivate (NMDevice *device)
priv->waiting_for_interface = FALSE;
}
+typedef struct {
+ NMDeviceOvsInterface *self;
+ GCancellable *cancellable;
+ NMDeviceDeactivateCallback callback;
+ gpointer callback_user_data;
+ gulong link_changed_id;
+ gulong cancelled_id;
+} DeactivateData;
+
+static void
+deactivate_invoke_cb (DeactivateData *data, GError *error)
+{
+ data->callback (NM_DEVICE (data->self),
+ error,
+ data->callback_user_data);
+
+ nm_clear_g_signal_handler (nm_device_get_platform (NM_DEVICE (data->self)),
+ &data->link_changed_id);
+ nm_clear_g_signal_handler (data->cancellable,
+ &data->cancelled_id);
+ g_object_unref (data->self);
+ g_object_unref (data->cancellable);
+ g_slice_free (DeactivateData, data);
+}
+
+static void
+link_changed_cb (NMPlatform *platform,
+ int obj_type_i,
+ int ifindex,
+ NMPlatformLink *info,
+ int change_type_i,
+ DeactivateData *data)
+{
+ NMDeviceOvsInterface *self = data->self;
+ NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE (self);
+ const NMPlatformSignalChangeType change_type = change_type_i;
+
+ if ( change_type == NM_PLATFORM_SIGNAL_REMOVED
+ && ifindex == priv->link_ifindex) {
+ _LOGT (LOGD_DEVICE,
+ "link %d gone, proceeding with deactivation",
+ priv->link_ifindex);
+ priv->link_ifindex = 0;
+ deactivate_invoke_cb (data, NULL);
+ return;
+ }
+}
+
+static void
+deactivate_cancelled_cb (GCancellable *cancellable,
+ gpointer user_data)
+{
+ gs_free_error GError *error = NULL;
+
+ nm_utils_error_set_cancelled (&error, FALSE, NULL);
+ deactivate_invoke_cb ((DeactivateData *) user_data, error);
+}
+
+static void
+deactivate_cb_on_idle (gpointer user_data,
+ GCancellable *cancellable)
+{
+ DeactivateData *data = user_data;
+ gs_free_error GError *cancelled_error = NULL;
+
+ g_cancellable_set_error_if_cancelled (data->cancellable, &cancelled_error);
+ deactivate_invoke_cb (data, cancelled_error);
+}
+
+static void
+deactivate_async (NMDevice *device,
+ GCancellable *cancellable,
+ NMDeviceDeactivateCallback callback,
+ gpointer callback_user_data) {
+
+ NMDeviceOvsInterface *self = NM_DEVICE_OVS_INTERFACE (device);
+ NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE (self);
+ DeactivateData *data;
+
+ priv->waiting_for_interface = FALSE;
+
+ data = g_slice_new (DeactivateData);
+ *data = (DeactivateData) {
+ .self = g_object_ref (self),
+ .cancellable = g_object_ref (cancellable),
+ .callback = callback,
+ .callback_user_data = callback_user_data,
+ };
+
+ if ( !priv->link_ifindex
+ || !nm_platform_link_get (nm_device_get_platform (device), priv->link_ifindex)) {
+ priv->link_ifindex = 0;
+ nm_utils_invoke_on_idle (deactivate_cb_on_idle, data, cancellable);
+ return;
+ }
+
+ _LOGT (LOGD_DEVICE,
+ "async deactivation: waiting for link %d to disappear",
+ priv->link_ifindex);
+
+ data->cancelled_id = g_cancellable_connect (cancellable,
+ G_CALLBACK (deactivate_cancelled_cb),
+ data,
+ NULL);
+ data->link_changed_id = g_signal_connect (nm_device_get_platform (device),
+ NM_PLATFORM_SIGNAL_LINK_CHANGED,
+ G_CALLBACK (link_changed_cb),
+ data);
+}
+
/*****************************************************************************/
static void
@@ -183,6 +297,7 @@ nm_device_ovs_interface_class_init (NMDeviceOvsInterfaceClass *klass)
device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_OPENVSWITCH);
device_class->deactivate = deactivate;
+ device_class->deactivate_async = deactivate_async;
device_class->get_type_description = get_type_description;
device_class->create_and_realize = create_and_realize;
device_class->get_generic_capabilities = get_generic_capabilities;