summary refs log tree commit diff
path: root/clients
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2019-02-26 19:01:41 +0100
committerMichael Biebl <biebl@debian.org>2019-02-26 19:01:41 +0100
commit964ae8cc391520440cf5aa13e2b9cc34850ea6c2 (patch)
tree50da9ecaee7fbb612ec18f9e24f7dec215bf7861 /clients
parent3626b425d1bc017fdc6f1ea0cfd329d1e1681641 (diff)
New upstream version 1.14.6 upstream/1.14.6
Diffstat (limited to 'clients')
-rw-r--r--clients/cli/connections.c58
-rw-r--r--clients/cli/devices.c155
-rw-r--r--clients/cli/utils.c2
-rw-r--r--clients/common/meson.build14
-rw-r--r--clients/common/nm-meta-setting-desc.c129
-rw-r--r--clients/common/settings-docs.h10
-rw-r--r--clients/common/settings-docs.h.in10
-rwxr-xr-xclients/tests/test-client.py4
8 files changed, 188 insertions, 194 deletions
diff --git a/clients/cli/connections.c b/clients/cli/connections.c
index bcd257ac..8a10691e 100644
--- a/clients/cli/connections.c
+++ b/clients/cli/connections.c
@@ -6534,6 +6534,12 @@ static gboolean nmc_editor_cb_called;
 static GError *nmc_editor_error;
 static MonitorACInfo *nmc_editor_monitor_ac;
 
+static void
+editor_connection_changed_cb (NMConnection *connection, gboolean *changed)
+{
+	*changed = TRUE;
+}
+
 /*
  * Store 'error' to shared 'nmc_editor_error' and monitoring info to
  * 'nmc_editor_monitor_ac' and signal the condition so that
@@ -6579,8 +6585,8 @@ static gboolean
 progress_activation_editor_cb (gpointer user_data)
 {
 	MonitorACInfo *info = (MonitorACInfo *) user_data;
-	gs_unref_object NMDevice *device = info->device;
-	gs_unref_object NMActiveConnection *ac = info->ac;
+	NMDevice *device = info->device;
+	NMActiveConnection *ac = info->ac;
 	NMActiveConnectionState ac_state;
 	NMDeviceState dev_state;
 
@@ -6613,11 +6619,13 @@ progress_activation_editor_cb (gpointer user_data)
 		                               nm_object_get_path (NM_OBJECT (connection)));
 	}
 
-	return TRUE;
+	return G_SOURCE_CONTINUE;
 
 finish:
+	nm_g_object_unref (device);
+	nm_g_object_unref (ac);
 	info->monitor_id = 0;
-	return FALSE;
+	return G_SOURCE_REMOVE;
 }
 
 static void
@@ -7128,6 +7136,16 @@ menu_switch_to_level1 (const NmcConfig *nmc_config,
 }
 
 static gboolean
+editor_save_timeout (gpointer user_data)
+{
+	gboolean *timeout = user_data;
+
+	*timeout = TRUE;
+
+	return G_SOURCE_REMOVE;
+}
+
+static gboolean
 editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_type)
 {
 	gs_unref_object NMRemoteConnection *rem_con = NULL;
@@ -7646,6 +7664,10 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 			/* Save the connection */
 			if (nm_connection_verify (connection, &err1)) {
 				gboolean persistent = TRUE;
+				gboolean connection_changed;
+				nm_auto_unref_gsource GSource *source = NULL;
+				gboolean timeout = FALSE;
+				gulong handler_id = 0;
 
 				/* parse argument */
 				if (cmd_arg) {
@@ -7674,23 +7696,44 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 					                    connection,
 					                    add_connection_editor_cb,
 					                    info);
+					connection_changed = TRUE;
 				} else {
 					/* Save/update already saved (existing) connection */
 					nm_connection_replace_settings_from_connection (NM_CONNECTION (rem_con),
 					                                                connection);
 					update_connection (persistent, rem_con, update_connection_editor_cb, NULL);
+
+					handler_id = g_signal_connect (rem_con,
+					                               NM_CONNECTION_CHANGED,
+					                               G_CALLBACK (editor_connection_changed_cb),
+					                               &connection_changed);
+					connection_changed = FALSE;
 				}
 
-				//FIXME: add also a timeout for cases the callback is not called
-				while (!nmc_editor_cb_called)
+				source = g_timeout_source_new (10 * NM_UTILS_MSEC_PER_SECOND);
+				g_source_set_callback (source, editor_save_timeout, &timeout, NULL);
+				g_source_attach (source, g_main_loop_get_context (loop));
+
+				while (!nmc_editor_cb_called && !timeout)
 					g_main_context_iteration (NULL, TRUE);
 
