mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-29 01:00:09 +01:00
merge: branch 'bg/rh1934122'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/862
(cherry picked from commit 2d879c1ac5)
This commit is contained in:
commit
2188c00ed4
14 changed files with 398 additions and 43 deletions
|
|
@ -1150,6 +1150,63 @@ managed=1
|
|||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry id="keep-configuration">
|
||||
<term><varname>keep-configuration</varname></term>
|
||||
<listitem>
|
||||
<para>
|
||||
On startup, NetworkManager tries to not interfere with
|
||||
interfaces that are already configured. It does so by
|
||||
generating a in-memory connection based on the interface
|
||||
current configuration.
|
||||
</para>
|
||||
<para>
|
||||
If this generated connection matches one of the existing
|
||||
persistent connections, the persistent connection gets
|
||||
activated. If there is no match, the generated
|
||||
connection gets activated as "external", which means
|
||||
that the connection is considered as active, but
|
||||
NetworkManager doesn't actually touch the interface.
|
||||
</para>
|
||||
<para>
|
||||
It is possible to disable this behavior by setting
|
||||
<literal>keep-configuration</literal> to
|
||||
<literal>no</literal>. In this way, on startup
|
||||
NetworkManager always tries to activate the most
|
||||
suitable persistent connection (the one with highest
|
||||
autoconnect-priority or, in case of a tie, the one
|
||||
activated most recently).
|
||||
</para>
|
||||
<para>
|
||||
Note that when NetworkManager gets restarted, it stores
|
||||
the previous state in
|
||||
<filename>/run/NetworkManager</filename>; in particular
|
||||
it saves the UUID of the connection that was previously
|
||||
active so that it can be activated again after the
|
||||
restart. Therefore,
|
||||
<literal>keep-configuration</literal> does not have
|
||||
any effect on service restart.
|
||||
</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>
|
||||
|
|
@ -1647,6 +1704,55 @@ interface-name:vboxnet*,except:interface-name:vboxnet2
|
|||
</programlisting>
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2 id="connection-spec">
|
||||
<title>Connection List Format</title>
|
||||
<para>
|
||||
Connections can be specified using the following format:
|
||||
</para>
|
||||
<para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>*</term>
|
||||
<listitem><para>Matches every connection.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>uuid:UUID</term>
|
||||
<listitem><para>Match the connection by UUID, for example
|
||||
<literal>"uuid:83037490-1d17-4986-a397-01f1db3a7fc2"</literal></para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>id=ID</term>
|
||||
<listitem><para>Match the connection by name.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>origin:ORIGIN</term>
|
||||
<listitem><para>Match the connection by origin, stored in the
|
||||
<literal>org.freedesktop.NetworkManager.origin</literal> tag of the user setting. For example, use
|
||||
<literal>"except:origin:nm-initrd-generator"</literal> to forbid activation of connections created by the
|
||||
initrd generator.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>except:SPEC</term>
|
||||
<listitem><para>Negative match of a connection. A negative match has higher priority then the positive
|
||||
matches above.</para>
|
||||
<para>If there is a list consisting only of negative matches, the behavior is the same as if there is also
|
||||
match-all. That means, if none of all the negative matches is satisfied, the overall result is still a
|
||||
positive match.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>SPEC[,;]SPEC</term>
|
||||
<listitem><para>Multiple specs can be concatenated with commas or semicolons. The order does not matter as
|
||||
matches are either inclusive or negative (<literal>except:</literal>), with negative matches having higher
|
||||
priority.</para>
|
||||
<para>Backslash is supported to escape the separators ';' and ',', and to express special characters such as
|
||||
newline ('\n'), tabulator ('\t'), whitespace ('\s') and backslash ('\\'). Whitespace is not a separator but
|
||||
will be trimmed between two specs (unless escaped as '\s').</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
|
|
|||
|
|
@ -7239,6 +7239,16 @@ _get_maybe_ipv6_disabled(NMDevice *self)
|
|||
return (nm_platform_sysctl_get_int32(platform, NMP_SYSCTL_PATHID_ABSOLUTE(path), 0) == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* nm_device_generate_connection:
|
||||
*
|
||||
* Generates a connection from an existing interface.
|
||||
*
|
||||
* If the device doesn't have an IP configuration and it's not a port or a
|
||||
* controller, then no connection gets generated and the function returns
|
||||
* %NULL. In such case, @maybe_later is set to %TRUE if a connection can be
|
||||
* generated later when an IP address is assigned to the interface.
|
||||
*/
|
||||
NMConnection *
|
||||
nm_device_generate_connection(NMDevice *self,
|
||||
NMDevice *master,
|
||||
|
|
@ -7495,6 +7505,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) {
|
||||
|
|
@ -7571,6 +7583,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;
|
||||
}
|
||||
|
||||
|
|
@ -7637,7 +7658,7 @@ nm_device_check_slave_connection_compatible(NMDevice *self, NMConnection *slave)
|
|||
*
|
||||
* Returns: %TRUE if the device is capable of assuming connections, %FALSE if not
|
||||
*/
|
||||
static gboolean
|
||||
gboolean
|
||||
nm_device_can_assume_connections(NMDevice *self)
|
||||
{
|
||||
return !!NM_DEVICE_GET_CLASS(self)->update_connection;
|
||||
|
|
|
|||
|
|
@ -527,6 +527,7 @@ nm_device_check_connection_compatible(NMDevice *device, NMConnection *connection
|
|||
|
||||
gboolean nm_device_check_slave_connection_compatible(NMDevice *device, NMConnection *connection);
|
||||
|
||||
gboolean nm_device_can_assume_connections(NMDevice *self);
|
||||
gboolean nm_device_unmanage_on_quit(NMDevice *self);
|
||||
|
||||
gboolean nm_device_spec_match_list(NMDevice *device, const GSList *specs);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -806,6 +807,13 @@ _setting_is_device_spec(const char *group, const char *key)
|
|||
&& nm_streq(key, NM_CONFIG_KEYFILE_KEY_MATCH_DEVICE));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
@ -878,6 +886,8 @@ static const ConfigGroup config_groups[] = {
|
|||
NM_CONFIG_KEYFILE_KEY_DEVICE_IGNORE_CARRIER,
|
||||
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,
|
||||
|
|
@ -1059,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;
|
||||
|
|
|
|||
|
|
@ -1484,6 +1484,112 @@ nm_match_spec_device(const GSList *specs,
|
|||
return _match_result(has_except, has_not_except, has_match, has_match_except);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char *uuid;
|
||||
const char *id;
|
||||
const char *origin;
|
||||
} MatchConnectionData;
|
||||
|
||||
static gboolean
|
||||
match_connection_eval(const char *spec_str, const MatchConnectionData *match_data)
|
||||
{
|
||||
if (spec_str[0] == '*' && spec_str[1] == '\0')
|
||||
return TRUE;
|
||||
|
||||
if (_MATCH_CHECK(spec_str, "id:"))
|
||||
return nm_streq0(spec_str, match_data->id);
|
||||
|
||||
if (_MATCH_CHECK(spec_str, "uuid:"))
|
||||
return nm_streq0(spec_str, match_data->uuid);
|
||||
|
||||
if (_MATCH_CHECK(spec_str, "origin:"))
|
||||
return nm_streq0(spec_str, match_data->origin);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static NMMatchSpecMatchType
|
||||
match_spec_connection(const GSList *specs, const char *id, const char *uuid, const char *origin)
|
||||
{
|
||||
const GSList * iter;
|
||||
gboolean has_match = FALSE;
|
||||
gboolean has_match_except = FALSE;
|
||||
gboolean has_except = FALSE;
|
||||
gboolean has_not_except = FALSE;
|
||||
const char * spec_str;
|
||||
const MatchConnectionData match_data = {
|
||||
.id = nm_str_not_empty(id),
|
||||
.uuid = nm_str_not_empty(uuid),
|
||||
.origin = nm_str_not_empty(origin),
|
||||
};
|
||||
|
||||
if (!specs)
|
||||
return NM_MATCH_SPEC_NO_MATCH;
|
||||
|
||||
for (iter = specs; iter; iter = iter->next) {
|
||||
gboolean except;
|
||||
|
||||
spec_str = iter->data;
|
||||
|
||||
if (!spec_str || !*spec_str)
|
||||
continue;
|
||||
|
||||
spec_str = match_except(spec_str, &except);
|
||||
|
||||
if (except)
|
||||
has_except = TRUE;
|
||||
else
|
||||
has_not_except = TRUE;
|
||||
|
||||
if ((except && has_match_except) || (!except && has_match)) {
|
||||
/* evaluating the match does not give new information. Skip it. */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!match_connection_eval(spec_str, &match_data))
|
||||
continue;
|
||||
|
||||
if (except)
|
||||
has_match_except = TRUE;
|
||||
else
|
||||
has_match = TRUE;
|
||||
}
|
||||
|
||||
return _match_result(has_except, has_not_except, has_match, has_match_except);
|
||||
}
|
||||
|
||||
int
|
||||
nm_utils_connection_match_spec_list(NMConnection *connection,
|
||||
const GSList *specs,
|
||||
int no_match_value)
|
||||
{
|
||||
NMMatchSpecMatchType m;
|
||||
NMSettingUser * s_user;
|
||||
const char * origin = NULL;
|
||||
|
||||
if (!specs)
|
||||
return no_match_value;
|
||||
|
||||
s_user = _nm_connection_get_setting(connection, NM_TYPE_SETTING_USER);
|
||||
if (s_user)
|
||||
origin = nm_setting_user_get_data(s_user, NM_USER_TAG_ORIGIN);
|
||||
|
||||
m = match_spec_connection(specs,
|
||||
nm_connection_get_id(connection),
|
||||
nm_connection_get_uuid(connection),
|
||||
origin);
|
||||
switch (m) {
|
||||
case NM_MATCH_SPEC_MATCH:
|
||||
return TRUE;
|
||||
case NM_MATCH_SPEC_NEG_MATCH:
|
||||
return FALSE;
|
||||
case NM_MATCH_SPEC_NO_MATCH:
|
||||
return no_match_value;
|
||||
}
|
||||
nm_assert_not_reached();
|
||||
return no_match_value;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
match_config_eval(const char *str, const char *tag, guint cur_nm_version)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -211,6 +211,10 @@ gboolean nm_utils_kernel_cmdline_match_check(const char *const *proc_cmdline,
|
|||
guint num_patterns,
|
||||
GError ** error);
|
||||
|
||||
int nm_utils_connection_match_spec_list(NMConnection *connection,
|
||||
const GSList *specs,
|
||||
int no_match_value);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
gboolean nm_utils_connection_has_default_route(NMConnection *connection,
|
||||
|
|
|
|||
|
|
@ -2595,6 +2595,12 @@ get_existing_connection(NMManager *self, NMDevice *device, gboolean *out_generat
|
|||
|
||||
nm_device_capture_initial_config(device);
|
||||
|
||||
if (!nm_device_can_assume_connections(device)) {
|
||||
nm_device_assume_state_reset(device);
|
||||
_LOG2D(LOGD_DEVICE, device, "assume: device cannot assume connection");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ifindex) {
|
||||
int master_ifindex = nm_platform_link_get_master(priv->platform, ifindex);
|
||||
|
||||
|
|
@ -2626,39 +2632,47 @@ get_existing_connection(NMManager *self, NMDevice *device, gboolean *out_generat
|
|||
}
|
||||
}
|
||||
|
||||
/* The core of the API is nm_device_generate_connection() function and
|
||||
* update_connection() virtual method and the convenient connection_type
|
||||
* class attribute. Subclasses supporting the new API must have
|
||||
* update_connection() implemented, otherwise nm_device_generate_connection()
|
||||
* returns NULL.
|
||||
*/
|
||||
connection = nm_device_generate_connection(device, master, &maybe_later, &gen_error);
|
||||
if (!connection) {
|
||||
if (maybe_later) {
|
||||
/* The device can generate a connection, but it failed for now.
|
||||
* Give it a chance to match a connection from the state file. */
|
||||
only_by_uuid = TRUE;
|
||||
} else {
|
||||
nm_device_assume_state_reset(device);
|
||||
_LOG2D(LOGD_DEVICE,
|
||||
device,
|
||||
"assume: cannot generate connection: %s",
|
||||
gen_error->message);
|
||||
return NULL;
|
||||
if (nm_config_data_get_device_config_boolean(NM_CONFIG_GET_DATA,
|
||||
NM_CONFIG_KEYFILE_KEY_DEVICE_KEEP_CONFIGURATION,
|
||||
device,
|
||||
TRUE,
|
||||
TRUE)) {
|
||||
/* The core of the API is nm_device_generate_connection() function, based on
|
||||
* update_connection() virtual method and the @connection_type_supported
|
||||
* class attribute. Devices that support assuming existing connections must
|
||||
* have update_connection() implemented, otherwise
|
||||
* nm_device_generate_connection() returns NULL. */
|
||||
connection = nm_device_generate_connection(device, master, &maybe_later, &gen_error);
|
||||
if (!connection) {
|
||||
if (maybe_later) {
|
||||
/* The device can potentially assume connections, but at this
|
||||
* time we can't generate a connection because no address is
|
||||
* configured. Allow the device to assume a connection indicated
|
||||
* in the state file by UUID. */
|
||||
only_by_uuid = TRUE;
|
||||
} else {
|
||||
nm_device_assume_state_reset(device);
|
||||
_LOG2D(LOGD_DEVICE,
|
||||
device,
|
||||
"assume: cannot generate connection: %s",
|
||||
gen_error->message);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
connection = NULL;
|
||||
only_by_uuid = TRUE;
|
||||
g_set_error(&gen_error,
|
||||
NM_DEVICE_ERROR,
|
||||
NM_DEVICE_ERROR_FAILED,
|
||||
"device %s has 'keep-configuration=no'",
|
||||
nm_device_get_iface(device));
|
||||
}
|
||||
|
||||
nm_device_assume_state_get(device, &assume_state_guess_assume, &assume_state_connection_uuid);
|
||||
|
||||
/* Now we need to compare the generated connection to each configured
|
||||
* connection. The comparison function is the heart of the connection
|
||||
* assumption implementation and it must compare the connections very
|
||||
* carefully to sort out various corner cases. Also, the comparison is
|
||||
* not entirely symmetric.
|
||||
*
|
||||
* When no configured connection matches the generated connection, we keep
|
||||
* the generated connection instead.
|
||||
*/
|
||||
/* If the device state file indicates a connection that was active before NM
|
||||
* restarted, perform basic sanity checks on it. */
|
||||
if (assume_state_connection_uuid
|
||||
&& (connection_checked =
|
||||
nm_settings_get_connection_by_uuid(priv->settings, assume_state_connection_uuid))
|
||||
|
|
@ -2692,8 +2706,9 @@ get_existing_connection(NMManager *self, NMDevice *device, gboolean *out_generat
|
|||
gs_free NMSettingsConnection **sett_conns = NULL;
|
||||
guint len, i, j;
|
||||
|
||||
/* the state file doesn't indicate a connection UUID to assume. Search the
|
||||
* persistent connections for a matching candidate. */
|
||||
/* @assume_state_guess_assume=TRUE means this is the first start of NM
|
||||
* and the state file contains no UUID. Search persistent connections
|
||||
* for a matching candidate. */
|
||||
sett_conns = nm_manager_get_activatable_connections(self, FALSE, FALSE, &len);
|
||||
if (len > 0) {
|
||||
for (i = 0, j = 0; i < len; i++) {
|
||||
|
|
@ -2766,6 +2781,8 @@ get_existing_connection(NMManager *self, NMDevice *device, gboolean *out_generat
|
|||
return matched;
|
||||
}
|
||||
|
||||
/* When no configured connection matches the generated connection, we keep
|
||||
* the generated connection instead. */
|
||||
_LOG2D(LOGD_DEVICE,
|
||||
device,
|
||||
"assume: generated connection '%s' (%s)",
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -62,6 +62,8 @@
|
|||
#define NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED "managed"
|
||||
#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 \
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@
|
|||
#include "nm-setting-team-port.h"
|
||||
#include "nm-setting-team.h"
|
||||
#include "nm-setting-tun.h"
|
||||
#include "nm-setting-user.h"
|
||||
#include "nm-setting-veth.h"
|
||||
#include "nm-setting-vlan.h"
|
||||
#include "nm-setting-vpn.h"
|
||||
|
|
@ -79,6 +80,10 @@
|
|||
#include "nm-vpn-editor-plugin.h"
|
||||
#include "libnm-core-aux-intern/nm-libnm-core-utils.h"
|
||||
|
||||
#define NM_USER_TAG_ORIGIN "org.freedesktop.NetworkManager.origin"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* NM_SETTING_COMPARE_FLAG_INFERRABLE: check whether a device-generated
|
||||
* connection can be replaced by a already-defined connection. This flag only
|
||||
* takes into account properties marked with the %NM_SETTING_PARAM_INFERRABLE
|
||||
|
|
|
|||
|
|
@ -1258,6 +1258,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,
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,14 @@ output_conn(gpointer key, gpointer value, gpointer user_data)
|
|||
gs_free char * data = NULL;
|
||||
gs_free_error GError *error = NULL;
|
||||
gsize len;
|
||||
NMSetting * setting;
|
||||
|
||||
setting = nm_setting_user_new();
|
||||
nm_connection_add_setting(connection, setting);
|
||||
nm_setting_user_set_data(NM_SETTING_USER(setting),
|
||||
NM_USER_TAG_ORIGIN,
|
||||
"nm-initrd-generator",
|
||||
NULL);
|
||||
|
||||
if (!nm_connection_normalize(connection, NULL, NULL, &error))
|
||||
goto err_out;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue