summary refs log tree commit diff
path: root/clients/common
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2019-07-31 10:51:42 +0200
committerMichael Biebl <biebl@debian.org>2019-07-31 10:51:42 +0200
commit2e5fa45ddfbb5cffa1e78221f1cea706e2f298af (patch)
tree86f69d36c56de3074280456eddc854a780b8e04b /clients/common
parent85563b7fc7ec2cd21e38debb9b28db342e2e8e7c (diff)
New upstream version 1.19.90 upstream/1.19.90
Diffstat (limited to 'clients/common')
-rw-r--r--clients/common/nm-meta-setting-access.c2
-rw-r--r--clients/common/nm-meta-setting-access.h1
-rw-r--r--clients/common/nm-meta-setting-desc.c690
-rw-r--r--clients/common/nm-meta-setting-desc.h12
-rw-r--r--clients/common/nm-polkit-listener.c1
-rw-r--r--clients/common/nm-polkit-listener.h1
-rw-r--r--clients/common/nm-secret-agent-simple.c1
-rw-r--r--clients/common/nm-secret-agent-simple.h1
-rw-r--r--clients/common/nm-vpn-helpers.c3
-rw-r--r--clients/common/nm-vpn-helpers.h1
-rw-r--r--clients/common/settings-docs.h21
-rw-r--r--clients/common/settings-docs.h.in21
-rw-r--r--clients/common/tests/meson.build44
-rw-r--r--clients/common/tests/test-clients-common.c (renamed from clients/common/tests/test-general.c)1
-rw-r--r--clients/common/tests/test-libnm-core-aux.c250
15 files changed, 662 insertions, 388 deletions
diff --git a/clients/common/nm-meta-setting-access.c b/clients/common/nm-meta-setting-access.c
index 8399f29d..ce5cd331 100644
--- a/clients/common/nm-meta-setting-access.c
+++ b/clients/common/nm-meta-setting-access.c
@@ -273,6 +273,7 @@ nm_meta_abstract_info_complete (const NMMetaAbstractInfo *abstract_info,
                                 gpointer environment_user_data,
                                 const NMMetaOperationContext *operation_context,
                                 const char *text,
+                                gboolean *out_complete_filename,
                                 char ***out_to_free)
 {
 	const char *const*values;
@@ -292,6 +293,7 @@ nm_meta_abstract_info_complete (const NMMetaAbstractInfo *abstract_info,
 	                                                 environment_user_data,
 	                                                 operation_context,
 	                                                 text,
+	                                                 out_complete_filename,
 	                                                 out_to_free);
 
 	nm_assert (!*out_to_free || values == (const char *const*) *out_to_free);
diff --git a/clients/common/nm-meta-setting-access.h b/clients/common/nm-meta-setting-access.h
index ec1c2ba0..38f22c7a 100644
--- a/clients/common/nm-meta-setting-access.h
+++ b/clients/common/nm-meta-setting-access.h
@@ -69,6 +69,7 @@ const char *const*nm_meta_abstract_info_complete (const NMMetaAbstractInfo *abst
                                                   gpointer environment_user_data,
                                                   const NMMetaOperationContext *operation_context,
                                                   const char *text,
+                                                  gboolean *out_complete_filename,
                                                   char ***out_to_free);
 
 /*****************************************************************************/
diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c
index 698ded86..c1a5c2a7 100644
--- a/clients/common/nm-meta-setting-desc.c
+++ b/clients/common/nm-meta-setting-desc.c
@@ -28,6 +28,7 @@
 #include "nm-glib-aux/nm-enum-utils.h"
 #include "nm-glib-aux/nm-secret-utils.h"
 #include "nm-libnm-core-intern/nm-libnm-core-utils.h"
+#include "nm-libnm-core-aux/nm-libnm-core-aux.h"
 
 #include "nm-vpn-helpers.h"
 #include "nm-client-utils.h"
@@ -76,6 +77,25 @@ _gtype_property_get_gtype (GType gtype, const char *property_name)
 
 /*****************************************************************************/
 
+static char *
+bytes_to_string (GBytes *bytes)
+{
+	const guint8 *data;
+	gsize len;
+
+	if (!bytes)
+		return NULL;
+
+	data = g_bytes_get_data (bytes, &len);
+	return nm_utils_bin2hexstr_full (data,
+	                                 len,
+	                                 '\0',
+	                                 TRUE,
+	                                 NULL);
+}
+
+/*****************************************************************************/
+
 static int
 _int64_cmp_desc (gconstpointer a,
                  gconstpointer b,
@@ -188,7 +208,7 @@ _value_strsplit (const char *value,
 	gsize len;
 
 	/* FIXME: some modes should support backslash escaping.
-	 * In particular, to distingish from _value_str_as_index_list(), which
+	 * In particular, to distinguish from _value_str_as_index_list(), which
 	 * does not accept '\\'. */
 
 	/* note that all modes remove empty tokens (",", "a,,b", ",,"). */
@@ -432,158 +452,7 @@ _parse_ip_route (int family,
 	return route;
 }
 
-static char *
-_dump_team_link_watcher (NMTeamLinkWatcher *watcher)
-{
-	const char *name;
-	NMTeamLinkWatcherArpPingFlags flags;
-	GString *w_dump;
-
-	if (!watcher)
-		return NULL;
-
-	w_dump = g_string_new (NULL);
-	name = nm_team_link_watcher_get_name (watcher);
-	g_string_append_printf (w_dump, "name=%s", name);
-
-#define DUMP_WATCHER_INT(str, watcher, name, key) \
-	G_STMT_START { \
-		int _val = nm_team_link_watcher_get_##key (watcher); \
-		\
-		if (_val) \
-			g_string_append_printf (str, " %s=%d", name, _val); \
-	} G_STMT_END;
-
-	if (nm_streq (name, NM_TEAM_LINK_WATCHER_ETHTOOL)) {
-		DUMP_WATCHER_INT (w_dump, watcher, "delay-up", delay_up);
-		DUMP_WATCHER_INT (w_dump, watcher, "delay-down", delay_down);
-		return g_string_free (w_dump, FALSE);
-	}
-	/* NM_TEAM_LINK_WATCHER_NSNA_PING and NM_TEAM_LINK_WATCHER_ARP_PING */
-	DUMP_WATCHER_INT (w_dump, watcher, "init-wait", init_wait);
-	DUMP_WATCHER_INT (w_dump, watcher, "interval", interval);
-	DUMP_WATCHER_INT (w_dump, watcher, "missed-max", missed_max);
-	g_string_append_printf (w_dump, " target-host=%s",
-	                        nm_team_link_watcher_get_target_host (watcher));
-
-	if (nm_streq (name, NM_TEAM_LINK_WATCHER_NSNA_PING))
-		return g_string_free (w_dump, FALSE);
-
-	DUMP_WATCHER_INT (w_dump, watcher, "vlanid", vlanid);
-#undef DUMP_WATCHER_INT
-	g_string_append_printf (w_dump, " source-host=%s",
-	                        nm_team_link_watcher_get_source_host (watcher));
-	flags = nm_team_link_watcher_get_flags (watcher);
-	if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE)
-		g_string_append_printf (w_dump, " validate-active=true");
-	if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE)
-		g_string_append_printf (w_dump, " validate-inactive=true");
-	if (flags & NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS)
-		g_string_append_printf (w_dump, "send-always=true");
-
-	return g_string_free (w_dump, FALSE);
-}
-
-static NMTeamLinkWatcher *
-_parse_team_link_watcher (const char *str,
-                          GError **error)
-{
-	gs_free const char **watcherv = NULL;
-	gs_free char *str_clean_free = NULL;
-	const char *str_clean;
-	guint i;
-	gs_free const char *name = NULL;
-	int val1 = 0, val2 = 0, val3 = 3, val4 = -1;
-	gs_free const char *target_host = NULL;
-	gs_free const char *source_host = NULL;
-	NMTeamLinkWatcherArpPingFlags flags = 0;
-
-	nm_assert (str);
-	nm_assert (!error || !*error);
-
-	str_clean = nm_strstrip_avoid_copy_a (300, str, &str_clean_free);
-	watcherv = nm_utils_strsplit_set (str_clean, " \t");
-	if (!watcherv) {
-		g_set_error (error, 1, 0, "'%s' is not valid", str);
-		return NULL;
-	}
-
-	for (i = 0; watcherv[i]; i++) {
-		gs_free const char **pair = NULL;
-
-		pair = nm_utils_strsplit_set (watcherv[i], "=");
-		if (!pair) {
-			g_set_error (error, 1, 0, "'%s' is not valid: %s", watcherv[i],
-			             "properties should be specified as 'key=value'");
-			return NULL;
-		}
-		if (!pair[1]) {
-			g_set_error (error, 1, 0, "'%s' is not valid: %s", watcherv[i],
-			             "missing key value");
-			return NULL;
-		}
-		if (pair[2]) {
-			g_set_error (error, 1, 0, "'%s' is not valid: %s", watcherv[i],
-			             "properties should be specified as 'key=value'");
-			return NULL;
-		}
-
-		if (nm_streq (pair[0], "name"))
-			name = g_strdup (pair[1]);
-		else if (   nm_streq (pair[0], "delay-up")
-		         || nm_streq (pair[0], "init-wait"))
-			val1 = _nm_utils_ascii_str_to_int64 (pair[1], 10, 0, G_MAXINT32, -1);
-		else if (   nm_streq (pair[0], "delay-down")
-		         || nm_streq (pair[0], "interval"))
-			val2 = _nm_utils_ascii_str_to_int64 (pair[1], 10, 0, G_MAXINT32, -1);
-		else if (nm_streq (pair[0], "missed-max"))
-			val3 = _nm_utils_ascii_str_to_int64 (pair[1], 10, 0, G_MAXINT32, -1);
-		else if (nm_streq (pair[0], "vlanid"))
-			val4 = _nm_utils_ascii_str_to_int64 (pair[1], 10, -1, 4094, -2);
-		else if (nm_streq (pair[0], "target-host"))
-			target_host = g_strdup (pair[1]);
-		else if (nm_streq (pair[0], "source-host"))
-			source_host = g_strdup (pair[1]);
-		else if (nm_streq (pair[0], "validate-active")) {
-			if (nm_streq (pair[1], "true"))
-				flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE;
-		} else if (nm_streq (pair[0], "validate-inactive")) {
-			if (nm_streq (pair[1], "true"))
-				flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE;
-		} else if (nm_streq (pair[0], "send-always")) {
-			if (nm_streq (pair[1], "true"))
-				flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS;
-		} else {
-			g_set_error (error, 1, 0, "'%s' is not valid: %s", watcherv[i],
-			             "unknown key");
-			return NULL;
-		}
-
-		if ((val1 < 0) || (val2 < 0) || (val3 < 0)) {
-			g_set_error (error, 1, 0, "'%s' is not valid: %s", watcherv[i],
-			             "value is not a valid number [0, MAXINT]");
-			return NULL;
-		}
-		if (val4 < -1) {
-			g_set_error (error, 1, 0, "'%s' is not valid: %s", watcherv[i],
-			             "value is not a valid number [-1, 4094]");
-			return NULL;
-		}
-	}
-
-	if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_ETHTOOL))
-		return nm_team_link_watcher_new_ethtool (val1, val2, error);
-	else if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_NSNA_PING))
-		return nm_team_link_watcher_new_nsna_ping (val1, val2, val3, target_host, error);
-	else if (nm_streq0 (name, NM_TEAM_LINK_WATCHER_ARP_PING))
-		return nm_team_link_watcher_new_arp_ping2 (val1, val2, val3, val4, target_host, source_host, flags, error);
-
-	if (!name)
-		g_set_error (error, 1, 0, "link watcher name missing");
-	else
-		g_set_error (error, 1, 0, "unknown link watcher name: '%s'", name);
-	return NULL;
-}
+/*****************************************************************************/
 
 /* Max priority values from libnm-core/nm-setting-vlan.c */
 #define MAX_SKB_PRIO   G_MAXUINT32
@@ -685,7 +554,6 @@ nmc_team_check_config (const char *config, char **out_config, GError **error)
 		_TEAM_CONFIG_TYPE_FILE,
 		_TEAM_CONFIG_TYPE_JSON,
 	} desired_type = _TEAM_CONFIG_TYPE_GUESS;
-	const char *filename = NULL;
 	size_t c_len = 0;
 	gs_free char *config_clone = NULL;
 
@@ -719,22 +587,10 @@ nmc_team_check_config (const char *config, char **out_config, GError **error)
 				             config);
 				return FALSE;
 			}
-			filename = config;
 			config = config_clone = g_steal_pointer (&contents);
 		}
 	}
 
-	if (!nm_utils_is_json_object (config, NULL)) {
-		if (filename) {
-			g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
-			             _("'%s' does not contain a valid team configuration"), filename);
-		} else {
-			g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
-			             _("team configuration must be a JSON object"));
-		}
-		return FALSE;
-	}
-
 	*out_config = (config == config_clone)
 	              ? g_steal_pointer (&config_clone)
 	              : g_strdup (config);
