core: rework master/slave handling
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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 */
|
||||
|
||||
|
@@ -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_log_info (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);
|
||||
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;
|
||||
|
@@ -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,90 +384,20 @@ 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;
|
||||
|
||||
success = nm_system_bridge_attach (nm_device_get_ip_ifindex (device),
|
||||
nm_device_get_ip_iface (device),
|
||||
nm_device_get_ip_ifindex (slave),
|
||||
nm_device_get_ip_iface (slave));
|
||||
if (success) {
|
||||
SlaveInfo *sinfo;
|
||||
NMSettingBridgePort *s_port;
|
||||
const char *iface = nm_device_get_ip_iface (device);
|
||||
const char *slave_iface = nm_device_get_ip_iface (slave);
|
||||
|
||||
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);
|
||||
success = nm_system_bridge_attach (nm_device_get_ip_ifindex (device),
|
||||
iface,
|
||||
nm_device_get_ip_ifindex (slave),
|
||||
slave_iface);
|
||||
if (!success)
|
||||
return FALSE;
|
||||
|
||||
/* Set port properties */
|
||||
s_port = nm_connection_get_setting_bridge_port (connection);
|
||||
@@ -476,33 +406,26 @@ enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection)
|
||||
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_log_info (LOGD_DEVICE, "(%s): detached bridge port %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);
|
||||
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;
|
||||
|
435
src/nm-device.c
435
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 */
|
||||
/* 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);
|
||||
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),
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
||||
|
Reference in New Issue
Block a user