+				while (!connection_changed && !timeout)
+					g_main_context_iteration (NULL, TRUE);
+
+				if (handler_id)
+					g_signal_handler_disconnect (rem_con, handler_id);
+				g_source_destroy (source);
+
 				if (nmc_editor_error) {
 					g_print (_("Error: Failed to save '%s' (%s) connection: %s\n"),
 					         nm_connection_get_id (connection),
 					         nm_connection_get_uuid (connection),
 					         nmc_editor_error->message);
 					g_error_free (nmc_editor_error);
+				} else if (timeout) {
+					g_print (_("Error: Timeout saving '%s' (%s) connection\n"),
+					         nm_connection_get_id (connection),
+					         nm_connection_get_uuid (connection));
 				} else {
 					g_print (!rem_con ?
 					         _("Connection '%s' (%s) successfully saved.\n") :
@@ -7713,9 +7756,10 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
 						if (menu_ctx.curr_setting)
 							s_name = g_strdup (nm_setting_get_name (menu_ctx.curr_setting));
 
-						/* Update settings in the local connection */
+						/* Update settings and secrets in the local connection */
 						nm_connection_replace_settings_from_connection (connection,
 						                                                NM_CONNECTION (con_tmp));
+						update_secrets_in_connection (con_tmp, connection);
 
 						/* Also update setting for menu context and TAB-completion */
 						menu_ctx.curr_setting = s_name ? nm_connection_get_setting_by_name (connection, s_name) : NULL;
diff --git a/clients/cli/devices.c b/clients/cli/devices.c
index 029ca671..5aaf4ef8 100644
--- a/clients/cli/devices.c
+++ b/clients/cli/devices.c
@@ -2094,6 +2094,7 @@ typedef struct {
 	GSList *queue;
 	guint timeout_id;
 	gboolean cmd_disconnect;
+	GCancellable *cancellable;
 } DeviceCbInfo;
 
 static void device_cb_info_finish (DeviceCbInfo *info, NMDevice *device);
@@ -2166,7 +2167,10 @@ device_cb_info_finish (DeviceCbInfo *info, NMDevice *device)
 
 	if (info->timeout_id)
 		g_source_remove (info->timeout_id);
+
 	g_signal_handlers_disconnect_by_func (info->nmc->client, device_removed_cb, info);
+	nm_clear_g_cancellable (&info->cancellable);
+
 	g_slice_free (DeviceCbInfo, info);
 	quit ();
 }
@@ -2343,11 +2347,14 @@ disconnect_device_cb (GObject *object, GAsyncResult *result, gpointer user_data)
 {
 	NMDevice *device = NM_DEVICE (object);
 	DeviceCbInfo *info = (DeviceCbInfo *) user_data;
-	NmCli *nmc = info->nmc;
+	NmCli *nmc;
 	NMDeviceState state;
 	GError *error = NULL;
 
 	if (!nm_device_disconnect_finish (device, result, &error)) {
+		if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+			return;
+		nmc = info->nmc;
 		g_string_printf (nmc->return_text, _("Error: not all devices disconnected."));
 		g_printerr (_("Error: Device '%s' (%s) disconnecting failed: %s\n"),
 		            nm_device_get_iface (device),
@@ -2357,6 +2364,7 @@ disconnect_device_cb (GObject *object, GAsyncResult *result, gpointer user_data)
 		nmc->return_value = NMC_RESULT_ERROR_DEV_DISCONNECT;
 		device_cb_info_finish (info, device);
 	} else {
+		nmc = info->nmc;
 		state = nm_device_get_state (device);
 		if (nmc->nowait_flag || state <= NM_DEVICE_STATE_DISCONNECTED) {
 			/* Don't want to wait or device already disconnected */
@@ -2393,6 +2401,7 @@ do_devices_disconnect (NmCli *nmc, int argc, char **argv)
 	info = g_slice_new0 (DeviceCbInfo);
 	info->nmc = nmc;
 	info->cmd_disconnect = TRUE;
+	info->cancellable = g_cancellable_new ();
 	if (nmc->timeout > 0)
 		info->timeout_id = g_timeout_add_seconds (nmc->timeout, device_op_timeout_cb, info);
 
@@ -2410,7 +2419,7 @@ do_devices_disconnect (NmCli *nmc, int argc, char **argv)
 		                  G_CALLBACK (disconnect_state_cb), info);
 
 		/* Now disconnect the device */
-		nm_device_disconnect_async (device, NULL, disconnect_device_cb, info);
+		nm_device_disconnect_async (device, info->cancellable, disconnect_device_cb, info);
 	}
 
 out:
@@ -2795,7 +2804,7 @@ show_access_point_info (NMDeviceWifi *wifi, NmCli *nmc, NmcOutputData *out)
 
 		aps = sort_access_points (nm_device_wifi_get_access_points (wifi));
 		g_ptr_array_foreach (aps, fill_output_access_point, &info);
-		g_ptr_array_free (aps, FALSE);
+		g_ptr_array_free (aps, TRUE);
 	}
 
 	print_data_prepare_width (out->output_data);
@@ -2870,28 +2879,38 @@ wifi_print_aps (NMDeviceWifi *wifi,
 
 typedef struct {
 	NmCli *nmc;
-	NMDeviceWifi *wifi;
-	const NMMetaAbstractInfo *const*tmpl;
-
+	NMDevice **devices;
+	const NMMetaAbstractInfo *const *tmpl;
 	const char *bssid_user;
+	GArray *out_indices;
+} ScanInfo;
+
+typedef struct {
+	ScanInfo *scan_info;
+	NMDeviceWifi *wifi;
 	gulong last_scan_id;
 	guint  timeout_id;
 	GCancellable *scan_cancellable;
-	GArray *out_indices;
 } WifiListData;
 
 static void
 wifi_list_finish (WifiListData *data)
 {
-	NmCli *nmc = data->nmc;
-
-	wifi_print_aps (data->wifi, data->nmc, data->out_indices,
-	                data->tmpl, data->bssid_user);
+	ScanInfo *info = data->scan_info;
+	NmCli *nmc = info->nmc;
+	guint i;
 
-	if (--nmc->should_wait == 0) {
+	if (--info->nmc->should_wait == 0) {
+		for (i = 0; info->devices[i]; i++) {
+			wifi_print_aps (NM_DEVICE_WIFI (info->devices[i]),
+			                info->nmc,
+			                info->out_indices,
+			                info->tmpl,
+			                info->bssid_user);
+		}
 		if (nmc->return_value == NMC_RESULT_ERROR_NOT_FOUND) {
 			g_string_printf (nmc->return_text, _("Error: Access point with bssid '%s' not found."),
-			                 data->bssid_user);
+			                 data->scan_info->bssid_user);
 		}
 		g_main_loop_quit (loop);
 	}
@@ -2899,9 +2918,15 @@ wifi_list_finish (WifiListData *data)
 	g_signal_handler_disconnect (data->wifi, data->last_scan_id);
 	nm_clear_g_source (&data->timeout_id);
 	nm_clear_g_cancellable (&data->scan_cancellable);
-	g_array_unref (data->out_indices);
-	g_object_unref (data->wifi);
 	g_slice_free (WifiListData, data);
+
+	if (info->nmc->should_wait == 0) {
+		for (i = 0; info->devices[i]; i++)
+			g_object_unref (info->devices[i]);
+		g_free (info->devices);
+		g_array_unref (info->out_indices);
+		g_free (info);
+	}
 }
 
 static void
@@ -2946,49 +2971,6 @@ wifi_list_scan_timeout (gpointer user_data)
 }
 
 static void
-wifi_list_aps (NMDeviceWifi *wifi,
-               NmCli *nmc,
-               GArray *out_indices,
-               const NMMetaAbstractInfo *const*tmpl,
-               const char *bssid_user,
-               gint64 rescan_cutoff)
-{
-	gboolean needs_rescan;
-	WifiListData *data;
-
-	needs_rescan = rescan_cutoff < 0 || (rescan_cutoff > 0 && nm_device_wifi_get_last_scan (wifi) < rescan_cutoff);
-
-	/* FIXME: nmcli should either
-	 *  - don't request any new scan for any device and print the full AP list right
-	 *    away.
-	 *  - or, when requesting a scan on one or more devices, don't print the result
-	 *    before all requests complete.
-	 *
-	 *  Otherwise:
-	 *    - the printed output is not self consistent. E.g. it will print the result
-	 *      on one device at a certain time, while printing the result for another
-	 *      device at a later point in time.
-	 *    - the order in which we print the AP list per-device, is unstable. */
-	if (needs_rescan) {
-		data = g_slice_new0 (WifiListData);
-		data->nmc = nmc;
-		data->wifi = g_object_ref (wifi);
-		data->tmpl = tmpl;
-		data->out_indices = g_array_ref (out_indices);;
-		data->bssid_user = bssid_user;
-		data->last_scan_id = g_signal_connect (wifi, "notify::" NM_DEVICE_WIFI_LAST_SCAN,
-		                                       G_CALLBACK (wifi_last_scan_updated), data);
-		data->scan_cancellable = g_cancellable_new ();
-		data->timeout_id = g_timeout_add_seconds (15, wifi_list_scan_timeout, data);
-		nm_device_wifi_request_scan_async (wifi, data->scan_cancellable, wifi_list_rescan_cb, data);
-
-		nmc->should_wait++;
-	} else {
-		wifi_print_aps (wifi, nmc, out_indices, tmpl, bssid_user);
-	}
-}
-
-static void
 complete_aps (NMDevice **devices, const char *ifname,
               const char *bssid_prefix, const char *ssid_prefix)
 {
@@ -3017,12 +2999,15 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
 	const char *bssid_user = NULL;
 	const char *rescan = NULL;
 	gs_free NMDevice **devices = NULL;
-	guint i;
 	const char *fields_str = NULL;
 	const NMMetaAbstractInfo *const*tmpl;
 	gs_unref_array GArray *out_indices = NULL;
 	int option;
 	guint64 rescan_cutoff;
+	NMDeviceWifi *wifi;
+	ScanInfo *scan_info = NULL;
+	WifiListData *data;
+	guint i, j;
 
 	devices = nmc_get_devices_sorted (nmc->client);
 
@@ -3110,7 +3095,8 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
 		}
 
 		if (NM_IS_DEVICE_WIFI (device)) {
-			wifi_list_aps (NM_DEVICE_WIFI (device), nmc, out_indices, tmpl, bssid_user, rescan_cutoff);
+			devices[0] = device;
+			devices[1] = NULL;
 		} else {
 			if (   nm_device_get_device_type (device) == NM_DEVICE_TYPE_GENERIC
 			    && g_strcmp0 (nm_device_get_type_description (device), "wifi") == 0) {
@@ -3124,13 +3110,52 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
 			}
 			return NMC_RESULT_ERROR_UNKNOWN;
 		}
+	}
+
+	/* Filter out non-wifi devices */
+	for (i = 0, j = 0; devices[i]; i++) {
+		if (NM_IS_DEVICE_WIFI (devices[i]))
+			devices[j++] = devices[i];
+	}
+	devices[j] = NULL;
+
+	/* Start a new scan for devices that need it */
+	for (i = 0; devices[i]; i++) {
+		wifi = (NMDeviceWifi *) devices[i];
+		g_object_ref (wifi);
+
+		if (   rescan_cutoff == 0
+		    || (rescan_cutoff > 0 && nm_device_wifi_get_last_scan (wifi) >= rescan_cutoff))
+			continue;
+
+		if (!scan_info) {
+			scan_info = g_new0 (ScanInfo, 1);
+			scan_info->out_indices = g_array_ref (out_indices);
+			scan_info->tmpl = tmpl;
+			scan_info->bssid_user = bssid_user;
+			scan_info->nmc = nmc;
+		}
+
+		nmc->should_wait++;
+		data = g_slice_new0 (WifiListData);
+		data->wifi = wifi;
+		data->scan_info = scan_info;
+		data->last_scan_id = g_signal_connect (wifi, "notify::" NM_DEVICE_WIFI_LAST_SCAN,
+		                                       G_CALLBACK (wifi_last_scan_updated), data);
+		data->scan_cancellable = g_cancellable_new ();
+		data->timeout_id = g_timeout_add_seconds (15, wifi_list_scan_timeout, data);
+		nm_device_wifi_request_scan_async (wifi, data->scan_cancellable, wifi_list_rescan_cb, data);
+	}
+
+	if (scan_info) {
+		scan_info->devices = g_steal_pointer (&devices);
 	} else {
+		/* Print results right away if no scan is pending */
 		for (i = 0; devices[i]; i++) {
-			NMDevice *dev = devices[i];
-
-			if (NM_IS_DEVICE_WIFI (dev)) {
-				wifi_list_aps (NM_DEVICE_WIFI (dev), nmc, out_indices, tmpl, bssid_user, rescan_cutoff);
-			}
+			wifi_print_aps (NM_DEVICE_WIFI (devices[i]),
+			                nmc, out_indices,
+			                tmpl, bssid_user);
+			g_object_unref (devices[i]);
 		}
 	}
 
diff --git a/clients/cli/utils.c b/clients/cli/utils.c
index e21c108d..feb67221 100644
--- a/clients/cli/utils.c
+++ b/clients/cli/utils.c
@@ -919,6 +919,8 @@ nmc_empty_output_fields (NmcOutputData *output_data)
 	/* Empty output_data array */
 	if (output_data->output_data->len > 0)
 		g_ptr_array_remove_range (output_data->output_data, 0, output_data->output_data->len);
+
+	g_ptr_array_unref (output_data->output_data);
 }
 
 /*****************************************************************************/
