summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2020-01-15 18:30:17 +0100
committerThomas Haller <thaller@redhat.com>2020-08-17 17:38:43 +0200
commitcb7c7c29bdde6654b3a5d498c592033772592ad0 (patch)
tree37653994670c9fc67f7fd5919794370a49f63f53
parent34a02243bce35fb04bb53f105cf7f10e3460f9ac (diff)
downloadNetworkManager-cb7c7c29bdde6654b3a5d498c592033772592ad0.tar.gz
ovs: wait that link disappears before continuing with deactivation
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 https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/402 (cherry picked from commit 623a1e1f993b3166509202bc580c30e3daf9c67b) (cherry picked from commit a1b0edd24b078294cd3959044a7ae35287d55f87)
-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 e066977214..6768d3efc2 100644
--- a/src/devices/ovs/nm-device-ovs-interface.c
+++ b/src/devices/ovs/nm-device-ovs-interface.c
@@ -35,6 +35,7 @@ _LOG_DECLARE_SELF(NMDeviceOvsInterface);
typedef struct {
bool waiting_for_interface:1;
+ int link_ifindex;
} NMDeviceOvsInterfacePrivate;
struct _NMDeviceOvsInterface {
@@ -112,6 +113,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) {
@@ -167,6 +171,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);
+ nm_g_slice_free (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
@@ -197,6 +311,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;