@@ -788,7 +644,7 @@ _env_warn_fcn (const NMMetaEnvironment *environment,
 	const NMMetaPropertyInfo *property_info, const NMMetaEnvironment *environment, gpointer environment_user_data, NMSetting *setting, const char *value, GError **error
 
 #define ARGS_COMPLETE_FCN \
-	const NMMetaPropertyInfo *property_info, const NMMetaEnvironment *environment, gpointer environment_user_data, const NMMetaOperationContext *operation_context, const char *text, char ***out_to_free
+	const NMMetaPropertyInfo *property_info, const NMMetaEnvironment *environment, gpointer environment_user_data, const NMMetaOperationContext *operation_context, const char *text, gboolean *out_complete_filename, char ***out_to_free
 
 #define ARGS_VALUES_FCN \
 	const NMMetaPropertyInfo *property_info, char ***out_to_free
@@ -849,9 +705,21 @@ _SET_FCN_DO_REMOVE (char modifier, const char *value)
 #define RETURN_STR_TO_FREE(val) \
 	G_STMT_START { \
 		char *_val = (val); \
+		\
 		return ((*(out_to_free)) = _val); \
 	} G_STMT_END
 
+#define RETURN_STR_TEMPORARY(val) \
+	G_STMT_START { \
+		const char *_val = (val); \
+		\
+		if (_val == NULL) \
+			return NULL; \
+		if (_val[0] == '\0') \
+			return ""; \
+		return ((*(out_to_free)) = g_strdup (_val)); \
+	} G_STMT_END
+
 static gboolean
 _gobject_property_is_default (NMSetting *setting, const char *prop_name)
 {
@@ -894,7 +762,7 @@ _gobject_property_reset (NMSetting *setting,
 
 	g_value_init (&v, pspec->value_type);
 	if (reset_default)
-		g_param_value_defaults (pspec, &v);
+		g_param_value_set_default (pspec, &v);
 	g_object_set_property (G_OBJECT (setting), prop_name, &v);
 	return TRUE;
 }
@@ -905,73 +773,167 @@ _gobject_property_reset_default (NMSetting *setting, const char *prop_name)
 	return _gobject_property_reset (setting, prop_name, TRUE);
 }
 
+static const char *
+_coerce_str_emptyunset (NMMetaAccessorGetType get_type,
+                        gboolean is_default,
+                        const char *cstr,
+                        char **out_str)
+{
+	nm_assert (out_str && !*out_str);
+	nm_assert (   (!is_default && cstr && cstr[0] != '\0')
+	           || NM_IN_STRSET (cstr, NULL, ""));
+
+	if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) {
+		if (   !cstr
+		    || cstr[0] == '\0') {
+			if (is_default)
+				return "";
+			else
+				return "\"\"";
+		}
+		nm_assert (!is_default);
+		return (*out_str = g_strdup_printf ("\"%s\"", cstr));
+	}
+
+	/* we coerce NULL/"" to either "" or " ". */
+	if (   !cstr
+	    || cstr[0] == '\0') {
+		if (is_default)
+			return "";
+		else
+			return " ";
+	}
+	nm_assert (!is_default);
+	return cstr;
+}
+
+static gboolean
+_is_default (const NMMetaPropertyInfo *property_info,
+             NMSetting *setting)
+{
+	if (   property_info->property_typ_data
+	    && property_info->property_typ_data->is_default_fcn)
+		return !!(property_info->property_typ_data->is_default_fcn (setting));
+
+	return _gobject_property_is_default (setting, property_info->property_name);
+
+}
+
 static gconstpointer
 _get_fcn_gobject_impl (const NMMetaPropertyInfo *property_info,
                        NMSetting *setting,
                        NMMetaAccessorGetType get_type,
+                       gboolean handle_emptyunset,
                        gboolean *out_is_default,
                        gpointer *out_to_free)
 {
 	const char *cstr;
 	GType gtype_prop;
 	nm_auto_unset_gvalue GValue val = G_VALUE_INIT;
+	gboolean is_default;
+	gboolean glib_handles_str_transform;
 
 	RETURN_UNSUPPORTED_GET_TYPE ();
-	NM_SET_OUT (out_is_default, _gobject_property_is_default (setting, property_info->property_name));
 
-	if (   property_info->property_typ_data
-	    && property_info->property_typ_data->is_default_fcn
-	    && property_info->property_typ_data->is_default_fcn (setting)) {
-		if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY)
-			return _("(default)");
-		return "";
-	}
+	is_default = _is_default (property_info, setting);
+
+	NM_SET_OUT (out_is_default, is_default);
 
 	gtype_prop = _gobject_property_get_gtype (G_OBJECT (setting), property_info->property_name);
 
+	glib_handles_str_transform = !NM_IN_SET (gtype_prop, G_TYPE_BOOLEAN,
+	                                                     G_TYPE_STRV,
+	                                                     G_TYPE_BYTES,
+	                                                     G_TYPE_HASH_TABLE);
+
+	if (glib_handles_str_transform) {
+		/* We rely on the type convertion of the gobject property to string. */
+		g_value_init (&val, G_TYPE_STRING);
+	} else
+		g_value_init (&val, gtype_prop);
+
+	g_object_get_property (G_OBJECT (setting), property_info->property_name, &val);
+
+	/* Currently only one particular property asks us to "handle_emptyunset".
+	 * So, don't implement it (yet) for the other types, where it's unneeded. */
+	nm_assert (   !handle_emptyunset
+	           || (   gtype_prop == G_TYPE_STRV
+	               && !glib_handles_str_transform));
+
+	if (glib_handles_str_transform)
+		RETURN_STR_TEMPORARY (g_value_get_string (&val));
+
 	if (gtype_prop == G_TYPE_BOOLEAN) {
 		gboolean b;
 
-		g_value_init (&val, gtype_prop);
-		g_object_get_property (G_OBJECT (setting), property_info->property_name, &val);
 		b = g_value_get_boolean (&val);
 		if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY)
 			cstr = b ? _("yes") : _("no");
 		else
 			cstr = b ? "yes" : "no";
 		return cstr;
-	} else {
-		char *str;
+	}
 
-		/* Note that we register certain transform functions in nmc_value_transforms_register().
-		 * This makes G_TYPE_STRV working.
-		 *
-		 * FIXME: that is particularly ugly because it's non-obvious which code relies
-		 * on nmc_value_transforms_register(). Also, nmc_value_transforms_register() is
-		 * in clients/cli, while we are here in clients/common. */
-		g_value_init (&val, G_TYPE_STRING);
-		g_object_get_property (G_OBJECT (setting), property_info->property_name, &val);
-		cstr = g_value_get_string (&val);
-
-		if (   property_info->property_typ_data
-		    && property_info->property_typ_data->is_default_fcn) {
-			if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) {
-				str =   cstr
-				      ? g_strdup_printf ("\"%s\"", cstr)
-				      : g_strdup ("");
-			} else
-				str = g_strdup (cstr && cstr[0] ? cstr : " ");
-		} else
-			str = cstr ? g_strdup (cstr) : NULL;
+	if (gtype_prop == G_TYPE_STRV) {
+		const char *const*strv;
+
+		strv = g_value_get_boxed (&val);
+		if (strv && strv[0])
+			RETURN_STR_TO_FREE (g_strjoinv (",", (char **) strv));
 
+		/* special hack for handling properties that can be empty and unset
+		 * (see multilist.clear_emptyunset_fcn). */
+		if (handle_emptyunset) {
+			char *str = NULL;
+
+			cstr = _coerce_str_emptyunset (get_type, is_default, NULL, &str);
+			if (str)
+				RETURN_STR_TO_FREE (str);
+			RETURN_STR_TEMPORARY (cstr);
+		}
+
+		return "";
+	}
+
+	if (gtype_prop == G_TYPE_BYTES) {
+		char *str;
+
+		str = bytes_to_string (g_value_get_boxed (&val));
+		NM_SET_OUT (out_is_default, !str || !str[0]);
 		RETURN_STR_TO_FREE (str);
 	}
+
+	if (gtype_prop == G_TYPE_HASH_TABLE) {
+		GHashTable *strdict;
+		gs_free const char **keys = NULL;
+		GString *str;
+		gsize i;
+
+		strdict = g_value_get_boxed (&val);
+		keys = nm_utils_strdict_get_keys (strdict, TRUE, NULL);
+		if (!keys)
+			return NULL;
+
+		str = g_string_new (NULL);
+		for (i = 0; keys[i]; i++) {
+			if (str->len > 0)
+				g_string_append_c (str, ',');
+			g_string_append_printf (str,
+			                        "%s=%s",
+			                        keys[i],
+			                        (const char *) g_hash_table_lookup (strdict, keys[i]));
+		}
+		RETURN_STR_TO_FREE (g_string_free (str, FALSE));
+	}
+
+	nm_assert_not_reached ();
+	return NULL;
 }
 
 static gconstpointer
 _get_fcn_gobject (ARGS_GET_FCN)
 {
-	return _get_fcn_gobject_impl (property_info, setting, get_type, out_is_default, out_to_free);
+	return _get_fcn_gobject_impl (property_info, setting, get_type, FALSE, out_is_default, out_to_free);
 }
 
 static gconstpointer
@@ -1063,7 +1025,7 @@ _get_fcn_gobject_mtu (ARGS_GET_FCN)
 
 	if (   !property_info->property_typ_data
 	    || !property_info->property_typ_data->subtype.mtu.get_fcn)
-		return _get_fcn_gobject_impl (property_info, setting, get_type, out_is_default, out_to_free);
+		return _get_fcn_gobject_impl (property_info, setting, get_type, FALSE, out_is_default, out_to_free);
 
 	mtu = property_info->property_typ_data->subtype.mtu.get_fcn (setting);
 	if (mtu == 0) {
@@ -1195,7 +1157,7 @@ _get_fcn_gobject_enum (ARGS_GET_FCN)
 		s =    format_numeric_hex
 		    || (   format_numeric_hex_unknown
 		        && !G_IS_ENUM_CLASS (gtype_class ?: (gtype_class = g_type_class_ref (gtype))))
-		    ? g_strdup_printf ("0x%"G_GINT64_FORMAT, v)
+		    ? g_strdup_printf ("0x%"G_GINT64_MODIFIER"x", v)
 		    : g_strdup_printf ("%"G_GINT64_FORMAT, v);
 		RETURN_STR_TO_FREE (g_steal_pointer (&s));
 	}
@@ -1213,7 +1175,7 @@ _get_fcn_gobject_enum (ARGS_GET_FCN)
 	if (   format_numeric_hex
 	    || (   format_numeric_hex_unknown
 	        && !G_IS_ENUM_CLASS (gtype_class ?: (gtype_class = g_type_class_ref (gtype)))))
-		nm_sprintf_buf (s_numeric, "0x%"G_GINT64_FORMAT, v);
+		nm_sprintf_buf (s_numeric, "0x%"G_GINT64_MODIFIER"x", v);
 	else
 		nm_sprintf_buf (s_numeric, "%"G_GINT64_FORMAT, v);
 
@@ -1723,23 +1685,6 @@ wep_key_type_to_string (NMWepKeyType type)
 }
 
 static char *
