diff options
author | Thomas Haller <thaller@redhat.com> | 2015-05-15 11:36:28 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2015-06-05 12:38:29 +0200 |
commit | dc0193ac023e30a9a3794e78c66f8c5266695a60 (patch) | |
tree | 2017276f2bec76590e38c9552e3030005fcef543 /src | |
parent | f031b926c452aea5a28390eee2cfb9b9f0d15652 (diff) |
config: support a [connection] section to NetworkManager.conf to specify connection defaults
Add support for a new section [connection] in NetworkManager.conf.
If the connection leaves an option at "unknown"/"default", we can
support overwriting the value from global configuration.
We also support other sections that are named with "connection"
as a prefix, such as [connection2], [connection-wifi]. This is
to support multiple default values that can be applied depending
on the used device.
I think this has great potential. Only downside is that when
the user looks at a connection value, it will see that it is
unspecified. But the actually used value depends on the device
type and might not be obvious.
https://bugzilla.gnome.org/show_bug.cgi?id=695383
https://bugzilla.redhat.com/show_bug.cgi?id=1164677
Diffstat (limited to 'src')
-rw-r--r-- | src/nm-config-data.c | 122 | ||||
-rw-r--r-- | src/nm-config-data.h | 4 | ||||
-rw-r--r-- | src/tests/config/NetworkManager.conf | 24 | ||||
-rw-r--r-- | src/tests/config/test-config.c | 51 |
4 files changed, 201 insertions, 0 deletions
diff --git a/src/nm-config-data.c b/src/nm-config-data.c index 41995a043..73c36312f 100644 --- a/src/nm-config-data.c +++ b/src/nm-config-data.c @@ -27,6 +27,19 @@ #include "gsystem-local-alloc.h" #include "nm-device.h" #include "nm-core-internal.h" +#include "nm-macros-internal.h" + +typedef struct { + char *group_name; + gboolean stop_match; + struct { + /* have a separate boolean field @has, because a @spec with + * value %NULL does not necessarily mean, that the property + * "match-device" was unspecified. */ + gboolean has; + GSList *spec; + } match_device; +} ConnectionInfo; typedef struct { char *config_main_file; @@ -34,6 +47,10 @@ typedef struct { GKeyFile *keyfile; + /* A zero-terminated list of pre-processed information from the + * [connection] sections. This is to speed up lookup. */ + ConnectionInfo *connection_infos; + struct { char *uri; char *response; @@ -172,6 +189,100 @@ nm_config_data_get_assume_ipv6ll_only (const NMConfigData *self, NMDevice *devic /************************************************************************/ +char * +nm_config_data_get_connection_default (const NMConfigData *self, + const char *property, + NMDevice *device) +{ + NMConfigDataPrivate *priv; + const ConnectionInfo *connection_info; + + g_return_val_if_fail (self, NULL); + g_return_val_if_fail (property && *property, NULL); + g_return_val_if_fail (strchr (property, '.'), NULL); + + priv = NM_CONFIG_DATA_GET_PRIVATE (self); + + if (!priv->connection_infos) + return NULL; + + for (connection_info = &priv->connection_infos[0]; connection_info->group_name; connection_info++) { + char *value; + gboolean match; + + value = g_key_file_get_value (priv->keyfile, connection_info->group_name, property, NULL); + if (!value && !connection_info->stop_match) + continue; + + match = TRUE; + if (connection_info->match_device.has) + match = device && nm_device_spec_match_list (device, connection_info->match_device.spec); + + if (match) + return value; + g_free (value); + } + return NULL; +} + +static ConnectionInfo * +_get_connection_infos (GKeyFile *keyfile) +{ + char **groups; + guint i; + char *connection_tag = NULL; + GSList *connection_groups = NULL; + ConnectionInfo *connection_infos = NULL; + + /* get the list of existing [connection.\+] sections that we consider + * for nm_config_data_get_connection_default(). Also, get them + * in the right order. */ + groups = g_key_file_get_groups (keyfile, NULL); + for (i = 0; groups && groups[i]; i++) { + if (g_str_has_prefix (groups[i], "connection")) { + if (strlen (groups[i]) == STRLEN ("connection")) + connection_tag = groups[i]; + else + connection_groups = g_slist_prepend (connection_groups, groups[i]); + } else + g_free (groups[i]); + } + g_free (groups); + if (connection_tag) { + /* We want the group "connection" checked at last, so that + * all other "connection.\+" have preference. Those other + * groups are checked in order of appearance. */ + connection_groups = g_slist_prepend (connection_groups, connection_tag); + } + if (connection_groups) { + guint len = g_slist_length (connection_groups); + GSList *iter; + + connection_infos = g_new0 (ConnectionInfo, len + 1); + for (iter = connection_groups; iter; iter = iter->next) { + ConnectionInfo *connection_info; + char *value; + + nm_assert (len >= 1); + connection_info = &connection_infos[--len]; + connection_info->group_name = iter->data; + + value = g_key_file_get_value (keyfile, iter->data, "match-device", NULL); + if (value) { + connection_info->match_device.has = TRUE; + connection_info->match_device.spec = nm_match_spec_split (value); + g_free (value); + } + connection_info->stop_match = nm_config_keyfile_get_boolean (keyfile, iter->data, "stop-match", FALSE); + } + g_slist_free (connection_groups); + } + + return connection_infos; +} + +/************************************************************************/ + static gboolean _keyfile_a_contains_all_in_b (GKeyFile *kf_a, GKeyFile *kf_b) { @@ -324,6 +435,7 @@ static void finalize (GObject *gobject) { NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE (gobject); + guint i; g_free (priv->config_main_file); g_free (priv->config_description); @@ -340,6 +452,14 @@ finalize (GObject *gobject) g_slist_free_full (priv->ignore_carrier, g_free); g_slist_free_full (priv->assume_ipv6ll_only, g_free); + if (priv->connection_infos) { + for (i = 0; priv->connection_infos[i].group_name; i++) { + g_free (priv->connection_infos[i].group_name); + g_slist_free_full (priv->connection_infos[i].match_device.spec, g_free); + } + g_free (priv->connection_infos); + } + g_key_file_unref (priv->keyfile); G_OBJECT_CLASS (nm_config_data_parent_class)->finalize (gobject); @@ -357,6 +477,8 @@ constructed (GObject *object) NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE (self); char *interval; + priv->connection_infos = _get_connection_infos (priv->keyfile); + priv->connectivity.uri = g_key_file_get_value (priv->keyfile, "connectivity", "uri", NULL); priv->connectivity.response = g_key_file_get_value (priv->keyfile, "connectivity", "response", NULL); diff --git a/src/nm-config-data.h b/src/nm-config-data.h index a8182f283..78b04ec8c 100644 --- a/src/nm-config-data.h +++ b/src/nm-config-data.h @@ -94,6 +94,10 @@ const char *nm_config_data_get_rc_manager (const NMConfigData *self); gboolean nm_config_data_get_ignore_carrier (const NMConfigData *self, NMDevice *device); gboolean nm_config_data_get_assume_ipv6ll_only (const NMConfigData *self, NMDevice *device); +char *nm_config_data_get_connection_default (const NMConfigData *self, + const char *property, + NMDevice *device); + G_END_DECLS #endif /* NM_CONFIG_DATA_H */ diff --git a/src/tests/config/NetworkManager.conf b/src/tests/config/NetworkManager.conf index 401ba48a7..36113661f 100644 --- a/src/tests/config/NetworkManager.conf +++ b/src/tests/config/NetworkManager.conf @@ -13,3 +13,27 @@ response=Hello [extra-section] extra-key=some value + + + +[connection] +ipv4.route-metric=50 +ipv6.ip6_privacy=0 +dummy.test1=no +dummy.test2=no + +[connection.dev51] +match-device=mac:00:00:00:00:00:51 +stop-match=yes +ipv4.route-metric=51 +dummy.test1=yes + +[connection.dev52] +match-device=mac:00:00:00:00:00:52 +ipv4.route-metric=52 + +[connection.public] +match-device=interface-name:wlan1 +# match-wifi is not yet implemented. Just an idea what could be useful. +match-wifi=ssid:*[Ss]tarbucks*|*University* +ipv6.ip6_privacy=2 diff --git a/src/tests/config/test-config.c b/src/tests/config/test-config.c index f4d72d333..4a23f23fe 100644 --- a/src/tests/config/test-config.c +++ b/src/tests/config/test-config.c @@ -94,6 +94,9 @@ test_config_simple (void) GError *error = NULL; const char **plugins; char *value; + gs_unref_object NMDevice *dev50 = nm_test_device_new ("00:00:00:00:00:50"); + gs_unref_object NMDevice *dev51 = nm_test_device_new ("00:00:00:00:00:51"); + gs_unref_object NMDevice *dev52 = nm_test_device_new ("00:00:00:00:00:52"); config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "/no/such/dir", NULL); @@ -122,6 +125,54 @@ test_config_simple (void) g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND); g_clear_error (&error); + value = nm_config_data_get_value (nm_config_get_data_orig (config), "connection", "ipv6.ip6_privacy", NULL); + g_assert_cmpstr (value, ==, "0"); + g_free (value); + + value = nm_config_data_get_value (nm_config_get_data_orig (config), "connection.dev51", "ipv4.route-metric", NULL); + g_assert_cmpstr (value, ==, "51"); + g_free (value); + + + value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "ipv6.route-metric", NULL); + g_assert_cmpstr (value, ==, NULL); + g_free (value); + + + value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "ipv4.route-metric", NULL); + g_assert_cmpstr (value, ==, "50"); + g_free (value); + + value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "ipv4.route-metric", dev50); + g_assert_cmpstr (value, ==, "50"); + g_free (value); + + value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "ipv4.route-metric", dev51); + g_assert_cmpstr (value, ==, "51"); + g_free (value); + + value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "ipv4.route-metric", dev52); + g_assert_cmpstr (value, ==, "52"); + g_free (value); + + + value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "dummy.test1", dev51); + g_assert_cmpstr (value, ==, "yes"); + g_free (value); + + value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "dummy.test1", dev50); + g_assert_cmpstr (value, ==, "no"); + g_free (value); + + value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "dummy.test2", dev51); + g_assert_cmpstr (value, ==, NULL); + g_free (value); + + value = nm_config_data_get_connection_default (nm_config_get_data_orig (config), "dummy.test2", dev50); + g_assert_cmpstr (value, ==, "no"); + g_free (value); + + g_object_unref (config); } |