diff options
author | Jiří Klimeš <jklimes@redhat.com> | 2013-10-18 12:32:01 +0200 |
---|---|---|
committer | Jiří Klimeš <jklimes@redhat.com> | 2013-10-24 11:58:18 +0200 |
commit | f4dbf27410ce51e95c70b9e2572e30771a67eeed (patch) | |
tree | ee4904a72eb47d920022421dc6ab7c98f822fba1 | |
parent | 1a67f8df03eed7fcb6160429be48d933991c165d (diff) | |
download | NetworkManager-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.c | 9 | ||||
-rw-r--r-- | src/nm-manager.c | 57 | ||||
-rw-r--r-- | src/nm-manager.h | 6 |
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); |