summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2014-03-31 23:48:00 -0500
committerDan Williams <dcbw@redhat.com>2014-03-31 23:48:00 -0500
commit7c328ec19926d4ecd3e4b174d5af67e539c5922a (patch)
tree81316a1b3e7bf27d66385e74938d5bc329f07e1e
parent06412329ae92f0f6a3cf103150561fbeb2f8c69e (diff)
downloadNetworkManager-dcbw/external-ifaces.tar.gz
core: wait to manage !IFF_UP software devices until they come up (rh #1030947)dcbw/external-ifaces
NM sets a device IFF_UP when it manages the device, to ensure things like link detection work and that firmware is loaded for the device. Unfortunately, this prevents adding bridge ports or bond slaves outside NetworkManager if the bridge/bond was created outside NM. Since we'd really like to cooperate better with external changes, don't begin to manage the interface until it's set IFF_UP (and thus actually usable) by whatever created it.
-rw-r--r--src/devices/nm-device.c20
-rw-r--r--src/devices/nm-device.h8
-rw-r--r--src/nm-manager.c118
3 files changed, 104 insertions, 42 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 430363495f..4b23d8b777 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -105,6 +105,7 @@ enum {
IP6_CONFIG_CHANGED,
REMOVED,
RECHECK_AUTO_ACTIVATE,
+ ADMIN_UP,
LAST_SIGNAL,
};
static guint signals[LAST_SIGNAL] = { 0 };
@@ -235,6 +236,7 @@ typedef struct {
gpointer act_source6_func;
/* Link stuff */
+ gboolean admin_up; /* IFF_UP */
guint link_connected_id;
guint link_disconnected_id;
guint carrier_defer_id;
@@ -1196,6 +1198,15 @@ link_changed_cb (NMPlatform *platform, int ifindex, NMPlatformLink *info, NMPlat
if (klass->link_changed)
klass->link_changed (device, info);
+ if (priv->admin_up != info->up) {
+ priv->admin_up = info->up;
+
+ /* If this is the first time a device that we're waiting to come up
+ * has come up, notify the manager.
+ */
+ if (priv->admin_up && !nm_device_get_managed_flag (device, NM_MANAGED_ADMIN_UP))
+ g_signal_emit (device, signals[ADMIN_UP], 0);
+ }
} else if (priv->ip_iface && ifindex == nm_device_get_ip_ifindex (device)) {
if (info->name[0] && strcmp (priv->ip_iface, info->name)) {
nm_log_info (LOGD_DEVICE, "(%s): interface index %d renamed ip_iface (%d) from '%s' to '%s'",
@@ -6376,6 +6387,13 @@ nm_device_class_init (NMDeviceClass *klass)
0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
+ signals[ADMIN_UP] =
+ g_signal_new (NM_DEVICE_ADMIN_UP,
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
+
nm_dbus_manager_register_exported_type (nm_dbus_manager_get (),
G_TYPE_FROM_CLASS (klass),
&dbus_glib_nm_device_object_info);
@@ -7165,6 +7183,8 @@ nm_device_get_managed_flag (NMDevice *device, NMManagedFlags flag)
return FALSE;
else if (!(priv->managed_flags & NM_MANAGED_USER))
return FALSE;
+ else if (!(priv->managed_flags & NM_MANAGED_ADMIN_UP))
+ return FALSE;
else if (!(priv->managed_flags & NM_MANAGED_DEFAULT))
return (priv->state != NM_DEVICE_STATE_UNMANAGED);
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index 35f0f49240..9ca1b5b3df 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -76,6 +76,7 @@
#define NM_DEVICE_IP6_CONFIG_CHANGED "ip6-config-changed"
#define NM_DEVICE_REMOVED "removed"
#define NM_DEVICE_RECHECK_AUTO_ACTIVATE "recheck-auto-activate"
+#define NM_DEVICE_ADMIN_UP "admin-up"
G_BEGIN_DECLS
@@ -303,6 +304,8 @@ RfKillType nm_device_get_rfkill_type (NMDevice *device);
* @NM_MANAGED_INTERNAL: whether managed by internal decision (ie, because NM
* is sleeping or not managed the device for some other reason)
* @NM_MANAGED_USER: whether managed by user decision (ie, not in unmanaged-specs)
+ * @NM_MANAGED_ADMIN_UP: whether managed because device is administratively
+ * enabled (IFF_UP)
*/
typedef enum {
NM_MANAGED_UNKNOWN = 0x00,
@@ -310,10 +313,11 @@ typedef enum {
NM_MANAGED_DEFAULT = 0x01,
NM_MANAGED_INTERNAL = 0x02,
NM_MANAGED_USER = 0x04,
+ NM_MANAGED_ADMIN_UP = 0x08,
/* Boundary values */
- NM_MANAGED_LAST = NM_MANAGED_USER,
- NM_MANAGED_ALL = NM_MANAGED_DEFAULT | NM_MANAGED_INTERNAL | NM_MANAGED_USER,
+ NM_MANAGED_LAST = NM_MANAGED_ADMIN_UP,
+ NM_MANAGED_ALL = NM_MANAGED_DEFAULT | NM_MANAGED_INTERNAL | NM_MANAGED_USER | NM_MANAGED_ADMIN_UP,
} NMManagedFlags;
gboolean nm_device_get_managed (NMDevice *device);
diff --git a/src/nm-manager.c b/src/nm-manager.c
index a92aa34dec..050a104bb6 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -1735,6 +1735,64 @@ get_existing_connection (NMManager *manager, NMDevice *device)
return added ? NM_CONNECTION (added) : NULL;
}
+static void
+assume_connection (NMManager *self, NMDevice *device, NMConnection *connection)
+{
+ NMActiveConnection *active, *master_ac = NULL;
+ NMAuthSubject *subject;
+ GError *error = NULL;
+
+ nm_log_dbg (LOGD_DEVICE, "(%s): will attempt to assume connection '%s'",
+ nm_device_get_iface (device),
+ nm_connection_get_id (connection));
+
+ /* Move device to DISCONNECTED to activate the connection */
+ nm_device_state_changed (device,
+ NM_DEVICE_STATE_DISCONNECTED,
+ NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
+
+ subject = nm_auth_subject_new_internal ();
+ active = _new_active_connection (self, connection, NULL, device, subject, &error);
+ if (active) {
+ /* If the device is a slave or VLAN, find the master ActiveConnection */
+ if (find_master (self, connection, device, NULL, NULL, &master_ac, NULL) && master_ac)
+ nm_active_connection_set_master (active, master_ac);
+
+ nm_active_connection_set_assumed (active, TRUE);
+ nm_active_connection_export (active);
+ active_connection_add (self, active);
+ nm_device_queue_activation (device, NM_ACT_REQUEST (active));
+ g_object_unref (active);
+ } else {
+ nm_log_warn (LOGD_DEVICE, "(%s): assumed connection '%s' failed to activate: (%d) %s",
+ nm_device_get_iface (device),
+ nm_connection_get_id (connection),
+ error ? error->code : -1,
+ error && error->message ? error->message : "(unknown)");
+ g_error_free (error);
+ }
+ g_object_unref (subject);
+}
+
+static void
+device_admin_up (NMDevice *device, gpointer user_data)
+{
+ NMManager *self = NM_MANAGER (user_data);
+ NMConnection *connection = NULL;
+
+ if (nm_device_get_managed_flag (device, NM_MANAGED_USER) &&
+ nm_device_get_managed_flag (device, NM_MANAGED_INTERNAL))
+ connection = get_existing_connection (self, device);
+
+ nm_device_set_managed (device,
+ NM_MANAGED_ADMIN_UP,
+ TRUE,
+ connection ? NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED :
+ NM_DEVICE_STATE_REASON_NOW_MANAGED);
+ if (nm_device_get_managed (device) && connection)
+ assume_connection (self, device, connection);
+}
+
/**
* add_device:
* @self: the #NMManager
@@ -1752,12 +1810,13 @@ add_device (NMManager *self, NMDevice *device, gboolean generate_con)
char *path;
static guint32 devcount = 0;
const GSList *unmanaged_specs;
- gboolean user_unmanaged, sleeping;
+ gboolean user_unmanaged, sleeping, wait_for_up;
NMConnection *connection = NULL;
gboolean enabled = FALSE;
RfKillType rtype;
NMDeviceType devtype;
GSList *iter, *remove = NULL;
+ int ifindex;
devtype = nm_device_get_device_type (device);
@@ -1795,6 +1854,10 @@ add_device (NMManager *self, NMDevice *device, gboolean generate_con)
G_CALLBACK (device_removed_cb),
self);
+ g_signal_connect (device, NM_DEVICE_ADMIN_UP,
+ G_CALLBACK (device_admin_up),
+ self);
+
if (priv->startup) {
g_signal_connect (device, "notify::" NM_DEVICE_HAS_PENDING_ACTION,
G_CALLBACK (device_has_pending_action_changed),
@@ -1838,17 +1901,26 @@ add_device (NMManager *self, NMDevice *device, gboolean generate_con)
type_desc = nm_device_get_type_desc (device);
g_assert (type_desc);
driver = nm_device_get_driver (device);
+ ifindex = nm_device_get_ifindex (device);
if (!driver)
driver = "unknown";
nm_log_info (LOGD_HW, "(%s): new %s device (driver: '%s' ifindex: %d)",
- iface, type_desc, driver, nm_device_get_ifindex (device));
+ iface, type_desc, driver, ifindex);
unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings);
user_unmanaged = nm_device_spec_match_list (device, unmanaged_specs);
sleeping = manager_sleeping (self);
+
+ /* Don't manage downed software devices until the user brings them up */
+ wait_for_up = (generate_con &&
+ nm_device_is_software (device) &&
+ !nm_platform_link_is_up (ifindex) &&
+ !nm_device_get_default_unmanaged (device));
+
nm_device_set_initial_managed_flags (device,
NM_MANAGED_USER, !user_unmanaged,
NM_MANAGED_INTERNAL, !sleeping,
+ NM_MANAGED_ADMIN_UP, !wait_for_up,
NM_MANAGED_UNKNOWN);
path = g_strdup_printf ("/org/freedesktop/NetworkManager/Devices/%d", devcount++);
@@ -1858,8 +1930,8 @@ add_device (NMManager *self, NMDevice *device, gboolean generate_con)
g_free (path);
/* Don't generate a connection e.g. for devices NM just created, or
- * for the loopback, or when we're sleeping. */
- if (generate_con && !user_unmanaged && !sleeping)
+ * for the loopback, or when we're not managing the device yet. */
+ if (generate_con && !user_unmanaged && !sleeping && !wait_for_up)
connection = get_existing_connection (self, device);
/* Start the device if it'supposed to be managed. Note that this will
@@ -1882,42 +1954,8 @@ add_device (NMManager *self, NMDevice *device, gboolean generate_con)
system_create_virtual_devices (self);
/* If the device has a connection it can assume, do that now */
- if (connection) {
- NMActiveConnection *active;
- NMAuthSubject *subject;
- GError *error = NULL;
-
- nm_log_dbg (LOGD_DEVICE, "(%s): will attempt to assume connection",
- nm_device_get_iface (device));
-
- /* Move device to DISCONNECTED to activate the connection */
- nm_device_state_changed (device,
- NM_DEVICE_STATE_DISCONNECTED,
- NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
-
- subject = nm_auth_subject_new_internal ();
- active = _new_active_connection (self, connection, NULL, device, subject, &error);
- if (active) {
- NMActiveConnection *master_ac = NULL;
-
- /* If the device is a slave or VLAN, find the master ActiveConnection */
- if (find_master (self, connection, device, NULL, NULL, &master_ac, NULL) && master_ac)
- nm_active_connection_set_master (active, master_ac);
-
- nm_active_connection_set_assumed (active, TRUE);
- nm_active_connection_export (active);
- active_connection_add (self, active);
- nm_device_queue_activation (device, NM_ACT_REQUEST (active));
- g_object_unref (active);
- } else {
- nm_log_warn (LOGD_DEVICE, "assumed connection %s failed to activate: (%d) %s",
- nm_connection_get_path (connection),
- error ? error->code : -1,
- error && error->message ? error->message : "(unknown)");
- g_error_free (error);
- }
- g_object_unref (subject);
- }
+ if (connection)
+ assume_connection (self, device, connection);
}
static NMDevice *