-bytes_to_string (GBytes *bytes)
-{
-	const guint8 *data;
-	gsize len;
-
-	if (!bytes)
-		return NULL;
-
-	data = g_bytes_get_data (bytes, &len);
-	return nm_utils_bin2hexstr_full (data,
-	                                 len,
-	                                 '\0',
-	                                 TRUE,
-	                                 NULL);
-}
-
-static char *
 vlan_flags_to_string (guint32 flags, NMMetaAccessorGetType get_type)
 {
 	GString *flag_str;
@@ -1839,19 +1784,41 @@ _multilist_do_validate (const NMMetaPropertyInfo *property_info,
 	return item;
 }
 
+static gconstpointer
+_get_fcn_multilist (ARGS_GET_FCN)
+{
+	return _get_fcn_gobject_impl (property_info,
+	                              setting,
+	                              get_type,
+	                              property_info->property_typ_data->subtype.multilist.clear_emptyunset_fcn != NULL,
+	                              out_is_default,
+	                              out_to_free);
+}
+
+static gboolean
+_multilist_clear_property (const NMMetaPropertyInfo *property_info,
+                           NMSetting *setting,
+                           gboolean is_set /* or else set default */)
+{
+	if (property_info->property_typ_data->subtype.multilist.clear_emptyunset_fcn) {
+		property_info->property_typ_data->subtype.multilist.clear_emptyunset_fcn (setting, is_set);
+		return TRUE;
+	}
+	if (property_info->property_typ_data->subtype.multilist.clear_all_fcn) {
+		property_info->property_typ_data->subtype.multilist.clear_all_fcn (setting);
+		return TRUE;
+	}
+	return _gobject_property_reset (setting, property_info->property_name, FALSE);
+}
+
 static gboolean
 _set_fcn_multilist (ARGS_SET_FCN)
 {
 	gs_free const char **strv = NULL;
 	gsize i, j, nstrv;
 
-	if (_SET_FCN_DO_RESET_DEFAULT_WITH_SUPPORTS_REMOVE (property_info, modifier, value)) {
-		if (property_info->property_typ_data->subtype.multilist.clear_all_fcn) {
-			property_info->property_typ_data->subtype.multilist.clear_all_fcn (setting);
-			return TRUE;
-		}
-		return _gobject_property_reset (setting, property_info->property_name, FALSE);
-	}
+	if (_SET_FCN_DO_RESET_DEFAULT_WITH_SUPPORTS_REMOVE (property_info, modifier, value))
+		return _multilist_clear_property (property_info, setting, FALSE);
 
 	if (   _SET_FCN_DO_REMOVE (modifier, value)
 	    && (   property_info->property_typ_data->subtype.multilist.remove_by_idx_fcn_u32
@@ -1884,6 +1851,11 @@ _set_fcn_multilist (ARGS_SET_FCN)
 		}
 	}
 
+	if (   _SET_FCN_DO_SET_ALL (modifier, value)
+	    && property_info->property_typ_data->subtype.multilist.clear_emptyunset_fcn
+	    && value[0] == '\0')
+		return _multilist_clear_property (property_info, setting, FALSE);
+
 	strv = _value_strsplit (value,
 	                          property_info->property_typ_data->subtype.multilist.strsplit_plain
 	                        ? VALUE_STRSPLIT_MODE_MULTILIST
@@ -1906,11 +1878,13 @@ _set_fcn_multilist (ARGS_SET_FCN)
 	}
 	nstrv = j;
 
-	if (_SET_FCN_DO_SET_ALL (modifier, value)) {
-		if (property_info->property_typ_data->subtype.multilist.clear_all_fcn)
-			property_info->property_typ_data->subtype.multilist.clear_all_fcn (setting);
-		else
-			_gobject_property_reset (setting, property_info->property_name, FALSE);
+	if (_SET_FCN_DO_SET_ALL (modifier, value))
+		_multilist_clear_property (property_info, setting, TRUE);
+	else if (   property_info->property_typ_data->subtype.multilist.clear_emptyunset_fcn
+	         && _is_default (property_info, setting)) {
+		/* the property is already the default. But we hav here a '+' / '-' modifier, so
+		 * that always makes it non-default (empty) first. */
+		_multilist_clear_property (property_info, setting, TRUE);
 	}
 
 	for (i = 0; i < nstrv; i++) {
@@ -2229,8 +2203,7 @@ _get_fcn_cert_8021x (ARGS_GET_FCN)
 
 	switch (vtable->scheme_func (s_8021X)) {
 	case NM_SETTING_802_1X_CK_SCHEME_BLOB:
-		if (   vtable->is_secret
-		    && !NM_FLAGS_HAS (get_flags, NM_META_ACCESSOR_GET_FLAGS_SHOW_SECRETS))
+		if (!NM_FLAGS_HAS (get_flags, NM_META_ACCESSOR_GET_FLAGS_SHOW_SECRETS))
 			return _get_text_hidden (get_type);
 		str = bytes_to_string (vtable->blob_func (s_8021X));
 		break;
@@ -2268,16 +2241,25 @@ _set_fcn_cert_8021x (ARGS_SET_FCN)
 	vtable = &nm_setting_8021x_scheme_vtable[property_info->property_typ_data->subtype.cert_8021x.scheme_type];
 
 	if (vtable->is_secret) {
-		gs_free char *path = NULL;
 		nm_auto_free_secret char *password_free = NULL;
-		char *password;
-
-		path = g_strdup (value);
-		password = path + strcspn (path, " \t");
-		if (password[0] != '\0') {
-			password[0] = '\0';
-			while (nm_utils_is_separator (password[0]))
-				password++;
+		gs_free const char **strv = NULL;
+		const char *password;
+		const char *path;
+		gsize len;
+
+		strv = nm_utils_escaped_tokens_split (value, NM_ASCII_SPACES);
+		len = NM_PTRARRAY_LEN (strv);
+		if (len > 2) {
+			g_set_error_literal (error,
+			                     NM_UTILS_ERROR,
+			                     NM_UTILS_ERROR_INVALID_ARGUMENT,
+			                     _("too many arguments. Please only specify a private key file and optionally a password"));
+			return FALSE;
+		}
+
+		path = len > 0 ? strv[0] : NULL;
+		if (len == 2) {
+			password = strv[1];
 		} else {
 			password_free = g_strdup (vtable->passwd_func (NM_SETTING_802_1X (setting)));
 			password = password_free;
@@ -2298,19 +2280,24 @@ _set_fcn_cert_8021x (ARGS_SET_FCN)
 	}
 }
 
-static gconstpointer
-_get_fcn_gobject_bytes (ARGS_GET_FCN)
+static const char *const*
+_complete_fcn_cert_8021x (ARGS_COMPLETE_FCN)
 {
-	gs_unref_bytes GBytes *bytes = NULL;
-	char *str;
+	const NMSetting8021xSchemeVtable *vtable;
 
-	RETURN_UNSUPPORTED_GET_TYPE ();
+	vtable = &nm_setting_8021x_scheme_vtable[property_info->property_typ_data->subtype.cert_8021x.scheme_type];
 
-	g_object_get (setting, property_info->property_name, &bytes, NULL);
+	if (vtable->is_secret) {
+		gs_free const char **strv = NULL;
 
-	str = bytes_to_string (bytes);
-	NM_SET_OUT (out_is_default, !str || !str[0]);
-	RETURN_STR_TO_FREE (str);
+		strv = nm_utils_escaped_tokens_split (text, NM_ASCII_SPACES);
+		/* don't try to complete the password */
+		if (NM_PTRARRAY_LEN (strv) > 1)
+			return NULL;
+	}
+
+	NM_SET_OUT (out_complete_filename, TRUE);
+	return NULL;
 }
 
 static gconstpointer
@@ -2479,8 +2466,9 @@ _complete_fcn_connection_type (ARGS_COMPLETE_FCN)
 	guint i, j;
 	char **result;
 	gsize text_len;
+	const char *slave_types[] = {"bond-slave", "bridge-slave", "team-slave"};
 
-	result = g_new (char *, _NM_META_SETTING_TYPE_NUM * 2 + 1);
+	result = g_new (char *, _NM_META_SETTING_TYPE_NUM * 2 + G_N_ELEMENTS (slave_types) + 1);
 
 	text_len = text ? strlen (text) : 0;
 
@@ -2500,6 +2488,12 @@ _complete_fcn_connection_type (ARGS_COMPLETE_FCN)
 		if (!text || strncmp (text, v, text_len) == 0)
 			result[j++] = g_strdup (v);
 	}
+	for (i = 0; i < G_N_ELEMENTS (slave_types); i++) {
+		const char *v = slave_types[i];
+
+		if (!text || strncmp (text, v, text_len) == 0)
+			result[j++] = g_strdup (v);
+	}
 	if (j)
 		result[j++] = NULL;
 	else {
@@ -3362,8 +3356,7 @@ _objlist_set_fcn_ip_config_routes (NMSetting *setting,
 static gboolean
 _is_default_func_ip_config_dns_options (NMSetting *setting)
 {
-	return    nm_setting_ip_config_has_dns_options (NM_SETTING_IP_CONFIG (setting))
-	       && !nm_setting_ip_config_get_num_dns_options (NM_SETTING_IP_CONFIG (setting));
+	return !nm_setting_ip_config_has_dns_options (NM_SETTING_IP_CONFIG (setting));
 }
 
 static void
@@ -3405,7 +3398,7 @@ _objlist_set_fcn_ip_config_routing_rules (NMSetting *setting,
 		return FALSE;
 
 	/* also for @do_add, we first always search whether such a rule already exist
-	 * and remove the first occurance.
+	 * and remove the first occurrence.
 	 *
 	 * The effect is, that we don't add multiple times the same rule,
 	 * and that if the rule already exists, it gets moved to the end (append).
@@ -3687,85 +3680,6 @@ _validate_fcn_team_config (const char *value, char **out_to_free, GError **error
 }
 
 static void
-_multilist_clear_all_fcn_team_runner_tx_hash (NMSetting *setting)
-{
-	/* Workaround libnm bug (confirmed against version 1.16.0).
-	 * We need to both clear the GObject property and call the libnm API.
-	 *
-	 * This workaround was added in nmcli as [1]. This needs fixing in libnm.
-	 *
-	 * Without this, CI test "team_abs_set_runner_tx_hash" fails.
-	 * Try (without the following workaround): */
-#if 0
-     $ (nmcli connection delete team0 ; :); \
-       nmcli connection add type team con-name team0 ifname team0 autoconnect no \
-           team.runner lacp && \
-       echo ">>> FIRST:" && \
-       PAGER= nmcli -o connection show team0 && \
-       nmcli connection modify team0 team.runner-tx-hash l3 && \
-       echo ">>> AFTER:" && \
-       PAGER= nmcli -o connection show team0
-#endif
-	/* See also:
-	 *
-	 *   - https://github.com/NetworkManager/NetworkManager/pull/318
-	 *   - https://bugzilla.redhat.com/show_bug.cgi?id=1691619
-	 *
-	 * [1] https://cgit.freedesktop.org/NetworkManager/NetworkManager/commit/?id=350dbb55abf3a80267c398e6f64c2cee4645475a
-	 */
-
-	/* it appears, we don't really need _gobject_property_reset(). Just to be sure
-	 * also call it. */
-	_gobject_property_reset (setting, NM_SETTING_TEAM_RUNNER_TX_HASH, FALSE);
-	while (nm_setting_team_get_num_runner_tx_hash (NM_SETTING_TEAM (setting)))
-		nm_setting_team_remove_runner_tx_hash (NM_SETTING_TEAM (setting), 0);
-}
-
-static void
-_objlist_clear_all_fcn_team_link_watchers (NMSetting *setting)
-{
-	/* the same workaround as _multilist_clear_all_fcn_team_runner_tx_hash() above.
-	 *
-	 * Reproduce with: */
-#if 0
-     $ (nmcli connection delete team0 ; :); \
-       nmcli connection add type team con-name team0 ifname team0 autoconnect no \
-             team.link-watchers 'name=arp_ping source-host=172.16.1.1 target-host=172.16.1.254, name=ethtool delay-up=3' && \
-       echo ">>> FIRST:" && \
-       PAGER= nmcli -o connection show team0 && \
-       nmcli connection modify team0 team.link-watchers 'name=ethtool delay-up=4' && \
-       echo ">>> AFTER:" && \
-       PAGER= nmcli -o connection show team0
-
-       (nmcli connection delete team0-slave ; :); \
-       nmcli connection add type ethernet con-name team0-slave master team0 slave-type team ifname eth0 autoconnect no \
-             team-port.link-watchers 'name=arp_ping source-host=172.16.1.1 target-host=172.16.1.254, name=ethtool delay-up=3' && \
-       echo ">>> FIRST:" && \
-       PAGER= nmcli -o connection show team0-slave && \
-       nmcli connection modify team0-slave team.link-watchers 'name=ethtool delay-up=4' && \
-       echo ">>> AFTER:" && \
-       PAGER= nmcli -o connection show team0-slave
-#endif
-	/* See also:
-	 *
-	 *   - https://cgit.freedesktop.org/NetworkManager/NetworkManager/commit/?id=72bf38cad6ca6033d0117bf67b0e726001922d8f
-	 *   - https://github.com/NetworkManager/NetworkManager/pull/318
-	 *   - https://bugzilla.redhat.com/show_bug.cgi?id=1691619
-	 */
-
-	/* In this case, it appears both GObject reset and nm_setting_team*_clear_link_watchers()
-	 * work (on their own). So, we might not need the workaround.
-	 * Just to be sure, as something is not right with libnm here. */
-	if (NM_IS_SETTING_TEAM (setting)) {
-		_gobject_property_reset (setting, NM_SETTING_TEAM_LINK_WATCHERS, FALSE);
-		nm_setting_team_clear_link_watchers (NM_SETTING_TEAM (setting));
-	} else {
-		_gobject_property_reset (setting, NM_SETTING_TEAM_PORT_LINK_WATCHERS, FALSE);
-		nm_setting_team_port_clear_link_watchers (NM_SETTING_TEAM_PORT (setting));
-	}
-}
-
-static void
 _objlist_obj_to_str_fcn_team_link_watchers (NMMetaAccessorGetType get_type,
                                             NMSetting *setting,
                                             guint idx,
@@ -3779,9 +3693,9 @@ _objlist_obj_to_str_fcn_team_link_watchers (NMMetaAccessorGetType get_type,
 	else
 		watcher = nm_setting_team_port_get_link_watcher (NM_SETTING_TEAM_PORT (setting), idx);
 
-	s = _dump_team_link_watcher (watcher);
+	s = nm_utils_team_link_watcher_to_string (watcher);
 	if (s)
-		g_string_append (str, s);
+		nm_utils_escaped_tokens_escape_gstr (s, ESCAPED_TOKENS_DELIMITERS, str);
 }
 
 static gboolean
@@ -3792,7 +3706,7 @@ _objlist_set_fcn_team_link_watchers (NMSetting *setting,
 {
 	nm_auto_unref_team_link_watcher NMTeamLinkWatcher *watcher = NULL;
 
-	watcher = _parse_team_link_watcher (value, error);
+	watcher = nm_utils_team_link_watcher_from_string (value, error);
 	if (!watcher)
 		return FALSE;
 	if (NM_IS_SETTING_TEAM (setting)) {
@@ -4412,7 +4326,7 @@ static const NMMetaPropertyType _pt_gobject_mtu = {
 };
 
 static const NMMetaPropertyType _pt_gobject_bytes = {
-	.get_fcn =                     _get_fcn_gobject_bytes,
+	.get_fcn =                     _get_fcn_gobject,
 	.set_fcn =                     _set_fcn_gobject_bytes,
 };
 
@@ -4457,6 +4371,7 @@ static const NMMetaPropertyType _pt_dcb = {
 static const NMMetaPropertyType _pt_cert_8021x = {
 	.get_fcn =                      _get_fcn_cert_8021x,
 	.set_fcn =                      _set_fcn_cert_8021x,
+	.complete_fcn =                 _complete_fcn_cert_8021x,
 };
 
 static const NMMetaPropertyType _pt_ethtool = {
@@ -4466,7 +4381,7 @@ static const NMMetaPropertyType _pt_ethtool = {
 };
 
 static const NMMetaPropertyType _pt_multilist = {
-	.get_fcn =                      _get_fcn_gobject,
+	.get_fcn =                      _get_fcn_multilist,
 	.set_fcn =                      _set_fcn_multilist,
 	.set_supports_remove =          TRUE,
 };
@@ -4485,6 +4400,7 @@ static const NMMetaPropertyType _pt_objlist = {
 #define MULTILIST_REMOVE_BY_IDX_FCN_S(type, func)   (((func) == ((void     (*) (type *, int         )) (func))) ? ((void     (*) (NMSetting *, int         )) (func)) : NULL)
 #define MULTILIST_REMOVE_BY_IDX_FCN_U(type, func)   (((func) == ((void     (*) (type *, guint       )) (func))) ? ((void     (*) (NMSetting *, guint       )) (func)) : NULL)
 #define MULTILIST_REMOVE_BY_VALUE_FCN(type, func)   (((func) == ((gboolean (*) (type *, const char *)) (func))) ? ((gboolean (*) (NMSetting *, const char *)) (func)) : NULL)
+#define MULTILIST_CLEAR_EMPTYUNSET_FCN(type, func)  (((func) == ((void     (*) (type *, gboolean    )) (func))) ? ((void     (*) (NMSetting *, gboolean    )) (func)) : NULL)
 
 #define OBJLIST_GET_NUM_FCN(type, func)             (((func) == ((guint    (*) (type *              )) (func))) ? ((guint    (*) (NMSetting *              )) (func)) : NULL)
 #define OBJLIST_CLEAR_ALL_FCN(type, func)           (((func) == ((void     (*) (type *              )) (func))) ? ((void     (*) (NMSetting *              )) (func)) : NULL)
@@ -5270,6 +5186,9 @@ static const NMMetaPropertyInfo *const property_infos_CONNECTION[] = {
 			),
 		),
 	),
+	PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT,
+		.property_type =                &_pt_gobject_int,
+	),
 	NULL
 };
 
@@ -5595,6 +5514,7 @@ static const NMMetaPropertyInfo *const property_infos_IP4_CONFIG[] = {
 				.add_fcn =              _multilist_add_fcn_ip_config_dns_options,
 				.remove_by_idx_fcn_s =  MULTILIST_REMOVE_BY_IDX_FCN_S (NMSettingIPConfig, nm_setting_ip_config_remove_dns_option),
 				.remove_by_value_fcn =  MULTILIST_REMOVE_BY_VALUE_FCN (NMSettingIPConfig, nm_setting_ip_config_remove_dns_option_by_value),
+				.clear_emptyunset_fcn = MULTILIST_CLEAR_EMPTYUNSET_FCN (NMSettingIPConfig, nm_setting_ip_config_clear_dns_options),
 				.strsplit_plain =       TRUE,
 			),
 			.is_default_fcn =           _is_default_func_ip_config_dns_options,
@@ -5761,7 +5681,8 @@ static const NMMetaPropertyInfo *const property_infos_IP6_CONFIG[] = {
 			                                          NM_SETTING_IP6_CONFIG_METHOD_DHCP,
 			                                          NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL,
 			                                          NM_SETTING_IP6_CONFIG_METHOD_MANUAL,
-			                                          NM_SETTING_IP6_CONFIG_METHOD_SHARED),
+			                                          NM_SETTING_IP6_CONFIG_METHOD_SHARED,
+			                                          NM_SETTING_IP6_CONFIG_METHOD_DISABLED),
 		),
 	),
 	PROPERTY_INFO (NM_SETTING_IP_CONFIG_DNS, DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS,
@@ -5807,6 +5728,7 @@ static const NMMetaPropertyInfo *const property_infos_IP6_CONFIG[] = {
 				.add_fcn =              _multilist_add_fcn_ip_config_dns_options,
 				.remove_by_idx_fcn_s =  MULTILIST_REMOVE_BY_IDX_FCN_S (NMSettingIPConfig, nm_setting_ip_config_remove_dns_option),
 				.remove_by_value_fcn =  MULTILIST_REMOVE_BY_VALUE_FCN (NMSettingIPConfig, nm_setting_ip_config_remove_dns_option_by_value),
+				.clear_emptyunset_fcn = MULTILIST_CLEAR_EMPTYUNSET_FCN (NMSettingIPConfig, nm_setting_ip_config_clear_dns_options),
 				.strsplit_plain =       TRUE,
 			),
 			.is_default_fcn =           _is_default_func_ip_config_dns_options,
@@ -6201,6 +6123,21 @@ static const NMMetaPropertyInfo *const property_infos_OVS_BRIDGE[] = {
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_OVS_BRIDGE_STP_ENABLE,
 		.property_type =                &_pt_gobject_bool,
 	),
+	PROPERTY_INFO_WITH_DESC (NM_SETTING_OVS_BRIDGE_DATAPATH_TYPE,
+		.property_type =                &_pt_gobject_string,
+		.property_typ_data = DEFINE_PROPERTY_TYP_DATA (
+			.values_static =            NM_MAKE_STRV ("system", "netdev"),
+		),
+	),
+	NULL
+};
+
+#undef  _CURRENT_NM_META_SETTING_TYPE
+#define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_OVS_DPDK
+static const NMMetaPropertyInfo *const property_infos_OVS_DPDK[] = {
+	PROPERTY_INFO_WITH_DESC (NM_SETTING_OVS_DPDK_DEVARGS,
+		.property_type =                &_pt_gobject_string,
+	),
 	NULL
 };
 
@@ -6210,7 +6147,7 @@ static const NMMetaPropertyInfo *const property_infos_OVS_INTERFACE[] = {
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_OVS_INTERFACE_TYPE,
 		.property_type =                &_pt_gobject_string,
 		.property_typ_data = DEFINE_PROPERTY_TYP_DATA (
-			.values_static =            NM_MAKE_STRV ("internal", "patch"),
+			.values_static =            NM_MAKE_STRV ("internal", "system", "patch", "dpdk"),
 		),
 	),
 	NULL
@@ -6524,6 +6461,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = {
 		.property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int,
 			.value_infos =              INT_VALUE_INFOS (
 				{
+					.value.i64 = -1,
+					.nick = "unset",
+				},
+				{
 					.value.i64 = 0,
 					.nick = "disabled",
 				},
@@ -6535,6 +6476,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = {
 		.property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int,
 			.value_infos =              INT_VALUE_INFOS (
 				{
+					.value.i64 = -1,
+					.nick = "unset",
+				},
+				{
 					.value.i64 = 0,
 					.nick = "default",
 				},
@@ -6546,6 +6491,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = {
 		.property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int,
 			.value_infos =              INT_VALUE_INFOS (
 				{
+					.value.i64 = -1,
+					.nick = "unset",
+				},
+				{
 					.value.i64 = 0,
 					.nick = "disabled",
 				},
@@ -6557,6 +6506,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = {
 		.property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int,
 			.value_infos =              INT_VALUE_INFOS (
 				{
+					.value.i64 = -1,
+					.nick = "unset",
+				},
+				{
 					.value.i64 = 0,
 					.nick = "default",
 				},
@@ -6587,7 +6540,6 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = {
 		.property_typ_data = DEFINE_PROPERTY_TYP_DATA (
 			PROPERTY_TYP_DATA_SUBTYPE (multilist,
 				.get_num_fcn_u =        MULTILIST_GET_NUM_FCN_U       (NMSettingTeam, nm_setting_team_get_num_runner_tx_hash),
-				.clear_all_fcn =        _multilist_clear_all_fcn_team_runner_tx_hash,
 				.add_fcn =              MULTILIST_ADD_FCN             (NMSettingTeam, nm_setting_team_add_runner_tx_hash),
 				.remove_by_idx_fcn_u =  MULTILIST_REMOVE_BY_IDX_FCN_U (NMSettingTeam, nm_setting_team_remove_runner_tx_hash),
 				.remove_by_value_fcn =  MULTILIST_REMOVE_BY_VALUE_FCN (NMSettingTeam, nm_setting_team_remove_runner_tx_hash_by_value),
@@ -6608,6 +6560,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = {
 		.property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int,
 			.value_infos =              INT_VALUE_INFOS (
 				{
+					.value.i64 = -1,
+					.nick = "unset",
+				},
+				{
 					.value.i64 = NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL_DEFAULT,
 					.nick = "default",
 				},
@@ -6625,6 +6581,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = {
 		.property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int,
 			.value_infos =              INT_VALUE_INFOS (
 				{
+					.value.i64 = -1,
+					.nick = "unset",
+				},
+				{
 					.value.i64 = NM_SETTING_TEAM_RUNNER_SYS_PRIO_DEFAULT,
 					.nick = "default",
 				},
@@ -6636,7 +6596,11 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = {
 		.property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int,
 			.value_infos =              INT_VALUE_INFOS (
 				{
-					.value.i64 = 0,
+					.value.i64 = -1,
+					.nick = "unset",
+				},
+				{
+					.value.i64 = 1,
 					.nick = "default",
 				},
 			),
@@ -6658,11 +6622,9 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = {
 		.property_typ_data = DEFINE_PROPERTY_TYP_DATA (
 			PROPERTY_TYP_DATA_SUBTYPE (objlist,
 				.get_num_fcn =          OBJLIST_GET_NUM_FCN         (NMSettingTeam, nm_setting_team_get_num_link_watchers),
-				.clear_all_fcn =        _objlist_clear_all_fcn_team_link_watchers,
 				.obj_to_str_fcn =       _objlist_obj_to_str_fcn_team_link_watchers,
 				.set_fcn =              _objlist_set_fcn_team_link_watchers,
 				.remove_by_idx_fcn_u =  OBJLIST_REMOVE_BY_IDX_FCN_U (NMSettingTeam, nm_setting_team_remove_link_watcher),
-				.strsplit_plain =       TRUE,
 			),
 		),
 	),
@@ -6687,7 +6649,11 @@ static const NMMetaPropertyInfo *const property_infos_TEAM_PORT[] = {
 		.property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int,
 			.value_infos =              INT_VALUE_INFOS (
 				{
-					.value.i64 = NM_SETTING_TEAM_PORT_QUEUE_ID_DEFAULT,
+					.value.i64 = -1,
+					.nick = "unset",
+				},
+				{
+					.value.i64 = 0,
 					.nick = "default",
 				},
 			),
@@ -6699,6 +6665,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM_PORT[] = {
 			.value_infos =              INT_VALUE_INFOS (
 				{
 					.value.i64 = 0,
+					.nick = "unset",
+				},
+				{
+					.value.i64 = 0,
 					.nick = "default",
 				},
 			),
@@ -6712,6 +6682,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM_PORT[] = {
 		.property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int,
 			.value_infos =              INT_VALUE_INFOS (
 				{
+					.value.i64 = -1,
+					.nick = "unset",
+				},
+				{
 					.value.i64 = NM_SETTING_TEAM_PORT_LACP_PRIO_DEFAULT,
 					.nick = "default",
 				},
@@ -6723,6 +6697,10 @@ static const NMMetaPropertyInfo *const property_infos_TEAM_PORT[] = {
 		.property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (gobject_int,
 			.value_infos =              INT_VALUE_INFOS (
 				{
+					.value.i64 = -1,
+					.nick = "unset",
+				},
+				{
 					.value.i64 = 0,
 					.nick = "default",
 				},
@@ -6735,11 +6713,9 @@ static const NMMetaPropertyInfo *const property_infos_TEAM_PORT[] = {
 		.property_typ_data = DEFINE_PROPERTY_TYP_DATA (
 			PROPERTY_TYP_DATA_SUBTYPE (objlist,
 				.get_num_fcn =          OBJLIST_GET_NUM_FCN         (NMSettingTeamPort, nm_setting_team_port_get_num_link_watchers),
-				.clear_all_fcn =        _objlist_clear_all_fcn_team_link_watchers,
 				.obj_to_str_fcn =       _objlist_obj_to_str_fcn_team_link_watchers,
 				.set_fcn =              _objlist_set_fcn_team_link_watchers,
 				.remove_by_idx_fcn_u =  OBJLIST_REMOVE_BY_IDX_FCN_U (NMSettingTeamPort, nm_setting_team_port_remove_link_watcher),
-				.strsplit_plain =       TRUE,
 			),
 		),
 	),
@@ -7161,6 +7137,12 @@ static const NMMetaPropertyInfo *const property_infos_WIREGUARD[] = {
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_WIREGUARD_MTU,
 		.property_type =                &_pt_gobject_mtu,
 	),
+	PROPERTY_INFO_WITH_DESC (NM_SETTING_WIREGUARD_IP4_AUTO_DEFAULT_ROUTE,
+		.property_type =                &_pt_gobject_enum,
+	),
+	PROPERTY_INFO_WITH_DESC (NM_SETTING_WIREGUARD_IP6_AUTO_DEFAULT_ROUTE,
+		.property_type =                &_pt_gobject_enum,
+	),
 	NULL
 };
 
@@ -7186,7 +7168,8 @@ static const NMMetaPropertyInfo *const property_infos_WIRELESS[] = {
 		.property_typ_data = DEFINE_PROPERTY_TYP_DATA (
 			.values_static =            NM_MAKE_STRV (NM_SETTING_WIRELESS_MODE_INFRA,
 			                                          NM_SETTING_WIRELESS_MODE_ADHOC,
-			                                          NM_SETTING_WIRELESS_MODE_AP),
+			                                          NM_SETTING_WIRELESS_MODE_AP,
+			                                          NM_SETTING_WIRELESS_MODE_MESH),
 		),
 	),
 	PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_BAND,
@@ -7657,6 +7640,7 @@ _setting_init_fcn_wireless (ARGS_SETTING_INIT_FCN)
 #define SETTING_PRETTY_NAME_MATCH               N_("Match")
 #define SETTING_PRETTY_NAME_OLPC_MESH           N_("OLPC Mesh connection")
 #define SETTING_PRETTY_NAME_OVS_BRIDGE          N_("Open vSwitch bridge settings")
+#define SETTING_PRETTY_NAME_OVS_DPDK            N_("Open vSwitch DPDK interface settings")
 #define SETTING_PRETTY_NAME_OVS_INTERFACE       N_("Open vSwitch interface settings")
 #define SETTING_PRETTY_NAME_OVS_PATCH           N_("Open vSwitch patch interface settings")
 #define SETTING_PRETTY_NAME_OVS_PORT            N_("Open vSwitch port settings")
@@ -7837,10 +7821,12 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[] = {
 			NM_META_SETTING_VALID_PART_ITEM (OVS_BRIDGE,            TRUE),
 		),
 	),
+	SETTING_INFO (OVS_DPDK),
 	SETTING_INFO (OVS_INTERFACE,
 		.valid_parts = NM_META_SETTING_VALID_PARTS (
 			NM_META_SETTING_VALID_PART_ITEM (CONNECTION,            TRUE),
 			NM_META_SETTING_VALID_PART_ITEM (OVS_INTERFACE,         TRUE),
+			NM_META_SETTING_VALID_PART_ITEM (OVS_DPDK,              FALSE),
 			NM_META_SETTING_VALID_PART_ITEM (OVS_PATCH,             FALSE),
 			NM_META_SETTING_VALID_PART_ITEM (IP4_CONFIG,            FALSE),
 			NM_META_SETTING_VALID_PART_ITEM (IP6_CONFIG,            FALSE),
@@ -8150,6 +8136,7 @@ _meta_type_property_info_complete_fcn (const NMMetaAbstractInfo *abstract_info,
                                        gpointer environment_user_data,
                                        const NMMetaOperationContext *operation_context,
                                        const char *text,
+                                       gboolean *out_complete_filename,
                                        char ***out_to_free)
 {
 	const NMMetaPropertyInfo *info = (const NMMetaPropertyInfo *) abstract_info;
@@ -8162,6 +8149,7 @@ _meta_type_property_info_complete_fcn (const NMMetaAbstractInfo *abstract_info,
 		                                          environment_user_data,
 		                                          operation_context,
 		                                          text,
+		                                          out_complete_filename,
 		                                          out_to_free);
 	}
 
diff --git a/clients/common/nm-meta-setting-desc.h b/clients/common/nm-meta-setting-desc.h
index b69a07b5..27ae4254 100644
--- a/clients/common/nm-meta-setting-desc.h
+++ b/clients/common/nm-meta-setting-desc.h
@@ -62,7 +62,8 @@ struct _NMDevice;
 #define NM_META_TEXT_WORD_INFRA  "infrastructure"
 #define NM_META_TEXT_WORD_AP     "ap"
 #define NM_META_TEXT_WORD_ADHOC  "adhoc"
-#define NM_META_TEXT_PROMPT_WIFI_MODE_CHOICES "(" NM_META_TEXT_WORD_INFRA "/" NM_META_TEXT_WORD_AP "/" NM_META_TEXT_WORD_ADHOC ") [" NM_META_TEXT_WORD_INFRA "]"
+#define NM_META_TEXT_WORD_MESH   "mesh"
+#define NM_META_TEXT_PROMPT_WIFI_MODE_CHOICES "(" NM_META_TEXT_WORD_INFRA "/" NM_META_TEXT_WORD_AP "/" NM_META_TEXT_WORD_ADHOC "/" NM_META_TEXT_WORD_MESH ") [" NM_META_TEXT_WORD_INFRA "]"
 
 #define NM_META_TEXT_PROMPT_TUN_MODE N_("Tun mode")
 #define NM_META_TEXT_WORD_TUN  "tun"
@@ -221,6 +222,7 @@ struct _NMMetaPropertyType {
 	                                   gpointer environment_user_data,
 	                                   const NMMetaOperationContext *operation_context,
 	                                   const char *text,
+	                                   gboolean *out_complete_filename,
 	                                   char ***out_to_free);
 
 	/* Whether set_fcn() supports the '-' modifier. That is, whether the property
@@ -270,6 +272,13 @@ struct _NMMetaPropertyTypData {
 			guint32 (*get_num_fcn_u32) (NMSetting *setting);
 			guint (*get_num_fcn_u) (NMSetting *setting);
 			void (*clear_all_fcn) (NMSetting *setting);
+
+			/* some multilist properties distinguish between an empty list and
+			 * and unset. If this function pointer is set, certain behaviors come
+			 * into action to handle that. */
+			void (*clear_emptyunset_fcn) (NMSetting *setting,
+			                              gboolean is_set /* or else set default */);
+
 			gboolean (*add_fcn) (NMSetting *setting,
 			                     const char *item);
 			void (*add2_fcn) (NMSetting *setting,
@@ -444,6 +453,7 @@ struct _NMMetaType {
 	                                   gpointer environment_user_data,
 	                                   const NMMetaOperationContext *operation_context,
 	                                   const char *text,
+	                                   gboolean *out_complete_filename,
 	                                   char ***out_to_free);
 };
 
diff --git a/clients/common/nm-polkit-listener.c b/clients/common/nm-polkit-listener.c
index 7367459d..139bb35a 100644
--- a/clients/common/nm-polkit-listener.c
+++ b/clients/common/nm-polkit-listener.c
@@ -1,4 +1,3 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
 /*
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
diff --git a/clients/common/nm-polkit-listener.h b/clients/common/nm-polkit-listener.h
index ee86104b..63939053 100644
--- a/clients/common/nm-polkit-listener.h
+++ b/clients/common/nm-polkit-listener.h
@@ -1,4 +1,3 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
 /*
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
diff --git a/clients/common/nm-secret-agent-simple.c b/clients/common/nm-secret-agent-simple.c
index f3a398d7..52059f95 100644
--- a/clients/common/nm-secret-agent-simple.c
+++ b/clients/common/nm-secret-agent-simple.c
@@ -1,4 +1,3 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
 /*
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
diff --git a/clients/common/nm-secret-agent-simple.h b/clients/common/nm-secret-agent-simple.h
index 4a666d17..650b9713 100644
--- a/clients/common/nm-secret-agent-simple.h
+++ b/clients/common/nm-secret-agent-simple.h
@@ -1,4 +1,3 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
 /*
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
diff --git a/clients/common/nm-vpn-helpers.c b/clients/common/nm-vpn-helpers.c
index 081d6056..204b7c28 100644
--- a/clients/common/nm-vpn-helpers.c
+++ b/clients/common/nm-vpn-helpers.c
@@ -1,4 +1,3 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
 /*
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -737,7 +736,7 @@ fail_invalid_secret:
 	}
 
 	for (is_v4 = 0; is_v4 < 2; is_v4++) {
-		const char *method_disabled = is_v4 ? NM_SETTING_IP4_CONFIG_METHOD_DISABLED : NM_SETTING_IP6_CONFIG_METHOD_IGNORE;
+		const char *method_disabled = is_v4 ? NM_SETTING_IP4_CONFIG_METHOD_DISABLED : NM_SETTING_IP6_CONFIG_METHOD_DISABLED;
 		const char *method_manual   = is_v4 ? NM_SETTING_IP4_CONFIG_METHOD_MANUAL   : NM_SETTING_IP6_CONFIG_METHOD_MANUAL;
 		NMSettingIPConfig *s_ip     = is_v4 ? s_ip4                                 : s_ip6;
 		GPtrArray *data_dns         = is_v4 ? data_dns_v4                           : data_dns_v6;
diff --git a/clients/common/nm-vpn-helpers.h b/clients/common/nm-vpn-helpers.h
index 686687ba..90017534 100644
--- a/clients/common/nm-vpn-helpers.h
+++ b/clients/common/nm-vpn-helpers.h
@@ -1,4 +1,3 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
 /*
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
diff --git a/clients/common/settings-docs.h b/clients/common/settings-docs.h
index 811f2f16..78908305 100644
--- a/clients/common/settings-docs.h
+++ b/clients/common/settings-docs.h
@@ -13,7 +13,7 @@
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_MAC_ADDRESS N_("If specified, this connection will only apply to the Wi-Fi device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing).")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST N_("A list of permanent MAC addresses of Wi-Fi devices to which this connection should never apply.  Each MAC address should be given in the standard hex-digits-and-colons notation (eg \"00:11:22:33:44:55\").")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION N_("One of NM_SETTING_MAC_RANDOMIZATION_DEFAULT (0) (never randomize unless the user has set a global default to randomize and the supplicant supports randomization),  NM_SETTING_MAC_RANDOMIZATION_NEVER (1) (never randomize the MAC address), or NM_SETTING_MAC_RANDOMIZATION_ALWAYS (2) (always randomize the MAC address). This property is deprecated for 'cloned-mac-address'. Deprecated: 1")
-#define DESCRIBE_DOC_NM_SETTING_WIRELESS_MODE N_("Wi-Fi network mode; one of \"infrastructure\", \"adhoc\" or \"ap\".  If blank, infrastructure is assumed.")
+#define DESCRIBE_DOC_NM_SETTING_WIRELESS_MODE N_("Wi-Fi network mode; one of \"infrastructure\", \"mesh\", \"adhoc\" or \"ap\".  If blank, infrastructure is assumed.")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple Ethernet frames.")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_POWERSAVE N_("One of NM_SETTING_WIRELESS_POWERSAVE_DISABLE (2) (disable Wi-Fi power saving), NM_SETTING_WIRELESS_POWERSAVE_ENABLE (3) (enable Wi-Fi power saving), NM_SETTING_WIRELESS_POWERSAVE_IGNORE (1) (don't touch currently configure setting) or NM_SETTING_WIRELESS_POWERSAVE_DEFAULT (0) (use the globally configured value). All other values are reserved.")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_RATE N_("If non-zero, directs the device to only use the specified bitrate for communication with the access point.  Units are in Kb/s, ie 5500 = 5.5 Mbit/s.  This property is highly driver dependent and not all devices support setting a static bitrate.")
@@ -152,6 +152,7 @@
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_TIMESTAMP N_("The time, in seconds since the Unix Epoch, that the connection was last _successfully_ fully activated. NetworkManager updates the connection timestamp periodically when the connection is active to ensure that an active connection has the latest timestamp. The property is only meant for reading (changes to this property will not be preserved).")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_TYPE N_("Base type of the connection. For hardware-dependent connections, should contain the setting name of the hardware-type specific setting (ie, \"802-3-ethernet\" or \"802-11-wireless\" or \"bluetooth\", etc), and for non-hardware dependent connections like VPN or otherwise, should contain the setting name of that setting type (ie, \"vpn\" or \"bridge\", etc).")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_UUID N_("A universally unique identifier for the connection, for example generated with libuuid.  It should be assigned when the connection is created, and never changed as long as the connection still applies to the same network.  For example, it should not be changed when the \"id\" property or NMSettingIP4Config changes, but might need to be re-created when the Wi-Fi SSID, mobile broadband network provider, or \"type\" property changes. The UUID must be in the format \"2815492f-7e56-435e-b2e9-246bd7cdc664\" (ie, contains only hexadecimal characters and \"-\").")
+#define DESCRIBE_DOC_NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT N_("Timeout in milliseconds to wait for device at startup. During boot, devices may take a while to be detected by the driver. This property will cause to delay NetworkManager-wait-online.service and nm-online to give the device a chance to appear. Note that this property only works together with NMSettingConnection:interface-name to identify the device that will be waited for. The value 0 means no wait time. The default value is -1, which currently has the same meaning as no wait time.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_ZONE N_("The trust level of a the connection.  Free form case-insensitive string (for example \"Home\", \"Work\", \"Public\").  NULL or unspecified zone means the connection will be placed in the default zone as defined by the firewall. When updating this property on a currently activated connection, the change takes effect immediately.")
 #define DESCRIBE_DOC_NM_SETTING_DCB_APP_FCOE_FLAGS N_("Specifies the NMSettingDcbFlags for the DCB FCoE application.  Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4).")
 #define DESCRIBE_DOC_NM_SETTING_DCB_APP_FCOE_MODE N_("The FCoE controller mode; either \"fabric\" (default) or \"vn2vn\".")
@@ -208,13 +209,13 @@
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_TIMEOUT N_("A timeout for a DHCP transaction in seconds.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS N_("Array of IP addresses of DNS servers.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties.")
-#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting.  A lower value is better (higher priority). Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections.  It does not disambiguate multiple DNS servers within the same connection profile. When using dns=default, servers with higher priority will be on top of resolv.conf.  To prioritize a given server over another one within the same connection, just specify them in the desired order.  When multiple devices have configurations with the same priority, the one with an active default route will be preferred.  Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports split-DNS as dns=dnsmasq or dns=systemd-resolved, each connection is used to query domains in its search list.  Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually).  When multiple connections specify the same domain, the one with the highest priority (lowest numerical value) wins.  If a connection specifies a domain which is subdomain of another domain with a negative DNS priority value, the subdomain is ignored.")
+#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting.  A lower value is better (higher priority). Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections.  It does not disambiguate multiple DNS servers within the same connection profile. When using dns=default, servers with higher priority will be on top of resolv.conf.  To prioritize a given server over another one within the same connection, just specify them in the desired order.  When multiple devices have configurations with the same priority, the one with an active default route will be preferred.  Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports Conditional Forwarding as dns=dnsmasq or dns=systemd-resolved, each connection is used to query domains in its search list.  Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually).  When multiple connections specify the same domain, the one with the highest priority (lowest numerical value) wins.  If a connection specifies a domain which is subdomain of another domain with a negative DNS priority value, the subdomain is ignored.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_SEARCH N_("Array of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured nameservers and search domains are ignored and only nameservers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_IGNORE_AUTO_ROUTES N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured routes are ignored and only routes specified in the \"routes\" property, if any, are used.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_MAY_FAIL N_("If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out.  Note that at least one IP configuration must succeed or overall network configuration will still fail.  For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully.")
-#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_METHOD N_("IP configuration method. NMSettingIP4Config and NMSettingIP6Config both support \"auto\", \"manual\", and \"link-local\". See the subclass-specific documentation for other values. In general, for the \"auto\" method, properties such as \"dns\" and \"routes\" specify information that is added on to the information returned from automatic configuration.  The \"ignore-auto-routes\" and \"ignore-auto-dns\" properties modify this behavior. For methods that imply no upstream network, such as \"shared\" or \"link-local\", these properties must be empty. For IPv4 method \"shared\", the IP subnet can be configured by adding one manual IPv4 address or otherwise 10.42.x.0/24 is chosen. Note that the shared method must be configured on the interface which shares the internet to a subnet, not on the uplink which is shared.")
+#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_METHOD N_("IP configuration method. NMSettingIP4Config and NMSettingIP6Config both support \"disabled\", \"auto\", \"manual\", and \"link-local\". See the subclass-specific documentation for other values. In general, for the \"auto\" method, properties such as \"dns\" and \"routes\" specify information that is added on to the information returned from automatic configuration.  The \"ignore-auto-routes\" and \"ignore-auto-dns\" properties modify this behavior. For methods that imply no upstream network, such as \"shared\" or \"link-local\", these properties must be empty. For IPv4 method \"shared\", the IP subnet can be configured by adding one manual IPv4 address or otherwise 10.42.x.0/24 is chosen. Note that the shared method must be configured on the interface which shares the internet to a subnet, not on the uplink which is shared.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_NEVER_DEFAULT N_("If TRUE, this connection will never be the default connection for this IP type, meaning it will never be assigned the default route by NetworkManager.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ROUTE_METRIC N_("The default metric for routes that don't explicitly specify a metric. The default value -1 means that the metric is chosen automatically based on the device type. The metric applies to dynamic routes, manual (static) routes that don't have an explicit metric setting, address prefix routes, and the default route. Note that for IPv6, the kernel accepts zero (0) but coerces it to 1024 (user default). Hence, setting this property to zero effectively mean setting it to 1024. For IPv4, zero is a regular value for the metric.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ROUTE_TABLE N_("Enable policy routing (source routing) and set the routing table used when adding routes. This affects all routes, including device-routes, IPv4LL, DHCP, SLAAC, default-routes and static routes. But note that static routes can individually overwrite the setting by explicitly specifying a non-zero routing table. If the table setting is left at zero, it is eligible to be overwritten via global configuration. If the property is zero even after applying the global configuration value, policy routing is disabled for the address family of this connection. Policy routing disabled means that NetworkManager will add all routes to the main table (except static routes that explicitly configure a different table). Additionally, NetworkManager will not delete any extraneous routes from tables except the main table. This is to preserve backward compatibility for users who manage routing tables outside of NetworkManager.")
@@ -228,14 +229,14 @@
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_TIMEOUT N_("A timeout for a DHCP transaction in seconds.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS N_("Array of IP addresses of DNS servers.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties.")
-#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting.  A lower value is better (higher priority). Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections.  It does not disambiguate multiple DNS servers within the same connection profile. When using dns=default, servers with higher priority will be on top of resolv.conf.  To prioritize a given server over another one within the same connection, just specify them in the desired order.  When multiple devices have configurations with the same priority, the one with an active default route will be preferred.  Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports split-DNS as dns=dnsmasq or dns=systemd-resolved, each connection is used to query domains in its search list.  Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually).  When multiple connections specify the same domain, the one with the highest priority (lowest numerical value) wins.  If a connection specifies a domain which is subdomain of another domain with a negative DNS priority value, the subdomain is ignored.")
+#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting.  A lower value is better (higher priority). Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections.  It does not disambiguate multiple DNS servers within the same connection profile. When using dns=default, servers with higher priority will be on top of resolv.conf.  To prioritize a given server over another one within the same connection, just specify them in the desired order.  When multiple devices have configurations with the same priority, the one with an active default route will be preferred.  Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports Conditional Forwarding as dns=dnsmasq or dns=systemd-resolved, each connection is used to query domains in its search list.  Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually).  When multiple connections specify the same domain, the one with the highest priority (lowest numerical value) wins.  If a connection specifies a domain which is subdomain of another domain with a negative DNS priority value, the subdomain is ignored.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_SEARCH N_("Array of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured nameservers and search domains are ignored and only nameservers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IGNORE_AUTO_ROUTES N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured routes are ignored and only routes specified in the \"routes\" property, if any, are used.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IP6_PRIVACY N_("Configure IPv6 Privacy Extensions for SLAAC, described in RFC4941.  If enabled, it makes the kernel generate a temporary IPv6 address in addition to the public one generated from MAC address via modified EUI-64.  This enhances privacy, but could cause problems in some applications, on the other hand.  The permitted values are: -1: unknown, 0: disabled, 1: enabled (prefer public address), 2: enabled (prefer temporary addresses). Having a per-connection setting set to \"-1\" (unknown) means fallback to global configuration \"ipv6.ip6-privacy\". If also global configuration is unspecified or set to \"-1\", fallback to read \"/proc/sys/net/ipv6/conf/default/use_tempaddr\". Note that this setting is distinct from the Stable Privacy addresses that can be enabled with the \"addr-gen-mode\" property's \"stable-privacy\" setting as another way of avoiding host tracking with IPv6 addresses.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_MAY_FAIL N_("If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out.  Note that at least one IP configuration must succeed or overall network configuration will still fail.  For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully.")
-#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_METHOD N_("IP configuration method. NMSettingIP4Config and NMSettingIP6Config both support \"auto\", \"manual\", and \"link-local\". See the subclass-specific documentation for other values. In general, for the \"auto\" method, properties such as \"dns\" and \"routes\" specify information that is added on to the information returned from automatic configuration.  The \"ignore-auto-routes\" and \"ignore-auto-dns\" properties modify this behavior. For methods that imply no upstream network, such as \"shared\" or \"link-local\", these properties must be empty. For IPv4 method \"shared\", the IP subnet can be configured by adding one manual IPv4 address or otherwise 10.42.x.0/24 is chosen. Note that the shared method must be configured on the interface which shares the internet to a subnet, not on the uplink which is shared.")
+#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_METHOD N_("IP configuration method. NMSettingIP4Config and NMSettingIP6Config both support \"disabled\", \"auto\", \"manual\", and \"link-local\". See the subclass-specific documentation for other values. In general, for the \"auto\" method, properties such as \"dns\" and \"routes\" specify information that is added on to the information returned from automatic configuration.  The \"ignore-auto-routes\" and \"ignore-auto-dns\" properties modify this behavior. For methods that imply no upstream network, such as \"shared\" or \"link-local\", these properties must be empty. For IPv4 method \"shared\", the IP subnet can be configured by adding one manual IPv4 address or otherwise 10.42.x.0/24 is chosen. Note that the shared method must be configured on the interface which shares the internet to a subnet, not on the uplink which is shared.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_NEVER_DEFAULT N_("If TRUE, this connection will never be the default connection for this IP type, meaning it will never be assigned the default route by NetworkManager.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ROUTE_METRIC N_("The default metric for routes that don't explicitly specify a metric. The default value -1 means that the metric is chosen automatically based on the device type. The metric applies to dynamic routes, manual (static) routes that don't have an explicit metric setting, address prefix routes, and the default route. Note that for IPv6, the kernel accepts zero (0) but coerces it to 1024 (user default). Hence, setting this property to zero effectively mean setting it to 1024. For IPv4, zero is a regular value for the metric.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ROUTE_TABLE N_("Enable policy routing (source routing) and set the routing table used when adding routes. This affects all routes, including device-routes, IPv4LL, DHCP, SLAAC, default-routes and static routes. But note that static routes can individually overwrite the setting by explicitly specifying a non-zero routing table. If the table setting is left at zero, it is eligible to be overwritten via global configuration. If the property is zero even after applying the global configuration value, policy routing is disabled for the address family of this connection. Policy routing disabled means that NetworkManager will add all routes to the main table (except static routes that explicitly configure a different table). Additionally, NetworkManager will not delete any extraneous routes from tables except the main table. This is to preserve backward compatibility for users who manage routing tables outside of NetworkManager.")
@@ -255,11 +256,13 @@
 #define DESCRIBE_DOC_NM_SETTING_MACVLAN_PROMISCUOUS N_("Whether the interface should be put in promiscuous mode.")
 #define DESCRIBE_DOC_NM_SETTING_MACVLAN_TAP N_("Whether the interface should be a MACVTAP.")
 #define DESCRIBE_DOC_NM_SETTING_MATCH_INTERFACE_NAME N_("A list of interface names to match. Each element is a shell wildcard pattern.  When an element is prefixed with exclamation mark (!) the condition is inverted. A candidate interface name is considered matching when both these conditions are satisfied: (a) any of the elements not prefixed with '!' matches or there aren't such elements; (b) none of the elements prefixed with '!' match.")
+#define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_DATAPATH_TYPE N_("The data path type. One of \"system\", \"netdev\" or empty.")
 #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_FAIL_MODE N_("The bridge failure mode. One of \"secure\", \"standalone\" or empty.")
 #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_MCAST_SNOOPING_ENABLE N_("Enable or disable multicast snooping.")
 #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_RSTP_ENABLE N_("Enable or disable RSTP.")
 #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_STP_ENABLE N_("Enable or disable STP.")
-#define DESCRIBE_DOC_NM_SETTING_OVS_INTERFACE_TYPE N_("The interface type. Either \"internal\", or empty.")
+#define DESCRIBE_DOC_NM_SETTING_OVS_DPDK_DEVARGS N_("Open vSwitch DPDK device arguments.")
+#define DESCRIBE_DOC_NM_SETTING_OVS_INTERFACE_TYPE N_("The interface type. Either \"internal\", \"system\", \"patch\", \"dpdk\", or empty.")
 #define DESCRIBE_DOC_NM_SETTING_OVS_PATCH_PEER N_("Specifies the unicast destination IP address of a remote Open vSwitch bridge port to connect to.")
 #define DESCRIBE_DOC_NM_SETTING_OVS_PORT_BOND_DOWNDELAY N_("The time port must be inactive in order to be considered down.")
 #define DESCRIBE_DOC_NM_SETTING_OVS_PORT_BOND_MODE N_("Bonding mode. One of \"active-backup\", \"balance-slb\", or \"balance-tcp\".")
@@ -310,7 +313,7 @@
 #define DESCRIBE_DOC_NM_SETTING_TEAM_MCAST_REJOIN_INTERVAL N_("Corresponds to the teamd mcast_rejoin.interval.")
 #define DESCRIBE_DOC_NM_SETTING_TEAM_NOTIFY_PEERS_COUNT N_("Corresponds to the teamd notify_peers.count.")
 #define DESCRIBE_DOC_NM_SETTING_TEAM_NOTIFY_PEERS_INTERVAL N_("Corresponds to the teamd notify_peers.interval.")
-#define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER N_("Corresponds to the teamd runner.name. Permitted values are: \"roundrobin\", \"broadcast\", \"activebackup\", \"loadbalance\", \"lacp\", \"random\". When setting the runner, all the properties specific to the runner will be reset to the default value; all the properties specific to other runners will be set to an empty value (or if not possible to a default value).")
+#define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER N_("Corresponds to the teamd runner.name. Permitted values are: \"roundrobin\", \"broadcast\", \"activebackup\", \"loadbalance\", \"lacp\", \"random\".")
 #define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER_ACTIVE N_("Corresponds to the teamd runner.active.")
 #define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY N_("Corresponds to the teamd runner.agg_select_policy.")
 #define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER_FAST_RATE N_("Corresponds to the teamd runner.fast_rate.")
@@ -366,7 +369,9 @@
 #define DESCRIBE_DOC_NM_SETTING_WIFI_P2P_WPS_METHOD N_("Flags indicating which mode of WPS is to be used. There's little point in changing the default setting as NetworkManager will automatically determine the best method to use.")
 #define DESCRIBE_DOC_NM_SETTING_WIMAX_MAC_ADDRESS N_("If specified, this connection will only apply to the WiMAX device whose MAC address matches. This property does not change the MAC address of the device (known as MAC spoofing). Deprecated: 1")
 #define DESCRIBE_DOC_NM_SETTING_WIMAX_NETWORK_NAME N_("Network Service Provider (NSP) name of the WiMAX network this connection should use. Deprecated: 1")
-#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_FWMARK N_("The use of fwmark is optional and is by default off. Setting it to 0 disables it. Otherwise it is a 32-bit fwmark for outgoing packets.")
+#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_FWMARK N_("The use of fwmark is optional and is by default off. Setting it to 0 disables it. Otherwise it is a 32-bit fwmark for outgoing packets. Note that \"ip4-auto-default-route\" or \"ip6-auto-default-route\" enabled, implies to automatically choose a fwmark.")
+#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_IP4_AUTO_DEFAULT_ROUTE N_("Whether to enable special handling of the IPv4 default route. If enabled, the IPv4 default route will be placed to a dedicated routing-table and two policy routing rules will be added. The fwmark number is also used as routing-table for the default-route, and if fwmark is zero, a unused fwmark/table is chosen automatically. This corresponds to what wg-quick does with Table=auto. Leaving this at the default will enable this option automatically if ipv4.never-default is not set and there are any peers that use a default-route as allowed-ips.")
+#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_IP6_AUTO_DEFAULT_ROUTE N_("Like ip4-auto-default-route, but for the IPv6 default route.")
 #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_LISTEN_PORT N_("The listen-port. If listen-port is not specified, the port will be chosen randomly when the interface comes up.")
 #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple fragments. If zero a default MTU is used. Note that contrary to wg-quick's MTU setting, this does not take into account the current routes at the time of activation.")
 #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_PEER_ROUTES N_("Whether to automatically add routes for the AllowedIPs ranges of the peers. If TRUE (the default), NetworkManager will automatically add routes in the routing tables according to ipv4.route-table and ipv6.route-table. If FALSE, no such routes are added automatically. In this case, the user may want to configure static routes in ipv4.routes and ipv6.routes, respectively.")
diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in
index 811f2f16..78908305 100644
--- a/clients/common/settings-docs.h.in
+++ b/clients/common/settings-docs.h.in
@@ -13,7 +13,7 @@
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_MAC_ADDRESS N_("If specified, this connection will only apply to the Wi-Fi device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing).")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST N_("A list of permanent MAC addresses of Wi-Fi devices to which this connection should never apply.  Each MAC address should be given in the standard hex-digits-and-colons notation (eg \"00:11:22:33:44:55\").")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION N_("One of NM_SETTING_MAC_RANDOMIZATION_DEFAULT (0) (never randomize unless the user has set a global default to randomize and the supplicant supports randomization),  NM_SETTING_MAC_RANDOMIZATION_NEVER (1) (never randomize the MAC address), or NM_SETTING_MAC_RANDOMIZATION_ALWAYS (2) (always randomize the MAC address). This property is deprecated for 'cloned-mac-address'. Deprecated: 1")
-#define DESCRIBE_DOC_NM_SETTING_WIRELESS_MODE N_("Wi-Fi network mode; one of \"infrastructure\", \"adhoc\" or \"ap\".  If blank, infrastructure is assumed.")
+#define DESCRIBE_DOC_NM_SETTING_WIRELESS_MODE N_("Wi-Fi network mode; one of \"infrastructure\", \"mesh\", \"adhoc\" or \"ap\".  If blank, infrastructure is assumed.")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple Ethernet frames.")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_POWERSAVE N_("One of NM_SETTING_WIRELESS_POWERSAVE_DISABLE (2) (disable Wi-Fi power saving), NM_SETTING_WIRELESS_POWERSAVE_ENABLE (3) (enable Wi-Fi power saving), NM_SETTING_WIRELESS_POWERSAVE_IGNORE (1) (don't touch currently configure setting) or NM_SETTING_WIRELESS_POWERSAVE_DEFAULT (0) (use the globally configured value). All other values are reserved.")
 #define DESCRIBE_DOC_NM_SETTING_WIRELESS_RATE N_("If non-zero, directs the device to only use the specified bitrate for communication with the access point.  Units are in Kb/s, ie 5500 = 5.5 Mbit/s.  This property is highly driver dependent and not all devices support setting a static bitrate.")
@@ -152,6 +152,7 @@
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_TIMESTAMP N_("The time, in seconds since the Unix Epoch, that the connection was last _successfully_ fully activated. NetworkManager updates the connection timestamp periodically when the connection is active to ensure that an active connection has the latest timestamp. The property is only meant for reading (changes to this property will not be preserved).")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_TYPE N_("Base type of the connection. For hardware-dependent connections, should contain the setting name of the hardware-type specific setting (ie, \"802-3-ethernet\" or \"802-11-wireless\" or \"bluetooth\", etc), and for non-hardware dependent connections like VPN or otherwise, should contain the setting name of that setting type (ie, \"vpn\" or \"bridge\", etc).")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_UUID N_("A universally unique identifier for the connection, for example generated with libuuid.  It should be assigned when the connection is created, and never changed as long as the connection still applies to the same network.  For example, it should not be changed when the \"id\" property or NMSettingIP4Config changes, but might need to be re-created when the Wi-Fi SSID, mobile broadband network provider, or \"type\" property changes. The UUID must be in the format \"2815492f-7e56-435e-b2e9-246bd7cdc664\" (ie, contains only hexadecimal characters and \"-\").")
+#define DESCRIBE_DOC_NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT N_("Timeout in milliseconds to wait for device at startup. During boot, devices may take a while to be detected by the driver. This property will cause to delay NetworkManager-wait-online.service and nm-online to give the device a chance to appear. Note that this property only works together with NMSettingConnection:interface-name to identify the device that will be waited for. The value 0 means no wait time. The default value is -1, which currently has the same meaning as no wait time.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_ZONE N_("The trust level of a the connection.  Free form case-insensitive string (for example \"Home\", \"Work\", \"Public\").  NULL or unspecified zone means the connection will be placed in the default zone as defined by the firewall. When updating this property on a currently activated connection, the change takes effect immediately.")
 #define DESCRIBE_DOC_NM_SETTING_DCB_APP_FCOE_FLAGS N_("Specifies the NMSettingDcbFlags for the DCB FCoE application.  Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4).")
 #define DESCRIBE_DOC_NM_SETTING_DCB_APP_FCOE_MODE N_("The FCoE controller mode; either \"fabric\" (default) or \"vn2vn\".")
@@ -208,13 +209,13 @@
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_TIMEOUT N_("A timeout for a DHCP transaction in seconds.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS N_("Array of IP addresses of DNS servers.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties.")
-#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting.  A lower value is better (higher priority). Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections.  It does not disambiguate multiple DNS servers within the same connection profile. When using dns=default, servers with higher priority will be on top of resolv.conf.  To prioritize a given server over another one within the same connection, just specify them in the desired order.  When multiple devices have configurations with the same priority, the one with an active default route will be preferred.  Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports split-DNS as dns=dnsmasq or dns=systemd-resolved, each connection is used to query domains in its search list.  Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually).  When multiple connections specify the same domain, the one with the highest priority (lowest numerical value) wins.  If a connection specifies a domain which is subdomain of another domain with a negative DNS priority value, the subdomain is ignored.")
+#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting.  A lower value is better (higher priority). Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections.  It does not disambiguate multiple DNS servers within the same connection profile. When using dns=default, servers with higher priority will be on top of resolv.conf.  To prioritize a given server over another one within the same connection, just specify them in the desired order.  When multiple devices have configurations with the same priority, the one with an active default route will be preferred.  Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports Conditional Forwarding as dns=dnsmasq or dns=systemd-resolved, each connection is used to query domains in its search list.  Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually).  When multiple connections specify the same domain, the one with the highest priority (lowest numerical value) wins.  If a connection specifies a domain which is subdomain of another domain with a negative DNS priority value, the subdomain is ignored.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_SEARCH N_("Array of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured nameservers and search domains are ignored and only nameservers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_IGNORE_AUTO_ROUTES N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured routes are ignored and only routes specified in the \"routes\" property, if any, are used.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_MAY_FAIL N_("If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out.  Note that at least one IP configuration must succeed or overall network configuration will still fail.  For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully.")
-#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_METHOD N_("IP configuration method. NMSettingIP4Config and NMSettingIP6Config both support \"auto\", \"manual\", and \"link-local\". See the subclass-specific documentation for other values. In general, for the \"auto\" method, properties such as \"dns\" and \"routes\" specify information that is added on to the information returned from automatic configuration.  The \"ignore-auto-routes\" and \"ignore-auto-dns\" properties modify this behavior. For methods that imply no upstream network, such as \"shared\" or \"link-local\", these properties must be empty. For IPv4 method \"shared\", the IP subnet can be configured by adding one manual IPv4 address or otherwise 10.42.x.0/24 is chosen. Note that the shared method must be configured on the interface which shares the internet to a subnet, not on the uplink which is shared.")
+#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_METHOD N_("IP configuration method. NMSettingIP4Config and NMSettingIP6Config both support \"disabled\", \"auto\", \"manual\", and \"link-local\". See the subclass-specific documentation for other values. In general, for the \"auto\" method, properties such as \"dns\" and \"routes\" specify information that is added on to the information returned from automatic configuration.  The \"ignore-auto-routes\" and \"ignore-auto-dns\" properties modify this behavior. For methods that imply no upstream network, such as \"shared\" or \"link-local\", these properties must be empty. For IPv4 method \"shared\", the IP subnet can be configured by adding one manual IPv4 address or otherwise 10.42.x.0/24 is chosen. Note that the shared method must be configured on the interface which shares the internet to a subnet, not on the uplink which is shared.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_NEVER_DEFAULT N_("If TRUE, this connection will never be the default connection for this IP type, meaning it will never be assigned the default route by NetworkManager.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ROUTE_METRIC N_("The default metric for routes that don't explicitly specify a metric. The default value -1 means that the metric is chosen automatically based on the device type. The metric applies to dynamic routes, manual (static) routes that don't have an explicit metric setting, address prefix routes, and the default route. Note that for IPv6, the kernel accepts zero (0) but coerces it to 1024 (user default). Hence, setting this property to zero effectively mean setting it to 1024. For IPv4, zero is a regular value for the metric.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ROUTE_TABLE N_("Enable policy routing (source routing) and set the routing table used when adding routes. This affects all routes, including device-routes, IPv4LL, DHCP, SLAAC, default-routes and static routes. But note that static routes can individually overwrite the setting by explicitly specifying a non-zero routing table. If the table setting is left at zero, it is eligible to be overwritten via global configuration. If the property is zero even after applying the global configuration value, policy routing is disabled for the address family of this connection. Policy routing disabled means that NetworkManager will add all routes to the main table (except static routes that explicitly configure a different table). Additionally, NetworkManager will not delete any extraneous routes from tables except the main table. This is to preserve backward compatibility for users who manage routing tables outside of NetworkManager.")
@@ -228,14 +229,14 @@
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_TIMEOUT N_("A timeout for a DHCP transaction in seconds.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS N_("Array of IP addresses of DNS servers.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties.")
-#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting.  A lower value is better (higher priority). Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections.  It does not disambiguate multiple DNS servers within the same connection profile. When using dns=default, servers with higher priority will be on top of resolv.conf.  To prioritize a given server over another one within the same connection, just specify them in the desired order.  When multiple devices have configurations with the same priority, the one with an active default route will be preferred.  Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports split-DNS as dns=dnsmasq or dns=systemd-resolved, each connection is used to query domains in its search list.  Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually).  When multiple connections specify the same domain, the one with the highest priority (lowest numerical value) wins.  If a connection specifies a domain which is subdomain of another domain with a negative DNS priority value, the subdomain is ignored.")
+#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting.  A lower value is better (higher priority). Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections.  It does not disambiguate multiple DNS servers within the same connection profile. When using dns=default, servers with higher priority will be on top of resolv.conf.  To prioritize a given server over another one within the same connection, just specify them in the desired order.  When multiple devices have configurations with the same priority, the one with an active default route will be preferred.  Negative values have the special effect of excluding other configurations with a greater priority value; so in presence of at least a negative priority, only DNS servers from connections with the lowest priority value will be used. When using a DNS resolver that supports Conditional Forwarding as dns=dnsmasq or dns=systemd-resolved, each connection is used to query domains in its search list.  Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually).  When multiple connections specify the same domain, the one with the highest priority (lowest numerical value) wins.  If a connection specifies a domain which is subdomain of another domain with a negative DNS priority value, the subdomain is ignored.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_SEARCH N_("Array of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured nameservers and search domains are ignored and only nameservers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IGNORE_AUTO_ROUTES N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured routes are ignored and only routes specified in the \"routes\" property, if any, are used.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IP6_PRIVACY N_("Configure IPv6 Privacy Extensions for SLAAC, described in RFC4941.  If enabled, it makes the kernel generate a temporary IPv6 address in addition to the public one generated from MAC address via modified EUI-64.  This enhances privacy, but could cause problems in some applications, on the other hand.  The permitted values are: -1: unknown, 0: disabled, 1: enabled (prefer public address), 2: enabled (prefer temporary addresses). Having a per-connection setting set to \"-1\" (unknown) means fallback to global configuration \"ipv6.ip6-privacy\". If also global configuration is unspecified or set to \"-1\", fallback to read \"/proc/sys/net/ipv6/conf/default/use_tempaddr\". Note that this setting is distinct from the Stable Privacy addresses that can be enabled with the \"addr-gen-mode\" property's \"stable-privacy\" setting as another way of avoiding host tracking with IPv6 addresses.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_MAY_FAIL N_("If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out.  Note that at least one IP configuration must succeed or overall network configuration will still fail.  For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully.")
-#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_METHOD N_("IP configuration method. NMSettingIP4Config and NMSettingIP6Config both support \"auto\", \"manual\", and \"link-local\". See the subclass-specific documentation for other values. In general, for the \"auto\" method, properties such as \"dns\" and \"routes\" specify information that is added on to the information returned from automatic configuration.  The \"ignore-auto-routes\" and \"ignore-auto-dns\" properties modify this behavior. For methods that imply no upstream network, such as \"shared\" or \"link-local\", these properties must be empty. For IPv4 method \"shared\", the IP subnet can be configured by adding one manual IPv4 address or otherwise 10.42.x.0/24 is chosen. Note that the shared method must be configured on the interface which shares the internet to a subnet, not on the uplink which is shared.")
+#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_METHOD N_("IP configuration method. NMSettingIP4Config and NMSettingIP6Config both support \"disabled\", \"auto\", \"manual\", and \"link-local\". See the subclass-specific documentation for other values. In general, for the \"auto\" method, properties such as \"dns\" and \"routes\" specify information that is added on to the information returned from automatic configuration.  The \"ignore-auto-routes\" and \"ignore-auto-dns\" properties modify this behavior. For methods that imply no upstream network, such as \"shared\" or \"link-local\", these properties must be empty. For IPv4 method \"shared\", the IP subnet can be configured by adding one manual IPv4 address or otherwise 10.42.x.0/24 is chosen. Note that the shared method must be configured on the interface which shares the internet to a subnet, not on the uplink which is shared.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_NEVER_DEFAULT N_("If TRUE, this connection will never be the default connection for this IP type, meaning it will never be assigned the default route by NetworkManager.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ROUTE_METRIC N_("The default metric for routes that don't explicitly specify a metric. The default value -1 means that the metric is chosen automatically based on the device type. The metric applies to dynamic routes, manual (static) routes that don't have an explicit metric setting, address prefix routes, and the default route. Note that for IPv6, the kernel accepts zero (0) but coerces it to 1024 (user default). Hence, setting this property to zero effectively mean setting it to 1024. For IPv4, zero is a regular value for the metric.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ROUTE_TABLE N_("Enable policy routing (source routing) and set the routing table used when adding routes. This affects all routes, including device-routes, IPv4LL, DHCP, SLAAC, default-routes and static routes. But note that static routes can individually overwrite the setting by explicitly specifying a non-zero routing table. If the table setting is left at zero, it is eligible to be overwritten via global configuration. If the property is zero even after applying the global configuration value, policy routing is disabled for the address family of this connection. Policy routing disabled means that NetworkManager will add all routes to the main table (except static routes that explicitly configure a different table). Additionally, NetworkManager will not delete any extraneous routes from tables except the main table. This is to preserve backward compatibility for users who manage routing tables outside of NetworkManager.")
@@ -255,11 +256,13 @@
 #define DESCRIBE_DOC_NM_SETTING_MACVLAN_PROMISCUOUS N_("Whether the interface should be put in promiscuous mode.")
 #define DESCRIBE_DOC_NM_SETTING_MACVLAN_TAP N_("Whether the interface should be a MACVTAP.")
 #define DESCRIBE_DOC_NM_SETTING_MATCH_INTERFACE_NAME N_("A list of interface names to match. Each element is a shell wildcard pattern.  When an element is prefixed with exclamation mark (!) the condition is inverted. A candidate interface name is considered matching when both these conditions are satisfied: (a) any of the elements not prefixed with '!' matches or there aren't such elements; (b) none of the elements prefixed with '!' match.")
+#define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_DATAPATH_TYPE N_("The data path type. One of \"system\", \"netdev\" or empty.")
 #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_FAIL_MODE N_("The bridge failure mode. One of \"secure\", \"standalone\" or empty.")
 #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_MCAST_SNOOPING_ENABLE N_("Enable or disable multicast snooping.")
 #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_RSTP_ENABLE N_("Enable or disable RSTP.")
 #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_STP_ENABLE N_("Enable or disable STP.")
-#define DESCRIBE_DOC_NM_SETTING_OVS_INTERFACE_TYPE N_("The interface type. Either \"internal\", or empty.")
+#define DESCRIBE_DOC_NM_SETTING_OVS_DPDK_DEVARGS N_("Open vSwitch DPDK device arguments.")
+#define DESCRIBE_DOC_NM_SETTING_OVS_INTERFACE_TYPE N_("The interface type. Either \"internal\", \"system\", \"patch\", \"dpdk\", or empty.")
 #define DESCRIBE_DOC_NM_SETTING_OVS_PATCH_PEER N_("Specifies the unicast destination IP address of a remote Open vSwitch bridge port to connect to.")
 #define DESCRIBE_DOC_NM_SETTING_OVS_PORT_BOND_DOWNDELAY N_("The time port must be inactive in order to be considered down.")
 #define DESCRIBE_DOC_NM_SETTING_OVS_PORT_BOND_MODE N_("Bonding mode. One of \"active-backup\", \"balance-slb\", or \"balance-tcp\".")
@@ -310,7 +313,7 @@
 #define DESCRIBE_DOC_NM_SETTING_TEAM_MCAST_REJOIN_INTERVAL N_("Corresponds to the teamd mcast_rejoin.interval.")
 #define DESCRIBE_DOC_NM_SETTING_TEAM_NOTIFY_PEERS_COUNT N_("Corresponds to the teamd notify_peers.count.")
 #define DESCRIBE_DOC_NM_SETTING_TEAM_NOTIFY_PEERS_INTERVAL N_("Corresponds to the teamd notify_peers.interval.")
-#define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER N_("Corresponds to the teamd runner.name. Permitted values are: \"roundrobin\", \"broadcast\", \"activebackup\", \"loadbalance\", \"lacp\", \"random\". When setting the runner, all the properties specific to the runner will be reset to the default value; all the properties specific to other runners will be set to an empty value (or if not possible to a default value).")
+#define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER N_("Corresponds to the teamd runner.name. Permitted values are: \"roundrobin\", \"broadcast\", \"activebackup\", \"loadbalance\", \"lacp\", \"random\".")
 #define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER_ACTIVE N_("Corresponds to the teamd runner.active.")
 #define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY N_("Corresponds to the teamd runner.agg_select_policy.")
 #define DESCRIBE_DOC_NM_SETTING_TEAM_RUNNER_FAST_RATE N_("Corresponds to the teamd runner.fast_rate.")
@@ -366,7 +369,9 @@
 #define DESCRIBE_DOC_NM_SETTING_WIFI_P2P_WPS_METHOD N_("Flags indicating which mode of WPS is to be used. There's little point in changing the default setting as NetworkManager will automatically determine the best method to use.")
 #define DESCRIBE_DOC_NM_SETTING_WIMAX_MAC_ADDRESS N_("If specified, this connection will only apply to the WiMAX device whose MAC address matches. This property does not change the MAC address of the device (known as MAC spoofing). Deprecated: 1")
 #define DESCRIBE_DOC_NM_SETTING_WIMAX_NETWORK_NAME N_("Network Service Provider (NSP) name of the WiMAX network this connection should use. Deprecated: 1")
-#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_FWMARK N_("The use of fwmark is optional and is by default off. Setting it to 0 disables it. Otherwise it is a 32-bit fwmark for outgoing packets.")
+#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_FWMARK N_("The use of fwmark is optional and is by default off. Setting it to 0 disables it. Otherwise it is a 32-bit fwmark for outgoing packets. Note that \"ip4-auto-default-route\" or \"ip6-auto-default-route\" enabled, implies to automatically choose a fwmark.")
+#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_IP4_AUTO_DEFAULT_ROUTE N_("Whether to enable special handling of the IPv4 default route. If enabled, the IPv4 default route will be placed to a dedicated routing-table and two policy routing rules will be added. The fwmark number is also used as routing-table for the default-route, and if fwmark is zero, a unused fwmark/table is chosen automatically. This corresponds to what wg-quick does with Table=auto. Leaving this at the default will enable this option automatically if ipv4.never-default is not set and there are any peers that use a default-route as allowed-ips.")
+#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_IP6_AUTO_DEFAULT_ROUTE N_("Like ip4-auto-default-route, but for the IPv6 default route.")
 #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_LISTEN_PORT N_("The listen-port. If listen-port is not specified, the port will be chosen randomly when the interface comes up.")
 #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple fragments. If zero a default MTU is used. Note that contrary to wg-quick's MTU setting, this does not take into account the current routes at the time of activation.")
 #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_PEER_ROUTES N_("Whether to automatically add routes for the AllowedIPs ranges of the peers. If TRUE (the default), NetworkManager will automatically add routes in the routing tables according to ipv4.route-table and ipv6.route-table. If FALSE, no such routes are added automatically. In this case, the user may want to configure static routes in ipv4.routes and ipv6.routes, respectively.")
diff --git a/clients/common/tests/meson.build b/clients/common/tests/meson.build
index 3eb32a47..624dd89c 100644
--- a/clients/common/tests/meson.build
+++ b/clients/common/tests/meson.build
@@ -1,23 +1,43 @@
-test_unit = 'test-general'
-
-deps = [
-  libnm_dep,
-  libnmc_dep,
-  libnmc_base_dep,
-  libnm_core_dep,
-]
+test_name = 'test-clients-common'
 
 exe = executable(
-  'clients-' + test_unit,
-  test_unit + '.c',
-  dependencies: deps,
+  test_name,
+  test_name + '.c',
+  dependencies: [
+    libnm_dep,
+    libnmc_dep,
+    libnmc_base_dep,
+    libnm_core_dep,
+  ],
   c_args: clients_cflags + [
     '-DNETWORKMANAGER_COMPILATION_TEST',
   ],
 )
 
 test(
-  'clients/' + test_unit,
+  test_name,
   test_script,
   args: test_args + [exe.full_path()],
 )
+
+###############################################################################
+
+exe = executable(
+    'test-libnm-core-aux',
+    [ 'test-libnm-core-aux.c', ],
+    c_args: [
+        '-DNETWORKMANAGER_COMPILATION_TEST',
+        '-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_CLIENT',
+    ],
+    dependencies: [
+        libnm_dep,
+        shared_nm_libnm_core_aux_dep,
+        shared_nm_libnm_core_intern_dep,
+    ],
+)
+
+test(
+    'clients/common/tests/test-libnm-core-aux',
+    test_script,
+    args: test_args + [exe.full_path()]
+)
diff --git a/clients/common/tests/test-general.c b/clients/common/tests/test-clients-common.c
index c39901ba..75233acd 100644
--- a/clients/common/tests/test-general.c
+++ b/clients/common/tests/test-clients-common.c
@@ -1,4 +1,3 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
 /*
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/clients/common/tests/test-libnm-core-aux.c b/clients/common/tests/test-libnm-core-aux.c
new file mode 100644
index 00000000..609a688c
--- /dev/null
+++ b/clients/common/tests/test-libnm-core-aux.c
@@ -0,0 +1,250 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2019 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+
+#include "nm-libnm-core-aux/nm-libnm-core-aux.h"
+#include "nm-libnm-core-intern/nm-libnm-core-utils.h"
+
+#include "nm-utils/nm-test-utils.h"
+
+/*****************************************************************************/
+
+static NMTeamLinkWatcher *
+_team_link_watcher_from_string_impl (const char *str, gsize nextra, const char *const*vextra)
+{
+	NMTeamLinkWatcher *watcher;
+	gs_free char *str1_free = NULL;
+	gs_free_error GError *error = NULL;
+	gsize i;
+
+	g_assert (str);
+
+	watcher = nm_utils_team_link_watcher_from_string (str, &error);
+	nmtst_assert_success (watcher, error);
+
+	for (i = 0; i < 1 + nextra; i++) {
+		nm_auto_unref_team_link_watcher NMTeamLinkWatcher *watcher1 = NULL;
+		const char *str1;
+
+		if (i == 0) {
+			str1_free = nm_utils_team_link_watcher_to_string (watcher);
+			g_assert (str1_free);
+			str1 = str1_free;
+			g_assert_cmpstr (str, ==, str1);
+		} else
+			str1 = vextra[i - 1];
+
+		watcher1 = nm_utils_team_link_watcher_from_string (str1, &error);
+		nmtst_assert_success (watcher1, error);
+		if (!nm_team_link_watcher_equal (watcher, watcher1)) {
+			gs_free char *ss1 = NULL;
+			gs_free char *ss2 = NULL;
+
+			g_print (">>> watcher differs: \"%s\" vs. \"%s\"",
+			         (ss1 = nm_utils_team_link_watcher_to_string (watcher)),
+			         (ss2 = nm_utils_team_link_watcher_to_string (watcher1)));
+			g_print (">>> ORIG: \"%s\" vs. \"%s\"", str, str1);
+			g_assert_not_reached ();
+		}
+		g_assert (nm_team_link_watcher_equal (watcher1, watcher));
+	}
+
+	return watcher;
+}
+#define _team_link_watcher_from_string(str, ...) \
+	_team_link_watcher_from_string_impl ((str), NM_NARG (__VA_ARGS__), NM_MAKE_STRV (__VA_ARGS__))
+
+/*****************************************************************************/
+
+static void
+test_team_link_watcher_tofro_string (void)
+{
+	nm_auto_unref_team_link_watcher NMTeamLinkWatcher *w = NULL;
+
+#define _team_link_watcher_cmp(watcher, \
+                               name, \
+                               delay_down, \
+                               delay_up, \
+                               init_wait, \
+                               interval, \
+                               missed_max, \
+                               target_host, \
+                               source_host, \
+                               vlanid, \
+                               arping_flags) \
+	G_STMT_START { \
+		nm_auto_unref_team_link_watcher NMTeamLinkWatcher *_w = g_steal_pointer (watcher); \
+		\
+		g_assert_cmpstr ((name),         ==, nm_team_link_watcher_get_name (_w)); \
+		g_assert_cmpint ((delay_down),   ==, nm_team_link_watcher_get_delay_down (_w)); \
+		g_assert_cmpint ((delay_up),     ==, nm_team_link_watcher_get_delay_up (_w)); \
+		g_assert_cmpint ((init_wait),    ==, nm_team_link_watcher_get_init_wait (_w)); \
+		g_assert_cmpint ((interval),     ==, nm_team_link_watcher_get_interval (_w)); \
+		g_assert_cmpint ((missed_max),   ==, nm_team_link_watcher_get_missed_max (_w)); \
+		g_assert_cmpstr ((target_host),  ==, nm_team_link_watcher_get_target_host (_w)); \
+		g_assert_cmpstr ((source_host),  ==, nm_team_link_watcher_get_source_host (_w)); \
+		g_assert_cmpint ((vlanid),       ==, nm_team_link_watcher_get_vlanid (_w)); \
+		g_assert_cmpint ((arping_flags), ==, nm_team_link_watcher_get_flags (_w)); \
+	} G_STMT_END
+
+	w = _team_link_watcher_from_string ("name=ethtool",
+	                                    "delay-up=0   name=ethtool",
+	                                    "  delay-down=0   name=ethtool   ");
+	_team_link_watcher_cmp (&w,
+	                        "ethtool",
+	                        0,
+	                        0,
+	                        -1,
+	                        -1,
+	                        -1,
+	                        NULL,
+	                        NULL,
+	                        -1,
+	                        NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE);
+
+	w = _team_link_watcher_from_string ("name=ethtool delay-up=10",
+	                                    "   delay-down=0  delay-up=10   name=ethtool");
+	_team_link_watcher_cmp (&w,
+	                        "ethtool",
+	                        0,
+	                        10,
+	                        -1,
+	                        -1,
+	                        -1,
+	                        NULL,
+	                        NULL,
+	                        -1,
+	                        NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE);
+
+	w = _team_link_watcher_from_string ("name=ethtool delay-up=10 delay-down=11",
+	                                    "   delay-down=11  delay-up=10   name=ethtool");
+	_team_link_watcher_cmp (&w,
+	                        "ethtool",
+	                        11,
+	                        10,
+	                        -1,
+	                        -1,
+	                        -1,
+	                        NULL,
+	                        NULL,
+	                        -1,
+	                        NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE);
+
+	w = _team_link_watcher_from_string ("name=nsna_ping target-host=xxx",
+	                                    "name=nsna_ping target-host=xxx",
+	                                    "  missed-max=3    target-host=xxx        name=nsna_ping   ");
+	_team_link_watcher_cmp (&w,
+	                        "nsna_ping",
+	                        -1,
+	                        -1,
+	                        0,
+	                        0,
+	                        3,
+	                        "xxx",
+	                        NULL,
+	                        -1,
+	                        NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE);
+
+	w = _team_link_watcher_from_string ("name=arp_ping target-host=xxx source-host=yzd",
+	                                    "  source-host=yzd target-host=xxx        name=arp_ping   ");
+	_team_link_watcher_cmp (&w,
+	                        "arp_ping",
+	                        -1,
+	                        -1,
+	                        0,
+	                        0,
+	                        3,
+	                        "xxx",
+	                        "yzd",
+	                        -1,
+	                        NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE);
+
+	w = _team_link_watcher_from_string ("name=arp_ping missed-max=0 target-host=xxx vlanid=0 source-host=yzd");
+	_team_link_watcher_cmp (&w,
+	                        "arp_ping",
+	                        -1,
+	                        -1,
+	                        0,
+	                        0,
+	                        0,
+	                        "xxx",
+	                        "yzd",
+	                        0,
+	                        NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE);
+
+	w = _team_link_watcher_from_string ("name=arp_ping target-host=xxx source-host=yzd validate-active=true",
+	                                    "source-host=yzd send-always=false name=arp_ping validate-active=true validate-inactive=false target-host=xxx",
+	                                    "  source-host=yzd target-host=xxx   validate-active=true      name=arp_ping   ");
+	_team_link_watcher_cmp (&w,
+	                        "arp_ping",
+	                        -1,
+	                        -1,
+	                        0,
+	                        0,
+	                        3,
+	                        "xxx",
+	                        "yzd",
+	                        -1,
+	                        NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE);
+
+	w = _team_link_watcher_from_string ("name=arp_ping target-host=xxx source-host=yzd validate-active=true validate-inactive=true send-always=true",
+	                                    "source-host=yzd send-always=true name=arp_ping validate-active=true validate-inactive=true target-host=xxx",
+	                                    "source-host=yzd send-always=true name=arp_ping validate-active=1 validate-inactive=yes target-host=xxx",
+	                                    "  source-host=yzd target-host=xxx   validate-inactive=true send-always=true    validate-active=true      name=arp_ping   ");
+	_team_link_watcher_cmp (&w,
+	                        "arp_ping",
+	                        -1,
+	                        -1,
+	                        0,
+	                        0,
+	                        3,
+	                        "xxx",
+	                        "yzd",
+	                        -1,
+	                          NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE
+	                        | NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE
+	                        | NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS);
+
+	w = _team_link_watcher_from_string ("name=arp_ping missed-max=0 target-host=xxx vlanid=0 source-host=yzd");
+	_team_link_watcher_cmp (&w,
+	                        "arp_ping",
+	                        -1,
+	                        -1,
+	                        0,
+	                        0,
+	                        0,
+	                        "xxx",
+	                        "yzd",
+	                        0,
+	                        NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE);
+}
+
+/*****************************************************************************/
+
+NMTST_DEFINE ();
+
+int main (int argc, char **argv)
+{
+	nmtst_init (&argc, &argv, TRUE);
+
+	g_test_add_func ("/libnm-core-aux/test_team_link_watcher_tofro_string", test_team_link_watcher_tofro_string);
+
+	return g_test_run ();
+}