summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJiří Klimeš <jklimes@redhat.com>2013-10-18 12:32:01 +0200
committerJiří Klimeš <jklimes@redhat.com>2013-10-24 11:58:18 +0200
commitf4dbf27410ce51e95c70b9e2572e30771a67eeed (patch)
treeee4904a72eb47d920022421dc6ab7c98f822fba1
parent1a67f8df03eed7fcb6160429be48d933991c165d (diff)
downloadNetworkManager-f4dbf27410ce51e95c70b9e2572e30771a67eeed.tar.gz
core: track autoconnect for removed software devices (rh #1005913)
When an interface is manually disconnected NM remembers that, and prevents automatic activation of the device. However, software devices are removed when they are disconnected, and thus the state of the device is lost. We need to track autoconnect outside the device - hash table of interface names not allowed to activate automatically. Without that the device would be auto-activated again and again, even if explicitly disconnected. Test case: $ nmcli con add type bond ifname bb con-name bb-con $ nmcli con add type bond-slave ifname em1 con-name b1-con master bb $ nmcli dev disconnect bb https://bugzilla.redhat.com/show_bug.cgi?id=1005913
-rw-r--r--src/devices/nm-device.c9
-rw-r--r--src/nm-manager.c57
-rw-r--r--src/nm-manager.h6
3 files changed, 68 insertions, 4 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 7dc536ce9a..294aa9918f 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -42,6 +42,7 @@
#include "nm-device.h"
#include "nm-device-private.h"
#include "NetworkManagerUtils.h"
+#include "nm-manager.h"
#include "nm-platform.h"
#include "nm-rdisc.h"
#include "nm-lndp-rdisc.h"
@@ -4339,6 +4340,14 @@ disconnect_cb (NMDevice *device,
g_error_free (local);
} else {
priv->autoconnect = FALSE;
+
+ /* Software devices are removed when manually disconnected and thus
+ * we need to track the autoconnect flag outside the device.
+ */
+ nm_manager_prevent_device_auto_connect (nm_manager_get (),
+ nm_device_get_ip_iface (device),
+ TRUE);
+
nm_device_state_changed (device,
NM_DEVICE_STATE_DISCONNECTED,
NM_DEVICE_STATE_REASON_USER_REQUESTED);
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 073783473d..4f0d0073d9 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -263,6 +263,9 @@ typedef struct {
GHashTable *nm_bridges;
+ /* Track auto-activation for software devices */
+ GHashTable *noauto_sw_devices;
+
gboolean startup;
gboolean disposed;
} NMManagerPrivate;
@@ -3096,13 +3099,29 @@ nm_manager_activate_connection (NMManager *manager,
}
device = find_device_by_ip_iface (manager, iface);
- g_free (iface);
if (!device) {
- /* Create it */
+ /* Create the software device. Only exception is when:
+ * - this is an auto-activation *and* the device denies auto-activation
+ * at this time (the device was manually disconnected/deleted before)
+ */
+ if (!nm_manager_can_device_auto_connect (manager, iface)) {
+ if (dbus_sender) {
+ /* Manual activation - allow device auto-activation again */
+ nm_manager_prevent_device_auto_connect (manager, iface, FALSE);
+ } else {
+ g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_AUTOCONNECT_NOT_ALLOWED,
+ "'%s' does not allow automatic connections at this time => software device '%s' not created for '%s'",
+ iface, nm_connection_get_id (connection), iface);
+ g_free (iface);
+ return NULL;
+ }
+ }
+
device = system_create_virtual_device (manager, connection);
if (!device) {
- g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
- "Failed to create virtual interface");
+ g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+ "Failed to create virtual interface '%s'", iface);
+ g_free (iface);
return NULL;
}
@@ -3118,6 +3137,7 @@ nm_manager_activate_connection (NMManager *manager,
NM_DEVICE_STATE_REASON_NONE);
}
}
+ g_free (iface);
}
if (!nm_device_can_activate (device, connection)) {
@@ -3498,6 +3518,30 @@ impl_manager_deactivate_connection (NMManager *self,
}
}
+/*
+ * Track (software) devices that cannot auto activate.
+ * It is needed especially for software devices, that can be removed and added
+ * again. So we can't simply use a flag inside the device.
+ */
+void
+nm_manager_prevent_device_auto_connect (NMManager *manager, const char *ifname, gboolean prevent)
+{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+
+ if (prevent)
+ g_hash_table_add (priv->noauto_sw_devices, g_strdup (ifname));
+ else
+ g_hash_table_remove (priv->noauto_sw_devices, ifname);
+}
+
+gboolean
+nm_manager_can_device_auto_connect (NMManager *manager, const char *ifname)
+{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+
+ return !g_hash_table_contains (priv->noauto_sw_devices, ifname);
+}
+
static void
do_sleep_wake (NMManager *self)
{
@@ -4575,6 +4619,8 @@ dispose (GObject *object)
g_object_unref (priv->fw_monitor);
}
+ g_hash_table_unref (priv->noauto_sw_devices);
+
g_slist_free (priv->factories);
if (priv->timestamp_update_id) {
@@ -4938,6 +4984,9 @@ nm_manager_init (NMManager *manager)
KERNEL_FIRMWARE_DIR);
}
+ /* Hash table storing software devices that should not auto activate */
+ priv->noauto_sw_devices = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
load_device_factories (manager);
/* Update timestamps in active connections */
diff --git a/src/nm-manager.h b/src/nm-manager.h
index e972644e6d..fd6fa0aeee 100644
--- a/src/nm-manager.h
+++ b/src/nm-manager.h
@@ -125,6 +125,12 @@ gboolean nm_manager_deactivate_connection (NMManager *manager,
NMDeviceStateReason reason,
GError **error);
+void nm_manager_prevent_device_auto_connect (NMManager *manager,
+ const char *ifname,
+ gboolean prevent);
+gboolean nm_manager_can_device_auto_connect (NMManager *manager,
+ const char *ifname);
+
/* State handling */
NMState nm_manager_get_state (NMManager *manager);