diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml
index 819c051e20..2eba34dff2 100644
--- a/man/NetworkManager.conf.xml
+++ b/man/NetworkManager.conf.xml
@@ -1685,6 +1685,55 @@ interface-name:vboxnet*,except:interface-name:vboxnet2
+
+
+ Connection List Format
+
+ Connections can be specified using the following format:
+
+
+
+
+ *
+ Matches every connection.
+
+
+ uuid:UUID
+ Match the connection by UUID, for example
+ "uuid:83037490-1d17-4986-a397-01f1db3a7fc2"
+
+
+ id=ID
+ Match the connection by name.
+
+
+ origin:ORIGIN
+ Match the connection by origin, stored in the
+ org.freedesktop.NetworkManager.origin tag of the user setting. For example, use
+ "except:origin:nm-initrd-generator" to forbid activation of connections created by the
+ initrd generator.
+
+
+ except:SPEC
+ Negative match of a connection. A negative match has higher priority then the positive
+ matches above.
+ 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.
+
+
+ SPEC[,;]SPEC
+ Multiple specs can be concatenated with commas or semicolons. The order does not matter as
+ matches are either inclusive or negative (except:), with negative matches having higher
+ priority.
+ 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').
+
+
+
+
+
diff --git a/src/core/nm-core-utils.c b/src/core/nm-core-utils.c
index ec4d724454..eda63c5b4c 100644
--- a/src/core/nm-core-utils.c
+++ b/src/core/nm-core-utils.c
@@ -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)
{
diff --git a/src/core/nm-core-utils.h b/src/core/nm-core-utils.h
index 920330bc43..a2b94e6711 100644
--- a/src/core/nm-core-utils.h
+++ b/src/core/nm-core-utils.h
@@ -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,