summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2022-04-27 16:27:24 +0200
committerBeniamino Galvani <bgalvani@redhat.com>2022-05-03 13:19:24 +0200
commit9fcbc6b37deccaa0bfcc9bddec726e41d5df5ced (patch)
tree6582cc920c0bbd1c4ac2d724541c89874dc216e8
parentbcc958c411287ccc650cd04bc77ac22c8fecb08c (diff)
downloadNetworkManager-9fcbc6b37deccaa0bfcc9bddec726e41d5df5ced.tar.gz
device: make attach_port() asynchronous
For some device types the attach-port operation doesn't complete immediately. NMDevice needs to wait that the operation completes before proceeding (for example, before starting stage3 for the port). Change attach_port() so that it can return TERNARY_DEFAULT to indicate that the operation will complete asynchronously. Most of devices are not affected by this and can continue returning TRUE/FALSE as before without callback.
-rw-r--r--src/core/devices/nm-device-bond.c10
-rw-r--r--src/core/devices/nm-device-bridge.c10
-rw-r--r--src/core/devices/nm-device-vrf.c10
-rw-r--r--src/core/devices/nm-device.c114
-rw-r--r--src/core/devices/nm-device.h17
-rw-r--r--src/core/devices/ovs/nm-device-ovs-bridge.c10
-rw-r--r--src/core/devices/ovs/nm-device-ovs-port.c10
-rw-r--r--src/core/devices/team/nm-device-team.c10
8 files changed, 136 insertions, 55 deletions
diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c
index 80400afcc4..d5cb158a1b 100644
--- a/src/core/devices/nm-device-bond.c
+++ b/src/core/devices/nm-device-bond.c
@@ -424,8 +424,14 @@ commit_port_options(NMDevice *bond_device, NMDevice *port, NMSettingBondPort *s_
queue_id_str);
}
-static gboolean
-attach_port(NMDevice *device, NMDevice *port, NMConnection *connection, gboolean configure)
+static NMTernary
+attach_port(NMDevice *device,
+ NMDevice *port,
+ NMConnection *connection,
+ gboolean configure,
+ GCancellable *cancellable,
+ NMDeviceAttachPortCallback callback,
+ gpointer user_data)
{
NMDeviceBond *self = NM_DEVICE_BOND(device);
NMSettingBondPort *s_port;
diff --git a/src/core/devices/nm-device-bridge.c b/src/core/devices/nm-device-bridge.c
index 796e58c650..7b7053296c 100644
--- a/src/core/devices/nm-device-bridge.c
+++ b/src/core/devices/nm-device-bridge.c
@@ -974,8 +974,14 @@ deactivate(NMDevice *device)
}
}
-static gboolean
-attach_port(NMDevice *device, NMDevice *port, NMConnection *connection, gboolean configure)
+static NMTernary
+attach_port(NMDevice *device,
+ NMDevice *port,
+ NMConnection *connection,
+ gboolean configure,
+ GCancellable *cancellable,
+ NMDeviceAttachPortCallback callback,
+ gpointer user_data)
{
NMDeviceBridge *self = NM_DEVICE_BRIDGE(device);
NMConnection *master_connection;
diff --git a/src/core/devices/nm-device-vrf.c b/src/core/devices/nm-device-vrf.c
index 6454d4d30d..2aef0e3d1e 100644
--- a/src/core/devices/nm-device-vrf.c
+++ b/src/core/devices/nm-device-vrf.c
@@ -206,8 +206,14 @@ update_connection(NMDevice *device, NMConnection *connection)
g_object_set(G_OBJECT(s_vrf), NM_SETTING_VRF_TABLE, priv->props.table, NULL);
}
-static gboolean
-attach_port(NMDevice *device, NMDevice *port, NMConnection *connection, gboolean configure)
+static NMTernary
+attach_port(NMDevice *device,
+ NMDevice *port,
+ NMConnection *connection,
+ gboolean configure,
+ GCancellable *cancellable,
+ NMDeviceAttachPortCallback callback,
+ gpointer user_data)
{
NMDeviceVrf *self = NM_DEVICE_VRF(device);
gboolean success = TRUE;
diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c
index 93f9e7fd2f..a1a024cef3 100644
--- a/src/core/devices/nm-device.c
+++ b/src/core/devices/nm-device.c
@@ -120,11 +120,12 @@ typedef enum _nm_packed {
} AddrMethodState;
typedef struct {
- CList lst_slave;
- NMDevice *slave;
- gulong watch_id;
- bool slave_is_enslaved;
- bool configure;
+ CList lst_slave;
+ NMDevice *slave;
+ GCancellable *cancellable;
+ gulong watch_id;
+ bool slave_is_enslaved;
+ bool configure;
} SlaveInfo;
typedef struct {
@@ -5927,43 +5928,16 @@ find_slave_info(NMDevice *self, NMDevice *slave)
return NULL;
}
-/**
- * nm_device_master_enslave_slave:
- * @self: the master device
- * @slave: the slave device to enslave
- * @connection: (allow-none): the slave device's connection
- *
- * If @self is capable of enslaving other devices (ie it's a bridge, bond, team,
- * etc) then this function enslaves @slave.
- *
- * Returns: %TRUE on success, %FALSE on failure or if this device cannot enslave
- * other devices.
- */
-static gboolean
-nm_device_master_enslave_slave(NMDevice *self, NMDevice *slave, NMConnection *connection)
+static void
+attach_port_done(NMDevice *self, NMDevice *slave, gboolean success)
{
SlaveInfo *info;
- gboolean success = FALSE;
- gboolean configure;
-
- g_return_val_if_fail(self != NULL, FALSE);
- g_return_val_if_fail(slave != NULL, FALSE);
- g_return_val_if_fail(NM_DEVICE_GET_CLASS(self)->attach_port != NULL, FALSE);
info = find_slave_info(self, slave);
if (!info)
- return FALSE;
-
- if (info->slave_is_enslaved)
- success = TRUE;
- else {
- configure = (info->configure && connection != NULL);
- if (configure)
- g_return_val_if_fail(nm_device_get_state(slave) >= NM_DEVICE_STATE_DISCONNECTED, FALSE);
+ return;
- success = NM_DEVICE_GET_CLASS(self)->attach_port(self, slave, connection, configure);
- info->slave_is_enslaved = success;
- }
+ info->slave_is_enslaved = success;
nm_device_slave_notify_enslave(info->slave, success);
@@ -5983,8 +5957,71 @@ nm_device_master_enslave_slave(NMDevice *self, NMDevice *slave, NMConnection *co
*/
if (success)
nm_device_activate_schedule_stage3_ip_config(self, FALSE);
+}
- return success;
+static void
+attach_port_cb(NMDevice *self, GError *error, gpointer user_data)
+{
+ NMDevice *slave = user_data;
+ SlaveInfo *info;
+
+ if (nm_utils_error_is_cancelled(error))
+ return;
+
+ info = find_slave_info(self, slave);
+ if (!info)
+ return;
+
+ nm_clear_g_cancellable(&info->cancellable);
+ attach_port_done(self, slave, !error);
+}
+
+/**
+ * nm_device_master_enslave_slave:
+ * @self: the master device
+ * @slave: the slave device to enslave
+ * @connection: (allow-none): the slave device's connection
+ *
+ * If @self is capable of enslaving other devices (ie it's a bridge, bond, team,
+ * etc) then this function enslaves @slave.
+ */
+static void
+nm_device_master_enslave_slave(NMDevice *self, NMDevice *slave, NMConnection *connection)
+{
+ SlaveInfo *info;
+ NMTernary success;
+ gboolean configure;
+
+ g_return_if_fail(self);
+ g_return_if_fail(slave);
+ g_return_if_fail(NM_DEVICE_GET_CLASS(self)->attach_port);
+
+ info = find_slave_info(self, slave);
+ if (!info)
+ return;
+
+ if (info->slave_is_enslaved)
+ success = TRUE;
+ else {
+ configure = (info->configure && connection != NULL);
+ if (configure)
+ g_return_if_fail(nm_device_get_state(slave) >= NM_DEVICE_STATE_DISCONNECTED);
+
+ nm_clear_g_cancellable(&info->cancellable);
+ info->cancellable = g_cancellable_new();
+ success = NM_DEVICE_GET_CLASS(self)->attach_port(self,
+ slave,
+ connection,
+ configure,
+ info->cancellable,
+ attach_port_cb,
+ slave);
+
+ if (success == NM_TERNARY_DEFAULT)
+ return;
+ }
+
+ attach_port_done(self, slave, success);
}
/**
@@ -6038,6 +6075,7 @@ nm_device_master_release_slave(NMDevice *self,
g_return_if_fail(self == slave_priv->master);
nm_assert(slave == info->slave);
+ nm_clear_g_cancellable(&info->cancellable);
/* first, let subclasses handle the release ... */
if (info->slave_is_enslaved || nm_device_sys_iface_state_is_external(slave)
@@ -7609,7 +7647,7 @@ nm_device_master_add_slave(NMDevice *self, NMDevice *slave, gboolean configure)
g_return_val_if_fail(NM_IS_DEVICE(self), FALSE);
g_return_val_if_fail(NM_IS_DEVICE(slave), FALSE);
- g_return_val_if_fail(NM_DEVICE_GET_CLASS(self)->attach_port != NULL, FALSE);
+ g_return_val_if_fail(NM_DEVICE_GET_CLASS(self)->attach_port, FALSE);
priv = NM_DEVICE_GET_PRIVATE(self);
slave_priv = NM_DEVICE_GET_PRIVATE(slave);
diff --git a/src/core/devices/nm-device.h b/src/core/devices/nm-device.h
index bfa274d69e..377c2fb6b8 100644
--- a/src/core/devices/nm-device.h
+++ b/src/core/devices/nm-device.h
@@ -163,6 +163,7 @@ typedef enum {
} NMDeviceCheckDevAvailableFlags;
typedef void (*NMDeviceDeactivateCallback)(NMDevice *self, GError *error, gpointer user_data);
+typedef void (*NMDeviceAttachPortCallback)(NMDevice *self, GError *error, gpointer user_data);
typedef struct _NMDeviceClass {
NMDBusObjectClass parent;
@@ -373,11 +374,17 @@ typedef struct _NMDeviceClass {
NMConnection *connection,
GError **error);
- gboolean (*attach_port)(NMDevice *self,
- NMDevice *port,
- NMConnection *connection,
- gboolean configure);
-
+ /* Attachs a port asynchronously. Returns TRUE/FALSE on immediate
+ * success/error; in such cases, the callback is not invoked. If the
+ * action couldn't be completed immediately, DEFAULT is returned and
+ * the callback will always be invoked asynchronously. */
+ NMTernary (*attach_port)(NMDevice *self,
+ NMDevice *port,
+ NMConnection *connection,
+ gboolean configure,
+ GCancellable *cancellable,
+ NMDeviceAttachPortCallback callback,
+ gpointer user_data);
void (*detach_port)(NMDevice *self, NMDevice *port, gboolean configure);
void (*parent_changed_notify)(NMDevice *self,
diff --git a/src/core/devices/ovs/nm-device-ovs-bridge.c b/src/core/devices/ovs/nm-device-ovs-bridge.c
index da0a830e5d..bea6e77bc8 100644
--- a/src/core/devices/ovs/nm-device-ovs-bridge.c
+++ b/src/core/devices/ovs/nm-device-ovs-bridge.c
@@ -78,8 +78,14 @@ act_stage3_ip_config(NMDevice *device, int addr_family)
nm_device_devip_set_state(device, addr_family, NM_DEVICE_IP_STATE_READY, NULL);
}
-static gboolean
-attach_port(NMDevice *device, NMDevice *port, NMConnection *connection, gboolean configure)
+static NMTernary
+attach_port(NMDevice *device,
+ NMDevice *port,
+ NMConnection *connection,
+ gboolean configure,
+ GCancellable *cancellable,
+ NMDeviceAttachPortCallback callback,
+ gpointer user_data)
{
if (!configure)
return TRUE;
diff --git a/src/core/devices/ovs/nm-device-ovs-port.c b/src/core/devices/ovs/nm-device-ovs-port.c
index 72c534ebf0..86f5e6bec6 100644
--- a/src/core/devices/ovs/nm-device-ovs-port.c
+++ b/src/core/devices/ovs/nm-device-ovs-port.c
@@ -115,8 +115,14 @@ set_mtu_cb(GError *error, gpointer user_data)
g_object_unref(self);
}
-static gboolean
-attach_port(NMDevice *device, NMDevice *port, NMConnection *connection, gboolean configure)
+static NMTernary
+attach_port(NMDevice *device,
+ NMDevice *port,
+ NMConnection *connection,
+ gboolean configure,
+ GCancellable *cancellable,
+ NMDeviceEnslaveSlaveCallback callback,
+ gpointer user_data)
{
NMDeviceOvsPort *self = NM_DEVICE_OVS_PORT(device);
NMActiveConnection *ac_port = NULL;
diff --git a/src/core/devices/team/nm-device-team.c b/src/core/devices/team/nm-device-team.c
index 77a259d413..1f098806d3 100644
--- a/src/core/devices/team/nm-device-team.c
+++ b/src/core/devices/team/nm-device-team.c
@@ -790,8 +790,14 @@ deactivate(NMDevice *device)
teamd_cleanup(self, TRUE);
}
-static gboolean
-attach_port(NMDevice *device, NMDevice *port, NMConnection *connection, gboolean configure)
+static NMTernary
+attach_port(NMDevice *device,
+ NMDevice *port,
+ NMConnection *connection,
+ gboolean configure,
+ GCancellable *cancellable,
+ NMDeviceAttachPortCallback callback,
+ gpointer user_data)
{
NMDeviceTeam *self = NM_DEVICE_TEAM(device);
NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self);