diff --git a/src/nm-activation-request.c b/src/nm-activation-request.c index ce878c994..4070edbae 100644 --- a/src/nm-activation-request.c +++ b/src/nm-activation-request.c @@ -62,8 +62,7 @@ typedef struct { gulong user_uid; char *dbus_sender; - NMActiveConnection *dep; - guint dep_state_id; + NMDevice *master; gboolean shared; GSList *share_rules; @@ -75,13 +74,6 @@ enum { PROP_MASTER = 2000, }; -enum { - DEP_RESULT, - - LAST_SIGNAL -}; -static guint signals[LAST_SIGNAL] = { 0 }; - /*******************************************************************/ typedef struct { @@ -229,31 +221,10 @@ nm_act_request_get_assumed (NMActRequest *req) return NM_ACT_REQUEST_GET_PRIVATE (req)->assumed; } -NMActiveConnection * -nm_act_request_get_dependency (NMActRequest *req) +GObject * +nm_act_request_get_master (NMActRequest *req) { - return NM_ACT_REQUEST_GET_PRIVATE (req)->dep; -} - -static NMActRequestDependencyResult -ac_state_to_dep_result (NMActiveConnection *ac) -{ - NMActiveConnectionState state = nm_active_connection_get_state (ac); - - if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATING) - return NM_ACT_REQUEST_DEP_RESULT_WAIT; - else if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) - return NM_ACT_REQUEST_DEP_RESULT_READY; - - return NM_ACT_REQUEST_DEP_RESULT_FAILED; -} - -NMActRequestDependencyResult -nm_act_request_get_dependency_result (NMActRequest *req) -{ - NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (req); - - return priv->dep ? ac_state_to_dep_result (priv->dep) : NM_ACT_REQUEST_DEP_RESULT_READY; + return (GObject *) NM_ACT_REQUEST_GET_PRIVATE (req)->master; } /********************************************************************/ @@ -411,39 +382,6 @@ device_state_changed (NMDevice *device, /********************************************************************/ -static void -dep_gone (NMActRequest *self, GObject *ignored) -{ - NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (self); - - g_warn_if_fail (G_OBJECT (priv->dep) == ignored); - - /* Dependent connection is gone; clean up and fail */ - priv->dep = NULL; - priv->dep_state_id = 0; - g_signal_emit (self, signals[DEP_RESULT], 0, NM_ACT_REQUEST_DEP_RESULT_FAILED); -} - -static void -dep_state_changed (NMActiveConnection *dep, - GParamSpec *pspec, - NMActRequest *self) -{ - NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (self); - NMActRequestDependencyResult result; - - g_warn_if_fail (priv->dep == dep); - - result = ac_state_to_dep_result (priv->dep); - if (result == NM_ACT_REQUEST_DEP_RESULT_FAILED) { - g_object_weak_unref (G_OBJECT (priv->dep), (GWeakNotify) dep_gone, self); - g_signal_handler_disconnect (priv->dep, priv->dep_state_id); - priv->dep = NULL; - priv->dep_state_id = 0; - } - g_signal_emit (self, signals[DEP_RESULT], 0, result); -} - /** * nm_act_request_new: * @@ -458,9 +396,9 @@ dep_state_changed (NMActiveConnection *dep, * @assumed: pass %TRUE if the activation should "assume" (ie, taking over) an * existing connection made before this instance of NM started * @device: the device/interface to configure according to @connection - * @dependency: if the activation depends on another device (ie, VLAN slave, - * bond slave, etc) pass the #NMActiveConnection that this activation request - * should wait for before proceeding + * @master: if the activation depends on another device (ie, bond or bridge + * master to which this device will be enslaved) pass the #NMDevice that this + * activation request be enslaved to * * Begins activation of @device using the given @connection and other details. * @@ -474,7 +412,7 @@ nm_act_request_new (NMConnection *connection, const char *dbus_sender, gboolean assumed, gpointer *device, - NMActiveConnection *dependency) + gpointer *master) { GObject *object; NMActRequestPrivate *priv; @@ -500,14 +438,11 @@ nm_act_request_new (NMConnection *connection, priv->user_requested = user_requested; priv->dbus_sender = g_strdup (dbus_sender); priv->assumed = assumed; + if (master) { + g_assert (NM_IS_DEVICE (master)); + g_assert (NM_DEVICE (master) != NM_DEVICE (device)); - if (dependency) { - priv->dep = dependency; - g_object_weak_ref (G_OBJECT (dependency), (GWeakNotify) dep_gone, object); - priv->dep_state_id = g_signal_connect (dependency, - "notify::" NM_ACTIVE_CONNECTION_STATE, - G_CALLBACK (dep_state_changed), - object); + priv->master = g_object_ref (master); } if (!nm_active_connection_export (NM_ACTIVE_CONNECTION (object), @@ -530,16 +465,10 @@ get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (object); - NMDevice *master; switch (prop_id) { case PROP_MASTER: - if (priv->dep && NM_IS_ACT_REQUEST (priv->dep)) { - master = NM_DEVICE (nm_act_request_get_device (NM_ACT_REQUEST (priv->dep))); - g_assert (master); - g_value_set_boxed (value, nm_device_get_path (master)); - } else - g_value_set_boxed (value, "/"); + g_value_set_boxed (value, priv->master ? nm_device_get_path (priv->master) : "/"); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -580,12 +509,7 @@ dispose (GObject *object) g_free (priv->dbus_sender); - if (priv->dep) { - g_object_weak_unref (G_OBJECT (priv->dep), (GWeakNotify) dep_gone, object); - g_signal_handler_disconnect (priv->dep, priv->dep_state_id); - priv->dep = NULL; - priv->dep_state_id = 0; - } + g_clear_object (&priv->master); G_OBJECT_CLASS (nm_act_request_parent_class)->dispose (object); } @@ -611,13 +535,5 @@ nm_act_request_class_init (NMActRequestClass *req_class) object_class->finalize = finalize; g_object_class_override_property (object_class, PROP_MASTER, NM_ACTIVE_CONNECTION_MASTER); - - signals[DEP_RESULT] = - g_signal_new (NM_ACT_REQUEST_DEPENDENCY_RESULT, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, G_TYPE_UINT); } diff --git a/src/nm-activation-request.h b/src/nm-activation-request.h index 16bd026a7..50dc67a38 100644 --- a/src/nm-activation-request.h +++ b/src/nm-activation-request.h @@ -34,15 +34,6 @@ #define NM_IS_ACT_REQUEST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_ACT_REQUEST)) #define NM_ACT_REQUEST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_ACT_REQUEST, NMActRequestClass)) -typedef enum { - NM_ACT_REQUEST_DEP_RESULT_UNKNOWN, - NM_ACT_REQUEST_DEP_RESULT_WAIT, - NM_ACT_REQUEST_DEP_RESULT_READY, - NM_ACT_REQUEST_DEP_RESULT_FAILED, -} NMActRequestDependencyResult; - -#define NM_ACT_REQUEST_DEPENDENCY_RESULT "dependency-result" - typedef struct { GObject parent; } NMActRequest; @@ -52,8 +43,6 @@ typedef struct { /* Signals */ void (*properties_changed) (NMActRequest *req, GHashTable *properties); - - void (*dependency_result) (NMActRequest *req, NMActRequestDependencyResult result); } NMActRequestClass; GType nm_act_request_get_type (void); @@ -65,7 +54,7 @@ NMActRequest *nm_act_request_new (NMConnection *connection, const char *dbus_sender, gboolean assumed, gpointer *device, /* An NMDevice */ - NMActiveConnection *dependency); + gpointer *master); /* An NMDevice */ NMConnection *nm_act_request_get_connection (NMActRequest *req); @@ -87,9 +76,7 @@ GObject * nm_act_request_get_device (NMActRequest *req); gboolean nm_act_request_get_assumed (NMActRequest *req); -NMActiveConnection * nm_act_request_get_dependency (NMActRequest *req); - -NMActRequestDependencyResult nm_act_request_get_dependency_result (NMActRequest *req); +GObject * nm_act_request_get_master (NMActRequest *req); /* Secrets handling */ diff --git a/src/nm-device-bond.c b/src/nm-device-bond.c index ed2bbb660..600954852 100644 --- a/src/nm-device-bond.c +++ b/src/nm-device-bond.c @@ -46,7 +46,7 @@ G_DEFINE_TYPE (NMDeviceBond, nm_device_bond, NM_TYPE_DEVICE_WIRED) #define NM_BOND_ERROR (nm_bond_error_quark ()) typedef struct { - GSList *slaves; + gboolean unused; } NMDeviceBondPrivate; enum { @@ -321,118 +321,43 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) return ret; } -static void -slave_state_changed (NMDevice *slave, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason, - gpointer user_data) -{ - NMDeviceBond *self = NM_DEVICE_BOND (user_data); - - nm_log_dbg (LOGD_BOND, "(%s): slave %s state change %d -> %d", - nm_device_get_iface (NM_DEVICE (self)), - nm_device_get_iface (slave), - old_state, - new_state); - - if ( old_state > NM_DEVICE_STATE_DISCONNECTED - && new_state <= NM_DEVICE_STATE_DISCONNECTED) { - /* Slave is no longer available or managed; can't use it */ - nm_device_release_slave (NM_DEVICE (self), slave); - } -} - -typedef struct { - NMDevice *slave; - guint state_id; -} SlaveInfo; - -static SlaveInfo * -find_slave_info_by_device (NMDeviceBond *self, NMDevice *slave) -{ - NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (self); - GSList *iter; - - for (iter = priv->slaves; iter; iter = g_slist_next (iter)) { - if (((SlaveInfo *) iter->data)->slave == slave) - return iter->data; - } - return NULL; -} - -static void -free_slave_info (SlaveInfo *sinfo) -{ - g_return_if_fail (sinfo != NULL); - g_return_if_fail (sinfo->slave != NULL); - - g_signal_handler_disconnect (sinfo->slave, sinfo->state_id); - g_object_unref (sinfo->slave); - memset (sinfo, 0, sizeof (*sinfo)); - g_free (sinfo); -} - static gboolean enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection) { - NMDeviceBond *self = NM_DEVICE_BOND (device); - NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (self); gboolean success, no_firmware = FALSE; - - if (find_slave_info_by_device (self, slave)) - return TRUE; + const char *iface = nm_device_get_ip_iface (device); + const char *slave_iface = nm_device_get_ip_iface (slave); nm_device_hw_take_down (slave, TRUE); success = nm_system_bond_enslave (nm_device_get_ip_ifindex (device), - nm_device_get_ip_iface (device), + iface, nm_device_get_ip_ifindex (slave), - nm_device_get_ip_iface (slave)); - if (success) { - SlaveInfo *sinfo; - - sinfo = g_malloc0 (sizeof (*slave)); - sinfo->slave = g_object_ref (slave); - sinfo->state_id = g_signal_connect (slave, - "state-changed", - (GCallback) slave_state_changed, - self); - priv->slaves = g_slist_append (priv->slaves, sinfo); - - nm_log_dbg (LOGD_BOND, "(%s): enslaved bond slave %s", - nm_device_get_ip_iface (device), - nm_device_get_ip_iface (slave)); - g_object_notify (G_OBJECT (device), "slaves"); - } + slave_iface); nm_device_hw_bring_up (slave, TRUE, &no_firmware); + if (success) { + nm_log_info (LOGD_BOND, "(%s): enslaved bond slave %s", iface, slave_iface); + g_object_notify (G_OBJECT (device), "slaves"); + } + return success; } static gboolean release_slave (NMDevice *device, NMDevice *slave) { - NMDeviceBond *self = NM_DEVICE_BOND (device); - NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (self); gboolean success; - SlaveInfo *sinfo; - - sinfo = find_slave_info_by_device (self, slave); - if (!sinfo) - return FALSE; success = nm_system_bond_release (nm_device_get_ip_ifindex (device), nm_device_get_ip_iface (device), nm_device_get_ip_ifindex (slave), nm_device_get_ip_iface (slave)); - nm_log_dbg (LOGD_BOND, "(%s): released bond slave %s (success %d)", - nm_device_get_ip_iface (device), - nm_device_get_ip_iface (slave), - success); - priv->slaves = g_slist_remove (priv->slaves, sinfo); - free_slave_info (sinfo); + nm_log_info (LOGD_BOND, "(%s): released bond slave %s (success %d)", + nm_device_get_ip_iface (device), + nm_device_get_ip_iface (slave), + success); g_object_notify (G_OBJECT (device), "slaves"); return success; } @@ -473,12 +398,9 @@ static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMDeviceBond *self = NM_DEVICE_BOND (object); - NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (self); const guint8 *current_addr; GPtrArray *slaves; - GSList *iter; - SlaveInfo *info; + GSList *list, *iter; switch (prop_id) { case PROP_HW_ADDRESS: @@ -490,10 +412,10 @@ get_property (GObject *object, guint prop_id, break; case PROP_SLAVES: slaves = g_ptr_array_new (); - for (iter = priv->slaves; iter; iter = iter->next) { - info = iter->data; - g_ptr_array_add (slaves, g_strdup (nm_device_get_path (info->slave))); - } + list = nm_device_master_get_slaves (NM_DEVICE (object)); + for (iter = list; iter; iter = iter->next) + g_ptr_array_add (slaves, g_strdup (nm_device_get_path (NM_DEVICE (iter->data)))); + g_slist_free (list); g_value_take_boxed (value, slaves); break; default: @@ -513,21 +435,6 @@ set_property (GObject *object, guint prop_id, } } -static void -dispose (GObject *object) -{ - NMDeviceBond *self = NM_DEVICE_BOND (object); - NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (self); - GSList *iter; - - for (iter = priv->slaves; iter; iter = g_slist_next (iter)) - release_slave (NM_DEVICE (self), ((SlaveInfo *) iter->data)->slave); - g_slist_free (priv->slaves); - priv->slaves = NULL; - - G_OBJECT_CLASS (nm_device_bond_parent_class)->dispose (object); -} - static void nm_device_bond_class_init (NMDeviceBondClass *klass) { @@ -540,7 +447,6 @@ nm_device_bond_class_init (NMDeviceBondClass *klass) object_class->constructed = constructed; object_class->get_property = get_property; object_class->set_property = set_property; - object_class->dispose = dispose; parent_class->get_generic_capabilities = get_generic_capabilities; parent_class->update_hw_address = update_hw_address; diff --git a/src/nm-device-bridge.c b/src/nm-device-bridge.c index 3c54cb000..35ff2af26 100644 --- a/src/nm-device-bridge.c +++ b/src/nm-device-bridge.c @@ -46,7 +46,7 @@ G_DEFINE_TYPE (NMDeviceBridge, nm_device_bridge, NM_TYPE_DEVICE_WIRED) #define NM_BRIDGE_ERROR (nm_bridge_error_quark ()) typedef struct { - GSList *slaves; + gboolean unused; } NMDeviceBridgePrivate; enum { @@ -384,125 +384,48 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) return ret; } -static void -slave_state_changed (NMDevice *slave, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason, - gpointer user_data) -{ - NMDeviceBridge *self = NM_DEVICE_BRIDGE (user_data); - - nm_log_dbg (LOGD_DEVICE, "(%s): slave %s state change %d -> %d", - nm_device_get_iface (NM_DEVICE (self)), - nm_device_get_iface (slave), - old_state, - new_state); - - if ( old_state > NM_DEVICE_STATE_DISCONNECTED - && new_state <= NM_DEVICE_STATE_DISCONNECTED) { - /* Slave is no longer available or managed; can't use it */ - nm_device_release_slave (NM_DEVICE (self), slave); - } -} - -typedef struct { - NMDevice *slave; - guint state_id; -} SlaveInfo; - -static SlaveInfo * -find_slave_info_by_device (NMDeviceBridge *self, NMDevice *slave) -{ - NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_GET_PRIVATE (self); - GSList *iter; - - for (iter = priv->slaves; iter; iter = g_slist_next (iter)) { - if (((SlaveInfo *) iter->data)->slave == slave) - return iter->data; - } - return NULL; -} - -static void -free_slave_info (SlaveInfo *sinfo) -{ - g_return_if_fail (sinfo != NULL); - g_return_if_fail (sinfo->slave != NULL); - - g_signal_handler_disconnect (sinfo->slave, sinfo->state_id); - g_object_unref (sinfo->slave); - memset (sinfo, 0, sizeof (*sinfo)); - g_free (sinfo); -} - static gboolean enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection) { - NMDeviceBridge *self = NM_DEVICE_BRIDGE (device); - NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_GET_PRIVATE (self); gboolean success; - - if (find_slave_info_by_device (self, slave)) - return TRUE; + NMSettingBridgePort *s_port; + const char *iface = nm_device_get_ip_iface (device); + const char *slave_iface = nm_device_get_ip_iface (slave); success = nm_system_bridge_attach (nm_device_get_ip_ifindex (device), - nm_device_get_ip_iface (device), + iface, nm_device_get_ip_ifindex (slave), - nm_device_get_ip_iface (slave)); - if (success) { - SlaveInfo *sinfo; - NMSettingBridgePort *s_port; - const char *slave_iface = nm_device_get_ip_iface (slave); + slave_iface); + if (!success) + return FALSE; - sinfo = g_malloc0 (sizeof (*slave)); - sinfo->slave = g_object_ref (slave); - sinfo->state_id = g_signal_connect (slave, - "state-changed", - (GCallback) slave_state_changed, - self); - priv->slaves = g_slist_append (priv->slaves, sinfo); - - nm_log_dbg (LOGD_DEVICE, "(%s): attached bridge component %s", - nm_device_get_ip_iface (device), - nm_device_get_ip_iface (slave)); - - g_object_notify (G_OBJECT (device), NM_DEVICE_BRIDGE_SLAVES); - - /* Set port properties */ - s_port = nm_connection_get_setting_bridge_port (connection); - if (s_port) { - set_sysfs_uint (slave_iface, G_OBJECT (s_port), NM_SETTING_BRIDGE_PORT_PRIORITY, "priority", TRUE, FALSE); - set_sysfs_uint (slave_iface, G_OBJECT (s_port), NM_SETTING_BRIDGE_PORT_PATH_COST, "path_cost", TRUE, FALSE); - set_sysfs_uint (slave_iface, G_OBJECT (s_port), NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, "hairpin_mode", FALSE, FALSE); - } + /* Set port properties */ + s_port = nm_connection_get_setting_bridge_port (connection); + if (s_port) { + set_sysfs_uint (slave_iface, G_OBJECT (s_port), NM_SETTING_BRIDGE_PORT_PRIORITY, "priority", TRUE, FALSE); + set_sysfs_uint (slave_iface, G_OBJECT (s_port), NM_SETTING_BRIDGE_PORT_PATH_COST, "path_cost", TRUE, FALSE); + set_sysfs_uint (slave_iface, G_OBJECT (s_port), NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, "hairpin_mode", FALSE, FALSE); } - return success; + nm_log_info (LOGD_DEVICE, "(%s): attached bridge port %s", iface, slave_iface); + + g_object_notify (G_OBJECT (device), NM_DEVICE_BRIDGE_SLAVES); + return TRUE; } static gboolean release_slave (NMDevice *device, NMDevice *slave) { - NMDeviceBridge *self = NM_DEVICE_BRIDGE (device); - NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_GET_PRIVATE (self); gboolean success; - SlaveInfo *sinfo; - - sinfo = find_slave_info_by_device (self, slave); - if (!sinfo) - return FALSE; success = nm_system_bridge_detach (nm_device_get_ip_ifindex (device), nm_device_get_ip_iface (device), nm_device_get_ip_ifindex (slave), nm_device_get_ip_iface (slave)); - nm_log_dbg (LOGD_DEVICE, "(%s): detached bridge component %s (success %d)", - nm_device_get_ip_iface (device), - nm_device_get_ip_iface (slave), - success); - priv->slaves = g_slist_remove (priv->slaves, sinfo); - free_slave_info (sinfo); + nm_log_info (LOGD_DEVICE, "(%s): detached bridge port %s (success %d)", + nm_device_get_ip_iface (device), + nm_device_get_ip_iface (slave), + success); g_object_notify (G_OBJECT (device), NM_DEVICE_BRIDGE_SLAVES); return success; } @@ -543,12 +466,9 @@ static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMDeviceBridge *self = NM_DEVICE_BRIDGE (object); - NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_GET_PRIVATE (self); const guint8 *current_addr; GPtrArray *slaves; - GSList *iter; - SlaveInfo *info; + GSList *list, *iter; switch (prop_id) { case PROP_HW_ADDRESS: @@ -560,10 +480,10 @@ get_property (GObject *object, guint prop_id, break; case PROP_SLAVES: slaves = g_ptr_array_new (); - for (iter = priv->slaves; iter; iter = iter->next) { - info = iter->data; - g_ptr_array_add (slaves, g_strdup (nm_device_get_path (info->slave))); - } + list = nm_device_master_get_slaves (NM_DEVICE (object)); + for (iter = list; iter; iter = iter->next) + g_ptr_array_add (slaves, g_strdup (nm_device_get_path (NM_DEVICE (iter->data)))); + g_slist_free (list); g_value_take_boxed (value, slaves); break; default: @@ -583,21 +503,6 @@ set_property (GObject *object, guint prop_id, } } -static void -dispose (GObject *object) -{ - NMDeviceBridge *self = NM_DEVICE_BRIDGE (object); - NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_GET_PRIVATE (self); - GSList *iter; - - for (iter = priv->slaves; iter; iter = g_slist_next (iter)) - release_slave (NM_DEVICE (self), ((SlaveInfo *) iter->data)->slave); - g_slist_free (priv->slaves); - priv->slaves = NULL; - - G_OBJECT_CLASS (nm_device_bridge_parent_class)->dispose (object); -} - static void nm_device_bridge_class_init (NMDeviceBridgeClass *klass) { @@ -610,7 +515,6 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *klass) object_class->constructed = constructed; object_class->get_property = get_property; object_class->set_property = set_property; - object_class->dispose = dispose; parent_class->get_generic_capabilities = get_generic_capabilities; parent_class->update_hw_address = update_hw_address; diff --git a/src/nm-device.c b/src/nm-device.c index 86e5ffd88..53c4e29ed 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -149,6 +149,12 @@ typedef struct { guint id; } QueuedState; +typedef struct { + NMDevice *slave; + gboolean enslaved; + guint watch_id; +} SlaveInfo; + typedef struct { gboolean disposed; gboolean initialized; @@ -181,8 +187,6 @@ typedef struct { gpointer act_source_func; guint act_source6_id; gpointer act_source6_func; - guint act_dep_result_id; - guint act_dep_timeout_id; gulong secrets_updated_id; gulong secrets_failed_id; @@ -241,8 +245,12 @@ typedef struct { /* allow autoconnect feature */ gboolean autoconnect; - /* master interface for bridge, bond, vlan, etc */ - NMDevice * master; + /* master interface for bridge/bond slave */ + NMDevice * master; + gboolean enslaved; + + /* list of SlaveInfo for bond/bridge master */ + GSList * slaves; NMConnectionProvider *con_provider; @@ -281,6 +289,8 @@ static void cp_connections_loaded (NMConnectionProvider *cp, NMConnection *conne static void cp_connection_removed (NMConnectionProvider *cp, NMConnection *connection, gpointer user_data); static void cp_connection_updated (NMConnectionProvider *cp, NMConnection *connection, gpointer user_data); +static const char *state_to_string (NMDeviceState state); + static void nm_device_init (NMDevice *self) { @@ -762,6 +772,30 @@ nm_device_get_connection_provider (NMDevice *device) return NM_DEVICE_GET_PRIVATE (device)->con_provider; } +static SlaveInfo * +find_slave_info (NMDevice *self, NMDevice *slave) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + SlaveInfo *info; + GSList *iter; + + for (iter = priv->slaves; iter; iter = g_slist_next (iter)) { + info = iter->data; + if (info->slave == slave) + return info; + } + return NULL; +} + +static void +free_slave_info (SlaveInfo *info) +{ + g_signal_handler_disconnect (info->slave, info->watch_id); + g_clear_object (&info->slave); + memset (info, 0, sizeof (*info)); + g_free (info); +} + /** * nm_device_enslave_slave: * @dev: the master device @@ -774,22 +808,35 @@ nm_device_get_connection_provider (NMDevice *device) * Returns: %TRUE on success, %FALSE on failure or if this device cannot enslave * other devices. */ -gboolean +static gboolean nm_device_enslave_slave (NMDevice *dev, NMDevice *slave, NMConnection *connection) { + SlaveInfo *info; + gboolean success = FALSE; + g_return_val_if_fail (dev != NULL, FALSE); g_return_val_if_fail (slave != NULL, FALSE); g_return_val_if_fail (nm_device_get_state (slave) >= NM_DEVICE_STATE_DISCONNECTED, FALSE); + g_return_val_if_fail (NM_DEVICE_GET_CLASS (dev)->enslave_slave != NULL, FALSE); - if (NM_DEVICE_GET_CLASS (dev)->enslave_slave) - return NM_DEVICE_GET_CLASS (dev)->enslave_slave (dev, slave, connection); - return FALSE; + info = find_slave_info (dev, slave); + if (!info) + return FALSE; + + g_warn_if_fail (info->enslaved == FALSE); + success = NM_DEVICE_GET_CLASS (dev)->enslave_slave (dev, slave, connection); + if (success) { + info->enslaved = TRUE; + nm_device_slave_notify_enslaved (info->slave, TRUE, FALSE); + } + return success; } /** - * nm_device_release_slave: + * nm_device_release_one_slave: * @dev: the master device * @slave: the slave device to release + * @failed: %TRUE if the release was unexpected, ie the master failed * * If @dev is capable of enslaving other devices (ie it's a bridge, bond, etc) * then this function releases the previously enslaved @slave. @@ -797,15 +844,197 @@ nm_device_enslave_slave (NMDevice *dev, NMDevice *slave, NMConnection *connectio * Returns: %TRUE on success, %FALSE on failure, if this device cannot enslave * other devices, or if @slave was never enslaved. */ -gboolean -nm_device_release_slave (NMDevice *dev, NMDevice *slave) +static gboolean +nm_device_release_one_slave (NMDevice *dev, NMDevice *slave, gboolean failed) { + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (dev); + SlaveInfo *info; + gboolean success = FALSE; + + g_return_val_if_fail (slave != NULL, FALSE); + g_return_val_if_fail (NM_DEVICE_GET_CLASS (dev)->release_slave != NULL, FALSE); + + info = find_slave_info (dev, slave); + if (!info) + return FALSE; + + if (info->enslaved) { + success = NM_DEVICE_GET_CLASS (dev)->release_slave (dev, slave); + g_warn_if_fail (success); + } + nm_device_slave_notify_enslaved (info->slave, FALSE, failed); + + priv->slaves = g_slist_remove (priv->slaves, info); + free_slave_info (info); + return success; +} + +static void +slave_state_changed (NMDevice *slave, + NMDeviceState slave_new_state, + NMDeviceState slave_old_state, + NMDeviceStateReason reason, + NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + gboolean release = FALSE; + + nm_log_dbg (LOGD_DEVICE, "(%s): slave %s state change %d (%s) -> %d (%s)", + nm_device_get_iface (self), + nm_device_get_iface (slave), + slave_old_state, + state_to_string (slave_old_state), + slave_new_state, + state_to_string (slave_new_state)); + + g_assert (priv->state > NM_DEVICE_STATE_DISCONNECTED); + g_assert (priv->state <= NM_DEVICE_STATE_ACTIVATED); + + /* Don't try to enslave slaves until the master is ready */ + if (priv->state < NM_DEVICE_STATE_CONFIG) + return; + + if (slave_new_state == NM_DEVICE_STATE_IP_CONFIG) + nm_device_enslave_slave (self, slave, nm_device_get_connection (slave)); + else if (slave_new_state > NM_DEVICE_STATE_ACTIVATED) + release = TRUE; + else if ( slave_new_state <= NM_DEVICE_STATE_DISCONNECTED + && slave_old_state > NM_DEVICE_STATE_DISCONNECTED) { + /* Catch failures due to unavailable or unmanaged */ + release = TRUE; + } + + if (release) { + nm_device_release_one_slave (self, slave, FALSE); + if (priv->slaves == NULL) { + /* FIXME: all slaves gone; do something? */ + } + } +} + +/** + * nm_device_master_add_slave: + * @dev: the master device + * @slave: the slave device to enslave + * + * If @dev is capable of enslaving other devices (ie it's a bridge, bond, etc) + * then this function adds @slave to the slave list for later enslavement. + * + * Returns: %TRUE on success, %FALSE on failure + */ +gboolean +nm_device_master_add_slave (NMDevice *dev, NMDevice *slave) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (dev); + SlaveInfo *info; + g_return_val_if_fail (dev != NULL, FALSE); g_return_val_if_fail (slave != NULL, FALSE); + g_return_val_if_fail (nm_device_get_state (slave) >= NM_DEVICE_STATE_DISCONNECTED, FALSE); + g_return_val_if_fail (NM_DEVICE_GET_CLASS (dev)->enslave_slave != NULL, FALSE); - if (NM_DEVICE_GET_CLASS (dev)->release_slave) - return NM_DEVICE_GET_CLASS (dev)->release_slave (dev, slave); - return FALSE; + if (!find_slave_info (dev, slave)) { + info = g_malloc0 (sizeof (SlaveInfo)); + info->slave = g_object_ref (slave); + info->watch_id = g_signal_connect (slave, "state-changed", + G_CALLBACK (slave_state_changed), dev); + priv->slaves = g_slist_prepend (priv->slaves, info); + } + + return TRUE; +} + + +/** + * nm_device_master_get_slaves: + * @dev: the master device + * + * Returns: any slaves of which @device is the master. Caller owns returned list. + */ +GSList * +nm_device_master_get_slaves (NMDevice *dev) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (dev); + GSList *slaves = NULL, *iter; + + for (iter = priv->slaves; iter; iter = g_slist_next (iter)) + slaves = g_slist_prepend (slaves, ((SlaveInfo *) iter->data)->slave); + + return slaves; +} + +/* release all slaves */ +static void +nm_device_master_release_slaves (NMDevice *self, gboolean failed) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + GSList *iter; + + for (iter = priv->slaves; iter; iter = g_slist_next (iter)) + nm_device_release_one_slave (self, ((SlaveInfo *) iter->data)->slave, failed); + g_slist_free (priv->slaves); + priv->slaves = NULL; +} + + +/** + * nm_device_slave_notify_enslaved: + * @dev: the slave device + * @enslaved: %TRUE if the device is now enslaved, %FALSE if released + * @master_failed: if released, indicates whether the release was unexpected, + * ie the master device failed. + * + * Notifies a slave that it has been enslaved or released. If released, provides + * information on whether the release was expected or not, and thus whether the + * slave should fail it's activation or gracefully deactivate. + */ +void +nm_device_slave_notify_enslaved (NMDevice *dev, + gboolean enslaved, + gboolean master_failed) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (dev); + NMConnection *connection = nm_device_get_connection (dev); + + g_assert (priv->master); + + if (enslaved) { + g_warn_if_fail (priv->enslaved == FALSE); + g_warn_if_fail (priv->state == NM_DEVICE_STATE_IP_CONFIG); + + nm_log_info (LOGD_DEVICE, + "Activation (%s) connection '%s' enslaved, continuing activation", + nm_device_get_iface (dev), + nm_connection_get_id (connection)); + + /* Now that we're enslaved, proceed with activation. Remember, slaves + * don't have any IP configuration, so they skip directly to SECONDARIES. + */ + priv->enslaved = TRUE; + priv->ip4_state = IP_DONE; + priv->ip6_state = IP_DONE; + nm_device_queue_state (dev, NM_DEVICE_STATE_SECONDARIES, NM_DEVICE_STATE_REASON_NONE); + } else { + NMDeviceState new_state = NM_DEVICE_STATE_DISCONNECTED; + NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; + + if (master_failed) { + new_state = NM_DEVICE_STATE_FAILED; + reason = NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED; + + nm_log_warn (LOGD_DEVICE, + "Activation (%s) connection '%s' master failed", + nm_device_get_iface (dev), + nm_connection_get_id (connection)); + } else { + nm_log_dbg (LOGD_DEVICE, + "Activation (%s) connection '%s' master deactivated", + nm_device_get_iface (dev), + nm_connection_get_id (connection)); + } + + nm_device_queue_state (dev, new_state, reason); + } } /* @@ -1097,26 +1326,7 @@ ip6_method_matches (NMConnection *connection, const char *match) static NMActStageReturn act_stage1_prepare (NMDevice *self, NMDeviceStateReason *reason) { - NMActRequest *req; - NMActiveConnection *master_ac; - NMDevice *master; - NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; - - req = nm_device_get_act_request (self); - g_assert (req); - - /* If the interface is going to be a slave, let the master enslave it here */ - master_ac = nm_act_request_get_dependency (req); - if (master_ac && NM_IS_ACT_REQUEST (master_ac)) { - /* FIXME: handle VPNs here too */ - - master = NM_DEVICE (nm_act_request_get_device (NM_ACT_REQUEST (master_ac))); - g_assert (master); - if (!nm_device_enslave_slave (master, self, nm_act_request_get_connection (req))) - ret = NM_ACT_STAGE_RETURN_FAILURE; - } - - return ret; + return NM_ACT_STAGE_RETURN_SUCCESS; } /* @@ -1137,11 +1347,6 @@ nm_device_activate_stage1_device_prepare (gpointer user_data) /* Clear the activation source ID now that this stage has run */ activation_source_clear (self, FALSE, 0); - if (priv->act_dep_timeout_id) { - g_source_remove (priv->act_dep_timeout_id); - priv->act_dep_timeout_id = 0; - } - priv->ip4_state = priv->ip6_state = IP_NONE; iface = nm_device_get_iface (self); @@ -1190,6 +1395,17 @@ nm_device_activate_schedule_stage1_device_prepare (NMDevice *self) static NMActStageReturn act_stage2_config (NMDevice *dev, NMDeviceStateReason *reason) { + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (dev); + GSList *iter; + + /* If we have slaves that aren't yet enslaved, do that now */ + for (iter = priv->slaves; iter; iter = g_slist_next (iter)) { + SlaveInfo *info = iter->data; + + if (nm_device_get_state (info->slave) == NM_DEVICE_STATE_IP_CONFIG) + nm_device_enslave_slave (dev, info->slave, nm_device_get_connection (info->slave)); + } + /* Nothing to do */ return NM_ACT_STAGE_RETURN_SUCCESS; } @@ -2451,6 +2667,7 @@ nm_device_activate_stage3_ip_config_start (gpointer user_data) NMIP4Config *ip4_config = NULL; NMIP6Config *ip6_config = NULL; int ifindex; + NMDevice *master; /* Clear the activation source ID now that this stage has run */ activation_source_clear (self, FALSE, 0); @@ -2466,6 +2683,26 @@ nm_device_activate_stage3_ip_config_start (gpointer user_data) priv->ip4_state = priv->ip6_state = IP_CONF; + /* If the device is a slave, then we don't do any IP configuration but we + * use the IP config stage to indicate to the master we're ready for + * enslavement. Either the master has already enslaved us, in which case + * our state transition to SECONDARIES is already queued courtesy of + * nm_device_slave_notify_enslaved(), or the master is still activating, + * in which case we postpone activation here until the master enslaves us, + * which calls nm_device_slave_notify_enslaved(). + */ + master = (NMDevice *) nm_act_request_get_master (priv->act_request); + if (master) { + if (priv->enslaved == FALSE) { + nm_log_info (LOGD_DEVICE, "Activation (%s) connection '%s' waiting on master '%s'", + nm_device_get_iface (self), + nm_connection_get_id (nm_device_get_connection (self)), + nm_device_get_iface (master)); + } + goto out; + } + + /* IPv4 */ ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip4_config_start (self, &ip4_config, &reason); if (ret == NM_ACT_STAGE_RETURN_SUCCESS) { g_assert (ip4_config); @@ -2480,6 +2717,7 @@ nm_device_activate_stage3_ip_config_start (gpointer user_data) } else g_assert (ret == NM_ACT_STAGE_RETURN_POSTPONE); + /* IPv6 */ ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip6_config_start (self, &ip6_config, &reason); if (ret == NM_ACT_STAGE_RETURN_SUCCESS) { g_assert (ip6_config); @@ -2496,16 +2734,6 @@ nm_device_activate_stage3_ip_config_start (gpointer user_data) out: nm_log_info (LOGD_DEVICE, "Activation (%s) Stage 3 of 5 (IP Configure Start) complete.", iface); - - /* Handle interfaces (bond slaves, etc) that won't have any IP config; they - * need to move to SECONDARIES. - */ - if (priv->ip4_state == IP_DONE && priv->ip6_state == IP_DONE) { - /* FIXME: call layer2 stuff to set MTU? */ - - nm_device_state_changed (self, NM_DEVICE_STATE_SECONDARIES, NM_DEVICE_STATE_REASON_NONE); - } - return FALSE; } @@ -3250,15 +3478,6 @@ nm_device_deactivate (NMDevice *self, NMDeviceStateReason reason) activation_source_clear (self, TRUE, AF_INET); activation_source_clear (self, TRUE, AF_INET6); - if (priv->act_dep_result_id) { - g_source_remove (priv->act_dep_result_id); - priv->act_dep_result_id = 0; - } - if (priv->act_dep_timeout_id) { - g_source_remove (priv->act_dep_timeout_id); - priv->act_dep_timeout_id = 0; - } - /* Clear any queued transitions */ nm_device_queued_state_clear (self); @@ -3284,6 +3503,13 @@ nm_device_deactivate (NMDevice *self, NMDeviceStateReason reason) if (NM_DEVICE_GET_CLASS (self)->deactivate) NM_DEVICE_GET_CLASS (self)->deactivate (self); + /* master: release slaves */ + g_clear_object (&priv->master); + nm_device_master_release_slaves (self, FALSE); + + /* slave: mark no longer enslaved */ + priv->enslaved = FALSE; + /* Tear down an existing activation request */ clear_act_request (self); @@ -3353,61 +3579,6 @@ impl_device_disconnect (NMDevice *device, DBusGMethodInvocation *context) NULL); } -static gboolean -act_dep_timeout_cb (gpointer user_data) -{ - NMDevice *self = NM_DEVICE (user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMConnection *connection; - - connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (priv->act_request)); - nm_log_warn (LOGD_DEVICE, - "Activation (%s) connection '%s' dependency timed out", - nm_device_get_iface (self), - nm_connection_get_id (connection)); - - nm_device_queue_state (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED); - return FALSE; -} - -static void -act_dep_result_cb (NMActRequest *req, - NMActRequestDependencyResult result, - NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMConnection *connection; - - connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (priv->act_request)); - - switch (result) { - case NM_ACT_REQUEST_DEP_RESULT_FAILED: - g_source_remove (priv->act_dep_result_id); - priv->act_dep_result_id = 0; - - nm_log_warn (LOGD_DEVICE, - "Activation (%s) connection '%s' dependency failed", - nm_device_get_iface (self), - nm_connection_get_id (connection)); - nm_device_queue_state (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED); - break; - case NM_ACT_REQUEST_DEP_RESULT_READY: - g_warn_if_fail (priv->state == NM_DEVICE_STATE_PREPARE); - if (priv->state == NM_DEVICE_STATE_PREPARE) { - nm_log_info (LOGD_DEVICE, - "Activation (%s) connection '%s' dependency ready, continuing activation", - nm_device_get_iface (self), - nm_connection_get_id (connection)); - nm_device_activate_schedule_stage1_device_prepare (self); - } - break; - case NM_ACT_REQUEST_DEP_RESULT_WAIT: - default: - g_assert_not_reached (); - break; - } -} - void nm_device_activate (NMDevice *self, NMActRequest *req) { @@ -3441,8 +3612,7 @@ nm_device_activate (NMDevice *self, NMActRequest *req) nm_device_state_changed (self, NM_DEVICE_STATE_IP_CONFIG, NM_DEVICE_STATE_REASON_NONE); nm_device_activate_schedule_stage3_ip_config_start (self); } else { - NMActiveConnection *dep_ac; - NMConnection *dep_con; + NMDevice *master; /* HACK: update the state a bit early to avoid a race between the * scheduled stage1 handler and nm_policy_device_change_check() thinking @@ -3452,33 +3622,17 @@ nm_device_activate (NMDevice *self, NMActRequest *req) nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE); /* Handle any dependencies this connection might have */ - switch (nm_act_request_get_dependency_result (priv->act_request)) { - case NM_ACT_REQUEST_DEP_RESULT_FAILED: - nm_device_queue_state (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED); - break; - case NM_ACT_REQUEST_DEP_RESULT_WAIT: - dep_ac = nm_act_request_get_dependency (priv->act_request); - g_assert (dep_ac); - dep_con = nm_active_connection_get_connection (dep_ac); - g_assert (dep_con); - nm_log_info (LOGD_DEVICE, "Activation (%s) connection '%s' waiting on dependency '%s'", - nm_device_get_iface (self), - nm_connection_get_id (connection), - nm_connection_get_id (dep_con)); + master = (NMDevice *) nm_act_request_get_master (req); + if (master) { + /* Master should at least already be activating */ + g_assert (nm_device_get_state (master) > NM_DEVICE_STATE_DISCONNECTED); - priv->act_dep_result_id = g_signal_connect (priv->act_request, - NM_ACT_REQUEST_DEPENDENCY_RESULT, - G_CALLBACK (act_dep_result_cb), - self); - priv->act_dep_timeout_id = g_timeout_add_seconds (60, act_dep_timeout_cb, self); - break; - default: - g_warn_if_reached (); - /* fall through */ - case NM_ACT_REQUEST_DEP_RESULT_READY: - nm_device_activate_schedule_stage1_device_prepare (self); - break; + g_assert (priv->master == NULL); + priv->master = g_object_ref (master); + nm_device_master_add_slave (master, self); } + + nm_device_activate_schedule_stage1_device_prepare (self); } } @@ -3821,6 +3975,8 @@ dispose (GObject *object) addrconf6_cleanup (self); dnsmasq_cleanup (self); + g_warn_if_fail (priv->slaves == NULL); + /* Take the device itself down and clear its IPv4 configuration */ if (priv->managed && take_down) { NMDeviceStateReason ignored = NM_DEVICE_STATE_REASON_NONE; @@ -4668,6 +4824,9 @@ nm_device_state_changed (NMDevice *device, nm_device_get_iface (device), nm_connection_get_id (connection)); + /* Notify any slaves of the unexpected failure */ + nm_device_master_release_slaves (device, TRUE); + /* If the connection doesn't yet have a timestamp, set it to zero so that * we can distinguish between connections we've tried to activate and have * failed (zero timestamp), connections that succeeded (non-zero timestamp), diff --git a/src/nm-device.h b/src/nm-device.h index ba3dc8f27..10a6e2105 100644 --- a/src/nm-device.h +++ b/src/nm-device.h @@ -217,8 +217,14 @@ NMDHCP6Config * nm_device_get_dhcp6_config (NMDevice *dev); NMIP4Config * nm_device_get_ip4_config (NMDevice *dev); NMIP6Config * nm_device_get_ip6_config (NMDevice *dev); -gboolean nm_device_enslave_slave (NMDevice *dev, NMDevice *slave, NMConnection *connection); -gboolean nm_device_release_slave (NMDevice *dev, NMDevice *slave); +/* Master */ +gboolean nm_device_master_add_slave (NMDevice *dev, NMDevice *slave); +GSList * nm_device_master_get_slaves (NMDevice *dev); + +/* Slave */ +void nm_device_slave_notify_enslaved (NMDevice *dev, + gboolean enslaved, + gboolean master_failed); NMActRequest * nm_device_get_act_request (NMDevice *dev); NMConnection * nm_device_get_connection (NMDevice *dev); diff --git a/src/nm-manager.c b/src/nm-manager.c index bddc69262..a600e2524 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -2289,6 +2289,7 @@ internal_activate_device (NMManager *manager, GError **error) { NMActRequest *req; + NMDevice *master_device = NULL; g_return_val_if_fail (NM_IS_MANAGER (manager), NULL); g_return_val_if_fail (NM_IS_DEVICE (device), NULL); @@ -2307,6 +2308,9 @@ internal_activate_device (NMManager *manager, NM_DEVICE_STATE_REASON_NONE); } + if (master) + master_device = (NMDevice *) nm_act_request_get_device (NM_ACT_REQUEST (master)); + req = nm_act_request_new (connection, specific_object, user_requested, @@ -2314,7 +2318,7 @@ internal_activate_device (NMManager *manager, dbus_sender, assumed, (gpointer) device, - master); + (gpointer) master_device); nm_device_activate (device, req); g_object_unref (req);