summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2021-06-03 09:01:23 +0200
committerBeniamino Galvani <bgalvani@redhat.com>2021-07-27 17:43:45 +0200
commitbace14fe1f374db26e49e4e7d61d2fbfce4241cc (patch)
tree2c67a193b10cb4895d079881df54577f9fc9ef31
parent604c611cd0520f97a2052f4b2f4560d09de0e738 (diff)
downloadNetworkManager-bg/rh1934122.tar.gz
core: introduce device 'allowed-connections' propertybg/rh1934122
Configuration can have [device*] and [connection*] settings and both can include a 'match-device=' key, which is a list of device-specs. Introduce a new 'allowed-connections' key for [device*] sections, which specifies a list of connection-specs to indicate which connections can be activated on the device. With this, it becomes possible to have a device configuration like: [device-enp1s0] match-device=interface-name:enp1s0 allowed-connections=except:origin:nm-initrd-generator so that NM in the real root ignores connections created by the nm-initrd-generator, and starts activating a persistent connection. This requires also setting 'keep-configuration=no' to not generate an assumed connection.
-rw-r--r--man/NetworkManager.conf.xml19
-rw-r--r--src/core/devices/nm-device.c11
-rw-r--r--src/core/nm-config-data.c81
-rw-r--r--src/core/nm-config-data.h4
-rw-r--r--src/core/nm-config.c12
-rw-r--r--src/core/settings/nm-settings.c10
-rw-r--r--src/libnm-base/nm-config-base.h1
-rw-r--r--src/libnm-glib-aux/nm-shared-utils.h1
8 files changed, 127 insertions, 12 deletions
diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml
index 2eba34dff2..7eaa4cb2a1 100644
--- a/man/NetworkManager.conf.xml
+++ b/man/NetworkManager.conf.xml
@@ -1188,6 +1188,25 @@ managed=1
</para>
</listitem>
</varlistentry>
+ <varlistentry id="allowed-connections">
+ <term><varname>allowed-connections</varname></term>
+ <listitem>
+ <para>
+ A list of connections that can be activated on the
+ device. See <xref linkend="connection-spec"/> for the
+ syntax to specify a connection. If this option is not
+ specified, all connections can be potentially activated
+ on the device, provided that the connection type and
+ other settings match.
+ </para>
+ <para>
+ A notable use case for this is to filter which
+ connections can be activated based on how they were
+ created; see the <literal>origin</literal> keyword in
+ <xref linkend="connection-spec"/>.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry>
<term><varname>wifi.scan-rand-mac-address</varname></term>
<listitem>
diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c
index f8aca987c9..cc18777a00 100644
--- a/src/core/devices/nm-device.c
+++ b/src/core/devices/nm-device.c
@@ -7507,6 +7507,8 @@ check_connection_compatible(NMDevice *self, NMConnection *connection, GError **e
gs_free char * conn_iface = NULL;
NMDeviceClass * klass;
NMSettingMatch * s_match;
+ const GSList * specs;
+ gboolean has_match = FALSE;
klass = NM_DEVICE_GET_CLASS(self);
if (klass->connection_type_check_compatible) {
@@ -7583,6 +7585,15 @@ check_connection_compatible(NMDevice *self, NMConnection *connection, GError **e
}
}
+ specs =
+ nm_config_data_get_device_allowed_connections_specs(NM_CONFIG_GET_DATA, self, &has_match);
+ if (has_match && !nm_utils_connection_match_spec_list(connection, specs, FALSE)) {
+ nm_utils_error_set_literal(error,
+ NM_UTILS_ERROR_CONNECTION_AVAILABLE_DISALLOWED,
+ "device configuration doesn't allow this connection");
+ return FALSE;
+ }
+
return TRUE;
}
diff --git a/src/core/nm-config-data.c b/src/core/nm-config-data.c
index e127ea23bb..0cbff02771 100644
--- a/src/core/nm-config-data.c
+++ b/src/core/nm-config-data.c
@@ -26,6 +26,15 @@ typedef struct {
gboolean has;
GSList * spec;
} match_device;
+ union {
+ struct {
+ GSList * allowed_connections;
+ gboolean allowed_connections_has;
+ } device;
+ };
+ gboolean is_device;
+
+ /* List of key/value pairs in the section, sorted by key */
gsize lookup_len;
const NMUtilsNamedValue *lookup_idx;
} MatchSectionInfo;
@@ -1436,13 +1445,13 @@ _match_section_infos_lookup(const MatchSectionInfo *match_section_infos,
match = TRUE;
if (match) {
- *out_value = value;
+ NM_SET_OUT(out_value, value);
return match_section_infos;
}
}
out:
- *out_value = NULL;
+ NM_SET_OUT(out_value, NULL);
return NULL;
}
@@ -1538,6 +1547,37 @@ nm_config_data_get_device_config_int64(const NMConfigData *self,
return _nm_utils_ascii_str_to_int64(value, base, min, max, val_invalid);
}
+const GSList *
+nm_config_data_get_device_allowed_connections_specs(const NMConfigData *self,
+ NMDevice * device,
+ gboolean * has_match)
+{
+ const NMConfigDataPrivate *priv;
+ const MatchSectionInfo * connection_info;
+ const GSList * ret = NULL;
+
+ g_return_val_if_fail(self, NULL);
+
+ priv = NM_CONFIG_DATA_GET_PRIVATE(self);
+
+ connection_info = _match_section_infos_lookup(&priv->device_infos[0],
+ priv->keyfile,
+ NM_CONFIG_KEYFILE_KEY_DEVICE_ALLOWED_CONNECTIONS,
+ device,
+ NULL,
+ NULL,
+ NULL);
+
+ if (connection_info) {
+ nm_assert(connection_info->device.allowed_connections_has);
+ ret = connection_info->device.allowed_connections;
+ NM_SET_OUT(has_match, TRUE);
+ } else
+ NM_SET_OUT(has_match, FALSE);
+
+ return ret;
+}
+
const char *
nm_config_data_get_connection_default(const NMConfigData *self,
const char * property,
@@ -1610,7 +1650,10 @@ _match_section_info_get_str(const MatchSectionInfo *m, GKeyFile *keyfile, const
}
static void
-_match_section_info_init(MatchSectionInfo *connection_info, GKeyFile *keyfile, char *group)
+_match_section_info_init(MatchSectionInfo *connection_info,
+ GKeyFile * keyfile,
+ char * group,
+ gboolean is_device)
{
char ** keys = NULL;
gsize n_keys;
@@ -1629,6 +1672,14 @@ _match_section_info_init(MatchSectionInfo *connection_info, GKeyFile *keyfile, c
connection_info->stop_match =
nm_config_keyfile_get_boolean(keyfile, group, NM_CONFIG_KEYFILE_KEY_STOP_MATCH, FALSE);
+ if (is_device) {
+ connection_info->device.allowed_connections =
+ nm_config_get_match_spec(keyfile,
+ group,
+ NM_CONFIG_KEYFILE_KEY_DEVICE_ALLOWED_CONNECTIONS,
+ &connection_info->device.allowed_connections_has);
+ }
+
keys = g_key_file_get_keys(keyfile, group, &n_keys, NULL);
nm_utils_strv_sort(keys, n_keys);
@@ -1680,9 +1731,13 @@ _match_section_infos_free(MatchSectionInfo *match_section_infos)
if (!match_section_infos)
return;
+
for (m = match_section_infos; m->group_name; m++) {
g_free(m->group_name);
g_slist_free_full(m->match_device.spec, g_free);
+ if (m->is_device) {
+ g_slist_free_full(m->device.allowed_connections, g_free);
+ }
for (i = 0; i < m->lookup_len; i++) {
g_free(m->lookup_idx[i].name_mutable);
g_free(m->lookup_idx[i].value_str_mutable);
@@ -1693,12 +1748,16 @@ _match_section_infos_free(MatchSectionInfo *match_section_infos)
}
static MatchSectionInfo *
-_match_section_infos_construct(GKeyFile *keyfile, const char *prefix)
+_match_section_infos_construct(GKeyFile *keyfile, gboolean is_device)
{
char ** groups;
gsize i, j, ngroups;
char * connection_tag = NULL;
MatchSectionInfo *match_section_infos = NULL;
+ const char * prefix;
+
+ prefix =
+ is_device ? NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE : NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION;
/* get the list of existing [connection.\+]/[device.\+] sections.
*
@@ -1730,13 +1789,17 @@ _match_section_infos_construct(GKeyFile *keyfile, const char *prefix)
}
match_section_infos = g_new0(MatchSectionInfo, ngroups + 1 + (connection_tag ? 1 : 0));
+ match_section_infos->is_device = is_device;
for (i = 0; i < ngroups; i++) {
/* pass ownership of @group on... */
- _match_section_info_init(&match_section_infos[i], keyfile, groups[ngroups - i - 1]);
+ _match_section_info_init(&match_section_infos[i],
+ keyfile,
+ groups[ngroups - i - 1],
+ is_device);
}
if (connection_tag) {
/* pass ownership of @connection_tag on... */
- _match_section_info_init(&match_section_infos[i], keyfile, connection_tag);
+ _match_section_info_init(&match_section_infos[i], keyfile, connection_tag, is_device);
}
g_free(groups);
@@ -1950,10 +2013,8 @@ constructed(GObject *object)
priv->keyfile = _merge_keyfiles(priv->keyfile_user, priv->keyfile_intern);
- priv->connection_infos =
- _match_section_infos_construct(priv->keyfile, NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION);
- priv->device_infos =
- _match_section_infos_construct(priv->keyfile, NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE);
+ priv->connection_infos = _match_section_infos_construct(priv->keyfile, FALSE);
+ priv->device_infos = _match_section_infos_construct(priv->keyfile, TRUE);
priv->connectivity.enabled =
nm_config_keyfile_get_boolean(priv->keyfile,
diff --git a/src/core/nm-config-data.h b/src/core/nm-config-data.h
index 42d69a8b92..fa58d869c7 100644
--- a/src/core/nm-config-data.h
+++ b/src/core/nm-config-data.h
@@ -243,6 +243,10 @@ gint64 nm_config_data_get_device_config_int64(const NMConfigData *self,
gint64 val_no_match,
gint64 val_invalid);
+const GSList *nm_config_data_get_device_allowed_connections_specs(const NMConfigData *self,
+ NMDevice * device,
+ gboolean * has_match);
+
char ** nm_config_data_get_groups(const NMConfigData *self);
char ** nm_config_data_get_keys(const NMConfigData *self, const char *group);
gboolean nm_config_data_is_intern_atomic_group(const NMConfigData *self, const char *group);
diff --git a/src/core/nm-config.c b/src/core/nm-config.c
index 981950ff70..817368d1cd 100644
--- a/src/core/nm-config.c
+++ b/src/core/nm-config.c
@@ -796,6 +796,7 @@ static gboolean
_setting_is_device_spec(const char *group, const char *key)
{
#define _IS(group_v, key_v) (nm_streq(group, "" group_v "") && nm_streq(key, "" key_v ""))
+
return _IS(NM_CONFIG_KEYFILE_GROUP_MAIN, NM_CONFIG_KEYFILE_KEY_MAIN_NO_AUTO_DEFAULT)
|| _IS(NM_CONFIG_KEYFILE_GROUP_MAIN, NM_CONFIG_KEYFILE_KEY_MAIN_IGNORE_CARRIER)
|| _IS(NM_CONFIG_KEYFILE_GROUP_MAIN, NM_CONFIG_KEYFILE_KEY_MAIN_ASSUME_IPV6LL_ONLY)
@@ -807,6 +808,13 @@ _setting_is_device_spec(const char *group, const char *key)
}
static gboolean
+_setting_is_connection_spec(const char *group, const char *key)
+{
+ return NM_STR_HAS_PREFIX(group, NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE)
+ && nm_streq(key, NM_CONFIG_KEYFILE_KEY_DEVICE_ALLOWED_CONNECTIONS);
+}
+
+static gboolean
_setting_is_string_list(const char *group, const char *key)
{
return _IS(NM_CONFIG_KEYFILE_GROUP_MAIN, NM_CONFIG_KEYFILE_KEY_MAIN_PLUGINS)
@@ -879,6 +887,7 @@ static const ConfigGroup config_groups[] = {
NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED,
NM_CONFIG_KEYFILE_KEY_DEVICE_SRIOV_NUM_VFS,
NM_CONFIG_KEYFILE_KEY_DEVICE_KEEP_CONFIGURATION,
+ NM_CONFIG_KEYFILE_KEY_DEVICE_ALLOWED_CONNECTIONS,
NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_BACKEND,
NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_SCAN_RAND_MAC_ADDRESS,
NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_SCAN_GENERATE_MAC_ADDRESS_MASK,
@@ -1060,7 +1069,8 @@ read_config(GKeyFile * keyfile,
is_string_list = _setting_is_string_list(group, base_key);
- if (is_string_list || _setting_is_device_spec(group, base_key)) {
+ if (is_string_list || _setting_is_device_spec(group, base_key)
+ || _setting_is_connection_spec(group, base_key)) {
gs_unref_ptrarray GPtrArray *new = g_ptr_array_new_with_free_func(g_free);
char ** iter_val;
gs_strfreev char **old_val = NULL;
diff --git a/src/core/settings/nm-settings.c b/src/core/settings/nm-settings.c
index 843d073e2c..8ac162d057 100644
--- a/src/core/settings/nm-settings.c
+++ b/src/core/settings/nm-settings.c
@@ -498,6 +498,8 @@ _startup_complete_check_is_ready(NMSettings * self,
conn = nm_settings_connection_get_connection(sett_conn);
nm_manager_for_each_device (priv->manager, device, tmp_lst) {
+ gs_free_error GError *error = NULL;
+
if (!nm_device_is_real(device))
continue;
@@ -508,7 +510,13 @@ _startup_complete_check_is_ready(NMSettings * self,
continue;
}
- if (!nm_device_check_connection_compatible(device, conn, NULL))
+ /* Check that device is compatible with the device. We are also happy
+ * with a device compatible but for which the connection is disallowed
+ * by NM configuration. */
+ if (!nm_device_check_connection_compatible(device, conn, &error)
+ && !g_error_matches(error,
+ NM_UTILS_ERROR,
+ NM_UTILS_ERROR_CONNECTION_AVAILABLE_DISALLOWED))
continue;
return TRUE;
diff --git a/src/libnm-base/nm-config-base.h b/src/libnm-base/nm-config-base.h
index 9ef5d7f846..c413e867ea 100644
--- a/src/libnm-base/nm-config-base.h
+++ b/src/libnm-base/nm-config-base.h
@@ -63,6 +63,7 @@
#define NM_CONFIG_KEYFILE_KEY_DEVICE_IGNORE_CARRIER "ignore-carrier"
#define NM_CONFIG_KEYFILE_KEY_DEVICE_SRIOV_NUM_VFS "sriov-num-vfs"
#define NM_CONFIG_KEYFILE_KEY_DEVICE_KEEP_CONFIGURATION "keep-configuration"
+#define NM_CONFIG_KEYFILE_KEY_DEVICE_ALLOWED_CONNECTIONS "allowed-connections"
#define NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_BACKEND "wifi.backend"
#define NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_SCAN_RAND_MAC_ADDRESS "wifi.scan-rand-mac-address"
#define NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_SCAN_GENERATE_MAC_ADDRESS_MASK \
diff --git a/src/libnm-glib-aux/nm-shared-utils.h b/src/libnm-glib-aux/nm-shared-utils.h
index 8d12f05ef5..ac522e6d21 100644
--- a/src/libnm-glib-aux/nm-shared-utils.h
+++ b/src/libnm-glib-aux/nm-shared-utils.h
@@ -1274,6 +1274,7 @@ typedef enum {
NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE,
NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE,
NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
+ NM_UTILS_ERROR_CONNECTION_AVAILABLE_DISALLOWED,
NM_UTILS_ERROR_SETTING_MISSING,