diff options
author | Jiří Klimeš <jklimes@redhat.com> | 2015-06-19 12:19:18 +0200 |
---|---|---|
committer | Jiří Klimeš <jklimes@redhat.com> | 2015-06-19 12:19:18 +0200 |
commit | b7b47941c00abf8158eef82a2116287796952956 (patch) | |
tree | 548add68b48b93fce299a080aa6b4159283c61ce | |
parent | 2f51ba50df8341370ab1f480f9ec6d60cd32ece2 (diff) | |
parent | 94337e58b7be0937decd18e0ef118c6d4602e0ed (diff) |
merge: activate slaves when master is activated (bgo #735052) (rh #1158529)
When a master connection is activated, check all its slaves and decide whether
they should be activated as well. This is done according to the
connection.autoconnect-slaves property.
https://bugzilla.gnome.org/show_bug.cgi?id=735052
https://bugzilla.redhat.com/show_bug.cgi?id=1158529
(cherry-picked from b18f328967a97671b1ed9f662375a2becb5e2631)
-rw-r--r-- | clients/cli/settings.c | 56 | ||||
-rw-r--r-- | libnm-core/nm-setting-connection.c | 55 | ||||
-rw-r--r-- | libnm-core/nm-setting-connection.h | 21 | ||||
-rw-r--r-- | libnm-core/tests/test-general.c | 1 | ||||
-rw-r--r-- | libnm/libnm.ver | 2 | ||||
-rw-r--r-- | man/NetworkManager.conf.xml.in | 4 | ||||
-rw-r--r-- | src/nm-manager.c | 124 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/reader.c | 2 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/writer.c | 16 |
9 files changed, 276 insertions, 5 deletions
diff --git a/clients/cli/settings.c b/clients/cli/settings.c index 1967ac05af..166c3076c0 100644 --- a/clients/cli/settings.c +++ b/clients/cli/settings.c @@ -51,8 +51,9 @@ NmcOutputField nmc_fields_setting_connection[] = { SETTING_FIELD (NM_SETTING_CONNECTION_ZONE, 10), /* 10 */ SETTING_FIELD (NM_SETTING_CONNECTION_MASTER, 20), /* 11 */ SETTING_FIELD (NM_SETTING_CONNECTION_SLAVE_TYPE, 20), /* 12 */ - SETTING_FIELD (NM_SETTING_CONNECTION_SECONDARIES, 40), /* 13 */ - SETTING_FIELD (NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT, 30), /* 14 */ + SETTING_FIELD (NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES, 13), /* 13 */ + SETTING_FIELD (NM_SETTING_CONNECTION_SECONDARIES, 40), /* 14 */ + SETTING_FIELD (NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT, 30), /* 15 */ {NULL, NULL, 0, NULL, FALSE, FALSE, 0} }; #define NMC_FIELDS_SETTING_CONNECTION_ALL "name"","\ @@ -68,6 +69,7 @@ NmcOutputField nmc_fields_setting_connection[] = { NM_SETTING_CONNECTION_ZONE","\ NM_SETTING_CONNECTION_MASTER","\ NM_SETTING_CONNECTION_SLAVE_TYPE","\ + NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES","\ NM_SETTING_CONNECTION_SECONDARIES","\ NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT #define NMC_FIELDS_SETTING_CONNECTION_COMMON NMC_FIELDS_SETTING_CONNECTION_ALL @@ -758,6 +760,20 @@ ip6_privacy_to_string (NMSettingIP6ConfigPrivacy ip6_privacy) } static char * +autoconnect_slaves_to_string (NMSettingConnectionAutoconnectSlaves autoconnect_slaves) +{ + switch (autoconnect_slaves) { + case NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_NO: + return g_strdup_printf (_("%d (no)"), autoconnect_slaves); + case NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_YES: + return g_strdup_printf (_("%d (yes)"), autoconnect_slaves); + case NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_DEFAULT: + default: + return g_strdup_printf (_("%d (default)"), autoconnect_slaves); + } +} + +static char * secret_flags_to_string (guint32 flags) { GString *flag_str; @@ -1046,6 +1062,14 @@ nmc_property_connection_get_permissions (NMSetting *setting) DEFINE_GETTER (nmc_property_connection_get_zone, NM_SETTING_CONNECTION_ZONE) DEFINE_GETTER (nmc_property_connection_get_master, NM_SETTING_CONNECTION_MASTER) DEFINE_GETTER (nmc_property_connection_get_slave_type, NM_SETTING_CONNECTION_SLAVE_TYPE) + +static char * +nmc_property_connection_get_autoconnect_slaves (NMSetting *setting) +{ + NMSettingConnection *s_con = NM_SETTING_CONNECTION (setting); + return autoconnect_slaves_to_string (nm_setting_connection_get_autoconnect_slaves (s_con)); +} + DEFINE_GETTER (nmc_property_connection_get_secondaries, NM_SETTING_CONNECTION_SECONDARIES) DEFINE_GETTER (nmc_property_connection_get_gateway_ping_timeout, NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT) @@ -2240,6 +2264,22 @@ nmc_property_set_bool (NMSetting *setting, const char *prop, const char *val, GE } static gboolean +nmc_property_set_trilean (NMSetting *setting, const char *prop, const char *val, GError **error) +{ + long int val_int; + + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + if (!nmc_string_to_int (val, TRUE, -1, 1, &val_int)) { + g_set_error (error, 1, 0, _("'%s' is not a valid value; use -1, 0 or 1"), val); + return FALSE; + } + + g_object_set (setting, prop, val_int, NULL); + return TRUE; +} + +static gboolean nmc_property_set_ssid (NMSetting *setting, const char *prop, const char *val, GError **error) { GBytes *ssid; @@ -5233,6 +5273,13 @@ nmc_properties_init (void) NULL, nmc_property_con_allowed_slave_type, NULL); + nmc_add_prop_funcs (GLUE (CONNECTION, AUTOCONNECT_SLAVES), + nmc_property_connection_get_autoconnect_slaves, + nmc_property_set_trilean, + NULL, + NULL, + NULL, + NULL); nmc_add_prop_funcs (GLUE (CONNECTION, SECONDARIES), nmc_property_connection_get_secondaries, nmc_property_connection_set_secondaries, @@ -6611,8 +6658,9 @@ setting_connection_details (NMSetting *setting, NmCli *nmc, const char *one_pro set_val_str (arr, 10, nmc_property_connection_get_zone (setting)); set_val_str (arr, 11, nmc_property_connection_get_master (setting)); set_val_str (arr, 12, nmc_property_connection_get_slave_type (setting)); - set_val_str (arr, 13, nmc_property_connection_get_secondaries (setting)); - set_val_str (arr, 14, nmc_property_connection_get_gateway_ping_timeout (setting)); + set_val_str (arr, 13, nmc_property_connection_get_autoconnect_slaves (setting)); + set_val_str (arr, 14, nmc_property_connection_get_secondaries (setting)); + set_val_str (arr, 15, nmc_property_connection_get_gateway_ping_timeout (setting)); g_ptr_array_add (nmc->output_data, arr); print_data (nmc); /* Print all data */ diff --git a/libnm-core/nm-setting-connection.c b/libnm-core/nm-setting-connection.c index 7bc927bc1d..e727e97e0b 100644 --- a/libnm-core/nm-setting-connection.c +++ b/libnm-core/nm-setting-connection.c @@ -27,6 +27,7 @@ #include "nm-utils.h" #include "nm-utils-private.h" +#include "nm-core-enum-types.h" #include "nm-setting-connection.h" #include "nm-connection-private.h" #include "nm-setting-bond.h" @@ -66,6 +67,7 @@ typedef struct { char *type; char *master; char *slave_type; + NMSettingConnectionAutoconnectSlaves autoconnect_slaves; GSList *permissions; /* list of Permission structs */ gboolean autoconnect; gint autoconnect_priority; @@ -90,6 +92,7 @@ enum { PROP_ZONE, PROP_MASTER, PROP_SLAVE_TYPE, + PROP_AUTOCONNECT_SLAVES, PROP_SECONDARIES, PROP_GATEWAY_PING_TIMEOUT, @@ -603,6 +606,23 @@ nm_setting_connection_is_slave_type (NMSettingConnection *setting, } /** + * nm_setting_connection_get_autoconnect_slaves: + * @setting: the #NMSettingConnection + * + * Returns the #NMSettingConnection:autoconnect-slaves property of the connection. + * + * Returns: whether slaves of the connection should be activated together + * with the connection. + **/ +NMSettingConnectionAutoconnectSlaves +nm_setting_connection_get_autoconnect_slaves (NMSettingConnection *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_CONNECTION (setting), NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_DEFAULT); + + return NM_SETTING_CONNECTION_GET_PRIVATE (setting)->autoconnect_slaves; +} + +/** * nm_setting_connection_get_num_secondaries: * @setting: the #NMSettingConnection * @@ -1122,6 +1142,9 @@ set_property (GObject *object, guint prop_id, g_free (priv->slave_type); priv->slave_type = g_value_dup_string (value); break; + case PROP_AUTOCONNECT_SLAVES: + priv->autoconnect_slaves = g_value_get_enum (value); + break; case PROP_SECONDARIES: g_slist_free_full (priv->secondaries, g_free); priv->secondaries = _nm_utils_strv_to_slist (g_value_get_boxed (value)); @@ -1193,6 +1216,9 @@ get_property (GObject *object, guint prop_id, case PROP_SLAVE_TYPE: g_value_set_string (value, nm_setting_connection_get_slave_type (setting)); break; + case PROP_AUTOCONNECT_SLAVES: + g_value_set_enum (value, nm_setting_connection_get_autoconnect_slaves (setting)); + break; case PROP_SECONDARIES: g_value_take_boxed (value, _nm_utils_slist_to_strv (priv->secondaries)); break; @@ -1524,6 +1550,35 @@ nm_setting_connection_class_init (NMSettingConnectionClass *setting_class) G_PARAM_STATIC_STRINGS)); /** + * NMSettingConnection:autoconnect-slaves: + * + * Whether or not slaves of this connection should be automatically brought up + * when NetworkManager activates this connection. This only has a real effect + * for master connections. + * The permitted values are: 0: leave slave connections untouched, + * 1: activate all the slave connections with this connection, -1: default. + * If -1 (default) is set, global connection.autoconnect-slaves is read to + * determine the real value. If it is default as well, this fallbacks to 0. + **/ + /* ---ifcfg-rh--- + * property: autoconnect-slaves + * variable: AUTOCONNECT-SLAVES(+) + * default: missing variable means global default + * description: Whether slaves of this connection should be auto-connected + * when this connection is activated. + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_AUTOCONNECT_SLAVES, + g_param_spec_enum (NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES, "", "", + NM_TYPE_SETTING_CONNECTION_AUTOCONNECT_SLAVES, + NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_DEFAULT, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + NM_SETTING_PARAM_FUZZY_IGNORE | + G_PARAM_STATIC_STRINGS)); + + /** * NMSettingConnection:secondaries: * * List of connection UUIDs that should be activated when the base diff --git a/libnm-core/nm-setting-connection.h b/libnm-core/nm-setting-connection.h index d1ad0fe1e5..1e365dd3ca 100644 --- a/libnm-core/nm-setting-connection.h +++ b/libnm-core/nm-setting-connection.h @@ -56,9 +56,29 @@ G_BEGIN_DECLS #define NM_SETTING_CONNECTION_ZONE "zone" #define NM_SETTING_CONNECTION_MASTER "master" #define NM_SETTING_CONNECTION_SLAVE_TYPE "slave-type" +#define NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES "autoconnect-slaves" #define NM_SETTING_CONNECTION_SECONDARIES "secondaries" #define NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT "gateway-ping-timeout" +/* Types for property values */ +/** + * NMSettingConnectionAutoconnectSlaves: + * @NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_DEFAULT: default value + * @NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_NO: slaves are not brought up when + * master is activated + * @NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_YES: slaves are brought up when + * master is activated + * + * #NMSettingConnectionAutoconnectSlaves values indicate whether slave connections + * should be activated when master is activated. + */ +typedef enum { + NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_DEFAULT = -1, + NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_NO = 0, + NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_YES = 1, +} NMSettingConnectionAutoconnectSlaves; + + /** * NMSettingConnection: * @@ -111,6 +131,7 @@ const char *nm_setting_connection_get_master (NMSettingConnection *set gboolean nm_setting_connection_is_slave_type (NMSettingConnection *setting, const char *type); const char *nm_setting_connection_get_slave_type (NMSettingConnection *setting); +NMSettingConnectionAutoconnectSlaves nm_setting_connection_get_autoconnect_slaves (NMSettingConnection *setting); guint32 nm_setting_connection_get_num_secondaries (NMSettingConnection *setting); const char *nm_setting_connection_get_secondary (NMSettingConnection *setting, guint32 idx); diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index 202326ffa5..b686f6ce26 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -1963,6 +1963,7 @@ test_connection_diff_a_only (void) { NM_SETTING_CONNECTION_ZONE, NM_SETTING_DIFF_RESULT_IN_A }, { NM_SETTING_CONNECTION_MASTER, NM_SETTING_DIFF_RESULT_IN_A }, { NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_DIFF_RESULT_IN_A }, + { NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES, NM_SETTING_DIFF_RESULT_IN_A }, { NM_SETTING_CONNECTION_SECONDARIES, NM_SETTING_DIFF_RESULT_IN_A }, { NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT, NM_SETTING_DIFF_RESULT_IN_A }, { NULL, NM_SETTING_DIFF_RESULT_UNKNOWN } diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 82bcdb9f07..88a79a88b8 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -466,8 +466,10 @@ global: nm_setting_compare_flags_get_type; nm_setting_connection_add_permission; nm_setting_connection_add_secondary; + nm_setting_connection_autoconnect_slaves_get_type; nm_setting_connection_get_autoconnect; nm_setting_connection_get_autoconnect_priority; + nm_setting_connection_get_autoconnect_slaves; nm_setting_connection_get_connection_type; nm_setting_connection_get_gateway_ping_timeout; nm_setting_connection_get_id; diff --git a/man/NetworkManager.conf.xml.in b/man/NetworkManager.conf.xml.in index fac4616ff6..bd187ff57c 100644 --- a/man/NetworkManager.conf.xml.in +++ b/man/NetworkManager.conf.xml.in @@ -451,6 +451,7 @@ unmanaged-devices=mac:00:22:68:1c:59:b1;mac:00:1E:65:30:D1:C4;interface-name:eth <programlisting> [connection] ipv6.ip6-privacy=0 +connection.autoconnect-slaves=1 [connection-wifi-wlan0] match-device=interface-name:wlan0 @@ -517,6 +518,9 @@ ipv6.ip6-privacy=1 <varlistentry> <term><varname>ipv6.route-metric</varname></term> </varlistentry> + <varlistentry> + <term><varname>connection.autoconnect-slaves</varname></term> + </varlistentry> </variablelist> </para> </refsect1> diff --git a/src/nm-manager.c b/src/nm-manager.c index 31303e80e2..4950c98f86 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -2392,6 +2392,127 @@ ensure_master_active_connection (NMManager *self, return NULL; } +/** + * find_slaves: + * @manager: #NMManager object + * @connection: the master #NMConnection to find slave connections for + * @device: the master #NMDevice for the @connection + * + * Given an #NMConnection, attempts to find its slaves. If @connection is not + * master, or has not any slaves, this will return %NULL. + * + * Returns: list of slave connections for given master @connection, or %NULL + **/ +static GSList * +find_slaves (NMManager *manager, + NMConnection *connection, + NMDevice *device) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); + GSList *all_connections, *iter; + GSList *slaves = NULL; + NMSettingConnection *s_con; + const char *master; + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + master = nm_setting_connection_get_master (s_con); + + if (master != NULL) + return NULL; /* connection is not master */ + + /* Search through all connections, not only inactive ones, because + * even if a slave was already active, it might be deactivated during + * master reactivation. + */ + all_connections = nm_settings_get_connections (priv->settings); + for (iter = all_connections; iter; iter = iter->next) { + NMConnection *master_connection = NULL; + NMDevice *master_device = NULL; + NMConnection *candidate = iter->data; + + find_master (manager, candidate, NULL, &master_connection, &master_device, NULL, NULL); + if ( (master_connection && master_connection == connection) + || (master_device && master_device == device)) { + slaves = g_slist_prepend (slaves, candidate); + } + } + g_slist_free (all_connections); + + return g_slist_reverse (slaves); +} + +static gboolean +should_connect_slaves (NMConnection *connection, NMDevice *device) +{ + NMSettingConnection *s_con; + NMSettingConnectionAutoconnectSlaves autoconnect_slaves; + gs_free char *value = NULL; + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + + /* Check autoconnect-slaves property */ + autoconnect_slaves = nm_setting_connection_get_autoconnect_slaves (s_con); + if (autoconnect_slaves != NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_DEFAULT) + goto out; + + /* Check configuration default for autoconnect-slaves property */ + value = nm_config_data_get_connection_default (nm_config_get_data (nm_config_get ()), + "connection.autoconnect-slaves", device); + if (value) + autoconnect_slaves = _nm_utils_ascii_str_to_int64 (value, 10, 0, 1, -1); + +out: + if (autoconnect_slaves == NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_NO) + return FALSE; + if (autoconnect_slaves == NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_YES) + return TRUE; + return FALSE; +} + +static gboolean +autoconnect_slaves (NMManager *manager, + NMConnection *master_connection, + NMDevice *master_device, + NMAuthSubject *subject) +{ + GError *local_err = NULL; + gboolean ret = FALSE; + + if (should_connect_slaves (master_connection, master_device)) { + GSList *slaves, *iter; + + iter = slaves = find_slaves (manager, master_connection, master_device); + ret = slaves != NULL; + + while (iter) { + NMConnection *slave_connection = iter->data; + + iter = iter->next; + nm_log_dbg (LOGD_CORE, "will activate slave connection '%s' (%s) as a dependency for master '%s' (%s)", + nm_connection_get_id (slave_connection), + nm_connection_get_uuid (slave_connection), + nm_connection_get_id (master_connection), + nm_connection_get_uuid (master_connection)); + + /* Schedule slave activation */ + nm_manager_activate_connection (manager, + slave_connection, + NULL, + nm_manager_get_best_device_for_connection (manager, slave_connection), + subject, + &local_err); + if (local_err) { + nm_log_warn (LOGD_CORE, "Slave connection activation failed: %s", local_err->message); + g_error_free (local_err); + } + } + g_slist_free (slaves); + } + return ret; +} + static gboolean _internal_activate_vpn (NMManager *self, NMActiveConnection *active, GError **error) { @@ -2565,6 +2686,9 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * nm_active_connection_get_path (master_ac)); } + /* Check slaves for master connection and possibly activate them */ + autoconnect_slaves (self, connection, device, nm_active_connection_get_subject (active)); + /* Disconnect the connection if connected or queued on another device */ existing = nm_manager_get_connection_device (self, connection); if (existing) diff --git a/src/settings/plugins/ifcfg-rh/reader.c b/src/settings/plugins/ifcfg-rh/reader.c index 2ef2617f92..881d18ce4f 100644 --- a/src/settings/plugins/ifcfg-rh/reader.c +++ b/src/settings/plugins/ifcfg-rh/reader.c @@ -178,6 +178,8 @@ make_connection_setting (const char *file, NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MIN, NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MAX, NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_DEFAULT), + NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES, + svTrueValue (ifcfg, "AUTOCONNECT_SLAVES", NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_DEFAULT), NULL); value = svGetValue (ifcfg, "USERS", FALSE); diff --git a/src/settings/plugins/ifcfg-rh/writer.c b/src/settings/plugins/ifcfg-rh/writer.c index d2b0c97008..cef990d819 100644 --- a/src/settings/plugins/ifcfg-rh/writer.c +++ b/src/settings/plugins/ifcfg-rh/writer.c @@ -1665,7 +1665,7 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) { guint32 n, i; GString *str; - const char *master; + const char *master, *type; char *tmp; gint i_int; @@ -1682,6 +1682,20 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) svSetValue (ifcfg, "AUTOCONNECT_PRIORITY", tmp, FALSE); g_free (tmp); + /* Only save the value for master connections */ + svSetValue (ifcfg, "AUTOCONNECT_SLAVES", NULL, FALSE); + type = nm_setting_connection_get_connection_type (s_con); + if ( !g_strcmp0 (type, NM_SETTING_BOND_SETTING_NAME) + || !g_strcmp0 (type, NM_SETTING_TEAM_SETTING_NAME) + || !g_strcmp0 (type, NM_SETTING_BRIDGE_SETTING_NAME)) { + NMSettingConnectionAutoconnectSlaves autoconnect_slaves; + autoconnect_slaves = nm_setting_connection_get_autoconnect_slaves (s_con); + svSetValue (ifcfg, "AUTOCONNECT_SLAVES", + autoconnect_slaves == NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_YES ? "yes" : + autoconnect_slaves == NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_NO ? "no" : NULL, + FALSE); + } + /* Permissions */ svSetValue (ifcfg, "USERS", NULL, FALSE); n = nm_setting_connection_get_num_permissions (s_con); |