diff options
author | Beniamino Galvani <bgalvani@redhat.com> | 2020-01-15 18:30:17 +0100 |
---|---|---|
committer | Beniamino Galvani <bgalvani@redhat.com> | 2020-01-17 13:41:15 +0100 |
commit | 385c5cf5e539b196dc90ed711f27f0bf98ddcf64 (patch) | |
tree | 21d276cd61221d3f2db5671208070a3901353d2b | |
parent | c2f8400e6606918873505280d0edff3577e7d7ab (diff) | |
download | NetworkManager-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.c | 115 |
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; |