diff --git a/clients/common/meson.build b/clients/common/meson.build
index 0db2868e..30fd2cfa 100644
--- a/clients/common/meson.build
+++ b/clients/common/meson.build
@@ -37,15 +37,11 @@ if enable_introspection
     command: [xsltproc, '--output', '@OUTPUT@', join_paths(meson.current_source_dir(), 'settings-docs.xsl'), '@INPUT@']
   )
 
-  # FIXME: if enabled the check happens even if the settings_docs_source is not set
-  '''
-  if get_option('check_settings_docs')
-    res = run_command(find_program('cmp'), '-s', settings_docs + '.in', settings_docs_source.full_path())
-    if res.returncode() != 0
-      message('The generated file ' + settings_docs_source.full_path() + ' differs from the source file ' + settings_docs + '.in' + '. You probably should copy the generated file over to the source file. You can skip this test by setting -Dcheck_settings_docs=false')
-    endif
-  endif
-  '''
+  test(
+    'check-settings-docs',
+    find_program(join_paths(meson.source_root(), 'tools', 'check-settings-docs.sh')),
+    args: [meson.source_root(), meson.build_root(), 'clients/common/' + settings_docs]
+  )
 else
   settings_docs_source = configure_file(
     input: settings_docs + '.in',
diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c
index d291732a..d13ee4ce 100644
--- a/clients/common/nm-meta-setting-desc.c
+++ b/clients/common/nm-meta-setting-desc.c
@@ -283,7 +283,7 @@ _dump_team_link_watcher (NMTeamLinkWatcher *watcher)
 	}
 	/* 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, "initerval", interval);
+	DUMP_WATCHER_INT (w_dump, watcher, "interval", interval);
 	DUMP_WATCHER_INT (w_dump, watcher, "missed-max", missed_max);
 #undef DUMP_WATCHER_INT
 	g_string_append_printf (w_dump, " target-host=%s",
@@ -2190,7 +2190,7 @@ _get_fcn_802_1x_phase2_private_key (ARGS_GET_FCN)
 		strv = nm_utils_strsplit_set (value, " \t,", FALSE); \
 		if (strv) { \
 			for (i = 0; strv[i]; i++) \
-				set_func (NM_SETTING_802_1X (setting), strv[i++]); \
+				set_func (NM_SETTING_802_1X (setting), strv[i]); \
 		} \
 		return TRUE; \
 	}
@@ -3349,7 +3349,7 @@ DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_ipv4_config_dns,
                                _validate_and_remove_ipv4_dns)
 
 static gboolean
-_set_fcn_ip4_config_dns_search (ARGS_SET_FCN)
+_set_fcn_ip_config_dns_search (ARGS_SET_FCN)
 {
 	gs_free const char **strv = NULL;
 	gsize i;
@@ -3368,9 +3368,9 @@ _set_fcn_ip4_config_dns_search (ARGS_SET_FCN)
 }
 
 static gboolean
-_validate_and_remove_ipv4_dns_search (NMSettingIPConfig *setting,
-                                      const char *dns_search,
-                                      GError **error)
+_validate_and_remove_ip_dns_search (NMSettingIPConfig *setting,
+                                    const char *dns_search,
+                                    GError **error)
 {
 	gboolean ret;
 
@@ -3381,33 +3381,36 @@ _validate_and_remove_ipv4_dns_search (NMSettingIPConfig *setting,
 		             dns_search);
 	return ret;
 }
-DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_ipv4_config_dns_search,
+DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_ip_config_dns_search,
                                NM_SETTING_IP_CONFIG,
                                nm_setting_ip_config_get_num_dns_searches,
                                nm_setting_ip_config_remove_dns_search,
-                               _validate_and_remove_ipv4_dns_search)
+                               _validate_and_remove_ip_dns_search)
 
 static gboolean
-_set_fcn_ip4_config_dns_options (ARGS_SET_FCN)
+_set_fcn_ip_config_dns_options (ARGS_SET_FCN)
 {
 	gs_free const char **strv = NULL;
+	NMSettingIPConfig *s_ip;
 	gsize i;
 
 	nm_assert (!error || !*error);
+	s_ip = NM_SETTING_IP_CONFIG (setting);
 
-	nm_setting_ip_config_clear_dns_options (NM_SETTING_IP_CONFIG (setting), TRUE);
 	strv = nm_utils_strsplit_set (value, " \t,", FALSE);
 	if (strv) {
-		for (i = 0; strv[i]; i++)
-			nm_setting_ip_config_add_dns_option (NM_SETTING_IP_CONFIG (setting), strv[i]);
+		for (i = 0; strv[i]; i++) {
+			nm_setting_ip_config_remove_dns_option_by_value (s_ip, strv[i]);
+			nm_setting_ip_config_add_dns_option (s_ip, strv[i]);
+		}
 	}
 	return TRUE;
 }
 
 static gboolean
-_validate_and_remove_ipv4_dns_option (NMSettingIPConfig *setting,
-                                      const char *dns_option,
-                                      GError **error)
+_validate_and_remove_ip_dns_option (NMSettingIPConfig *setting,
+                                    const char *dns_option,
+                                    GError **error)
 {
 	gboolean ret;
 
@@ -3418,11 +3421,11 @@ _validate_and_remove_ipv4_dns_option (NMSettingIPConfig *setting,
 		             dns_option);
 	return ret;
 }
-DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_ipv4_config_dns_options,
+DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_ip_config_dns_options,
                                NM_SETTING_IP_CONFIG,
                                nm_setting_ip_config_get_num_dns_options,
                                nm_setting_ip_config_remove_dns_option,
-                               _validate_and_remove_ipv4_dns_option)
+                               _validate_and_remove_ip_dns_option)
 
 static gboolean
 _set_fcn_ip4_config_addresses (ARGS_SET_FCN)
@@ -3593,82 +3596,6 @@ DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_ipv6_config_dns,
                                _validate_and_remove_ipv6_dns)
 
 static gboolean
-_set_fcn_ip6_config_dns_search (ARGS_SET_FCN)
-{
-	gs_free const char **strv = NULL;
-	gsize i;
-
-	nm_assert (!error || !*error);
-
-	strv = nm_utils_strsplit_set (value, " \t,", FALSE);
-	if (!verify_string_list (strv, property_info->property_name, nmc_util_is_domain, error))
-		return FALSE;
-
-	if (strv) {
-		for (i = 0; strv[i]; i++)
-			nm_setting_ip_config_add_dns_search (NM_SETTING_IP_CONFIG (setting), strv[i]);
-	}
-	return TRUE;
-}
-
-static gboolean
-_validate_and_remove_ipv6_dns_search (NMSettingIPConfig *setting,
-                                      const char *dns_search,
-                                      GError **error)
-{
-	gboolean ret;
-
-	ret = nm_setting_ip_config_remove_dns_search_by_value (setting, dns_search);
-	if (!ret)
-		g_set_error (error, 1, 0,
-		             _("the property doesn't contain DNS search domain '%s'"),
-		             dns_search);
-	return ret;
-}
-DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_ipv6_config_dns_search,
-                               NM_SETTING_IP_CONFIG,
-                               nm_setting_ip_config_get_num_dns_searches,
-                               nm_setting_ip_config_remove_dns_search,
-                               _validate_and_remove_ipv6_dns_search)
-
-static gboolean
-_set_fcn_ip6_config_dns_options (ARGS_SET_FCN)
-{
-	gs_free const char **strv = NULL;
-	gsize i;
-
-	nm_assert (!error || !*error);
-
-	nm_setting_ip_config_clear_dns_options (NM_SETTING_IP_CONFIG (setting), TRUE);
-	strv = nm_utils_strsplit_set (value, " \t,", FALSE);
-	if (strv) {
-		for (i = 0; strv[i]; i++)
-			nm_setting_ip_config_add_dns_option (NM_SETTING_IP_CONFIG (setting), strv[i]);
-	}
-	return TRUE;
-}
-
-static gboolean
-_validate_and_remove_ipv6_dns_option (NMSettingIPConfig *setting,
-                                      const char *dns_option,
-                                      GError **error)
-{
-	gboolean ret;
-
-	ret = nm_setting_ip_config_remove_dns_option_by_value (setting, dns_option);
-	if (!ret)
-		g_set_error (error, 1, 0,
-		             _("the property doesn't contain DNS option '%s'"),
-		             dns_option);
-	return ret;
-}
-DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_ipv6_config_dns_options,
-                               NM_SETTING_IP_CONFIG,
-                               nm_setting_ip_config_get_num_dns_options,
-                               nm_setting_ip_config_remove_dns_option,
-                               _validate_and_remove_ipv6_dns_option)
-
-static gboolean
 _dns_options_is_default (NMSettingIPConfig *setting)
 {
 	return    nm_setting_ip_config_has_dns_options (setting)
@@ -6183,15 +6110,15 @@ static const NMMetaPropertyInfo *const property_infos_IP4_CONFIG[] = {
 	PROPERTY_INFO (NM_SETTING_IP_CONFIG_DNS_SEARCH, DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_SEARCH,
 		.property_type = DEFINE_PROPERTY_TYPE (
 			.get_fcn =                  _get_fcn_gobject,
-			.set_fcn =                  _set_fcn_ip4_config_dns_search,
-			.remove_fcn =               _remove_fcn_ipv4_config_dns_search,
+			.set_fcn =                  _set_fcn_ip_config_dns_search,
+			.remove_fcn =               _remove_fcn_ip_config_dns_search,
 		),
 	),
 	PROPERTY_INFO (NM_SETTING_IP_CONFIG_DNS_OPTIONS, DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_OPTIONS,
 		.property_type = DEFINE_PROPERTY_TYPE (
 			.get_fcn =                  _get_fcn_nmc_with_default,
-			.set_fcn =                  _set_fcn_ip4_config_dns_options,
-			.remove_fcn =               _remove_fcn_ipv4_config_dns_options,
+			.set_fcn =                  _set_fcn_ip_config_dns_options,
+			.remove_fcn =               _remove_fcn_ip_config_dns_options,
 		),
 		.property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (get_with_default,
 			.fcn =                      GET_FCN_WITH_DEFAULT (NMSettingIPConfig, _dns_options_is_default),
@@ -6346,15 +6273,15 @@ static const NMMetaPropertyInfo *const property_infos_IP6_CONFIG[] = {
 	PROPERTY_INFO (NM_SETTING_IP_CONFIG_DNS_SEARCH, DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_SEARCH,
 		.property_type = DEFINE_PROPERTY_TYPE (
 			.get_fcn =                  _get_fcn_gobject,
-			.set_fcn =                  _set_fcn_ip6_config_dns_search,
-			.remove_fcn =               _remove_fcn_ipv6_config_dns_search,
+			.set_fcn =                  _set_fcn_ip_config_dns_search,
+			.remove_fcn =               _remove_fcn_ip_config_dns_search,
 		),
 	),
 	PROPERTY_INFO (NM_SETTING_IP_CONFIG_DNS_OPTIONS, DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_OPTIONS,
 		.property_type = DEFINE_PROPERTY_TYPE (
 			.get_fcn =                  _get_fcn_nmc_with_default,
-			.set_fcn =                  _set_fcn_ip6_config_dns_options,
-			.remove_fcn =               _remove_fcn_ipv6_config_dns_options,
+			.set_fcn =                  _set_fcn_ip_config_dns_options,
+			.remove_fcn =               _remove_fcn_ip_config_dns_options,
 		),
 		.property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (get_with_default,
 			.fcn =     GET_FCN_WITH_DEFAULT (NMSettingIPConfig, _dns_options_is_default),
diff --git a/clients/common/settings-docs.h b/clients/common/settings-docs.h
index f07769c0..bc56edae 100644
--- a/clients/common/settings-docs.h
+++ b/clients/common/settings-docs.h
@@ -144,7 +144,7 @@
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_READ_ONLY N_("FALSE if the connection can be modified using the provided settings service's D-Bus interface with the right privileges, or TRUE if the connection is read-only and cannot be modified.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_SECONDARIES N_("List of connection UUIDs that should be activated when the base connection itself is activated. Currently only VPN connections are supported.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_SLAVE_TYPE N_("Setting name of the device type of this slave's master connection (eg, \"bond\"), or NULL if this connection is not a slave.")
-#define DESCRIBE_DOC_NM_SETTING_CONNECTION_STABLE_ID N_("This represents the identity of the connection used for various purposes. It allows to configure multiple profiles to share the identity. Also, the stable-id can contain placeholders that are substituted dynamically and deterministically depending on the context. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable and to derive the DHCP DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid]. Note that depending on the context where it is used, other parameters are also seeded into the generation algorithm. For example, a per-host key is commonly also included, so that different systems end up generating different IDs. Or with ipv6.addr-gen-mode=stable-privacy, also the device's name is included, so that different interfaces yield different addresses. The '$' character is treated special to perform dynamic substitutions at runtime. Currently supported are \"${CONNECTION}\", \"${DEVICE}\", \"${BOOT}\", \"${RANDOM}\". These effectively create unique IDs per-connection, per-device, per-boot, or every time. Note that \"${DEVICE}\" corresponds the the interface name of the device. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as \"$$\". For example, set it to \"${CONNECTION}-${BOOT}-${DEVICE}\" to create a unique id for this connection that changes with every reboot and differs depending on the interface where the profile activates. If the value is unset, a global connection default is consulted. If the value is still unset, the default is similar to \"${CONNECTION}\" and uses a unique, fixed ID for the connection.")
+#define DESCRIBE_DOC_NM_SETTING_CONNECTION_STABLE_ID N_("This represents the identity of the connection used for various purposes. It allows to configure multiple profiles to share the identity. Also, the stable-id can contain placeholders that are substituted dynamically and deterministically depending on the context. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable and to derive the DHCP DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid]. Note that depending on the context where it is used, other parameters are also seeded into the generation algorithm. For example, a per-host key is commonly also included, so that different systems end up generating different IDs. Or with ipv6.addr-gen-mode=stable-privacy, also the device's name is included, so that different interfaces yield different addresses. The '$' character is treated special to perform dynamic substitutions at runtime. Currently supported are \"${CONNECTION}\", \"${DEVICE}\", \"${MAC}\", \"${BOOT}\", \"${RANDOM}\". These effectively create unique IDs per-connection, per-device, per-boot, or every time. Note that \"${DEVICE}\" corresponds the the interface name of the device and \"${MAC}\" is the permanent MAC address of the device. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as \"$$\". For example, set it to \"${CONNECTION}-${BOOT}-${DEVICE}\" to create a unique id for this connection that changes with every reboot and differs depending on the interface where the profile activates. If the value is unset, a global connection default is consulted. If the value is still unset, the default is similar to \"${CONNECTION}\" and uses a unique, fixed ID for the connection.")
 #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 \"-\").")
@@ -197,7 +197,7 @@
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_TTL N_("The TTL to assign to tunneled packets. 0 is a special value meaning that packets inherit the TTL value.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ADDRESSES N_("Array of IP addresses.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DAD_TIMEOUT N_("Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network.  If an address conflict is detected, the activation will fail.  A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero).  A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4.")
-#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID N_("A string sent to the DHCP server to identify the local machine which the DHCP server may use to customize the DHCP lease and options. When the property is a hex string ('aa:bb:cc') it is interpreted as a binary client ID, in which case the first byte is assumed to be the 'type' field as per RFC 2132 section 9.14 and the remaining bytes may be an hardware address (e.g. '01:xx:xx:xx:xx:xx:xx' where 1 is the Ethernet ARP type and the rest is a MAC address). If the property is not a hex string it is considered as a non-hardware-address client ID and the 'type' field is set to 0. The special values \"mac\" and \"perm-mac\" are supported, which use the current or permanent MAC address of the device to generate a client identifier with type ethernet (01). Currently, these options only work for ethernet type of links. The special value \"stable\" is supported to generate a type 0 client identifier based on the stable-id (see connection.stable-id) and a per-host key. If unset, a globally configured default is used. If still unset, the client-id from the last lease is reused.")
+#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID N_("A string sent to the DHCP server to identify the local machine which the DHCP server may use to customize the DHCP lease and options. When the property is a hex string ('aa:bb:cc') it is interpreted as a binary client ID, in which case the first byte is assumed to be the 'type' field as per RFC 2132 section 9.14 and the remaining bytes may be an hardware address (e.g. '01:xx:xx:xx:xx:xx:xx' where 1 is the Ethernet ARP type and the rest is a MAC address). If the property is not a hex string it is considered as a non-hardware-address client ID and the 'type' field is set to 0. The special values \"mac\" and \"perm-mac\" are supported, which use the current or permanent MAC address of the device to generate a client identifier with type ethernet (01). Currently, these options only work for ethernet type of links. The special value \"duid\" generates a RFC4361-compliant client identifier based on a hash of the interface name as IAID and /etc/machine-id. The special value \"stable\" is supported to generate a type 0 client identifier based on the stable-id (see connection.stable-id) and a per-host key. If you set the stable-id, you may want to include the \"${DEVICE}\" or \"${MAC}\" specifier to get a per-device key. If unset, a globally configured default is used. If still unset, the default depends on the DHCP plugin.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_FQDN N_("If the \"dhcp-send-hostname\" property is TRUE, then the specified FQDN will be sent to the DHCP server when acquiring a lease. This property and \"dhcp-hostname\" are mutually exclusive and cannot be set at the same time.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_HOSTNAME N_("If the \"dhcp-send-hostname\" property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and \"dhcp-fqdn\" are mutually exclusive and cannot be set at the same time.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_SEND_HOSTNAME N_("If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer.  If the \"dhcp-hostname\" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent.")
@@ -218,7 +218,7 @@
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE N_("Configure method for creating the address for use with RFC4862 IPv6 Stateless Address Autoconfiguration. The permitted values are: NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64 (0) or NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY (1). If the property is set to EUI64, the addresses will be generated using the interface tokens derived from hardware address. This makes the host part of the address to stay constant, making it possible to track host's presence when it changes networks. The address changes when the interface hardware is replaced. The value of stable-privacy enables use of cryptographically secure hash of a secret host-specific key along with the connection's stable-id and the network address as specified by RFC7217. This makes it impossible to use the address track host's presence, and makes the address stable when the network interface hardware is replaced. On D-Bus, the absence of an addr-gen-mode setting equals enabling stable-privacy. For keyfile plugin, the absence of the setting on disk means EUI64 so that the property doesn't change on upgrade from older versions. Note that this setting is distinct from the Privacy Extensions as configured by \"ip6-privacy\" property and it does not affect the temporary addresses configured with this option.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ADDRESSES N_("Array of IP addresses.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DAD_TIMEOUT N_("Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network.  If an address conflict is detected, the activation will fail.  A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero).  A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4.")
-#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_DUID N_("A string containing the DHCPv6 Unique Identifier (DUID) used by the dhcp client to identify itself to DHCPv6 servers (RFC 3315). The DUID is carried in the Client Identifier option. If the property is a hex string ('aa:bb:cc') it is interpreted as a binary DUID and filled as an opaque value in the Client Identifier option. The special value \"lease\" will retrieve the DUID previously used from the lease file belonging to the connection. If no DUID is found and \"dhclient\" is the configured dhcp client, the DUID is searched in the system-wide dhclient lease file. If still no DUID is found, or another dhcp client is used, a global and permanent DUID-UUID (RFC 6355) will be generated based on the machine-id. The special values \"llt\" and \"ll\" will generate a DUID of type LLT or LL (see RFC 3315) based on the current MAC address of the device. In order to try providing a stable DUID-LLT, the time field will contain a constant timestamp that is used globally (for all profiles) and persisted to disk. The special values \"stable-llt\", \"stable-ll\" and \"stable-uuid\" will generate a DUID of the corresponding type, derived from the connection's stable-id and a per-host unique key. So, the link-layer address of \"stable-ll\" and \"stable-llt\" will be a generated address derived from the stable id. The DUID-LLT time value in the \"stable-llt\" option will be picked among a static timespan of three years (the upper bound of the interval is the same constant timestamp used in \"llt\"). When the property is unset, the global value provided for \"ipv6.dhcp-duid\" is used. If no global value is provided, the default \"lease\" value is assumed.")
+#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_DUID N_("A string containing the DHCPv6 Unique Identifier (DUID) used by the dhcp client to identify itself to DHCPv6 servers (RFC 3315). The DUID is carried in the Client Identifier option. If the property is a hex string ('aa:bb:cc') it is interpreted as a binary DUID and filled as an opaque value in the Client Identifier option. The special value \"lease\" will retrieve the DUID previously used from the lease file belonging to the connection. If no DUID is found and \"dhclient\" is the configured dhcp client, the DUID is searched in the system-wide dhclient lease file. If still no DUID is found, or another dhcp client is used, a global and permanent DUID-UUID (RFC 6355) will be generated based on the machine-id. The special values \"llt\" and \"ll\" will generate a DUID of type LLT or LL (see RFC 3315) based on the current MAC address of the device. In order to try providing a stable DUID-LLT, the time field will contain a constant timestamp that is used globally (for all profiles) and persisted to disk. The special values \"stable-llt\", \"stable-ll\" and \"stable-uuid\" will generate a DUID of the corresponding type, derived from the connection's stable-id and a per-host unique key. You may want to include the \"${DEVICE}\" or \"${MAC}\" specifier in the stable-id, in case this profile gets activated on multiple devices. So, the link-layer address of \"stable-ll\" and \"stable-llt\" will be a generated address derived from the stable id. The DUID-LLT time value in the \"stable-llt\" option will be picked among a static timespan of three years (the upper bound of the interval is the same constant timestamp used in \"llt\"). When the property is unset, the global value provided for \"ipv6.dhcp-duid\" is used. If no global value is provided, the default \"lease\" value is assumed.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_HOSTNAME N_("If the \"dhcp-send-hostname\" property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and \"dhcp-fqdn\" are mutually exclusive and cannot be set at the same time.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_SEND_HOSTNAME N_("If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer.  If the \"dhcp-hostname\" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_TIMEOUT N_("A timeout for a DHCP transaction in seconds.")
@@ -296,8 +296,8 @@
 #define DESCRIBE_DOC_NM_SETTING_SERIAL_SEND_DELAY N_("Time to delay between each byte sent to the modem, in microseconds.")
 #define DESCRIBE_DOC_NM_SETTING_SERIAL_STOPBITS N_("Number of stop bits for communication on the serial port.  Either 1 or 2. The 1 in \"8n1\" for example.")
 #define DESCRIBE_DOC_NM_SETTING_SRIOV_AUTOPROBE_DRIVERS N_("Whether to autoprobe virtual functions by a compatible driver. If set to NM_TERNARY_TRUE (1), the kernel will try to bind VFs to a compatible driver and if this succeeds a new network interface will be instantiated for each VF. If set to NM_TERNARY_FALSE (0), VFs will not be claimed and no network interfaces will be created for them. When set to NM_TERNARY_DEFAULT (-1), the global default is used; in case the global default is unspecified it is assumed to be NM_TERNARY_TRUE (1).")
-#define DESCRIBE_DOC_NM_SETTING_SRIOV_TOTAL_VFS N_("The total number of virtual functions to create.")
-#define DESCRIBE_DOC_NM_SETTING_SRIOV_VFS N_("Array of virtual function descriptors. Each VF descriptor is a dictionary mapping attribute names to GVariant values. The 'index' entry is mandatory for each VF. When represented as string a VF is in the form: \"INDEX [ATTR=VALUE[ ATTR=VALUE]...]\". for example: \"2 mac=00:11:22:33:44:55 spoof-check=true\". The \"vlans\" attribute is represented as a semicolor-separated list of VLAN descriptors, where each descriptor has the form \"ID[.PRIORITY[.PROTO]]\". PROTO can be either 'q' for 802.1Q (the default) or 'ad' for 802.1ad.")
+#define DESCRIBE_DOC_NM_SETTING_SRIOV_TOTAL_VFS N_("The total number of virtual functions to create. Note that when the sriov setting is present NetworkManager enforces the number of virtual functions on the interface also when it is zero. To prevent any changes to SR-IOV parameters don't add a sriov setting to the connection.")
+#define DESCRIBE_DOC_NM_SETTING_SRIOV_VFS N_("Array of virtual function descriptors. Each VF descriptor is a dictionary mapping attribute names to GVariant values. The 'index' entry is mandatory for each VF. When represented as string a VF is in the form: \"INDEX [ATTR=VALUE[ ATTR=VALUE]...]\". for example: \"2 mac=00:11:22:33:44:55 spoof-check=true\". Multiple VFs can be specified using a comma as separator. Currently the following attributes are supported: mac, spoof-check, trust, min-tx-rate, max-tx-rate, vlans. The \"vlans\" attribute is represented as a semicolon-separated list of VLAN descriptors, where each descriptor has the form \"ID[.PRIORITY[.PROTO]]\". PROTO can be either 'q' for 802.1Q (the default) or 'ad' for 802.1ad.")
 #define DESCRIBE_DOC_NM_SETTING_TC_CONFIG_QDISCS N_("Array of TC queueing disciplines.")
 #define DESCRIBE_DOC_NM_SETTING_TC_CONFIG_TFILTERS N_("Array of TC traffic filters.")
 #define DESCRIBE_DOC_NM_SETTING_TEAM_CONFIG N_("The JSON configuration for the team network interface.  The property should contain raw JSON configuration data suitable for teamd, because the value is passed directly to teamd. If not specified, the default configuration is used.  See man teamd.conf for the format details.")
diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in
index f07769c0..bc56edae 100644
--- a/clients/common/settings-docs.h.in
+++ b/clients/common/settings-docs.h.in
@@ -144,7 +144,7 @@
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_READ_ONLY N_("FALSE if the connection can be modified using the provided settings service's D-Bus interface with the right privileges, or TRUE if the connection is read-only and cannot be modified.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_SECONDARIES N_("List of connection UUIDs that should be activated when the base connection itself is activated. Currently only VPN connections are supported.")
 #define DESCRIBE_DOC_NM_SETTING_CONNECTION_SLAVE_TYPE N_("Setting name of the device type of this slave's master connection (eg, \"bond\"), or NULL if this connection is not a slave.")
-#define DESCRIBE_DOC_NM_SETTING_CONNECTION_STABLE_ID N_("This represents the identity of the connection used for various purposes. It allows to configure multiple profiles to share the identity. Also, the stable-id can contain placeholders that are substituted dynamically and deterministically depending on the context. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable and to derive the DHCP DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid]. Note that depending on the context where it is used, other parameters are also seeded into the generation algorithm. For example, a per-host key is commonly also included, so that different systems end up generating different IDs. Or with ipv6.addr-gen-mode=stable-privacy, also the device's name is included, so that different interfaces yield different addresses. The '$' character is treated special to perform dynamic substitutions at runtime. Currently supported are \"${CONNECTION}\", \"${DEVICE}\", \"${BOOT}\", \"${RANDOM}\". These effectively create unique IDs per-connection, per-device, per-boot, or every time. Note that \"${DEVICE}\" corresponds the the interface name of the device. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as \"$$\". For example, set it to \"${CONNECTION}-${BOOT}-${DEVICE}\" to create a unique id for this connection that changes with every reboot and differs depending on the interface where the profile activates. If the value is unset, a global connection default is consulted. If the value is still unset, the default is similar to \"${CONNECTION}\" and uses a unique, fixed ID for the connection.")
+#define DESCRIBE_DOC_NM_SETTING_CONNECTION_STABLE_ID N_("This represents the identity of the connection used for various purposes. It allows to configure multiple profiles to share the identity. Also, the stable-id can contain placeholders that are substituted dynamically and deterministically depending on the context. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable and to derive the DHCP DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid]. Note that depending on the context where it is used, other parameters are also seeded into the generation algorithm. For example, a per-host key is commonly also included, so that different systems end up generating different IDs. Or with ipv6.addr-gen-mode=stable-privacy, also the device's name is included, so that different interfaces yield different addresses. The '$' character is treated special to perform dynamic substitutions at runtime. Currently supported are \"${CONNECTION}\", \"${DEVICE}\", \"${MAC}\", \"${BOOT}\", \"${RANDOM}\". These effectively create unique IDs per-connection, per-device, per-boot, or every time. Note that \"${DEVICE}\" corresponds the the interface name of the device and \"${MAC}\" is the permanent MAC address of the device. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as \"$$\". For example, set it to \"${CONNECTION}-${BOOT}-${DEVICE}\" to create a unique id for this connection that changes with every reboot and differs depending on the interface where the profile activates. If the value is unset, a global connection default is consulted. If the value is still unset, the default is similar to \"${CONNECTION}\" and uses a unique, fixed ID for the connection.")
 #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 \"-\").")
@@ -197,7 +197,7 @@
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_TTL N_("The TTL to assign to tunneled packets. 0 is a special value meaning that packets inherit the TTL value.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ADDRESSES N_("Array of IP addresses.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DAD_TIMEOUT N_("Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network.  If an address conflict is detected, the activation will fail.  A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero).  A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4.")
-#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID N_("A string sent to the DHCP server to identify the local machine which the DHCP server may use to customize the DHCP lease and options. When the property is a hex string ('aa:bb:cc') it is interpreted as a binary client ID, in which case the first byte is assumed to be the 'type' field as per RFC 2132 section 9.14 and the remaining bytes may be an hardware address (e.g. '01:xx:xx:xx:xx:xx:xx' where 1 is the Ethernet ARP type and the rest is a MAC address). If the property is not a hex string it is considered as a non-hardware-address client ID and the 'type' field is set to 0. The special values \"mac\" and \"perm-mac\" are supported, which use the current or permanent MAC address of the device to generate a client identifier with type ethernet (01). Currently, these options only work for ethernet type of links. The special value \"stable\" is supported to generate a type 0 client identifier based on the stable-id (see connection.stable-id) and a per-host key. If unset, a globally configured default is used. If still unset, the client-id from the last lease is reused.")
+#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID N_("A string sent to the DHCP server to identify the local machine which the DHCP server may use to customize the DHCP lease and options. When the property is a hex string ('aa:bb:cc') it is interpreted as a binary client ID, in which case the first byte is assumed to be the 'type' field as per RFC 2132 section 9.14 and the remaining bytes may be an hardware address (e.g. '01:xx:xx:xx:xx:xx:xx' where 1 is the Ethernet ARP type and the rest is a MAC address). If the property is not a hex string it is considered as a non-hardware-address client ID and the 'type' field is set to 0. The special values \"mac\" and \"perm-mac\" are supported, which use the current or permanent MAC address of the device to generate a client identifier with type ethernet (01). Currently, these options only work for ethernet type of links. The special value \"duid\" generates a RFC4361-compliant client identifier based on a hash of the interface name as IAID and /etc/machine-id. The special value \"stable\" is supported to generate a type 0 client identifier based on the stable-id (see connection.stable-id) and a per-host key. If you set the stable-id, you may want to include the \"${DEVICE}\" or \"${MAC}\" specifier to get a per-device key. If unset, a globally configured default is used. If still unset, the default depends on the DHCP plugin.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_FQDN N_("If the \"dhcp-send-hostname\" property is TRUE, then the specified FQDN will be sent to the DHCP server when acquiring a lease. This property and \"dhcp-hostname\" are mutually exclusive and cannot be set at the same time.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_HOSTNAME N_("If the \"dhcp-send-hostname\" property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and \"dhcp-fqdn\" are mutually exclusive and cannot be set at the same time.")
 #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_SEND_HOSTNAME N_("If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer.  If the \"dhcp-hostname\" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent.")
@@ -218,7 +218,7 @@
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE N_("Configure method for creating the address for use with RFC4862 IPv6 Stateless Address Autoconfiguration. The permitted values are: NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64 (0) or NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY (1). If the property is set to EUI64, the addresses will be generated using the interface tokens derived from hardware address. This makes the host part of the address to stay constant, making it possible to track host's presence when it changes networks. The address changes when the interface hardware is replaced. The value of stable-privacy enables use of cryptographically secure hash of a secret host-specific key along with the connection's stable-id and the network address as specified by RFC7217. This makes it impossible to use the address track host's presence, and makes the address stable when the network interface hardware is replaced. On D-Bus, the absence of an addr-gen-mode setting equals enabling stable-privacy. For keyfile plugin, the absence of the setting on disk means EUI64 so that the property doesn't change on upgrade from older versions. Note that this setting is distinct from the Privacy Extensions as configured by \"ip6-privacy\" property and it does not affect the temporary addresses configured with this option.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ADDRESSES N_("Array of IP addresses.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DAD_TIMEOUT N_("Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network.  If an address conflict is detected, the activation will fail.  A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero).  A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4.")
-#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_DUID N_("A string containing the DHCPv6 Unique Identifier (DUID) used by the dhcp client to identify itself to DHCPv6 servers (RFC 3315). The DUID is carried in the Client Identifier option. If the property is a hex string ('aa:bb:cc') it is interpreted as a binary DUID and filled as an opaque value in the Client Identifier option. The special value \"lease\" will retrieve the DUID previously used from the lease file belonging to the connection. If no DUID is found and \"dhclient\" is the configured dhcp client, the DUID is searched in the system-wide dhclient lease file. If still no DUID is found, or another dhcp client is used, a global and permanent DUID-UUID (RFC 6355) will be generated based on the machine-id. The special values \"llt\" and \"ll\" will generate a DUID of type LLT or LL (see RFC 3315) based on the current MAC address of the device. In order to try providing a stable DUID-LLT, the time field will contain a constant timestamp that is used globally (for all profiles) and persisted to disk. The special values \"stable-llt\", \"stable-ll\" and \"stable-uuid\" will generate a DUID of the corresponding type, derived from the connection's stable-id and a per-host unique key. So, the link-layer address of \"stable-ll\" and \"stable-llt\" will be a generated address derived from the stable id. The DUID-LLT time value in the \"stable-llt\" option will be picked among a static timespan of three years (the upper bound of the interval is the same constant timestamp used in \"llt\"). When the property is unset, the global value provided for \"ipv6.dhcp-duid\" is used. If no global value is provided, the default \"lease\" value is assumed.")
+#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_DUID N_("A string containing the DHCPv6 Unique Identifier (DUID) used by the dhcp client to identify itself to DHCPv6 servers (RFC 3315). The DUID is carried in the Client Identifier option. If the property is a hex string ('aa:bb:cc') it is interpreted as a binary DUID and filled as an opaque value in the Client Identifier option. The special value \"lease\" will retrieve the DUID previously used from the lease file belonging to the connection. If no DUID is found and \"dhclient\" is the configured dhcp client, the DUID is searched in the system-wide dhclient lease file. If still no DUID is found, or another dhcp client is used, a global and permanent DUID-UUID (RFC 6355) will be generated based on the machine-id. The special values \"llt\" and \"ll\" will generate a DUID of type LLT or LL (see RFC 3315) based on the current MAC address of the device. In order to try providing a stable DUID-LLT, the time field will contain a constant timestamp that is used globally (for all profiles) and persisted to disk. The special values \"stable-llt\", \"stable-ll\" and \"stable-uuid\" will generate a DUID of the corresponding type, derived from the connection's stable-id and a per-host unique key. You may want to include the \"${DEVICE}\" or \"${MAC}\" specifier in the stable-id, in case this profile gets activated on multiple devices. So, the link-layer address of \"stable-ll\" and \"stable-llt\" will be a generated address derived from the stable id. The DUID-LLT time value in the \"stable-llt\" option will be picked among a static timespan of three years (the upper bound of the interval is the same constant timestamp used in \"llt\"). When the property is unset, the global value provided for \"ipv6.dhcp-duid\" is used. If no global value is provided, the default \"lease\" value is assumed.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_HOSTNAME N_("If the \"dhcp-send-hostname\" property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and \"dhcp-fqdn\" are mutually exclusive and cannot be set at the same time.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_SEND_HOSTNAME N_("If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer.  If the \"dhcp-hostname\" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_TIMEOUT N_("A timeout for a DHCP transaction in seconds.")
@@ -296,8 +296,8 @@
 #define DESCRIBE_DOC_NM_SETTING_SERIAL_SEND_DELAY N_("Time to delay between each byte sent to the modem, in microseconds.")
 #define DESCRIBE_DOC_NM_SETTING_SERIAL_STOPBITS N_("Number of stop bits for communication on the serial port.  Either 1 or 2. The 1 in \"8n1\" for example.")
 #define DESCRIBE_DOC_NM_SETTING_SRIOV_AUTOPROBE_DRIVERS N_("Whether to autoprobe virtual functions by a compatible driver. If set to NM_TERNARY_TRUE (1), the kernel will try to bind VFs to a compatible driver and if this succeeds a new network interface will be instantiated for each VF. If set to NM_TERNARY_FALSE (0), VFs will not be claimed and no network interfaces will be created for them. When set to NM_TERNARY_DEFAULT (-1), the global default is used; in case the global default is unspecified it is assumed to be NM_TERNARY_TRUE (1).")
-#define DESCRIBE_DOC_NM_SETTING_SRIOV_TOTAL_VFS N_("The total number of virtual functions to create.")
-#define DESCRIBE_DOC_NM_SETTING_SRIOV_VFS N_("Array of virtual function descriptors. Each VF descriptor is a dictionary mapping attribute names to GVariant values. The 'index' entry is mandatory for each VF. When represented as string a VF is in the form: \"INDEX [ATTR=VALUE[ ATTR=VALUE]...]\". for example: \"2 mac=00:11:22:33:44:55 spoof-check=true\". The \"vlans\" attribute is represented as a semicolor-separated list of VLAN descriptors, where each descriptor has the form \"ID[.PRIORITY[.PROTO]]\". PROTO can be either 'q' for 802.1Q (the default) or 'ad' for 802.1ad.")
+#define DESCRIBE_DOC_NM_SETTING_SRIOV_TOTAL_VFS N_("The total number of virtual functions to create. Note that when the sriov setting is present NetworkManager enforces the number of virtual functions on the interface also when it is zero. To prevent any changes to SR-IOV parameters don't add a sriov setting to the connection.")
+#define DESCRIBE_DOC_NM_SETTING_SRIOV_VFS N_("Array of virtual function descriptors. Each VF descriptor is a dictionary mapping attribute names to GVariant values. The 'index' entry is mandatory for each VF. When represented as string a VF is in the form: \"INDEX [ATTR=VALUE[ ATTR=VALUE]...]\". for example: \"2 mac=00:11:22:33:44:55 spoof-check=true\". Multiple VFs can be specified using a comma as separator. Currently the following attributes are supported: mac, spoof-check, trust, min-tx-rate, max-tx-rate, vlans. The \"vlans\" attribute is represented as a semicolon-separated list of VLAN descriptors, where each descriptor has the form \"ID[.PRIORITY[.PROTO]]\". PROTO can be either 'q' for 802.1Q (the default) or 'ad' for 802.1ad.")
 #define DESCRIBE_DOC_NM_SETTING_TC_CONFIG_QDISCS N_("Array of TC queueing disciplines.")
 #define DESCRIBE_DOC_NM_SETTING_TC_CONFIG_TFILTERS N_("Array of TC traffic filters.")
 #define DESCRIBE_DOC_NM_SETTING_TEAM_CONFIG N_("The JSON configuration for the team network interface.  The property should contain raw JSON configuration data suitable for teamd, because the value is passed directly to teamd. If not specified, the default configuration is used.  See man teamd.conf for the format details.")
diff --git a/clients/tests/test-client.py b/clients/tests/test-client.py
index e8f1f7f2..d92d499c 100755
--- a/clients/tests/test-client.py
+++ b/clients/tests/test-client.py
@@ -744,8 +744,8 @@ class TestNmcli(NmTestBase):
                     skip_test_for_l10n_diff.append(n['test_name'])
                     continue
                 print("\n\n\nThe file '%s' does not have the expected content:" % (filename))
-                print("ACTUAL OUTPUT:\n[[%s]]\n" % (results_expect[i]))
-                print("EXPECT OUTPUT:\n[[%s]]\n" % (n['content']))
+                print("ACTUAL OUTPUT:\n[[%s]]\n" % (n['content']))
+                print("EXPECT OUTPUT:\n[[%s]]\n" % (results_expect[i]))
                 print("Let the test write the file by rerunning with NM_TEST_REGENERATE=1")
                 print("See howto in %s for details.\n" % (PathConfiguration.canonical_script_filename()))
                 self.fail("Unexpected output of command, expected %s. Rerun test with NM_TEST_REGENERATE=1 to regenerate files" % (filename))